home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / windows / openloo / 3687 < prev    next >
Encoding:
Text File  |  1992-09-01  |  5.5 KB  |  171 lines

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