home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky comp.windows.open-look:3687 alt.toolkits.xview:815
- Path: sparky!uunet!sun-barr!news2me.ebay.sun.com!exodus.Eng.Sun.COM!appserv.Eng.Sun.COM!midniteoil!soloway
- From: soloway@midniteoil.Eng.Sun.COM (Mark Soloway)
- Newsgroups: comp.windows.open-look,alt.toolkits.xview
- Subject: Re: Q: C++ and callback problems (LONG)
- Date: 1 Sep 1992 23:14:06 GMT
- Organization: Sun Microsystems, Inc.
- Lines: 156
- Distribution: world
- Message-ID: <la7u9uINN7uv@appserv.Eng.Sun.COM>
- References: <1992Aug30.171624.1330@isy.liu.se>
- Reply-To: soloway@midniteoil.Eng.Sun.COM
- NNTP-Posting-Host: midniteoil
-
- This article describes a method I use to provide a convenient C++
- callback interface for XView and provide the ability to encapsulate
- callback behavior in a subclass. The method described is used in
- UIT V2.
-
- In order to provide a convenient C++ callback interface for XView
- you want the callback to call a member function of the class that
- is encapsulating the XView package. Ordinary (non-static) member
- functions provide an implicit "this" pointer for access to other members
- of the object. Many compilers pass the "this" pointer as an invisible
- first argument in the member function. This means that the following
- member function:
-
- ClassName::memberFunction (Panel_item item, Event *event)
-
- can look like the following in the C code generated by cfront:
-
- memberFunction__9ClassNameF10Panel_itemP5Event (ClassName *this,
- Panel_item item,
- Event *event)
-
- (See C++ Annotated Refernce Manual (ARM), section 7.2 for
- more information regarding funtion name encoding).
-
- This causes a problem with callbacks becuase of the "this" argument.
- The way to get around this is by using a static member function in
- callbacks. Static member functions do not provide a "this" pointer
- to access ordinary class members and do not have a "this" argument in
- the C code form of the member function. If you have the following static
- member function defined for a Button class (encapsulating the XView
- PANEL_BUTTON package):
-
- void Button::notifyProc (Panel_item item, Event *event)
-
- You can specify it as a callback in the following way:
-
- // Create the XView button and store it in a data mwember
- // of the Button class (Button::xviewButton).
- xviewButton = xv_create (owner, PANEL_BUTTON,
- PANEL_NOTIFY_PROC, &Button::notifyProc,
- NULL);
-
- With some compilers (g++, for example) the static member function must
- be public if you want to get the address of it. This is not true for
- most AT&T derived compilers.
-
- In order to actually provide a convenient callback interface you really
- need to get hold of a pointer to the Button object when the callback is
- called. This can be done by attaching data to the XView object that
- calls the callback. XV_KEY_DATA provides an easy way to do this. First
- a constant key value must be created. Here are 2 ways of doing this:
-
- 1) Use a "const int" or a "#define" to define a key value in
- a header file that will be used for this purpose:
-
- const int THIS_POINTER_KEY = 100;
-
- or:
-
- #define THIS_POINTER_KEY 100
-
- Of course, you must make sure the key value you choose is unique
- for your application. Or,
-
- 2) Create a global variable and use xv_unique_key to initialize
- the value:
-
- int this_pointer_key_g;
-
- void main (int argc, char **argv)
- {
- this_pointer_key_g = xv_unique_key();
-
- ...
- }
-
- After creating the unique key, use the key to store the encapsulating object
- "this" pointer in the XView button object:
-
- xv_set (xviewButton,
- XV_KEY_DATA, THIS_POINTER_KEY, this,
- NULL);
-
- A basic notifyProc member function that calls a user spcified callback
- handler might look like this:
-
- void Button::notifyProc (Panel_item item, Event *event)
- {
- Button *object = (Button *)xv_get(item,
- XV_KEY_DATA,
- THIS_POINTER_KEY);
-
- // If a notify handler has been specified, via
- // "void Button::setNotifyHandler (void (*)(Button *, Event *))",
- // then call it.
- if (object->notifyHandler)
- (*object->notifyHandler)(object, event);
- }
-
- This provides a "convenient" callback interface, but it does not provide
- for encapsulation of callback behavior in the class. To provide the ability
- to encapsulate the behavior, you need to provde a virtual function that
- will be overridden in subclasses that are encapsulating the callback
- behavior:
-
- class Button {
- public:
- ...
-
- protected:
- // Make xviewButton protected so that derived classes can get hold
- // of the XView button object when inside of their personalized
- // handlers.
- Panel_item xviewButton;
-
- private:
- static void notifyProc(Panel_item, Event *);
- virtual void notifyHandler(Event *);
- }
-
- void Button::notifyProc (Panel_item item, Event *event)
- {
- Button *object = (Button *)xv_get(item,
- XV_KEY_DATA,
- THIS_POINTER_KEY);
-
- (*object->notifyHandler)(event);
- }
-
- You can then define the behavior of notifyHandler in a class derived
- from Button:
-
- class FileButton : public Button {
- public:
- ...
-
- private:
- virtual notifyHandler(Button *, Event *);
- }
-
- void FileButton::notifyHandler (Event *event)
- {
- // Do whatever I want...
- }
-
- Because of virtual functions, FileButton::notifyHandler will have
- an implicit "this" pointer to the FileButton object that is encapsulating
- the XView object the callback occurred on.
-
- - Mark
- __________________________________________
- \_Mark Soloway (mark.soloway@Eng.Sun.COM)_\
- /_Distributed Systems Services (ToolTalk)_/
- \__SunSoft (A Sun Microsystems Company)___\
-
-
-