[Comp.Sci.Dept, Utrecht] Note from archiver<at>cs.uu.nl: This page is part of a big collection of Usenet postings, archived here for your convenience. For matters concerning the content of this page, please contact its author(s); use the source, if all else fails. For matters concerning the archive as a whole, please refer to the archive description or contact the archiver.

Subject: Motif FAQ (Part 6 of 9)

This article was archived around: 23 May 2006 04:24:20 GMT

All FAQs in Directory: motif-faq
All FAQs posted in: comp.windows.x.motif
Source: Usenet Version

Archive-name: motif-faq/part6 Last-modified: 1 FEB 2002 Posting-Frequency: irregular Organization: Kenton Lee, X/Motif Consultant, http://www.rahul.net/kenton/ URL: http://www.rahul.net/kenton/mfaq.html Version: 8.1
----------------------------------------------------------------------------- Subject: 156) TOPIC: DRAWING AREA WIDGET ----------------------------------------------------------------------------- Subject: 157) How can I send an expose event to a Drawing Area widget? (or any other, come to that). I want to send an expose event so that it will redraw itself. [Last modified: Nov 97] Answer: Use the Xlib call XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True) This clears the widget's window and generates an expose event in doing so. The widgets expose action will then redraw it. This uses a round trip request. An alternative, without the round trip is from orca!mesa!rthomson@uunet.uu.net (Rich Thomson): Widget da; XmDrawingAreaCallbackStruct da_struct; da_struct.reason = XmCR_EXPOSE; da_struct.event = (XEvent *) NULL; da_struct.window = XtWindow(da); XtCallCallbacks(da, XmNexposeCallback, (XtPointer) &da_struct); Thanks to rand@ling.umu.se (Ola Andersson) for a correction to the above. ----------------------------------------------------------------------------- Subject: 158) How can I know when a DrawingArea has been resized? It generates an expose event whn it is enlarged, but not when it is shrunk. Answer: Use the resize callback. ----------------------------------------------------------------------------- Subject: 159) How can I create a drawing area widget with a visual type different from its parent? [Last modified: Sep 97] Answer: The standard Motif drawing area does not support this. You can, however, easily create a subclass with a new Realize class method. You may want to create visual type, colormap, and depth resources so you can set these values at initialization time. In SGI's Motif, such a widget is called SgVisualDrawingArea. Other Motif implementations may have similar widgets. Ken Lee, http://www.rahul.net/kenton/ ----------------------------------------------------------------------------- Subject: 160) How can I display postscript in a Motif widget, such as XmDrawingArea? [Last modified: Sept 95] Answer: Richard M. Goldstein (rickg@Eng.Sun.COM) writes: If your system supports the Display PostScript extension (or NX agent), the newer revs of the dpstkXm library contains a type of drawing area widget designed specifically for use with DPS. Source for the latest DPS client-side is also ftp'able from contrib. Ramiro Estrugo (restrugo@fateware.com) writes: Have a look at ghostscript. [With] a little editting, you can extract the Ghostview widget and use it in your application... ----------------------------------------------------------------------------- Subject: 161) TOPIC: MAIN WINDOW WIDGET ----------------------------------------------------------------------------- Subject: 162) How can I create a message window in an XmMainWindow? [Last modified: Nov 95] Answer: XmMainWindow supports a message window, but you cannot specify it via XmMainWindowSetAreas(). Instead, create the widget as a child of the XmMainWindow, then specify to the XmMainWindow with XtSetValues() of XmNmessageWindow. Ken Lee ----------------------------------------------------------------------------- Subject: 163) TOPIC: SCROLLED WINDOW WIDGET ----------------------------------------------------------------------------- Subject: 164) How do I tell if a scrolled window's scrollbars are visible? Answer: Use XtGetValues() to get the scrollbar widget ID's, then use XtIsManaged() to see if they are managed (visible). Ken Lee ----------------------------------------------------------------------------- Subject: 165) How can I programatically scroll a XmScrolledWindow in XmAUTOMATIC mode? Answer: In Motif 1.2, use XmScrollVisible(). If you're using a scrolled text or scrolled list combination widget, use XmTextScroll() or XmListSet*() instead. The Motif manuals specifically forbid manipulating the scrollbars directly, but some people have reported success with XmScrollBarSetValues, with the "notify" parameter set to "True". Ken Lee ----------------------------------------------------------------------------- Subject: 166) What widget does the XmScrolledWindow use for its clip window? [Last modified: Apr 98] Answer: In Motif 1.2, if the XmScrolledWindow is using the XmAUTOMATIC scrolling policy, it automatically creates an XmDrawingArea widget as its clip window. If you wish, you can retrieve the XmDrawingArea's widget ID by using XtGetValues on the XmNclipWindow resource and then set resources on that widget. Some useful resources are XmNbackground and XmNresizeCallback. Note that Motif 2.X uses a new XmClipWindow widget instead of the XmDrawingArea. Since XmClipWindow is subclassed from XmDrawingArea, the above resources should still work. Ken Lee ----------------------------------------------------------------------------- Subject: 167) How do I create a scrolled window with only one scrollbar? [Last modified: July 95] Answer: If you're using the default application-defined scrolling mode, you can just create one and specify NULL for the other. If, however, you're using automatic scrolling, retrieve the ID of the unwanted scrollbar with XmNhorizontalScrollBar or XmNverticalScrollBar and unmanage that widget: Widget hScroll; XtVaGetValues(scrollbar, XmNhorizontalScrollBar, &hScroll, NULL); XtUnmanageChild(hScroll); Thanks to Ken Lee, http://www.rahul.net/kenton/. Typo corrected by Paul Tomblin, ptomblin@canoe.com. ----------------------------------------------------------------------------- Subject: 168) TOPIC: MENUS ----------------------------------------------------------------------------- Subject: 169) How can I change the cursor used in Motif menus? [Last modified: Oct 95] Answer: Set XmNmenuCursor on XmScreen (Motif 1.2) or XmRowColumn (Motif 1.1). This should be set globally at start-up time, e.g., usually via an app- defaults file. Ken Lee ----------------------------------------------------------------------------- Subject: 170) How do I put my help menu on the far right of my menubar? [Last modified: Oct 95] Answer: Set the XmNmenuHelpWidget resource of the menu bar to the help menu's cascade button. Ken Lee ----------------------------------------------------------------------------- Subject: 171) Can I change or disable the menu bar accelerator from the default (F10)? [Last modified: May 97] Answer: Changing it will confuse some of your users. If you must, this accelerator is controlled by these resources on the menu bar's XmRowColumn: XmNpopupEnabled (enables accelerators) and XmNmenuAccelerator (specifies the accelerator key). Ken Lee ----------------------------------------------------------------------------- Subject: 172) How do I set the current choice in a radio box or an option menu? [Last modified: May 95] Answer: Set the XmNmenuHistory resource on its XmRowColumn parent. Ken Lee buser@tartan.com (Mark) sent this code fragment: Widget menu; int num_buttons; WidgetList buttons; XtVaGetValues( simple_option_widget, XmNsubMenuId, &menu, NULL); XtVaGetValues( menu, XmNnumChildren, &num_buttons, XmNchildren, &buttons, NULL ) ; and change current selection with: XtVaSetValues( simple_option_widget, XmNmenuHistory, buttons[index], NULL ) ; /* where index is between 0 and num_buttons */ Thanks to Phil Gehlich <pgehlich@hp7001.ecae.StorTek.COM> for a correction. ----------------------------------------------------------------------------- Subject: 173) How can I determine the item selected in a a radio box or option menu? Answer: The value of the XmNmenuHistory resource of the XmRowColumn parent is the widget ID of the last selected item. It works the same way for all menus and radio boxes. Ken Lee ----------------------------------------------------------------------------- Subject: 174) How can I change the cascade indicator on an option menu? [Last modified: Dec 97] Answer: Set XmNcascadePixmap on the option menu's cascade button gadget. Ken Lee ----------------------------------------------------------------------------- Subject: 175) How do I unset an XmToggleButton in a radio box? If a radio- mode toggle button is set and I XtSetValues XmNset a different toggle button, the first radio button is not automatically unset. How do can I automatically unset the first button? [Last modified: Jun 98] Answer: There are two easy ways to do this. First, you can set the toggle with XmNmenuHistory on the radio box instead of XmNset on the toggle button. Second, you can use XmToggleButtonSetState() with True for the notify argument. Note that some people have reported that XmNmenuHistory correctly sets the toggle state but the toggle is not always redrawn to show the new state. This is a bug in their implementation of Motif. If you cannot get a patch, you should use the XmToggleButtonSetState() method. Ken Lee ----------------------------------------------------------------------------- Subject: 176) Can I place a radio box in a pulldown menu? [Last modified: May 97] Answer: You cannot place a XmRowColumn widget child in a menu pane. Since the menu pane itself is a XmRowColumn widget, however, you can enable XmNradioBehavior on it. This only works if all of the menu items are radio buttons. An alternative is to manage your radio behavior via your button callback functions. This is more work, but much more flexible. Ken Lee ----------------------------------------------------------------------------- Subject: 177) How do I make a menu choice insensitive if it was created with XmVaCreateSimplePulldownMenu? [Last modified: Sept 94] Answer: According to the Motif manual, the buttons are named "button_n", where "n" is an integer starting from 0. You can use XtNameToWidget() to convert these names to widget ID's. Ken Lee ----------------------------------------------------------------------------- Subject: 178) What widgets can I put inside a menubar? [Last modified: Oct 95] Answer: You can only put cascade buttons (widgets or gadgets) in the top level of menubars. However, the children of these cascade buttons can be pushbuttons with labels, pushbuttons with pixmaps, toggle buttons, separators, other cascade buttons. ----------------------------------------------------------------------------- Subject: 179) Can I have a cascade button without a submenu in a pulldown menu? Answer: Yes you can. A cascade button has an activate callback which is called when you click on it and it doesn't have a submenu. It can have a mnemonic, but keyboard traversal using the arrow keys in the menu will skip over it. ----------------------------------------------------------------------------- Subject: 180) Should I have a cascade button without a submenu in a pulldown menu? Answer: No. This is forbidden by the style guide. Technically you can do it (see previous question) but if you do it will not be Motif style compliant. This is unlikely to change - if a "button" is important enough to be in a pulldown menu bar with no pulldown, it should be a button elsewhere. (Mind you, you won't be able to put accelerators on it elsewhere though.) ----------------------------------------------------------------------------- Subject: 181) What is the best way to create popup menus? [Last modified: August 92] Susan Murdock Thompson (from OSF): In general, create a popupMenu as the child from which you will be posting it from (ie: if you have a bulletinBoard with a PushButton in it and want MB2 on the pushButton to post the popupMenu, create the popupMenu as a child of the pushButton). [This parent-child relationship seems to make a big difference in the behavior of the popups.] Add an event handler to handle buttonPress events. You'll need to check for the correct button (what you've specified menuPost to be) before posting the menu. To create a popup that can be accessible from within an entire client window, create it as the child of the top-most widget (but not the shell) and add event handlers for the top-most widget and children widgets. ie: { XtManageChild(rc=XmCreateRowColumn(Shell1, "rc", NULL, 0)); XtManageChild(label = XmCreateLabel(rc, "label", NULL, 0)); XtManageChild(text = XmCreateText(rc, "text", NULL, 0)); XtManageChild(pushbutton = XmCreatePushButton(rc, "pushbutton", NULL, 0)); n = 0; XtSetArg(args[n], XmNmenuPost, "<Btn3Down>"); n++; popup = XmCreatePopupMenu(rc, "popup", args, n); XtAddEventHandler(rc, ButtonPressMask, False, PostMenu3, popup); XtAddEventHandler(text, ButtonPressMask, False, PostMenu3, popup); XtAddEventHandler(label, ButtonPressMask, False, PostMenu3, popup); XtAddEventHandler(pushbutton, ButtonPressMask, False, PostMenu3, popup); XtManageChild(m1 = XmCreatePushButton(popup, "m1", NULL, 0)); XtManageChild(m2 = XmCreatePushButton(popup, "m2", NULL, 0)); XtManageChild(m3 = XmCreatePushButton(popup, "m3", NULL, 0)); XtAddCallback(m1, XmNactivateCallback, SayCB, "button M1"); XtAddCallback(m2, XmNactivateCallback, SayCB, "button M2"); XtAddCallback(m3, XmNactivateCallback, SayCB, "button M3"); } /* where PostMenu3 is ... */ PostMenu3 (w, popup, event) Widget w; Widget popup; XButtonEvent * event; { printf("menuPost = 3, button %d\n", event->button); if (event->button != Button3) return; XmMenuPosition(popup, event); XtManageChild(popup); } ----------------------------------------------------------------------------- Subject: 182) How do popup menus work? [Last modified: Feb 98] Answer: When a popup menu is created as the child of a widget the menu system installs a translation on the parent of the popup and descendants with an action which: (1) when 3-rd button (the default for the menuPost resource) is pressed the cursor changes and the mouse is grabbed for 3 seconds; (2) disables event handlers on the descendants and the handlers are never called; (3) an event handler installed on the parent works fine. It is done so that the correct event handler will (in fact) be called. There is a grab with owner_events true. The grab is released by a timer, but normally the posted menu shell puts up it's own grab. If you only have widgets then you can use the subwindow field in the event to identify the original widget. If you have gadgets or other data that you want to change the menu for (or use a specific menu for) then you must do a walk of the parent's children to find the best match. One thing to beware of is that even with the grab, because the menu system does a grab with owner events true, you must either have an event handler, or nothing that will use the event on each widget in the hierarchy of the menu's parent. If a child widget has another event handler for button down, it may swallow the event and do something else. ----------------------------------------------------------------------------- Subject: 183) How can I disable the button 3 grab if I am not using popup menus? [Last modified: Nov 98] Answer: The menu system initiates the 3 second grab if XmNpopupEnabled is true (the default), whether or not you will actually be popping up a menu. You can avoid this grab by setting XmNpopupEnabled to False for widgets that do no have popup menus. ----------------------------------------------------------------------------- Subject: 184) Should I use translation tables or actions for popup menus? [Last modified: August 92] Answer: The original goal of popupMenus was that the user would not have to specify an event handler to manage popupMenus; however, that did not become reality. Larry Rogers wrote: > There appear to be two ways to manage popup menus. I > am curious what the correct way would be: 1. Change the translation table of the widget with the popup child to popup the menu. Note that this does not currently working for many widgets, because aug- menting their translations, even for augment breaks the widget. 2. Add an event handler at creation to the widget; then determine if the event that caused the event handler to be called is the current button being used by the menu as its activation button. Susan Murdock Thompson (from OSF) replied: *Theoretically, you should be able to do both.* Our documentation says use event handlers. Our tests for the toolkit use event handlers and for UIL use translations. (Although I tried an event handler with a UIL test and it works). ----------------------------------------------------------------------------- Subject: 185) What are the known bugs in popup menus? [Last modified: August 92] Answer: As at Motif 1.1.4, the bugs for which an OSF PIR exists are: (3) Menus not being sticky (ie: posted on a Btn CLICK) [ Note:this problem occurs with OptionMenus as well] (PIR 3435) (6) Destroying a widget with an associated popupMenu results in "Warning: Attempt to remove non-existant passive grab" (PIR 2972) (7) Current documentation insufficient regarding requirements for success in using PopupMenus. (PIR 3433) ----------------------------------------------------------------------------- Subject: 186) Can I have multiple popup menus on the same widget? [Last modified: July 96] Answer: Ken Lee wrote that with Motif 1.2.*, you can have multiple popup menus on a single widget as long as you set the menu's XmNmenuPost correctly. The older answer for Motif 1.1.* was: If you want to have several popups (activated by different mouse buttons) on the same widget..., well, that doesn't work yet. If you want to have several popups on different children... that works. But don't put a popup on the parent (manager) widget, or it will rule! ----------------------------------------------------------------------------- Subject: 187) How can I change the shell title of a tear-off menu? [Last modified: Dec 97] Answer: There is menu title resource to set this in Motif 2.0. In Motif 1.*, explicitly set XmNtitle and XmNtitleEncoding on the menu shell, possibly in your XmNtearOffMenuActivateCallback. Note: The shell that is about to be mapped is the parent of the widget passed to the XmNtearOffMenuActivateCallback. Thanks to Ken Lee (http://www.rahul.net/kenton/), Fernando D. Mato Mira (matomira@lig.di.epfl.ch), and Michael O'Keefe (Michael.OKeefe@LMC.Ericsson.SE) ----------------------------------------------------------------------------- Subject: 188) Can I programmatically tear-off a menu? [Last modified: Dec 97] Answer: As far as I know, there is no supported (or easy and unsupported) way to do this. Ken Lee ----------------------------------------------------------------------------- Subject: 189) What widgets are valid within Motif menus? [Last modified: July 96] Answer: In Motif 1.*, menus may contain labels, push buttons, cascade buttons, toggle buttons, and separators (widgets or gadgets). RowColumn will complain if you use anything else within a menu. Note that drawn buttons and arrow buttons are not allowed. Ken Lee ----------------------------------------------------------------------------- Subject: 190) Can I create multi-column popup or pulldown menus? [Last modified: Nov 96] Answer: Yes. Menu panes are just XmRowColumn widgets. Set XmNpacking to XmPACK_COLUMN and XmNnumColumns to the number of columns you want. Ken Lee ----------------------------------------------------------------------------- Subject: 191) How can I keep my program from hanging if a user activates a popup that is a child of an insensitive push button? [Last modified: Nov 96] Answer: There are two workarounds for this problem. You need only use one. 1. Set XmNancestorSensitive to False on the XmMenuShell when its parent is insensitive. 2. Set XmNpopupEnabled on the menu pane (XmRowColumn widget) to False when the menu is insensitive. Reset the resource to True if you make your button sensitive again. Ken Lee ----------------------------------------------------------------------------- Subject: 192) TOPIC: DRAG AND DROP ----------------------------------------------------------------------------- Subject: 193) Where can I find info and examples of the Motif drag and drop protocol? [Last modified: Jul 97] Answer: A technical specification is available over the Internet: OSF/Motif Drag and Drop Protocol ftp://ftp.red-bean.com/pub/teak/ Thanks to Elliot Lee, sopwith@redhat.com OSF's "Motif Programmers Guide" includes complete source code for several drag and drop demos. Chapter 15 has simple examples demonstrating the basic behaviour. Appendix B has a more complex example. (The source code for some of the demos also appears on the OSF tape.) Ken Lee ----------------------------------------------------------------------------- Subject: 194) How can I disable Drag and Drop in my Motif 1.2 client ? [Last modified: Oct 94] Answer: Several people have reported that for complex hierarchies of widgets, drag and drop can slow down an application considerably. If you do not need drag and drop's significant power, you can disable it in your application. Set the XmDisplay drag-protocol resources to XmDRAG_NONE. The following code fragment demonstrates this: #include <Xm/Display.h> dw = XmGetXmDisplay(XtDisplay(shell)); /* where "shell" is your client's top- level shell. */ XtVaSetValues(dw, XmNdragInitiatorProtocolStyle, XmDRAG_NONE, NULL); XtVaSetValues(dw, XmNdragReceiverProtocolStyle, XmDRAG_NONE, NULL); Thanks to Lance Purple (purple@austin.ibm.com) Ken Lee and Christoph Widmer (widmer@einsteinium.SLCS.SLB.COM) describe how to disable drag and drop from a resource file: *dragInitiatorProtocolStyle: XmDRAG_NONE *dragReceiverProtocolStyle: XmDRAG_NONE Ken Lee also notes that as of Motif 1.2, the "Xm" prefix is required for all token constants in resource files. (Which is why specifying "DRAG_NONE" won't work but "XmDRAG_NONE" will.) ----------------------------------------------------------------------------- Subject: 195) Can I register client data for the Motif XmDropSite drop callback? [Last modified: Mar 96] Answer: Apparently not. You can, however, put your data in the drop site widget's XmNuserData. Or, you can use the Xlib context manager. Ken Lee ----------------------------------------------------------------------------- Subject: 196) Can unmanged widgets be valid (drag-and-drop) drop sites? [Last modified: Nov 96] Answer: Yes, the drop site stacking order is independent of the window stacking order. You can modify the active drop site order with XmDropSiteConfigureStackingOrder() or by using XmDropSiteUpdate() to change the drop site's XmNdropSiteActivity resource (to XmDROP_SITE_ACTIVE or XmDROP_SITE_INACTIVE). Ken Lee ----------------------------------------------------------------------------- Subject: 197) TOPIC: INPUT FOCUS ----------------------------------------------------------------------------- Subject: 198) How can I specify the widget that should have the keyboard focus when my application starts up? [Last modified: June 95] Answer: In Motif 1.2 or later, use XmNinitialFocus on the manager widget. Ken Lee ----------------------------------------------------------------------------- Subject: 199) How can I specify my own keyboard traversal order? [Last modified: May 97] Answer: In Motif 1.2 or later, set the XmNnavigationType resource for the widgets in your tab group. When any widget in a hierarchy has an XmNnavigationType of XmEXCLUSIVE_TAB_GROUP, traversal of tab groups in the hierarchy proceeds to widgets in the order in which their XmNnavigationType resources were specified as XmEXCLUSIVE_TAB_GROUP or XmSTICKY_TAB_GROUP. Earlier releases have a XmAddTabGroup(), but that is obsolete and has been replaced by XmNnavigationType. Ken Lee ----------------------------------------------------------------------------- Subject: 200) How can I determine which widget has keyboard focus? [Last modified: Sept 95] Answer: In Motif 1.2 or later, use XmGetFocusWidget(). Ken Lee -------------------------------------------------------------------------- Subject: 201) How can I direct the keyboard input to a particular widget? Answer: In Motif 1.1 call XmProcessTraversal(target, XmTRAVERSE_CURRENT). The widget (and all of its ancestors) does need to be realized BEFORE you call this. Otherwise it has no effect. XmProcessTraversal is reported to have many bugs, so it may not work right. A common occurrence is that it doesn't move to the widget, but if you call XmProcessTraversal *twice* in a row, it will. If you can't get it to work, try this from Kee Hinckley: // This insane sequence is as follows: // On manage set up a focus callback // On focus callback set up a timer (and get rid of focus callback!) // On timer set the focus (which only works if the parent // has the focus, // which is why we went through all of this garbage) // There may be a better way, but I haven't time to try it now. // static void focusTO(void *data, XtIntervalId *) { XmProcessTraversal((Widget) data, XmTRAVERSE_CURRENT); } static void focusCB(Widget w, XtPointer data, XtPointer) { XtRemoveCallback(w, XmNfocusCallback, focusCB, data); XtAppAddTimeOut(XtWidgetToApplicationContext(w), 0, focusTO, data); } void OmXSetFocus(Widget parent, Widget w) { XtAddCallback(parent, XmNfocusCallback, focusCB, w); } In Motif 1.0 call the undocumented _XmGrabTheFocus(target). Do not use the X or Xt calls such as XtSetKeyboardFocus since this bypasses the Motif traversal layer and can cause it to get confused. This can lead to odd keyboard behaviour elsewhere in your application. ----------------------------------------------------------------------------- Subject: 202) How can I have a modal dialog which has to be answered before the application can continue? [Last modified: Sep 97] Answer: Warning: the following answer relies on nested event loops. Use these with caution, as nested loops can affect the ordering of events and widget destruction, leading to several undesirable side effects. Ken Lee Note: J.-N. Meurisse (uunet!rc4.vub.ac.be!jnmeuris) sent a correction to the following code fragment. Change: XtAddCallback(dialog, XmNpopdownCallback, ...) to XtAddCallback(XtParent(dialog), XmNpopdownCallback, ...) The answer depends on whether you are using the Motif window manager mwm or not. Test for this by XmIsMotifWMRunning. The window manager mwm knows how to control event passing to dialog widgets declared as modal. If the dialog is set to application modal, then no interaction with the rest of the application can occur until the dialog is destroyed or unmanaged. Use the appropriate code in the following program. There is followup discussion after the program. /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates. * This program is freely distributable without licensing fees and * is provided without guarantee or warranty expressed or implied. * This program is -not- in the public domain. This program is * taken from the Motif Programming Manual, O'Reilly Volume 6. */ /* * ask_user.c -- create a pushbutton that posts a dialog box * that asks the user a question that requires an immediate * response. The function that asks the question actually * posts the dialog that displays the question, waits for and * returns the result. */ #include <X11/Intrinsic.h> #include <Xm/DialogS.h> #include <Xm/SelectioB.h> #include <Xm/RowColumn.h> #include <Xm/MessageB.h> #include <Xm/PushBG.h> #include <Xm/PushB.h> XtAppContext app; #define YES 1 #define NO 2 /* main() --create a pushbutton whose callback pops up a dialog box */ main(argc, argv) char *argv[]; int argc; { Widget parent, button, toplevel; XmString label; void pushed(); toplevel = XtAppInitialize(&app, "Demos", NULL, 0, &argc, argv, NULL, NULL, 0); label = XmStringCreateLocalized("/bin/rm *"); button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, toplevel, XmNlabelString, label, NULL); XtAddCallback(button, XmNactivateCallback, pushed, "Remove Everything?"); XmStringFree(label); XtRealizeWidget(toplevel); XtAppMainLoop(app); } /* pushed() --the callback routine for the main app's pushbutton. */ void pushed(w, question) Widget w; char *question; { if (AskUser(w, question) == YES) puts("Yes"); else puts("No"); } /* * AskUser() -- a generalized routine that asks the user a question * and returns the response. */ AskUser(parent, question) char *question; { static Widget dialog; XmString text, yes, no; static int answer; extern void response(); answer = 0; if (!dialog) { dialog = XmCreateQuestionDialog(parent, "dialog", NULL, 0); yes = XmStringCreateLocalized("Yes"); no = XmStringCreateLocalized("No"); XtVaSetValues(dialog, XmNdialogStyle, XmDIALOG_APPLICATION_MODAL, XmNokLabelString, yes, XmNcancelLabelString, no, NULL); XtSetSensitive( XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON), False); XtAddCallback(dialog, XmNokCallback, response, &answer); XtAddCallback(dialog, XmNcancelCallback, response, &answer); /* if the user interacts via the system menu: */ /* SEE CORRECTION ABOVE */ XtAddCallback(dialog, XmNpopdownCallback, response, &answer); } text = XmStringCreateLocalized(question); XtVaSetValues(dialog, XmNmessageString, text, NULL); XmStringFree(text); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); /* while the user hasn't provided an answer, simulate XtMainLoop. * The answer changes as soon as the user selects one of the * buttons and the callback routine changes its value. Don't * break loop until XtPending() also returns False to assure * widget destruction. */ while (answer == 0 || XtAppPending(app)) XtAppProcessEvent(app, XtIMAll); return answer; } /* response() --The user made some sort of response to the * question posed in AskUser(). Set the answer (client_data) * accordingly and destroy the dialog. */ void response(w, answer, reason) Widget w; int *answer; XmAnyCallbackStruct *reason; { switch (reason->reason) { case XmCR_OK: *answer = YES; break; case XmCR_CANCEL: *answer = NO; break; default: *answer = NO; return; } } If you aren't running a window manager that acknowledges this hint, then you may have to grab the pointer (and keyboard) yourself to make sure the user doesn't interact with any other widget. Change the grab flag in XtPopup to XtGrabExclusive, and XtRemoveGrab(XtParent(w)) to the response() function. ----------------------------------------------------------------------------- Subject: 203) TOPIC: MEMORY AND SPEED ----------------------------------------------------------------------------- Subject: 204) When can I free data structures passed to or retrieved from Motif? Answer: In most cases, especially for XmStrings and XmFontLists, Motif copies data passed to it or retrieved from it, so it may be freed immediately. Server-side resources, such as pixmaps and color cells, however, are not copied, so should not be freed. More recent versions of Motif are better than earlier versions and exceptions should be documented. Ken Lee ----------------------------------------------------------------------------- Subject: 205) What memory leaks are known? Why does my application grow in size? [Last modified: Jun 98] Answer: Detailed information about Motif-related memory leaks (and how you can avoid them) can be found in two great articles by Kenton Lee: http://www.rahul.net/kenton/txa/feb96.html http://www.rahul.net/kenton/txa/mar96.html Answer: Motif 1.0 has many memory leaks, particularly in XmString manipulation. Switch to Motif 1.1. 1.2, or 2.0. Answer: In Motif 1.2.x, if one is using XmStringGetNextSegment very often (several 100 times) you'll get very big memory leaks, because one has to XtFree() also the charset variable and not only the variable holding the text value. Thanks to Ingo Schulz (ing@bb-data.de). Answer: The Intrinsics have a memory leak in accelerator table management, and Motif uses this heavily. Avoid this by mapping/unmapping widgets rather than creating/destroying them, or get X11R4 fix-15/16/17. Answer: The server may grow in size due to its own memory leaks. Switch to a later server. Answer: You are responsible for garbage collection in `C'. Some common cases where a piece of memory becomes garbage are a. Memory is allocated by Motif for XmStrings by the functions XmStringConcat, XmStringCopy, XmStringCreate, XmStringCreateLtoR, XmStringCreateLocalized, XmStringDirectionCreate, XmStringNConcat, XmStringNCopy, XmStringSegmentCreate, and XmStringSeparatorCreate. The values returned by these functions should be freed using XmStringFree when they are no longer needed. b. Memory is allocated by Motif for ordinary character strings (of type String) by Motif in XmStringGetLtoR, XmStringGetNextComponent, and XmStringGetNextSegment. After using the string, XtFree() it. [Note that XmStrings and Strings are two different data types. XmStrings are XmStringFree'd, Strings are XtFree'd.] c. If you have set the label (an XmString) in a label, pushbutton, etc widget, free it after calling XtSetValues() or the widget creation routine by XmStringFree(). d. If you have set text in a text widget, the text widget makes its own copy. Unless you have a use for it, there is no need to keep your own copy. e. If you have set the strings in a list widget the list widget makes its own copy. Unless you have a use for it, there is no need to keep your own copy. f. When you get the value of a single compound string from a Widget e.g. XmNlabelString, XmNmessageString, ... Motif gives you a copy of its internal value. You should XmStringFree this when you have finished with it. g. On the other hand, when you get a value of a Table e.g. XmStringTable for a List, you get a *pointer* to the internal Table, and should not free it. h. When you get the value of the text in a widget by XmTextGetString or from the resource XmNvalue, you get a copy of the text. You should XtFree this when you have finished with it. Answer: Josef Nelissen wrote: at least in Motif 1.1.4, X11R4 on a HP 720, the XmText/XmTextFieldSetString() functions have a memory leak. The old value/contents of the Widget isn't freed correctly. To work around this bug, one should use a XmText Widget (in single-line-mode) instead of a XmTextField Widget (the solution fails with XmTextField Widgets !) and replace any XmTextSetString(text_widget, str); by XmTextReplace(text_widget, (XmTextPosition) 0, XmTextGetLastPosition(text_widget), str); ----------------------------------------------------------------------------- Subject: 206) Why do I get so many uninitilized memory read (UMR) errors when I run Purify[tm] on my Motif programs? [Last modified: July 96] Answer: Purify's reports are suggestions and do not always indicate real bugs. The X libraries frequently allocate dynamic memory, e.g., for attribute or event structures, but don't explicitly initialize all of the memory. X keeps track of which structure fields are valid via a union type or a mask. When X tries to copy or write the memory (part of which is uninitialized) as one block, Purify reports a UMR. This is not a bug and you can safely supress or ignore the report. Yes, X could initialize the unused field, but since this happens alot, the needless operation could negatively affect your performance. Ken Lee ----------------------------------------------------------------------------- Subject: 207) Why does my application take a long time to start up? Answer: You are probably creating too many widgets at startup time. Delay creating them until needed. If you have a large number of resources in text files (such as in app-defaults), time may be spent reading and parsing it. ----------------------------------------------------------------------------- Subject: 208) My application is running too slowly. How can I speed it up? Answer: Use the R4 rather than R3 server. It is much faster. Answer: The standard memory allocator is not well tuned to Motif, and can degrade performance. Use a better allocator. e.g. with SCO Unix, link with libmalloc.a; use the allocator from GNU emacs; use the allocator from Perl. Answer: Avoid lots of widget creation and destruction. It fragments memory and slows everything down. Popup/popdown, manage/unmanage instead. Answer: Set mappedWhenManaged to FALSE, and then call XtMapWidget() XtUnmapWidget() rather than managing. Answer: Get more memory - your application, the server and the Operating System may be spending a lot of time being swapped. Answer: If you are doing much XmString work yourself, such as heavy use of XmStringCompare, speed may deteriorate due to the large amount of internal conversions and malloc'ing. Try using XmStringByteCompare if appropriate or ordinary Ascii strings if you can. Answer: There are some more hints at http://www.rahul.net/kenton/perf.html ----------------------------------------------------------------------------- Subject: 209) Why is my application so huge? Answer: The typical size of a statically linked Motif app is in the megabytes. This is often caused by the size of libXm.a. A large part of this gets linked in to even trivial Motif programs. You can reduce the code size by linking against shared libraries if they are available. Running "strip" on the executable can often reduce size. Note that the size of the running program should be measured by "ps", not by the code size. ----------------------------------------------------------------------------- Subject: 210) How can I improve performance when creating and deleting hundreds of text widgets? [Last modified: Feb 98] Answer: Ken Lee writes: This is mostly a problem with Motif 1.2.0 through 1.2.2. Later versions are much better. If you're stuck with an early version of Motif 1.2, you may be able to greatly improve performance by batching the drop site updates: surround the create or delete code with XmDropSiteStartUpdate and XmDropSiteEndUpdate. Alternatively, you can completely disable drag-and-drop for your application. See the subject: "How can I disable Drag and Drop in my Motif 1.2 client?" Mike Youell adds: Using XmDropSiteStartUpdate sped up destruction of widgets in Motif 1.2.5. Also it may be worthwhile reminding people that it is not as simple as "surround the create or delete code with XmDropSiteStartUpdate and XmDropSiteEndUpdate" because it doesn't destroy the widgets when you do a XtDestroy. X does it at a later time, hence you still need to be inside the drop-site update when these destroys are completed by X. ----------------------------------------------------------------------------- Subject: 211) After I call XtSetValues, when will I see the changes in my GUI? [Last modified: Nov 97] Answer: For each change you make, the widget decides if it needs to redraw. If so, Xt calls XtClearArea to generate an expose event. You main loop dispatches the resulting expose event to your widget, causing a redisplay. Note that the redisplay may be delayed somewhat if you do not immediately return to the event loop after calling XtSetValues. You can often work around this by calling XmUpdateDisplay(). Note also that you should try to make all your changes in one large XtSetValues changing several values at once. If you call XtSetValues individually for each change you need to make, you could generate several expose events and redraw several times. ----------------------------------------------------------------------------- Subject: 212) TOPIC: XMSTRING ----------------------------------------------------------------------------- Subject: 213) What string functions differ in Motif 1.1 and 1.2? Is XmStringCreateSimple obsolete? What should I use instead? [Last modified: Feb 95] Answer: XmStringCreateSimple is obsolete. Use XmStringCreateLocalized instead. Matthew B. Evans (Evans@EDFUA6.ctis.af.mil) writes: We just upgraded from Motif 1.1 to 1.2. When we went to compile, no problem, but our XmStringCreateSimple() and XmStringGetLtoR() seemed to have problems. As we found out, Motif 1.2 STRONGLY recommends to use the constant XmFONTLIST_DEFAULT_TAG instead of XmSTRING_DEFAULT_CHARSET in all of the XmStringXXX() functions, as XmSTRING_DEFAULT_CHARSET is maintained only for compatibility (not a whole lot in my opinion). I got this information from Book 6B from O'Reilly. You may want to take a look at this book if you can. Some XmString functions are outdated and maintained only for compatibility, whereas some don't function correctly when using XmSTRING_DEFAULT_CHARSET (from our in-depth tests). We have changed all our XmStringCreateSimple() to XmStringCreateLocalized() (as suggested in book 6B) and changed all XmSTRING_DEFAULT_CHARSET to XmFONTLIST_DEFAULT_TAG. [Thanks to John West (jwest@nas.nasa.gov) for fixing a typo in the above.] NOTE: All string answers in this FAQ now use XmStringCreateLocalized rather than XmStringCreateSimple. The documentaton makes it clear that XmStringCreateSimple is obsolete and is only kept for compatibility with Motif 1.1. New applications should not use this function since XmStringCreateSimple may disappear in a subsequent Motif release. (Thanks to Miguel Angel Chamochin (mangel@tid.es) for reminding me to fix this mess.)....ksall@cen.com. ----------------------------------------------------------------------------- Subject: 214)* How can I get the ASCII text out of an XmString? [Last modified: Feb 02] Answer: In Motif 1.x, use XmStringGetLtoR: char *str; XmString xmstr; XmStringGetLtoR(xmstr, XmSTRING_DEFAULT_CHARSET, &str); In Motif 2.x, use XmStringUnparse: str = XmStringUnparse(xmstr, NULL, 0, XmCHARSET_TEXT, NULL, 0, NULL); In both cases, you should free the string to avoid a memory leak: XtFree(str); ----------------------------------------------------------------------------- Subject: 215) When can XmStrings used as resources be freed? Answer: The policy OSF have been trying to enforce is that if you set an XmString or XmStringTable resource, the application is responsible for freeing the XmStrings used because the widget makes a copy. If you get an XmString resource, then the application must free the value gotten. If you get an XmStringTable, then the application should NOT free the value gotten. If the application wants to manipulate it, it should make a copy first. This policy appears to be implemented progressively, so may be less true for Motif 1.0 than 1.1. ----------------------------------------------------------------------------- Subject: 216) Why doesn't XmStringGetNextSegment() work properly? Answer: The documentation in Motif 1.0 is in error. Instead of XmStringGetnextSegment(context, ...) XmStringContext * context; it should be XmStringGetnextSegment(context, ...) XmStringContext context; i.e. with no indirection. ----------------------------------------------------------------------------- Subject: 217) Why does using XmStringDraw cause a BadFont error? [Last modified: Mar 96] Answer: Thomas Berlage (berlage@gmdzi.gmd.de) wrote: You could call this a bug in Motif. You pass a GC to XmStringDraw, however, Motif wants to use the fonts from the font list to draw the string. Therefore it replaces the font of the GC temporarily with some fonts of its own as specified in the font list. In the end it tries to restore the old font of the GC. There comes the problem: If a GC uses the default font, the client side GC structure does not have a valid font id (that is the 0xffffffff you may see in the error message). Motif tries to restore this invalid id at the end. The workaround is: Before drawing with XmStringDraw, set the font id of the GC to any valid font id, for example using XSetFont (display, gc, XLoadFont (display, "fixed")); Another solution is available from "Harry's Motif Programming Corner", Harald Albrecht, albrecht@igpm.rwth-aachen.de, who writes: "It's somewhat longer but doesn't rely on a font named "fixed" installed on your platform. Instead it takes a fontlist and then uses the first font listed there. You'll find this source together with a short demo program (which creates a DrawingArea and then paints some text in it) on: ftp.igpm.rwth- aachen.de ( in: /arc/pub/unix/motif/RenderXmString.tar.gz There's also a html page available: Harry's Motif Programming Corner http://www.igpm.rwth-aachen.de/~albrecht/motifcorner.html Thanks to Harald Albrecht (albrecht@igpm.rwth-aachen.de). URL corrected by irca (irca@zip.cra.enel.it). ----------------------------------------------------------------------------- Subject: 218) How can I control color of individual strings to show status, etc.? [Last modified: June 95] Answer: This is difficult to do with Motif 1.X. If you can, upgrade to Motif 2.0, which supports colored XmStrings. Ken Lee ----------------------------------------------------------------------------- Subject: 219) TOPIC: DIALOGS ----------------------------------------------------------------------------- Subject: 220) How do I stop my dialog disappearing when I press the help button? Answer: Bulletin board has the resource autoUnmanage which defaults to True. This unmanages the widget when any button child is activated - including the help button. Set this to False to stop it disappearing. Note that you then have to unmanage the bulletin board yourself when any other button is activated. ----------------------------------------------------------------------------- Subject: 221) How do I make my own dialog? I want a dialog with my own set of buttons that stretch and shrink like the ones in e.g. PromptDialog and its own contents. Answer: Start off with say a PromptDialog. Unmanage the buttons you don't want or manage the Apply button if you want another. Unmanage the other bits of the selection box you don't want. You can add another WorkArea child to the selection box for any extra stuff you want. /* Copyright 1990, Kee Hinckley and Brian Holt Hawthorne */ /* Permission granted for any use, provided this copyright */ /* notice is maintained. */ /* Create a dialog box */ argcount = setArgs(&args, XmNautoUnmanage, False, NULL); SomeDialog = XmCreatePromptDialog(mainShell, "someDialog", args, argcount); /* Now get rid of the things we don't want */ child = XmSelectionBoxGetChild(SomeDialog, XmDIALOG_SELECTION_LABEL); XtUnmanageChild(child); child = XmSelectionBoxGetChild(SomeDialog, XmDIALOG_TEXT); XtUnmanageChild(child); /* set the callbacks, and make sure the buttons we want are there */ child = XmSelectionBoxGetChild(SomeDialog, XmDIALOG_OK_BUTTON); XtAddCallback(child, XmNactivateCallback, callSomeFunc, someArg); XtAddCallback(child, XmNactivateCallback, unManage, SomeDialog); XtManageChild(child); child = XmSelectionBoxGetChild(SomeDialog, XmDIALOG_APPLY_BUTTON); XtAddCallback(child, XmNactivateCallback, callSomeFunc, someOtherArg); XtManageChild(child); child = XmSelectionBoxGetChild(SomeDialog, XmDIALOG_CANCEL_BUTTON); XtAddCallback(child, XmNactivateCallback, dialogUnmanage, SomeDialog); XtManageChild(child); /* Add a new work area. This can be any manager. */ child = XmCreateForm(SomeDialog, "someForm", NULL, 0); XtManageChild(child); /* and fill it up... */ something = doYourStuff(child); another Answer: I had a some people asking about my xmSmartMessageBoxWidget It's public domain, and needs Motif-1.2 and is available at ftp.x.org:/contrib/widget/SmartMB.tar.Z. The basic idea behind it is that it allows the programmer to specify the management of child widgets in 4 areas: Label, Control, Separator and Action. You can have up to 1 Label, 1 Control, 1 Separator and as many Action children as you want. It does not REQUIRE any of these, and there is no unmanaging of extra widgets, as the programmer creates what is needed. Thanks for the smart dialog info to: John L. Cwikla Wolfram Research, Inc. cwikla@wri.com ----------------------------------------------------------------------------- Subject: 222) Why do dialog title bars have "_popup" or "<-popup" concatenated onto the widget name? Answer: Motif 1.0.3 (?) "fixed" things such that title bars without an explicit dialogTitle setting use the widget name with "_popup" or whatever added on. Set the dialogTitle resource explicitly if you don't want this new default naming scheme. ----------------------------------------------------------------------------- Subject: 223) How can I force a dialog window to display? I manage a "working" dialog, and do some computing, but the dialog window appears blank until the work has finished. How can I force it to be displayed? [Last modified: Dec '94] Answer: David Brooks <dbrooks@ics.com> writes: The dialog window won't get expose events until the window manager has fielded the map request, done the reparenting with all that entails, and finally convinced the server that the window is for real. The safe way of doing it is [below]. Use this. (David Brooks, Systems Engineering, Open Software Foundation) /* * This procedure will ensure that, if a dialog window is being mapped, * its contents become visible before returning. It is intended to be * used just before a bout of computing that doesn't service the display. * You should still call XmUpdateDisplay() at intervals during this * computing if possible. * * The monitoring of window states is necessary because attempts to map * the dialog are redirected to the window manager (if there is one) and * this introduces a significant delay before the window is actually mapped * and exposed. This code works under mwm, twm, uwm, and no-wm. It * doesn't work (but doesn't hang) with olwm if the mainwindow is iconified. * * The argument to ForceDialog is any widget in the dialog (often it * will be the BulletinBoard child of a DialogShell). */ ForceDialog(w) Widget w; { Widget diashell, topshell; Window diawindow, topwindow; Display *dpy; XWindowAttributes xwa; XEvent event; XtAppContext cxt; /* Locate the shell we are interested in. In a particular instance, you * may know these shells already. */ for (diashell = w; !XtIsShell(diashell); diashell = XtParent(diashell)) ; /* Locate its primary window's shell (which may be the same) */ for (topshell = diashell; !XtIsTopLevelShell(topshell); topshell = XtParent(topshell)) ; if (XtIsRealized(diashell) && XtIsRealized(topshell)) { dpy = XtDisplay(topshell); diawindow = XtWindow(diashell); topwindow = XtWindow(topshell); cxt = XtWidgetToApplicationContext(diashell); /* Wait for the dialog to be mapped. It's guaranteed to become so unless... */ while (XGetWindowAttributes(dpy, diawindow, &xwa), xwa.map_state != IsViewable) { /* ...if the primary is (or becomes) unviewable or unmapped, it's probably iconified, and nothing will happen. */ if (XGetWindowAttributes(dpy, topwindow, &xwa), xwa.map_state != IsViewable) break; /* At this stage, we are guaranteed there will be an event of some kind. Beware; we are presumably in a callback, so this can recurse. */ XtAppNextEvent(cxt, &event); XtDispatchEvent(&event); } } /* The next XSync() will get an expose event if the dialog was unmapped. */ XmUpdateDisplay(topshell); } ----------------------------------------------------------------------------- Subject: 224) How can I control placement of a popup widget? Each time a popup is created, it is placed in or over the middle of its parent. How can I make it obey the XmNx and XmNy values? [Last modified: Feb 95] Answer: Set the resource XmNdefaultPosition for the popup to False. Set the position of the popup by the resource values of XmNx and XmNy. Do not use XtMoveWidget, as this is for widget writers only. Here's a demo program from Dan Heller: /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates. * This program is freely distributable without licensing fees and * is provided without guarantee or warranty expressed or implied. * This program is -not- in the public domain. This program is * taken from the Motif Programming Manual, O'Reilly Volume 6. */ /* map_dlg.c -- Use the XmNmapCallback to automatically position * a dialog on the screen. Each time the dialog is displayed, it * is mapped down and to the right by 200 pixels in each direction. */ #include <Xm/MessageB.h> #include <Xm/PushB.h> /* main() --create a pushbutton whose callback pops up a dialog box */ main(argc, argv) char *argv[]; { Widget toplevel, button; XtAppContext app; void pushed(); toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); button = XtCreateManagedWidget("button", xmPushButtonWidgetClass, toplevel, NULL, 0); XtAddCallback(button, XmNactivateCallback, pushed, "Hello World"); XtRealizeWidget(toplevel); XtAppMainLoop(app); } /* callback function for XmNmapCallback. Position dialog in 200 pixel * "steps". When the edge of the screen is hit, start over. */ static void map_dialog(dialog, client_data, cbs) Widget dialog; XtPointer client_data; XmAnyCallbackStruct *cbs; { static Position x, y; Dimension w, h; XtVaGetValues(dialog, XmNwidth, &w, XmNheight, &h, NULL); if ((x + w) >= WidthOfScreen(XtScreen(dialog))) x = 0; if ((y + h) >= HeightOfScreen(XtScreen(dialog))) y = 0; XtVaSetValues(dialog, XmNx, x, XmNy, y, NULL); x += 200, y += 200; } /* pushed() --the callback routine for the main app's pushbutton. * Create and popup a dialog box that has callback functions for * the Ok, Cancel and Help buttons. */ void pushed(w, message) Widget w; char *message; /* The client_data parameter passed by XtAddCallback */ { Widget dialog; Arg arg[3]; XmString t = XmStringCreateLocalized(message); extern void response(); XtSetArg(arg[0], XmNautoUnmanage, False); XtSetArg(arg[1], XmNmessageString, t); XtSetArg(arg[2], XmNdefaultPosition, False); dialog = XmCreateMessageDialog(w, "notice", arg, 3); XmStringFree(t); XtAddCallback(dialog, XmNmapCallback, map_dialog, NULL); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); } ----------------------------------------------------------------------------- Subject: 225) How can I set the dialog's default button? [Last modified: June 95] Answer: Use XmNdefaultButton on the bulletin board widget. Ken Lee ----------------------------------------------------------------------------- Subject: 226) How can I create a dialog that behaves like, but looks a little different from, XmMessageBox? [Last modified: June 95] Answer: Motif 1.2 provides a XmCreateTemplateDialog(), which allows you to specify any combination of child widgets. Ken Lee ----------------------------------------------------------------------------- Subject: 227) How can I use Motif's message dialog bitmaps in my own dialogs? [Last modified: Nov 95] Answer: The bitmaps are normally stored in /usr/include/X11/bitmaps (or the equivalent bitmaps directory, which is vendor specific) and are cached if you create a XmMessageBox. You can retrieve them by name with XmGetPixmap() or XmGetPixmapByDepth(). The names of the bitmap files are in the XmMessageBox man page. Ken Lee ----------------------------------------------------------------------------- END OF PART SIX