A Tcl Binding to Motif

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 and Motif, 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. The focus
in this paper is on the mechanisms of this implementation, but some
discussion is given to the language against toolkit debate.

Elements of tcl

Elements of Motif

Elements of Tk

The Tm 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 ``mish'' [what a lousy
name!!]. This sets up an Xt world by calling XtAppInitialize, creating a
Tcl interpreter, sourcing a Tcl file and then entering 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.

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.


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 calls 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 as
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
aplicabel 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 the resource lists and call XtConvertAndStore. It can then call
XtSetValues to install the converted value, and Xt and Motif do the rest!

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
ading 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. Motif may offer
more support than I know of, in that deep and dark corner over there...

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


Bugs
Validation
