In Xt, the primary means of associating an input event with a widget-specific procedure is the combination of translations and actions. Each widget (but not gadget) instance contains a table of translations that maps event descriptions to procedure names. Each widget instance also has a table of actions that maps these procedure names to actual procedures. When a widget receives an input event, the Xt event-dispatching facility looks up the event in the translation table, looks up the associated procedure in the action table, and invokes the action procedure itself. This procedure usually takes some action to change the widget state and often invokes callback procedures.
An application or user specifies a translation table as a string whose format is defined in X Toolkit Intrinsics--C Language Interface. In general, the table consists of individual translations separated by "\n". Each translation consists of an event description sequence, a colon, and one or more associated procedure names. Each procedure name also has a list of parameters within parentheses to be passed to the procedure when it is invoked as a result of that translation.
An event description in general consists of an optional list of modifiers, an event type within angle brackets (< and >), an optional repeat count within parentheses, and an optional event detail. Modifiers apply only to key, button, motion, enter, and leave events. If an exclamation point (!) precedes the modifiers, then the modifiers in the list and no others must be asserted for the action to be invoked. Otherwise, the modifiers in the list must be asserted, but others may be as well. A tilde (~) before any modifier means that that modifier must not be asserted. If the modifier list is empty, any modifiers may be asserted.
The detail field varies depending on the event type. The most common use is to identify the keysym for a KeyPress or KeyRelease event.
Event descriptions in a sequence are separated by commas. Mouse motion is discarded if it occurs between events in a sequence that does not include explicit motion events. This allows the following sort of translation to invoke an action even if the mouse moves between button press and release:
Following are some important considerations in using translations:
Ctrl<Key>space: action_1() <Key>space: action_2()
<Btn1Down>,<Btn1Up>: click_action() <Btn1Up>: up_action()
<Btn1Up>(2): double_click() <Btn1Up>,<Btn1Down>,<Btn1Up>: double_click()
This result, combined with the implicit insertion of motion events between any two other events, means that motion translations cannot exist in a table with multiclick translations.
See X Toolkit Intrinsics--C Language Interface for more information on the format of translation tables.
One translation table frequently needs to be merged with another. For example, a user may want to add one or more translations to a widget's default translations. A translation table may begin with one of three directives that specifies how the table is to be merged with an existing table:
A widget's translation table is the value of the Core XmNtranslations resource. The initial value is determined in the following way:
To take advantage of this initialization ordering, an application should usually provide any translations of its own by specifying a value for baseTranslations rather than XmNtranslations in an application class defaults file or a fallback resource list. This essentially reserves XmNtranslations to the user. The application can change the widget class translations by specifying baseTranslations, and the user can change the application's translations by specifying XmNtranslations.
As the value of a widget's XmNtranslations, a translation table must be in a parsed format rather than a string. The string-to-translation-table converter parses a resource string into a translation table. An application can also use XtParseTranslationTable to compile a translation table string into the parsed format. The application can then merge the parsed table with a widget's XmNtranslations in three ways:
Some Motif widgets merge additional translations in their initialize and set_values methods. This process may make it impossible for an application or user to override some translations by means of resource files. For example, for some widgets it may not be possible to change traversal translations in this way.
Each widget instance has a table that maps action procedure names, as they appear in translation tables, to actual action procedures. When an action is invoked through a translation, Xt looks up the action procedure name in this table and calls the associated procedure.
Each widget class may have its own action table. In addition, an application can use XtAppAddActions to add entries to an action table associated with the application context. Only one such table exists per application context. If a call to XtAppAddActions contains an action name that is already in the table, the action name becomes associated with the action procedure supplied in the call to XtAppAddActions, overriding the existing action.
Xt creates a widget's action table when the widget is realized. It uses actions from the following action tables, those listed first having highest precedence:
This ordering means that an application cannot use XtAppAddActions to provide a new action procedure for an action name that is already registered by a widget class. To do that, the application must supply a translation that maps the event to an action name that is not registered by the class. The application must then call XtAppAddActions to supply a procedure for the action name.
An action procedure is a function of type XtActionProc. This function receives four arguments:
An application can use the parameter list to perform a number of related actions in a single action routine. For example, a widget might have the following translations:
c <Key> osfLeft: move-object(left) \n\ c <Key> osfRight: move-object(right) \n\ c <Key> osfUp: move-object(up) \n\ c <Key> osfDown: move-object(down)
The routine implementing the move-object() action is passed one of the strings "left", "right", "up", and "down" as the only item in the parameter list, depending on which key event invoked the action. The routine performs the action appropriate for this parameter.
Motif maintains a client-side mechanism for mapping one set of keysyms to another set. This mapping allows Motif widgets and applications to use a single set of keysyms in translation tables and also allows applications and users to customize the keysyms used in the translations for the particular keyboard used with the display.
The names of keysyms eligible for use in translations in this way begin with the prefix "osf" and are referred to as osf keysyms. Motif maintains a mapping between these "virtual" keysyms and the "actual" keysyms that correspond to keys on a particular keyboard. When Xt receives a keyboard event, the function XmTranslateKey translates the keycode of the event to the appropriate osf keysym if a mapping exists for that keysym. Xt then dispatches the event to the appropriate action routine if a translation exists for that osf keysym.
The mapping between osf and actual keysyms is determined at application startup based on information obtained from one of the following sources, listed in order of precedence:
The file xmbind.alias maps combinations of vendor strings and vendor release numbers to pathnames. Each pathname represents a file that contains keysym bindings for a particular vendor string and optional vendor release number. If Motif fails to find a bindings file for the current display, it uses a set of hard-coded fallback bindings.
The format of the defaultVirtualBindings resource is similar to that of a string specifying translations. Each binding consists of an osf keysym, a colon, a list of key event descriptions (with optional modifiers) for actual keysyms, and "\n". Use a comma to separate multiple key event descriptions. The format of a .motifbind file or a file containing vendor bindings is the same, except that each binding is on a separate line.
Following is an example of a specification for the defaultVirtualBindings resource in a resource file:
*defaultVirtualBindings: \ osfBackSpace: <Key>BackSpace \n\ osfInsert: <Key>InsertChar \n\ osfDelete: <Key>DeleteChar
The example specification above appears as follows in a .motifbind or vendor bindings file:
osfBackSpace: <Key>BackSpace osfInsert: <Key>InsertChar osfDelete: <Key>DeleteChar
For more information, see the VirtualBindings(3) and xmbind(1) reference pages in the Motif Programmer's Reference.