home *** CD-ROM | disk | FTP | other *** search
/ ftp.pasteur.org/FAQ/ / ftp-pasteur-org-FAQ.zip / FAQ / motif-faq / part9 < prev   
Text File  |  2004-05-05  |  62KB  |  1,734 lines

  1. Path: senator-bedfellow.mit.edu!dreaderd!not-for-mail
  2. Message-ID: <motif-faq/part9_1083675484@rtfm.mit.edu>
  3. Supersedes: <motif-faq/part9_1082292761@rtfm.mit.edu>
  4. Expires: 17 Jun 2004 12:58:04 GMT
  5. References: <motif-faq/part1_1083675484@rtfm.mit.edu>
  6. X-Last-Updated: 2002/01/31
  7. Organization: none
  8. Subject: Motif FAQ (Part 9 of 9)
  9. Newsgroups: comp.windows.x.motif,comp.answers,news.answers
  10. Keywords: FAQ question answer
  11. From: kenton@rahul.net (Ken Lee)
  12. Reply-To: kenton@rahul.net (Ken Lee)
  13. Approved: news-answers-request@MIT.EDU
  14. Followup-To: poster
  15. Summary: Motif Frequently Asked Questions (with answers).
  16. Originator: faqserv@penguin-lust.MIT.EDU
  17. Date: 04 May 2004 12:59:13 GMT
  18. Lines: 1713
  19. NNTP-Posting-Host: penguin-lust.mit.edu
  20. X-Trace: 1083675553 senator-bedfellow.mit.edu 568 18.181.0.29
  21. Xref: senator-bedfellow.mit.edu comp.windows.x.motif:75192 comp.answers:57057 news.answers:270861
  22.  
  23. Archive-name: motif-faq/part9
  24. Last-modified: 1 FEB 2002
  25. Posting-Frequency: irregular
  26. Organization: Kenton Lee, X/Motif Consultant, http://www.rahul.net/kenton/
  27. URL:  http://www.rahul.net/kenton/mfaq.html
  28. Version: 8.1
  29.  
  30. -----------------------------------------------------------------------------
  31. Subject: 293)  Why doesn't the Help callback work on some widgets?
  32. [Last modified: May 95]
  33.  
  34. Answer: If you press the help key the help callback of the widget with the
  35. keyboard focus is called (not the one containing the mouse).  You can't get
  36. the help callback of a non-keyboard-selectable widget called. To get `context
  37. sensitive' help on these, you have to find the mouse, associate its position
  38. with a widget and then do the help.
  39.  
  40. The X Resource, Issue 6, has an article on implementing context help in Motif
  41. in this manner, that is, using the mouse position to indicate the widget for
  42. which context help is desired, as well as using resources to specify the help.
  43.  
  44. The demo program lets you toggle between using the method described in the
  45. article and XmTrackingLocate() for comparision purposes.
  46.  
  47. Contributed by: Jay Schmidgall  jay@vnet.ibm.com (author of the article
  48. mentioned above).  Thanks to chen@adi.com (Franklin Chen) for correcting the
  49. URL.
  50.  
  51. -----------------------------------------------------------------------------
  52. Subject: 294)*  How can I implement "bubble help" or "tool tips" with Motif?
  53. [Last modified: Jan 02]
  54.  
  55. Answer: Open Motif 2.2 includes a built-in ToolTips feature.  The following
  56. material may be of interest to users of earlier versions of Motif.
  57.  
  58. Gary Aviv (gary@compgen.com) informed this maintainer about the free LiteClue
  59. widget from Computer Generation, Inc. (http://www.compgen.com/).  LiteClue is
  60. a widget which pops a one line help message when the user passes the pointer
  61. over another "watched" widget. This is known by various names in the industry
  62. such as hints, clues, tips, bubble help and balloon help. Technical
  63. documentation and source for the LiteClue widget are available from:
  64.  
  65. http://www.compgen.com/widgets/LiteClue.html
  66. ftp://ftp.compgen.com/pub/widgets/LiteClue.tar.Z
  67.  
  68.  
  69. Ken Lee (http://www.rahul.net/kenton/) writes: A simple technique is to popup
  70. a shell containing your message whenever an enter event occurs (possibly
  71. delayed by a timer) and pop it down again after a leave event.
  72.  
  73. David Lewis (dbl@ics.com) writes: To those resources I should add that the
  74. XmHTML sources (HTML parser, browser, etc) have this ToolTip/bubble-help/popup
  75. feature, in readily-usable code. In addition, the ICS EnhancementPak widget
  76. set (http://www.ics.com) has both a toolbar with built-in popups for its
  77. entries and a small library which adds popup capabilities to any widget.
  78.  
  79. -----------------------------------------------------------------------------
  80. Subject: 295)  Can I specify a widget in a resource file?
  81.  
  82. Answer: This answer, which uses the Xmu library, is due to David Elliott.  If
  83. the converter is added, then the name of a widget (a string) can be used in
  84. resource files, and will be converted to the appropriate widget.
  85.  
  86. This code, which was basically stolen from the Athena Form widget, adds a
  87. String to Widget converter.  I wrote it as a general routine that I call at
  88. the beginning of all of my programs, and made it so I could add other
  89. converters as needed (like String to Unit Type ;-).
  90.  
  91. #include <X11/Intrinsic.h>
  92. #include <X11/StringDefs.h>
  93. #include <Xm/Xm.h>
  94. #include <X11/Xmu/Converters.h>
  95. #include <X11/IntrinsicP.h>
  96. #include <X11/CoreP.h>
  97.  
  98. void
  99. setupConverters()
  100. {
  101.         static XtConvertArgRec parentCvtArgs[] = {
  102.                 {XtBaseOffset, (caddr_t)XtOffset(Widget, core.parent),
  103.                         sizeof(Widget)}
  104.         };
  105.         XtAddConverter(XmRString, XmRWindow, XmuCvtStringToWidget,
  106.                 parentCvtArgs, XtNumber(parentCvtArgs));
  107. }
  108.  
  109.  
  110. -----------------------------------------------------------------------------
  111. Subject: 296)  Why are only some of my translations are being installed?  I
  112. have a translation table like the following, but only the first ones are
  113. getting installed and the rest are ignored.
  114.  
  115. *Text.translations:    #override \
  116. Ctrl<Key>a:    beginning-of-line() \n\
  117. Ctrl<Key>e:    end-of-line() \n\
  118. Ctrl<Key>f:    forward-character() \n\
  119.  
  120. Answer: Most likely, you have a space at the end of one of the lines (the
  121. first in this case).
  122.  
  123. Ctrl<Key>a:    beginning-of-line() \n\
  124.                                   ^ space here
  125.  
  126. The second backslash in each line is there to protect the real newline
  127. character and so you must not follow it with anything other than the newline
  128. itself. Otherwise it acts as the end of the resource definition and the
  129. remaining lines are not added.
  130.  
  131. -----------------------------------------------------------------------------
  132. Subject: 297)  Can I have separate translations for shifted and unshifted
  133. keys?
  134. [Last modified: Jan 99]
  135.  
  136. Answer: Alec Flett <alecf@netscape.com> writes:
  137.  
  138. I've got an addition for the motif FAQ that just solved a problem I've been
  139. wrestling with for a month - it's really an addition to #303  "Why are only
  140. some of my translations being installed?"
  141.  
  142. On certain platforms you cannot use an upper-case key in combination with the
  143. Shift modifier.  For example,
  144.  
  145.     Meta Shift <Key>F:   find-in-list()
  146.  
  147. will not always work because the F is capitalized.
  148.  
  149. The reason for this is because some platforms (such as IRIX) distinguish upper
  150. case and lowercase keysyms. Using Jamie Zawinski's xkeycaps program
  151. (http://www.jwz.org/xkeycaps/), you will see that on Solaris the "F" key just
  152. has one keysym: "F" On IRIX they same key has two: "f" and "F".
  153.  
  154. -----------------------------------------------------------------------------
  155. Subject: 298)  What are these "non-existant passive grab" warnings?  When I
  156. destroy certain widgets I get a stream of messages
  157.  
  158. Warning: Attempt to remove non-existant passive grab
  159.  
  160.  
  161. Answer: They are meaningless, and you want to ignore them.  Do this (from Kee
  162. Hinckley) by installing an XtWarning handler that explicitly looks for them
  163. and discards them:
  164.  
  165. static void xtWarnCB(String message) {
  166.    if (asi_strstr(message, "non-existant passive grab", TRUE)) return;
  167.    ...
  168.  
  169. They come from Xt, and (W. Scott Meeks): "it's something that the designers of
  170. Xt decided the toolkit should do. Unfortunately, Motif winds up putting
  171. passive grabs all over the place for the menu system.  On the one hand, we
  172. want to remove all these grabs when menus get destroyed so that they don't
  173. leak memory; on the other hand, it's almost impossible to keep track of all
  174. the grabs, so we have a conservative strategy of ungrabbing any place where a
  175. grab could have been made and we don't explicitly know that there is no grab.
  176. The unfortunate side effect is the little passive grab warning messages.
  177. We're trying to clean these up where possible, but there are some new places
  178. where the warning is generated.  Until we get this completely cleaned up (1.2
  179. maybe), your best bet is probably to use a warning handler."
  180.  
  181. -----------------------------------------------------------------------------
  182. Subject: 299)  How do I have more buttons than three in a MessageBox?  I want
  183. to have something like a MessageBox (or other widget) with more than three
  184.  
  185.  
  186. buttons, but with the same nice appearance.
  187. [Last modified: Feb 95]
  188.  
  189. Answer: The Motif 1.2 MessageBox widget allows extra buttons to be added after
  190. the OK button. Just create the extra buttons as children of the MessageBox.
  191. Similarly with the SelectionBox.
  192.  
  193. Pre-Motif 1.2, you have to do one of the following methods.
  194.  
  195. A SelectionBox is created with four buttons, but the fourth (the Apply button)
  196. is unmanaged. To manage it get its widget ID via
  197. XmSelectionBoxGetChild(parent, XmDIALOG_APPLY_BUTTON) and then XtManage it.
  198. Unmanage all of the other bits in the SelectionBox that you don't want.  If
  199. you want more than four buttons, try two SelectionBoxes (or similar) together
  200. in a container, where all of the unwanted parts of the widgets are unmanaged.
  201.  
  202. Alternatively, build your own dialog:
  203.  
  204. /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  205. * This program is freely distributable without licensing fees and
  206. * is provided without guarantee or warranty expressed or implied.
  207. * This program is -not- in the public domain.  This program is
  208. * taken from the Motif Programming Manual, O'Reilly Volume 6.
  209. */
  210.  
  211. /* action_area.c -- demonstrate how CreateActionArea() can be used
  212. * in a real application.  Create what would otherwise be identified
  213. * as a PromptDialog, only this is of our own creation.  As such,
  214. * we provide a TextField widget for input.  When the user presses
  215. * Return, the Ok button is activated.
  216. */
  217. #include <Xm/DialogS.h>
  218. #include <Xm/PushBG.h>
  219. #include <Xm/PushB.h>
  220. #include <Xm/LabelG.h>
  221. #include <Xm/PanedW.h>
  222. #include <Xm/Form.h>
  223. #include <Xm/RowColumn.h>
  224. #include <Xm/TextF.h>
  225.  
  226. typedef struct {
  227. char *label;
  228. void (*callback)();
  229. caddr_t data;
  230. } ActionAreaItem;
  231.  
  232. static void
  233. do_dialog(), close_dialog(), activate_cb(),
  234. ok_pushed(), cancel_pushed(), help();
  235.  
  236. main(argc, argv)
  237. int argc;
  238. char *argv[];
  239. {
  240. Widget toplevel, button;
  241. XtAppContext app;
  242.  
  243. toplevel = XtVaAppInitialize(&app, "Demos",
  244. NULL, 0, &argc, argv, NULL, NULL);
  245.  
  246. button = XtVaCreateManagedWidget("Push Me",
  247. xmPushButtonWidgetClass, toplevel, NULL);
  248. XtAddCallback(button, XmNactivateCallback, do_dialog, NULL);
  249.  
  250. XtRealizeWidget(toplevel);
  251. XtAppMainLoop(app);
  252. }
  253.  
  254. /* callback routine for "Push Me" button.  Actually, this represents
  255. * a function that could be invoked by any arbitrary callback.  Here,
  256. * we demonstrate how one can build a standard customized dialog box.
  257. * The control area is created here and the action area is created in
  258. * a separate, generic routine: CreateActionArea().
  259. */
  260. static void
  261. do_dialog(w, file)
  262. Widget w; /* will act as dialog's parent */
  263. char *file;
  264. {
  265. Widget dialog, pane, rc, label, text_w, action_a;
  266. XmString string;
  267. extern Widget CreateActionArea();
  268. Arg args[10];
  269. static ActionAreaItem action_items[] = {
  270. { "Ok",     ok_pushed,     NULL          },
  271. { "Cancel", cancel_pushed, NULL          },
  272. { "Close",  close_dialog,  NULL          },
  273. { "Help",   help,          "Help Button" },
  274. };
  275.  
  276. /* The DialogShell is the Shell for this dialog.  Set it up so
  277. * that the "Close" button in the window manager's system menu
  278. * destroys the shell (it only unmaps it by default).
  279. */
  280. dialog = XtVaCreatePopupShell("dialog",
  281. xmDialogShellWidgetClass, XtParent(w),
  282. XmNtitle,  "Dialog Shell",     /* give arbitrary title in wm */
  283. XmNdeleteResponse, XmDESTROY,  /* system menu "Close" action */
  284. NULL);
  285.  
  286. /* now that the dialog is created, set the Close button's
  287. * client data, so close_dialog() will know what to destroy.
  288. */
  289. action_items[2].data = (caddr_t)dialog;
  290.  
  291. /* Create the paned window as a child of the dialog.  This will
  292. * contain the control area (a Form widget) and the action area
  293. * (created by CreateActionArea() using the action_items above).
  294. */
  295. pane = XtVaCreateWidget("pane", xmPanedWindowWidgetClass, dialog,
  296. XmNsashWidth,  1,
  297. XmNsashHeight, 1,
  298. NULL);
  299.  
  300. /* create the control area (Form) which contains a
  301. * Label gadget and a List widget.
  302. */
  303. rc = XtVaCreateWidget("control_area", xmRowColumnWidgetClass, pane, NULL);
  304. string = XmStringCreateLocalized("Type Something:");
  305. XtVaCreateManagedWidget("label", xmLabelGadgetClass, rc,
  306. XmNlabelString,    string,
  307. XmNleftAttachment, XmATTACH_FORM,
  308. XmNtopAttachment,  XmATTACH_FORM,
  309. NULL);
  310. XmStringFree(string);
  311.  
  312. text_w = XtVaCreateManagedWidget("text-field",
  313. xmTextFieldWidgetClass, rc, NULL);
  314.  
  315. /* RowColumn is full -- now manage */
  316. XtManageChild(rc);
  317.  
  318. /* Set the client data "Ok" and "Cancel" button's callbacks. */
  319. action_items[0].data = (caddr_t)text_w;
  320. action_items[1].data = (caddr_t)text_w;
  321.  
  322. /* Create the action area -- we don't need the widget it returns. */
  323. action_a = CreateActionArea(pane, action_items, XtNumber(action_items));
  324.  
  325. /* callback for Return in TextField.  Use action_a as client data */
  326. XtAddCallback(text_w, XmNactivateCallback, activate_cb, action_a);
  327.  
  328. XtManageChild(pane);
  329. XtPopup(dialog, XtGrabNone);
  330. }
  331.  
  332. /*--------------*/
  333. /* The next four functions are the callback routines for the buttons
  334. * in the action area for the dialog created above.  Again, they are
  335. * simple examples, yet they demonstrate the fundamental design approach.
  336. */
  337. static void
  338. close_dialog(w, shell)
  339. Widget w, shell;
  340. {
  341. XtDestroyWidget(shell);
  342. }
  343.  
  344. /* The "ok" button was pushed or the user pressed Return */
  345. static void
  346. ok_pushed(w, text_w, cbs)
  347. Widget w, text_w;         /* the text widget is the client data */
  348. XmAnyCallbackStruct *cbs;
  349. {
  350. char *text = XmTextFieldGetString(text_w);
  351.  
  352. printf("String = %s0, text);
  353. XtFree(text);
  354. }
  355.  
  356. static void
  357. cancel_pushed(w, text_w, cbs)
  358. Widget w, text_w;         /* the text field is the client data */
  359. XmAnyCallbackStruct *cbs;
  360. {
  361. /* cancel the whole operation; reset to NULL. */
  362. XmTextFieldSetString(text_w, "");
  363. }
  364.  
  365. static void
  366. help(w, string)
  367. Widget w;
  368. String string;
  369. {
  370. puts(string);
  371. }
  372. /*--------------*/
  373.  
  374. /* When Return is pressed in TextField widget, respond by getting
  375. * the designated "default button" in the action area and activate
  376. * it as if the user had selected it.
  377. */
  378. static void
  379. activate_cb(text_w, client_data, cbs)
  380. Widget text_w;              /* user pressed Return in this widget */
  381. XtPointer client_data;        /* action_area passed as client data */
  382. XmAnyCallbackStruct *cbs;   /* borrow the "event" field from this */
  383. {
  384. Widget dflt, action_area = (Widget)client_data;
  385.  
  386. XtVaGetValues(action_area, XmNdefaultButton, &dflt, NULL);
  387. if (dflt) /* sanity check -- this better work */
  388. /* make the default button think it got pushed.  This causes
  389.  * "ok_pushed" to be called, but XtCallActionProc() causes
  390.  * the button appear to be activated as if the user selected it.
  391.  */
  392. XtCallActionProc(dflt, "ArmAndActivate", cbs->event, NULL, 0);
  393. }
  394.  
  395. #define TIGHTNESS 20
  396.  
  397. Widget
  398. CreateActionArea(parent, actions, num_actions)
  399. Widget parent;
  400. ActionAreaItem *actions;
  401. int num_actions;
  402. {
  403. Widget action_area, widget;
  404. int i;
  405.  
  406. action_area = XtVaCreateWidget("action_area", xmFormWidgetClass, parent,
  407. XmNfractionBase, TIGHTNESS*num_actions - 1,
  408. XmNleftOffset,   10,
  409. XmNrightOffset,  10,
  410. NULL);
  411.  
  412. for (i = 0; i < num_actions; i++) {
  413. widget = XtVaCreateManagedWidget(actions[i].label,
  414.     xmPushButtonWidgetClass, action_area,
  415.     XmNleftAttachment,       i? XmATTACH_POSITION : XmATTACH_FORM,
  416.     XmNleftPosition,         TIGHTNESS*i,
  417.     XmNtopAttachment,        XmATTACH_FORM,
  418.     XmNbottomAttachment,     XmATTACH_FORM,
  419.     XmNrightAttachment,
  420.             i != num_actions-1? XmATTACH_POSITION : XmATTACH_FORM,
  421.     XmNrightPosition,        TIGHTNESS*i + (TIGHTNESS-1),
  422.     XmNshowAsDefault,        i == 0,
  423.     XmNdefaultButtonShadowThickness, 1,
  424.     NULL);
  425. if (actions[i].callback)
  426.     XtAddCallback(widget, XmNactivateCallback,
  427.         actions[i].callback, actions[i].data);
  428. if (i == 0) {
  429.     /* Set the action_area's default button to the first widget
  430.      * created (or, make the index a parameter to the function
  431.      * or have it be part of the data structure). Also, set the
  432.      * pane window constraint for max and min heights so this
  433.      * particular pane in the PanedWindow is not resizable.
  434.      */
  435.     Dimension height, h;
  436.     XtVaGetValues(action_area, XmNmarginHeight, &h, NULL);
  437.     XtVaGetValues(widget, XmNheight, &height, NULL);
  438.     height += 2 * h;
  439.     XtVaSetValues(action_area,
  440.         XmNdefaultButton, widget,
  441.         XmNpaneMaximum,   height,
  442.         XmNpaneMinimum,   height,
  443.         NULL);
  444. }
  445. }
  446.  
  447. XtManageChild(action_area);
  448.  
  449. return action_area;
  450. }
  451.  
  452.  
  453. -----------------------------------------------------------------------------
  454. Subject: 300)  How do I create a "busy working cursor"?
  455. [Last modified: Feb 95]
  456.  
  457. Answer: - in Baudouin's code (following), the idea is to keep in an array an
  458. up-to-date list of all shells used in the application, and set for all of them
  459. the cursor to a watch or to the default cursor, with the 2 functions provided.
  460.  
  461. - in Dan Heller's code (later), the idea is to turn on the watch cursor for
  462. the top-level shell only, popup a working window to possibly abort the
  463. callback, and manage some expose events during the callback.
  464.  
  465. - in the FAQ for comp.windows.x, the idea is to bring a large window on top of
  466. the application, hide all windows below it, and turn on the watch cursor on
  467. this large window. Unmapping the large window resets the default cursor,
  468. mapping it turns on the watch cursor.
  469.  
  470. Baudouin Raoult (mab@ecmwf.int) wrote:
  471.  
  472. void my_SetWatchCursor(w)
  473. Widget w;
  474. {
  475. static Cursor watch = NULL;
  476.  
  477. if(!watch)
  478.         watch = XCreateFontCursor(XtDisplay(w),XC_watch);
  479.  
  480. XDefineCursor(XtDisplay(w),XtWindow(w),watch);
  481. XmUpdateDisplay(w);
  482. }
  483.  
  484. void my_ResetCursor(w)
  485. Widget w;
  486. {
  487. XUndefineCursor(XtDisplay(w),XtWindow(w));
  488. XmUpdateDisplay(w);
  489. }
  490.  
  491.  
  492. Answer: A solution with lots of bells and whistles is
  493.  
  494. /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  495. * This program is freely distributable without licensing fees and
  496. * is provided without guarantee or warrantee expressed or implied.
  497. * This program is -not- in the public domain.
  498. */
  499.  
  500. /* busy.c -- demonstrate how to use a WorkingDialog and to process
  501. * only "important" events.  e.g., those that may interrupt the
  502. * task or to repaint widgets for exposure.  Set up a simple shell
  503. * and a widget that, when pressed, immediately goes into its own
  504. * loop.  First, "lock" the shell so that a timeout cursor is set on
  505. * the shell and pop up a WorkingDialog.  Then enter loop ... sleep
  506. * for one second ten times, checking between each interval to see
  507. * if the user clicked the Stop button or if any widgets need to be
  508. * refreshed.  Ignore all other events.
  509. *
  510. * main() and get_busy() are stubs that would be replaced by a real
  511. * application; all other functions can be used "as is."
  512. */
  513. #include <Xm/MessageB.h>
  514. #include <Xm/PushB.h>
  515. #include <X11/cursorfont.h>
  516.  
  517. Widget shell;
  518. void TimeoutCursors();
  519. Boolean CheckForInterrupt();
  520.  
  521. main(argc, argv)
  522. int argc;
  523. char *argv[];
  524. {
  525. XtAppContext app;
  526. Widget button;
  527. XmString label;
  528. void get_busy();
  529.  
  530. shell = XtVaAppInitialize(&app, "Demos",
  531. NULL, 0, &argc, argv, NULL, NULL);
  532.  
  533. label = XmStringCreateLocalized(
  534. "Boy, is *this* going to take a long time.");
  535. button = XtVaCreateManagedWidget("button",
  536. xmPushButtonWidgetClass, shell,
  537. XmNlabelString,          label,
  538. NULL);
  539. XmStringFree(label);
  540. XtAddCallback(button, XmNactivateCallback, get_busy, argv[1]);
  541.  
  542. XtRealizeWidget(shell);
  543. XtAppMainLoop(app);
  544. }
  545.  
  546. void
  547. get_busy(widget)
  548. Widget widget;
  549. {
  550. int n;
  551.  
  552. TimeoutCursors(True, True);
  553. for (n = 0; n < 10; n++) {
  554. sleep(1);
  555. if (CheckForInterrupt()) {
  556.     puts("Interrupt!");
  557.     break;
  558. }
  559. }
  560. if (n == 10)
  561. puts("done.");
  562. TimeoutCursors(False, NULL);
  563. }
  564.  
  565. /* The interesting part of the program -- extract and use at will */
  566. static Boolean stopped;  /* True when user wants to stop processing */
  567. static Widget dialog;    /* WorkingDialog displayed when timed out */
  568.  
  569. /* timeout_cursors() turns on the "watch" cursor over the application
  570. * to provide feedback for the user that he's going to be waiting
  571. * a while before he can interact with the appliation again.
  572. */
  573. void
  574. TimeoutCursors(on, interruptable)
  575. int on, interruptable;
  576. {
  577. static int locked;
  578. static Cursor cursor;
  579. extern Widget shell;
  580. XSetWindowAttributes attrs;
  581. Display *dpy = XtDisplay(shell);
  582. XEvent event;
  583. Arg args[1];
  584. XmString str;
  585. extern void stop();
  586.  
  587. /* "locked" keeps track if we've already called the function.
  588. * This allows recursion and is necessary for most situations.
  589. */
  590. on? locked++ : locked--;
  591. if (locked > 1 || locked == 1 && on == 0)
  592. return; /* already locked and we're not unlocking */
  593.  
  594. stopped = False; /* doesn't matter at this point; initialize */
  595. if (!cursor) /* make sure the timeout cursor is initialized */
  596. cursor = XCreateFontCursor(dpy, XC_watch);
  597.  
  598. /* if "on" is true, then turn on watch cursor, otherwise, return
  599. * the shell's cursor to normal.
  600. */
  601. attrs.cursor = on? cursor : None;
  602.  
  603. /* change the main application shell's cursor to be the timeout
  604. * cursor (or to reset it to normal).  If other shells exist in
  605. * this application, they will have to be listed here in order
  606. * for them to have timeout cursors too.
  607. */
  608. XChangeWindowAttributes(dpy, XtWindow(shell), CWCursor, &attrs);
  609.  
  610. XFlush(dpy);
  611.  
  612. if (on) {
  613. /* we're timing out, put up a WorkingDialog.  If the process
  614.  * is interruptable, allow a "Stop" button.  Otherwise, remove
  615.  * all actions so the user can't stop the processing.
  616.  */
  617. str = XmStringCreateLocalized("Busy.  Please Wait.");
  618. XtSetArg(args[0], XmNmessageString, str);
  619. dialog = XmCreateWorkingDialog(shell, "Busy", args, 1);
  620. XmStringFree(str);
  621. XtUnmanageChild(
  622.     XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON));
  623. if (interruptable) {
  624.     str = XmStringCreateLocalized("Stop");
  625.     XtVaSetValues(dialog, XmNcancelLabelString, str, NULL);
  626.     XmStringFree(str);
  627.     XtAddCallback(dialog, XmNcancelCallback, stop, NULL);
  628. } else
  629.     XtUnmanageChild(
  630.         XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
  631. XtUnmanageChild(
  632.     XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
  633. XtManageChild(dialog);
  634. } else {
  635. /* get rid of all button and keyboard events that occured
  636.  * during the time out.  The user shouldn't have done anything
  637.  * during this time, so flush for button and keypress events.
  638.  * KeyRelease events are not discarded because accelerators
  639.  * require the corresponding release event before normal input
  640.  * can continue.
  641.  */
  642. while (XCheckMaskEvent(dpy,
  643.         ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
  644.         | PointerMotionMask | KeyPressMask, &event)) {
  645.     /* do nothing */;
  646. }
  647. XtDestroyWidget(dialog);
  648. }
  649. }
  650.  
  651. /* User Pressed the "Stop" button in dialog. */
  652. void
  653. stop(dialog)
  654. Widget dialog;
  655. {
  656. stopped = True;
  657. }
  658.  
  659. Boolean
  660. CheckForInterrupt()
  661. {
  662. extern Widget shell;
  663. Display *dpy = XtDisplay(shell);
  664. Window win = XtWindow(dialog);
  665. XEvent event;
  666.  
  667. /* Make sure all our requests get to the server */
  668. XFlush(dpy);
  669.  
  670. /* Let motif process all pending exposure events for us. */
  671. XmUpdateDisplay(shell);
  672.  
  673. /* Check the event loop for events in the dialog ("Stop"?) */
  674. while (XCheckMaskEvent(dpy,
  675.     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
  676.     PointerMotionMask | KeyPressMask | KeyReleaseMask,
  677.     &event)) {
  678. /* got an "interesting" event. */
  679. if (event.xany.window == win)
  680.     XtDispatchEvent(&event); /* it's in our dialog.. */
  681. else /* uninteresting event--throw it away and sound bell */
  682.     XBell(dpy, 50);
  683. }
  684. return stopped;
  685. }
  686.  
  687.  
  688. -----------------------------------------------------------------------------
  689. Subject: 301)  Can I use the hourglass that mwm uses?
  690. [Last modified: March 93]
  691.  
  692. Answer: The hourglass used by mwm is hard-coded into code that is subject to
  693. OSF copyright. In Motif 1.2 though, the bitmaps for this and other things
  694. (information, no_enter, question, warning, working) were made available.  The
  695. install process will probably add them to /usr/include/X11/bitmaps.
  696. Otherwise, just use the watch cursor XC_watch of the previous question,
  697. because that has the same semantics.
  698.  
  699. -----------------------------------------------------------------------------
  700. Subject: 302)  What order should the libraries be linked in?
  701. [Last modified: August 92]
  702.  
  703. Answer: At link time, use the library order  -lXm -lXt -lX11. There are two
  704. reasons for this (dbrooks@osf.org):
  705.  
  706. On most systems, the order matters because the linker won't re-scan a library
  707. once it is done with it.  Thus any references to Xlib calls from Xm will
  708. probably be unresolved.
  709.  
  710. The [other] problem is that there are two VendorShell widgets. A dummy is
  711. provided in the Xt library, but a widget set will rely on its own being
  712. referenced.  If you mention Xt first, the linker will choose the wrong one.
  713.  
  714. Motif code will wrongly assume the Motif VendorShell has been class-
  715. initialized [and will probably crash].  Xaw has a similar problem, but a
  716. softer landing; it only complains about unregistered converters.
  717.  
  718.  
  719. -----------------------------------------------------------------------------
  720. Subject: 303)  How do I use xmkmf for Motif clients?
  721. [Last modified: July 96]
  722.  
  723. Answer: This advice comes from dbrooks@osf.org. For another answer, see the
  724. question immediately following this one ("How do I use imake with Motif
  725. 2.0?").
  726.  
  727. There are a number of intractable problems with using X configuration files
  728. and xmkmf, while trying to make it easy to build Motif.  Not the least of
  729. these, but one I've never heard mentioned yet, is that the rules for
  730. contructing the names of shared library macros are machine-dependent, and in
  731. the various xxxLib.tmpl files.  Do we edit all those files to add definitions
  732. for XMLIB, DEPXMLIB, etc., or do we put a maze of #ifdefs into the Motif.tmpl
  733. file?
  734.  
  735. Please note that, if you install Motif, it overwrites your installed
  736. Imake.tmpl with one that includes Motif.tmpl and Motif.rules.
  737.  
  738. With those caveats, I think the following guidelines will help.
  739.  
  740. David Brooks OSF
  741.  
  742. Clients in the X11R5 release use the xmkmf command to build Makefiles.  In
  743. general, the xmkmf command cannot be used for Motif clients, because of the
  744. need to consider the UseInstalledMotif flag separately.  Since xmkmf is a
  745. simple script that calls imake, it is easy to construct the proper call to
  746. imake using the following rules.
  747.  
  748. In the following, replace {MTOP} by the toplevel directory with the Motif
  749. source tree, and {XTOP} by the toplevel ("mit") directory with the X source.
  750. It is assumed that the directory containing your installed imake is in your
  751. PATH.
  752.  
  753. When needed, the imake variables XTop and MTop are normally set in your
  754. site.def (to {XTOP} amd {MTOP} respectively); however they may also be set
  755. with additional -D arguments to imake.
  756.  
  757. 1. With both X and Motif in their source trees, ensure the imake variables
  758. XTop and MTop are set, and use:
  759.  
  760. ${XTOP}/config/imake -I{MTOP}/config
  761.  
  762. 2. With Motif in its source tree, and X installed, ensure MTop is set, and
  763. use:
  764.  
  765. imake -I{MTOP}/config -DUseInstalled
  766.  
  767. 3. With both Motif and X installed, and a nonstandard ProjectRoot (see
  768. site.def for an explanation of this), use:
  769.  
  770. imake -DUseInstalled -DUseInstalledMotif -I{ProjectRoot}/lib/X11/config
  771.  
  772. or, if the configuration files are in /usr/lib/X11/config:
  773.  
  774. imake -DUseInstalled -DUseInstalledMotif  -I/usr/lib/X11/config
  775.  
  776. [Thanks to Paul DuBois (dubois@primate.wisc.edu) for correcting this.]
  777.  
  778. To build a simple Imakefile, remember to include lines like this:
  779.  
  780. LOCAL_LIBRARIES = XmClientLibs
  781.         DEPLIBS = XmClientDepLibs
  782.  
  783. Or, for a client that uses uil/mrm, replace these by MrmClientLibs and
  784. MrmClientDepLibs, and also use:
  785.  
  786. MSimpleUilTarget(program)
  787.  
  788. to build the client and uid file.  Look at the demos for more examples.
  789.  
  790.  
  791. And Paul Howell <grue@engin.umich.edu> added:
  792.  
  793. i did this, calling the new script "xmmkmf".  It passes both -DUseInstalled
  794. and -DUseInstalledMotif.
  795.  
  796. and i modified the stock R5 Imake.tmpl to do this:
  797.  
  798. #include <Project.tmpl>
  799. #ifdef UseInstalledMotif
  800. #include <Motif.tmpl>
  801. #endif
  802.  
  803. #include <Imake.rules>
  804. #ifdef UseInstalledMotif
  805. #include <Motif.rules>
  806. #endif
  807.  
  808. the result was something that does both athena and motif rules.  and it really
  809. works, just that easy!
  810.  
  811. -----------------------------------------------------------------------------
  812. Subject: 304)  How do I use imake with Motif 2.0?
  813. [Last modified: July 96]
  814.  
  815. Answer: Paul DuBois (dubois@primate.wisc.edu), the author of the O'Reilly and
  816. Associates book, Software Portability with imake, recently wrote some notes on
  817. the use of imake to configure Motif (2.0). It has some discussion on the roles
  818. of UseInstalled and UseInstalledMotif, for instance, which seem to be murky to
  819. many people.  The document is available at:
  820.  
  821. http://www.primate.wisc.edu/software/imake-stuff
  822.  
  823. -----------------------------------------------------------------------------
  824. Subject: 305)  How do I make context sensitive help?  The Motif Style Guide
  825. says that an application must initiate context-sensitive help by changing the
  826. shape of the pointer to the question pointer. When the user moves the pointer
  827. to the component help is wanted on and presses BSelect, any available context
  828. sensitive help for the component must be presented, and the pointer reverts
  829. from the question pointer.
  830. [Last modified: August 92]
  831.  
  832. Answer: A widget that gives context sensitive help would place this help in
  833. the XmNhelpCallback function. To trigger this function: (from Martin G C
  834. Davies, mgcd@se.alcbel.be)
  835.  
  836. I use the following callback that is called when the "On Context" help
  837. pulldown menu is selected. It does the arrow bit and calls the help callbacks
  838. for the widget. It also zips up the widget tree looking for help if needs be.
  839. I don't restrict the arrows motion so I can get help on dialog boxes. No
  840. prizes for guessing what "popup_message" does.
  841.  
  842.  
  843. static void ContextHelp(
  844. Widget          w ,
  845. Opaque          * tag ,
  846. XmAnyCallbackStruct     * callback_struct
  847. )
  848. {
  849. static Cursor   context_cursor = NULL ;
  850. Widget      context_widget ;
  851.  
  852. if ( context_cursor == NULL )
  853. context_cursor = XCreateFontCursor( display, XC_question_arrow ) ;
  854.  
  855. context_widget = XmTrackingLocate( top_level_widget,
  856.                         context_cursor, FALSE ) ;
  857.  
  858. if ( context_widget != NULL ) /* otherwise its not a widget */
  859. {
  860. XmAnyCallbackStruct cb ;
  861.  
  862. cb.reason = XmCR_HELP ;
  863. cb.event = callback_struct->event ;
  864.  
  865. /*
  866.  * If there's no help at this widget we'll track back
  867.    up the hierarchy trying to find some.
  868.  */
  869.  
  870. do
  871. {
  872.     if ( ( XtHasCallbacks( context_widget, XmNhelpCallback ) ==
  873.                                         XtCallbackHasSome ) )
  874.     {
  875.         XtCallCallbacks( context_widget, XmNhelpCallback, & cb ) ;
  876.         return ;
  877.     }
  878.     else
  879.         context_widget = XtParent( context_widget ) ;
  880. } while ( context_widget != NULL ) ;
  881. }
  882.  
  883. popup_message( "No context-sensitive help found0or the selected object." ) ;
  884. }
  885.  
  886.  
  887. Dave Bonnett suggested, to use the following translations for XmText (and
  888. XmTextField) widgets to get the same help with key strokes, and to provide an
  889. accelerator label in the Context help menu entry.
  890.  
  891. MyApp*XmText*translations: #override\n\
  892.                         <Key>F1:    Help()
  893.  
  894. MyApp*Help_menu*Contextual Help.acceleratorText:   F1
  895.  
  896. MyApp*defaultVirtualBindings:           osfBackSpace : <Key>Delete\n\
  897.                                 osfRight : <Key>Right\n\
  898.                                 osfLeft  : <Key>Left\n\
  899.                                 osfUp    : <Key>Up\n\
  900.                                 osfHelp  : <Key>F1\n\
  901.                                 osfDown  : <Key>Down
  902.  
  903.  
  904. -----------------------------------------------------------------------------
  905. Subject: 306)  How do I debug a modal interaction?
  906.  
  907. When an application crashes in a modal section (such as in a modal dialog, a
  908. menu or when a drag and drop is in action), I cannot access the debugger.
  909. [Last modified: January 1993]
  910.  
  911. Answer: Run the debugger on one display while the application writes to
  912. another display.
  913.  
  914. -----------------------------------------------------------------------------
  915. Subject: 307)  Why can't I install my own colormap using XInstallColormap?
  916. [Last modified: Nov 96]
  917.  
  918. Answer: You shouldn't install the colormap yourself using XInstallColormap.
  919. See the ICCCM document for all the reasons.  Instead put the colormap as an
  920. argument on the Shell widget and the window manager will take care of this.
  921.  
  922. When the colormap is installed,  unless you have a display with multiple
  923. colormaps, the other windows will go "technicolor" and there is no way around
  924. this problem.
  925.  
  926. Thanks to Doug Rand (drand@sgi.com)
  927.  
  928. Kenton Lee (http://www.rahul.net/kenton/) adds: Use XtSetWMColormapWindows()
  929. to specify non-default colormaps.
  930.  
  931. -----------------------------------------------------------------------------
  932. Subject: 308)  How do I install a private colormap?
  933. [Last modified: Jan 96]
  934.  
  935. Answer: Mark Buser (buser@tartan.com) writes: If you find that your
  936. XAllocNamedColor is failing or XpmCreatePixmapFromData is dieing from
  937. XpmColorFaileds, you may have exhausted the number of colormap entries.  One
  938. way to install a new colormap is the following:
  939.  
  940.  
  941. Toplevel = XtVaAppInitialize ( &app, ...
  942. dpy = XtDisplay (Toplevel);
  943. cmap = DefaultColormapOfScreen ( XtScreen( Toplevel) );
  944. /* Detect color errors due to colormap depletion */
  945. if (colors_depleted) {
  946. cmap = XCopyColormapAndFree ( dpy, cmap );
  947.  
  948. /* Run through color allocation again to see if ok now */
  949. }
  950.  
  951. /* Install colormap into toplevel widget.  This must be done
  952. ** before any child widgets are created.
  953. */
  954. XtVaSetValues ( Toplevel, XmNcolormap, cmap, NULL);
  955.  
  956. /* Create any children of toplevel, they will inherit new colormap */
  957.  
  958.  
  959. This is only one way to go, there are other possibilities, but this seems to
  960. be the simplest.
  961.  
  962. -----------------------------------------------------------------------------
  963. Subject: 309)  How do I get correct shadow colors to match other color
  964. changes?
  965. [Last modified: Sept 95]
  966.  
  967. Answer: Thanks to Craig MacFarlane (craigm@chateau-rouge.ICS.UCI.EDU) for the
  968. following explanation and code:
  969.  
  970. You have to make a call to calculate the new shadow colors.  The trick is
  971. actually getting a value of type Pixel when all you have is the string "Blue".
  972. I use the XtConvertAndStore() function to convert from a char * to a Pixel.
  973. For example:
  974.  
  975.  
  976. char *color = "blue";
  977. XrmValue color_value, pixel_value;
  978. Pixel background;
  979.  
  980. color_value.size = strlen(color);
  981. color_value.addr = (XtPointer) color;
  982. pixel_value.size = sizeof(Pixel);
  983. pixel_value.addr = (XtPointer) 0;
  984.  
  985. result = XtConvertAndStore(widget,
  986.                      XtRString, &color_value,
  987.                      XtRPixel, &pixel_value);
  988.  
  989. background = (*(Pixel *)pixel_value.addr);
  990.  
  991.  
  992. You can then use the pixel value obtained by XtConvertAndStore() in the
  993. XmGetColors call.  XmGetColors calculates appropriate foreground, topshadow,
  994. bottomshadow, and select colors for the given background. e.g.
  995.  
  996.  
  997. XmGetColors(screen,
  998.       DefaultColormap(display_id, DefaultScreen(display_id)),
  999.       background,
  1000.       &foreground, &topshadow, &bottomshadow, &select);
  1001.  
  1002.  
  1003. Then it's trivial to set the shadow colors at the same time you set the
  1004. foreground and background colors.  For example:
  1005.  
  1006.  
  1007. XtVaSetValues(widget,
  1008.     XmNforeground, foreground,
  1009.     XmNbackground, background,
  1010.     XmNarmColor, select,
  1011.     XmNtopShadowColor, topshadow,
  1012.     XmNbottomShadowColor, bottomshadow,
  1013.     NULL);
  1014.  
  1015.  
  1016. You'll get asthetically pleasing colors every time. :)
  1017.  
  1018. Wolfram Gries <1gries@informatik.uni-hamburg.de> adds:
  1019.  
  1020. The function XmChangeColor() takes a Widget and a Pixel-value for the new
  1021. background-color and does the calculation of the new shadow-colors on its own.
  1022. But it seems to me that this function is rather slow, so if you often change
  1023. the color of your widgets, the XmGetColors()/XmSetColors() approach might be
  1024. better.
  1025.  
  1026. -----------------------------------------------------------------------------
  1027. Subject: 310)  What color algorithm does Motif use?  I am told that Motif uses
  1028. some sort of algorithm that will take a single color that is defined for the
  1029. "background" and scale it so that the widget remains discriminable from the
  1030. background, etc.  What is the algorithm?
  1031. [Last modified: Oct 94]
  1032.  
  1033. Answer: Chris Flatters (cflatter@nrao.edu) writes: Shiz Kobara's book "Visual
  1034. Design with OSF/Motif", Addison Wesley,  1991, ISBN 0-201-56320-7) is a good
  1035. source for information of this sort.  I haven't seen it in bookshops for a
  1036. while so it may have gone out of print (which would be a pity).  In essence
  1037. each widget has 4 colours which, to first order, are
  1038.  
  1039. background
  1040. select          (background * 85%)
  1041. top shadow      (background * 150%)
  1042. bottom shadow   (background * 50%)
  1043.  
  1044. An additional correction may be applied to the hues of the calculated colours
  1045. if any of the RGB values saturates.  The algorithm works best if the brightest
  1046. of the RGB components lies in the range 155-175 (on a scale of 0-255).  The
  1047. top shadow becomes darker than the background for light background colours
  1048. which does not lead to a particularly pleasing effect.
  1049.  
  1050. -----------------------------------------------------------------------------
  1051. Subject: 311)  How can you access the superclass widget from which Motif
  1052. convenience dialogs are subclassed?
  1053. [Last modified: Oct 94]
  1054.  
  1055. Answer: Kim Frei (uunet!ask.uniras.dk!kimf) wrote: If you are using Motif 1.2,
  1056. read about XmTemplateDialog.
  1057.  
  1058. -----------------------------------------------------------------------------
  1059. Subject: 312)  Can the Motif 2.0 Notebook widget display non-rectangular "file
  1060. tabs"?  Is it possible to use the Shape extension to fiddle with the shape of
  1061. the major tabs (XmPushButtons right now) to get non-rectangular buttons, going
  1062. for that "file tab" look?
  1063. [Last modified: May 95]
  1064.  
  1065. Answer: Vania Joloboff <uunet!gr.osf.org!vania> wrote:
  1066.  
  1067. On the Motif 2.0* CD-ROM, in the demos directory, there is a library of
  1068. additional widgets lib/Exm.  Among the widgets, there is a ExmTabButton
  1069. especially designed to fit within a Notebook. It has a smooth shape like real
  1070. tabs in folders.
  1071.  
  1072.  
  1073. It also a good example on how to use the new traits and the Xme API for widget
  1074. writers.
  1075.  
  1076. (Thanks to Ken Lee, http://www.rahul.net/kenton/, for a correction here.)
  1077.  
  1078. -----------------------------------------------------------------------------
  1079. Subject: 313)  How does the clipboard mechanism work?
  1080. [Last modified: Dec 94]
  1081.  
  1082. A.  Doug Rand <drand@sgi.com> writes:
  1083.  
  1084. Basically there are two selections CLIPBOARD_MANAGER and CLIPBOARD which are
  1085. used.  The Motif clipboard is not a clipboard manager, but xclipboard,  or a
  1086. more functional clipboard client would be.  The newest ICCCM (2.0) spells this
  1087. out.
  1088.  
  1089. The basic process is that the clipboard manager:
  1090.  
  1091. 1) Check to see if CLIPBOARD_MANAGER is owned by anyone,  abort if it is.
  1092.  
  1093. 2) Assert ownership of CLIPBOARD_MANAGER and CLIPBOARD
  1094.  
  1095. 3) When the CLIPBOARD selection is lost,  query new owner for data and then
  1096. retake ownership of CLIPBOARD
  1097.  
  1098. #3 is done until the application exists.  What you do with the data is up to
  1099. the application.
  1100.  
  1101. -----------------------------------------------------------------------------
  1102. Subject: 314)  Why does the xyz application core dump when I cut and paste?
  1103.  
  1104. Answer: Application crashes when text is cut and pasted into an XmText widget
  1105. may occur with statically linked executables linked with X11R5 libraries under
  1106. SunOS. For example, a Netscape README file says:
  1107.  
  1108. The SunOS 4.1 [Netscape 0.94] distribution also includes a directory called
  1109. "nls".  This directory is a standard part of the MIT X11R5 distribution, but
  1110. is not included with OpenWindows 3.0 or earlier.  We have linked Netscape
  1111. against the MIT R5 libraries because they are less buggy in general; however,
  1112. they have one rather serious bug, which is that if this "nls" directory does
  1113. not exist, the program will dump core any time you try to paste into a text
  1114. field!
  1115.  
  1116. So, if you don't have the "nls" directory on your system, you will need to
  1117. install it first.  The usual place is /usr/lib/X11/nls, but you can put it
  1118. anywhere: just point the $XNLSPATH environment variable at it.
  1119.  
  1120. Some sites don't have their X libraries installed in /usr/lib/X11/.  This
  1121. doesn't matter.  You either need to put the nls directory in /usr/lib/X11/, or
  1122. every user will need to set this environment variable.
  1123.  
  1124. So, for example, we do:
  1125.  
  1126. setenv XNLSPATH /usr/local/x11r5/lib/X11/nls
  1127.  
  1128. since our X11R5 is not installed in the default location.
  1129.  
  1130. -----------------------------------------------------------------------------
  1131. Subject: 315)  Why is XtWindow(widget) == 0?
  1132. [Last modified: Oct 95]
  1133.  
  1134. Answer: The window is not created (and is NULL) until the widget is realized.
  1135. In general, using XtWindow() is a bad idea.  In most cases, you can create
  1136. more robust code by subclassing the widget and putting your window code in new
  1137. wiget class methods.
  1138.  
  1139. Ken Lee
  1140.  
  1141. -----------------------------------------------------------------------------
  1142. Subject: 316)  How do I debug X protocol errors (e.g., BadWindow, BadMatch) in
  1143. Motif applications?
  1144.  
  1145. [Last modified: Jun 98]
  1146. Answer: For a general tutorial on X protocol errors, see:
  1147.  
  1148. http://www.rahul.net/kenton/perrors.html
  1149.  
  1150.  
  1151. Here are two common problems.  First, if you get a BadWindow error showing a
  1152. 0x0 window ID, you're probably calling XtWindow() on a widget that is not
  1153. realized.  See the previous subject.
  1154.  
  1155. Second, a BadMatch error often indicates that the depth of a window or a
  1156. pixmap is not correct.  You could be using a depth 1 pixmap when you should be
  1157. using a pixmap with the depth of the associated window.  Or, you could be
  1158. creating a new shell with a depth that does not match its visual type or
  1159. colormap.
  1160.  
  1161. Ken Lee
  1162.  
  1163. -----------------------------------------------------------------------------
  1164. Subject: 317)  Why doesn't XtNameToWidget (widget, "MyName") work?
  1165. [Last modified: Apr 95]
  1166.  
  1167. Answer: The second argument must be a qualified specification (like a resource
  1168. specification).  In most cases, you'll use something like "*MyName".  The
  1169. leading '*' is required.
  1170.  
  1171. Ken Lee
  1172.  
  1173. -----------------------------------------------------------------------------
  1174. Subject: 318)  Why does my callback's client data structure contain incorrect
  1175. values when the callback is called?  I created a structure and used a pointer
  1176. to it as callback client data.
  1177. [Last modified: Apr 95]
  1178.  
  1179. Answer: If your structure is declared as automatic, the callback will probably
  1180. not be executed within the structure's scope, so the pointer to the structure
  1181. will become invalid.  You can avoid this problem by declaring your structure
  1182. external or by allocating with malloc or (in C++) new.
  1183.  
  1184. Ken Lee
  1185.  
  1186. -----------------------------------------------------------------------------
  1187. Subject: 319)  How can an application manage events on multiple displays?
  1188. [Last modified: May 95]
  1189.  
  1190. Answer: Just put multiple display pointers into one application context.  (You
  1191. normally specify which application context as an argument to XtOpenDisplay()).
  1192. XtAppNextEvent() and XtAppMainLoop() automatically poll all displays in the
  1193. application context.
  1194.  
  1195. Ken Lee
  1196.  
  1197. -----------------------------------------------------------------------------
  1198. Subject: 320)  Can a Motif application create windows on mutiple screens (on a
  1199. multi-screen workstation)?
  1200. [Last modified: Sep 97]
  1201.  
  1202. Answer: Multiple screens is simpler than multiple displays, since one X server
  1203. controls all of the screens.  Simply specify the XmNscreen resource when you
  1204. create your top level (or other) shell widget and the X Toolkit will create
  1205. the shell on that screen.  You should generally also explicitly set your
  1206. XmNcolormap, XmNdepth, and XmNvisual resources for the new shell, since the
  1207. defaults may not be valid on the second screen.
  1208.  
  1209. Ken Lee
  1210.  
  1211. -----------------------------------------------------------------------------
  1212. Subject: 321)  Why do I get "Error: attempt to add non-widget child "dsm" to
  1213. parent"?
  1214. [Last modified: May 95]
  1215.  
  1216. Answer: Most likely, you are linking your libraries in the wrong order.  You
  1217. must link -lXm *before* -lXt.
  1218.  
  1219. Ken Lee
  1220.  
  1221. Ken Sall (ksall@cen.com) adds: This same error occurs if you combine Motif and
  1222. Athena widgets in the same application. If you link with "-lXaw" before "-
  1223. lXm", you get the runtime error. However, if you switch the order of the two
  1224. libraries, there is no problem. For example:
  1225.  
  1226. cc mothena.c -o mothena -lXm -lXaw -lXt -lXmu -lX11
  1227.  
  1228.  
  1229. -----------------------------------------------------------------------------
  1230. Subject: 322)  Why do I get link errors about "XShape" symbols?
  1231. [Last modified: May 95]
  1232.  
  1233. Answer: You must link with the X extensions library, -lXext, after any widget
  1234. libraries.  For example,
  1235.  
  1236. cc -o myapp myapp.o -lXm -lXt -lXext -lX11
  1237.  
  1238. Ken Lee
  1239.  
  1240. -----------------------------------------------------------------------------
  1241. Subject: 323)  Why do I get link errors about "ICE" and "SM" symbols?
  1242. [Last modified: Sep 97]
  1243.  
  1244. Answer: You must link with the the X ICE and/or SM libraries.  For example,
  1245.  
  1246. cc -o myapp myapp.o -lXm -lXt -lXext -lICE -lSM -lX11
  1247.  
  1248. Ken Lee
  1249.  
  1250. -----------------------------------------------------------------------------
  1251. Subject: 324)  Why does my X11R6 program crash with undefined symbol
  1252. "LowerCase"?
  1253. [Last modified: May 95]
  1254.  
  1255. Answer: If you are using Motif version 1.1.[123], then the problem may be a
  1256. failure to set MotifBC to YES in your site.def.
  1257.  
  1258. Thanks to Geoffrey Leach, geoff@netcom.com
  1259.  
  1260. -----------------------------------------------------------------------------
  1261. Subject: 325)  How do I programatically control xwd to dump a specific window?
  1262. I need a non-interactive way to tell xwd what X window to make an image of...
  1263. NOT by the traditional point-and-click method.
  1264. [Last modified: July 95]
  1265.  
  1266. Answer: Ken Sall (ksall@cen.com) wrote:
  1267.  
  1268. 1. Get the window id of the toplevel shell widget using the "XtWindow"
  1269. function.
  1270. 2. Invoke "xwd" from the program that has access to the window id, such as:
  1271.  
  1272. Window dumpId; /* returned from XtWindow */
  1273. sprintf (cmd_string, "xwd -frame -out tmp.xwd -id 0x%x", dumpId);
  1274. system (cmd_string);
  1275.  
  1276.  
  1277. -----------------------------------------------------------------------------
  1278. Subject: 326)  How can I display an xwd in a window (without using xwud)?
  1279. [Last modified: Sept 95]
  1280.  
  1281. Answer:
  1282.  
  1283. 1.  read the xwd file into an XImage
  1284. 2.  create a pixmap and XPutImage the image into the pixmap
  1285. 3.  use the pixmap as the XmNlabelPixmap of a label widget
  1286.  
  1287. Ken Lee
  1288.  
  1289. -----------------------------------------------------------------------------
  1290. Subject: 327)  Can I write a multi-threaded Motif application?
  1291. [Last modified: May 97]
  1292.  
  1293. Answer: Motif 2.1 can be compiled to be thread-safe (if libX11 and libXt are
  1294. also compiled to be thread-safe).
  1295.  
  1296. Motif releases prior to Motif 2.1 were not thread-safe.  In these releases,
  1297. you can use Motif from one thread and do other things in other threads but you
  1298. cannot call Motif functions from more than one thread.
  1299.  
  1300. Try looking in the X FAQ for information on threads:
  1301.  
  1302. http://www.cis.ohio-state.edu/hypertext/faq/usenet/x-faq/top.html
  1303. ftp://ftp.x.org/contrib/faqs/FAQ
  1304.  
  1305. Ken Lee
  1306.  
  1307. -----------------------------------------------------------------------------
  1308. Subject: 328)  How can I dump my widget instance tree in a way that reflects
  1309. the hierarchy?
  1310. [Last modified: July 97]
  1311.  
  1312. Answer: Jeremy Jameson (jameson@drmail.dr.att.com) posted this code to c.w.x.m
  1313. in 5/95.
  1314.  
  1315. [Note:  this code does not consider popup children, which are not listed in
  1316. the XmNchildren array. To find those, you have to peek at the popup_list in
  1317. core widget record.  - K.Lee 7/97]
  1318.  
  1319.  
  1320. /*******************************************************************************
  1321. * dumpWidgetTree( Widget w )
  1322. *
  1323. *       This function will recursively descend throught the Widget tree
  1324. *       and print the children and their pointer addresses.
  1325. *
  1326. *       Jeremy Jameson          5/17/95
  1327. *
  1328. *******************************************************************************/
  1329.  
  1330. static void dumpWidgetTree( Widget w )
  1331. {
  1332. WidgetList list = NULL;
  1333. Cardinal num_children = 0;
  1334. int i;
  1335. static int n = 0;
  1336. Widget child;
  1337. static char* indent =
  1338. "-----------------------------------------------------------------------------";
  1339. char tmp[256];
  1340.  
  1341. *tmp = ' ';
  1342.  
  1343. if ( n >= strlen( indent ) +1 )
  1344. {
  1345. printf(
  1346.  "ERROR:Widget tree is too deep, not enough indent string ( < %d )!\n",
  1347.   n );
  1348. n = 0;
  1349. return;
  1350. }
  1351.  
  1352. strncpy( tmp, indent, n );
  1353. tmp[n] = ' ';
  1354.  
  1355. printf( "%s> Dumping widget tree of %s - %#x \n", tmp, XtName( w ), w );
  1356.  
  1357. if ( ! XtIsComposite( w ) )
  1358. {
  1359. printf(
  1360.  "%s>   %s is not a subclass of Composite and therefore has no children\n",
  1361.  tmp, XtName( w ) );
  1362. return;
  1363. }
  1364.  
  1365. XtVaGetValues( w,
  1366.  XmNchildren, &list,
  1367.  XmNnumChildren, &num_children,
  1368.  NULL );
  1369.  
  1370. printf( "%s>   %s has %d %s\n", tmp, XtName( w ),
  1371. num_children, num_children == 1 ? "child" : "children" );
  1372.  
  1373. for ( i = 1; i <= num_children; i++ )
  1374. {
  1375. child = list[i-1];
  1376. printf( "%s>   child %2d  %20s \t (%#x)\n", tmp, i, XtName( child ), child );
  1377. }
  1378.  
  1379. printf( "\n" );
  1380.  
  1381. for ( i = 1; i <= num_children; i++ )
  1382. {
  1383. child = list[i-1];
  1384. n += 3;
  1385. dumpWidgetTree( child );
  1386.  
  1387. n -= 3;
  1388. }
  1389. printf( "\n" );
  1390. }
  1391.  
  1392.  
  1393. -----------------------------------------------------------------------------
  1394. Subject: 329)  How do I get the events for gadgets? Or the name of the gadget?
  1395. [Last modified: July 96]
  1396.  
  1397. Answer: Get events from the gadget's parent.  Ken Lee
  1398.  
  1399. A related question is "How the name of a gadget an event is directed to?"
  1400. Daniel Dardailler (daniel@x.org) writes:
  1401.  
  1402. Motif 2.0 provides a XmObjectAtPoint public function that support this
  1403. functionality.  For earlier version, something like the undocumented
  1404. _XmInputInGadget( wid, x, y ) should do it.
  1405.  
  1406. _XmInputInGadget
  1407. Given a composite widget and an (x, y) coordinate, see if the
  1408. (x, y) lies within one of the gadgets contained within the
  1409. composite.  Return the gadget if found, otherwise return NULL.
  1410.  
  1411.  
  1412. -----------------------------------------------------------------------------
  1413. Subject: 330)  Can I set the foreground and background colors of gadgets
  1414. (e.g., convenience dialog buttons)?
  1415. [Last modified: Nov 96]
  1416.  
  1417. Answer: Not in Motif 1.x.  Gadgets don't have their own colors, they use those
  1418. of their parents.  Notice that Motif's convenience dialogs generally use label
  1419. gadgets, not widgets, so you cannot customize the colors of individual
  1420. buttons.
  1421.  
  1422. Beginning in Motif 2.0, gadgets do have their own color resources.
  1423.  
  1424. Ken Lee
  1425.  
  1426. -----------------------------------------------------------------------------
  1427. Subject: 331)  Can I use a gadget as the parent of a dialog shell?
  1428. [Last modified: Dec 97]
  1429.  
  1430. Answer: No.  The Core widget class contains the functionality for popup
  1431. children.  Since the Gadget class is not a subclass of Core, gadgets cannot
  1432. have popup children (like dialogs).
  1433.  
  1434. -----------------------------------------------------------------------------
  1435. Subject: 332)  Which other widget features do gadgets lack?
  1436. [Last modified: Dec 97]
  1437.  
  1438. Answer: Here's a list from Asente & Swick (p. 397).  Note that many of these
  1439. restrictions are primarily of interest to widget (and gadget) writers, not to
  1440. application writers.
  1441.  
  1442. 1.  gadgets have no background or border colors or pixmaps
  1443. 2.  gadgets cannot have event handlers
  1444. 3.  gadgets have no translations, accelerators, or actions
  1445. 4.  gadgets cannot have pop-up children
  1446. 5.  gadgets cannot do grabs
  1447. 6.  gadgets cannot redirect the Intrincis keyboard focus or take the X focus
  1448. 7.  gadgets cannot own or request selections
  1449. 8.  gadgets do not need to be and cannot be realized
  1450. 9.  gadgets cannot have their window, display, or screen queried (but
  1451. there are separate functions for computing these)
  1452. 10. gadgets have no stacking order
  1453.  
  1454.  
  1455. -----------------------------------------------------------------------------
  1456. Subject: 333)  Where can I get the xmon or xscope programs to trace my X
  1457. protocol?
  1458. [Last modified: Mar 96]
  1459.  
  1460. Answer: Both are included in the contrib section of X11R5:
  1461. ftp://ftp.x.org/pub/R5/
  1462.  
  1463. Xmon is also available at: ftp://ftp.x.org/contrib/devel_tools/ and
  1464. ftp://ftp.crl.research.digital.com/pub/X11/contrib/devel_tools/
  1465.  
  1466. Ken Lee
  1467.  
  1468. -----------------------------------------------------------------------------
  1469. Subject: 334)  What does the error "Couldn't find per display information"
  1470. mean?
  1471. [Last modified: Mar 96]
  1472.  
  1473. Answer: Xt often needs information about the current X display.  It generates
  1474. this error when it couldn't find the display pointer.  Common causes
  1475. applications accidentally destroying widgets twice or trying to generate fake,
  1476. incomplete events with XSendEvent().
  1477.  
  1478. Ken Lee
  1479.  
  1480. -----------------------------------------------------------------------------
  1481. Subject: 335)  Can I set widget fallback resources after I've called
  1482. XtAppInitialize()?
  1483. [Last modified: Mar 96]
  1484.  
  1485. Answer: No.  Fallbacks are only checked when displays are initialized.
  1486.  
  1487. Ken Lee
  1488.  
  1489. -----------------------------------------------------------------------------
  1490. Subject: 336)  Can I use the newline character in widget names?
  1491. [Last modified: Mar 96]
  1492.  
  1493. Answer: No.  Widget names are designed to be used in resource specifications.
  1494. The Xlib resource file syntax says the only alphanumeric characters (plus '-'
  1495. and '_') may be used in a resource component name.  If you want more than one
  1496. line of text in a label widget, set the XmNlabelString resource.
  1497.  
  1498. Ken Lee
  1499.  
  1500. -----------------------------------------------------------------------------
  1501. Subject: 337)  Is anybody out there selling Windows95 look-alike widgets?  Why
  1502. isn't there a Widget builder for Motif/X yet? Something like OCX (I believe on
  1503. Windows95).
  1504. [Last modified: Mar 96]
  1505.  
  1506. Answer: David B. Lewis (dbl%craft@uunet.uu.net) writes:
  1507.  
  1508. None that I know of. There are similar widgets available in Motif 2.0.  There
  1509. are similar widgets available in the ICS EnhancementPak.
  1510.  
  1511. [For the second part of the question...] Because it's very hard to do. I don't
  1512. know what OCX is, but I can't imagine that the technology is so much better
  1513. than that used in Xt that it's possible to write something to generate real
  1514. code. It's trivial, of course, to generate the framework for a widget given
  1515. only its name, superclass, and resources; but everything else is real code.
  1516.  
  1517. -----------------------------------------------------------------------------
  1518. Subject: 338)  How can I convert my OLIT programs to the Motif look & feel?
  1519. [Last modified: July 96]
  1520.  
  1521. Answer: Mark Fresolone (mjf@mjm.com) writes: There are a number of translator
  1522. products on the market which translate OLIT source code or DevGuide builder
  1523. files into Motif source code and builder files.
  1524.  
  1525. In 1995, MJM Software (Melillo Consulting Inc.) released the MoOLIT 5.1
  1526. toolkit, which allows one to simply re-compile Sun or UnixWare OLIT programs,
  1527. and have them be switchable between the OPENLOOK and Motif look and feels.
  1528. MoOLIT 5.1 is available on most popular UNIX platforms.  More information is
  1529. available at:
  1530.  
  1531. http://www.mjm.com/Products/MoOLIT
  1532.  
  1533. -----------------------------------------------------------------------------
  1534. Subject: 339)  What does this mean: Warning: Cannot find callback list in
  1535. XtAddCallback?
  1536. [Last modified: July 96]
  1537.  
  1538. Answer: It means that you gave an invalid callback name to XtAddCallback,
  1539. e.g., using XmNactivateCallback when the widget does not have a callback with
  1540. that name.
  1541.  
  1542. Ken Lee
  1543.  
  1544. -----------------------------------------------------------------------------
  1545. Subject: 340)  If a single widget has multiple callback functions, are they
  1546. all executed?  If so, in what order?
  1547. [Last modified: Nov 96]
  1548.  
  1549. Answer: Yes, they are all executed.  The order, however, is not defined by the
  1550. X Toolkit specifications.  If you really want a certain order, you should
  1551. register a single callback function and have it call your other functions in
  1552. the order you want.
  1553.  
  1554. Ken Lee
  1555.  
  1556. -----------------------------------------------------------------------------
  1557. Subject: 341)  Why are some widgets still visible after I call
  1558. XtDestroyWidget() on them?
  1559. [Last modified: Nov 96]
  1560.  
  1561. Answer: To avoid memory corruption problems, the X Toolkit uses a 2 phase
  1562. destroy process.  When you call XtDestroyWidget(), the widgets are not really
  1563. destroyed until after you return to the Xt main loop.  Until then, the widget
  1564. will behave (mostly) as if they were not destroyed.  If this is a problem, you
  1565. should unmanage them as well (you can safely unmanage them after you destroy
  1566. them and before you return to the main loop).
  1567.  
  1568. Ken Lee
  1569.  
  1570. Note: The details of the two-phase destruction are described on the
  1571. XtCreateWidget(3Xt)/XtDestroyWidget(3Xt) man page. - ksall@cen.com
  1572.  
  1573. -----------------------------------------------------------------------------
  1574. Subject: 342)  If I call XtGetValues on a resource that does not exist for a
  1575. given widget, what value is returned?
  1576. [Last modified: Nov 96]
  1577.  
  1578. Answer: No value is returned.  Your return variable is not modified.  If it
  1579. was uninitialized (i.e., garbage) before the call to XtGetValues, it will
  1580. remain uninitialized.
  1581.  
  1582. Ken Lee
  1583.  
  1584. -----------------------------------------------------------------------------
  1585. Subject: 343)  Can I reparent a widget (change its parent)?
  1586. [Last modified: Aug 97]
  1587.  
  1588. Answer: Xt does not support reparenting of widgets within the widget
  1589. hierarchy.  This would complicate the hierarchical resource model.  You can
  1590. destroy the old hierarchy and create a new one.  On most systems, this is
  1591. pretty fast for reasonably sized widget hierarchies.
  1592.  
  1593. Note, however, that X11R6.3 provides an "application group" extension that
  1594. allows one X client to act as the root of another X client's window hierarchy.
  1595. See the X11R6.3 documentation for more details.
  1596.  
  1597. Ken Lee
  1598.  
  1599. -----------------------------------------------------------------------------
  1600. Subject: 344)  Are there any "year 2000" issues within Motif?
  1601. [Last modified: Jun 98]
  1602.  
  1603. Answer: According to
  1604.  
  1605. http://www.camb.opengroup.org/tech/desktop/faq/y2k.htm
  1606.  
  1607.  
  1608. Dear Customer:
  1609.  
  1610. The Open Group has completed a review of Motif (OSF/Motif) and the X Window
  1611. System with regard to Year 2000 issues, and has determined that Motif
  1612. (versions 1.0 through 2.1) and X Window System (X11 Releases 5 through 6.4)
  1613. source code, as provided directly by The Open Group (or, previously provided
  1614. by Open Software Foundation, Inc.; or X Consortium in the case of X Window
  1615. System) does not contain any date-dependent source code. The arrival of the
  1616. year 2000 should have no effect on the operation of Motif or X Window System
  1617. source code.
  1618.  
  1619. Please note, however, that Motif & X Window System object code or
  1620. applications, or derivative works thereof, which would have been provided to
  1621. you by a third party, are not covered by the above statement. You are hereby
  1622. referred to your supplier for statements regarding Year 2000 issues for such
  1623. third-party products.
  1624.  
  1625. Very truly yours,
  1626.  
  1627. The Open Group
  1628.  
  1629. -----------------------------------------------------------------------------
  1630. Subject: 345)  Can I suppress or customize Motif warning and error messages?
  1631. [Last modified: Aug 97]
  1632.  
  1633. Answer: A better idea is usually to fix problems indicated by the messages.
  1634. If you must, Motif justs uses Xt's message system which can be customized with
  1635. XtAppSetWarningHandler and XtAppSetErrorHandler.
  1636.  
  1637. -----------------------------------------------------------------------------
  1638. Subject: 346)  TOPIC: Motif FAQ HISTORY and ACKNOWLEDGEMENTS
  1639. [Last modified: April 97]
  1640.  
  1641. Answer:
  1642.  
  1643. History:
  1644. -------
  1645. November 89 to July 93: FAQ was maintained by Jan Newmarch
  1646.                 (jan@ise.canberra.edu.au)
  1647.  
  1648. July 93 to August 94:   FAQ was maintained by Brian Dealy
  1649.                 (dealy@c3i.saic.com)
  1650.  
  1651. Sept. 94 to April 97:   FAQ was maintained by Ken Sall
  1652.                 (ksall@cen.com)
  1653.  
  1654. beginning April 97:     FAQ was maintained by Kenton Lee
  1655.                 (http://www.rahul.net/kenton/)
  1656.  
  1657. Acknowledgments:
  1658. ----------------
  1659. This list was compiled using questions and answers posed to
  1660. comp.windows.x.motif and motif-talk. Some information was excerpted from the
  1661. comp.windows.x FAQ.  To all who contributed one way or the other, thanks! We
  1662. try to give individual references, but you may recognize something
  1663.                 (jan@ise.canberra.edu.au)
  1664.  
  1665. July 93 to August 94:   FAQ was maintained by Brian Dealy
  1666.                 (dealy@c3i.saic.com)
  1667.  
  1668. Sept. 94 to April 97:   FAQ was maintained by Ken Sall
  1669.                 (ksall@cen.com)
  1670.  
  1671. beginning April 97:     FAQ was maintained by Kenton Lee
  1672.                 (http://www.rahul.net/kenton/)
  1673.  
  1674. Acknowledgments:
  1675. ----------------
  1676. This list was compiled using questions and answers posed to
  1677. comp.windows.x.motif and motif-talk. Some information was excerpted from the
  1678. comp.windows.x FAQ.  To all who contributed one way or the other, thanks! We
  1679. try to give individual references, but you may recognize something uncredited
  1680. as your contribution. If we've mangled the words (or, heaven forbid, the code)
  1681. too much, let the current maintainer know.
  1682.  
  1683. NOTE: If you are a two-or-more-time contributor to this FAQ and you have a WWW
  1684. personal home page which you'd like to have listed, see the subject: "Which X
  1685. and Motif developers have their own home page URLs?"
  1686.  
  1687. Jan Newmarch, Information Science and Engineering,
  1688. University of Canberra, PO Box 1, Belconnen, Act 2616
  1689. Australia. Tel: (Aust) 6-2522422. Fax: (Aust) 6-2522999
  1690.  
  1691. ACSnet: jan@ise.canberra.edu.au
  1692. ARPA:   jan%ise.canberra.edu.au@uunet.uu.net
  1693. UUCP:   {uunet,ukc}!munnari!ise.canberra.edu.au!jan
  1694. JANET:  jan%au.edu.canberra.ise@EAN-RELAY
  1695.  
  1696.  
  1697. Jan Newmarch maintained this FAQ for a long time and has really helped a great
  1698. many of us by providing this valuable service.  He deserves a big round of
  1699. applause for his efforts.  I use this resource all the time and it has saved
  1700. me countless hours with manuals and source code trying to relearn what others
  1701. have already discovered.  Jan`s efforts are gratefully acknowledged here.
  1702.  
  1703. Brian Dealy, SAIC
  1704. dealy@c3i.saic.com
  1705.  
  1706.  
  1707. Likewise, Brian Dealy of SAIC did an admirable job taking over the Motif FAQ
  1708. from Jan. A considerable amount of information was added during his tenure and
  1709. we greatly appreciate Brian's work on the FAQ, as well as his efforts in
  1710. maintaining the comp.windows.x.motif newsgroup reflector, for the good of all
  1711. Motif-dom.
  1712.  
  1713. Ken Sall
  1714. ksall@cen.com
  1715. Tel: (301) 953-3330  FAX: (301) 953-2368
  1716. Century Computing, Inc.
  1717. http://www.cen.com/
  1718.  
  1719.  
  1720. My thanks to Ken Sall for maintaining the FAQ for 1994-1997.  During Ken's
  1721. tenure the FAQ more than doubled in size. Ken was one of the first FAQ
  1722. maintainers to change all ftp references to URLs and to incorporate http URLs
  1723. thoroughout the FAQ.
  1724.  
  1725. Kenton Lee
  1726. X/Motif Consultant
  1727. kenton@nojunk.rahul.net
  1728. http://www.rahul.net/kenton/
  1729.  
  1730.  
  1731. The end.
  1732.  
  1733.  
  1734.