Widget dialog = NULL;
/* first see if this menu item's dialog has been created yet */
XtVaGetValues(w, XmNuserData, &dialog, NULL);
if (!dialog) {
/* menu item hasn't been chosen yet −− create the dialog.
* Use the toplevel as the parent because we don't want the
* parent of a dialog to be a menu item.
*/
dialog = (*func)(toplevel, "dialog", NULL, 0);
XtVaSetValues (XtParent (dialog), XmNtitle, XtName (w), NULL);
XtVaSetValues (dialog, XmNautoUnmanage, True, NULL);
/* store the newly created dialog in the XmNuserData for the menu
* item for easy retrieval next time. (see get−values above.)
*/
XtVaSetValues (w, XmNuserData, dialog, NULL);
}
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
/* If the dialog was already open, XtPopup does nothing. In
* this case, at least make sure the window is raised to the top
* of the window tree (or as high as it can get).
*/
XRaiseWindow (XtDisplay (dialog), XtWindow (XtParent (dialog)));
}
The output of the program is shown in the figure.
Output of popups.c
The program displays two PushButtons, one of which is a gadget and the other a widget. We get the ButtonPress
event by specifically asking for it using XtAddEventHandler(). This routine requires a widget because it needs a
window. To add an event handler for a gadget, you would have to install it on the gadget's parent, which is a manager
widget. Anytime a ButtonPress event occurs in the manager, the event handler would be called, so the event
16 Menus 16.4.3 Building Popup Menus
464
handler would have to check the coordinates of the event and see if it happened within the boundaries of the gadget.
This technique would work, but it is beyond the scope of this simple demonstration.
XtAddEventHandler() takes the following form:
void XtAddEventHandler(w, event_mask, nonmaskable,
proc, client_data)
Widget w;
EventMask event_mask;
Boolean nonmaskable;
XtEventHandler proc;
XtPointer client_data;
The widget parameter specifies the widget on which the event handler is to be installed, while event_mask
identifies the events that are being handled. We specify ButtonPressMask to indicate that we are interested in
ButtonPress events. The nonmaskable argument indicates whether or not the event handler should be called on
non−maskable events. We specify False since we are not interested in the events. The final arguments specify the
event handler routine and the client data that is passed to it. In our case, we specify the PostIt() routine and pass it
the PopupMenu as client data. See Volume Four, X Toolkit Intrinsics Programming Manual, for a complete list of
event masks and more detailed information about XtAddEventHandler().
An event handler routine takes the following form:
void
event_handler(widget, client_data, event)
Widget widget;
XtPointer client_data;
XEvent *event;
In the PostIt() event handler, we check which button produced the ButtonPress event. If it wasn't the third
button, we simply return. To pop up the menu, we need to position the menu and then manage the menu pane. To
position it, we use XmMenuPosition(), which takes the following form:
void
XmMenuPosition(widget, event)
Widget widget;
XButtonPressedEvent *event;
Since the event parameter for this function is defined to be of type XButtonPressedEvent, you may run into
problems if you try to use another type of event. The x_root and y_root fields in the event structure are used to
position the menu appropriately, since these fields indicate the position where the mouse button was pressed. You
could modify these fields to position the menu elsewhere, but we recommend restraint.
In order to actually pop up the menu, we call XtManageChild() on the PopupMenu. Motif treats PopupMenus just
like dialog widgets with respect to their shell parents. Although the visible PopupMenu is a RowColumn widget, it has
an invisible MenuShell parent. As with dialogs, when you call XtManageChild(), the RowColumn checks its
XmNrowColumnType resource to see if it is a PopupMenu. If it is, the widget checks to see if its parent is a
MenuShell and if so, it automatically calls XtPopup() on the MenuShell.
The RowColumn widget has a resource that you can set on PopupMenus called XmNmenuPost, which allows you to
specify an alternate button to post the menu. As of Motif 1.2, if you specify this resource and then simply position and
manage the menu in an event handler, the toolkit takes care of checking the event to make sure it matches the event
description for the XmNmenuPost resource. In earlier releases of Motif, setting this resource could cause the server
16 Menus 16.4.3 Building Popup Menus
465

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.