[ Previous | Next | Contents | Glossary | Home | Search ]
Motif 2.1 Programmer's Guide



Controlling Keyboard Navigation

In order to receive keyboard focus when the shell's XmNkeyboardFocusPolicy is XmEXPLICIT, a widget or gadget must meet the following conditions:

  1. The widget and its ancestors must not be in the process of being destroyed.

  2. The widget and its ancestors must be sensitive. A widget is sensitive when its XmNsensitive and XmNancestorSensitive resources are both True.

  3. The XmNtraversalOn resource for the widget and its ancestors must be True.

  4. The widget must be viewable. This means that the widget and its ancestors must be managed, realized, and (except for gadgets) mapped. Furthermore, in general, some part of the widget's rectangular area must be unobscured by the widget's ancestors.

    In a ScrolledWindow with an XmNscrollingPolicy of XmAUTOMATIC, a widget that is obscured because it is not within the clip window may be traversable if some part of the widget is within the work area and if an XmNtraverseObscuredCallback routine can make the widget unobscured by scrolling the window.

    Most managers cannot receive focus even if they meet all these conditions. In general only primitives and gadgets are eligible to receive focus. A DrawingArea can receive focus if it meets the conditions above and if, in addition, it has no child whose XmNtraversalOn resource is True.

    XmGetFocusWidget takes a widget argument that identifies a widget hierarchy, up to the nearest shell ancestor. It returns the widget in that hierarchy that has keyboard focus or that last had focus when the user navigated away from that hierarchy.

    An application can use XmIsTraversable and XmGetVisibility to determine whether a widget is eligible to receive focus. XmIsTraversable returns True if the widget argument meets all the conditions described in this section. Otherwise, it returns False. This routine generally returns False if the widget argument is a composite, even if it has traversable children.

    Note:

    When all widgets in a shell hierarchy have been made untraversable, they are considered to have lost focus. When a widget in this hierarchy is made traversable again, it regains focus.

    XmGetVisibility returns a value indicating the visibility of the widget argument:

    XmVISIBILITY_FULLY_OBSCURED

    The widget is completely obscured by its ancestors or is not visible for some other reason (such as being unmapped or unrealized).

    XmVISIBILITY_PARTIALLY_OBSCURED

    Some part of the widget's rectangular area is obscured by its ancestors.

    XmVISIBILITY_UNOBSCURED

    None of the widget's rectangular area is obscured by its ancestors.

    Note that a fully obscured widget may be traversable if it is inside the work area of an automatic ScrolledWindow with an XmNtraverseObscuredCallback list. See Section 13.2.5 for more information.

  5. Sensitivity

    Unless a widget is sensitive, Xt does not dispatch keyboard or pointer events to the widget. An insensitive widget, therefore, cannot receive keyboard focus.

    A widget can be sensitive only when all its ancestors are sensitive. Two Boolean resources determine sensitivity: XmNsensitive and XmNancestorSensitive. XmNsensitive indicates whether the widget itself is sensitive, and XmNancestorSensitive indicates whether all ancestors are sensitive.

    An application uses the function XtIsSensitive to find out whether a widget is sensitive. This function returns True when XmNsensitive and XmNancestorSensitive are both True; otherwise, it returns False.

    The function XtSetSensitive changes the sensitivity of a widget. With an argument of False, this function sets XmNsensitive to False and sets each child's XmNancestorSensitive to False. With an argument of True, this function sets XmNsensitive to True and, if the widget's XmNancestorSensitive is also True, it sets each child's XmNancestorSensitive to True. The function then recursively descends the widget tree. For each descendant whose XmNsensitive and XmNancestorSensitive are both True, it sets XmNancestorSensitive to True for that widget's children. Otherwise, it sets XmNancestorSensitive to False for the descendant widget's children.

    In this way, XtSetSensitive ensures that each widget's XmNancestorSensitive is True only when the parent's XmNsensitive and XmNancestorSensitive are both True. In other words, the widget is sensitive only when it and all its ancestors are sensitive. To maintain this relation, an application should always use XtSetSensitive to change a widget's sensitivity instead of calling XtSetValues on the widget's resources.

    Note that XtSetSensitive does not modify any resources for pop-up children. If the parent widget is insensitive when a pop-up child is created, the child's XmNancestorSensitive will be False. XtSetSensitive on the parent widget will not change this value, and the child will remain insensitive. To avoid this problem, an application that creates a DialogShell or a MenuShell should either ensure that the parent is sensitive when the child is created, or specify a value of True for the child's XmNancestorSensitive. One way to do this is in a resource file:

    *XmMenuShell.ancestorSensitive:   True
    *XmDialogShell.ancestorSensitive: True

    When a widget or gadget is insensitive, Motif indicates the insensitivity to the user by stippling or graying the widget.

    XmNtraversalOn

    XmNtraversalOn determines whether or not a widget is eligible to receive keyboard focus when XmNkeyboardFocusPolicy is XmEXPLICIT. When XmNtraversalOn is False and XmNkeyboardFocusPolicy is XmEXPLICIT, it is not possible for the user to give keyboard focus to the widget, even if the widget is sensitive and viewable. XmNtraversalOn has no effect when XmNkeyboardFocusPolicy is XmPOINTER.

    The default value for XmNtraversalOn is True for most Motif widgets. Following are the exceptions:

    1. Separator and SeparatorGadget, where XmNtraversalOn is forced to False

    2. ScrollBar, where XmNtraversalOn defaults to True when it is the child of a ScrolledWindow whose XmNscrollingPolicy is XmAUTOMATIC and to False otherwise

    3. Label and LabelGadget, where XmNtraversalOn is forced to False inside menus and defaults to False otherwise

    4. RowColumn, where XmNtraversalOn defaults to True in a WorkArea and is not applicable otherwise

    5. Tab Groups

      A tab group is a collection of traversable widgets or a single widget that contains a collection of traversable elements. When the shell's XmNkeyboardFocusPolicy is XmEXPLICIT and the Display's XmNenableButtonTab is False, the user traverses to a tab group by using osfNextField or osfPrevField. Within a tab group, when the focus is on a non-tab-group widget or an element, the user traverses to another non-tab-group widget or another element by using osfUp, osfDown, osfLeft, or osfRight.

      A tab group is always represented by a widget or gadget. When the group is a collection of widgets, the tab group is typically the manager that is the parent of the widgets. When the group is a single widget like List or Text, the tab group is that widget itself.

      The arrow keys do not traverse to tab groups or to non-tab-group widgets or elements outside the current tab group.

      The Display resource XmNenableButtonTab influences the meaning of osfNextField and osfPrevField. In brief, setting XmNenableButtonTab to True lets a user navigate through an entire application using only one key. To examine XmNenableButtonTab more closely, consider an application containing the two tab groups shown in Figure 14. As the figure shows, each tab group contains three widgets. You can assume that the XmNlayoutDirection resource is set to XmLEFT_TO_RIGHT_TOP_TO_BOTTOM.

      Figure 14. An Application With Two Tab Groups.

      View figure.

      Suppose that XmNenableButtonTab is False. Further suppose Widget B of Tab Group 1 has traversal focus. If XmNenableButtonTab is False, then an osfNextField event will send traversal focus to the first widget in Tab Group 1 (probably Widget D). That is, the application responds to the osfNextField event by traversing to the next tab group. If the user provides a second osfNextField event, Motif traverses back to the first widget in Tab Group 1 (probably Widget A).

      Now suppose that XmNenableButtonTab is True and that traversal focus is at Widget B. Whenever the user provides an osfNextField event, Motif traverses to the next traversable widget in the application, whether or not that field is in the current tab group. Therefore, pressing osfNextField six times would send traversal focus to Widget C, then Widget D, then Widget E, then Widget F, then Widget A, and then back to Widget B.

      To be eligible for traversal, a tab group must meet all the conditions discussed in Section 13.2, except that a manager that is a tab group and meets the other conditions is eligible for traversal as long as it contains a descendant that can receive focus. If the tab group does not meet these conditions, the osfNextField and osfPrevField actions ignore the tab group.

      Within a tab group, non-tab-group widgets must also meet all the conditions discussed in Section 13.2 to be eligible for traversal. If they do not meet these conditions, the arrow key actions ignore the widgets.

      Whether or not a widget is a tab group is determined by the value of the XmNnavigationType resource. The two primary values for this resource are XmTAB_GROUP, which indicates that the widget is a tab group, and XmNONE, which indicates that it is not.

      When the user traverses to the next or previous tab group, the direction of the traversal is usually determined by the relative locations of the current and target groups. In a left-to-right language environment, traversal to each subsequent tab group proceeds from left to right and top to bottom. At the bottom right, traversal wraps to the tab group at the top left. Traversal to previous tab groups proceeds in the opposite direction.

      The application can control the order of traversal by specifying an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP for a widget in the hierarchy. When any widget in a hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP, osfNextField and osfPrevField do not move to any widgets in that hierarchy that have been designated tab groups by means of an XmNnavigationType of XmTAB_GROUP. But osfNextField and osfPrevField do move to widgets whose XmNnavigationType is XmSTICKY_TAB_GROUP, even if some widgets are exclusive tab groups. Thus, an application that uses XmEXCLUSIVE_TAB_GROUP to control traversal must be sure that all tab groups have an XmNnavigationType of either XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP.

      When any widget in a hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP, traversal to subsequent tab groups does not depend on the relative locations of the groups. Instead, it proceeds to widgets in the order in which their XmNnavigationType resources were specified as XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP, either by creating the widgets with that value or by calling XtSetValues. That is, traversal proceeds to the widget whose XmNnavigationType was next specified to be XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP. Traversal to previous tab groups proceeds in the opposite direction.

      Within a tab group whose XmNnavigationType is XmEXCLUSIVE_TAB_GROUP, the arrow keys do not behave the same way as they would if the XmNnavigationType were either XmTAB_GROUP or XmSTICKY_TAB_GROUP. With XmTAB_GROUP or XmSTICKY_TAB_GROUP, the direction of traversal using the arrow keys depends on the relative locations of the tab group's children. Pressing osfRight moves to the next traversable child to the right of the child with the focus; osfDown moves to the next traversable child below the child with the focus; and so on.

      With XmEXCLUSIVE_TAB_GROUP, traversal using the arrow keys depends on the order of the tab group's list of children, not on the relative locations of the children. Pressing osfRight has the same effect as osfDown: both move to the next traversable child in the tab group's list of children. Pressing osfLeft has the same effect as osfUp: both move to the previous traversable child in the tab group's list of children.

      There are three principal differences between XmEXCLUSIVE_TAB_GROUP and XmSTICKY_TAB_GROUP:

      1. XmEXCLUSIVE_TAB_GROUP has the effect of disabling traversal to tab groups that have an XmNnavigationType of XmTAB_GROUP. XmSTICKY_TAB_GROUP does not; it simply ensures that traversal to that tab group is possible, even when some widget in the hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP.

      2. XmEXCLUSIVE_TAB_GROUP changes the order of traversal of tab groups within the widget hierarchy. XmSTICKY_TAB_GROUP does not.

      3. XmEXCLUSIVE_TAB_GROUP changes the order of traversal of widgets inside the tab group. XmSTICKY_TAB_GROUP does not.

        The function XmAddTabGroup has the same effect as calling XtSetValues with an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP. The function XmRemoveTabGroup has the same effect as calling XtSetValues with an XmNnavigationType of XmNONE. XmAddTabGroup and XmRemoveTabGroup are obsolete and exist for compatibility with earlier releases of Motif.

        All Motif managers except RowColumn have a default XmNnavigationType of XmTAB_GROUP. In RowColumn, XmNnavigationType is not applicable for MenuBars, PulldownMenus, and PopupMenus. For a WorkArea the default is XmTAB_GROUP, and for an OptionMenu the default is XmNONE.

        All Motif primitives except List, ScrollBar, Text, and TextField have a default XmNnavigationType of XmNONE. The default for List, Text, and TextField is XmTAB_GROUP, and the default for ScrollBar is XmSTICKY_TAB_GROUP. These are all controls that have their own internal navigation.

        Motif sets the navigation type of widgets in some situations. In particular:

        1. The child of a shell always behaves as a tab group, no matter what the value of its XmNnavigationType.

        2. Panes and sashes inside PanedWindows have a default XmNnavigationType of XmTAB_GROUP. If the XmNnavigationType of a pane is XmNONE when the pane is created, Motif sets the value of that resource to XmTAB_GROUP.

        3. SelectionBox and its subclasses set the XmNnavigationType of their automatically created List and Text children to XmSTICKY_TAB_GROUP.

          The function XmGetTabGroup returns the tab group that contains a widget. If the widget itself is a tab group or a shell, it returns that widget. If neither the widget nor any ancestor up to the nearest shell is a tab group, it returns the nearest ancestor that is a shell. Otherwise, it returns the nearest ancestor that is a tab group.

        4. Controlling Tab Group Traversal Order

          By default, osfNextField and osfPrevField traverse to successive tab groups in order of layout, from left to right and top to bottom, within a parent tab group, before proceeding in layout order to the next tab group that is a sibling of the parent. Traversal order changes when any widget in a shell hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP. In this case, osfNextField and osfPrevField traverse only to widgets in the hierarchy whose XmNnavigationType is either XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP. The traversal order is the order in which the widgets' XmNnavigationType was specified to be either XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP.

          This mechanism gives an application the means to control tab group traversal order. An application must do the following:

          1. Ensure that at least one widget in the shell hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP

          2. Ensure that all widgets that the application wants to be tab groups have an XmNnavigationType of either XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP

          3. Specify values for the tab groups' XmNnavigationType, using either creation argument lists or XtSetValues, in the order in which the tab groups are to be traversed

            Note that, when a tab group has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP, traversal to non-tab-group widgets inside that tab group proceeds in the order in which the children appear in their parents' XmNchildren lists. If the application wants to specify the order of tab group traversal but still wants traversal of non-tab-group widgets to proceed according to layout, it should select one widget in the hierarchy to have an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP. This tab group should contain no non-tab-group widgets. For example, it could be the MainWindow if the MainWindow contains only tab groups, or it could be a primitive tab group, such as List or Text. The application should then specify an XmNnavigationType of XmSTICKY_TAB_GROUP for all other tab groups in the hierarchy.

          4. Initial Focus

            A tab group may contain any combination of tab group and non-tab-group widgets. A tab group that contains other widgets cannot receive focus itself. When the user traverses to a composite tab group, Motif gives focus to some widget within the tab group.

            Motif uses the Manager resource XmNinitialFocus in determining which widget receives focus. The value of XmNinitialFocus is a widget that meets the following conditions:

            1. The widget must be either a tab group or a non-tab-group widget that can receive keyboard focus. In general, a widget can receive keyboard focus when it is a primitive, a gadget, or a manager (such as a DrawingArea with no traversable children) that acts as a primitive.

            2. The widget must not be a descendant of a tab group that is itself a descendant of the manager. That is, the widget cannot be contained within a tab group that is nested inside the manager.

            3. The widget and its ancestors must have a value of True for their XmNtraversalOn resources.

              If the widget does not meet these conditions, XmNinitialFocus is treated as if the value were NULL.

              Motif uses XmNinitialFocus to determine which widget receives focus in these situations:

              1. When the manager is the child of a shell and the shell hierarchy receives focus for the first time

              2. When focus is inside the shell hierarchy, the manager is a composite tab group, and the user traverses to the manager using the keyboard

                Motif then determines focus as follows:

                1. If XmNinitialFocus is a traversable non-tab-group widget, that widget receives focus.

                2. If XmNinitialFocus is a traversable tab group, that tab group receives focus. If that tab group is a composite with descendant tab groups or traversable non-tab-group widgets, these procedures are used recursively to assign focus to a descendant of that tab group.

                3. If XmNinitialFocus is NULL, the first traversable non-tab-group widget that is not contained within a nested tab group receives focus.

                4. If XmNinitialFocus is NULL and no traversable non-tab-group widget exists, the first traversable tab group that is not contained within a nested tab group receives focus. If that tab group is a composite with descendant tab groups or traversable non-tab-group widgets, these procedures are used recursively to assign focus to a descendant of that tab group.

                  If a shell hierarchy regains focus after losing it, focus returns to the widget that had the focus at the time it left the hierarchy.

                  The use of XmNinitialFocus is undefined if the manager is a MenuBar, PulldownMenu, PopupMenu, or OptionMenu.

                5. Traversing to Obscured Widgets

                  In general, a widget is not eligible to receive focus unless some part of its rectangular area is unobscured by its ancestors. However, it may be possible to traverse to a widget that is a descendant of a ScrolledWindow whose XmNscrollingPolicy is XmAUTOMATIC, even if that widget is not within the ScrolledWindow's clip window. Traversal to such a widget is possible under the following conditions:

                  1. Some part of the widget's rectangular area is within the bounds of the ScrolledWindow's work window.

                  2. The ScrolledWindow's clip window is completely unobscured by its ancestors. If the ScrolledWindow is a descendant of another ScrolledWindow, it must be unobscured by the ancestor's work window but may be outside the ancestor's clip window.

                  3. The ScrolledWindow has a procedure on its XmNtraverseObscuredCallback list that can bring some part of the widget's rectangular area into the clip window.

                  4. The widget meets the other conditions for receiving focus described in Section 13.2.

                    Whenever the user attempts to traverse to such a widget and the widget is partially or fully obscured by the clip window, Motif calls the ScrolledWindow's XmNtraverseObscuredCallback procedures. If the ScrolledWindow has one or more ancestor ScrolledWindows, Motif calls the XmNtraverseObscuredCallback list for each ScrolledWindow whose clip window obscures the traversal target, from the lowest level of the hierarchy to the highest. The XmNtraverseObscuredCallback procedure can try to bring the widget into the clip window if necessary, usually by calling XmScrollVisible. If the target widget is traversable after the XmNtraverseObscuredCallback procedures are invoked, that widget receives focus.

                    A procedure can determine the visibility of a widget by calling XmGetVisibility.

                  5. XmProcessTraversal

                    The principal routine for traversing to a widget is XmProcessTraversal. Motif uses this routine to effect traversal when the user presses an arrow key, osfNextField, or osfPrevField. An application can use XmProcessTraversal to implement its own traversal actions.

                    XmProcessTraversal takes two arguments, a widget and a constant specifying a traversal action. The routine uses the widget argument to identify the hierarchy that contains the widget and that has its root at the nearest shell. If that shell does not currently have the focus, any changes to the element with focus within that shell will not occur until the next time the shell receives focus.

                    The traversal action argument identifies one of three kinds of action to take. The following descriptions of these actions refer to traversable non-tab-group widgets and traversable tab groups. A traversable non-tab-group widget is a widget that is not a tab group and that meets all the conditions for receiving focus discussed in Section 13.2. A traversable tab group is a tab group widget that meets the same conditions, except that a manager that is a tab group and meets the other conditions is also traversable as long as it contains a descendant that can receive focus.

                    The routine begins the traversal action from the widget in the hierarchy that currently has keyboard focus or that last had focus when the user traversed away from the shell hierarchy.

                    Note that XmProcessTraversal cannot be called recursively. In particular, an application cannot call this routine from an XmNfocusCallback or XmNlosingFocusCallback procedure.

                    The descriptions in the following three subsections all assume that XmNlayoutDirection is set to XmLEFT_TO_RIGHT_TOP_TO_BOTTOM. Later in this section, we will explore the influence of XmNlayoutDirection in greater detail.

                    Traversal to a Non-Tab-Group Widget

                    This kind of traversal is possible only when the widget that currently has focus is not a tab group. Also, these actions do not move focus from one tab group to another. The actions first determine the containing tab group. This is the tab group containing the widget that currently has focus. The actions traverse only to a non-tab-group widget within the containing tab group.

                    XmTRAVERSE_RIGHT

                    If the XmNnavigationType of the containing tab group is not XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget to the right of the widget that currently has focus. At the right side of the tab group, this action wraps to the non-tab-group widget at the left side and next toward the bottom. At the lower right corner of the tab group, this action wraps to the non-tab-group widget at the upper left.

                    If the XmNnavigationType of the containing tab group is XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget in the tab group, proceeding in the order in which the widgets appear in their parents' XmNchildren lists. After the last widget in the tab group, this action wraps to the first non-tab-group widget.

                    XmTRAVERSE_LEFT

                    If the XmNnavigationType of the containing tab group is not XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget to the left of the widget that currently has focus. At the left side of the tab group, this action wraps to the non-tab-group widget at the right side and next toward the top. At the upper left corner of the tab group, this action wraps to the non-tab-group widget at the lower right.

                    If the XmNnavigationType of the containing tab group is XmEXCLUSIVE_TAB_GROUP, focus moves to the previous traversable non-tab-group widget in the tab group, proceeding in the reverse order in which the widgets appear in their parents' XmNchildren lists. After the first widget in the tab group, this action wraps to the last non-tab-group widget.

                    XmTRAVERSE_DOWN

                    If the XmNnavigationType of the containing tab group is not XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget below the widget that currently has focus. At the bottom of the tab group, this action wraps to the non-tab-group widget at the top and next toward the right. At the lower right corner of the tab group, this action wraps to the non-tab-group widget at the upper left.

                    If the XmNnavigationType of the containing tab group is XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget in the tab group, proceeding in the order in which the widgets appear in their parents' XmNchildren lists. After the last widget in the tab group, this action wraps to the first non-tab-group widget.

                    XmTRAVERSE_UP

                    If the XmNnavigationType of the containing tab group is not XmEXCLUSIVE_TAB_GROUP, focus moves to the next traversable non-tab-group widget above the widget that currently has focus. At the top of the tab group, this action wraps to the non-tab-group widget at the bottom and next toward the left. At the upper left corner of the tab group, this action wraps to the non-tab-group widget at the lower right.

                    If the XmNnavigationType of the containing tab group is XmEXCLUSIVE_TAB_GROUP, focus moves to the previous traversable non-tab-group widget in the tab group, proceeding in the reverse order in which the widgets appear in their parents' XmNchildren lists. After the first widget in the tab group, this action wraps to the last non-tab-group widget.

                    XmTRAVERSE_NEXT

                    Focus moves to the next traversable non-tab-group widget in the tab group, proceeding in the order in which the widgets appear in their parents' XmNchildren lists. After the last widget in the tab group, this action wraps to the first non-tab-group widget.

                    XmTRAVERSE_PREV

                    Focus moves to the previous traversable non-tab-group widget in the tab group, proceeding in the reverse order in which the widgets appear in their parents' XmNchildren lists. After the first widget in the tab group, this action wraps to the last non-tab-group widget.

                    XmTRAVERSE_HOME

                    If the XmNnavigationType of the containing tab group is not XmEXCLUSIVE_TAB_GROUP, focus moves to the first traversable non-tab-group widget at the top left corner of the tab group.

                    If the XmNnavigationType of the containing tab group is XmEXCLUSIVE_TAB_GROUP, focus moves to the first traversable non-tab-group widget in the tab group, according to the order in which the widgets appear in their parents' XmNchildren lists.

                    Traversal to a Tab Group

                    The following actions begin by determining the current widget hierarchy and the containing tab group. The current widget hierarchy is the widget hierarchy whose root is the nearest shell ancestor of the widget that currently has focus. The containing tab group is is the tab group containing the widget that currently has focus.

                    XmTRAVERSE_NEXT_TAB_GROUP

                    If no tab group in the current widget hierarchy has a value of XmEXCLUSIVE_TAB_GROUP for XmNnavigationType, focus goes to the next traversable tab group that is to the right of the widget with current focus and is within the containing tab group. At the right side of the containing tab group, this action wraps to the tab group at the left side and next toward the bottom. At the lower right corner of the containing tab group, this action recursively moves up one level in the hierarchy. Focus then goes to the next traversable tab group that is to the right of the original containing tab group and is within the tab group that contains that one. At the lower right corner of the topmost tab group in the hierarchy, this action wraps to the first traversable tab group at the upper left corner of the topmost tab group.

                    If any tab group in the current widget hierarchy has a value of XmEXCLUSIVE_TAB_GROUP for XmNnavigationType, focus goes to the next traversable tab group in the hierarchy, in the order in which the XmNnavigationType resources of the tab groups were set to XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP. After the last tab group in the hierarchy, this action wraps to the first tab group.

                    XmTRAVERSE_PREV_TAB_GROUP

                    If no tab group in the current widget hierarchy has a value of XmEXCLUSIVE_TAB_GROUP for XmNnavigationType, focus goes to the next traversable tab group that is to the left of the widget with current focus and is within the containing tab group. At the left side of the containing tab group, this action wraps to the tab group at the right side and next toward the top. At the upper left corner of the containing tab group, this action recursively moves up one level in the hierarchy. Focus then goes to the next traversable tab group that is to the left of the original containing tab group and is within the tab group that contains that one. At the upper left corner of the topmost tab group in the hierarchy, this action wraps to the first traversable tab group at the lower right corner of the topmost tab group.

                    If any tab group in the current widget hierarchy has a value of XmEXCLUSIVE_TAB_GROUP for XmNnavigationType, focus goes to the previous traversable tab group in the hierarchy, in the reverse order in which the XmNnavigationType resources of the tab groups were set to either XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP. After the first tab group in the hierarchy, this action wraps to the last tab group.

                    Traversal to Any Widget

                    In the following case, the widget argument is the widget to which XmProcessTraversal tries to give focus.

                    XmTRAVERSE_CURRENT

                    Focus goes to the widget argument if that widget is a traversable non-tab-group widget or tab group.

                    Effect of XmNlayoutDirection on XmProcessTraversal

                    The descriptions in the preceding subsections all assumed that XmNlayoutDirection was set to XmLEFT_TO_RIGHT_TOP_TO_BOTTOM. When XmNlayoutDirection is set to some other direction, the navigation rules are somewhat different. To help explain these differences, consider the application shown in Figure 15. This application consists of one tab group. This one tab group consists of 12 widgets.

                    Figure 15. An Application With 12 Widgets in One Tab Group.

                    View figure.

                    Given the application shown in Figure 15, Table 13 summarizes what happens when the application calls XmProcessTraversal with a direction argument of XmTRAVERSE_HOME.

                    Table 13. Effect of XmNlayoutDirection on XmTRAVERSE_HOME

                    XmNlayoutDirection Home Widget
                    =
                    XmLEFT_TO_RIGHT_TOP_TO_BOTTOM A
                    XmRIGHT_TO_LEFT_TOP_TO_BOTTOM B
                    XmLEFT_TO_RIGHT_BOTTOM_TO_TOP K
                    XmRIGHT_TO_LEFT_BOTTOM_TO_TOP L
                    XmTOP_TO_BOTTOM_LEFT_TO_RIGHT C
                    XmTOP_TO_BOTTOM_RIGHT_TO_LEFT F
                    XmBOTTOM_TO_TOP_LEFT_TO_RIGHT G
                    XmBOTTOM_TO_TOP_RIGHT_TO_LEFT J

                    Table 14 summarizes the influence of XmNlayoutDirection on XmProcessTraversal in the application shown in Figure 15. For example, suppose that the second argument to XmProcessTraversal is XmTRAVERSE_RIGHT and that the XmNlayoutDirection resource is set to XmRIGHT_TO_LEFT_TOP_TO_BOTTOM. If XmNinitialFocus for the tab group manager is NULL, Table 14 says that initial focus will default to widget B. When XmProcessTraversal is called again with XmTRAVERSE_RIGHT as its direction argument, the application will navigate to widget K, then to widget L, and so on. After navigating through all 12 widgets, the application will navigate around to the starting widget, which in this case is widget B.

                    One way to understand the navigation rules is to ask yourself whether the application is trying to traverse forwards or traverse backwards. To understand forwards and backwards, suppose that XmNlayoutDirection is set to XmLEFT_TO_RIGHT_TOP_TO_BOTTOM. In this case

                    1. XmTRAVERSE_RIGHT and XmTRAVERSE_DOWN are forward traversals (with the flow)

                    2. XmTRAVERSE_LEFT and XmTRAVERSE_UP are backwards traversals (against the flow)

                      Understanding forwards and backwards helps you understand what Motif does when the application wants to traverse past the last widget in a particular direction. For example, what happens when the application wants to traverse right but there are no widgets to the right of the current widget? If the traversal is forwards, then upon reaching the last widget in given direction, Motif navigates towards the direction specified by XmNlayoutDirection. If the traversal is backwards, Motif navigates away from the direction specified by XmNlayoutDirection.

                      Table 14. Effect of XmNlayoutDirection on XmProcessTraversal

                      XmProcessTraversal XmNlayoutDirection Sequence
                      =
                      XmTRAVERSE_RIGHT XmLEFT_TO_RIGHT_TOP_TO_BOTTOM A,B,C,D,E,F,G,H,I,J,K,L
                        XmRIGHT_TO_LEFT_TOP_TO_BOTTOM B,K,L,G,H,I,J,C,D,E,F,A
                        XmLEFT_TO_RIGHT_BOTTOM_TO_TOP K,L,G,H,I,J,C,D,E,F,A,B
                        XmRIGHT_TO_LEFT_BOTTOM_TO_TOP L,A,B,C,D,E,F,G,H,I,J,K
                        XmTOP_TO_BOTTOM_LEFT_TO_RIGHT C,D,E,F,G,H,I,J,K,L,A,B
                        XmTOP_TO_BOTTOM_RIGHT_TO_LEFT F,A,B,K,L,G,H,I,J,C,D,E
                        XmBOTTOM_TO_TOP_LEFT_TO_RIGHT G,H,I,J,C,D,E,F,A,B,K,L
                        XmBOTTOM_TO_TOP_RIGHT_TO_LEFT J,K,L,A,B,C,D,E,F,G,H,I
                      XmTRAVERSE_LEFT XmLEFT_TO_RIGHT_TOP_TO_BOTTOM A,L,K,J,I,H,G,F,E,D,C,B
                        XmRIGHT_TO_LEFT_TOP_TO_BOTTOM B,A,F,E,D,C,J,I,H,G,L,K
                        XmLEFT_TO_RIGHT_BOTTOM_TO_TOP K,B,A,F,E,D,C,J,I,H,G,L
                        XmRIGHT_TO_LEFT_BOTTOM_TO_TOP L,K,J,I,H,G,F,E,D,C,B,A
                        XmTOP_TO_BOTTOM_LEFT_TO_RIGHT C,B,A,L,K,J,I,H,G,F,E,D
                        XmTOP_TO_BOTTOM_RIGHT_TO_LEFT F,E,D,C,J,I,H,G,L,K,B,A
                        XmBOTTOM_TO_TOP_LEFT_TO_RIGHT G,L,K,B,A,F,E,D,C,J,I,H
                        XmBOTTOM_TO_TOP_RIGHT_TO_LEFT J,I,H,G,F,E,D,C,B,A,L,K
                      XmTRAVERSE_DOWN XmLEFT_TO_RIGHT_TOP_TO_BOTTOM A,D,H,K,B,E,I,L,F,J,C,G
                        XmRIGHT_TO_LEFT_TOP_TO_BOTTOM B,E,I,L,A,D,H,K,C,G,F,J
                        XmLEFT_TO_RIGHT_BOTTOM_TO_TOP K,C,G,F,J,B,E,I,L,A,D,H
                        XmRIGHT_TO_LEFT_BOTTOM_TO_TOP L,F,J,C,G,A,D,H,K,B,E,I
                        XmTOP_TO_BOTTOM_LEFT_TO_RIGHT C,G,A,D,H,K,B,E,I,L,F,J
                        XmTOP_TO_BOTTOM_RIGHT_TO_LEFT F,J,B,E,I,L,A,D,H,K,C,G
                        XmBOTTOM_TO_TOP_LEFT_TO_RIGHT G,F,J,B,E,I,L,A,D,H,K,C
                        XmBOTTOM_TO_TOP_RIGHT_TO_LEFT J,C,G,A,D,H,K,B,E,I,L,F
                      XmTRAVERSE_UP XmLEFT_TO_RIGHT_TOP_TO_BOTTOM A,G,C,J,F,L,I,E,B,K,H,D
                        XmRIGHT_TO_LEFT_TOP_TO_BOTTOM B,J,F,G,C,K,H,D,A,L,I,E
                        XmLEFT_TO_RIGHT_BOTTOM_TO_TOP K,H,D,A,L,I,E,B,J,F,G,C
                        XmRIGHT_TO_LEFT_BOTTOM_TO_TOP L,I,E,B,K,H,D,A,G,C,J,F
                        XmTOP_TO_BOTTOM_LEFT_TO_RIGHT C,J,F,L,I,E,B,K,H,D,A,G
                        XmTOP_TO_BOTTOM_RIGHT_TO_LEFT F,G,C,K,H,D,A,L,I,E,B,J
                        XmBOTTOM_TO_TOP_LEFT_TO_RIGHT G,C,K,H,D,A,L,I,E,B,J,F
                        XmBOTTOM_TO_TOP_RIGHT_TO_LEFT J,F,L,I,E,B,K,H,D,A,G,C

                    3. Focus Callbacks

                      BulletinBoard, Text, and TextField have XmNfocusCallback callback lists. Motif invokes the procedures on these lists when these widgets receive keyboard focus. A callback procedure may change the widget's state to reflect the new focus, but it should not try to change the focus and, in particular, must not call XmProcessTraversal.

                      Text and TextField also have XmNlosingFocusCallback callback lists. The Text and TextField traversal actions invoke these procedures before traversing to another widget. The third argument to each procedure is a pointer to an XmTextVerifyCallbackStruct structure whose reason member is XmCR_LOSING_FOCUS. If a callback procedure sets the doit member of this structure to False, the traversal action does not carry out the traversal. In this way the application can prevent a user from traversing out of the widget by means of these actions.

                      Motif also invokes the XmNlosingFocusCallback procedures when the widget loses focus by some other means. For example, the user might click Btn1 in another traversable widget, or when the shell's XmNkeyboardFocusPolicy is XmPOINTER, the user might move the pointer into another widget. In such cases, setting the doit member of the callback structure has no effect.


                      [ Previous | Next | Contents | Glossary | Home | Search ]