Path: utzoo!attcan!uunet!lll-winken!lll-tis!ames!mailrus!husc6!uwvax!speedy!solomon From: solomon@speedy.cs.wisc.edu (Marvin Solomon) Newsgroups: comp.windows.x Subject: Re: How do I create popup menus with Xt? Message-ID: <6027@spool.cs.wisc.edu> Date: 20 Jul 88 18:02:36 GMT References: <6005@spool.cs.wisc.edu> <8807191717.AA00552@LYRE.MIT.EDU> Sender: news@spool.cs.wisc.edu Reply-To: solomon@speedy.cs.wisc.edu (Marvin Solomon) Organization: U of Wisconsin CS Dept Lines: 177 In article <8807191717.AA00552@LYRE.MIT.EDU> swick@ATHENA.MIT.EDU (Ralph R. Swick) writes: >> First, I looked at all the examples of applications I could find to see >> how others did it, and discovered that although the Toolkit intrinsics >> have all kinds of stuff that seems to be designed for the purpose, ABSOLUTELY >> NOBODY USES IT! > >You have here only another instance of resource allocation and scheduling >conflicts. The clients you cite were all built in pre-Xt days and therefore >had to (independently) do everything the hard way. The task of fixing >things that work has been very low on our priority list. > >The popup support in Xt does work. There are some kinks that will be >smoothed out in R3, as well as widgets which have more mechanism >(and less policy :-) for using the popup support in Xt. > >It sounds like you are basically on the right track in your adopted role >as widget writer trying to figure out how to use the mechanisms. Your >frustration in being forced to play that role is understandable. We >will be happy to deal with specific bugs in Xt and Xaw as they are >brought to our attention. David Scarbro of InterLeaf suggested an enhancement for my sample program. It now works exactly as I want it. It involves fixing a specific bug in Xt. More on this below. As the above message (as well as one by Robert Blumen of Xerox PARC) suggests, my problem is that I'm trying to take on the role of widget creater when I'd much rather be widget user. The main problem is that right now, the set of Xt-conforming widgets (i.e., lib/Xaw) is quite small. Hopefully, that will change in the near future. In the mean time, we've got lots of mechanism and precious little policy. Otherwise stated: The Intrinsics make everything possible, and nothing easy :-). A philosophical question: Where is the Toolkit (with a capital "T") headed? It seems to me that the "object-oriented" design dictates that there be no such thing as "application programs". Rather, each piece of application functionality is realized as a new widget class. This is the way xterm is (more or less) designed, and it is the design I finally came up with for my troff previewer: I defined a new Proof widget class. The justification for this approach goes as follows: If a widget class is only desiged to be instantiated (as opposed to inherited), it is likely to be either too inflexible, or loaded down with a zillion options, which make it complicated to understand and use. The object-oriented approach says that instead of giving a widget an option (resource) for every conceivable way that it might be customized, it is better to create custom versions by inheritence. For example, the Box widget class could be extended with a XtNlayout resource with values of "vertical", "horizontal", or "unconstrained" (the current behavior), which would make it easier to use as a popup menu. But a much better approach is to define a MenuBox subclass, as Robert Blumen suggests, which is not only vertical, but also resizes the members so they're all the same width. There are two drawbacks to this approach. First, it is an unfamiliar style of programming. However, once people get used to it, I think they'll like it. A little discussion in the Widgets document (including at least one realistic example) can go a long way to ease the path. The second problem is more serious: The Toolkit (both intrinsics and existing Athena widgets) seem to make the assumption that applications programmers are simpletons that need to be lead by the hand, whereas widget programmers are gurus initiated into the archane rites of toolkitism. The object-oriented approach erases the distinction. Existing widgets are admirably easy to use if they do what you want by default, and moderately easy to use if they can be customized by XtSetAttributes(). Creating a new widget class is mildly painful if you can find an existing class definition that is "close enough" to hack on (my Proof widget is a hacked Mailbox widget, which is itself a hack of the Clock widget, according to a comment in Mailbox.h). Creating a new widget class from scratch is VERY confusing to the uninitiated. It occurs to me that a lot of pain is caused by trying to do object-oriented programming in a language that doesn't support it. Is there likely to be a C++ version of the Toolkit? Yes I know about InterViews, but it seems to be totally incompatible with the Intrisics, and it is not clear to me how to mix widgets from the two worlds. Another approach might be a pre-processor that takes a specification, looking something like SmallTalk, and translates into FooP.h, Foo.h, and Foo.c. But I'm getting too far afield. Several people have indicated privately that they appreciate my sample popup program. Fixes mailed to me by David Scarbro make it much better. He found a bug in the Intrinsics that seems to be the root of all my problems with MenuPopdown(). With that bug fixed, adding MenuPopdown() to my program is straightforward. I quote both fixes below (without permission--I hope he doesn't mind). I hope he reported the bug fix to bugs@mit. If not, perhaps somebody at MIT reading this will take it as a bug report. > I found your description of the perils of trying to use Xt to create popups > very helpful. I been playing with the Xt and had just started to try building > a popup out of widgets. Your message saved me a lot of time. Thanks. > > I think I solved the problem that you were having with MenuPopup(). By using > a debugger, I discovered that _XtMenuPopup() was calling _XtPopup as follows: > _XtPopup(popup_shell, XtGrabNonexclusive, FALSE). So your hunch was correct, > no grab was active. I chased this problem to a bug in > XtConvertStringToBoolean(). To fix this bug, I changed: > *bP = (Boolean) *(int*)toVal.addr; > to > *bP = *(Boolean*)toVal.addr; > Now _XtPopup appears to be getting called correctly. > > With one additional change to your program, popups seem work. I had to add > another translation mapping. > > ---- > H. David Scarbro UUCP: ..!{sun!sunne,mit-eddie}!ileaf!hds > Interleaf, Inc. Internet: hds@ileaf.com > Ten Canal Park Phone: (617)577-9800 x6608 > Cambridge, MA 02141 The changes to my test program follow. I'm still not happy with the kludge I use for placement of the popup. I may take a hint from Robert Blumen and use XQueryPointer and requests to a geometry manager rather than XtTranslateCoords and XtSetValues for XtNx, and XtNy. ========================= cut here, use patch ============== RCS file: popup.c,v retrieving revision 1.2 diff -b -c -r1.2 popup.c *** /tmp/,RCSt1016586 Wed Jul 20 12:04:02 1988 --- popup.c Wed Jul 20 11:11:50 1988 *************** *** 64,70 { Widget toplevel, menu_bar, button, popupshell, menu, popupbutton; XtPopdownIDRec popdown_pair; ! XtTranslations button_actions, popup_actions; Arg arg; toplevel = XtInitialize( "popup_test", "XPopupTest", --- 64,70 ----- { Widget toplevel, menu_bar, button, popupshell, menu, popupbutton; XtPopdownIDRec popdown_pair; ! XtTranslations button_actions, popup_actions, popdown_actions; Arg arg; toplevel = XtInitialize( "popup_test", "XPopupTest", *************** *** 77,82 ": highlight() set()\n"); popup_actions = XtParseTranslationTable( ": set() MenuPopup(menu)\n"); /**** menu bar ****/ menu_bar = XtCreateManagedWidget( "menu_bar", boxWidgetClass, toplevel, --- 77,84 ----- ": highlight() set()\n"); popup_actions = XtParseTranslationTable( ": set() MenuPopup(menu)\n"); + popdown_actions = XtParseTranslationTable( + ": MenuPopdown()\n"); /**** menu bar ****/ menu_bar = XtCreateManagedWidget( "menu_bar", boxWidgetClass, toplevel, *************** *** 95,100 /**** popup menu ****/ popupshell = XtCreatePopupShell("menu", overrideShellWidgetClass, toplevel, (Arg *)0, ZERO); menu = XtCreateManagedWidget( "PopupMenu", boxWidgetClass, popupshell, (Arg *)0, ZERO); XtAddCallback(popupshell, --- 97,103 ----- /**** popup menu ****/ popupshell = XtCreatePopupShell("menu", overrideShellWidgetClass, toplevel, (Arg *)0, ZERO); + XtOverrideTranslations(popupshell, popdown_actions); menu = XtCreateManagedWidget( "PopupMenu", boxWidgetClass, popupshell, (Arg *)0, ZERO); XtAddCallback(popupshell, ========== end of patch ============= Marvin Solomon Computer Sciences Department University of Wisconsin, Madison WI solomon@cs.wisc.edu or seismo!uwvax!solomon