[comp.windows.x] C++ interface to the X toolkit

jdf@lri.lri.fr (Jean-Daniel Fekete) (11/28/90)

Since there seems to be some interest in packages to use widgets
from C++ and some inaccurate information has been posted, I have to make
things clear about WWL.

In his article:
> From: ctim@dolphin.aaet.ti.com (Craig Timmerman)
> Newsgroups: comp.windows.x.motif
> Subject: C++ interface to Motif 1 of 2 (long)
> Message-ID: <9011161934.AA00403@dolphin.aet_austin>
> Date: 16 Nov 90 19:34:13 GMT

Craig Timmerman says:
> The bindings are very thin.  There are only a couple of data members
> kept by the objects, one is the widget id, the other is a arg list and
> arg count used by the set/get functions.  [...]

In WWL, there is NOTHING MORE than the widget. Passing a C Widget or a
C++ Widget wrapper to a function produces identical code if handled by
a decent C++ compiler (g++ for instance).

There is no hidden hash table or allocated data structure to manage,
the price is ZERO in term of memory and time overhead compared to C
widgets.

Later, Craig Timmerman says:
> Callbacks, actions, and event handlers are defined with the aid of
> macros.  The main thing these macros do is provide the two lines of
> code that access the hash table to convert the widget id normally
> passed to these functions into a pointer to the proper C++ class
> instance.  This way you can keep the code for the callbacks in C++ and
> never have to worry about referencing widgets.  This is a big
> difference between the Univ Lowell bindings and the  Widget Wrapper
> Library (WWL) that you may have seen messages posted about.  The Widget
> Wrapper Library doesn't keep a hash table mapping of widgets to
> objects.  Therefore, all of your callbacks, actions and event handlers
> must be coded in straight C using Xt calls rather than in C++.   

WWL does not manage any hash table. However, there is
a simple mechanism to call member functions of a class derived from
the predefined class WWL. This is not documented in WWL 1.0, but will be
available in 1.1.
I have included at the end of this message an example of an
application using this. You can see that callbacks are declared as
methods in the object responsible for the handling of the windows and
decorations.
This scheme is more useful than having the callback be members of
the widget class itself, since most of the time it needs to access
some data OUTSIDE the widget.

> The behind the scenes adding of resources done by some of the Motif
> composites are not handled properly.  The form object is the biggest
> problem.  All of the Attach<foo> like resources that are added to form
> children are incorrectly represented in the bindings by set/get member
> functions on the form widget.  You really want the Attach<foo> member
> function to be on the child, but this member function only makes sense
> for children of forms.  I don't know how to fix this one except by
> keeping these set/get functions on the form, but make them take the
> child widget as a parameter.

In WWL, a special class is generated for widgets inheriting from
"Constraint".  The constraint resources are available to widgets
through a cast, which costs NOTHING: you can access the constraint
resources by casting the child widget to the right constraint class.

There is one problem left for now, when many resources should be set
in parallel, like for the form widget. This can be handled with
standard XtArgs. For the moment, getting and setting resources
is not buffered.

Very soon, I'll release the version 1.1 of WWL which will work with
Athena widgets and Motif 1.1. I have also added some documentation
about the callback mechanism with C++ methods (added by Michel
Beaudouin-Lafon, mbl@lri.lri.fr).

Small example.
----------------------------------------------------------------------------
#include <stream.h>
#include "WWL/TopLevelShell.h"
#include "WWL/XmPushButton.h"

class HelloWorld : public WWL {
protected :
	WTopLevelShell	toplevel;
	WXmPushButton	pushb;
static	int		once;

	void	HandleQuit (WCallback*);
public :
		HelloWorld (unsigned, char*[]);
};

HelloWorld :: HelloWorld (unsigned argc, char* argv[])
: toplevel (XtInitialize ("sample", "Sample", NULL, 0, &argc, argv)),
  pushb (toplevel, "Hello World")
{
	toplevel.Width (200);
	toplevel.Height (100);
	/*
	 * I add a method here as callback
	 */
	pushb.SetActivateCallback (this, HandleQuit);
	pushb.Manage ();
	toplevel.Realize ();
}

void
HelloWorld :: HandleQuit (WCallback*)
{
	if (! once++)
		pushb.LabelString("Goodbye Cruel World");
	else
		exit (0);
}

int
main(Cardinal argc, char* argv[])
{
	HelloWorld hw(argc, argv);
	XtMainLoop ();
}

-- 
   ___    0  Jean-Daniel Fekete            uucp  : jdf@lri.lri.fr
  /   \  /   LRI - Bat 490                 bitnet: jdf@FRLRI61.bitnet
 /   _/ /    Universite de Paris-Sud       voice : +33 (1) 69 41 69 10
/__   \/     F-91405 ORSAY Cedex                   +33 (1) 69 41 66 29