Path: bloom-beacon.mit.edu!hookup!swrinde!cs.utexas.edu!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!bounce-bounce From: ware@cis.ohio-state.edu (Peter Ware) Newsgroups: comp.windows.x.intrinsics,comp.windows.x,comp.answers,news.answers Subject: comp.windows.x.intrinsics Frequently Asked Questions (FAQ) Supersedes: Followup-To: comp.windows.x.intrinsics Date: 6 Apr 1994 09:23:20 -0400 Organization: The Ohio State University Dept. of Computer and Info. Science Lines: 2239 Approved: news-answers-request@MIT.Edu Expires: 18 May 1994 13:23:15 GMT Message-ID: Reply-To: ware@cis.ohio-state.edu NNTP-Posting-Host: harmonica.cis.ohio-state.edu Summary: Answers about the X11 Window System widgets and Xt Intrinsics library Xref: bloom-beacon.mit.edu comp.windows.x.intrinsics:2472 comp.windows.x:23365 comp.answers:4789 news.answers:17735 Archive-name: Xt-FAQ Version: $Id: FAQ-Xt,v 1.37 1994/04/06 13:22:57 ware Exp $ The X Toolkit Intrinsics F.A.Q A monthly posting This article contains the answers to some Frequently Asked Questions (FAQ) from comp.windows.x about the X Toolkit Intrinsics. To submit questions (preferably with an answer) send email to: ware@cis.ohio-state.edu This FAQ is available on the archive site rtfm.mit.edu in the directory: pub/usenet/comp.answers The name under which a FAQ is archived appears in the Archive-name line at the top of the article. This FAQ is archived as Xt-FAQ. All code fragments are public domain. Contents 0. Xt Glossary 1. Software Versions 2. Related FAQ's 3. Why does my app core dump when I use signals/alarms/cthreads? 4. How do I use a different visual than the default? 5. Which visual should an application use? 6. Why do only Shell widgets have a Visual? 7. Which visual, depth and colormap do Shells inherit? 8. I've done all the above and I still get a BadMatch error. Why? 9. Why doesn't my widget get destroyed when I call XtDestroyWidget()? 10. How do I exit but still execute the DestroyCallbacks? 11. How do I resize a Shell widget? 12. Why can't XtAppAddInput() handle files? 13. What good books and magazines are there on Xt? 14. What Widgets are available? 15. What alternatives to the Intrinsics are there? 16. How do I pass a float value to XtSetValues? 17. How do I write a resource converter? 18. How do I open multiple displays? 19. What changed from R3 to R4 to R5? 20. Where are the resources loaded from? 21. What order are callbacks executed in? 22. How do I know if a widget is visible? 23. How do I reparent a widget in Xt, i.e. XtReparentWidget()? 24. Why use XtMalloc, XtFree, etc? 25. How to debug an Xt application? 26. Why don't XtAddInput(), XtAddTimeout() and XtAddWorkProc() work? 27. What is and how can I implement drag and drop? 28. How can I add a C++ member function as a widget callback? 29. How can I identify the children of a manager widget? 30. Can I use XtMoveWidget(), ... to move widgets I created? 31. Why is XtGetValues() on XtNx, XtNy of my top level shell wrong? 32. Why do some people use XmN as resource names? 33. How do I make my life easier when designing an application? 34. Why can't I override translations? Only the first item works. 35. Why do I get "Warning: Widget class version mismatch"? 36. Where can I get a good file-selector widget? 37. Where can I find a hypertext widget or source code? 38. What widget is appropriate to use as a drawing canvas? 39. What is this link problem with _get_wmShellWidgetClass? 40. Why does XtGetValues not work for me (sic)? 41. Is this a memory leak in the X11R4 XtDestroyWidget()?! 42. Is this a memory leak in the X11R4 deletion of work procs?! 43. How do I query the user synchronously using Xt? 44. How do I simulate a button press/release event for a widget? 45. How to use Fallback resources (can I specify colors)? 46. What is the preferred way of setting the application resources? ---------------------------------------------------------------------- Subject: 0. Xt Glossary ---------------------------------------------------------------------- o The Xt Intrinsics implement an object oriented interface to C code to allow useful graphical components to be created. Included with this are classes that provide the base functionality: Object, RectObj, Core, Composite, Constraint, Shell, OverrideShell, WMShell, etc. The terms "Xt" and "Intrinsics" are used interchangeably, however, they are used very precisely to mean a specific library of the X window system. In particular, it does not include the Athena, Motif, OLIT or any other widget set. Without further widgets the Intrinsics are not especially useful. o A widget refers to a user interface abstraction created via Xt. The precise use, is any object that is a subclass of the Core class. It is used loosely to refer to anything that is a subclass of the Object class although these are more accurately called windowless widgets or gadgets. o Xlib is the C interface to the X11 protocol. It is one layer below the Xt Intrinsics. Typically a widget uses relatively few Xlib functions because Xt provides most such services although an understanding of Xlib helps with problems. ---------------------------------------------------------------------- Subject: 1. Software Versions ---------------------------------------------------------------------- The following are the latest versions of Xt based software: _____________________________________________________________ Software Version Released Next Expected _____________________________________________________________ X11R4 patch 18 (none) X11R5 patch 26 11/3/93 ?? Athena Widgets (see X11R5) Motif 1.2.3 9/16/93 ?? OLIT ?? ?? ?? Xtra 2.5 6/15/92 ?? Xw X11R4 (none) Xcu X11R5 (none) fwf 3.4 1/11/92 4/93 _____________________________________________________________ ---------------------------------------------------------------------- Subject: 2. Related FAQ's ---------------------------------------------------------------------- David B. Lewis (uunet!craft!faq) maintains the FAQ on X. It is posted monthly on comp.windows.x and located on ftp.x.org in contrib/FAQ. Liam R. E. Quin (lee@sq.sq.com) posts an FAQ list on Open Look to comp.windows.x. Brian Dealy (dealy@kong.gsfc.nasa.gov) posts an FAQ list on Motif to comp.windows.x.motif. it is also on ftp.x.org under contrib/Motif-FAQ Peter Ware (ware@cis.ohio-state.edu) posts an FAQ list for comp.windows.x.intrinsics; it is on ftp.x.org in contrib/FAQ-Xt. ---------------------------------------------------------------------- Subject: 3. Why does my app core dump when I use signals/alarms/cthreads? ---------------------------------------------------------------------- In brief, Xlib, Xt and most widget sets have no mutual exclusion for critical sections. Any interrupt handler is likely to leave one of the above libraries in an inconsistent state -- such as all the appropriate flags not yet set, dangling pointers, in the middle of a list traversal, etc. Note that the ANSI C standard points out that behavior of a signal handler is undefined if the signal handler calls any function other than signal() itself, so this is not a problem specific to Xlib and Xt; the POSIX specification mentions other functions which may be called safely but it may not be assumed that these functions are called by Xlib or Xt functions. The only safe way to deal with signals is to set a flag in the interrupt handler. This flag later needs to be checked either by a work procedure or a timeout callback. It is incorrect to add either of these in the interrupt handler. As another note, it is dangerous to add a work procedure that never finishes. This effectively preempts any work procedures previously added and so they will never be called. Another option is to open a pipe, tell the event loop about the read end using XtAppAddInput() and then the signal handler can write a byte to the write end of the pipe for each signal. However, this could deadlock your process if the pipe fills up. Why don't the Intrinsics deal with this problem? Primarily because it is supposed to be a portable layer to any hardware and operating system. Is that a good enough reason -- I don't think so. Note: the article in The X Journal 1:4 and the example in O'Reilly Volume 6 are in error. ---------------------------------------------------------------------- Subject: 4. How do I use a different visual than the default? ---------------------------------------------------------------------- This requires a more complicated answer than it should. A window has three things that are visual specific -- the visual, colormap and border pixmap. All widgets have their own Colormap and BorderPixmap resource; only shell widgets have Visual resources (another questions deals with why shells have a Visual). The default value of these resources is CopyFromParent which does exactly what it says. In the shell widget CopyFromParent gets evalulated as DefaultVisualOfScreen and DefaultColormapOfScreen. When any one of the three resources is not properly set, a BadMatch error occurs when the window is created. They are not properly set because each of the values depends on the visual being used. How to get this to work? There are two parts to the answer. The first is if you want an application to start with a particular visual and the second is if you want a particular shell within an application to start with a different visual. The second is actually easier because the basic information you need is available. The first is a little harder because you'll need to initialize much of the toolkit yourself in order to determine the needed information. /* * Some sample code to start up an application using something other * than the default visual. * * To compile: * cc -g visual.c -o visual -lXaw -lXmu -lXt -lXext -lX11 -lm * * To run: * ./visual -geometry 300x300 -depth 24 -visual StaticColor -fg blue -bg yellow * * you need to move the mouse to get the particular visuals colormap * to install. */ #include #include #include typedef struct { Visual *visual; int depth; } OptionsRec; OptionsRec Options; XtResource resources[] = { {"visual", "Visual", XtRVisual, sizeof (Visual *), XtOffsetOf (OptionsRec, visual), XtRImmediate, NULL}, {"depth", "Depth", XtRInt, sizeof (int), XtOffsetOf (OptionsRec, depth), XtRImmediate, NULL}, }; XrmOptionDescRec Desc[] = { {"-visual", "*visual", XrmoptionSepArg, NULL}, {"-depth", "*depth", XrmoptionSepArg, NULL} }; int main (argc, argv) int argc; char **argv; { XtAppContext app; /* the application context */ Widget top; /* toplevel widget */ Display *dpy; /* display */ char **xargv; /* saved argument vector */ int xargc; /* saved argument count */ Colormap colormap; /* created colormap */ XVisualInfo vinfo; /* template for find visual */ XVisualInfo *vinfo_list; /* returned list of visuals */ int count; /* number of matchs (only 1?) */ Arg args[10]; Cardinal cnt; char *name = "test"; char *class = "Test"; /* * save the command line arguments */ xargc = argc; xargv = (char **) XtMalloc (argc * sizeof (char *)); bcopy ((char *) argv, (char *) xargv, argc * sizeof (char *)); /* * The following creates a _dummy_ toplevel widget so we can * retrieve the appropriate visual resource. */ cnt = 0; top = XtAppInitialize (&app, class, Desc, XtNumber (Desc), &argc, argv, (String *) NULL, args, cnt); dpy = XtDisplay (top); cnt = 0; XtGetApplicationResources (top, &Options, resources, XtNumber (resources), args, cnt); cnt = 0; if (Options.visual && Options.visual != DefaultVisualOfScreen (XtScreen (top))) { XtSetArg (args[cnt], XtNvisual, Options.visual); ++cnt; /* * Now we create an appropriate colormap. We could * use a default colormap based on the class of the * visual; we could examine some property on the * rootwindow to find the right colormap; we could * do all sorts of things... */ colormap = XCreateColormap (dpy, RootWindowOfScreen (XtScreen (top)), Options.visual, AllocNone); XtSetArg (args[cnt], XtNcolormap, colormap); ++cnt; /* * Now find some information about the visual. */ vinfo.visualid = XVisualIDFromVisual (Options.visual); vinfo_list = XGetVisualInfo (dpy, VisualIDMask, &vinfo, &count); if (vinfo_list && count > 0) { XtSetArg (args[cnt], XtNdepth, vinfo_list[0].depth); ++cnt; XFree ((XPointer) vinfo_list); } } XtDestroyWidget (top); /* * Now create the real toplevel widget. */ XtSetArg (args[cnt], XtNargv, xargv); ++cnt; XtSetArg (args[cnt], XtNargc, xargc); ++cnt; top = XtAppCreateShell ((char *) NULL, class, applicationShellWidgetClass, dpy, args, cnt); /* * Display the application and loop handling all events. */ XtRealizeWidget (top); XtAppMainLoop (app); return (0); } ---------------------------------------------------------------------- Subject: 5. Which visual should an application use? ---------------------------------------------------------------------- This is a point that can be argued about but one opinion is there is no way for an application to know the appropriate visual -- it has to be specified by the user. If you disagree with this then your application probably falls into the category of always using the default visual or it is hardware specific and expects some particular visual such as 24bit TrueColor with an OverlayPlane extension (or some such). Why? No application runs in isolation. Depending on the way a server allocates resources I may not always want your application to run in TrueColor mode if it is going to mess up my other applications. I may be very upset if it chooses to run in GreyScale instead of PsuedoColor or just monochrome. As an example, on a low end color Sun server there are many different possible visuals: monochrome, 256 entry colormap, static gray, static color, and a 3/3/2 TrueColor. The SGI Iris's offer all the above plus 12 bit TrueColor, 24 bit TrueColor, an Overlay Plane. ---------------------------------------------------------------------- Subject: 6. Why do only Shell widgets have a Visual? ---------------------------------------------------------------------- This is strictly by convention. It makes it possible for an arbitrary widget to know that the visual it uses can be found by looking for the shell widget that is its ancestor and obtaining the visual of that shell. A widget can have its own visual resource. If it does, it must have its own realize method to use the visual when it calls XCreateWindow(). You should also make this a resource that can be obtained with XtGetValues() so other widgets can find it. A reasonable value is probably XtNvisual. ---------------------------------------------------------------------- Subject: 7. Which visual, depth and colormap do Shells inherit? ---------------------------------------------------------------------- The default value for these resources are set to CopyFromParent. This is interpreted as the DefaultColormapOfScreen(), DefaultDepthOfScreen() and the default visual of the screen if the widget has no parent -- i.e. it is an applicationShellWidgetClass and the root of your widget tree. If the parent of the widget is not null, then the shell copies colormap and depth from its parent and uses CopyFromParent as the visual. ---------------------------------------------------------------------- Subject: 8. I've done all the above and I still get a BadMatch error. Why? ---------------------------------------------------------------------- Some resource converters improperly cache references. This was especially true of X11R3 and earlier versions of Motif. ---------------------------------------------------------------------- Subject: 9. Why doesn't my widget get destroyed when I call XtDestroyWidget()? ---------------------------------------------------------------------- See section 2.8 of the Xt specification. It eventually does get destroyed, just not immediately. The Intrinsics destroy a widget in a two-phase process. First it and all of its children have a flag set that indicate it is being destroyed. It is then put on a list of widgets to be destroyed. This way any pending X events or further references to that widget can be cleaned up before the memory is actually freed. The second phase is then performed after all callbacks, event handlers, and actions have completed, before checking for the next X event. At this point the list is traversed and each widget's memory is actually free()'d, among other things. As some further caveats/trivia, the widgets may be destroyed if the Intrinsics determine that they have no further references to the widgets on the list. If so, then the phase 2 destruction occurs immediately. Also, if nested event loops are used, widgets placed on the destroy list before entering the inner event loop are not destroyed until returning to the outer event loop. ---------------------------------------------------------------------- Subject: 10. How do I exit but still execute the DestroyCallbacks? ---------------------------------------------------------------------- The problem is if a simple and entirely reasonable approach to exiting an application is used, such as calling exit() directly, then a widget may not have a chance to clean up any external state -- such as open sockets, temporary files, allocated X resources, etc. (this code for simplicity reasons assumes only a single toplevel widget): Widget ToplevelGet (gw) Widget gw; /* widget to find toplevel */ { Widget top; for (top = gw; XtParent (top); top = XtParent (top)) /* empty */; return (top); } void ExitCallback (gw, closure, call_data) Widget gw; /* widget */ XtPointer closure; /* data the app specified */ XtPointer call_data; /* widget specific data */ { Widget toplevel; toplevel = ToplevelGet (gw); XtUnmapWidget (toplevel); /* make it disappear quickly */ XtDestroyWidget (toplevel); exit (0); } One can see that the above code exit's immediately after destroying the toplevel widget. The trouble is the phase 2 destruction may never occur. This works for most widgets and most applications but will not work for those widgets that have any external state. You might think that since it works now it will always work but remember that part of the reason an object oriented approach is used is so one can be ignorant of the implementation details for each widget. Which means that the widget may change and someday require that some external state is cleaned up by the Destroy callbacks. One alternative is to modify ExitCallback() to set a global flag and then test for that flag in a private event loop. Or try the following code: #include extern Widget ToplevelGet ( #if NeedFunctionPrototypes Widget gw #endif ); extern Boolean ExitWorkProc ( #if NeedFunctionPrototypes XtPointer closure #endif ); extern void ExitCallback ( #if NeedFunctionPrototypes Widget gw, XtPointer closure, XtPointer call_data #endif ); Widget ToplevelGet (gw) Widget gw; /* widget to find toplevel */ { Widget top; for (top = gw; XtParent (top); top = XtParent (top)) /* empty */; return (top); } void ExitCallback (gw, closure, call_data) Widget gw; /* widget */ XtPointer closure; /* data the app specified */ XtPointer call_data; /* widget specific data */ { Widget toplevel; toplevel = ToplevelGet (gw); XtUnmapWidget (toplevel); /* make it disappear quickly */ XtDestroyWidget (toplevel); XtAppAddWorkProc (XtWidgetToApplicationContext (gw), ExitWorkProc, (XtPointer) NULL); } Boolean ExitWorkProc (closure) XtPointer closure; { exit (0); /*NOTREACHED*/ } ExitCallback() adds a work procedure that will get called when the application is next idle -- which happens after all the events are processed and the destroy callbacks are executed. ---------------------------------------------------------------------- Subject: 11. How do I resize a Shell widget? ---------------------------------------------------------------------- After it is realized, one doesn't resize a Shell widget. The proper thing is to resize the currently managed child of the Shell widget using XtSetValues(). The geometry change is then propagated to the Shell which asks the window manager which may or may not allow the request. However, the Shell must have the resource XtNallowShellResize set to True otherwise it will not even ask the window manager to grant the request and the Shell will not resize. To change the position of a Shell, use XtSetValues() on the Shell, not the child, and within the limits of the window manager it should be granted. ---------------------------------------------------------------------- Subject: 12. Why can't XtAppAddInput() handle files? ---------------------------------------------------------------------- It does, however Unix semantics for when I/O is ready for a file does not fit most peoples' intuitive model. In Unix terms a file descriptor is ready for reading whenever the read() call would not block, ignoring the setting of optional flags that indicate not to block. This works as expected for terminals, sockets and pipes. For a file the read() will always return but the return indicates an EOF -- i.e. no more data. The result is the code in the Intrinsics always calls the input handler because it always thinks something is about to be read. The culprit is the select() system call or on SYSV based OS's it is the poll() system call. How to get around this on a Unix system? The best approach is to use another process to check for available input on the file. Use a pipe to connect the application with this other process and pass the file descriptor from the pipe to XtAppAddInput(). A suitable program on BSD systems is "tail -f filename". It's rumored that select() on some systems is not _completely_ reliable. In particular: - IBM AIX 3.1: this is one where it would work for a while (several thousand times) and then stop until some other event woke it up. This seemed to be the result of a race condition in the Kernel. IBM claims to have a fix for this. - Pyramid, doesn't work at all. - Ultrix (and possibly others where pipes are implemented as sockets), wasn't completely broken, but although the writing side wrote in 512 byte blocks the reading side received it all broken up as if it was being put into the pipe a byte at a time. You can waste a lot of time by reading small blocks (get raound it by detecting the situation and having select() ignore the pipe for 10 mseconds - by then it had been given the whole block). Note that all the above descriptions used Unix terminology such as read(), file descriptor, pipes, etc. This is an OS dependent area and may not be identical on all systems. However the Intrinsic designers felt it was a common enough operation that it should be included with part of the toolkit. Why they didn't also deal with signals at this point I don't know. ---------------------------------------------------------------------- Subject: 13. What good books and magazines are there on Xt? ---------------------------------------------------------------------- I have a favorite that is the definitive reference. To my perspective it offers a reasonable introduction but also goes into the full details of the Intrinsics. When I started using it I was already familiar with Xt and the concepts behind it, so newcomers may or may not find it useful. I've always found it accurate and complete, which means its a 1000 pages. Asente, Paul J., and Swick, Ralph R., "X Window System Toolkit, The Complete Programmer's Guide and Specification", Digital Press, 1990, ISBN 1-55558-051-3, order number EY-E757E-DP; and by Prentice-Hall, ISBN 0-13-972191-6. Also available through DEC Direct at 1-800-DIGITAL. The other book I commonly recomend to novices is: Young, Doug. "The X Window System: Applications and Programming with Xt (Motif Version)," Prentice Hall, 1989 (ISBN 0-13-497074-8). (ISBN 0-13-972167-3) And of course O'Reilly has an entire series of manuals on X and Xt. O'Reilly ordering is 800-998-9938. In particular, Volume 5 is an Xt reference done in manual page style. The 3rd edition is extensively overhauled and goes far beyond the MIT manual pages. I'm finding it very useful. In particular, the permutted index and references to other manual pages help a great deal in chasing down related information. I read two periodicals, "The X Resource" and the "The X Journal". These are the only two dealing specifically with X. "The X Resource" is published quarterly, by O'Reilly, with one of the issues being the MIT X Consortium Technical Conference Proceedings. There is no advertising. I've found it informative with pretty good depth. For orders, call 1-800-998-9938, or email cathyr@ora.com. For editorial matters, email adrian@ora.com. Table of contents are posted at math.utah.edu in ~ftp/pub/tex/bib in TeX form and on ftp.uu.net in ~ftp/published/oreilly/xresource in ASCII form. "The X Journal" is a bimonthly trade rag with lots of advertising. The articles are informative and oriented toward a less technical audience. I read it more to see what's going on then with an expectation of learning a great deal (but remember, I represent a fairly small percentage of people). Also, they have a pretty good collection of people on the advisory board and as columnists. Call (908) 563-9033. ---------------------------------------------------------------------- Subject: 14. What Widgets are available? ---------------------------------------------------------------------- There are three popular widget sets: Athena - The set provided with X11. This is sufficient for most purposes but is on the ugly side. Recently, a 3d look is available for ftp on ftp.x.org:/contrib/Xaw3d.tar.Z. Motif - From OSF available for a license fee and commonly shipped on many workstation vendors platforms (almost everyone but Sun). It looks good and works well but personally I think it is poorly implemented. OLIT - The Open Look Intrinsics Toolkit is a set of widgets implementing Sun's Open Look specification. Developed by AT&T. I've never used it so can't comment on its quality. I've heard rumours that it is a pain to actually get. In addition the following collection of widgets are also available: Xtra - a library of widgets for sale from Graphical Software Technology (310-328-9338). It includes bar graph, stacked bar graph, line graph, pie chart, xy plot, hypertext, help, spreadsheet, and data entry form widgets. I've never seen them so I can't comment. FWF - The Free Widget Foundation is attempting to collect a set of freely available widgets. Included are a Pixmap editor, FileDialog, and a few others. The current set of widgets can be obtained via anonymous ftp from the machine a.cs.uiuc.edu (128.174.252.1) in the file pub/fwf.shar.Z. Xcu - The Cornell University widgets from Gene Dykes. One of the early widget sets released. Provides a nice appearance for buttons and has a mini command language. Probably not so widely used. Xs - The Sony widget set. This was around during R3 days but seemed to disappear. It looked like it had promise. Xw - The HP widgets. The precursor to Motif. Originally written for R3 there exists diffs to get it to work under R4 & R5. Again, a pretty good widget set but has more or less died. The precursor to this was the Xray toolkit which was originally implemented for X10R4 and apparently provided much experience for the designers of Xt. Xo - A widget set I'm working on. It's still primitive but you can give it a try in archive.cis.ohio-state.edu:pub/Xo/* The following specialized widgets are also available: Tbl - Implements a tabular layout of widgets. Supports Motif widgets as children. Part of Wcl. Plots - The Athena Plotting widgets (not the Athena widgets). Contact gnb@bby.oz.au or joe@Athena.MIT.EDU. ---------------------------------------------------------------------- Subject: 15. What alternatives to the Intrinsics are there? ---------------------------------------------------------------------- __________________________________________ Name Language Vendor __________________________________________ Xview C Sun OI C++ ParcPlace Interviews C++ Stanford Tcl/tk C sprite.berkeley.edu __________________________________________ However much I like C and admire the skill in both designing and implementing the Intrinsics, hopefully some alternative will develop in the next 3-5 years that uses an object oriented language. Keep your eyes open and expect some change about the same time a language other than C _starts_ gaining acceptance. ---------------------------------------------------------------------- Subject: 16. How do I pass a float value to XtSetValues? ---------------------------------------------------------------------- First, what is going wrong is the structure for an Arg is (essentially) typdef struct { String name; long value; } Arg; and the code: Arg arg; XtSetArg (arg, "name", 3.2) expands to Arg arg; arg.name = "name"; arg.value = 3.2; you can see that with normal C type conversions, the arg.value gets the integer "3" instead of the floating point value "3.2". When the value is copied into the widget resource, the bit pattern is wildly different than that required for a floating point value. So, how to get around this? The following macro is from the Athena widgets document and I am now recomending it over the previous suggestions. #define XtSetFloatArg(arg, n, d) \ if (sizeof(float) > sizeof(XtArgVal)) { \ XtSetArg(arg, n, &(d)); \ } else { \ XtArgVal *ld = (XtArgVal *)&(d); \ XtSetArg(arg, n, *ld); \ } ---------------------------------------------------------------------- Subject: 17. How do I write a resource converter? ---------------------------------------------------------------------- Courtesy of Rich Thomson (rthomson@dsd.es.com): The following discussion of resource converters assumes R4 (or R5) Intrinsics. Resource converters changed between R3 and R4 to allow for destructors and caching of converted values. There are several main types of resource converters: string to data type data type to string data type to data type i) string to data type Usually a string to data type converter has a fixed set of strings that will be converted to data type values. This is most often used to map enumerated names to enumerated values: Name Value "True" 1 "False" 0 In this case, the string to data type converter needs to compare the resource value to the list of fixed strings. This is most readily accomplished by the use of the "quark" mechanism of the resource manager. The resource value is turned into a quark, which is a unique representation of the string that fits into a single word. Then the resource quark is compared against the quarks for the fixed strings representing the enumerated values. If there are many enumerated strings in the converter (or many converters, each with a small number of enumeration strings), then a global initialization routine might be used to turn all the resource strings into quarks. That way, the first time one of these converters is used, the strings will be turned into quarks and held in static variables for use in the next invocation of one of the converters. ii) data type to string This type of converter is slightly easier than the string to data type converters since the use of quarks isn't necessary. Instead, the data type value is simply converted to a string value, probably by the use of sprintf. Data type to string converters are useful for applications that wish to convert an internal data type value into a string so that they can write out a valid resource specification to a file. This mechanism can be used to provide a "snapshot" of application state into a file. This snapshot can be used to restore the program to a known state via the usual X resource database mechanisms. If you are taking the trouble to write a string to data type converter, it isn't much extra effort to write the data type to string converter. Writing both at the same time helps to ensure that they are consistent. iii) data type to data type This type of converter is used to convert an existing data type value to another data type. For instance, an X pixel value can be converted to an RGB data type that contains separate fields for red, green and blue. The type signature for a resource converter is as follows: typedef Boolean (*XtTypeConverter)(Display *, XrmValuePtr, Cardinal *, XrmValuePtr, XrmValuePtr, XtPointer *); Display *dpy; XrmValuePtr args; Cardinal *num_args; XrmValuePtr fromVal; XrmValuePtr toVal; XtPointer *converter_data; When the converter is invoked, the "fromVal" argument points to the source X resource manager value and the "toVal" argument points to the destination X resource manager value. The "converter_data" argument is an opaque pointer to some converter-specific data that is specified when the converter is registered. The "args" and "num_args" arguments allow extra information to be passed to the converter when it is invoked. For instance, the Pixel to RGB structure converter discussed above would need colormap and visual arguments in which to lookup the Pixel to obtain the RGB values corresponding to that pixel. Care must be taken with the "toVal" argument. An XrmValue has the following type definition and specifies a size and location for a converted value: typedef struct { unsigned int size; caddr_t addr; } XrmValue, *XrmValuePtr; When the converter is invoked, the address may point to a location of the given size for the converted value or the location can be NULL. In the former case, the converter should ensure that the size of the destination area is large enough to handle the converted value. If the destination area is not large enough, then the converter should set the size to the amount of space needed and return False. The caller can then ensure that enough space is allocated and reinvoke the converter. If the size is large enough, then the converter can simply copy the converted value into the space given and return True. If the location is NULL, then the converter can assign the location to the address of a static variable containing the converted value and return True. When writing a group of converters, this code is often repeated and it becomes convenient to define a macro: #define DONE(var, type) \ if (toVal->addr) \ { \ if (toVal->size < sizeof(type)) \ { \ toVal->size = sizeof(type); \ return False; \ } \ else \ *((type *) toVal->addr) = var; \ } \ else \ toVal->addr = (caddr_t) &var; \ toVal->size = sizeof(type); \ return True; #define DONESTR(str) \ if (toVal->addr && toVal->size < sizeof(String)) \ { \ toVal->size = sizeof(String); \ return False; \ } \ else \ toVal->addr = (caddr_t) str; \ toVal->size = sizeof(String); \ return True; Inside the converter, it is a good idea to perform a little safety checking on the "num_args" and "args" arguments to ensure that your converter is being called properly. Once you have written your converter, you need to register it with the Intrinsics. The Intrinsics invokes resource converters when creating widgets and fetching their resource values from the resource database. To register a converter with a single application context, use XtAppSetTypeConverter: void XtAppSetTypeConverter(context, from, to, converter, args, num_args, cache, destructor) XtAppContext context; String from; String to; XtTypeConverter converter; XtConvertArgList args; Cardinal num_args; XtCacheType cache; XtDestructor destructor; To register a converter with all application contexts, use XtSetTypeConverter: void XtSetTypeConverter(from, to, converter, args, num_args, cache, destructor) String from; String to; XtTypeConverter converter; XtConvertArgList args; Cardinal num_args; XtCacheType cache; XtDestructor destructor; In the R3 Intrinsics, there were the routines XtAppAddConverter and XtAddConverter; these have been superseded by XtAppSetTypeConverter and XtSetTypeConverter. Whenever possible, the newer routines should be used. When a converter is registered with the Intrinsics, a "cache" argument specifies how converted resource values are to be cached: XtCacheNone Don't cache any converted values XtCacheAll Cache all converted values XtCacheByDisplay Cache converted values on a per display basis Caching converted values that require a round-trip to the server is a good idea (for instance string to Pixel conversions). The "destructor" argument is a routine that is invoked then the resource is destroyed, either because its cached reference count has been decremented to zero or because the widget owning the value is being destroyed. XtDestructor has the following type definition: typedef void (*XtDestructor)(XtAppContext, XrmValuePtr, XtPointer, XrmValuePtr, Cardinal *); XtAppContext context; XrmValuePtr to; XtPointer converter_data; XrmValuePtr args; Cardinal *num_args; The destructor is invoked to free any auxiliary storage associated with the "to" argument, but does not actually free the storage pointed to by the "to" argument itself (to->addr). The destructor is passed the extra arguments that were passed to the converter when the conversion was performed (for instance, colormap and visual arguments for the string to Pixel converter since the destructor would need to free the allocated Pixel from the colormap) as well as the private data passed in when the converter was registered. Sample converter code can be found in the following files in the MIT R5 distribution: mit/lib/Xt/Converters.c contrib/lib/PEXt/Converters.c contrib/lib/PEXt/Converters.h ---------------------------------------------------------------------- Subject: 18. How do I open multiple displays? ---------------------------------------------------------------------- See "Multi-user Application Software Using Xt", The X Resource, Issue 3, (Summer 1992) by Oliver Jones for a complete coverage of the issues involved. Most of this answer is based on that article. In a nutshell, one uses XtOpenDisplay() to add each display to a _single_ application context and then XtCloseDisplay() to shutdown each display and remove it from the application context. The real problems occur when trying to close down a display. This can happen 3 ways: 1. User selects a "quit" button on one of the displays, 2. User has window manager send a WM_DELETE_WINDOW message, 3. Server disconnect -- possibly from a KillClient message, server shutdown/crash, or network failure. I'll assume you can deal gracefully with 1 & 2 since it is _merely_ a problem of translating a Widget to a display and removing that display. If not, then read the Oliver Jones article. The third one is difficult to handle. The following is based on the Oliver Jones article and I include it here because it is a difficult problem. The difficulty arises because the Xlib design presumed that an I/O error is always unrecoverable and so fatal. This is essentially true for a single display X based application, but not true for a multiple display program or an application that does things other than display information on an X server. When an X I/O error occurs the I/O error handler is called and _if_ it returns then an exit() happens. The only way around this is to use setjmp/longjmp to avoid returning to the I/O error handler. The following code fragment demonstrates this: #include jmp_buf XIOrecover; void XIOHandler (dpy) Display *dpy; { destroyDisplay (dpy); longjmp (XIOrecover, 1); } main () { ... if (setjmp (XIOrecover) == 0) XSetIOErrorHandler (XIOHandler); XtAppMainLoop (app_context); } The destroyDisplay() is something that given a Display pointer can go back to the application specific data and perform any necessary cleanup. It should also call XtCloseDisplay(). For those of you unfamiliar with setjmp/longjmp, when setjmp() is first called it returns a 0 and save's enough information in the jmp_buf that a latter execution of longjmp() can return the program to the same state as if the setjmp() was just executed. The return value of this second setjmp() is the value of the second argument to longjmp(). There are several caveats about using these but for this purpose it is adequate. Some other problems you might run into are resource converters that improperly cache resources. The most likely symptoms are Xlib errors such as BadColor, BadAtom, or BadFont. There may be problems with the total number of displays you can open since typically only a limited number of file descriptors are available with 32 being a typical value. You may also run into authorization problems when trying to connect to a display. There was much discussion in comp.windows.x about this topic in November of 91. Robert Scheifler posted an article which basically said this is the way it will be and Xlib will not change. ---------------------------------------------------------------------- Subject: 19. What changed from R3 to R4 to R5? ---------------------------------------------------------------------- This addresses only changes in the Intrinsics. First, the general changes for each release are described. Then a, certainly incomplete, list of new functions added and others that are now deprecated are listed. Brevity is a primary goal. Much of the following information is retrieved from Chapter 13 of the MIT Xt Intrinsics Manual and from O'Reilly Volume 5, 3rd edition. From R3 to R4 - Addition of gadgets (windowless widgets) - New resource type converter interface to handle cacheing and additional data. - Variable argument list interface. - #define XtSpecificationRelease 4 (added with this release) - WMShellPart, TopLevelShellPart & TransientShellPart changed incompatibly. - core.initialize, core.set_values added ArgList and count parameters - event handlers had continue_to_dispatch parameter added - core.set_values_almost specification changed. - core.compress_exposure changed to an enumerated data type from Boolean - core.class_inited changed to enumerated data type from Boolean - constraint.get_values_hook added to extension record - core.initialize_hook obsolete as info is passed to core.initialize - shell.root_geometry_manager added to extension record - core.set_values_hook obsolete as info is passed to core.set_values - Calling XtQueryGeometry() must store complete geometry. - Added UnrealizeCallback. - XtTranslateCoords() actually works under R4. From R4 to R5: - Psuedo resource baseTranslation added. - Searching for app-default, and other files, made more flexible - customization resource added. - Per-screen resource database. - Support permanently allocated strings. - Permanetly allocated strings required for several class fields. - The args argument to XtAppInitialize, XtVaAppInitialize, XtOpenDisplay, XtDisplayInitialize, and XtInitialize were changed from Cardinal* to int* - Many performance improvements (this is summarized from the article "Xt Performance Improvements in Release 5" by Gabe Beged-Dov in "The X Resource", Issue 3): - XrmStringToQuark() augmented with XrmPermStringToQuark() to avoid string copies. Several fields in the class record are indicated as needing permanent strings. - Using an array of Strings for resources - Callback lists redesigned to use less memory - Translation manager redesigned and rewritten so it takes less memory, translation tables merges are faster, cache of action bindings - Keycode to Keysyms are cached. - Better sharing of GC's with modifiable fields - Window to Widget translation uses less space and faster - Does not malloc space for widget name since quark is available - Widget space is allocated to include the constraints - Over several example programs, about a 26% reduction in memory usage. Functions new with R5: ---------------------- XtAllocateGC() - sharable GC with modifiable fields XtGetActionList() - get the action table of a class XtScreenDatabase() - return resource database for a screen XtSetLanguageProc() - register language procedure called to set locale Functions new with R4: ---------------------- XtAppAddActionHook() - procedure to call before _every_ action. XtAppInitialize() - lots of initialization work. XtAppReleaseCacheRefs() - decrement cache reference count for converter XtAppSetFallbackResources() - specify default resources XtAppSetTypeConverter() - register a new style converter XtCallCallbackList() - directly execute a callback list XtCallConverter () - invoke a new style converter XtCallbackReleaseCacheRef() - release a cached resource value XtCallbackReleaseCacheRefList() - release a list of cached resource values XtConvertAndStore() - find and call a resource converter XtDirectConvert() - Invoke old-style converter XtDisplayOfObject() - Return the display XtDisplayStringConversionWarning() - issue a warning about conversion XtFindFile() - Find a file XtGetActionKeysym() - Retrieve keysym & modifies for this action XtGetApplicationNameAndClass() - return name and class XtGetConstraintResourceList() - get constraints for a widget XtGetKeysymTable() - return keycode-to-keysym mapping table XtGetMultiClickTime() - read the multi-click time XtGetSelectionRequest() - retrieve the SelectionRequest event XtGetSelectionValueIncremental() - obtain the selection value incrementally XtGetSelectionValuesIncremental() - obtain the selection value incrementally XtInitializeWidgetClass() - initialize a widget class manually XtInsertEventHanlder() - register event handler before/after others XtInsertRawEventHandler() - register event handler without modify input mask XtIsObject() - test if subclass of Object XtIsRectObj() - test if subclass of RectObj XtKeysymToKeyCodeList() - return list of keycodes XtLastTimestampProcessed() - retrieve most recent event time XtMenuPopdown - Action for popping down a widget XtMenuPopup - Action for popping up a widget XtOffsetOf - macro for structure offsets XtOwnSelectionIncremental() - make selection data availabe incrementally XtPoupSpringLoaded() - map a spring-loaded popup XtRegisterGrabAction() - indicate action procedure needs a passive grab XtRemoveActiohHook() - remove function called after every action XtResolvePathname() - find a file XtScreenOfObject() - return screen of object. XtSetMultiClickTime() - set the multi-click time XtSetWMColormapWindows() - set WM_COLORMAP_WINDOWS for custom colormaps XtUngrabButton() - cancel a passive button grab XtUngrabKey() - cancel a passive key grab XtUngrabKeybard() - release an active keyboard grab XtUngrabPointer() - release an active pointer grab XtVa*() - varags interfaces to a bunch of functions XtWindowOfObject() - return Window of nearest widget ancestor Deprecated Replacement When ---------------------------------------------------------------------- XtAddActions() XtAppAddActions() R3 XtAddConverter() XtAppAddConverter() R3 XtAddInput() XtAppAddInput () R3 XtAddTimeout() XtAppAddTimeout() R3 XtAddWorkProc() XtAppAddWorkProc() R3 XtConvert() XtConvertAndStore() R4 XtCreateApplicationShell XtAppCreateShell() R3 XtDestroyGC() XtReleaseGC() R3 XtError() XtAppError() R3 XtGetErrorDatabase() XtAppGetErrorDatabase R3 XtGetErrorDatabaseText() XtAppGetErrorDatabaseText R3 XtGetSelectionTimeout() XtAppGetSelectionTimeout R3 XtInitialize() XtAppInitialize() R3 XtMainLoop() XtAppMainLoop() R3 MenuPopdown(action) XtMenuPopdown(action) R4 MenuPopup(action) XtMenuPopup(action) R4 XtNextEvent() XtAppNextEvent() R3 XtPeekEvent() XtAppPeekEvent() R3 XtPending() XtAppPending() R3 XtSetErrorHandler() XtAppSetErrorHandler() R3 XtSetErrorMsgHandler XtAppSetErrorMsgHandler() R3 XtSetSelectionTimeout() XtAppSetSelectionTimeout() R3 XtSetWarningHandler() XtAppSetWarningHandler() R3 XtSetWarningMsgHandler() XtAppSetWarningMsgHandler() R3 XtWarning() XtAppWarning() R3 XtWarningMsg() XtAppWarningMsg() R3 ---------------------------------------------------------------------- Subject: 20. Where are the resources loaded from? ---------------------------------------------------------------------- The resources of a widget are filled in from the following places (from highest priority to lowest priority): 1. Args passed at creation time. 2. Command line arguments. 3. User's per host defaults file 4. User's defaults file. 5. User's per application default file. 6. System wide per application default file. Note that 2-6 are read only once on application startup. The result of steps 3-6 is a single resource database used for further queries. The per host defaults file contains customizations for all applications executing on a specific computer. This file is either specified with the XENVIRONMENT environment variable or if that is not set then the file $HOME/.Xdefaults- is used. The user defaults file is either obtained from the RESOURCE_MANAGER property on the root window of the display or if that is not set then the file $HOME/.Xdefaults is used. Typically, the program "xrdb" is used to set the RESOURCE_MANAGER property. Please note that this should be kept relatively small as each client that connects to the display must transfer the property. A size of around 1-3KByte is reasonable. Some toolkits may track changes to the RESOURCE_MANAGER but most do not. A user may have many per application default files containing customizations specific to each application. The intrinsics are quite flexible on how this file is found. Read the next part that describes the various environment variables and how they effect where this file is found. The system wide per application default files are typically found in /usr/lib/X11/app-defaults. If such a file is not found then the fallback resources are used. The intrinsics are quite flexible on how this file is found. Read the next part that describes the various environment variables and how they effect where this file is found. [Thanks to Oliver Jones (oj@pictel.com) for the following, 6/92] You can use several environment variables to control how resources are loaded for your Xt-based programs -- XFILESEARCHPATH, XUSERFILESEARCHPATH, and XAPPLRESDIR. These environment variables control where Xt looks for application-defaults files as an application is initializing. Xt loads at most one app-defaults file from the path defined in XFILESEARCHPATH and another from the path defined in XUSERFILESEARCHPATH. Set XFILESEARCHPATH if software is installed on your system in such a way that app-defaults files appear in several different directory hierarchies. Suppose, for example, that you are running Sun's Open Windows, and you also have some R4 X applications installed in /usr/lib/X11/app-defaults. You could set a value like this for XFILESEARCHPATH, and it would cause Xt to look up app-defaults files in both /usr/lib/X11 and /usr/openwin/lib (or wherever your OPENWINHOME is located): setenv XFILESEARCHPATH /usr/lib/X11/%T/%N:$OPENWINHOME/lib/%T/%N The value of this environment variable is a colon-separated list of pathnames. The pathnames contain replacement characters as follows (see XtResolvePathname()): %N The value of the filename parameter, or the application's class name. %T The value of the file "type". In this case, the literal string "app-defaults" %C customization resource (R5 only) %S Suffix. None for app-defaults. %L Language, locale, and codeset (e.g. "ja_JP.EUC") %l Language part of %L (e.g. "ja") %t The territory part of the display's language string %c The codeset part of the display's language string Let's take apart the example. Suppose the application's class name is "Myterm". Also, suppose Open Windows is installed in /usr/openwin. (Notice the example omits locale-specific lookup.) /usr/lib/X11/%T/%N means /usr/lib/X11/app-defaults/Myterm $OPENWINHOME/lib/%T/%N means /usr/openwin/lib/app-defaults/Myterm As the application initializes, Xt tries to open both of the above app-defaults files, in the order shown. As soon as it finds one, it reads it and uses it, and stops looking for others. The effect of this path is to search first in /usr/lib/X11, then in /usr/openwin. Let's consider another example. This time, let's set XUSERFILESEARCHPATH so it looks for the file Myterm.ad in the current working directory, then for Myterm in the directory ~/app-defaults. setenv XUSERFILESEARCHPATH ./%N.ad:$HOME/app-defaults/%N The first path in the list expands to ./Myterm.ad. The second expands to $HOME/app-defaults/Myterm. This is a convenient setting for debugging because it follows the Imake convention of naming the app-defaults file Myterm.ad in the application's source directory, so you can run the application from the directory in which you are working and still have the resources loaded properly. NOTE: when looking for app-default files with XUSERFILESEARCHPATH, for some bizarre reason, neither the type nor file suffix is defined so %T and %S are useless. With R5, there's another twist. You may specify a customization resource value. For example, you might run the "myterm" application like this: myterm -xrm "*customization: -color" If one of your pathname specifications had the value "/usr/lib/X11/app-defaults/%N%C" then the expanded pathname would be "/usr/lib/X11/app-defaults/Myterm-color" because the %C substitution character takes on the value of the customization resource. The default XFILESEARCHPATH, compiled into Xt, is: /usr/lib/X11/%L/%T/%N%C:\ (R5) /usr/lib/X11/%l/%T/%N%C:\ (R5) /usr/lib/X11/%T/%N%C:\ (R5) /usr/lib/X11/%L/%T/%N:\ /usr/lib/X11/%l/%T/%N:\ /usr/lib/X11/%T/%N (Note: some sites replace /usr/lib/X11 with a ProjectRoot in this batch of default settings.) The default XUSERFILESEARCHPATH, also compiled into Xt, is /%L/%N%C:\ (R5) /%l/%N%C:\ (R5) /%N%C:\ (R5) /%L/%N:\ /%l/%N:\ /%N: is either the value of XAPPLRESDIR or the user's home directory if XAPPLRESDIR is not set. If you set XUSERFILESEARCHPATH to some value other than the default, Xt ignores XAPPLRESDIR altogether. Notice that the quick and dirty way of making your application find your app-defaults file in your current working directory is to set XAPPLRESDIR to ".", a single dot. In R3, all this machinery worked differently; for R3 compatibilty, many people set their XAPPLRESDIR value to "./", a dot followed by a slash. ---------------------------------------------------------------------- Subject: 21. What order are callbacks executed in? ---------------------------------------------------------------------- (Courtesy of Donna Converse, converse@x.org; 5/10/92) The Intrinsics library do not guarantee an order. This is because both the widget writer and the application writer have the ability to modify the entire contents of the callback list. Neither one currently knows what the other is doing and so the Intrinsics cannot guarantee the order of execution. The application programmer cannot rely on the widget writer; the widget writer is not required to document when the widget will add and remove callbacks from the list or what effect this will have; therefore the functionality contained in a callback should be independent of the functionality contained in other callbacks on the list. Even though the Xt standard in the definition of XtAddCallback says: "callback_name: Specifies the callback list to which the procedure is to be appended." you may not infer from the word "appended" that the callback routines are called in the same order as they have been added to the callback list. ---------------------------------------------------------------------- Subject: 22. How do I know if a widget is visible? ---------------------------------------------------------------------- (Courtesy of Donna Converse, converse@x.org; 5/14/92) > I am building a widget needs to know if it is visible. I set the visible > interest field in Core and if my window is completely obscured, the Core > visible flag goes FALSE. However, if my window is iconified, the flag > stays set to TRUE. Right, everything is implemented correctly. This demonstrates a "deficiency" in the X protocol, and the Core widget is reflecting the capabilities of the protocol. (The "deficiency" is that the information is available in one way, in this case an inconvenient way.) The Xt specification is accurate, in the second and third paragraphs of section 7.10.2, so read this section carefully. The visible field will not change in response to iconification. A VisibilityNotify event will not be received when the window goes from viewable to unviewable, that is, when the widget or an ancestor is unmapped; that is, when iconification occurs. This is the protocol deficiency. Visibility state and viewable state have specific meanings in the X protocol; see the glossary in your Xlib and X protocol reference manual. > Is this a problem with "mwm" or is there something > else which needs to be done? You'll see this with any window manager, with no window manager. > If the problem is "mwm", what is the fastest > way to determine if a window is iconified? As an application writer, keep track with a global Boolean in an action routine with translations for MapNotify and UnmapNotify on the Shell widget which contains your custom widget. As the custom widget writer, see the map_state field returned by a call to XGetWindowAttributes. These are suggestions. ---------------------------------------------------------------------- Subject: 23. How do I reparent a widget in Xt, i.e. XtReparentWidget()? ---------------------------------------------------------------------- You can't. ---------------------------------------------------------------------- Subject: 24. Why use XtMalloc, XtFree, etc? ---------------------------------------------------------------------- Unfortunately, most code that calls malloc(), realloc() or calloc() tends to ignore the possibility of returning NULL. At best it is handled something like: ptr = (type *) malloc (sizeof (type)) if (!ptr) { perror ("malloc in xyzzy()"); exit (1) } To handle this common case the Intrinsics define the functions XtMalloc(), XtCalloc(), XtNew(), XtNewString() and XtRealloc() which all use the standard C language functions malloc(), calloc() and realloc() but execute XtErrorMsg() if a NULL value is returned. Xt error handlers are not supposed to return so this effectively exits. In addition, if XtRealloc() is called with a NULL pointer, it uses XtMalloc() to get the initial space. This allows code like: if (!ptr) ptr = (type *) malloc (sizeof (type)); else ptr = (type *) realloc (ptr, sizeof (type) * (count + 1)); ++count; to be written as: ptr = XtRealloc (ptr, sizeof (ptr) * ++count); Also, XtFree() accepts a NULL pointer as an argument. Generally, I've found the Xt functions conveniant to use. However, anytime I'm allocating anything potentially large I use the standard functions so I can fully recover from not enough memory errors. XtNew() and XtNewString() are conveniant macros for allocating a structure or copying a string: struct abc *xyzzy; char *ptr; char *str = "abcdef"; xyzzy = XtNew (struct abc); /* takes care of type casting */ ptr = XtNewString (str); A strict interpretation of the Intrinsics reference manual allow an implementation to provide functions that are not exchangable with malloc() and free(). I.e. code such as: char *ptr; ptr = XtMalloc (100); /* ... */ free (ptr); may not work. Personally, I'd call any implementation that did this broken and complain to the vendor. A common error for Motif programmers is to use XtFree() on a string when they should really be using XmStringFree(). ---------------------------------------------------------------------- Subject: 25. How to debug an Xt application? ---------------------------------------------------------------------- First, I'd recomend getting "purify" from Pure Software. This is a great package for tracing memory problems on Sun's. It's a bit pricey at $2750 but I'd still recomend it. Excuse the marketing blurb (contact support@pure.com for more info). Purify inserts additional checking instructions directly into the object code produced by existing compilers. These instructions check every memory read and write performed by the program under test and detect several types of access errors, such as reading unitialized memory, writing past malloc'd bounds, or writing to freed memory. Purify inserts checking logic into all of the code in a program, including third party and vendor object-code libraries, and verifies system call interfaces. In addition, Purify tracks memory usage and identifies individual memory leaks using a novel adaption of garbage collection techniques. Purify's nearly comprehensive memory access checking slows the target program down typically by a factor of two to five. An alternative package that isn't as pricey ($395 for a Sun), runs on many Unix's and has pretty similar features is "The SENTINEL Debugging Environment". This replaces malloc() and several other C library functions to add additional checks. (contact cpcahil@virtech.vti.com for more info) Next, if you are getting any sort of Xlib error, you'll need to run in synchronous mode, easily accomplished with the "-sync" command line argument or by setting the variable Xdebug to 1 with your debugger. Then set a break point in exit(). This will let you trace back to the original Xlib function being called. If you don't run in synchronous mode, then the actual error may have occured any number of calls to Xlib previously since the Xlib calls are buffered and replies from the server are asynchronous. Next, if you are having trouble with window layout, you can use the undocumented resource "xtIdentifyWindows" or the class resource "XtDebug" to cause the widget name to be identified with each window. For example: example% xload -xrm '*XtDebug:true' & example% xwininfo -tree will give the normal information but the widget name and class of each window is included. This can help for checking the location and size of errant widgets. Next, if you are having trouble with geometry managers or you want to test the way a widget manages it's children, you can try ftp.x.org:contrib/libXtGeo.tar.Z. This acts as a filter between any children and a geometry manager and checks the behaviour of both. It's a very clever idea. The most unfortunate problem is debugging a callback while the application is executing a grab of the keyboard or mouse (such as from a pulldown menu). The server effectively locks up and you'll need to go to another machine and kill the debugger manually. The server locks up because the application being debugged has said no one else can have access to the keyboard but the application is not stopped waiting because the debugger is waiting for your commands. Unfortunately you can't give them because all the input is going to your application which is stopped. The best way to debug this kind of problem is with two machines on your desk, running the program under a debugger (or other environment) on one machine, and running the application on the other, possibly using a command sequence like this: othermachine% xhost +thismachine thismachine% setenv DISPLAY othermachine:0; thismachine% gdb application # Your favorite debugger. or this: othermachine% xhost +thismachine thismachine% gdb application (gdb) set environment DISPLAY othermachine:0 (gdb) run ... I believe CodeCenter, a C interpreter/graphical debugger has a method of dealing with this by explicitely calling the Xlib functions to release any grabs during breakpoints. Debugging widget problems requires pretty good debugging skills and knowledge of how widgets work. You can go a long way without knowing the internals of a particular widget but not very far without understanding how a widget works. Judicious use of conditional breakpoints and adding print statements with the debugger help a great deal. ---------------------------------------------------------------------- Subject: 26. Why don't XtAddInput(), XtAddTimeout() and XtAddWorkProc() work? ---------------------------------------------------------------------- I have got a delicate problem with the three routines XtAddInput, XtAddTimeOut and XtAddWorkProc. The problem I have is that when I use them in my application they seem not to be registred properly. I have made a handy little testprogram where everything works perfect, but in my "real" application nothing happens. The introduction in R3 of the XtApp*() functions obsoleted those routines (see Q19 for other changes in R3, R4, and R5). What happens is they use a default application context different then the one you may have created. Since events and timeouts are distributed on a per application context basis and you are using two application contexts, you won't get those events. For example: ... cnt = 0; toplevel = XtAppInitialize(&app, class, Desc, XtNumber (Desc), &argc, argv, Fallback, args, cnt); XtAddTimeOut (...) XtAddWorkProc (...) XtAppMainLoop (app) would never invoke the timeout. ---------------------------------------------------------------------- Subject: 27. What is and how can I implement drag and drop? ---------------------------------------------------------------------- (Courtesy of Roger Reynolds, rogerr@netcom.com; 19 Feb 93) Drag-n-drop is a buzzword for moving data between clients, in an ``intuitive'' fashion. Motif Version 1.2 supports drag-n-drop capabilities, OpenLook has supported d-n-d all along. The two protocols are not compatable with each other, and so far as I know, they are not published. I wrote a package called RDD which is designed to be a flexible public protocol for doing drag 'n drop operations between clients. My intention was to provide a tool which would make it easy for people to support a "standard" drag-n-drop protocol in the programs they develop and contribute or sell, regardless of what widget set is used (as long as it is based on Xt). The implementation is based upon my understanding of the ICCCM conventions, for more details read the code. I have heard from dozens of people using RDD who like it and feel that it works a whole lot better than Motif 1.2 stuff. Also, there seem to be many who think that it is neat but are constrained to use Motif anyway. The latest RDD (and some other stuff) is available for ftp from netcom.com, in /pub/rogerr. A (possibly older) version is also available on ftp.x.org in /contrib. ---------------------------------------------------------------------- Subject: 28. How can I add a C++ member function as a widget callback? ---------------------------------------------------------------------- (Courtesy of lanzo@tekelec.com (Mark Lanzo), 7 Sep 1993) You can not add a regular C++ member function as a callback to a widget, because the callback function won't be invoked with the hidden object pointer "this" which all regular C++ member functions require. However, there is a way to get around this limitation: "static" member functions. A static member function is a function to which the usual scoping and access rules apply, but which is not in fact actually associated with a specific instance of an object, and it is NOT called using the special member function calling syntax. In particular, there is no "this" pointer supplied to the function. This means that a "static" member function is really a lot like a "friend" function except that its name is within the scope of the class (in other words, the name is prefixed with the class name). To demonstrate this, let's create a trivial class "Icon" which includes a "button" widget, and a member function "select_CB" which is installed as the "XmNselectCallback" on the button. The class declaration would then look something like this: class Icon { private: Widget button; static void select_CB(Widget, XtPointer, XtPointer); public: Icon(Widget parent); // Constructor }; For the example above, I can declare the constructor and callback functions like this: Icon::Icon (Widget parent) { button = XtVaCreateWidget ("icon_button", xmPushButtonWidgetClass, parent, NULL); // Depending on your compiler, you may be able to specify // "&Icon::select_CB" simply as "select_CB" in the // following statement: XtAddCallback (button, XmNselectCallback, &Icon::select_CB, (XtPointer) this); } void Icon::select_CB (Widget w, XtPointer userData, XtPointer callData) { Icon * icon = (Icon *) userData; // Instead of "this" // do whatever you want to do when the icon is selected ... } There are two things to note here: *) If you want the static member function to work on a specific object, you must supply the object pointer (such as by "userData" in the example). Just like a non-member function. *) Although the function is declared as "static" inside the class definition, you do NOT include the "static" keyword when you actually define the function. ---------------------------------------------------------------------- Subject: 29. How can I identify the children of a manager widget? ---------------------------------------------------------------------- Use XtGetValues() on XtNchildren (array of widget IDs) and XtNnumChildren (number of widgets in array). Widget *children = NULL; Cardinal count = 0; Arg args[10]; Cardinal cnt; cnt = 0; XtSetArg (args[cnt], XtNchildren, &children); ++cnt; XtSetArg (args[cnt], XtNnumChildren, &count); ++cnt; XtGetValues (widget, args, cnt); NOTE: This does not get the list of popup children. One must access the private members of Core to do so. ---------------------------------------------------------------------- Subject: 30. Can I use XtMoveWidget(), ... to move widgets I created? ---------------------------------------------------------------------- No. In general, XtMoveWidget(), XtResizeWidget(), XtMakeGeometryRequest(), and XtConfigureWidget() are for widget internals only. The only way for applications to change widget geometry or configuration is through the XtSetValues() interface and setting the XtNx, XtNy, XtNwidth and XtNheight resources. If this interface does not give you what you want, you should subclass the widget to modify its geometry managers. ---------------------------------------------------------------------- Subject: 31. Why is XtGetValues() on XtNx, XtNy of my top level shell wrong? ---------------------------------------------------------------------- XtNx and XtNy are the coordinates relative to your shell's parent window, which is usually a window manager's frame window. To translate to the root coordinate space, use XtTranslateCoords() or XTranslateCoordinates(). NOTE: XtTranslateCoords() was broken in releases prior to R4. ---------------------------------------------------------------------- Subject: 32. Why do some people use XmN as resource names? ---------------------------------------------------------------------- Motif adopted the convention of prefixing all their resources with XmN instead of XtN. Why? It makes some small amount of sense to not pollute the Xt name space. Unfortunately it is not really practical because it means every widget set would have to define all the resources, including ones defined by the Intrinsics. Very messy. But heh, OSF is it's own world, right? ---------------------------------------------------------------------- Subject: 33. How do I make my life easier when designing an application? ---------------------------------------------------------------------- Find out about WCL. Any other suggestions, anyone? ---------------------------------------------------------------------- Subject: 34. Why can't I override translations? Only the first item works. ---------------------------------------------------------------------- (Thanks to Timothy J. Horton, 5/91) You probably have an extra space after the specification of the first item, like this: basic*text.translations: #override \ Ctrla: beginning-of-line() \n\ Ctrle: end-of-line() ^ extra space The newline after that space is ending the translation definition. ---------------------------------------------------------------------- Subject: 35. Why do I get "Warning: Widget class version mismatch"? ---------------------------------------------------------------------- This error, which typically goes on to say, "widget 11004 vs. intrinsics 11003" indicates that the header files you included when building your program didn't match the header files that the Xt library you're linking against was built with; check your -I include path and -L link-path to be sure. However, the problem also occurs when linking against a version of the X11R4 Xt library before patch 10; the version number was wrong. Some Sun OW systems, in particular, were shipped with the flawed version of the library, and applications which link against the library typically give the warnings you have seen. ---------------------------------------------------------------------- Subject: 36. Where can I get a good file-selector widget? ---------------------------------------------------------------------- The Free Widget Foundation set offers a FileSelector widget, with separate directory path and file listing windows, and the FileComplete, which has emacs-style file completion and ~ expansion. Other available file-requestor widgets include the XiFileSelector from Iris Software's book, the xdbx file-selector extracted by David Nedde (daven@ivy.wpi.edu), and the FileNominator from the aXe distribution. The GhostView, Xfig, and vimage packages also include file-selector widgets. ---------------------------------------------------------------------- Subject: 37. Where can I find a hypertext widget or source code? ---------------------------------------------------------------------- A hypertext widget was posted to comp.sources.x. It can be found in volume 16 of the archives at ftp.uu.net under the name "hman". The distribution includes a hypertext widget with both Athena and Motif compatability (set at compile-time) and hman, a Motif-based man reference page reader that uses the widget to look up other man topics. [Joe Shelby (shelby@dirac.physics.jmu.edu); 6/93] ---------------------------------------------------------------------- Subject: 38. What widget is appropriate to use as a drawing canvas? ---------------------------------------------------------------------- Some widget sets have a widget particularly for this purpose -- a WorkSpace or DrawingArea which doesn't display anything but lets your Xt application know when it has been re-exposed, resized, and when it has received user key and mouse input. The best thing to do for other widget sets -- including the Athena set -- is to create or obtain such a widget; this is preferable to drawing into a core widget and grabbing events with XtAddEventHandler(), which loses a number of benefits of Xt and encapsulation of the functionality . The publicly-available programs xball and xpic include other versions. The Display widget in the XG library (libXG-2.0.tar.Z on ftp.x.org) provides a generic way of drawing graphics in a widget. The Athena Widget manual (mit/doc/Xaw/Template in the R5 distribution) includes a tutorial and source code to a simple widget which is suitable for use. The Free Widget Foundation set contains a Canvas widget. ---------------------------------------------------------------------- Subject: 39.!What is this link problem with _get_wmShellWidgetClass? ---------------------------------------------------------------------- Unresolved externals under SunOS 4.1.[23] is indicative of an incorrect configuration, specifically failure to set the OSTeenyVersion in sun.cf. If you are running on SunOS 4.1.[23] you should apply all the fixes up to fix-25. Make certain that you set the OSTeenyVersion correctly in mit/config/sun.cf. [Above from kaleb@expo.lcs.mit.edu (Kaleb Keithley) 15 Oct 1993] In SunOS 4.1.2 Sun fixed a shared-library bug in ld which conflicts with the way X builds the shared Xmu library, causing these symbols, notably, to be undefined when building some X11 clients: _get_wmShellWidgetClass _get_applicationShellWidgetClass Compiling "-Bstatic -lXmu -Bdynamic" appears to work. To solve the problem if you are using OpenWindows 3.0 (X11R4-based Xt), please contact your local Sun office and request the following patches: Patch i.d. Description 100512-02 4.1.x OpenWindows 3.0 libXt Jumbo patch 100573-03 4.1.x OpenWindows 3.0 undefined symbols when using shared libXmu [Greg Earle, earle@Sun.COM; 7/92] A source patch for use with the MIT X11R4 libraries was developed by Conrad Kimball (cek@sdc.boeing.com); it retrofits into R4 some fixes made in R5 to get around this problem. The patch is on ftp.x.org in [1/93] contrib/X11R4_sunos4.1.2_patch_version3.Z ---------------------------------------------------------------------- Subject: 40. Why does XtGetValues not work for me (sic)? ---------------------------------------------------------------------- The XtGetValues interface for retrieving resources from a widget is sensitive to the type of variable. Your code may be doing something like this: { Arg args[3]; int i; int sensitive; /* oops; wrong data type */ i=0; XtSetArg (args[i], XtNsensitive, &sensitive); i++; XtGetValues(widget, args, i ); ... } But XtNsensitive is a Boolean, which on most machines is a single byte; declaring the variable "sensitive" as Boolean works properly. This problem comes up often when using particular toolkits that redefine the Xt types Dimension and Position; code that assumes they are int will have similar problems if those types are actually short. In general: you are safe if you use the actual type of the resource, as it appears in the widget's man page. [11/90] ---------------------------------------------------------------------- Subject: 41. Is this a memory leak in the X11R4 XtDestroyWidget()?! ---------------------------------------------------------------------- Yes. This is the "unofficial" fix-19 for the X11R4 Destroy.c: *** Destroy.c.1.37 Thu Jul 11 15:41:25 1991 --- lib/Xt/Destroy.c Thu Jul 11 15:42:23 1991 *************** *** 1,4 **** --- 1,5 ---- /* $XConsortium: Destroy.c,v 1.37 90/09/28 10:21:32 swick Exp $ */ + /* Plus unofficial patches in revisions 1.40 and 1.41 */ /*********************************************************** Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, *************** *** 221,239 **** */ int i = 0; ! DestroyRec* dr = app->destroy_list; while (i < app->destroy_count) { if (dr->dispatch_level >= dispatch_level) { Widget w = dr->widget; if (--app->destroy_count) bcopy( (char*)(dr+1), (char*)dr, ! app->destroy_count*sizeof(DestroyRec) ); XtPhase2Destroy(w); } else { i++; - dr++; } } } --- 222,245 ---- */ int i = 0; ! DestroyRec* dr; while (i < app->destroy_count) { + + /* XtPhase2Destroy can result in calls to XtDestroyWidget, + * and these could cause app->destroy_list to be reallocated. + */ + + dr = app->destroy_list + i; if (dr->dispatch_level >= dispatch_level) { Widget w = dr->widget; if (--app->destroy_count) bcopy( (char*)(dr+1), (char*)dr, ! (app->destroy_count - i) * sizeof(DestroyRec) ); XtPhase2Destroy(w); } else { i++; } } } [from Donna Converse, converse@x.org] ---------------------------------------------------------------------- Subject: 42. Is this a memory leak in the X11R4 deletion of work procs?! ---------------------------------------------------------------------- Apparently the X11R4 NextEvent.c`CallWorkProc fails to properly replace the work proc record back on the free list correctly. if (delete) { w->next = freeWorkRecs; freeWorkRecs = w->next; /* should be =w; */ } ---------------------------------------------------------------------- Subject: 43. How do I query the user synchronously using Xt? ---------------------------------------------------------------------- It is possible to have code which looks like this trivial callback, which has a clear flow of control. The calls to AskUser() block until answer is set to one of the valid values. If it is not a "yes" answer, the code drops out of the callback and back to an event-processing loop: void quit(Widget w, XtPointer client, XtPointer call) { int answer; answer = AskUser(w, "Really Quit?"); if (RET_YES == answer) { answer = AskUser(w, "Are You Really Positive?"); if (RET_YES == answer) exit(0); } } A more realistic example might ask whether to create a file or whether to overwrite it. This is accomplished by entering a second event-processing loop and waiting until the user answers the question; the answer is returned to the calling function. That function AskUser() looks something like this, where the Motif can be replaced with widget-set-specific code to create some sort of dialog-box displaying the question string and buttons for "OK", "Cancel" and "Help" or equivalents: int AskUser(w, string) Widget w; char *string; { int answer=RET_NONE; /* some not-used marker */ Widget dialog; /* could cache&carry, but ...*/ Arg args[3]; int n = 0; XtAppContext context; n=0; XtSetArg(args[n], XmNmessageString, XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET)); n++; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); n++; dialog = XmCreateQuestionDialog(XtParent(w), string, args, n); XtAddCallback(dialog, XmNokCallback, response, &answer); XtAddCallback(dialog, XmNcancelCallback, response, &answer); XtAddCallback(dialog, XmNhelpCallback, response, &answer); XtManageChild(dialog); context = XtWidgetToApplicationContext (w); while (answer == RET_NONE || XtAppPending(context)) { XtAppProcessEvent (context, XtIMAll); } XtDestroyWidget(dialog); /* blow away the dialog box and shell */ return answer; } The dialog supports three buttons, which are set to call the same function when tickled by the user. The variable answer is set when the user finally selects one of those choices: void response(w, client, call) Widget w; XtPointer client; XtPointer call; { int *answer = (int *) client; XmAnyCallbackStruct *reason = (XmAnyCallbackStruct *) call; switch (reason->reason) { case XmCR_OK: *answer = RET_YES; /* some #define value */ break; case XmCR_CANCEL: *answer = RET_NO; break; case XmCR_HELP: *answer = RET_HELP; break; default: return; } } and the code unwraps back to the point at which an answer was needed and continues from there. [Thanks to Dan Heller (argv@sun.com); further code is in Dan's R3/contrib WidgetWrap library. 2/91] ---------------------------------------------------------------------- Subject: 44. How do I simulate a button press/release event for a widget? ---------------------------------------------------------------------- You can do this using XSendEvent(); it's likely that you're not setting the window field in the event, which Xt needs in order to match to the widget which should receive the event. If you're sending events to your own application, then you can use XtDispatchEvent() instead. This is more efficient than XSendEvent() in that you avoid a round-trip to the server. Depending on how well the widget was written, you may be able to call its action procedures in order to get the effects you want. [courtesy Mark A. Horstman (mh2620@sarek.sbc.com), 11/90] ---------------------------------------------------------------------- Subject: 45. How to use Fallback resources (can I specify colors)? ---------------------------------------------------------------------- (Courtesy of Donna Converse, converse@x.org; 12/7/93) See the R5 Intrinsics specification section 2.3 "Loading the Resource Database". Colors cannot be reliably specified in fallback resources. The only way you could force this to work would be to include in the application the same algorithm that Xt uses to determine the display; to open that display, determine if it is color, close the display; and then set the appropriate fallback resources; and continue on as usual. The intended use of fallback resources is to provide a minimal number of resources that will make the application usable (or at least terminate with helpful diagnostic messages) when some problem exists in finding and loading the application class defaults file. The application class defaults file is authored by the application developer and can be used to specify default colors that apply only to capable monitors. In addition, users of an Xt-based application can specify colors in an application-specific user-specific resource file and have those apply only to capable monitors. The mechanism for setting this up is introduced in R5 Xt and it is the customization resource and this is noted in the Xt specification section 13.3.3. Read that section, read section 2.3, and look at this simple example for an application whose class name is "Xmh". (Maybe there's a tutorial about this in one of the O'Reilly books? Maybe I should write a book?) The end-user must set the customization resource, at any point earlier than when the Intrinsics goes to look for the application defaults files. #ifdef COLOR Xmh.customization: -color #endif The application programmer supplies two application class defaults files, and one has the string "-color" appended to the application class name as the name of the file. This file includes the other file, and it also gives resources specific to color displays. The other file gives resources that generally apply. In the application class defaults file named "Xmh-color", it might say: #include "Xmh" xmh*borderColor: Red xmh*background: Ivory and so on. In the application class defaults file named "Xmh" it might say: ! AppDefaultsVersion should only be defined in the site-wide file Xmh.AppDefaultsVersion: 1 Xmh.Geometry: 508x750 Xmh.ReplyInsertFilter: cat Xmh.SendBreakWidth: 2000 and so on. The first line is a comment, and introduces another interesting mechanism that demonstrates how fallback resources can be useful in checking that the application class defaults file is installed. Xt will use the fallback resources only if the application class (site-wide) defaults file is not found. The application itself, in this case xmh, checks the value of application resource AppDefaultsVersion and if it is the default value, or of a revision earlier than the application expects, it can recognize that the correct default resources are not available and report it by popping up a dialog box with a message so the user can understand what needs to be done to get these default resources. The application class default files were intended to be modifiable by a site administrator -- if you try to stuff all the default resources into the fallback resources not only will you not have the power of the customization resource but you might also have to tell people to edit the source to change the default resources -- which is a disadvantage. ---------------------------------------------------------------------- Subject: 46. What is the preferred way of setting the application resources? ---------------------------------------------------------------------- (Courtesy of Donna Converse, converse@x.org; 1/8/94) I advise using a site-wide application default file. Advantages of using an application default file: + The site administrator can customize your application for all users at the site. + You can indicate in the application-defaults file which resources may be changed and the effect of changing them by commenting. + Its an additional form of documentation for power users of your app. Many users create an application-specific defaults file of their own. Those who do usually read the site-wide application defaults file in order to see what's going on. To allow user-specified defaults to take precedence over site-wide defaults, application developers should always give the loosest resource binding and use class names rather than instance names where possible, in the site-wide defaults file. + You can supply multiple versions, each implementing different styles, languages, presentation arrangements, options, colors, demonstrating the coherence and adaptability of your application by having the user changing the value of their customization resource for your application. Application default files may include other application default files, making it possible to separate color customization from language customization, from functional customization, for example. Disadvantages of using fallback resources for the default resources of the application: - Fallback resources were not designed with this purpose in mind. - Code bloat. - Users and site administrators will be tempted to edit your source in order to figure out what resources you have set and to make their own changes, making things messy and difficult for them when it comes time to update their sources. - Anyone can override all of your default resources by supplying their own application default file, often inexplicably breaking your app. - You're not taking advantage of one of the most powerful features of the X toolkit -- it's provision for end-users to customize applications. > I read where fallback > resources should be a minimum to get the application running or to > display an error if the application defaults cannot be loaded. Any > idea what a "minimum" is :-) ? The X Consortium's mail application, xmh, has an application defaults file aptly named Xmh. If you remove this file, it's fallback resources are used. In that case it pops up a dialog box warning you that the application functionality will probably not work because the application defaults file is missing. This same design can be used as a versioning check on the application defaults file, when one is used, and xmh implements that as well -- so you can update your application and the app-defaults file and implement a versioning check, and report it when the site administrator failed to install your application correctly. Now, try using the X Consortium's calculator application, xcalc, without its application defaults file. Nothing works at all, and, it doesn't say why, so the application is worthless and uncommunicative without its application defaults file. So a minimum is to report that the application defaults file is missing, or, if you have a simple application, to have the minimum functionality in place with no decorative resources set. -- Pete Ware ware@cis.ohio-state.edu CIS Dept, Ohio State University w/ (614) 292-7318 228 Bolz Hall, 2036 Neil Ave. h/ (614) 538-0965 Columbus, OH 43210