[comp.lang.c++] Calling a C++ routine as an X11 libXt callback function

vanandel@stout.atd.ucar.edu (Joe Van Andel) (08/21/90)

I am writing an application that uses the Athena widget set, but I would like 
to write this application in C++ (using g++),  if possible.  
(Yes, I know about the Interviews toolkit, but it doesn't have the ease of use
of the Widget Creation Language toolkit, nor does it let a user tailor 
an application by using X11 resources.  Solbourne's OI also looks interesting,
but I can't afford to pay AT&T $10000 + just now.)

I've heard rumors of some University writing a C++ binding for Motif, that 
will be released with X11 at some future date.  Does anyone know when this 
might be available?  Does this toolkit allow access to the Xt resource 
database?

The biggest hassle I see with using C++ and a non C++ toolkit is that
of using callbacks.  Since the callbacks are designed to be C
functions, how can I possibly invoke C++ functions, particularly if I
want to invoke the method of a given object?   If I have to, I'll write a bit 
of "glue" in "C", but I don't know how to do it.  Obviously, if writing the 
glue is too tedious or difficult, using C++ just may not be worth the hassle.

Surely, someone has solved the problem of calling a C++ function as a 
callback function!

Does anyone have any other suggestions about how to program X11 applications,
have access to the functionality of libXt, and still use C++ ?

Thanks much.  Please mail me responses, and I'll summarize the results. 

--
	Joe VanAndel  		Internet:vanandel@ncar.ucar.edu
	NCAR - RSG  			
	P.O Box 3000		Fax:	 303-497-2044
	Boulder, CO 80307-3000	Voice:	 303-497-2071 

jp@aurora.com (Jorge Phillips) (08/21/90)

In article <8271@ncar.ucar.edu> vanandel@stout.atd.ucar.edu (Joe Van Andel) writes:
>I am writing an application that uses the Athena widget set, but I would like 
>to write this application in C++ (using g++),  if possible.  
>            ...some stuff re. Interviews.
>The biggest hassle I see with using C++ and a non C++ toolkit is that
>of using callbacks.  Since the callbacks are designed to be C
>functions, how can I possibly invoke C++ functions, particularly if I
>want to invoke the method of a given object?   If I have to, I'll write a bit 
>of "glue" in "C", but I don't know how to do it.  Obviously, if writing the 
>glue is too tedious or difficult, using C++ just may not be worth the hassle.
>
>            ...more stuff...
>--
>	Joe VanAndel  		Internet:vanandel@ncar.ucar.edu


I had the same problem a while ago while writing g++ code that used Xt
widgets and library calls.

Initially I thought of rewriting the Xt, Xlib, Xmu, etc. headers as
C++ headers, like some people have suggested. Since I did not know of
`protoize' and `unprotoize' yet, I gave up on this alternative and
decided to use the glue approach.

Basically the idea is to write your C++ program in such a way that
after it performs all the necessary C++ object initializations, it
relinquishes control through glue to an X main program. This program
creates all widgets, establishes all callbacks (including those that
go to C++ through glue), and enters its event loop, thus effectively
driving the application from here on.

Here is a code skeleton of how I implemented callbacks to g++
functions following this idea, using a glue file. Admittedly, the
resulting code is not as clean and elegant an interface as I would
like it to be, but it works quite fine!

If you define a lean (i.e. well localized) interface between your C++
program and your X code, the glue file turns out to be quite small.
E.g. for a 7,000+ line g++ program using a substantial number of
widget classes and Xt and Xlib operations, the glue code turns out to
be only 100 lines of includes and glue procedure definitions.

I would appreciate any suggestions for a better (different, improved,
etc.) interface mechanism. Has anybody tried protoizing X11 headers and writing
ONLY c++ code that accesses Xt wdigets and primitives?

-Jorge


Encl:

==========================  X INTERFACE (x.c)
/*   Xt-based client
 *   Code skeleton
 */

#include <X11/...>         /* all Xt, Xlib, Xmu, Xaw, etc. headers needed */

Widget w1;
Widget w2; ....            /* declare all widgets */


void W1Callback(Widget w, caddr_t cl, caddr_t cd)
{
    /* here goes code that accesses widgets and X stuff */
    XGlueFoo(..args..);		/* call c++ callback through glue code */
    /* here goes any post-callback code, if needed. */
}


/* X driver portion main function */
int XMain(int argc, char** argv)
{
    /* local decls */
    top = XtInitialize(...);
    w1  = XtCreateManagedWidget("w1", ...someWidgetClass..., top, NULL, 0);
    XtAddCallback(w1, XtNcallback, W1Callback, 0);

    /* ...more Xt stuff... */
    XtRealizeWidget(top);
    XtMainLoop();
}


==========================  GLUE BETWEEN C++ and Xt CODE (glue.cc)

#include ...global header defs...
#include ...c++ headers needed by glue fns ...
#include "glue.h"

// declare below all C++ variables and procs used by glue
extern Class1* a;               // handle to some object used by glue
extern void SomeCCProc();       // maybe friend of some classes and objects
extern CC_Class someCCObject;   // will use this in callback


extern "C" {

/* declare here all x.c vars and procs used by glue */
extern int XMain(int, char**);
extern void XDoSomethingOnScreenFromCC();     /* called from C++ side */


/* declare here all C procs called from X interface */
void XGlueFoo(..arg decls..)
{
    /* This links to c++ callback code. Notice that objects used must be
       declared in included headers or above */
    someCCobject->SomeMethod(arg1, arg2, ... argK);  /* the c++ callback */
}


someCType XGlueReturnValue(..arg decls..)
{
  return anotherCCobject->AnotherMethod(...args...); /* returns val to x.c */
}


/* declare here C++ procs that call the X interface, such as XMain */
int XGlueXMain(int argc, char** argv)
{
    return XMain(argc, argv);		// start Xt portion of system
}



}; // end extern C


==========================  C++ CODE (main.cc)

// Main C++ program

#include ...c++ headers...

// include the glue header file for communication
extern "C" {
#include "glue.h"           
};

CC_Class someCCobject;		// to be used by XGlueFoo()

int main(int argc, char** argv)
{
    ...set up world...
    ...perform any preliminary C++ processing...
    return XGlueXMain(argc, argv);     // relinquish control to X through glue
}


-- 
jp@aurora.com --- Sic itur ad astra.