v06i067: Motif Resource Interpreter, Part01/03
David E. Smyth
david at jpl-devvax.jpl.nasa.gov
Thu Apr 12 17:42:56 AEST 1990
Submitted-by: david at jpl-devvax.jpl.nasa.gov (David E. Smyth)
Posting-number: Volume 6, Issue 67
Archive-name: mri/part01
These files make up the Motif Resource Interpreter, called Mri for
short. It is an evolution of the WsXc package posted to comp.windows.x
by Martin Brunecky about the 21 March, 1990. Martin did the hard
part, I just repackaged, tuned, and polished a few things. Several of
us here at JPL find Mri to be useful, I hope you do also.
david at jpl-devvax.jpl.nasa.gov (David E. Smyth)
# to unbundle, "sh" this file -- DO NOT use csh
# SHAR archive format. Archive created Wed Apr 11 09:58:12 PDT 1990
echo x - README
sed 's/^X//' > README <<'+FUNKY+STUFF+'
XThese files make up the Motif Resource Interpreter, called Mri for
Xshort. It is an evolution of the WsXc package posted to comp.windows.x
Xby Martin Brunecky about the 21 March, 1990. Martin did the hard
Xpart, I just repackaged, tuned, and polished a few things. Several of
Xus here at JPL find Mri to be useful, I hope you do also.
X
XIf you have any comments, code you want to donate such as String to
Xwhatever converters, or generally useful callbacks, bug reports or
Xsucess reports, ... please contact me using any of the addressing
Xschemes mentioned in my .sig:
X
X----------------------------------------------------------
XDavid Smyth david at jpl-devvax.jpl.nasa.gov
XSenior Software Engineer, seismo!cit-vax!jpl-devvax!david
XX and Object Guru. (818)354-6344
XJPL, M/S 301-260, 4800 Oak Grove Drive, Pasadena, CA 91109
X----------------------------------------------------------
X
XMri consists of a main() along with several useful routines including
Xgeneral purpose callbacks and resource type converters.
X
XThe intention of Mri is that an application writer can initially
Xdevelop the user interface of an application using the generic App
Xprogram generated by the Makefile and an application specific resource
Xfile. The supplied resource files R_1, R_2, and R_3 show simple
Xexamples of what can be done with resources and virtually no C code,
Xonly those callbacks defined in Application.c.
X
XAs the application evolves, the application writer need only to write C
Xcode which implement callbacks and a routine which registers these
Xcallbacks. The file Application.c is an example of such a file. The
Xapplication writer links the callbacks and registration routine with
Xthe Mri library libMri.a, and the standard Motif and X libraries (See
Xthe Makefile for an example).
X
XOne useful development concept which has evolved over the last couple
Xof weeks of fooling around with Mri is this: since the developer
Xinitially concentrates on the user interface, the application
Xnatuarally evolves as a direct manipulation system: widgets map
Xdirectly to the objects which the application is being developed to
Xmanipulate.
X
XThis suggests that adding a core.extension field to widgets (there
Xalready is a core_class.extension field in WidgetClassRec). These
Xcore.extension pointers in the widgets could then be used as pointers
Xto application objects.
X
XThe development group of which I am a part has been doing object
Xoriented programming in C for some time now, and this just seems to be
Xa useful scheme to closely link the Widget object concept and our
Xapplication objects.
X
XAfter you have unshared the distribution, you should only have to type
Xthe following commands (assuming the Motif libraries are named libXm.a
Xand libXtm.a):
X
X % make
X % setenv XENVIRONMENT R_1
X % App -D
X
X % setenv XENVIRONMENT R_2
X % App
X
X % setenv XENVIRONMENT R_3
X % App -D
X
XYou will notice the effect of the -D flag: it causes the names of each
Xwidget to be dumped as it is created. This is very helpful when you
Xare trying to figure out the names of children created by the Motif
X"Confusion" routines, like XmPulldownMenu or XmScrolledWindow. This
Xwidget name dump can also be enabled via the "debugging" application
Xresource:
X
X *debugging: True
X
XNote the dynamicChild_nn resources in the R_3 resource file, and that
Xthe activation callbacks of the "First Channel Set" and "stdout"
Xbuttons dynamically create widgets in the scrolled window on the
Xright. The callbacks on both the dynamically created widgets destroys
Xthem.
X
XHere is the README as posted by Martin with very minor edits:
X
X UIL or NOT to UIL ?
X
X A few weeks ago, comp.windows.x carried a discussion of the
X advantages and disadvantages of UIL. Some people suggested that UIL
X is essentially useless, that the X resource database is enough,
X while others have pointed out that there are things you cannot do
X with the database alone, such as definition of a widget tree,
X callbacks, compound strings etc.
X
X Prompted by this discussion, I have put together some code which, in
X my belief, extends the the X Resource Database so that an ENTIRE
X USER INTERFACE can be defined (and customized) within the database.
X This avoids the need for multiple sources of user interface
X definition by replacing UIL. I am posting an overview of this "POOR
X MAN'S UIL" here to get some feedback.
X
X To start, let me present a simple example of an application-class X
X resource file for a Motif based HelloWorld:
X
X #
X # shell - an application shell, containing RowColumn organizer
X #
X App.managedChild_0: box,xmRowColumn
X #
X # box - the main container, contains label and button
X #
X App.box.spacing: 8
X App.box.managedChild_0: label,xmLabel
X App.box.managedChild_1: button,xmPushButton
X #
X # label
X #
X App.box.label.labelString: Hello, WORLD !
X #
X # button
X #
X App.box.button.labelString: Push ME
X App.box.button.activateCallback: push(Push again to EXIT)
X #
X
X Except for the top-level shell creation, there is NO widget creation
X code in my HelloWorld. The entire widget tree definition is shown
X above. For any widget, I can specify any number of children with
X all their resources, and all recursively. Callbacks are specified
X in a similar way, by passing a string argument as call data. Note
X the example is a starting point: It does NOT show all the
X functionality such as deffered subtree creation, manage/unmanage
X callbacks, etc...
X
X APPLICATION CODE IMPACT
X
X A runtime interpreter must be able to translate X resource database
X strings into widget classes (or widget creation routines), and
X callbacks. Even though some systems (VMS for example) allow dynamic
X binding, the current implementation uses registration routines:
X
X MriRegisterObjectClass ( app, "xmLabel", xmLabelWidgetClass);
X MriRegisterObjectClass ( app, "xmPushButton", xmPushButtonWidgetClass);
X MriRegisterConstructor ( app, "xmRowColumn", XmCreateRowColumn );
X
X MriRegisterCallback ( app, "push", pushCB, NULL );
X
X In environments supporting shareable images, all toolkit classes and
X constructors may be registered during toolkit initialization.
X
X To initiate creation of the widget tree from the definitions stored
X in the X resource database, an application must (either directly, or
X by means of a callback) invoke the routine:
X
X MriCreateXrmChildren ( widget );
X
X
X WIDGET TREE CREATION MECHANISM
X
X The initial (static) widget tree is created when the main routine in
X libMri calls the MriCreateXrmChildren routine. MriCreateXrmChildren
X scans the X resource database for the following widget resources:
X
X path...widget.managedChild_n: name,class
X path...widget.unmanagedChild_n: name,class
X
X For each such resource, the routine creates a child as specified
X by the name and object class (or the creation routine -
X constructor). Creation recursively descends the widget tree, until
X stopped by a non-composite widget or gadget, or no more managedChild
X or unmanagedChild resources are found.
X
X Additional widgets can be created dynamically from the X resource
X database by invoking the MriCreateDynamicWidgetCB callback routine.
X This routine takes as an argument the names of the widgets which are
X to be created. The X resource database is then searched for the
X following widget resources:
X
X path...widget.dynamicChild_n: name, class
X path...widget.unmDynamicChild_n: name, class
X
X to be created. The X resource database is then searched for the
X The names passed as arguments to MriCreateDynamicWidgetCB are each
X broken apart into the parent name and the child name. The parent
X name is used to find the widget whose resources should include
X such dynamicChild and unmDynamicChild resources, with the child name
X used to determine which of the dynamic children are to be created.
X For each child created, MriCreateXrmChildren is invoked, causing a
X recursive creation of widgets, again stopping when a non-composite
X widget or gadget is encountered, or when no more managedChild
X and unmanagedChild resources are found.
X
X When a child is created, MriCreateXrmChildren checks the resource
X database for xrmCreateCallback resource for the child, and executes
X such callbacks if present. This mechanism allows the delivery of
X child's widget ID to other, already existing widgets (such as a
X Motif defaultButton resource in dialog boxes).
X
X
X CALLBACK STRING CONVERSION
X
X A string to callback converter is provided with the package. The
X converter builds an XtCallbackList using registered callback names.
X Any callback on the list may have an optional string argument. A
X pointer to the string is used as callback client data. If no
X argument (string) is provided, the default client data value
X provided at registration time is used. The callback resource
X specification in the X resource database has the following format:
X
X path...widget.callbackName: name[(args)][,name[(args)]]...
X
X where name is the callback name assigned by MriRegisterCallback, and
X args presents an arbitrary string.
X
X WIDGET TREE CONTROL CALLBACKS
X
X The package provides basic callbacks for widget tree control. The
X callbacks take a (list of) widget names as "client data". The
X widget name is qualified according to Xrm rules: box.label. The
X following is list of the provided callbacks, the names and arguments
X are shown as they should appear in a resource file:
X
X o CreateDynamicWidgetCB ( widgetName, widgetName, ... )
X creates dynamic widgets from the Xrm database. The (list of)
X named widget(s) is used as a starting point: frequently,
X dynamically created widgets have children, and these are
X recursively created.
X
X o ManageNamedChildrenCB ( widgetName, widgetName, ... )
X manages a (list of) named widget(s)
X
X o UnmanageNamedChildrenCB ( widgetName, widgetName, ... )
X unmanages a (list of) named widget(s).
X
X o SetResourceOnWidgetCB ( resourceName, resourceValue, widgetname, ... )
X sets the specified resource in a (list of) named widget(s) to
X the resource value. The value is converted from a String using
X registered resource type converters (for example, the value may
X may be a callback, and is bound by the String to Callback
X converter supplied with Mri).
X
X o QuitApplicationCB ()
X Quits the application, no confirmation is asked for.
X
X Consider the callbacks above as a starting point. More callbacks
X can be provided to control popup/popdown, to load additional
X resource files and much more.
X
X
X COMPARISON WITH UIL
X
X The Motif Resource Interpreter routines, called Mri for short,
X performs essentialy the same function as UIL. A complete comparison
X with UIL can not be done without additional input. Here I try
X only to mention several important differences between UIL and Mri.
X
X Implementation:
X can be provided to control popup/popdown, to load additional
X A UIL application uses multiple user interface definition sources
X (application code, UIL file, compiled UID file and an X resource
X file). Mri requires only application code and an X resource file,
X and the application code would be limited to callback functions.
X The UIL approach is based on a compiler generating intermediate code
X which is interpreted by Mrm at runtime. Mri is purely a runtime
X interpreter.
X
X Performance:
X Since UIL uses pre-compiled, machine specific data, the widget tree
X creation could be faster than that for Mri. However, even UIL
X widget creation accesses the X resource database for resources NOT
X explicitly specified by the UIL file. Since MOST resources are
X usually NOT explictly specified, the overhead depends more on the
X Xrm database volume, than on the widget creation method used.
X Preliminary experience with Mri is favorable. However, final
X judgement requires much more experience than is currently available.
X
X Extensibility.
X Adding new widgets to UIL, even with the new Motif WML facility, is
X not an easy process. Adding new data types (resource representation
X types) to UIL is sometimes impossible. On the contarry, there is
X nothing special about adding additional widgets to Mri. The same
X method also applies to adding new data types. The only requirement
X is the addition of a convertor from string to a particular data
X type.
X
X Syntax Checking:
X The UIL compiler can perform rigorous syntax checking for widget
X resources, thus assisting in user interface development. Mri can
X not catch any syntax errors in resource pathname specification, such
X resources are simply ignored. However, errors in resource value
X specification can be caught by the resource converter. A "debugging"
X resource is defined, which causes Mri to dump the names and classes
X of each widget created, which makes writing a correct resource file
X significantly easier. In addition, a simple tool that acquires a
X widget's resource list and performs X resource file syntax checking
X will very likely be provided in the next few weeks.
X
X Value Computations:
X The UIL compiler can compute the geometry of individual widgets
X using arbitrary arithmetic expressions. Geometry values in the X
X resource database can not, currently, contain expressions. But,
X since Xrm uses cpp, a string substitution could be applied. This
X limitation is a resource converter issue. A more intelligent string
X to integer converter could evaluate arithmetic expressions,
X including X resource database value substitution. Besides, geometry
X configuration should be left to the geometry manager widgets and not
X hardcoded.
X
X Resource Conversions:
X UIL supports resource conversions such as colors, pixelmaps and
X compound strings. Many of the conversions are performed at runtime,
X using resource converters, the same as Mri. For some resources,
X such as Compound Strings, UIL compile time conversion provides some
X runtime savings. In addition, the current string to compound string
X resource converters are not intelligent enough to allow an unlimited
X compound string specification in an X resource file.
X
+FUNKY+STUFF+
echo '-rw-r--r-- 1 david 14949 Apr 11 09:43 README (as sent)'
chmod u=rw,g=r,o=r README
ls -l README
echo x - Makefile
sed 's/^X//' > Makefile <<'+FUNKY+STUFF+'
X#
X# Makefile for building libMri.a and an application which uses
X# the Motif Resource Interpreter.
X#
X# This makefile works on Suns, and expects the Motif and X libraries
X# to exist in stadard directories (like /usr/lib) with the following
X# names:
X# Motif Widget Library: libXm.a
X# Motif Intrinsics: libXtm.a
X# X11 Xlib Library: libX11.a
X#
X# This makefile expects that the Motif include files are within
X# /usr/include/Xm and /usr/include/Xm/X11.
X#
X CC = cc
XCFLAGS = -g -I/usr/include/Xm -L.
X LOBJS = MriCallbacks.o MriCreate.o MriCvts.o MriDynCreate.o MriMain.o \
X MriMisc.o MriReg.o
X LIBS = -lMri -lXm -lXtm -lX11
X AOBJS = Application.o
X
XApp: $(AOBJS) libMri.a
X $(CC) $(CFLAGS) $(AOBJS) $(LIBS) -o App
X
XlibMri.a: $(LOBJS) Mri.h MriP.h
X rm -f libMri.a
X ar rc libMri.a $(LOBJS)
X ranlib libMri.a
X
Xclean:
X rm -f $(LOBJS) $(AOBJS)
X
Xclobber:
X rm -f $(OBJS) $(AOBJS) App
+FUNKY+STUFF+
echo '-rw-r--r-- 1 david 873 Apr 11 07:36 Makefile (as sent)'
chmod u=rw,g=r,o=r Makefile
ls -l Makefile
echo x - Mri.h
sed 's/^X//' > Mri.h <<'+FUNKY+STUFF+'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Include_name:
X*
X* Mri.h
X*
X* Subsystem_group:
X*
X* Motif Resource Interpreter
X*
X* Related_keywords:
X*
X* Public Defines
X*
X* Include_description:
X*
X* Public defines for the Motif Resource Interpreter which supports
X* widget tree creation and callback binding from the Xrm database.
X*
X* Include_history:
X*
X* mm/dd/yy initials action
X* -------- -------- -------------------------------------------------------
X* 03/02/90 marbru created
X* 04/03/90 d.smyth added MriSetValueFromString() and globals.
X* 04/05/90 d.smyth renamed to Mri
X*
X*******************************************************************************
X*/
X#ifndef _Mri_h
X#define _Mri_h
X
X/*
X -- These MUST be defined by the application
X*******************************************************************************
X*/
X
Xextern char appName[];
Xextern char appClass[];
Xextern XrmOptionDescRec appOptions[];
Xextern Cardinal numOptions;
X
Xextern void UserInitialization();
X/* int *argc; in/out, reflect returned size of argv
X * char *argv[]; in/out, should remove any consumed args
X */
X
Xextern void RegisterApplicationCallbacks();
X/* int *argc;
X * char *argv[];
X * XtAppContext app;
X */
X
X/*
X*******************************************************************************
X*/
X
X#define MAX_XRMSTRING 1024 /* max length of the Xrm DB string */
X#define MAX_ERRMSG 1024 /* max length of error message */
X#define MAX_CHILDREN 1024 /* max number of widget's children */
X
X/* -- Resource Converter Registration Routines
X*******************************************************************************
X*/
X
Xextern void MriAddStringToWidgetP();
Xextern void MriAddStringToCallbackP();
X
X/* -- Widget class, constructor, and callback registration routines
X*******************************************************************************
X*/
X
Xextern void MriRegisterObjectClass ();
X/* XtAppContext app; not used (yet), must be present
X * char* name; class name, case insensitive
X * WidgetClass class; Xt WidgetClassStruct pointer
X */
X
Xextern void MriRegisterConstructor ();
X/* XtAppContext app; not used (yet), must be present
X * char* name; constructor name, case insensitive
X * Widget (*constructor) (); pointer to a widget creation routine
X */
X
Xextern void MriRegisterCallback ();
X/* XtAppContext app; not used (yet), must be present
X * char* name; callback name, case insensitive
X * XtCallbackProc callback; pointer to callback function
X * caddr_t closure; default closure (client data)
X */
X
Xextern void MriRegisterMriCallbacks();
X/* XtAppContext app; not used (yet), must be present
X */
X
X/* -- Widget creation routine
X*******************************************************************************
X Creates widgets declared in the Xrm database.
X*/
X
Xextern void MriCreateXrmChildren ();
X/* Widget w; create children of this widget
X */
X
X/* -- Convenience callbacks:
X*******************************************************************************
X In all cases, drop the initial "Mri" to reference any of these
X callbacks in a resource file. For example, the following resource
X file line would cause MriCreateDynamicWidgetCB() to be invoked
X creating a new dynamic child of "main" called "foo" due to a
X button press on the XmButton widget named "button"
X
X *button.activateCallback: MriCreateDynamicWidgetCB( main.foo )
X*/
X
Xextern void MriCreateDynamicWidgetCB();
X/* Widget w; widget issuing callback
X * caddr_t client; list of named children
X * caddr_t call; not used
X */
X
Xextern void MriManageNamedChildrenCB();
X/* Widget w; widget issuing callback
X * caddr_t client; list of named children
X * caddr_t call; not used
X */
X
Xextern void MriUnmanageNamedChildrenCB();
X/* Widget w; widget issuing callback
X * caddr_t client; list of named children
X * caddr_t call; not used
X */
X
Xextern void MriSetResourceOnWidgetCB();
X/* Widget w; widget issuing callback
X * caddr_t client; res_name, res_val, target [,target] ...
X * caddr_t call; not used
X */
X
Xextern void MriQuitApplicationCB();
X/* Widget w; widget issuing callback (not used)
X * caddr_t client; exit value
X * caddr_t call; not used
X */
X
Xextern void MriLoadResourceFileCB();
X/* Widget w; widget issuing callback
X * caddr_t client; X resource filename
X * caddr_t call; not used
X */
X
X/* -- Convenience functions:
X*******************************************************************************
X*/
X
Xextern void MriNamesToWidgetList();
X/* Widget reference; name search starts at root of this widget
X * char* list_of_names; comma separated full path names
X * Widget widget_list[]; returned widget list, caller's storage
X * int* widget_count; returned count of widgets, caller's storage
X */
X
Xextern void MriSetValueFromString();
X/* Widget target; set value on this widget
X * char* resource_name; resource to be set
X * char* resource_value; value converted from string to whatever
X */
X
Xextern void MriDumpFullNameOfWidget();
X/* Widget w; dump full path name of this widget to stderr
X */
X
X/* -- Mri control globals */
X
Xextern Widget app_shellW; /* application shell widget */
Xextern XtAppContext app;
Xextern Boolean debugging;
X
X#endif /* _Mri_h */
+FUNKY+STUFF+
echo '-rw-r--r-- 1 david 5610 Apr 11 09:30 Mri.h (as sent)'
chmod u=rw,g=r,o=r Mri.h
ls -l Mri.h
echo x - MriP.h
sed 's/^X//' > MriP.h <<'+FUNKY+STUFF+'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Include_name:
X*
X* MriP.h
X*
X* Subsystem_group:
X*
X* Motif Resource Interpreter
X*
X* Related_keywords:
X*
X* Private Defines
X*
X* Include_description:
X*
X* Private defines for the Motif Resource Interpreter which supports
X* widget tree creation and callback binding from the Xrm database.
X*
X* Include_history:
X*
X* mm/dd/yy initials action
X* -------- -------- -------------------------------------------------------
X* 04/09/90 d.smyth extracted from Mri.c, named MriP.h
X*
X*******************************************************************************
X*/
X
X#ifndef _MrPi_h
X#define _MriP_h
X
X/*
X*******************************************************************************
X* Private_constant_declarations.
X*******************************************************************************
X*/
X
X#undef NUL
X#define NUL '\0'
X
X#define ADD_CLASSES 16 /* increment of class cache */
X#define MAX_CALLBACKS 64 /* max number of callbacks per list */
X#define ADD_CALLBACKS 16 /* increment of callback cache size */
X
X#define MriNxrmCreateCallback "xrmCreateCallback"
X#define MriCXrmCreateCallback "XrmCreateCallback"
X
X/*
X*******************************************************************************
X* Private_type_declarations.
X*******************************************************************************
X Class/constructor cache record contains both class and constructor,
X one of which must be NULL.
X*/
X
Xtypedef struct /* Class cache record */
X{
X XrmQuark quark; /* quarkified callback name */
X Widget (*constructor)(); /* constructor function ptr */
X WidgetClass class; /* widget class pointer */
X} ClCacheRec;
X
Xtypedef struct
X{
X XrmQuark quark; /* quarkified callback name */
X XtCallbackProc callback; /* callback procedure pointer */
X caddr_t closure; /* default client data */
X} CBCacheRec;
X
X/*
X*******************************************************************************
X* Private_macro_definitions.
X*******************************************************************************
X*/
X
X/*
X*******************************************************************************
X* Private_data_definitions.
X*******************************************************************************
X The following cache/registry of known widget classes and contructors,
X initially empty, are loaded by the application using "registration"
X routines.
X Assuming small numbers of constructors, the sequential search
X of such cache is (initially) considered acceptable.
X*/
X
X/* -- Named object classes cache, intially empty */
X
Xextern int classes_num;
Xextern int classes_max;
Xextern ClCacheRec *classes_ptr;
X
X/*
X The following cache/registry of known callbacks, initially empty,
X is loaded by the application using "registration" routines.
X Assuming small numbers of callbacks, the sequential search
X of such cache is (initially) considered acceptable.
X*/
X
X/* -- Named callback procedures cache, intially empty */
X
Xextern int callbacks_num;
Xextern int callbacks_max;
Xextern CBCacheRec *callbacks_ptr;
X
X/*
X*******************************************************************************
X* Private_function_declarations.
X*******************************************************************************
X*/
X
Xextern Widget CallCreateCallback();
X/* Widget w; invokes this widget's creation callbacks
X */
X
Xextern Boolean GetChildNameAndConstructor();
X/* Widget w; child's parent
X * char* type; "managed", "unmanaged", "dynamic", or "unmDynamic"
X * int nn; child number to look for ex: managedChild_2
X * char* name; returned child name - caller alloc's storage
X * char* constr; returned constructor name - caller alloc's storage
X * Boolean *recur; returned recursive flag - caller's storage
X */
X
Xextern Boolean FindClassOrConstrFromCache();
X/* char* constr; name of widget constructor
X * struct Found *found; class or constr
X */
X
Xextern Widget CreateChildUsingCache();
X/* Widget parent;
X * char* child_name;
X * char* constructor;
X * Boolean recursive;
X */
X
Xextern Widget CreateDatabaseChild();
X/* Widget w; child's parent
X * char* type; "managed", "unmanaged", "dynamic", or "unmDynamic"
X * int nn; child number to look for ex: managedChild_2
X */
X
Xextern void CreateDynamicChild();
X/* Widget w; child's parent
X * char* name; child's name
X */
X
X#endif _MrPi_h
+FUNKY+STUFF+
echo '-rw-r--r-- 1 david 4688 Apr 10 10:37 MriP.h (as sent)'
chmod u=rw,g=r,o=r MriP.h
ls -l MriP.h
echo x - MriCallbacks.c
sed 's/^X//' > MriCallbacks.c <<'+FUNKY+STUFF+'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Module_name:
X*
X* MriCallbacks.c
X*
X* Subsystem_group:
X*
X* Motif Resource Interpreter, Utility Callback Routines
X*
X* Related_keywords:
X*
X* Widget, Callback
X*
X* Module_description:
X*
X* This module contains convenience callbacks which seem generally
X* useful.
X*
X* Since (for portability reasons) we can not assume runtime binding,
X* all widget callback routines must be "registered" by the application
X* BEFORE widget tree creation. The standard callbacks, defined
X* in this file, get registered by the main() routine in MriMain.c
X* when it invokes MriRegisterStandardCallbacks().
X*
X* Several convenience callbacks are provided here, more will probably
X* follow.
X*
X* Module_interface_summary:
X*
X* Convenience Callbacks:
X*
X* MriCreateDynamicWidgetCB () - creates named dynamic widget
X* MriManageNamedChildrenCB () - manages named widgets
X* MriUnmanageNamedChidrenCB() - unmanages named widgets
X* MriSetResourceOnWidgetCB () - sets resource in named widgets
X* MriQuitApplicationCB () - calls exit()
X* MriLoadResourceFileCB () - loads a new database file
X* (currently unimplemented)
X*
X* Module_history:
X*
X* mm/dd/yy initials function action
X* -------- -------- -------- ---------------------------------------------
X* 02/26/90 MarBru All Created
X* 02/16/90 MarBru Create.. Limited creation to composite widgets/objects
X* 04/05/90 d.smyth Dynamic Creation, rename to Mri
X*
X* Design_notes:
X
X* For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic
X* (runtime) binding. But since most UNIX systems lack such capability,
X* we stick to the concept of "registration" routines.
X*
X*******************************************************************************
X*/
X/*
X*******************************************************************************
X* Include_files.
X*******************************************************************************
X*/
X
X/* -- Operating system includes */
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X
X/* -- X Window System includes */
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X#include <X11/CoreP.h>
X#include <XmP.h>
X
X/* -- Motif Resource Interpreter Includes */
X#include "Mri.h"
X#include "MriP.h"
X
X/*
X -- Create Dynamic Widgets callback
X*******************************************************************************
X
X Creates the named widgets dynamically. The widget names, which
X is obtained as a string in client data, must be a comma separated
X list of full widget path names (well, full path except for the
X ApplicationShell widget).
X
X The widgets which may be dynamically created are specified in the
X resource file like this:
X
X App.foo.bar.managedDynChild_0: glorp, XmRowColumn
X App.foo.bar.unmanagedDynChild_0: dweep, XmLabel
X
X The first specifies a child which will be managed after creation,
X the second widget child will not be managed. Neither is created
X initially, but only if specifically named in a call to this callback.
X
X For example, lets say a button's activate callback is specified to
X cause a "glorp" to be created as a child of foo.bar according to the
X above resource spec:
X
X App.nerf.button.activateCallback: CreateDynamicWidgetCB(foo.bar.glorp)
X
X Multiple dynamic widgets can be created in one invocation, for example:
X
X App.nerf.button.activateCallback: CreateDynamicWidgetCB(foo.bar.glorp, \
X foo.bar.dweep)
X
X ( The backslash at the end of the line is recognized by the resource
X manager and stripped out, allowing arbitrarily long resource specs.)
X Note that the created widgets can be, and usually are, children of
X widgets other than the widget which is invoking the callback: children
X must be parented by manager widgets, and callbacks are usually invoked
X from buttons (subclassed from Primitive, not Manager).
X
X*/
Xvoid MriCreateDynamicWidgetCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data, list of named children */
Xcaddr_t call; /* call data, not used */
X{
X typedef struct _pair {
X char *parent;
X char *child;
X struct _pair *next;
X } PairStruct, *Pair;
X
X Pair pair, first_pair;
X
X char *first, *last, *comma, *p, *ch, *c;
X
X pair = first_pair = NULL;
X
X first = client;
X
X while ( *first )
X {
X if ( *first <= ' ' || *first == ',' )
X {
X first++ ; continue; /* skip leading whitespace */
X }
X
X comma = index( first, ',' ); /* find the next comma */
X if (comma == NULL)
X comma = index( first, '\0' ); /* no comma, so find end */
X
X last = comma - 1;
X while (first < last && *last != '.')
X last--;
X
X /* now first points to first char of parent's name, and
X ** last points to last '.' which terminates parent's.
X ** comma still points to the next comma or the end.
X */
X
X {
X Pair new_pair = (Pair)XtMalloc(sizeof(PairStruct));
X if (pair == NULL)
X first_pair = new_pair; /* never made one before */
X else
X pair->next = new_pair; /* else add to linked list */
X pair = new_pair;
X }
X
X pair->parent = p = (char*)XtMalloc( (last - first) + 1 );
X pair->child = ch = (char*)XtMalloc( (comma - last) + 1 );
X pair->next = NULL;
X
X c = first;
X while (c < last) /* don't copy final `.' */
X *p++ = *c++;
X *p = NUL; /* null terminate parent name */
X
X c++; /* skip the `.' */
X while (c < comma && *c > ' ') /* stop before comma or whitespace */
X *ch++ = *c++;
X *ch = NUL; /* null terminate child name */
X
X first = comma;
X }
X if (first_pair == NULL)
X {
X XtWarning("No widget names passed to CreateDynamicWidgetCB()");
X return;
X }
X
X /* Create Children */
X pair = first_pair;
X while(pair)
X {
X Widget widget_list[MAX_CHILDREN];
X int widget_count;
X
X MriNamesToWidgetList ( w, pair->parent, widget_list, &widget_count );
X if (widget_count == 1)
X {
X CreateDynamicChild( widget_list[0], pair->child );
X pair = pair->next;
X }
X else
X {
X /* XtWarning("CreateDynamicWidgetCB arguments are garbled"); */
X break;
X }
X }
X
X /* Free allocated temporary storage */
X pair = first_pair;
X while(pair)
X {
X XtFree(pair->parent);
X XtFree(pair->child);
X XtFree(pair);
X pair = pair->next;
X }
X return;
X}
X
X/*
X -- Manage named children callback
X*******************************************************************************
X This callback translates string passed in as client data into a widget id
X and manages it. A comma separated list of children can be specified.
X NULL string pointer defaults widget invoking the callback
X*/
Xvoid MriManageNamedChildrenCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data, list of named children */
Xcaddr_t call; /* call data, not used */
X{
X Widget* widget_list[MAX_CHILDREN];
X Cardinal widget_count;
X
X MriNamesToWidgetList ( w, client, widget_list, &widget_count );
X XtManageChildren ( widget_list, widget_count );
X}
X
X
X/*
X -- Unmanage named children callback
X*******************************************************************************
X This callback translates string passed in as client data into a widget id
X and manages it. A comma separated list of children can be specified.
X NULL string pointer defaults widget invoking the callback
X*/
Xvoid MriUnmanageNamedChildrenCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data, list of named children */
Xcaddr_t call; /* call data, not used */
X{
X Widget* widget_list[MAX_CHILDREN];
X Cardinal widget_count;
X
X MriNamesToWidgetList ( w, client, widget_list, &widget_count );
X XtUnmanageChildren ( widget_list, widget_count );
X}
X
X/*
X -- Set Resource on Widget(s) Resource Callback
X*******************************************************************************
X This callback loads resource values into resources on the named widget(s).
X
X The client data argument has a format:
X
X resource_name,resource value,target_widget_name[,target_widget_name...]
X
X The special resource value of "this" means "this widget." Typically,
X using "this" as the resource value is used to set the "XmNdefaultButton"
X resource on a XmbulletinBoard, "menuBar", "workArea", etc on XmMainWindows,
X the subMenuId resource on menuBar cascade buttons, and so on.
X*/
Xvoid MriSetResourceOnWidgetCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data: res_name, res_val, target [,target] ...
Xcaddr_t call; /* call data, not used */
X{
X char resource[MAX_XRMSTRING];
X char res_val[MAX_XRMSTRING];
X Widget* widget_list[MAX_CHILDREN];
X Cardinal widget_count;
X register char *d,*s;
X register int i;
X Arg args[1];
X static char* msg =
X"Usage: SetResourceOnWidgetCB( res_name, res_value, widget [,widget ... ] )";
X
X /* copy from client into resource[]
X ** ignore all whitespace, warning if no resource name.
X */
X s = client;
X if (*s == ',' || *s == NUL)
X {
X XtWarning(msg); return;
X }
X for ( d=resource ; (*s && *s!=',') ; s++ )
X if (*s > ' ') *d++ = *s;
X *d = NUL;
X
X /* copy from client into res_val[]
X ** skip leading whitespace, warning if no resource value.
X */
X if (*s++ == NUL)
X {
X XtWarning(msg); return;
X }
X while (*s && *s == ' ')
X s++;
X if (*s == ',' || *s == NUL)
X {
X XtWarning(msg); return;
X }
X for ( d=res_val ; (*s && *s!=',') ; s++ )
X *d++ = *s;
X *d = NUL;
X
X /* now get widgets from the rest of the client[] string */
X if (*s == ',' ) s++;
X if (*s == NUL )
X {
X XtWarning(msg); return;
X }
X MriNamesToWidgetList ( w, s, widget_list, &widget_count );
X
X /* set the resource on the widgets */
X
X if (0 == strcmp(res_val,"this"))
X {
X args[0].name = resource;
X args[0].value = (XtArgVal)w;
X
X for (i=0; i<widget_count; i++)
X XtSetValues ( widget_list[i], args, 1 );
X }
X else
X {
X for (i=0; i<widget_count; i++)
X {
X /* convert to appropriate value and call XtSetValue() */
X MriSetValueFromString( widget_list[i], resource, res_val );
X }
X }
X}
X
X/*
X -- Quit the application
X*******************************************************************************
X Call exit().
X*/
Xvoid MriQuitApplicationCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data, not used */
Xcaddr_t call; /* call data, not used */
X{
X int exitval = 0;
X if (client)
X {
X /* skip leading garbage before int */
X while (*client)
X {
X if ('0' < *client && *client <= '9')
X break; /* found numbers, convert to exitval */
X client++;
X }
X
X /* convert to int */
X while (*client)
X {
X if ('0' < *client && *client <= '9')
X {
X exitval = exitval * 10 + (*client - '0');
X client++;
X }
X else
X break; /* ignore trailing garbage */
X }
X }
X exit(exitval);
X}
X
X/*
X -- Load Resource File
X*******************************************************************************
X This callbacks loads the specified resource file into application
X resource database. It allows to load the resources on as-needed
X basis, reducing the intitial resource load overhead.
X
X Two locations are searched for a specified file:
X
X XAPP_DEFAULT_PATH
X XUSER_DEFAULT_PATH (or env.variable "XAPPLRESLANGPATH")
X
X Not implemented -- too toolkit dependent ( R3/Motif/R4 ).
X*/
Xvoid MriLoadResourceFileCB ( w, client, call )
XWidget w;
Xcaddr_t client; /* client data, X resources file name */
Xcaddr_t call; /* call data, not used */
X{
X printf("Sorry, deffered resource load not implemented, file %s\n",call);
X printf("Merge your file into application class file\n");
X}
X
+FUNKY+STUFF+
echo '-rw-r--r-- 1 david 11869 Apr 11 09:40 MriCallbacks.c (as sent)'
chmod u=rw,g=r,o=r MriCallbacks.c
ls -l MriCallbacks.c
exit 0
dan
-----------------------------------------------------------
O'Reilly && Associates
argv at sun.com / argv at ora.com
632 Petaluma Ave, Sebastopol, CA 95472
800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list