david@devvax.Jpl.Nasa.Gov (David E. Smyth) (02/01/91)
Submitted-by: david@devvax.Jpl.Nasa.Gov (David E. Smyth) Posting-number: Volume 11, Issue 13 Archive-name: wcl/part01 The Widget Creation Library allows user interfaces to be completely defined within a resource file: the widget heirarchy, widget types, and bindings of widget callback lists and translations to application functions are specified in the resource file using Wc* resources. #! /bin/sh # Make a new directory for the wc sources, cd to it, and run kits 1 # thru 35 through sh. When all 35 kits have been run, read README. echo "This is wc 1.05 kit 1 (of 35). If kit 1 is complete, the line" echo '"'"End of kit 1 (of 35)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir Doc 2>/dev/null echo Extracting Doc/3rdREADME sed >Doc/3rdREADME <<'!STUFFY!FUNK!' -e 's/X//' XWidget Creation Resources X------------------------- X XThe Widget Creation Library allows user interfaces to be completely Xdefined within a resource file: the widget heirarchy, widget types, and Xbindings of widget callback lists and translations to application Xfunctions are specified in the resource file using Wc* resources. X XThe following is the complete set of resources which are Xinterpreted by the Widget Creation Library: X X ...widget.wcResFile: resourceFileName X ...widget.wcClass: classPointerName X ...widget.wcClassName: className X ...widget.wcConstructor: constructorFunctionName X ...widget.wcTrace: true/false (default = false) X ...widget.wcCallback: callback1(args), callback2(args), ... X ...widget.wcPopups: popupChildName1, popupChildName2, ... X ...widget.wcChildren: childName1, childName2, ... X ...widget.wcManaged: true/false (default = true) X XIn all cases, the Widget Creation resource names can be specified as XWc<name> or wc<name>, with the capitalized form having looser binding X(representing the resource class). X XWcResFile Resource X------------------ X XThis resource allows you to put additional resource specifications Xrelated to a widget or its children in a separate file. Like all Xwidget creation resources, the WcResFile resource value is retrieved Xfrom the Xrm database at widget creation time. X XBefore the widget is created, the specified resource file is loaded Xinto the Xrm database, and then another query of the Xrm database is Xmade to obtain the other Wc resources. Therefore, all wc resources X(except of course the WcResFile resource) and other widget resources Xmay be specified in the new resource file. X XWcClass, WcClassName, and WcConstructor Resources X------------------------------------------------- X XThese resources allow you to specify the type of the widget. Only one Xof these resources should be specified for each widget. X XWcTrace Resource X---------------- X XThis resource is useful for debugging your user interface. When `True' Xthe full name and class name of the widget is printed to stderr right Xafter the widget is created. X XWcCallback Resource X------------------- X XThis resource allows you to specify a list of callback functions Xwhich are invoked after the widget is created, and before it is Xmanaged. The callback functions receive the newly created widget as Xtheir widget argument, and whatever is within the parenthesis following Xthe callback function name as a string argument as client data. For Xexample: X X *foo.wcCallback: FooSpecialCB( Hi there ) X XThis specification will cause the function `FooSpecialCB' to be Xcalled. The widget argument will be the newly created widget foo, and Xthe client_data argument will be the null terminated character array " XHi there ". The call_data is whatever was specified when the XFooSpecialCB callback function was registered with XWcRegisterCallback(). X XThis is generally how the interface can create related objects within Xthe application. For example, if your application has a storage Xobject, each widget which provides storage related behaviors or Xattribute displays might register themselves with your application's Xstorage object. X XWcPopups and WcChildren Resource X-------------------------------- X XAfter a widget is created, but before it is managed, all of its Xchildren are created: first the pop-up children, and then the normal Xchildren. Only composite widgets can have normal children, but any Xwidget can have pop-up children. The names of children widgets are Xspecified by the WcPopups and WcChildren resources. The order of the Xnames in the resource value indicate the left-to-right order of widget Xcreation. The names of the widgets in the example below imply the Xorder of creation: X X *foo.wcPopups: ONE, TWO X *foo.wcChildren: THREE, FOUR, FIVE X XEach widget creation is recursive, the widgets are created depth Xfirst. I.e., the widget `ONE' and all of ONE's children will be Xcreated before widget `TWO' will be created. X XWcManaged Resource X------------------ X XThis resource only applies to widgets specified in WcChildren resource Xspecifications. WcManaged allows you to specify that a child of a Xcomposite widget should not be managed following its creation. By Xdefault, widgets specified with WcChildren are managed together with Xtheir siblings after all siblings are created. Wc uses a single call Xto XtManageChildren when possible. X X XHow the Application Interacts with the Widget Creation Library X-------------------------------------------------------------- X XThe typical Wc client application (including Ari and Mri) will create Xan application shell and load the Xrm database by calling XXtInitialize(). It will then register widgets, callbacks, and actions Xwith the Wc library, and then pass the application shell to the XWcWidgetCreation() function. This function returns when the entire Xconnected widget heirarchy specified in the Xrm database is created. XThe widget tree is realized, and then the XtMainLoop is entered. XBriefly: X X appShell = XtInitialize( ... ); X X /* Register widgets, callbacks, and actions */ X X WcWidgetCreation( appShell ); X XtRealizeWidget( appShell ); X XtMainLoop(); X XWhen Resources are Loaded Into the Xrm Database X----------------------------------------------- X XXtInitialize loads an initial set of resource files into the resource Xdatabase before any widgets are created. This initial database may Xcontain references to other resource files by way of WcResFile resource Xspecifications. If a widget `Foo' has a resource specification like Xthis: X X *Foo.wcResFile: FooResources X Xthen the resource file named FooResources will be merged into the Xresource database before the widget Foo is created. In fact, several Xfiles named FooResources may be loaded, as the standard Xt resource Xfile search and load is performed. See section 2.2 and 11.11 of the XX11R4 Xt Intrinsics - C Language Interface manual for more Xinformation. X X XWhen Resources are Retrieved from the Xrm Database X-------------------------------------------------- X XResources are retrieved from the Xrm resource database when widgets are Xcreated. If the resource database changes after widget `Foo' is Xcreated, subsequent changes to the database will have absolutely no Xeffect upon widget `Foo.' X XHow Widgets Are Created from the Xrm Database X--------------------------------------------- X XThe Widget Creation Library starts creating widgets when the XWcWidgetCreation() function is called. Here is the recursive Xscenario. The initial widget is usually the application shell: X X 1. Fetch the wcChildren resource from Xrm database for the X initial widget. This will be a list of widget names. X X 2. For each child: X X 3. Fetch the set of Wc resources. X X 3a. If wcResFile is specified, load that resource file and X fetch the Wc resources again. X X 3b. Using the wcClass, wcClassName, or wcConstructor resource, X create the new child widget. Widget creation uses other X resources defined in the Xrm database specific to the type X of the widget, such as labelString for XmLabels. X X 3c. Re-fetch the Wc* resources to obtain resources which may X apply due to the class of the created widget. X X 3d. If wcCallback resource is defined (specifying a list of X callback functions), invoke each callback in order. X X 3e. If wcTrace is True, then dump the name of the just created X widget to stdout. X X 3f. If wcManaged is True (the default), then this widget will be X managed along with all of its siblings, after they are all X created (a single call to XtManageChildren is invoked by Wc). X X 3f. If the newly created widget has wcPopups or wcChildren specified, X then recursively invoke step (2.) above. Note that this X implements a depth first creation policy, which is generally X optimal for widget trees with manager widget nodes. X X XThe resource files themselves have no explicit flow of control Xmechanisms. However, the order of events during widget creation causes Xthe resources to be evaluated in a deterministic and sometimes Xrepetitive pattern. X XThe most significant control over resource evaluation is the order that Xwidgets are created. Widget creation is ordered by the order of widget Xnames in wcPopups and wcChildren resource lists. The names of widgets in the Xexample below reflects the order these widgets will be created. The Xorder of the resource specifications themselves are irrelevent to the Xorder of creation: X X Mri.wcChildren: one, four X Mri.one.wcClassName: XmRowColumn X Mri.one.wcChildren: two, three X Mri.one.two.wcClassName: XmLabel X Mri.one.three.wcClassName: XmPushButton X Mri.four.wcConstructor: XmCreateWorkingDialog X XWidgets can also be created after the initial widget tree. For example, Xhelp dialogs may be dynamically created only when necessary, so an Xexperienced user does not need to suffer the additional start-up time Xof creating a large number of widgets which are not needed, nor is Xmemory or swap space consumed by the unnecessary widgets. X XHere are resources which demonstrate how a help dialog could be created Xdue to a button press. In this case, the newly created widget will Xbecome a child of the application shell (Mri if the resource file is Xbeing interpreted by Mri). The resources for the help dialog are Xsegregated into another set of resource files which are named X`HelpDialogResources.' The standard Xt resource file search path is Xused, so /usr/lib/X11/app-defaults/HelpDialogResources, ..., X~/apps-defaults/HelpDialogResources, may be loaded into the Xrm Xdatabase due to this one WcResFile specification: X X /* in initial resource file: */ X *helpButton.activateCallback: WcCreatePopupsCB( Mri, helpDialog ) X *helpDialog.wcResFile: HelpDialogResources X X /* in HelpDialogResources: */ X *helpDialog.wcConstructor: XmCreateMessageDialog X *helpDialog.messageLabel: Some help message... X *helpDialog.okCallback: WcDestroyCB( this ) X XFrequently, you probably want such dialogs to remain once they are Xcreated. See the M5.Dialogs resource file for one way to do this. X XIn the above example, notice that the resources specified in the XHelpDialogResources file are unknown to the Xrm database until an Xattempt is made to create the helpDialog widget. !STUFFY!FUNK! echo Extracting Doc/1stREADME sed >Doc/1stREADME <<'!STUFFY!FUNK!' -e 's/X//' X Widget Creation Library, X Motif Resource Interpreter, X Athena Resource Interpreter: X X An Easier Way to Develop Applications X using Motif and Athena Widgets. X XWindow-based applications are notoriously difficult to program. When Xthe Macintosh was introduced in early 1984, Bill Gates projected that X50% of Microsoft revenues would come from Mac application by October X1984. In reality, the first Mac applications were only beginning to be Xshipped by that date. X XWhen Steve Jobs left Apple and developed the NeXT computer, the window Xenvironment was specifically designed to support a WYSIWYG interface Xbuilder. NextStep and the NeXT IB were the results of this effort. X XThe X developers at MIT and DEC also needed an easy way to develop Xwindowed applications. Instead of developing a WYSIWYG tool like NeXT, Xthey developed a toolkit where interfaces were specified using C code, Xand could be significantly modified via `resource files' using a Xminimum number of attribute specifications. They provided an instance Xattribute inheritance mechanism to propogate attributes throughout an Xinterface. This allows such simple specification as the following to Xalter every font in an interface: X X *font: 9x15 X XThe toolkit is called the Xt Intrinsics. The windows, buttons, menus, Xscrollbars, etc., are called Widgets. The Athena Widgets are one set Xof user interface objects built upon the Xt Intrinsics. Motif is Xanother set of widgets. X XAs time went on, developers of widget-based applications found the Xresource files to be more and more useful. For the fourth release of Xthe X11 window system, many of the example programs evolved to the Xpoint that only the raw behavior of the applications were specified in XC, with most of the look and feel being specified using resource Xfiles. X XAt the fourth annual X Technical Conference, several people pointed out Xthat resource files could be used to specify everything about a widget Xbased user interface, except the actual "tree" of widgets, their types, Xand bindings of behaviors to the user interface widgets. Could the Xresource mechanism be enhanced to allow these to be specified as well? X XMartin Brunecky at Auto-Trol in Denver Colorado took up the challenge, Xand posted a simple set of routines which he called WsXc, for "Window XSystem: Xrm Creation." X XXrm stands for X Resource Manager, which is a heirarchical database for Xkeeping arbitrary named data related to X window interfaces. The Xt XIntrinsics use Xrm for widget resources. The basic idea of WsXc is to Xsearch the Xrm database, starting at the root, and pull out resources Xwhich describe the widget heirarchy and bindings to callback Xfunctions. X XOver the next several months, WsXc was repackaged as Mri (Motif XResource Interpreter), and then Ari (Athena Resource Interpreter), and Xfinally generalized into the Widget Creation Library. The result Xprovides several significant benefits to the developer and the user: X X o Rapid Prototyping: Arbitrarily complex widget interfaces X may be specified, and many common behaviors (pop-up, X change attributes, exit) can be specified for the X interface. X X o Prototyping Environment is the Development Environment is X the Delivery Environment: There is no specific breaking X point between prototyping, developing, and tuning a X delivered program. X X o Minimum Specifications: The Xrm and Xt Intrinsics instance X attribute inheritance mechanism is fully utilized, so X a minimum number of specifications can describe a X complete user interface. X X o Extensible: Adding new widget types and callback routines X is trivial. X X o Widget Set Independent: The library itself is completely X widget set independent. X X o Mostly Widget Set Independent Applications: Much of the X C code which provides the behavior of the application X can be written in a widget set independent manner. X This allows an application to be written which supports X multiple look-and-feel definitions: Motif, OpenLook, X and Athena interfaces can all be front-ends to the X same underlying application. X X o The user can make any change to the interface: Deeply nested X menus can be substituted for dialog boxes, or vice X versa. Any label or image can be altered, which X supports internationalization. X XOne of the guiding principles was and is KISS. This is intended to be Xa very small library which provides very big gains in productivity for Xprogrammers developing applications using the various widget sets based Xon the Xt Intrinsics. A large number of the total lines of code Xprovide error messages. The rest is quite straight forward. X X XThe Widget Creation Library Distribution X---------------------------------------- X XThe distribution contains files which make up the Widget Creation XLibrary, Ari (the Athena Resource Interpreter), Mri (the Motif Resource XInterpreter), and Athena and Motif demos. X X XAuthors X------- X XMartin Brunecky at Auto-trol Technology, Denver (marbru@auto-trol.UUCP) Xwrote the initial code and posted it to comp.windows.x with the title XPOOR MAN's UIL - WsXc. X XDavid Harrison of the UC Berkeley Electronics Research Lab X(davidh@ic.Berkeley.EDU or ...!ucbvax!ucbcad!davidh) wrote a very Xuseful Table widget. Kee Hinckley (nazgul@alphalpa.com) wrote a Xversion of Table which works with Motif. The Table widget, in both its Xincarnations, is so good I've included it with this distribution. It Xis separately available from archive sites. See TableHEARYE and XTableFIRST for information on this widget. X XMany people helped alot by providing bug fixes, enhancements, Xsuggestions, and just plain feedback. There are many who helped, Xincluding Andrew Peebles at MIPS, Randy Brown, Art Poley, Mike Yee of XOSF, Richard Hesketh, and our own Kaleb Keithley. X XThe rest was done by me, and here is my standard .sig: X X------------------------------------------------------------------------- XDavid Smyth david@jpl-devvax.jpl.nasa.gov XSenior Software Engineer, seismo!cit-vax!jpl-devvax!david XX and Object Guru. (818)393-0983 XJet Propulsion Lab, M/S 230-103, 4800 Oak Grove Drive, Pasadena, CA 91109 X------------------------------------------------------------------------- X X XMri and Ari Widget Resource Interpreters X---------------------------------------- X XTwo "interpreters" are provided which allow widget based user Xinterfaces to be developed and to have a few useful behaviors. These Xinterpreters are intended to be useful for prototyping. X XAri is the Athena Resource Interpreter, and it knows about all the XAthena widgets. Mri is the Motif Resource Interpreter, and is knows Xabout all the Motif widgets. Both interpreters also know about the Xvery useful Table widget, which is described in the files Table*. X XEach interpreter consists of a main() procedure, and a function which Xregisters all the known widget types. Mri consists of Mri.c and XMriRegAll.c while Ari consists of Ari.c and AriRegAll.c. The Xregistration files are intended to be independent. X XIt is a simple task to build a single interpreter which knows about Xevery widget on earth, but if you don't have shared libs, the resulting Xexecutable is HUGE. X XSeveral resource files are provided for each of the interpreters. They Xare named A<nn>_<description> and M<nn>_<description>. To try out the Xinterpreters (after you build them), do the following: X X % cd Ari X % alias se setenv XENVIRONMENT X % se A08_ClkLogo X % Ari X % cd ../Mri X % se M7_Periodic X % Mri X XThe resource files are intended to be tutorials, so they are heavily Xcommented and they explore various topics you may find interesting. X XOnce an interface is prototyped using Mri or Ari, one can take the XMri or Ari source files and makefiles and evolve them into applications. X X XSample Applications X------------------- X XThe program App is exactly one such example application. The file XAri.c was gradually modified as additional behaviors were defined, Xregistered with the Wc library, and bound to the appropriate widgets Xwithin the App01.All resource file. X XIf you look at App.c, you will notice that main() is very minimal. The Xapplication is really defined by its resource file (the look and feel) Xand the callbacks (the behavior). Notice that the callbacks use Xseveral routines provided by the Wc library. They will be introduced Xin another README file. X XAfter you build App, you can try it out as follows: X X % cd DemosAthena X % se App01.All X % App X XAnother sample application included with the distribution is MD, which Xis built as two versions: MDathena and MDmotif. The Motif version Xcurrently does not work very well due buggy interactions between Motif Xand the Intrinsics. This application demonstrates how a single Xapplication can support multiple display connections with multiple Xwidget heirarchies. These may be executed like this: X X % se MD X % MDathena X % cd ../DemosMotif X % MDmotif X !STUFFY!FUNK! echo Extracting Doc/4thREADME sed >Doc/4thREADME <<'!STUFFY!FUNK!' -e 's/X//' XWidget Creation Library Standard Callbacks X------------------------------------------ X XThe standard Wc callbacks are intended to map closely to existing Xt Xfunctions. They simply provide XtCallbackProc wrappers to many Xcommonly used Xt functions. These wrapper procs perform argument Xparsing: e.g., converting strings to widgets using WcFullNameToWidget. X XBelow is a complete list of callbacks which are registered by Wc Xwhenever you call WcWidgetCreation. The "arguments" below are Xprototypes of what one puts in a resouce file. The terms mean: X X parent name of widget, full path or wildcarded. X child name of child starting from the parent widget. X widget see parent X resLHS <widget path name> X resRHS <any legal resource value> X resType <any legal resource type, sich as Font or Pixel> X X WcCreatePopupsCB ( parent, child [, child] ... ) X WcCreateChildrenCB ( parent, child [, child] ... ) X WcManageChildrenCB ( parent, child [, child] ... ) X WcUnmanageChildrenCB ( parent, child [, child] ... ) X X WcManageCB ( widget [, widget] ... ) X WcUnmanageCB ( widget [, widget] ... ) X WcDestroyCB ( widget [, widget] ... ) X WcSetSensitiveCB ( widget [, widget] ... ) X WcSetInsensitiveCB ( widget [, widget] ... ) X X WcPopupCB ( widget ) X WcPopupGrabCB ( widget ) X WcPopdownCB ( widget ) X WcMapCB ( widget ) X WcUnmapCB ( widget ) X X WcSetValueCB ( resLHS: resRHS ) X WcSetTypeValueCB ( resLHS: resType, resRHS ) X X WcLoadResourceFileCB ( filename ) X X WcSystemCB ( shell command line ) X WcTraceCB ( annotation ) X X WcExitCB ( exitValue ) X XSee the file WcCallb.c for the implementations of all of these standard Xcallbacks. These callbacks are registered together in the function XWcRegisterWcCallbacks() which is at the bottom of the same source Xfile. Clients of Wc do not have to invoke WcRegisterWcCallbacks() Xdirectly, as it is called from WcWidgetCreation() in the WcCreate.c Xsource file. X X XWidget Naming in Callback Arguments X----------------------------------- X XIn all of these callbacks, the function WcFullNameToWidget is invoked Xto convert a string to a widget. WcFullNameToWidget allows relative Xwidget naming, relative to the widget which invoked the callback. The Xspecial characters are presented in examples below: X X this means: `the widget which invoked this callback' X ^foobar means: `a sibling widget named foobar' X ~foobar means: `a child of the shell ancestor named foobar' X ~^foobar means: `a sibling of the shell ancestor named foobar' X XThe relative naming characters `^' and `~' are parsed left to right. X XIn addition, normal wildcarding works as expected - as long as the Xfinal name component is a widget instance, and not a widget class Xname. For example: X X *foobar X *Table*XmRowColumn*foobar X X XWcCreatePopupsCB( parent, child [, child] ... ) XWcCreateChildrenCB( parent, child [, child] ... ) X------------------------------------------------- X XThese callbacks cause new widgets to be created. The name of the parent Xcan include wildcards, or can be a relative pathname from the widget Xinvoking the callback. The names of the children widgets must be Xsingle widget names, not pathnames. For example: X X *danger.callback: WcCreateChildrenCB( *Panel, EmergencyControls) X XIn this case, pressing a danger button creates a new tree of widgets Xproviding emergency controls. The new tree is rooted at the existing XPanel widget. X X XWcManageChildrenCB( parent, child [, child] ... ) X------------------------------------------------- X XThis callback manages multiple children of a single parent. It is a Xwrapper around XtManageChildren. As with WcCreateChildrenCB, the Xparent name can include wildcards, or can be a relative pathname from Xthe widget invoking the callback. The names of the children widgets Xmust be single widget names, not pathnames. For example: X X *new.activateCallback: WcManageChildrenCB( *foo, one, two, three ) X X XWcUnmanageChildrenCB( parent, child [, child] ... ) X--------------------------------------------------- X XIdentical to WcManageChildrenCB, except that the child widgets are Xunmanaged rather than managed via a call to XtUnmanageChildren. X X XWcManageCB( widget [, widget] ... ) X----------------------------------- X XThis callback takes a list of widget names, each of which Xcan be wildcarded and/or relative widget pathname. After Xthe widget ID is resolved via the WcFullNameToWidget function, Xthe widgets are managed using XtManageChild(). X X XWcUnmanageCB( widget [, widget] ... ) X------------------------------------- X XThis callback is identical to WcManageCB, except that the Xwidgets are unmanaged using XtUnmanageChild(). X X XWcDestroyCB( widget [, widget] ... ) X------------------------------------ X XThis callback allows widgets to be destroyed using XtDestroyWidget(). X X XWcSetSensitiveCB( widget [, widget] ... ) X----------------------------------------- X XThis callback invokes XtSetSensitive( TRUE ) on each of the Xwidgets named by the argument. X X XWcSetInsensitiveCB( widget [, widget] ... ) X------------------------------------------- X XThis callback is identical to WcSetSensitiveCB, but the widgets Xare made insensitive. X X XWcPopupCB( widget ) X------------------- X XThis callback invokes XtPopup() with the XtGrabKind set to XXtGrabNonexclusive. The widget must be a pop-up shell widget. X X XWcPopupGrabCB( widget ) X----------------------- X XThis callback invokes XtPopup() with the XtGrabKind set to XXtGrabExclusive. The widget must be a pop-up shell widget. X X XWcPopdownCB( widget ) X--------------------- X XThis callback invokes XtPopdown(). The widget must be a pop-up shell Xwidget. X XWcMapCB( widget ) X--------------------- X XThis callback invokes XtMapWidget(). The widget must be a shell Xwidget. X XWcUnmapCB( widget ) X--------------------- X XThis callback invokes XtUnmapWidget(). The widget must be a shell Xwidget. X X XWcSetValueCB( resLHS: resRHS ) X------------------------------ X XWcSetValueCB maps very closely to XtSetValues(). An augmented resource Xfile syntax is accepted so you can cut and paste the arguments and Xnames. The widget path name can include wildcards, and it can also be Xa relative path from the invoking widget. Real examples: X X *push.activateCallback: WcSetValueCB( *push.activateCallback: WcExitCB(1) ), \ X WcSetValueCB( *push.labelString: Goodbye! ) X X *fileMenu.wcCallback: WcSetValueCB(*file.subMenuId: this) X X *Pink.armCallback: WcSetValueCB( ^^drawing.background: Pink ) X XWcSetTypeValueCB( resLHS: resType, resRHS ) X------------------------------------------- X XDon't use this callback unless you absolutely MUST. The only time you Xneed to use this callback is when you are setting a sub-resource on a Xwidget. For example, if you want to set the font of an Athena or XMotif text widget. WcSetValueCB will just complain that the widget does Xnot have a Font resource. X XYou must specify the correct type of the resource. Make an error, and you Xwill very likely get a core dump. Just like if you use XtSetValues. X XWcLoadResourceFileCB( filename ) X-------------------------------- X XThis callback loads specified resource file into application resource Xdatabase. It allows resources to be loaded on as-needed basis, reducing the Xintitial resource file load overhead. The file to load is specified as Xclient data. The directory search for the file (should be) the same as Xfor application class resource file. X XTo prevent repeated loads of the same file, the callback keeps track of Xeach filename. Note that I do not allow a file to be re-loaded even if Xit is changed, or if a new file of the same name appears on the search Xpath. This was done for two reasons: first, it makes the code more Xportable, as I don't have to depend upon various system calls. Second, Xresources can't be un-written, so a user might get the wrong impression Xthat a resource specification can be deleted, and the resource file Xre-loaded, and something will happen. It just isn't so. X X XWcSystemCB( shell command line ) X-------------------------------- X XThis callback passes the entire string argument to you standard shell Xusing the system() C library function. Append an ampersand if you want Xthe shell to fork instead of blocking until complete. X X XWcTraceCB( annotation ) X----------------------- X XThis callback can be used to assist in interface debugging. The Xcallback prints the invoking wiget pathname and a specified message on Xstdout. X X XWcExitCB( exitValue ) X--------------------- X XThis callback converts the argument string into a base 10 integer, and Xpasses the result to exit(), which of course terminates the Xapplication. !STUFFY!FUNK! echo Extracting Doc/6thREADME sed >Doc/6thREADME <<'!STUFFY!FUNK!' -e 's/X//' XWidget Creation Functions X------------------------- X XThe widget creation Library provides several types of functions Xwhich are called by client applictions: X X 1. Registration Functions X 2. Creation Functions X 3. Callback Argument Parsing Utilities X XTwo include files are provided which declare the functions and Xsupporting data types used by the Widget Creation Library. Many Xapplications should only need to include WcCreate.h which Xcontains what can be considered "public" function declarations. X XIf you are writing additional resource converters, or sophisticated Xcallbacks, you will probably want to include WcCreateP.h which contains Xwhat can be considered "private" function declarations as well as Xtypedefs for several datatypes used by the Widget Creation Library. X XWidget Set Registration Functions X--------------------------------- X XTwo non-library functions are also provided in separate files: X XMriRegAll.c contains the single function MriRegisterMotif(). This Xfunction lets the Wc library know about all the Motif widget class Xnames (like XmPushButtonGadget), class pointers (like XxmPushButtonGadgetClass), and convenience constructors (like XXmCreatePushButtonGadget). X XAriRegAll.c contains the single function AriRegisterAthena(). This Xfunction lets the Wc library know about all the Athena widget class Xnamed (like Command), and class pointers (like commandWidgetClass). X XWcWidgetCreation() - see WcCreate.c X------------------ X XThis function takes a Widget as its only argument. A widget tree Xrooted at the widget is created from the Xrm database. This widget Xis called the root widget in this discussion, but it can really be any Xwidget. X XThe Xrm database is usually loaded as a matter of course by calling XXtInitialize(). It is possible to load the resource database directly, Xusing XrmGetFileDatabase() and XrmMergeDatabases(). See the function XWcLoadResourceFileCB in the file WcCallb.c for an example. X XThe algorithm used by WcWidgetCreation is recursive, as follows: X X 1. Fetch the wcChildren resource from Xrm database for the X initial widget. This will be a list of widget names. X X 2. For each child: X X 3. Fetch the set of Wc resources. X X 3a. If wcResFile is specified, load that resource file and X fetch the Wc resources again. X X 3b. Using the wcClass, wcClassName, or wcConstructor resource, X create the new child widget. Widget creation uses other X resources defined in the Xrm database specific to the type X of the widget, such as labelString for XmLabels. X X 3c. If wcCallback resource is defined (specifying a list of X callback functions), invoke each callback in order. X X 3d. If wcTrace is True, then dump the name of the just created X widget to stdout. X X 3e. If wcManaged is True (the default), then this widget will be X managed along with all of its siblings, after they are all X created (a single call to XtManageChildren is invoked by Wc). X X 3f. If the newly created widget has wcChildren specified, then X recursively invoke step (2.) above. Note that this X implements a depth first creation policy, which is generally X optimal for widget trees with manager widget nodes. X XNote that WcWidgetCreation() does a depth first creation, and that Xthe order of creation is controlled by the order of the names in the XwcChildren resource. X XEarlier versions of Wc required bizarre contortions when using Xconstructors in order to avoid toolkit warnings such as: X X Xt Warning: not all widgets have same parent in XtManageChildren() X XYou don't need to worry about this anymore - this behavior was Xconsidered a `bug' not a `feature' and therefore has been fixed. X X XWcCreateNamedPopups() XWcCreateNamedChildren() - see WcCreate.c X---------------------- X XThese functions create named children of a reference widget by invoking Xthe same algorithm as WcWidgetCreation, except that only the specifically Xnamed children are created, rather than all the children. X XRegistration Functions - see WcReg.c X---------------------- X XThe Widget Creation Library converts strings in the database, such as X"XmCreateFileSelectionBox", into its needed types, such as constructors, Xusing Xt converters. These converters intrinsicly know nothing: they Xmust be told what each string maps into. The converters learn about Xthe appropriate mappings via the registration functions: X X WcRegisterCallback() X WcRegisterClassPtr() X WcRegisterClassName() X WcRegisterConstructor() X WcRegisterAction() X XBy default, these registration routines ignore attempts to re-register Xa string-to-whatever mapping. This is generally useful, in that it Xhelps to catch duplicate and therefore unneeded invocations of the Xregistration routines. X XIn some clients, there exists the need to override such registrations. XFor example, interface builders built using the Widget Creation Library Xand a C interpreter or a dynamic linking environment may allow a given Xcallback name to refer to different functions as the application Xevolves. The following functions are provided to support these cases: X X WcAllowDuplicateRegistration() X WcAllowDuplicateCallbackReg() X WcAllowDuplicateClassPtrReg() X WcAllowDuplicateClassNameReg() X WcAllowDuplicateConstructorReg() X XAn interface builder will probably call WcAllowDuplicateRegistration() Xbefore any callbacks, classes, et al are registered. It may also be Xappropriate to first register all standard callbacks and widgets, and Xthen call WcAllowDuplicateRegistration(). X XWcRegisterCallback() - see WcReg.c X-------------------- X XProbably all of your useful applications will require your own Xcallbacks. These callbacks are registered with the Widget Creation XLibrary's string-to-callback converter using WcRegisterCallback(). X XIn fact, this function is used by Wc itself to register the standard Wc Xsupplied callbacks, such as WcSetValueCB and WcExitCB. See the Xfunction WcRegisterWcCallbacks() at the end of WcCallb.c to see how XWc uses this function internally. X XWcRegisterClassPtr() - see WcReg.c X-------------------- X XThis function is used to tell the Widget Creation Library about a Xwidget class pointer which can be used within XtCreateWidget(). The Xname of the widget class pointer is passed in as a string (for example, X"xmPushButtonWidgetClass"). This string value can be provided as the XwcClass resource value within a resource file. X XWcRegisterClassName() - see WcReg.c X--------------------- X XThis function is used to tell the Widget Creation Library about a Xwidget class name. The name is mapped to a widget class pointer which Xcan be used within XtCreateWidget(). The name of the widget class is Xpassed in as a string (for example, "XmPushButton"). This string value Xcan be provided as the wcClassName resource value within a resource Xfile. X XWcRegisterConstructor() - see WcReg.c X----------------------- X XThis function is used to tell the Widget Creation Library about a Xwidget constructor. The name of the constructor is passed in as a Xstring (for example, "XmCreatePushButton"). This string value can be Xprovided as the wcConstructor resource value within a resource file. X XWcRegisterAction() - see WcReg.c X----------------- X XThis is a simple wrapper around XtAppAddActions(). If you are Xregistering many actions, you probably should copy the function XWcRegisterWcActions() in WcActions.c and make the obvious Xmodifications rather than using this function. This will help Xperformance. X !STUFFY!FUNK! echo Extracting Doc/7thREADME sed >Doc/7thREADME <<'!STUFFY!FUNK!' -e 's/X//' XWriting Callback Functions X-------------------------- X XYour application will consist of two fairly independent parts: the Xresource file which describes the look and alot of the feel of the Xapplication, and the callbacks which you write in C (of course, Xyou can use languages other than C, but C is probably the easiest). X XIn order to bind the widgets created due to resource specifications Xto your callbacks implemented in C, you need to write the callbacks Xso they adhere to the standard Xt callback proc typedef, and you Xneed to register your callbacks with the Widget Creation Library's Xstring-to-callback converter. X XXtCallbackProc X-------------- X XAs defined by the XtIntrinsics, widget callback procedures must match Xthis typedef: X Xtypedef void (*XtCallbackProc)( X#if NeedFunctionPrototypes X Widget /* widget */, X XtPointer /* closure */, /* data the application registered */ X XtPointer /* call_data */ /* callback specific data */ X#endif X); X XHere is an example callback proc which does nothing with its Xarguments: X Xvoid MyExitCB ( w, ignored, unused ) X Widget w; X caddr_t ignored; X caddr_t unused; X{ X exit(); X} X XYou must register this function with the Widget Creation Library Xbefore creating any widgets which might want to bind to it. XIn general, register your callbacks after calling XtInitialize() Xand before calling WcCreateWidgets(). Here is an example of Xhow you register a callback: X X#define RCALL( name, func ) WcRegisterCallback ( app, name, func, NULL ) X X RCALL( "MyExitCB", MyExitCB ); X XAll registered callbacks can be bound to widget callback resources Xwithin the resource database. For example: X X *foo.activateCallback: MyExitCB X XMost callbacks really want to do something with the data they Xget as arguments. The closure data, often called client data, Xcan be specified as a string within the resource database. XThe string is passed as the second argument. For example: X Xvoid WcSystemCB ( w, shellCmdString, unused ) X Widget w; X char* shellCmdString; X caddr_t unused; X{ X system( shellCmdString ); X} X XNote that leading and trailing whitespace is now filtered out before Xthe callback gets it. For example, the resource specification: X X *foo.activateCallback: WcSystemCB( echo Howdy ) X Xpasses the string "echo Howdy" to the callback. The resource Xspecification: X X *foo.activateCallback: WcSystemCB( echo Howdy \ X and hello thar) X Xpasses the string "echo Howdy \t\t\t\tand hello thar" (where `\t' means Xthe tab character) to the callback. Since the callbacks usually need Xto parse these argument strings, several Widget Creation Library Xfunctions are provided in the hope of making your life easier: X Xchar* WcCleanName( char* src, char* clean ) X------------------------------------------- X XThis takes two pointers to char as arguments. The leading whitespace Xcharacters from src are skipped, and then all characters up to but Xnot including a whitespace are copied into the buffer pointed to by Xclean. Note the caller must provide storage for clean. The function Xreturns a pointer to the first whitespace following what got copied Xto clean, so this function may be used in a loop. X XWidget WcFullNameToWidget ( Widget ref, char* name ) X---------------------------------------------------- X XThis function uses the reference Widget for relative naming, and to Xdetermine the widget tree for converting full pathnames to a widget. XFor example, one may need to get the actual widget which is named by X"*Foo*bar.glorp" The ref widget is used to find the root of the widget Xtree, and start the name search from there. X XThe last component MUST be a widget instance name, it cannot be a Xwidget class name. X XAmbiguous names are resolved as done by XtNameToWidget() upon which XWcFullNameToWidget() is derived. X XVery frequently, one gets a name from an argument list using XWcCleanName() and then passes that name on to WcFullNameToWidget in Xorder to manipulate that widget. For example: X Xvoid MyPopupCB( w, name, unused ) X Widget w; X char* name; X caddr_t unused; X{ X Widget widget; X char clean[MAX_XRMNAME]; X X (void)WcCleanName ( name, cleanName ); X widget = WcFullNameToWidget ( w, cleanName ); X X if (XtIsShell(widget)) X XtPopup ( widget, XtGrabNonexclusive ); X} X XEfficiency Considerations X------------------------- X XI know parsing string arguments on every callback invocation is not so Xincredibly efficient. When Motif runs on Xt release 4, then I will Xre-write the string-to-widget converter so it caches the results, and Xthen callbacks can invoke the caching converter. X XAlso, if you are very interested in performance for a real application X(after you have fleshed out the interface using Ari or Mri), you Xshould write additional callbacks which are more intelligent, and Xdetect being called repeatedly from the same widget with the same Xargument. X XYou may want to consider using the XrmQuark functions for keeping Xtrack of strings as well. XrmQuarks are effectively indexes into Xa string symbol table kept by Xrm (part of Xlib). Doing comparisions Xand assingments using Quarks is substantially faster at run-time than Xusing character strings. XrmQuarkToString() and XrmStringToQuark() Xare used to convert between Quarks and Strings. !STUFFY!FUNK! echo Extracting Doc/8thREADME sed >Doc/8thREADME <<'!STUFFY!FUNK!' -e 's/X//' XWcSetTypeValueCB X---------------- X XSomebody was reporting that they were having problems setting fonts on Xtext widgets. I happened to want to change fonts in an application I'm Xdoing too. X XI tried using the WcSetValuesCB code which did not work, because the Xfont on an XmText widget (and XawText too) is a sub-resource. Since XI try to make Wc a safe library (:^) I had always been checking the Xappropraite resource type and then invoking the converter registered Xby the widget. The library did not need to know anything about the Xwidgets, and core dumps were nicely avoided. X XUnfortunately, there is no way to query widgets for their sub-resources, Xand therefore the Wcl library cannot know what resource type is required. XAs we all know, widgets have a habit of dumping core when an inappropriate Xtype is passed in to XtSetValue. Well, I can't do anything about it for Xthese sub resources! If you specify something incorrectly in the resource Xfile, it'll dump, exactly as when you do it in C code. X XAnyway, this is what now works using version 2.0 of Wcl: X XMri.wcChildren: msgWindow X X*msgWindow.wcClassName: XmText X*msgWindow.wcPopups: msgFontMenu X*msgWindow.fontList: -adobe-times-bold-i-normal--14-140-* X*msgWindow.value: Here is an XmText which has a popup menu X*msgWindow.translations: #augment \n\ X <Btn3Down>: MriPopupACT( *msgFontMenu ) X X*msgFontMenu.WcConstructor: XmCreatePopupMenu X*msgFontMenu.WcChildren: msgFont1, msgFont2, msgFont3 X X*msgFont1.wcConstructor: XmCreateCascadeButton X*msgFont1.labelString: courier bold oblique 10 X*msgFont1.fontList: -adobe-courier-bold-o-normal--10-100-* X*msgFont1.activateCallback: WcSetTypeValueCB( \ X *msgWindow.fontList: FontList,\ X -adobe-courier-bold-o-normal--10-100-* ) X*msgFont2.wcConstructor: XmCreateCascadeButton X*msgFont2.labelString: helvetica bold oblique 18 X*msgFont2.fontList: -adobe-helvetica-bold-o-normal--18-180-* X*msgFont2.activateCallback: WcSetTypeValueCB( \ X *msgWindow.fontList: FontList,\ X *-helvetica-bold-o-*--18-*) X*msgFont3.wcConstructor: XmCreateCascadeButton X*msgFont3.labelString: courier bold oblique 10 X*msgFont3.fontList: -adobe-courier-bold-o-normal--34-240-* X*msgFont3.activateCallback: WcSetTypeValueCB( \ X *msgWindow*fontList: FontList: \ X -adobe-courier-bold-o-normal--34-240-* ) X XNotes: It just so happens that XmText does rationally allow augmentation Xof its translations, so the translation specification: X X *msgWindow.translations: #augment \n\ X <Btn3Down>: MriPopupACT( *msgFontMenu ) X Xpredictably causes a pop-up menu to come up when Btn3 (the Menu button Xtypically) is pressed. X XNote that there is a new Wc resource defined: wcPopups. This allows Xpop-up children to be added to any widget, composite or primitive. X XNote that there is a new callback: WcSetTypeValueCB. This callback requires Xa resource type, which unfortunately must be specified as defined in the Xwidget include files. Xm.h, for example, has the following: X X #define XmRFontList "FontList" X XSo, since the XmText Output Resource Set has the following: X X XmNfontList XmCFontList XmFontList fixed CSG X Xand we know ;^) that XmFontList has this special mapping to the define XXmRFontList, we discover that the appropriate type to provide needs to Xbe FontList. Not Font, not font, not anything else. Anything else Xwill cause a core dump. Just like in your C code. Darn, I wish I Xcould be more socially responsible, but that's life, folks! X !STUFFY!FUNK! echo Extracting Doc/DocREADME sed >Doc/DocREADME <<'!STUFFY!FUNK!' -e 's/X//' XThis directory contains the documentation for the Widget Creation XLibrary. The files with .PS suffixes are postscript files which Xcontain viewgraphs for a Wcl tutorial and a paper which is close to Xbeing a reference or programmers manual. X XThe files with .doc suffixes are pure text files, and contain similar Xinformation to that presented in the tutorial and paper. X XAlso, the Table widget is documented by a .doc file. !STUFFY!FUNK! echo Extracting Imakefile sed >Imakefile <<'!STUFFY!FUNK!' -e 's/X//' X#include "Wc.tmpl" X X#define IHaveSubdirs X X#if HaveAthenaWidgetSet X ATHENA_DIRS = Xp Ari DemosAthena X#endif X X#if HaveMotifWidgetSet X MOTIF_DIRS = Xmp Mri DemosMotif X#endif X X/* X * It is absolutely essential that sub-directories with libraries X * come before subdirectories which link against the libraries! X */ X SUBDIRS = Wc $(ATHENA_DIRS) $(MOTIF_DIRS) X X/**/# "make all" builds the library and the applications without X/**/# installing anything. If you are using shared libraries, these X/**/# applications will not work anywhere else! X/**/# X#define PassTestFlags 'CDEBUGFLAGS=-I.. -L../Wc -L../Xp -L../Xmp $(CDEBUGFLAGS)' X XNamedTargetSubdirs(all,$(SUBDIRS),"making",PassTestFlags,all) X X X/**/# "make install" first builds the library, then installs the library X/**/# and includes, then builds all the applications. We must do it X/**/# like this so the applications point to the installed library X/**/# when shared libs are used. !STUFFY!FUNK! echo Extracting patchlevel.h sed >patchlevel.h <<'!STUFFY!FUNK!' -e 's/X//' X#define PATCHLEVEL 5 !STUFFY!FUNK! echo " " echo "End of kit 1 (of 35)" cat /dev/null >kit1isdone run='' config='' for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README." for combo in `find . -name '*:AA' -print`; do if test -f "$combo"; then realfile=`echo $combo | sed 's/:AA$//'` cat $realfile:[A-Z][A-Z] >$realfile rm -rf $realfile:[A-Z][A-Z] fi done rm -rf kit*isdone chmod ugo+x test* ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit -- dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.