home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / lang / cplus / 13174 < prev    next >
Encoding:
Text File  |  1992-09-01  |  5.7 KB  |  173 lines

  1. Path: sparky!uunet!sun-barr!news2me.ebay.sun.com!exodus.Eng.Sun.COM!appserv.Eng.Sun.COM!midniteoil!soloway
  2. From: soloway@midniteoil.Eng.Sun.COM (Mark Soloway)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Callbacks - C++ needs an extension?
  5. Date: 2 Sep 1992 00:44:16 GMT
  6. Organization: Sun Microsystems, Inc.
  7. Lines: 159
  8. Distribution: world
  9. Message-ID: <la83j0INN839@appserv.Eng.Sun.COM>
  10. References: <DAVIDM.92Aug31105639@consilium.com>
  11. Reply-To: soloway@midniteoil.Eng.Sun.COM
  12. NNTP-Posting-Host: midniteoil
  13.  
  14. This is an article I just posted to comp.windows.open-look and alt.toolkits.xview.
  15. Because of this thread of discussion, I decided to re-post here.  Even though the
  16. examples are XView specific, the concepts can be used with other toolkits...
  17.  
  18. This article describes a method I use to provide a convenient C++
  19. callback interface for XView and provide the ability to encapsulate
  20. callback behavior in a subclass.  The method described is used in
  21. UIT V2.
  22.  
  23. In order to provide a convenient C++ callback interface for XView
  24. you want the callback to call a member function of the class that
  25. is encapsulating the XView package.  Ordinary (non-static) member
  26. functions provide an implicit "this" pointer for access to other members
  27. of the object.  Many compilers pass the "this" pointer as an invisible
  28. first argument in the member function.  This means that the following
  29. member function:
  30.  
  31.     ClassName::memberFunction (Panel_item item, Event *event)
  32.  
  33. can look like the following in the C code generated by cfront:
  34.  
  35.     memberFunction__9ClassNameF10Panel_itemP5Event (ClassName  *this,
  36.                                        Panel_item  item,
  37.                                     Event      *event)
  38.  
  39.     (See C++ Annotated Refernce Manual (ARM), section 7.2 for
  40.      more information regarding funtion name encoding).
  41.  
  42. This causes a problem with callbacks becuase of the "this" argument.
  43. The way to get around this is by using a static member function in
  44. callbacks.  Static member functions do not provide a "this" pointer
  45. to access ordinary class members and do not have a "this" argument in
  46. the C code form of the member function.  If you have the following static
  47. member function defined for a Button class (encapsulating the XView
  48. PANEL_BUTTON package):
  49.  
  50.     void Button::notifyProc (Panel_item item, Event *event)
  51.  
  52. You can specify it as a callback in the following way:
  53.  
  54.     // Create the XView button and store it in a data mwember
  55.     // of the Button class (Button::xviewButton).
  56.     xviewButton = xv_create (owner, PANEL_BUTTON,
  57.                      PANEL_NOTIFY_PROC, &Button::notifyProc,
  58.                  NULL);
  59.  
  60. With some compilers (g++, for example) the static member function must
  61. be public if you want to get the address of it.  This is not true for
  62. most AT&T derived compilers.
  63.  
  64. In order to actually provide a convenient callback interface you really
  65. need to get hold of a pointer to the Button object when the callback is
  66. called.  This can be done by attaching data to the XView object that
  67. calls the callback.  XV_KEY_DATA provides an easy way to do this.  First
  68. a constant key value must be created.  Here are 2 ways of doing this:
  69.  
  70.     1) Use a "const int" or a "#define" to define a key value in
  71.        a header file that will be used for this purpose:
  72.  
  73.         const int THIS_POINTER_KEY = 100;
  74.  
  75.        or:
  76.  
  77.         #define THIS_POINTER_KEY 100
  78.  
  79.        Of course, you must make sure the key value you choose is unique
  80.        for your application.  Or,
  81.  
  82.     2) Create a global variable and use xv_unique_key to initialize
  83.        the value:
  84.  
  85.         int this_pointer_key_g;
  86.  
  87.         void main (int argc, char **argv)
  88.         {
  89.           this_pointer_key_g = xv_unique_key();
  90.  
  91.                   ...
  92.         }
  93.  
  94. After creating the unique key, use the key to store the encapsulating object
  95. "this" pointer in the XView button object:
  96.  
  97.         xv_set (xviewButton,
  98.             XV_KEY_DATA, THIS_POINTER_KEY, this,
  99.             NULL);
  100.  
  101. A basic notifyProc member function that calls a user spcified callback
  102. handler might look like this:
  103.  
  104.     void Button::notifyProc (Panel_item item, Event *event)
  105.     {
  106.       Button *object = (Button *)xv_get(item,
  107.                                         XV_KEY_DATA,
  108.                         THIS_POINTER_KEY);
  109.  
  110.       // If a notify handler has been specified, via
  111.       // "void Button::setNotifyHandler (void (*)(Button *, Event *))",
  112.       // then call it.
  113.           if (object->notifyHandler)
  114.             (*object->notifyHandler)(object, event);
  115.     }
  116.  
  117. This provides a "convenient" callback interface, but it does not provide
  118. for encapsulation of callback behavior in the class.  To provide the ability
  119. to encapsulate the behavior, you need to provde a virtual function that
  120. will be overridden in subclasses that are encapsulating the callback
  121. behavior:
  122.  
  123.     class Button {
  124.     public:
  125.       ...
  126.  
  127.     protected:
  128.       // Make xviewButton protected so that derived classes can get hold
  129.       // of the XView button object when inside of their personalized
  130.       // handlers.
  131.           Panel_item xviewButton;
  132.  
  133.     private:
  134.       static  void notifyProc(Panel_item, Event *);
  135.       virtual void notifyHandler(Event *);
  136.     }
  137.  
  138.     void Button::notifyProc (Panel_item item, Event *event)
  139.     {
  140.       Button *object = (Button *)xv_get(item,
  141.                                         XV_KEY_DATA,
  142.                         THIS_POINTER_KEY);
  143.  
  144.       (*object->notifyHandler)(event);
  145.     }
  146.     
  147. You can then define the behavior of notifyHandler in a class derived
  148. from Button:
  149.  
  150.     class FileButton : public Button {
  151.     public:
  152.       ...
  153.  
  154.     private:
  155.       virtual notifyHandler(Button *, Event *);
  156.     }
  157.  
  158.     void FileButton::notifyHandler (Event *event)
  159.     {
  160.       // Do whatever I want...
  161.     }
  162.  
  163. Because of virtual functions, FileButton::notifyHandler will have
  164. an implicit "this" pointer to the FileButton object that is encapsulating
  165. the XView object the callback occurred on.
  166.  
  167.                     - Mark
  168. __________________________________________
  169. \_Mark Soloway (mark.soloway@Eng.Sun.COM)_\
  170. /_Distributed Systems Services (ToolTalk)_/
  171. \__SunSoft (A Sun Microsystems Company)___\
  172.  
  173.