From: jps1741@aw2.fsl.ca.boeing.com (Joseph P. Stegman)
Newsgroups: comp.windows.x.intrinsics
Subject: Re: Q: C++ and callback problems.
Date: 22 Aug 92 20:40:05 GMT
Organization: none

jhd@irfu.se (Jan D.) writes:

>In article <1992Aug21.135038.3466@eua.ericsson.se> tvtjet@eua.ericsson.se (Jorgen Eriksson) writes:
>>
>>I have problems with c++ and callbacks. My intention was to create a window
>>class which contains one or more callback functions, implemented as class
>>methods. This doesn't work properly. Somewere along the way ( probably down in
>>Xlib ) the callback parameters are LOST i.e. if the callback funktion is NOT
>>declared as a static. This is not what i want but it seems to be the only way 

>You can't pass a member function to Xt as a callback function
>unless it is declared static.

There are a number of solutions available to this problem which involve the
use of callback classes (D. Young).  I use the following approach which may
work for you.  The solution requires a widget set which allows for user
specified data to be set as part of the widget (XmNuserData in Motif), is a
bit of a hack, and not for the weak of heart.  We use cfront which implicitly
passes the C++ "this" pointer as a hidden first argument to all non-static
member function calls.  Now the problem is that a callback is not called from
C++ code and therefore when it is called, it is not passed the "this" pointer.
Instead, the callback widget argument is passed as the hidden first argument.
As an example, if the following non-static callback was declared and called,
the arguments would look like the following:

void MyClass::MyNonStaticCB(XtPointer client, XmAnyCallbackStruct *data)
{
    // this   = widget
    // client = client data
    // data   = callback data
}

Now if the (Mofit XmPrimitive specific) XmNuserData field of the widget
is set to the "this" pointer as the following macro does:

#define MEMBER_ADD_CALLBACK(theWidget, callbackName, callback, callbackData) \
                                                                        \
     XtVaSetValues(theWidget, XmNuserData, (XtPointer)this, NULL);      \
     XtAddCallback(theWidget,                                           \
                callbackName,                                           \
                (XtCallbackProc)callback,                               \
                (XtPointer)callbackData);

Then a callback can be added:

MEMBER_ADD_CALLBACK(widget, XmNactivateCallback, MyClass::MyNonStaticCB, data);

and in the callback routine, the "this" pointer is extracted from the widget:

void MyClass::MyNonStaticCB(XtPointer client, XmAnyCallbackStruct *data)
{
    MyClass	*me;

    XtVaGetValues((Widget)this, XmNuserData, &me, NULL);
    this = me;

    // You're ready to roll
}

Now granted, there are some problems, like having one widget call callbacks
in different classes, but 99% of the time this is OK.

Joe

-- 
-- Joe Stegman                 |     Voice: (206) 234-2432                 --
\  Boeing Commercial Airplanes |  Internet: jps1741@aw300.fsl.ca.boeing.com /
/  P.O. Box 3707, M/S 66-04    |Boeing net: jps1741@aw300                   \
-- Seattle, WA  98124-2207     |      UUCP: ..!uunet!bcstec!aw300!jps1741  --
Xref: sparky comp.windows.x.intrinsics:196 comp.windows.x.motif:5717