From: a_mahmoo@edrc.ac.uk (Arshad Mahmood)
Newsgroups: comp.lang.c++
Subject: Re: Callbacks - C++ needs an extension?
Date: 7 Sep 92 17:32:59 GMT
Organization: Engineering Design Research Centre

A slightly different approach as covered in D. Young's book is to rely on a
global callback (and event handler), which supplies the implicit this
pointer to the method (accellarators are probably still best handled as
per David's solution). The code below (not taken from Young, I wrote this
before the book was published) is an example of how this can be
done (in this case your classes have to be subclasses of XCC to make use of
this facility, no doubt other's can think of other ways to go about it
(any ideas on how to implement this in a much nicer way are welcome, the
class LIST and LIST_Iterator are NOT supplied get in touch if you want to 
make use of it, and I will supply you the rest of code and an example).

/*
  File: XCC.h
  Description:
  My rather daft way of implementing callbacks for C++.
*/

#ifndef _XCC_H
#define _XCC_H

#include <X11/Intrinsic.h>
#include "list.h"

class XCC;

typedef void (XCC::*Callback)(Widget, void*, void*);
typedef void (XCC::*EventHandler)(Widget, void*, XEvent*);

class XCC {
 public:
  XCC();
  ~XCC();

  void AddCCCallback(Widget w, char* name, Callback cb, void* client_data);
  void AddCCEventHandler(Widget w, EventMask, Boolean, EventHandler, void*);

 private: /* if you're using gnu the next two functions have to be public */
  static void theCallback(Widget, void*, void*);
  static void theHandler(Widget, void*, XEvent*);

  LIST client_data_list;
};

#define AddCallback(w,name,cb,cdata) AddCCCallback(w,name, (Callback)&cb,cdata)

#define AddEventHandler(w,mask,nonmaskable,handler,cdata) \
           AddCCEventHandler(w,mask,nonmaskable,(EventHandler)&handler, cdata)

#endif _XCC_H
-----------------------------------------
/*
  File: XCC.C

*/

#include "XCC.h"
#include "list_it.h"

/*
  XCCStruct - This structure is passed as client data to the event handlers
	      and callbacks, it passes the implicit this pointer "me" so
	      so that member functions may be passed as callbacks and
	      event handlers.
*/

typedef struct
{
  XCC*   me;
  EventHandler handler;
  Callback   callback;
  void*      client_data;
} XCCStruct;

XCC::XCC()
{
}

 XCC::~XCC()
{
  LIST_Iterator it(client_data_list);
  XCCStruct* x;

  foreach(it,XCCStruct*,x) delete x;
}

/*
  AddCCCallback - like the toolkit function XtAddcallback this one 
  adds a particular member function as a callback. In order to use
  C++, I have routed all callbacks through one central callback
  (XCC::theCallback), the client data for this tells it what to
  do above and beyond that.
*/

void XCC::AddCCCallback(Widget w, char* name, Callback cb, 
			    void* client_data)
{
  XCCStruct* x = new XCCStruct;

  x->callback = cb;
  x->client_data = client_data;
  x->me = (XCC *)this;

  XtAddCallback(w, name, (XtCallbackProc)XCC::theCallback, (XtPointer)x);
  client_data_list.InsertAtEnd((void *)x);
}

/*
  AddCCEventHandler - Register a C++ event handler, as with the callbacks
                      all events pass through a central handler
		      (theHandler)
*/

void XCC::AddCCEventHandler(Widget w, EventMask mask, Boolean nonmaskable,
				EventHandler handler, void* client_data)
{
  XCCStruct* x = new XCCStruct;

  x->handler = handler;
  x->client_data = client_data;
  x->me = (XCC *)this;

  XtAddEventHandler(w, mask, nonmaskable, (XtEventHandler)XCC::theHandler, 
		    (XtPointer)x);
  client_data_list.InsertAtEnd((void *)x);
}
 
/*
 theCallback - This is the central callback for all callbacks
                registered as members of classes. It's a static member
		of the class.
*/
  
void XCC::theCallback(Widget w, void* client_data, void* call_data)
{
  XCCStruct* cb_struct = (XCCStruct *)client_data;
  XCC* mclass = cb_struct->me;
  
  (mclass->*(cb_struct->callback))(w, cb_struct->client_data, call_data);
}

/*
  theHandler - This is the central handler through which all C++ based
               Event Handlers work.
*/

void XCC::theHandler(Widget w, void* client_data, XEvent* event)
{
  XCCStruct* cb_struct = (XCCStruct *)client_data;
  XCC* mclass = cb_struct->me;

  (mclass->*(cb_struct->handler))(w, cb_struct->client_data, event);
} 

------------------------ end of XCC.C --
Regards,
A. Mahmood
Systems Manager
EDRC
e-mail: a_mahmoo@uk.ac.edrc
Newsgroups: comp.lang.c++