NULL);
XtOverrideTranslations (pb, XtParseTranslationTable ("<Key>Tab: do_tab"));
The translation table is merged into the existing translations for the PushButton widget. This translation table does not
interfere with the translation table in the manager widget, but it does interfere with event propagation to the manager.
When the TAB key is pressed, the action routine do_tab() is called and the event is consumed by the PushButton
widget. The event is not propagated up to the manager widget so that it can perform the appropriate keyboard traversal
action. The workaround for this problem is to have do_tab() process the keyboard traversal action on its own, in
addition to performing its own action. This technique is discussed in the next section.
Since a manager can also contain gadgets, the manager widget must also handle input that is destined for gadgets.
Since gadgets do not have windows, they cannot receive events. Only the manager widget that is the parent of a
gadget can receive events for the gadget. The manager widget has the following additional translations to handle input
on behalf of gadgets:
<Key>osfActivate: ManagerParentActivate()
<Key>osfCancel: ManagerParentCancel()
<Key>osfSelect: ManagerGadgetSelect()
<Key>osfHelp: ManagerGadgetHelp()
~Shift ~Meta ~Alt <Key>Return: ManagerParentActivate()
~Shift ~Meta ~Alt <Key>space: ManagerGadgetSelect()
<Key>: ManagerGadgetKeyInput()
<BtnMotion>: ManagerGadgetButtonMotion()
<Btn1Down>: ManagerGadgetArm()
<Btn1Down>,<Btn1Up>: ManagerGadgetActivate()
<Btn1Up>: ManagerGadgetActivate()
<Btn1Down>(2+): ManagerGadgetMultiArm()
<Btn1Up>(2+): ManagerGadgetMultiActivate()
<Btn2Down>: ManagerGadgetDrag()
Unlike with keyboard traversal translations, widget translations cannot interfere with the manager translations that
handle events destined for gadgets. If a widget had the input focus, the user's actions cannot be destined for a gadget,
since the user would have to traverse to the gadget first, in which case the manager would really have the input focus.
In Chapter 10, The DrawingArea Widget, we discuss the problems involved in handling input events on the
DrawingArea widget. The problems arise because the widget can be used for interactive drawing, as well as serve as a
manager. There may be events that you want to process in your application, but they could also be processed by the
DrawingArea itself. The problem is really a semantic one, as there is no way to determine which action procedure
should be invoked for each event if the DrawingArea has a manager−based action and the application defines its own
action. For more information on translation tables and action routines, see Chapter 2, The Motif Programming Model,
and Volume Four, X Toolkit Intrinsics Programming Manual.
9.8.4 Processing Traversal Manually
At times, an application may want to move the input focus as a result of something that the user has done. For
example, you might have an action area where each PushButton invokes a callback function and then sets the input
focus to the home item in the tab group, presumably to protect the user from inadvertently selecting the same item
twice. the source code demonstrates how this operation can be accomplished.
/* proc_traverse.c −− demonstrate how to process keyboard traversal
* from a PushButton's callback routine. This simple demo contains
* a RowColumn (a tab group) and three PushButtons. If any of the
* PushButtons are activated (selected), the input focus traverses
* to the "home" item.
9 Manager Widgets 9.8.4 Processing Traversal Manually
248
*/
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, rowcol, pb;
XtAppContext app;
void do_it();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
rowcol = XtVaCreateManagedWidget ("rowcolumn",
xmRowColumnWidgetClass, toplevel,
XmNorientation, XmHORIZONTAL,
NULL);
(void) XtVaCreateManagedWidget ("OK",
xmPushButtonWidgetClass, rowcol, NULL);
pb = XtVaCreateManagedWidget ("Cancel",
xmPushButtonWidgetClass, rowcol, NULL);
XtAddCallback (pb, XmNactivateCallback, do_it, NULL);
pb = XtVaCreateManagedWidget ("Help",
xmPushButtonWidgetClass, rowcol, NULL);
XtAddCallback (pb, XmNactivateCallback, do_it, NULL);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* callback for pushbuttons */
void
do_it(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
/* do stuff here for PushButton widget */
(void) XmProcessTraversal(widget, XmTRAVERSE_HOME);
}
The three frames in the figure show the movement of keyboard focus in the program. In the figure, the current input
focus is on the Cancel button; when it is selected, the input focus is changed to the OK button.
9 Manager Widgets 9.8.4 Processing Traversal Manually
249
Output of proc_traversal.c
The callback routine associated with the PushButtons does whatever it needs and then calls
XmProcessTraversal() to change the input item to the home item, which happens to be the OK button. This
function can be used when an application needs to set the current item in the tab group to another widget or gadget or
it can be used to traverse to a new tab group. The function takes the following form:
Boolean
XmProcessTraversal(widget, direction)
Widget widget;
int direction;
The function returns False if the VendorShell associated with the widget has no tab groups, the input focus policy
doesn't make sense, or if there are other extenuating circumstances that would be considered unusual. It is unlikely
that you'll ever have this problem.
The direction parameter specifies where the input focus should be moved. This parameter can take any of the
following values:
XmTRAVERSE_CURRENT
XmTRAVERSE_NEXT
XmTRAVERSE_PREV
XmTRAVERSE_HOME
XmTRAVERSE_UP
XmTRAVERSE_DOWN
XmTRAVERSE_LEFT
XmTRAVERSE_RIGHT
XmTRAVERSE_NEXT_TAB_GROUP
XmTRAVERSE_PREV_TAB_GROUP
All but the last two values are for traversing to items within the current tab group; the last two are for traversing to the
next or previous tab group relative to the current one. In the case of the source code the call to
XmProcessTraversal() forces the home element to be the current item in the current tab group. For a more
sophisticated example of manipulating the input focus, see Section #stextcbs in Chapter 14, Text Widgets. One
problem with XmProcessTraversal() is that you can only move in a relative direction from the item that has the
input focus. This functionality is sufficient in most cases, since the logic of your application should not rely on the
user following any particular input sequence. If you need to traverse to a specific widget regardless of the current
item, in most cases you can make the following call:
XmProcessTraversal (desired_widget, XmTRAVERSE_CURRENT);
This calling sequence specifies that the desired_widget takes the input focus, but only if the shell that contains
the widget already has the keyboard focus. If the shell does not have the focus, nothing happens until the shell obtains
the keyboard focus. When it does, the desired_widget should have the input focus.
Under certain conditions, this function may appear not to work. For example, if you create a dialog and want to set the
input focus to one of its subwidgets, you may or may not get this to happen, depending on whether or not the dialog
has been realized and mapped to the screen and whether or not keyboard focus has been accepted. Unfortunately, there
is no general solution to this problem because the Motif toolkit isn't very robust about the programmer changing input
focus out from under it. You cannot call generic X functions like XSetInputFocus() to force a widget to take
input focus or you will undermine Motif's attempt at monitoring and controlling the input policy on its own.
In Motif 1.2, there are some new functions that make it easier for an application to control keyboard traversal. The
9 Manager Widgets 9.8.4 Processing Traversal Manually
250
Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.