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



Making Widgets Visible

Creating a widget does not by itself make the widget visible. Widgets become visible when the following conditions exist:

  1. The widget and its ancestors are managed. A widget is managed when the Xt and Motif geometry managers take account of the widget when computing the positions and sizes of widgets they display.

  2. The widget and its ancestors are realized. A widget is realized when it has an associated window.

  3. The widget and its ancestors are mapped. A widget is mapped when its window is displayed.

    An application can manage, realize, and map widgets in separate steps, but each of these actions affects the others.

  4. Managing Widgets

    Parent widgets are responsible for managing the geometry of their children. A child can ask the parent to be given some size or position, but the parent decides whether or not to grant the request. A parent can move or resize a child without the child's permission. The process by which parent and child widgets interact to determine widget geometry is described in Chapter 14.

    An application tells a widget to manage a child widget's geometry by calling XtManageChild or XtManageChildren. If the parent is realized, XtManageChild calls the parent class's change_managed procedure. This procedure can change the size or position of any of the parent's children. After calling the parent's change_managed procedure, XtManageChild realizes the child and, if the child's XmNmappedWhenManaged resource is True, maps it.

    If the parent is not realized, XtManageChild marks the child as managed. Xt defers calling the parent's change_managed procedure until the parent is realized.

    When managing more than one child of a realized parent, it is more efficient for an application to call XtManageChildren than to call XtManageChild separately for each child being managed. Widget layout can be computationally expensive, and XtManageChild invokes the parent's change_managed procedure each time it is called. XtManageChildren calls the parent's change_managed procedure only once for all children being managed.

    An application tells a widget not to manage a child widget's geometry by calling XtUnmanageChild or XtUnmanageChildren. By managing and unmanaging widgets, an application can alternately display more than one set of children without having to create and destroy widgets each time the configuration of the application changes. In addition, managing a Motif dialog or PopupMenu causes the widget to pop up, and unmanaging it causes the widget to pop down.

    To create a widget and then manage it in the same call, an application can use XtCreateManagedWidget or XtVaCreateManagedWidget. The Motif routines that create widgets of particular classes return unmanaged widgets. When using these routines, the application must manage the widgets by using XtUnmanageChild or XtUnmanageChildren.

    Realizing Widgets

    An application uses XtRealizeWidget to realize a widget. This routine does the following:

    1. In post-order, traverses the tree whose root is the widget and calls the class change_managed procedure for any widget in the tree that has managed children.

    2. Recursively traverses the tree whose root is the widget and calls the class realize procedure for any widget in the tree that is managed. The realize procedure creates the widget's window.

    3. Maps the widget's managed children whose XmNmappedWhenManaged resource is True. If the widget is a top-level widget whose XmNmappedWhenManaged resource is True, XtRealizeWidget maps the widget.

      Note these implications:

      1. Geometry negotiation proceeds from the bottom up; then window creation proceeds from the top down.

      2. After a widget is realized, all its managed descendants are realized and, by default, mapped.

      3. If no widget in the tree is realized, all geometry negotiation between parents and their managed children takes place before any widget is realized.

        When making a widget tree visible for the first time, an application should usually manage all children before realizing any widgets, then realize only the top-level widget. This causes all initial sizing and positioning of children to take place and the overall size of the top-level window to be determined before any windows exist, minimizing interaction with the X server. It also allows the application to realize all widgets with a single call to XtRealizeWidget.

      4. Mapping Widgets

        Most applications do not explicitly map or unmap widgets' windows. Mapping usually takes place as part of the process of managing or realizing widgets. But it is possible to keep Xt from mapping windows at these times by setting a widget's XmNmappedWhenManaged to False. In this case, the application must explicitly use XtMapWidget to map the widget. An application can use XtUnmapWidget to unmap a widget.

        The effect of making a widget managed but unmapped is different from the effect of making a widget unmanaged. When a widget is unmanaged, its parent takes no account of it in laying out its children. When a widget is managed, its parent is likely to leave room for it in the widget layout. When the parent is mapped, the space allocated for a managed but unmapped child is filled with the parent's background rather than the child's window.

        Multiple Screens, Displays, and Applications

        An application can run on more than one display. In this case, it must use XOpenDisplay to open a connection to each display and must then call XtDisplayInitialize separately for each display connection. It need not create a separate application context for each display.

        Note:

        XtDisplayInitialize modifies its argv and argc arguments. If an application needs to call XtDisplayInitialize more than once, it must save these arguments before the first call and use a copy of the saved arguments on each call.

        The application should use XtAppCreateShell to create at least one top-level widget for each display on which it runs. Because Xt maintains a separate resource database for each display, a child widget running on a different display from that of its parent would use incorrect initial resource settings.

        An application can also run on more than one screen within a display. Such an application opens and initializes the display only once, no matter how many screens it uses within the display. However, the application also needs a widget on each screen, whose window is a child of the root window for that screen, to serve as the root of the widget hierarchy for the screen.

        One approach to using multiple screens is to create a single, unrealized ApplicationShell for the display. The application then creates one TopLevelShell for each screen as a popup child of the ApplicationShell. Although a shell normally has only one managed child, it can have more than one popup child. The application uses XtAppCreateShell to create the ApplicationShell and XtCreatePopupShell to create each TopLevelShell. If no screen is specified for the ApplicationShell, XtAppCreateShell sets the XmNscreen resource for this widget to the default screen of the display. In the argument list passed to XtCreatePopupShell, the application must specify the proper value for XmNscreen for each TopLevelShell so that the shell is created on the intended screen.

        The application does not manage the TopLevelShells. To realize and map the TopLevelShells, the program must use XtPopup with a grab_kind argument of XtGrabNone.

        int main(int argc, char **argv)
        {
         Widget         app_shell, top_shell;
         XtAppContext   app;
         Display        *display;
         char           name[20];
         Arg            args[5];
         Cardinal       n;
         int            i;
         
            app_shell = XtAppInitialize(&app, "Example",
                (XrmOptionDescList) NULL, 0, &argc, argv,
                (String *) NULL, (ArgList) NULL, 0);
            display = XtDisplay(app_shell);
         
            for (i = 0; i < ScreenCount(display); i++) {
                sprintf(name, "top_shell_%d", i);
                n = 0;
                XtSetArg(args[n], XmNscreen,
                    ScreenOfDisplay(display, i));    n++;
                top_shell = XtCreatePopupShell(name,
                                topLevelShellWidgetClass, app_shell,
                                args, n);
                /* Create and manage descendants of top shell */
                ...
                /* Realize and map the top shell */
                XtPopup(top_shell, XtGrabNone);
            }
            ...
        }

        It is possible for a program to have multiple logical applications on the same display. In this case, it can use XtAppCreateShell to create a separate top-level widget for each logical application.


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