[comp.windows.x.motif] C++ interface to Motif 1 of 2

ctim@dolphin.aaet.ti.com (Craig Timmerman) (11/17/90)

Since this question popped up again, here is some information on the
Univ of Lowell C++ interface to Motif that I have been collecting.  I
figured others might be interested in this as well.  The first part of
this is a description/review of the bindings.  The second part is a
series of messages explaining where you can get the bindings.  Maybe
if enough people are interested, OSF will stop sitting on this stuff
and release it for real.  

I have been using these bindings for about four months now for some
prototype work.  Overall I am pleased with how well they work.  You
can get a better picture of what the binding do by reading the Univ of
Lowell paper (see part two for how to get it).

The bindings are a set of C++ class wrappers around all of the
existing Motif widgets.  You refer to the widgets as true C++ classes
and all of the Motif and Xt functions are setup as member functions of
the classes.  Attribute/resource setting is done with set/get member
functions.  The only time you have to refer to the actual widgets or
windows is when you need to go down to the Xlib level.  

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.  All set/get functions
"queue-up" the attributes to be set/get much just they way you do with
Xt.  A member function equivalent to XtSet/GetValues is called to
flush everything at once.  The arg list is currently a fixed size, 100
element array.  If I were to go into full production with my code this
arg list would need to be changed to an array (preferably a C++ list
object) which could grow as needed.  100 elements is a bit excessive
for most applications.  The delayed set/get action can be avoided by
setting a static data member.  All get functions take pointers to
variables as parameters as a place to store the retrieved value (just
like Xt).  In many cases it would be preferable to just have the value
be the return value of the call.  This would be another change I would
make to the bindings for production code.

The bindings keep a global hash table of widget id to class instance
mappings.  When you call the object's constructor the mapping entry is
put into the hash table.  When an object is destroyed the hash table
entry is removed.  The bindings use the hash table for mapping Xt
calls which return widgets to the objects that you want to really use
in your C++ program.

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++.   

Being able to access the C++ object in callbacks is even a bigger plus
if you have subclassed the widget classes as I have done.  The
subclasses I have created have allowed me to keep track of additional
data I needed for the display and operation on the widgets.  This
allows me to keep all the data I need right with the widget it
pertains to without keeping a whole other data structure like I would
in C.  Subclassing also allows me to keep the functions which operate
on specific objects all packaged together.

The subclassing I have done only adds data and function members to the
existing objects.  It didn't change the basic way the widget works.
IF you want to create an whole new widget you must first do the normal
Xt subclassing in C, then write the proper C++ binding.  The writing
of the binding for a new class is straight forward.  Several macros
help you do it.  I created a new binding for the Table widget in very
short order.

The callbacks, actions and event handlers are written as standalone
C++ functions (not member functions).  I found this a bit limiting
since you either have to make the functions friends of your class or
make any extra data members public (this applies only if you
subclassed the objects as I did).  What I did was write another set of 
callback, actions and event handler macros to make them call member
functions on my subclasses instead of being standalone C++ functions.


There are some problems with the bindings.  Some of these are nits,
others I think are major shortcomings in the software.  Most of these
could be fixed without a lot of effort.   

The first thing has to do with the destructors.  The only thing the
class destructors do is remove the widget<->object mapping from the
hash table.  The object instance will be destroyed but not the widget
itself.  What I would expect is if I destroy the object its associated
widget gets destroyed too.  Now destroying the widget could cause
problems if objects were copied (you could have two objects pointing
to the same widget).  So what the objects need to keep is a widget and
a reference count.  The reference count is incremented when the object
is copied.  This way when the object is destroyed the widget is
destroyed only if the reference count is 0.   

There needs to be more convenence functions/classes added.  Creating
menus is one places where this is nice.  I have created a menu item
object patterned after some of Doug Young's menu examples.  I then
added constructors on the menu classes to take a menu item list as a
parameter.  This way with on simple constructor call for a menu I get
the entire menu created.  And with one call to the menubar constructor I
get the menubar, its menu items and all the pulldowns created. 

The bindings don't work with UIL (this may be a plus for some 
people :-) nor do they work with any of the interface builders
available today.  Getting the bindings to work with UIL would require
changes to the MrmFetchHeirarchy call (and its relatives) to have the
C++ objects created as well as the widgets.

Most of the member functions are real functions.  They should be
reworked to make them inlines instead.  Most of the member functions
are 1-2 lines so inlines would just make everything more efficient.

Objects are only created for "known" windows.  If a widget
automatically creates a "hidden" widget there is no C++ object to go
with it.  An example would be a scrolled window.  With the bindings
you will have a scrolled window object, but there will be no object
that represents the automatically created clip window inside the
scrolled window.  Normally this isn't a problem until you try to
traverse the parent-child heirarchy.  Remember with the bindings you
work entirely in C++.  If I ask for a child's parent I get a pointer
to the C++ object representing the parent.  A child in a scrolled
window is a child of the clip window, not the a child of the scrolled
window.  Asking for its parent gets a hash table error since there is
no C++ object for the clip window.

There is a XMString class provided with the bindings.  However, this
only implements the Motif XmString functionality.  It really needs to
have more of the functionality that you find with String classes found
in class libraries like NIH.  One function in particular would be a
overloaded (char*) operator so XMStrings could be easily converted to
normal char pointers.  In contrast to the WWL, the XMString class has
member functions to draw themselves, however these functions take the
same parameters as the Motif XmStringDraw functions.  They should take
just the object pointer and figure out the window, display, etc out
for themselves.

There is no class for fontlists.  You must use the stardard Motif
mechanisms for dealing with fontlists.

There are member functions for gaining access to the widget, window,
display, and screen ids/pointers for an object.  Most of the time you
need these when calling Xlib functions.  These member functions are
fine, but overloading casting operators like (Widget*), (Screen), and
(Display) might be a better way.  

The naming(capitalization) conventions used for the member functions
is inconsistent.  If the function represents an Xt function it is
called and capitalized just like the Xt functions (sans the beginning
Xt prefix).  Other functions specific to the bindings start with
initial lower case letters.  This is a nit, but it's confusing to
remember that Parent() is uppercase while display() and screen() are
lower. 

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.

That about wraps up my general comments.  I can provide more info if
someone has specific questions.  I haven't yet sent my
nits/shortcomings/bug fixes to OSF, but I will do so shortly.
Overall, I have found the bindings to be easy to use.  The general
programming paradigm still follows Xt/Motif so there is no learning
curve there.  The bindings allowed me to do what I wanted in my
prototype which is to code entirely in C++.

However, I truly feel that these bindings are just an interim
solution.  What is needed is a true C++ class library/API that is not
built on any existing C toolkit.  This way true subclassing of the
widgets to make new widgets would be possible.  Hopefully the X
consortium working off some kind of an Interviews base will get us in
the right direction.

My next message summarizes how you might obtain these bindings.

----------------------------------------------------------------------
Craig Timmerman 	ctim@aaet.csc.ti.com
Texas Instruments	
Austin, TX		
----------------------------------------------------------------------

nazgul@alphalpha.com (Kee Hinckley) (11/17/90)

> element array.  If I were to go into full production with my code this
> arg list would need to be changed to an array (preferably a C++ list
> object) which could grow as needed.  100 elements is a bit excessive
That's exactly what I did for my Motif wrappers.

> The bindings keep a global hash table of widget id to class instance
> mappings.  When you call the object's constructor the mapping entry is
> put into the hash table.  When an object is destroyed the hash table
> entry is removed.  The bindings use the hash table for mapping Xt
> calls which return widgets to the objects that you want to really use
> in your C++ program.
That sound expensive.  Are all of the X[tm] functions really defined as
member functions?  E.g. What about XmProcessTraversal (well, I
suppose that's only 1.1) or XtMapWidget.  If every one of those is
there that sounds like a fairly heavy object.

> 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
But it must produce a dummy callback routine no?  Or does it
just assume it knows the C++ calling conventions?  Or does it have
one callback for each signature, which then converts to object and
calls the C++ callback?

> The callbacks, actions and event handlers are written as standalone
> C++ functions (not member functions).  I found this a bit limiting
> since you either have to make the functions friends of your class or
> make any extra data members public (this applies only if you
> subclassed the objects as I did).  What I did was write another set of 
> callback, actions and event handler macros to make them call member
> functions on my subclasses instead of being standalone C++ functions.
I  made dummy callbacks in C that called the C++ member functions.

> The first thing has to do with the destructors.  The only thing the
> class destructors do is remove the widget<->object mapping from the
> hash table.  The object instance will be destroyed but not the widget
> itself.  
This is not an easy problem.  I fouled it up several times.  My solution was
to not actually use the destructor for the widget (except at the very
base class).  Particularly because in some instances I want to do
window cacheing and don't *really* want to destroy the widget.  What
I did was have the object constructor put a delete callback on the
widget.  When I want to destroy an object I call a special deleteWidget
member function.  That function then calls XtDestroyWidget on the
widget, which then calls back to destroy the object when the time
comes.  This allows caching and also ensures that the object doesn't
get referenced after it's been deleted.

> There needs to be more convenence functions/classes added.  Creating
> menus is one places where this is nice.  I have created a menu item
They don't do that?  That's the main reason for using wrappers in 
my mind.  I don't create them for lower class objects, just for the
complicated ones (like list, text, dialog, main window) and for complex
ones like menubar, pulldown, optionmenu.

> window.  Asking for its parent gets a hash table error since there is
> no C++ object for the clip window.
But you need to know the parent for lots of things!  Or does it not
do the convenience widgets like ScrolledText and ScrolledList?

>> in class libraries like NIH.  One function in particular would be a
> overloaded (char*) operator so XMStrings could be easily converted to
> normal char pointers.  In contrast to the WWL, the XMString class has
That can't be done without modifying the header files (since XmString
was typedef'd to char *).  At 1.1.1 it should be fixed to be unsigned char *,
which will allow overloading like that.

Thanks for the summary!

					-kee

P.S.  I should mention that the reason I haven't released my widget classes
is that they are a) pretty tightly bound with very non-widget related
classes and b) only cover the subset of widgets that I cared about.  However
if anyone wants specific examples (menu stuff, or base classes or whatever)
I'd be happy to ship out pieces, but they'll be more useful as a reference
than a toolkit.

ctim@dolphin.aaet.ti.com (Craig Timmerman) (11/20/90)

> > The bindings keep a global hash table of widget id to class instance
> > mappings.  When you call the object's constructor the mapping entry is
> > put into the hash table.  When an object is destroyed the hash table
> > entry is removed.  The bindings use the hash table for mapping Xt
> > calls which return widgets to the objects that you want to really use
> > in your C++ program.
> That sound expensive.  Are all of the X[tm] functions really defined as
> member functions?  E.g. What about XmProcessTraversal (well, I
> suppose that's only 1.1) or XtMapWidget.  If every one of those is
> there that sounds like a fairly heavy object.

I haven't done an exhaustive search, but most of the Xt/Xm calls are
member functions (X11R3 and Motif 1.0 only).  I don't really know what
you mean by heavy.  There is a short stub function for each Xt/Xm call
supported as a member function.  The added code for each function will
add code size, but only once, not per created object.  The objects are
call overhead heavy since the member functions are true functions.
This is one area that should be fixed.  It would be much more
efficient if they were just inlines.  The only true overhead each
object carries are data members for the Widget, arglist, and a
argcount.

> > 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
> But it must produce a dummy callback routine no?  Or does it
> just assume it knows the C++ calling conventions?  Or does it have
> one callback for each signature, which then converts to object and
> calls the C++ callback?

I should have been more explicit here.  The macros you use to define
the callbacks do create normal Xt callbacks.  The macros actually just
define the first three/four lines of the callback (the callback
definition, opening brace, do the widget->object hash table look up).
You provide the rest of the callback code including the terminating
brace.  The thing this scheme buys you is the widget to object
mapping.  All of the code you write/see only deals with the object and
not the widget.

> > The first thing has to do with the destructors.  The only thing the
> > class destructors do is remove the widget<->object mapping from the
> > hash table.  The object instance will be destroyed but not the widget
> > itself.  
> This is not an easy problem.  I fouled it up several times.  My solution was
> to not actually use the destructor for the widget (except at the very
> base class).  Particularly because in some instances I want to do
> window cacheing and don't *really* want to destroy the widget.  What
> I did was have the object constructor put a delete callback on the
> widget.  When I want to destroy an object I call a special deleteWidget
> member function.  That function then calls XtDestroyWidget on the
> widget, which then calls back to destroy the object when the time
> comes.  This allows caching and also ensures that the object doesn't
> get referenced after it's been deleted.

I don't know if I follow all your reasoning here.  Since I create 99%
of these wdiget objects using the new operator they are going to be
around (cached) until I explicitly delete them.  Therefore the
destructor seems to be the right place to put the widget destruction. 

> > There needs to be more convenence functions/classes added.  Creating
> > menus is one places where this is nice.  I have created a menu item
> They don't do that?  That's the main reason for using wrappers in 
> my mind.  I don't create them for lower class objects, just for the
> complicated ones (like list, text, dialog, main window) and for complex
> ones like menubar, pulldown, optionmenu.

I agree fully.  They only provide equvilents for what already exists.
They didn't try to add functionality.  This is probably just because
of time constraints and lack of trying this out on a large scale
product.  All of the demo/test programs that came with it are just
variations on "Hello World".  You don't get a very good feel for what
additions need to be made with tests like that.  This is a major area
for expansion IMHO.  Any expansion should also be done in pure C++.
I.E. Use C++ classes where ever possible. 

> > window.  Asking for its parent gets a hash table error since there is
> > no C++ object for the clip window.
> But you need to know the parent for lots of things!  Or does it not
> do the convenience widgets like ScrolledText and ScrolledList?

It supports all of the widgets.  This is why this is such a big
problem.  I have only run into it on scrolled windows, but any Motif
widget that creates widgets for you will be a problem.  I think it's a
fixable problem (some of the constructors would need to be smarter and
create extra objects), but it's a problem none the less.


----------------------------------------------------------------------
Craig Timmerman 	ctim@aaet.csc.ti.com
Texas Instruments	
Austin, TX		
----------------------------------------------------------------------

nazgul@alphalpha.com (Kee Hinckley) (11/20/90)

> > This is not an easy problem.  I fouled it up several times.  My solution was
> > to not actually use the destructor for the widget (except at the very
> > base class).  Particularly because in some instances I want to do
> > window cacheing and don't *really* want to destroy the widget.  What
> > I did was have the object constructor put a delete callback on the
> > widget.  When I want to destroy an object I call a special deleteWidget
> > member function.  That function then calls XtDestroyWidget on the
> > widget, which then calls back to destroy the object when the time
> > comes.  This allows caching and also ensures that the object doesn't
> > get referenced after it's been deleted.
> 
> I don't know if I follow all your reasoning here.  Since I create 99%
> of these wdiget objects using the new operator they are going to be
> around (cached) until I explicitly delete them.  Therefore the
> destructor seems to be the right place to put the widget destruction. 
That assumes that you always explicitly delete each widget.  In fact this
is hardly ever the case (I mean you *could*, but it would be a pain).  In
fact you are more likely to delete the top-level object and expect all the
others to go away automatically (just like they do in Xt).  Assuming that
this is the case you now have two choices.  You can mimic the Xt hierarchy
and chase down the objects and explicitly delete them.  That would be
wrong.  Or you can tell the widgets to delete the objects when they
get destroyed (via an XmNdestroyCallback).  However if you do the
latter case, then you have the problem of not really knowing whether
this particular object was deleted via 'delete' from your code, or from the
Xt callback.  And you start running into situations where you delete it,
it deletes the widget, the widget callbacks and deletes the object *again*.
Definitely not good.  You can probably work these out, but I found it
easier to never explicitly delete a wrapper object, but instead to call
a method which deletes the widget, which then calls back and deletes
the object.  That ended up being much easier to keep track of.

basti@orthogo.UUCP (Sebastian Wangnick) (11/23/90)

ctim@dolphin.aaet.ti.com (Craig Timmerman) writes:

>> > 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
>> But it must produce a dummy callback routine no?  Or does it
>> just assume it knows the C++ calling conventions?  Or does it have
>> one callback for each signature, which then converts to object and
>> calls the C++ callback?
>I should have been more explicit here.  The macros you use to define
>the callbacks do create normal Xt callbacks.  The macros actually just
>define the first three/four lines of the callback (the callback
>definition, opening brace, do the widget->object hash table look up).
>You provide the rest of the callback code including the terminating
>brace.

As all of you seen to write those wrappers, here's my DM 0,02 worth
of approach: Use static member functions as callbacks. They are C-callable
plus you don't need extra friends.

Sebastian Wangnick (basti@orthogo.uucp)

PS: inews hack
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................