tclMotif

Section: User Commands (1)
Updated: 18 November 1993
Index Return to Main Contents

 

NAME

tclMotif - the binding of tcl to the Motif widget set.

 

Introduction

This is a binding of the Tcl language to the Motif widgets. Tcl is an interpreted language originally intended for use as a command language for other applications. It has been used for that, but has also become useful as a language in its own right.

Tcl has been extended by a set of widgets called Tk. The Tk widgets are not based on the Xt Intrinsics, but are built above Xlib. They allow an easy way of writing X Window applications.

The standard set of widgets in the X world is now the Motif set. This forms a large set of widgets, and these have been through a large amount of development over the last five years. Use of this set is sometimes a requirement by busineses, and other widget sets try to conform to them in appearance and behaviour.

This system allows the programmer to use the Motif widgets instead of the Tk widgets from Tcl programs. This increases programmer choices, and allows comparison of the features of both Tcl and the Tk/Motif style of widget programming. The binding gives the full set of Motif widgets, accessible through the simple interpreted Tcl language.

 

Acknowledgments

This system is based on Tk for the style of widget programming. This was because it provides a good model, but it also allows the Tcl programmer to move relatively easily between Tk and Motif programming. An alternative style of binding to Motif is used in the WKSH system, which performs a similar sort of role for the Korn Shell. The WKSH is much closer to the C API for Xt than is Tk. An intermediate style is provided by the Wafe binding of Xt-based widgets to tcl.

The documentation is incomplete (and is likely to be for a very long time). Consequently the programmer will probably need to refer to the Motif Programers Reference Manual. The system has been designed so that it is relatively easy to translate the C-based information in this manual into the corresponding Tcl information. This has been aided by the consistency with which Motif has been implemented in certain areas.

 

Running Tcl/Motif programs

Tcl/Motif programs may be run by the `moat' (MOtif And Tcl) interpreter. When called with no arguments it reads Tcl commands from standard input. When called by

moat file-name

it reads Tcl commands from `file-name' and executes them. This is the same as any other extension to ``tclsh''.

The standard Xt command line options may appear after the file-name, as in

moat file-name -width 200 -height 100

Depending on your shell interpreter, you will probably be able to run Tcl/Motif programs as standalone programs. If your moat interpreter is installed in say `/usr/local/bin/moat', make this the first line of your executable program:

#!/usr/local/bin/moat

 

The Motif world

In earlier versions than 0.8, a specialised interpreter was used, much like Tk's ``wish''. To conform to the new extension methods of tcl7.0, this was changed. Part of the result of this is that the Xt world has to be explicitly brought into existence. This also allows the class and fallback resources to be set, and leaves hooks for things like setting the application icon to be added later to this binding.

The three world manipulation functions added are

xtAppInitialize
. realizeWidget
. mainLoop

xtAppInitialize may take parameters of -class, -fallback_resources and -options. If the class option is omitted, the binding will deduce a class by capitalising the first letter of the application name, and - if it was an `x' - also capitalising the second letter. The -fallback_resources may be used to set resources in case there is no application defaults file or user file setting them. The -options may be used to set additional application resources for later retrieval by the root widget method getAppResources.

A typical tclMotif program has the structure

# tcl function definitions # ... xtAppInitialize -class MyClass # widget creation commands # ... . realizeWidget . mainLoop

 

Widget naming

Widgets are visual objects that exist on the screen. They are organised as a hierarchy, with the application itself forming the root of this hierarchy. The naming of objects within this hierarchy is similar to the ``absolute path names'' of Unix files with a `.' replacing the `/' of Unix. The application itself is known as `.'. A Form in the application may be known as `.form1'. A Label in this form may be `.form1.okLabel', and so on. Note that Xt requires that `.' can only have one child (except for dialogs). This naming convention is the same as in Tk.

 

Widget creation

Widgets belong to classes, such as Label, PushButton or List. For each class there is a creation command which takes the pathName of the object as first argument with optional further arguments:

xmForm .form1 xmLabel .form1.okLabel xmLabel .form1.cancelLabel \ -labelString "Get rid of me"

creates a Form `form1' as child of `.', and two Labels `okLabel' and `cancelLabel' as children of `form1'. The `cancelLabel' has additional arguments that set the labelString to "Get rid of me". Note that the continuation character `\' may be used to spread a line over several lines.

The set of classes generally mirrors the Motif set. Some widgets in Motif and Xt are not accessible from this binding because they are intended for use in inheritance only, such as Core and Primitive. The types of widgets that can be created using this include the primitive widgets:

xmArrowButton - a simple arrow, xmDrawnButton - a button with graphics in it xmCascadeButton - for use in menus xmToggleButton - for on/off boxes xmLabel - a fixed piece of text xmText - a text editor xmTextField - a one line text editor xmSeparator - for simple lines between objects xmList - a list selector xmScrollBar - a horizontal or vertical scrolling bar

and the Manager widgets:

xmBulletinBoard - simple geometry management xmRowColumn - regular geometry management xmPanedWindow - multiple panes separated by sashes xmFrame - a 3-D border xmScale - a slider on a scale xmScrolledWindow - for displaying a clip view over an area xmMainWindow - contains a menu bar and the main application windows xmForm - for irregular geometry arrangements xmMessageBox - message display area xmCommand - a command entry area with a history list xmFileSelectionBox - selection of a file from a list

Motif has two special commands for creating a ScrolledList and a ScrolledText. These commands actually create a pair of widgets: a List or Text inside a ScrolledWindow. To create such widgets is similar to the C binding: the List (or Text) widget name is given. If the parent ScrolledWindow is required then you have to call the ``parent'' method on the List or Text widget.

xmForm .form1 xmScrolledList .form1.list2 [.form1.list2 parent] setValues -attachTop attach_form

Motif also has convenience functions that create dialogs. These don't create ordinary widgets, but Motif pretends that they do. TclMotif follows this, and allows you to use commands such as

xmQuestionDialog .askMe

to create such dialogs. When you have to destroy such widgets, destroy the parent:

[.askMe parent] destroy

This set of dialogs includes:

xmBulletinBoardDialog - a dialog with arbitrary contents, based on bulletinBoard
xmFileSelectionDialog - a dialog based on fileSelectionBox
xmFormDialog - a dialog based on form
xmInformationDialog - a dialog displaying information
xmMessageDialog - a dialog showing a message
xmPromptDialog - a dialog with a prompt area
xmQuestionDialog - a dialog asking a question
xmSelectionBoxDialog - a dialog based on selectionBox
xmWarningDialog - a dialog showing a warning message
xmWorkingDialog - a dialog showing a busy working message

For example, consider a rowColumn containing two labels and a pushButton, where the rowColumn is inside a mainWindow:

xmMainWindow .main xmRowColumn .main.rowcol xmLabel .main.rowcol.label1 xmLabel .main.rowcol.label2 xmPushButton .main.rowcol.btn

Not all objects used in the OSF C library are supported: gadgets are not supported by TclMotif, nor are the ``simple'' menu functions. These are design decisions: I don't like gadgets because they place extra processing code and complexity on the client-side Motif library, the need for which has been largely removed by improvements in X servers; I don't like the simple menu functions very much either because they are yet another attempt to fix up a complex system to which lots of people already have their own solutions, and it is not clear that this is a ``better'' one. I doubt if reversal of these would cause too many problems, but I don't feel like investigating them yet.

 

Managing widgets

Before a widget can be displayed, it must be brought under the geometry control of its parent (similar to placing a Tk widget). This can be done by the ``manageChild'' method of each widget, but also by an optional third command to each widget creation function, similar to the XtCreateManagedWidget functions. For example,

xmLabel .l1 managed xmLabel .l2 .l2 manageChild

 

Documentation


  The widgets described above not only look and act the same as the Motif widgets, they are the Motif widgets. So descriptions of them in any Motif book or reference apply. In the Motif Programmers Reference these widgets are described under the same names, with the initial `x' capitalised as in XmPushButton. The creation functions are prefixed by ``XmCreate'' as in XmCreatePushButton.

The TclMotif documentation is at present incomplete. There should be a man page for each widget, under the name of the widget prefixed by ``Tm'' as in TmPushButton.

In addition, there are additional manual pages. The entry for ``moat'' describes the interpreter that will generally be used for TclMotif. The entry for TmRoot describes the commands available for the root widget ``.''. Such commands usually apply to the Xt application context.

 

Widget commands

Creating a widget actually creates a Tcl command known by its pathName. This command may be executed with at least one parameter to either change the behavior of the object or the value of its components, or to get information about the object. The parameter acts like a ``method'' to the object, and specifies an action that it should perform. The parameters that are recognised by every object include:

unmanageChild - remove the object from its parents geometry management, which makes it disappear from the display
manageChild - bring it back under geometry management and make it appear again
mapWidget - remain under geometry management, but make it disappear
unmapWidget - make it reappear
realizeWidget - create windows for the widget and its children (usually used only by ``.'')
getValues - obtain properties of the widget
setValues - set properties of the widget
parent - return the parent of the widget
destroyWidget - destroy the widget and all its children
setSensitive - change the sensitivity of the widget to responses to input
callActionProc - call an action procedure (usually used in regression testing)
dragStart - used in drag and drop
dropSiteRegister - used in drag and drop
getGC - return a graphics context (used for drawing in DrawingArea and DrawnButton)
resources - return a list of all resources. Each resource is a list of the resource name as used in setValues/getValues, the resource name as known internally to Motif, the resource class, the resource type as known to Motif and the value of the resource. In cases where this value does not make sense (eg a bitmap), a null string is returned.
any string ending in ``Callback'' - register Tcl code to be executed when something happens to the widget.

For example,

.form1.okLabel unmanageChild .form1.okButton activateCallback \ {puts stdout "I was pushed into it..."}

Unmanaging a widget removes it from the display, and from the geometry management of its parent. Managing it reverses this. The other methods are explained later.

 

Other widget commands

The root widget ``.'' has a number of commands unique to it. Generally, these are commands that use the application context (moat only uses one application context). These commands include

addInput
removeInput
mainLoop

Both Text and List have a large number of other commands due to the complexity of these widgets. Other widgets also have special methods. See the manual pages for further information.

 

Widget resources

Each widget has a set of resources that can be set at creation time, set at a later time, or queried for their value. For example, an xmPushButton has a width and a height, a labelString that is the text that will show in it, a foreground and background colour, a fontList giving the set of fonts that will be used to draw the text, and so on.

All resource names are prefixed by a minus `-' in Tcl programs, for consistency with the Tk widgets. On setting a value, all resources take the next word as value, and on getting a value the next word is the name of a variable to store the value in.

On creation, the resource/value pairs come after the widget pathName, as in

xmLabel .okLabel -labelType pixmap -labelPixmap xlogo32

which sets the labelType to pixmap and the labelPixmap to xlogo32.

Resources can be set at any time using the setValues method

.text setValues -editMode editable -value "Some text"

which ensures that the text widget can be edited, and sets a value of "Some text".

Resources can be obtained from the widget using the getValues method. For example

.fileSelectionBox getValues \ -dirSpec file_selected \ -directory dir

stores in the Tcl variable file_selected the filename that was entered, and in the Tcl variable dir the directory in which the file selection occurred.

Each widget inherits resources from superclasses. For example, Label is a subclass of Primitive which in turn is a subclass of Core. From Core it inherits resources such as background, height and width. From Primitive it inherits resources such as foreground. It is neccessary to look at these superclasses. In addition, each class adds extra resources. For example, Label has the additional resources labelType, labelPixmap and labelString, among others.

Resources are documented in the Tm man page for each widget. This documentation is weak.

Resource names can be obtained from the Motif documentation for each widget. The Motif documentation for each widget has a set of tables headed ``Resource Set''. In the table of resources, the names of these are given prefixed by ``XmN'', such as XmNeditMode. Drop the prefix to get the Tcl resource name. Case is important here.

Resource values can also be obtained from the Motif documentation. For each resource look at its type. Types such as Dimension and Position are numeric types, and along with int types need an integer value. In the Tcl program they are implemented as Tcl strings, as is everything. In fact, all resource values are Tcl strings. Pixmaps, for example, are the string name of a pixmap such as ``xlogo32''. Pixel is a color such as ``blue'', or a hexadecimal representation of the color. Types such as the arrowDirection of an ArrowButton form a discrete set with values listed as XmARROW_UP, XmARROW_DOWN, etc. For these types, drop the ``Xm'' and use the rest of the string as the value. On setting values, case is not important but on getting values the string will be lower case for these discrete types.

So for example, a pushButton may have

xmPushButton .btn -width 100 .btn setValues -labelString "Push Me" -foreground red .btn getValues -background bg puts stdout "background colour is $bg"

 

Callbacks

When the user does things to a widget, it may cause the widget to take certain actions. For example, when a button is pressed it changes appearance to look pressed in. Some of these actions can have Tcl code attached to them, so that the Tcl code is evaluated when the action is performed. The Tcl code is attached to a ``callback'' by a widget command. For example, a pushButton has an activateCallback that is called when the user presses and releases the left mouse button inside the widget; it has an armCallback that is called when the user presses the mouse button; it has a disarmCallback that is called when the user releases the mouse button inside the widget.

Tcl code is attached to a callback by giving it as the second argument to the appropriate widget methodod. For example,

.btn armCallback {puts stdout "Stop squashing me!!!"} .btn disarmCallback {puts stdout "That's better!"}

There are two ways of specifying the Tcl code: as above, giving all the code as a single word (including a list or a string), or as individual words:

.btn armCallback puts stdout "Stop squashing me!!!"

The names of the callbacks available for a particular widget are derived from the resource documentation for the Motif widget. Each callback ends with the string "Callback" in its name. Drop the "XmN" from the Motif description to gain the widget command. Callbacks are treated differently to other resources because the Xt toolkit treats them differently - the resource is not meant to be handled directly by any ordinary application.

 

Callback substitutions

Motif supplies information to each callback function that is specific to the widget type. Generally this is not of much interest. However, for some widgets such as List this is used to supply important information, such as what item in the List was selected! To make this available to the Tcl callback function a pattern substitution mechanism may be used. Any ``%'' followed by a word will be treated as a pattern for potential substitution. For example, ``%item'' in a List will be replaced by the item selected, and ``%item_position'' will be replaced by its position in the list. An example list callback is

.list singleSelectionCallback \ {print_info %item %item_position} proc print_info {item position} { puts stdout "item was $item, at position $position" }

The substitutions allowed may be found from the Motif documentation. In the description of callback information one or more structures will be defined. The field names in these structures are the names used in ``%'' substitutions. Not all of the possibilities are implemented yet. This is admittedly obscure and not easy to find, so the TclMotif documentation needs to fix this lack. If you feel upto reading C code instead, the upto date ``list'' is found in the file ``tmExpand.c''

Every callback supports a substitution of ``%call_data''. This is a keyed list of all valid values in the callback structure. It is a list of two-element lists, where each two-element list consists of the name of the field followed by its value. For example, for an arrowButton it could be

{ {reason activate} {event event-12345} {click_count 1} }
(the event value is a pointer to the Xlib data structure which may be used by tclMotif, but is not expected to be examined by a tcl program.)

Some callback information is actually contained in the event that caused the callback to occur. The event may be obtained from the substitution %event. A tcl command ``xEvent'' may then be used to access the fields of the event. This command takes the event and an argument which is identical to the Tk % substitutions. For example, to extract the x coordinate from a motion event while in the callback, one could have

$w setValues \ -translations "<Motion>: action(trackit %event)" proc trackit {event} { set x [xEvent $event x] puts stdout $x }

 

Text verify callbacks

The Text widget allows special processing by the application of text entered. After a character has been typed, or text pasted in, initial processing by the Text widget determines what the user is entering. This text is then passed to special callback functions. These functions can make copies of the text, can alter it, or can set a flag to say do not display it. Simple uses for this are a password entry widget that reads the text but does not display it (or echoes `*' instead), or text formatting widgets.

The callback mechanism for this is basically the same as for other callbacks, and similar sorts of substitutions are allowed. For example, the term %currInsert is replaced by the current insertion position. Other substitutions do not give a value, but rather give the name of a tcl variable. This allows the application to change the value as required. The tcl variable is in the context of the callback caller, so upvar should be used. For example, to turn off echoing of characters, the following should be done:

.text modifyVerifyCallback {no_echo %doit} proc no_echo {doit} { upvar 1 $doit do_insert set do_insert false }

(Actually, the tcl variable here is the global variable ``_Tm_Text_Doit''. For this reason, variables beginning with ``_Tm_'' are reserved for use by the TclMotif library.)

Other substitutions that can be made in the modifyVerify callback are ``ptr'' and ``length''. ``ptr'' is the string that is being entered, and ``length'' is its length. These may be changed by the callback procedure. For example, to change all incoming text to uppercase,

proc allcaps {ptr length} { upvar 1 $ptr p upvar 1 $length l if {$l == 0} return set upper [string toupper $p] set p $upper } .text modifyVerifyCallback {allcaps %ptr %length}

 

Compound Strings

Motif uses two types of strings: ordinary text and Compound Strings. Ordinary text is used by widgets such as Text. This is 8-bit text, using a character set such as ISO-8859-1. Most other widgets use a format called Compound Text (or XmStrings) that allows the embedding of fonts, directions, newlines (and under Motif 2.0) colours and tabs. Examples are the labelString of the Label widget, the messageString of a MessageBox, etc. In versions prior to version 1.2 of tclMotif this possible information was ignored. From version 1.2, it is used, so that the programmer has to be aware of the difference in behaviour between Compound Text (or XmStrings) and ordinary text.

A compound string is treated as a tcl list of words. The words are concatenated with single spaces between them. If a word contains white space itself, this is preserved. For example, to set a label with and without preserved spacing,

.label setValues \ -labelString { string with single spaces between words and no newlines} .label setValues \ -labelString {" string with newlines and extra spaces"}
The list operator may be used to take an existing string and turn it into a list of one element consisting of the string with its preserved white spaces.

The symbol `@' beginning a word signals a format change. @n is a newline, @r sets direction to right-to-left, @l sets direction to left-to-right, @f signals a font change. @fX changes to the one-letter font X, @f(XY changes to the two-letter font XY, and @f{XYZ} changes to font XYZ, for any name length. The font is specified in the widget's fontlist

.label setValues \ -fontList "9x15=R, 9x15bold=bold" \ -labelString "ordinary @r right-to-left @f{bold} right-to-left bold text @fR @l ordinary font, left to right"

 

Dialogs

Selection Box has a number of component children, which may be managed or unmanaged by the application. If the SelectionBox was named .sel, these are

.sel.Items .sel.ItemsList .sel.Selection .sel.Text .sel.Separator .sel.Apply .sel.Cancel .sel.Help .sel.OK

The same applies to Message Box. These widgets are often managed or unmanaged to add or remove elements from a dialog. Each of these children is created with a method handler appropriate to the type of child. However, Motif documentation states that no assumptions should be made about this type, so you should check the type before using a widget-specific method. For example, the ItemsList in a SelectionBox is currently a Motif List. To set the selectedPosition, one can use a List method:

xmSelectionBox .selBox managed selBox.ItemsList setValues \ -items {a b c d} \ -itemCount 4 if {[.selBox.ItemsList class] == "XmList"} { .selBox.ItemsList selectPosition 4 false }

Whatever the type, the set of methods of the tclMotif Core widget are supported. In particular, the methods ``manageChild'' and ``unmanageChild'' are available.

 

Actions

Actions may be added to a widget in a similar way to the C version. In that you define an action in a translation table which is set in the widget. You then have to register the action with the toolkit so that it is attached to a C function. In this binding, the tcl code is placed as the arguments to the action in the translation table. Registering the action links a generic action handler which in turn will handle the tcl code. Here is what it looks like to add an action to make an arrow turn left or right when `l' or `r' is pressed:

xmArrowButton .arrow managed .arrow setValues -translations \ "<Key>r: action(arrow_direction %w arrow_right) \n\ <Key>l: action(\"arrow_direction %w arrow_left\")" proc arrow_direction {arrow direction} { puts stdout "Changing direction to $direction" $arrow setValues -arrowDirection $direction }

The pattern ``%w'' is substituted for the name of the tcl widget. More substitutions may be added in later (eg for x, y).

 

Examples

A number of examples are in the programs directory. Those with `DH' in them duplicate the examples in Dan Heller's ``Motif Programming Manual'', O'Reilly & Associates Inc. Those that are just numbered are undocumented test programs. They may not behave in a nice way, but that doesn't matter too much.

The following example is in the programs directory as progEG. The typical structure of a Motif program is that the top-level object is a mainWindow. This holds a menu bar, and a container object such as a form or a rowColumn which in turn holds the rest of the application objects. So a mainWindow with a list and some buttons in a form would be created by

xtAppInitialize -class Example xmMainWindow .main xmForm .main.form xmList .main.form.list xmPushButton .main.form.btn1 xmPushButton .main.form.btn2

The form acts as what is called the ``workWindow'' of the mainWindow. This resource would be set by

.main setValues -workWindow .main.form

Values would also be set into the list and buttons:

.main.form.list setValues \ -itemCount 3 \ -items "one two three" \ -selectionPolicy single_select .main.form.btn1 setValues -labelString Quit .main.form.btn2 setValues -labelString "Do nothing"

Behaviour would be set by a callback function

.main.form.btn1 activateCallback {exit 0} .main.form.list singleSelectionCallback {puts stdout "Selected %item"}

Geometry would be set for the form, to put the objects in their correct relation to each other. Suppose this is the list on the left, with the two buttons one under the other on the right:

.main.form.list setValues \ -topAttachment attach_form \ -leftAttachment attach_form \ -bottomAttachment attach_form .main.form.btn1 setValues \ -topAttachment attach_form \ -leftAttachment attach_widget \ -leftWidget .main.form.list .main.form.btn2 setValues \ -topAttachment attach_widget \ -topWidget .main.form.btn1 \ -leftAttachment attach_widget \ -leftWidget .main.form.list

Finally, windows are created and the main event loop is entered:

. realizeWidget . mainLoop

 

Menus

Motif supports three types of menus: pulldown menus, popup menus and option menus. It does so with a set of basic menu functions and an additional set of ``convenience'' functions. tclMotif supports the basic functions but not the convenience ones, since each author uses their own convenience functions and I am not convinced that the Motif ones are the ``best''.

Pulldown menus
Pulldown menus need a MenuBar to hold the set of buttons. These buttons must be cascade buttons. From these are created PulldownMenu widgets, which are parented from the MenuBar. To establish the link between a cascade button and its corresponding pulldown menu, the resource subMenuId must be set on the cascade buton to be the pulldown menu. The pulldown menu can contain any menu widgets such as push buttons, with their associated callbacks.

xmMenuBar .main.menuBar managed xmCascadeButton .main.menuBar.file managed \ -labelString File \ -mnemonic F xmCascadeButton .main.menuBar.edit managed \ -labelString Edit \ -mnemonic E xmCascadeButton .main.menuBar.help managed \ -labelString Help \ -mnemonic H # file pulldown xmPulldownMenu .main.menuBar.fileMenu xmPushButton .main.menuBar.fileMenu.new managed \ -labelString "New..." \ -mnemonic N xmPushButton .main.menuBar.fileMenu.quit managed \ -labelString Quit \ -mnemonic Q .main.menuBar.file setValues -subMenuId .main.menuBar.fileMenu

Popup menus
Popup menus are posted either from a keyboard accelerator or from a button 3 press over a widget. A popup menu is created by the function xmPopupMenu. A keyboard accelerator is set by the resource menuAccelerator for this widget. A button 3 press is easiest set up by adding an action to this button press that calls a menu popup function. This function should first call the popup menu widget method of menuPosition with one argument: the event that caused the popup. This event can be found by the action substitution %event. After this, the popup menu can be managed. Both methods are shown by this example:

proc popIt {event} { .fred.menu menuPosition $event .fred.menu manageChild } xtAppInitialize -class Program xmLabel .fred managed -labelString "ctrl-p or Btn3Down popups from me" .fred setValues -translations \ "<Btn3Down>: action(popIt %event)" xmPopupMenu .fred.menu -menuAccelerator "Ctrl <Key> p" xmPushButton .fred.menu.btn1 managed xmPushButton .fred.menu.btn2 managed . realizeWidget . mainLoop

Option menus
An option menu is made up of a PulldownMenu that is populated with buttons to give the alternative options. The option label is formed from an OptionMenu, with the labelString resource set to the label showing, and the subMenuId set to the PulldownMenu.

# option menu xtAppInitialize -class Program xmRowColumn .rc managed xmPulldownMenu .rc.pulldown1 xmPushButton .rc.pulldown1.options1 managed \ -labelString "value 1" xmPushButton .rc.pulldown1.options2 managed \ -labelString "value 2" xmOptionMenu .rc.option1 managed \ -labelString "Option set" \ -subMenuId .rc.pulldown1

Tear-off menus Pulldown and Popup menu panes can be made into tear-off menus by specifying the resource tearOffModel to have the value tear_off_enabled at the time of creation. They then show a tear-off button as a dotted line in the menu pane. Clicking on this with BSelect tears off the menu in place; dragging on this with BDrag will tear-off the menu and drag it elsewhere.

When a menu is a tear-off menu, an additional button is created with separator-like behaviour. This button has a pathname made up of the rowcolumn's name followed by ``.TearOffControl''. For example,

xmPulldownMenu .main.menuBar.fileMenu \ -tearOffModel tear_off_enabled -foreground red -background black

 

Drag and Drop

Drag and drop was introduced into Motif 1.2. It is complicated. We shall first look at the drop side. A widget has to first register itself as a drop site, so that when an attempt is made to drop something on it, it will try to handle it. This registration is done by the widget method ``dropSiteRegister''. This registration must include tcl code to be executed when a drop is attempted, and this is done using the resource ``dropProc''. The first part of what makes D&D hard is that you have potentially two different applications attempting to communicate, one dropping and the other accepting the drop. A protocol is needed between these, so that they share a common language. This is done in registration by saying what types of protocol are used, and how many there are. This is done using X atoms, and the major ones are ``COMPOUND_TEXT'', ``TEXT'' and ``STRING''. Thus registration by the drop site widget is done, for example, by

.l dropSiteRegister \ -dropProc {startDrop %dragContext} \ -numImportTargets 1 \ -importTargets COMPOUND_TEXT

This allows `.l' to be used as a drop site, accepting ``COMPOUND_TEXT'' only. Multiple types are allowed, using the Motif list structure of elements separated by commas as in "COMPOUND_TEXT, TEXT, STRING". When a drop occurs, the procedure ``startDrop'' is called, with one substituted parameter. This parameter is a ``dragContext'', which is a widget created to by Motif to handle the drag part of all this. You must include this parameter, or the next stage doesn't get off the ground.

When a drag actually occurs, Motif creates a dragContext widget. A drag is started by holding down the middle button in a drag source, which is discussed later. The dragContext widget contains information about the drag source, which is to be matched up against where the drop occurs. When the drop occurs, by releasing the middle button, the tcl code registered as dropProc is executed. This should have the dragContext widget as parameter. This code may try to determine if the drop should go ahead, but more normally will just act as a channel through to the actual information transfer. Still here? Good. The dragProc doesn't actually do the information transfer, it just determines whether or not it is possible, and if it is, what protocols should be used, and how.

The drop receiver may decide that it wants something encoded as TEXT, followed by something encoded as COMPOUND_TEXT, and then by something in STRING format (beats me why, though...). it signals this by a (Tcl) list of dropTransfer pairs, consisting of the protocol (as an X atom name) and the widget that is being dropped on. Huh? Why the widget that is being dropped on? Because when a drop on a widget takes place, this is actually dealt with by the dragContext widget, and this is about to hand the transfer over to a transferWidget. Yes, I know you are using Tcl because you couldn't handle triple indirections (or rather, don't want to!), but they occur anyway... So here is a simple dragProc:

proc startDrop {dragContext} { $dragContext dropTransferStart \ -dropTransfers {{COMPOUND_TEXT .l}} \ -numDropTransfers 1 \ -transferProc {doTransfer %closure {%value}} }

The dragContext widget uses the command dropTransferStart to signal the beginning of the information transfer (it could also signal that the drop is to terminate, with no information transfer). It will accept one chunk of information in the COMPOUND_TEXT format, and pass this on to the .l widget. The information transfer is actually carried on by the Tcl procedure in the transferProc resource. The only formats currently accepted (because they are hard-coded into TclMotif) are COMPOUND_TEXT, TEXT and STRING.

The transferProc resource is a function that is called when the drop receiver actually gets the information dropped on it. This should take at least two parameters. The %value is substituted for the actual information dropped on it, and %closure is the second element in the dropTransfer list which should be the widget the drop is happening on. (Why not let TclMotif determine this? I dunno. Consistency with Motif doco? Brain damage late at night?) Then the dropped on widget can take suitable action. This function resets the label to the text dropped on it:

proc doTransfer {destination value} { $destination setValues -labelString $value }

where destination is substituted by %closure and value by %value.

So much for the drop site, receiving widget. On the other side, a widget has to prepared to act as a drag source and then to send information when dropped.

A drag action is commenced (according to the Motif Style Guide) by dragging Button Two in the widget. To get this behaviour, the translation table for the widget has to have the Button2 action overriden. For example,

xmScrollBar .sb managed \ -translations "#override <Btn2Down>: action(startDrag %w)"

This will call the application defined ``startDrag'' function with the widget as argument. The purpose of this function is to call the ``drag'' method for that widget:

proc startDrag {w} { $w dragStart \ -exportTargets COMPOUND_TEXT \ -numExportTargets 1 \ -convertProc {dragConvertProc %w %type %value} }

This states that it is only prepared to send a message of type ``COMPOUND_TEXT'', and when the toolkit requires the dropped value it will call the application defined function ``dragConvertProc'' with three parameters: the widget, the data-type that is to be transferred, and the data value to be transferred. These last two are modified by the function, so are actually variables in the parent's context. These have to be modified using upvar.

For example, to send the value of a slider widget as COMPOUND_TEXT, the ``dragConvertProc'' would be:

proc dragConvertProc {w type value} { upvar 1 $type t upvar 1 $value v $w getValues -value v set t COMPOUND_TEXT }

tclMotif has builtin support for drops of three data types: TEXT, COMPOUND_TEXT and STRING. These form a large majority of the data types that may be dropped onto a widget. However, there may be others. To allow for this, tclMotif has a procedure Tm_InstallDropType that takes three parameters: a tcl interpreter, a string that will be used as an Atom to label a datatype, and a function of type

char *(*) ()
When a function is registered by using this command, it must be capable of transforming the datatype into a string, which it returns as value of the function. If this method is used, it should be added using the tcl extension techniques.

 

Send

Tk has a primitive called ``send''. In this, each interpreter has a name, and you can send tcl commands from one interpreter to another. When an interpreter receives a sent command it executes it, and returns any result back to the original interpreter. This mechanism is also available to TclMotif, so that Motif applications can set commands to other Motif applications, and also to and from Tk ones.

If a TclMotif application succeeds in registering its name, from then on, it can send to another. For example,

send interp2 {puts stdout "hello there"}

instructs ``interp2'' to display a message.

Similarly, once the ``send'' command has been registered, this application can be sent commands from other applications. The name of the interpreter is the ```title'' resource of the top-level widget `.'. Generally this will be the same as the application name, but may be changed in two ways: first the ``title'' resource may have been set explicitly. Secondly, ``send'' requires a unique name for the interpreter, so if an application is already running with that title, a ``#2'', or ``#3'', etc will be apended to the title until it is unique. This is not really satisfactory, but is the way that Tk does it.

 

Xlib Drawing

Motif only uses two widgets for Xlib style drawing: the DrawnButton and the DrawingArea. tclMotif allows drawing into these widgets, and does not allow drawing into other types of widget.

At present, the drawing functions are limited to XDrawImageString, using the method ``drawImageString''. This requires use of a graphics context. A graphics context is first obtained by the call

$w getGC -foreground fg -background
Any widget can be used for this, but typically the drawing widget will be used.

Given a graphics context, text can be drawn by

$w drawImageString gc x y text

 

Modal dialogs

Dialogs in Motif are modeless by default. A dialog can be made modal by using the BulletinBoard resource dialogStyle which can be set to values such as ``dialog_full_application_modal''. This makes the dialog modal for the application, so that the dialog has to be completed before any interaction can occur with the rest of the application. Here ``completed'' means that the dialog must be unmanaged or destroyed.

There is a serious difficulty in making dialogs modal: the modality is enforced by Xt, so that control must pass to Xt so that it can make the dialog modal. This usually means that no application code can follow setting the dialog resource, because control must pass back to the Xt event main loop.

The problem here is that this is often what the programmer explicitly does not want to do. A typical piece of code using modality is to ask a question such as ``remove file'' and use a modal dialog to wait for the answer and use it to determine what to do next. To allow this type of use, the application has to use its own event loop, and this is done by the `root' widget command ``processEvent'' which handles one event at a time.

A modal piece of code sets up a loop around the ``processEvent'' method. This loop is controlled by a Boolean flag which is initially true. When the flag is set to false the loop terminates. The loop is typically set to false by pressing the various buttons in the dialog. For example

proc ask {parent question} { global stillModal global answer xmQuestionDialog $parent.dialog managed \ -messageString $question \ -dialogStyle dialog_full_application_modal $parent.dialog okCallback {set stillModal 0; set answer 1} $parent.dialog cancelCallback {set stillModal 0; set answer 0} set stillModal 1 while {$stillModal} { . processEvent } $parent.dialog destroyWidget }

This can then be used in normal sequential code

if {ask $w "remove $file"} { exec rm $file }

 

Additional toplevel shells

Additional toplevel shells may be created using the command topLevelShell. This shell may use any widget for its parent. In order to make this shell visible, it must be popped up.

xtAppInitialize xmLabel .label managed \ -labelString "label in app shell" topLevelShell .toplevel xmLabel .toplevel.label managed \ -labelString "label in toplevel"

Do not atttempt to manage the toplevel shell - this will place it under the geometry control of its parent, so that when the parent resizes so will the shell! While this can produce some visually intriguing effects it is probably not what is desired, as well as breaking Xt rules.

 

Extending moat

From Tcl 7.0 onwards, a standard method was set up to allow extensions to be made in a consistent manner. tclMotif follows this extension method. The method allows for open-ended extensions so that further extensions can be made to moat. You need access to the tcl library and also to the tclMotif library.

Tcl expects a C function Tcl_AppInit() to be defined. This function should contain initialisation statements for each extension. In the case of tclMotif this function must contain a call to

Tm_AppInit(interp)
The prototype for this function is in tm.h, so this should be included as well.

To perform your own extension, write your own Tcl_AppInit() function based on any existing ones as a template, including the above line and any similar code for the other extensions. Then compile and link this with the tcl and extension libraries.

To add in additional widgets, see a later section for an easier way to do this.

 

Keyboard traversal

Keyboard traversal is normally handled automatically by Motif. Sometimes it is necessary for the application to reset the keyboard focus to a particular widget or to the ``next'' widget in a set. The widgets are grouped in sets called ``tab groups'' by Motif. Tab group manipulation has not been added to tclMotif (at version 1.0).

Keyboard focus may be set using the method ``processTraversal'' which takes a single argument. This may take values such as ``next'', ``up'', ``right'' to move to a suitable widget.

 

Application icons

Toplevel widgets such as the application widget can have an icon attached to them so that it is shown when the application is iconified. This is done using the resource iconPixmap for the toplevel widget. The value of the resource is a filename containing the pixmap definition. This file may be found in a large set of directories such as the current directory or /usr/lib/X11/bitmaps. The full set - and the environment variables that control this set - is documented in the Motif call XmGetPixmap().

 

Automated testing

Tcl uses an automated test system that can run regression tests on a system. it does so by ``sourcing'' a file containing a set of test procedures, including a procedure called ``test''. This takes 4 arguments: the first is the name of the test, the second is a textual description of the test, the third is the code to execute to perform the test, and the last is the expected result. The ``test'' procedure runs the test and if the actual result differs from the expected one, an error message is printed.

This mechanism is used well for the tcl core. It is also used for Tk, but with less success: while good for batch mode testing, it does not handle the interactive nature of GUI environments. To perform batch mode testing in such environments, one needs to be able to create input events to simulate an interactive user.

One approach is to create raw X events and to feed them directly into the Xt event loop handler. This requires a very low-level knowledge of what is going on, and anyway does not reflect the object structure of the Xt toolkit. Each widget defines a set of ``actions'' that are intended to be the ``public'' interface of that widget. This is the hook that the tclMotif test procedures use to extend the tcl testing into this GUI environment.

A command for any widget is ``callActionProc''. This takes an argument which is the name of the action for the widget. For example, a button has an Arm action, so this can be invoked by

.btn callActionProc Arm()

This will perform the visual behaviour for this action, and also call any callbacks associated with this action.

This sends (by default) a ClientMessage event to the widget. Most widgets ignore the event, so this is sufficient. Some actions require event detail, though. For example, when a mouse button release occurs, the widget checks to see if the release occurred inside or outside the widget. It does this because if the event occurs inside, then the callbacks attached to the Activate() action are invoked, but otherwise they are not. To handle this, an event of type ButtonPress, ButtonRelease, KeyPress or KeyRelease can be prepared with some fields set.

For tests, this means that you cannot just issue an Activate action. You do have to prepare an X button event to the extent of setting the x and y coordinates so that the internal Motif function can determine whether or not to invoke the callbacks. This looks like:

.btn callActionProc Activate \ -type ButtonPress \ -x 0 -y 0

to be within the widget, or

.btn getValues -width w -height h set big_h [expr {2 * $h}] set big_w [expr {2 * $w}] .btn callActionProc Activate \ -type ButtonPress \ -x $big_w -y $big_h

to be outside the widget.

Some of the Text manipulation actions require a KeyPress event, such as ``self-insert()'', which inserts the character pressed. The character is actually encoded as a keycode, which is a hardware dependant code, too low-level for this binding. To prepare such an event, this toolkit uses keysyms which are abstractions for each type of key symbol. The alphanumerics have simple representations as themselves (`a', `A', `2', etc). Others have symbolic names (`space', `Tab', `BackSpace', etc). These are derived from the X Reference manual or in the file <X11/keysymdefs.h> by removing the prefix ``XK_''.

For example, to insert the three characters `A a' into .text

.text callActionProc self-insert() \ -type KeyPress \ -keysym A .text callActionProc self-insert() \ -type KeyPress \ -keysym space .text callActionProc self-insert() \ -type KeyPress \ -keysym a

The set of actions that require this level of preparation of the X event is nowhere documented explicitly. You have to read between the lines of the Motif documentation, or guess at behaviour (or read Motif source code).

 

Adding widgets

[All the methods described in this section are new and a bit experimental. If there are any problems, please let me know.]

tclMotif has support for the widget set supplied in the Motif toolkit. There are an increasing number of Motif-compatable widgets becoming available from third party sources. To add any of these involves adding appropriate C code to tclMotif.

The file tmExtern.c contains some data structures that would have to be changed, and some skeleton code to assist in more complex tasks. You should make a copy of this file and either use it to replace the supplied tmExtern.c in each future release of tclMotif, or ensure that your version of this file is linked into each application before the supplied one.

The array Tm_ExternCommands can be used to add additional commands to tclMotif. It is an array of type Tm_Cmd, which is a structure The elements of this structure are

The string that is the widget creation name
The C function that is used to actually create the widget
The C function that is used to process the commands/methods issued to the new widget
If there is nothing special about creating this widget, make the second element of this array Tm_AnyCmd. If the widget has no special methods of its own, make the third element of this array Tm_AnyWidgetCmd.

For example,

Tm_Cmd Tm_ExternCommands[] = { {"htmlWidget", Tm_AnyCmd, Tm_AnyWidgetCmd}, {"myWidget", MyCreateCmd, MyWidgetCmd}, {(char *) NULL, (int (*)()) NULL, (Tm_WidgetCmdProc) NULL} };
adds in two more commands, ``htmlWidget'' and ``myWidget'', where the htmlWidget has no special creation requirements and no additional methods to the Core widget. On the other hand, myWidget has both special purpose creation requirements and additional methods, so needs custom creation and method functions. A skeleton for these two functions is supplied in the file tmExtern.c

In addition the array Tm_ExternCommandToClass contains a mapping from the tcl widget creation command to the Xt class. This is used by Tm_AnyCmd and also by the String to WidgetClass converter. The first entry in this is the widget creation string, and the second entry is a pointer to the Xt class. For example,

Tm_CommandToClassType Tm_ExternCommandToClass[] = { /* * Example: the Mosaic html widget: */ {"htmlWidget", &htmlWidgetClass}, /* * array terminator - do not remove or * place anything after this */ {NULL, NULL} };

Additional widgets will have their own callbacks, and will probably have a callback structure associated to each. To allow `%' substitutions to be used in callback code for these widgets, the function Tm_ExternExpandPercent (in tmExtern.c) may be modified to add in such substitutions.
  You will finally need to make a change to the Imakefile in the src directory, by setting the variables EXTRA_WIDGETS_INCLUDE to point to the include directory and EXTRA_WIDGETS_LIB to link in the library containing these extra widgets. For example,

EXTRA_WIDGETS_INCLUDE = /usr/local/include/html EXTRA_WIDGETS_LIB = -lhtmlw

this may be simplified by using the command ``addwidget''. This takes the name of a widget and looks in the directory ``extern_widgets'' for a set of description files. For a widget ``foo'', these are:

foo this contains lines specifying a pattern and a value. The patterns are widget
include-file
reason
library
include-dir The ``widget'' pattern is followed by the tcl command to create the widget, the Xt class of the widget, the C command to create the widget and the C command to handle methods. The include-file's are the any extra includes that need to be added to tmExtern.c. There may be any number of include files. There will generally be one for the additional Motif functions to create and manipulate the widget, and if extra tclMotif commands are needed they should also be prototyped in an include file and included here. The reason's are any additional reasons that may be available for your widget, the library is the link library for the widgets, and the include-dir is any additional path for the compiler to locate include files.

foo.initialise This contains the code to be inserted into the function Tm_ExternWidgetsInitialise. If this file does not exist, then no code will be inserted.

foo.expand This contains the code to be inserted into the function Tm_ExternExpandPercent. If this file does not exist, then no code will be inserted.

foo.commands This contains the function definitions for any non-standard widget creation and method handling that the extra widgets require.

[If you make a description file for a widget, please send it to me for inclusion in the next release.]

 

Patterns for commands

Pathnames for commands can become very long for complex widget hierarchies. The ``unknown'' command has been augmented for tclMotif to allow patterns to be used as abbreviations for commands. The patterns are those accepted by the tcl command ``info''. The way that it is expected that this will be used in tclMotif is that a long path will be abbreviated by replacing an initial portion of the command by ``*'' or ``.*'' as in

by
(It is recommended that the `.' be used to start patterns in order that widgets are selected rather than other tcl commands.) Note that the pattern must uniquely match a command/widget name for the pattern match to be successful.

The ``unknown'' procedure is augmented in the file init_tclMotif.tcl which is installed in the default X11 library directory (typically /usr/lib/X11). This is loaded by the tclMotif library unless the environment variable TM_LIBRARY is set to another directory, in which case the file init_tclMotif.tcl in that directory will be loaded instead.

Any tcl program can rename any procedure, in particular the ``unknown'' procedure. If this is done, then this pattern matching will cease to work. If you wish to prepend your own ``unknown'' procedure to this, it is recommended that you follow the ``stack'' structure used in init_tclMotif.tcl.

 

UIL

UIL (User Interface Language) is a declarative language for describing the widgets that make up an application. There is little to be gained by programming in UIL over programming in tclMotif. However, many interface builders have the option of outputting UIL code, and this can be used by tclMotif.

A UIl file is translated into a UID file by the uil compiler. This can be loaded by

The hierarchy can be closed by
Only one hierarchy can be opened per program.

A UIL widget tree can be attached to any widget by

$w mrmFetchWidget uil-widget

A traversal is made of the UIL widget tree, adding information that allows them to be used as tclMotif Core widgets. This means that you can use methods such as getValues, setValues, etc. Note that the top of the UIL tree is created unmanaged, so that you will will need to manage it yourself. For example:

-topAttachment attach_form

Callbacks in the UIL file should always be to the procedure ``tcl'' which takes a single string argument. This argument is the tcl command to be executed. For example, the UIL for an activateCallback may be

XmNactivateCallback = procedure tcl("puts stdout goodbye");
Widget names may be used in the callback procedures, but at present no % substitutions are supported (if you need them, let me know). Due to the impossibility of knowing exactly what the widget hierarchy will be when the UIL file is used, it is suggested that patterns described in the last section be used for widget names, as in
XmNactivateCallback = procedure tcl("*btn setValues -labelString pushed");

The method mrmFetchWidgetOverride is similar, but also allows the name of the top widget fetched to be set, and resource values to be changed for this widget. This is useful if you wish to have two (or more) copies of a widget hierarchy created with the same parent.

 

Multiple displays

When a topLevelShell is created, it may be given an argument that specifies the name of a display to create it on. Children of this topLevelShell will also appear on this display.

 

Named application contexts

Normally xtAppInitialise creates a topLevelShell and an application context with the name of `.'. On some occassions it may be useful to separate these names. The option ``-appContext'' may be used to give the application context a different name.

 

Author

Jan Newmarch, University of Canberra, PO Box 1, Belconnen, ACT 2616, Australia. Email: jan@ise.canberra.edu.au.


 

Index

NAME
Introduction
Acknowledgments
Running Tcl/Motif programs
The Motif world
Widget naming
Widget creation
Managing widgets
Documentation
Widget commands
Other widget commands
Widget resources
Callbacks
Callback substitutions
Text verify callbacks
Compound Strings
Dialogs
Actions
Examples
Menus
Drag and Drop
Send
Xlib Drawing
Modal dialogs
Additional toplevel shells
Extending moat
Keyboard traversal
Application icons
Automated testing
Adding widgets
Patterns for commands
UIL
Multiple displays
Named application contexts
Author

This document was created by man2html, using the manual pages.
Time: 04:19:03 GMT, December 02, 2024