A Tcl Binding to Motif

Jan Newmarch
University of Canberra

Introduction

The X Window System is now accepted as the standard windowing systems for
Unix graphics workstations and terminals. It provides a low-level set of
tools to build applications. Most applications now are built using a
higher-level toolkit which typically supplies objects usually known as
widgets. There are a number of such toolkits, but the one that has achieved
the major success is the Motif toolkit based on the Xt Intrinsics. Motif
has defined a look-and-feel that is copied to a greater or lesser extent by
other toolkits, and forms a component of specifications such as COSE.

The specification for Motif basically assumes a C-like language, and the
only implementation of that specification is the C library from OSF. This
has led to many bindings to this library from alternative systems. These
include even higher-level systems that can be ported across different
window systems, to specific language bindings. These include C++, Ada,
Prolog, Lisp, Poplog and the Korn Shell.

Tcl (Tool Command Language) is a type-free interpreted language that was
designed to be embedded into applications requiring a command language for
communication with users, to parse specification files requiring
language complexity, and to provide a macro language for applications such
as spreadsheets. The intent was to do it right once, so that
application-writers need not invent their own language and write their own
parsers and semantic evaluators.

Tcl has been extended with an X Window toolkit not based on the Intrinsics,
that supplies a set of widgets directly accessible from tcl. This Tk
toolkit is generally run from a program called ``wish'' that sets up a
suitable environment and then calls an event processing loop for the Tk
widgets.

However, there are differences between Tk and Motif, some minor and some
major. These differences are no better nor worse than the differences
between other toolkits such as InterViews, but do seem to give
rise to some heated debate at times. For example, there is the claim that
Motif must be slower than Tk because of the complexity of implementation
above Xt. On the other hand, it must be faster because Tcl/Tk is
interpreted. Tcl/Tk programs are often pointed at as significantly shorter
than equivalent Motif programs, without determining whether this difference
is caused by choice of language - C versus Tcl, or choice of toolkit -
Motif versus Tk. Other issues such as the complexity of Motif XmStrings
against their value for internationalisation are often discussed.

This paper reports on a project that attempts to remove some of the
variables from this debate. It provides a binding of Tcl to Motif so that
Tcl programs can be written directly using the Motif C libraries. This
binding is by a library of C functions called Tm (Tcl Motif). The focus
in this paper is on the mechanisms of this implementation, but some
discussion is given to the language against toolkit debate.

Recently the author became aware of the Wafe system, which was a binding
of the Athena widgets to tcl. This project had different aims to this
one, but there are many common elements. This is also discussed.

Elements of tcl

Elements of Motif

Elements of Tk

The moat Interpreter

Tm borrows heavily from Tk in many places. Tk has an interpreter called
``wish'' (Window Shell) that sets up the Tk world, sources a Tcl/Tk file
and then enters a Tk event processing loop. This is sufficiently general
that many useful Tk programs can be written just using ``wish'' as
application environment. Problems requiring a richer environment may use a
modified ``wish''.

Tm uses this idea and supplies an interpreter called ``moat'' (MOtif And Tcl)
This sets up an Xt world by calling XtAppInitialize, creates a
Tcl interpreter, sources a Tcl file, realizes all widgets and then enters
the Xt event loop.

Creating Widgets

Widgets are created using Tcl commands registered with the Tcl interpreter
on initialisation.  These creation commands follow the design of the Tk
system, in that there is one creation command per class of widget. In
addition, Motif has a set of dialogs, which are convenience routines for
creating a compound widget in a way that is supposed to be invisible to the
C programmer and act as though they create single objects. These routines
are also implemented as widget creation functions in Tm. It is not hard to
``special case'' some functions within Tm to handle these dialogs.
Motif also ``special cases'' two common operations - creating a ScrolledList
and a ScrolledText widget. This is also handled by Tm. In both of these
special cases, the parent is brought into the Tm system, and is given a
unique name. This name is produced from the pathname by introducing an
extra dot into the path.

Widget Commands

When a widget is created two major things occur: an Xt/Motif widget is
created and a command with the widget name is added to the Tcl interpreter.
This gives an object-oriented flavour to the system in that a widget becomes
a command which is interpreted as an object with methods.


Widget Methods

Each widget has a set of methods applicable to it. In general, most widgets
inherit from TmCore. This allows Xt methods such as ManageChild and
UnmanageChild to be handled from one function.  The design of Tcl registers
a command handler per command; widgets that have no special methods simply
register the TmCore handler. Widgets with more methods register a different
handler which may call TmCore eventually in an inheritance chain.

Each widget in fact has special methods: the callback procedures for that
class. This is handled by TmCore rather than in individual command handlers
because of regularities in the implementation of Motif that are better
discussed in the next section. Briefly, each callback can be recognised because
it ends in the string ``Callback''. This can then be added to the Xt widget
callbacks using XtAddCallback in the TmCore handler, without worrying about
exactly which callback it is.

In C, when a callback is added to a widget a specific C function is
specified that will be invoked when the action for that callback occurs.
However, we want a Tcl function to be executed. This is easily done by
using a generic C callback function that handles every widget, almost
without exception. When a callback is added in Xt, the ClientData field is
set to point to a structure containing the Tcl interpreter and the string
that is the Tcl callback function. This gives the generic C callback
fucntion enough information to execute the Tcl function.

Resource Converters

The presence of resource converters within Xt is the key to the ease with
which this binding has been implemented. Previous sections have used
existing Tcl/Tk concepts (and code) to a large extent. It is now time for
Xt to play a significant part. Xt allows users to store resource values in
files such as .Xdefaults to control run-time values for the program. This
user-level control is one of the major features of Xt. The resource files
contain strings representing the values the user wants. For example, a
width may be set to the string "200". Xt, and all toolkits built above it,
supply ``resource converters'' to transform these string values into the
internal data types required by the program.

To perform such conversions, Xt supplies a number of useful functions.
XtGetResourceList and XtGetConstraintList return lists of resources
applicable to each class of widget. Elements in these lists are structures
that contain strings representing the source and destination types, and
the size (in bytes) of the destination type. The string representations
allow searches for source types, and the structure when located in the list
provides enough information to call XtConvertAndStore. This looks up a list
of registered converters and calls the converter function if found.

This makes one side of this binding trivially simple: if a resource can be
specified in a resource file then a converter exists from string to
internal value. The Tcl setValues function simply has to locate the
resource in these resource lists and call XtConvertAndStore. It can then use 
XtSetValues to install the converted value, and Xt and Motif do the rest!

This also makes the naming conventions in tcl very easy. Because resources
are specified as strings, the names can be used by tcl without change.
Motif is quite consistent in its use of these names (alphabetic only,
beginning with a lower case letter, and with other words in the name
capitalised). Tk uses this convention as well, so the similarity in
programs across the two systems is maintained.

Well, it isn't really trivial. Some resources require widget values, such
as edge bindings in Form. Tm needs to supply another converter, from
TmWidgetName to Xt Widget. This, and similar needs are answered by just
adding more converters. A more serious problem is addressed in the next
section.

The largest amount of work in this binding is in implementing getValues.
This requires conversion from internal type to strings. For many types
such as Dimension there is no support from either Xt or Motif. However,
for enumerated types such as arrowDirection for the ArrowButton widget,
Motif not only gives ``Representation Type'' converters for conversion
from String to enumerated type, but also allows converters in the reverse
direction to be installed, so that names such as ``arrow_left' can be
generated. This was intended for GUI building systems which need to use
symbolic names when setting or getting widget values, but it suits tcl
very well, thank you.

Secondary Resources

Xt allows objects to have subobjects. There are not many examples of these.
Editors with Output subobjects and Input subobjects are the principal
ones. The nasty part is that these subobjects can have their own
resources and Xt supplies no means for an application to access them.
Xt has a ``hook'' to allow the toolkit library to access them, but not the
application (in Motif at any rate they are static to a file, so there is no
direct way of accesing them). Fortunately, Motif (not Xt) supplies
the function XmGetSecondaryResources to get these.

Special Cases

Convenience functions

{Scrolled List, Dialogs}
Motif supplies convenience functions of several types. Some such as the
various RowColumn functions of XmCreateMenuBar, XmCreateOptionMenu, etc
just set extra parameters for RowColumn and are easy to handle. Two other
sets are the ScrolledObject functions such as XmCreateScrolledList and
XmCreateScrolledText and the Dialog convenience functions such as
XmCreateFormDialog etc. Both of these sets of functions create a pair
of widgets, not just a single one. For example, XmCreateScrolledList
creates a ScrolledWindow parent and the List child, whereas the Dialog
functions create a Popup shell parent. In all cases, the Create function
returns the child widget.

The intent in Motif was to hide the parent widgets. Unfortunately it canot be
done completely for several reasons. Firstly, when the ScrolledList (or any
of the others) is destroyed, it is the parent that must be destroyed, not
just the child. Otherwise a memory leak occurs. Secondly, when you need to
set constraint resources (such as placing the ScrolledList into a Form), it
is the parent widget that needs resources set, not the child. Thus a
mechanism to access the parent is required.

In Motif, this may be done by the call XtParent, which returns the Xt
widget parent. In this binding it is neccessary to return a tcl widget
parent, and this may be a problem. The tcl parent must be generated
automatically, but must be guaranteed unique. Otherwise there may be an
accidental name collision with other tcl widgets. The Motif naming
mechanism (tacking ``SW'' onto Scrolled Objects, ``_popup'' onto dialogs)
does not guarantee this. Fortunately, the particular naming syntax used in
this binding (based on Tk), where widget names are separated by dots ``.''
does allow this, by inserting an extra dot. For example,

scrolledList .l
puts stdout [.l parent]

produces the unique `..l''.

Timing conversions

Some resources can only be set at creation time. Such resources are of two
types: the first is exemplified by ... in which the value of this resource
is used during the Initialize function and is thereafter unused. The second
is one that cannot be changed because it has too many ramifications. Such
a resource is the ScrollingPolicy of the ScrolledWindow widget. These
resources must be converted from their String value to be used in the Args
array to the XmCreate... function.

On the other hand, some resources use widget values in their calculation.
For example, any Dimension or Position resource such as the width uses the
Motif UnitType resource in its calculation, in order to gain independance
of the display size characteristics. Similarly, the LabelPixmap resource of
Labels needs to have a foreground and background before it can be created.

These differing cases cause a problem. The convertor functions from String
to Value use a widget parameter, and in the first case this can only be the
parent (as the child Create function cannot have been called yet) whereas
in the second it requires the widget itself. The special case code to
handle this is not only a maintainance problem, but is not guaranteed to be
correct in the first place as neither Motif nor Xt offer any support to
distinguish the cases (the recently released WKSH also faced this problem
and missed the LabelPixmap case, probably because it is quite well hidden
in the Motif source).

This binding divides the resources into ones which must be converted before
creation, those that must be converted after creation, and those for which
it does not matter. These are all handled correctly. A case which is not
handled is where the conversion must be done during creation.
Fortunately this does not occur, as it would break any bindings such as
this one that rely on the resource converter mechanism.

XmStringTables

Various widgets such as ScrolledList use XmStringTables, which are arrays
of XmStrings. Motif is inconsistent in its internal use of these arrays -
sometimes they are NULL-terminated, most times they are not. This means
that there is no way of determining from the XmStringtable itself exactly
how many elements it contains. This must be found from other means. For
example, the size of the List resource ``items'' is found in the List
resource ``itemCount'', and the size of the ``selectedItems'' resource is
found in the `selectedItemsCount'' resource. When an XmStringTable is
converted into a String, this size must be known to the resource converter.
This could be determined from the widget type and resource name (eg for
``items'' of a List widget, determine it from ``itemCount''), but the
resource name is not available to the resource converter. Thus special case
code must be inserted before any  resource converter can be called, just in
case it is one of these cases. This is inelegant and an overhead in time
for all of the resource conversions, whatever type.

Text Verify Callbacks

Motif callbacks provide extra information through the callback data. This
is generally a pointer to a structure specific to the widget type. Fro
example, the PushButton callback structure contains a field ``click_count''
to allow distinction between single and multiple clicks. Generally these
structures contain ``read only'' information that is not to be modified.

The Text widget has a set of ``verify'' callbacks that point to read/write 
structures. The purpose of these is to allow for things such as password
entry, where the application needs to be given the characters typed in, but
must be able to signal to Text not to echo these characters. This is done
by setting the ``doit'' field in the XmTextVerifyCallbackStruct to False.
These calllbacks are actually called by Motif in an unusual way: for
example, when characters are typed in Motif decodes the characters, calls
the modifyVerifyCallbacks, examines the return state of the callback
structure and only then actually inserts (or not) the characters typed.

This is handled by creating a global variable and passing its name (rather
than its value) into the callback. The application can then modify its
value, and this is used to set the Motif fields as appropriate. The Motif
mechanism is odd in this respect, and the tcl binding shows this in
practice.

Inconsistencies and Bugs

By and large tcl and Motif work well together. One area that does not integrate
perfectly concerns lists. In Motif there are sometimes lists of XmStrings, and
when they are represented as strings individual elements are separated by
commas.  tcl on the other hand represents lists as elements separated by
whitespace.  Both handle lists containing whitespace in different ways, with
the tcl solution being more general. Motif would have (say for a list of
authors of Motif books)

Dan Heller, Jan Newmarch, Thomas Berlage

tcl would have

{Dan Heller} {Jan Newmarch} {Thomas Berlage}


Hiding Complexity

One of the hurdles in any Xt program is the complexity of concepts in even
a trivial program. The Tk library hides parts of this by placing initialisation
and the event loop handler into the ``wish'' intepreter, and by making the
callback mechanism simpler. The Tm library copies most of this, and so achieves
the same simplicity in this respect.

Motif adds further layers of complexity above this. A particularly tricky 
hurdle to overcome is the support for internationalisation offered by
XmStrings. The Tm library handles XmStrings internally, and uses the normal
tcl String mechanism for all purposes. Thus this mechanism is hidden from
the tcl programmer. It is still present in Motif, so a Label widget can
display Japanese text as specified in a resource file. The ability of tcl to
manage this is still in doubt (it is at least 8-bit clean, and Tk can use the
X11 support to display ISO 8859-1 characters).

Validation

The Tm library is built on Motif. Can it be certified as Motif compliant?
Well, actually, no. This is basically a library into Motif, and as such
must be compliant with the AES (Application Environment Specification).
The AES details what functions a Motif library must make available, and this
binding falls short of that. For example, Tm hides XmStrings and has no
explicit support for them. So it fails the test of ``coverage'' as you can't
do everything in Tm that you can using the OSF C library.

On the other hand, applications built using this library can be certified
as Motif compliant. Application compliance just means that *out of the
elements of GUI used*, these conform to the Motif Style Guide. You can
really muck up a Tm application by putting the menu bar at the bottom, with
the Help button on the left and even worse things, and these will fail to 
give you Motif compliance, but if you aren't that silly you will be able
to get Motif certification for applications built using Tm.


Wafe and WKSH

The WKSH is a binding of the Korn Shell to Motif. It deals with the same
problems as this binding, in that it has to convert Strings to Motif types.
It appears to use the same mechanisms, and has run into the same problems.
For example, it handles the Conversion versus Creation problem for
resources such as width by disallowing setting of such
resources during creation! In this binding it is deferred until it is
valid. The lack of support by Xt and Motif in this area is evidenced by the
failure of the WKSH to correctly handle the LabelPixmap resource in its
initial release.

WKSH models itself on the syntax of the Motif C language binding. The
function calls use the same names, such as XmCreateMainWindow. The binding
also partly preserves the positional syntax of the C language, so that a C call

w = XmCreateLabel(parent, name, args, argc)

becomes

XmCreateLabel parent w name args...

The WKSH binding actually adds an extra argument to replace the return value of
the function, and uses the varargs style of argument passing that has
become quite popular within the X world.

The WKSH binding follows this even further in defining functions such as
XtManageChildren which place the action followed by arguments.

The Wafe binding follows this same principle of action followed by object,
but without the positional argument complexity of WKSH. This particular
binding seems to have suffered confused press in that it produces a Tcl
binding to Xt on one side, and an open-ended binding of Tcl/Xt to
almost any language on the other. This generality seems to have led to
impressions such as "it is a way of writing Perl programs that use Tcl to
talk to Xt". The current status of Wafe is that it binds Tcl to a variety
of Xt-based widget libraries, with Athena being well supported, and Motif
in beta. The Wafe callback model is very different to Tm. In Tm, the Motif
style is followed in that the callback contains useful information and
helps to give the ``feel'' part of the ``look and feel'' paradigm. Wafe
uses a limited set of callbacks to produce popup dialogs.

In implementation, the Wafe and Tm systems follow very similar lines as
there is really only one way of doing much of the binding of Xt toolkits to
string languages such as Tcl and Ksh. The authors of Wafe suffer the problem
of only having access to Motif
1.1 at the time of writing, so the additional aids supplied in Motif 1.2
are not available to them. This is a distinct drawback. I am in active email
correspodence with them, to avoid duplicating work.
