[comp.sources.x] v06i039: WsXc - Poor man's UIL, Part01/01

marbru@Central (Martin Brunecky) (03/21/90)

Submitted-by: sunpeaks!auto-trol!marbru@Central (Martin Brunecky)
Posting-number: Volume 6, Issue 39
Archive-name: wsxc/part01

     WsXc - POOR MAN'S UIL

     This posting contains WsXc, an Xt Intrinsic  extension  alowing  to
     specify  the  entire  user  interface within X resource database. A
     HelloWorld example using Motif widgets is included.  It is provided
     on  as-is basis, without any support or waranties, to gain feedback
     about this approach of user interface definition.

     CONTENTS:

     o  README                 Basic description of WsXc facility

     This is neither a tutorial, nor a reference manual.For more details
     about individual functions, plese refer to the source - it contains
     detailed  description of each function.  I am sorry I can't provide
     man pages nor Makefile, I just don't know how.

     The following files contain the code, based on  R3  Xt  Intrinsics,
     tested  on  SPARC, Ultrix/RISC and VAX/VMS.  I assume compatibility
     with R4, even though it has not been tested.

      o  WsCreateXrm.h          defines available public functions
      o  WsCreateXrmFunc.c      widget tree creation and control
      o  WsCvtStrToCallback.c   string to callback resource convertor

     The following is a demo application, using the code  listed  above,
     and  Motif  (1.0).   You  can  modify the code to use your favorite
     widget set, and play with application resource files.

      o  HelloWorld.c          sample application
      o  HelloWorldBasic       basic X resource file, move to ~/HelloWorld
      o  HelloWorldMore        an expanded X resource file 


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README WsCreateXrm.h WsCreateXrmFunc.c
#   WsCvtStrToCallback.c HelloWorld.c HelloWorld_Basic HelloWorld_More
# Wrapped by marbru@auto-trol on Fri Mar 16 19:31:21 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(9584 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
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  avoidins  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    HelloWorld.managed.child_0:             box,xmRowColumn
X    #
X    #  box - the main container, contains label and button
X    #
X    Helloworld.box.spacing:                 8
X    HelloWorld.box.managed.child_0:         label,xmLabel
X    HelloWorld.box.managed.child_1:         button,xmPushButton
X    #
X    #  label
X    #
X    HelloWorld.box.label.labelString:       Hello, WORLD !
X    #
X    #  button
X    #
X    HelloWorld.box.button.labelString:      Push ME
X    HelloWorld.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
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        WsRegisterObjectClass ( app, "xmlabel",      xmLabel           );
X        WsRegisterObjectClass ( app, "xmpushbutton", xmPushButton      );
X        WsRegisterConstructor ( app, "xmRowColumn",  XmCreateRowColumn );
X
X        WsRegisterCallback    ( 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                      WsCreateXrmChildren ( widget );
X
X
X    WIDGET TREE CREATION MECHANISM
X
X    The WsCreateXrmChildren routine scans the X  resource  database  for
X    widget subresources in the following format:
X
X    path...widget.[un]managed.child_n:    name,class[,nonrecursive]
X
X    For each such subresource, 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, unless
X    stopped  by  a  non-composite  widget/object  or  the "nonrecursive"
X    option.  The latter may be used to defer sub-tree creation, using  a
X    callback    which    invokes   WsCreateXrmChildren   (for   example,
X    WsCreateXrmChildrenCB).
X
X    When a child is created,  WsCreateXrmChildren  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 WsRegisterCallback,  and
X    args presents an arbitrary string.
X
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:
X
X     o  CreateXrmChildrenCB ( widgetName, widgetname, ...  )
X        creates children of the named widgets  as  specified  in  the  X
X        resource database
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  SetWidgetResourceCB ( resourceName, widgetname, ...  )
X        sets the specified resource in a (list of)  named  widget(s)  to
X        the widget id of the widget invoking the callback.
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 X resource database user interface definition, here (for lack of
X    better  names)  referred  to  as  WsXc, performs essentialy the same
X    function as UIL.  A complete comparison with UIL  can  not  be  done
X    without  additional  input.   Here  I  try  only  to mention several
X    important differences between UIL and WsXc.
X
X    Implementation:
X    A UIL application uses multiple user  interface  definition  sources
X    (application  code,  UIL  file,  compiled UID file and an X resource
X    file).  WsXc 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.  WsXc 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 WsXc.  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  WsXc  is  favorable.   However,  final
X
X                                                                Page 4
X
X
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 WsXc.  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.  WsXc 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.  In addition,
X    a  simple tool that acquires a widget's resource list and performs X
X    resource file syntax checking can be provided.
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 WsXc.   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
END_OF_FILE
if test 9584 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'WsCreateXrm.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'WsCreateXrm.h'\"
else
echo shar: Extracting \"'WsCreateXrm.h'\" \(1153 characters\)
sed "s/^X//" >'WsCreateXrm.h' <<'END_OF_FILE'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Include_name:
X*
X*     WsCreateXrm.h
X*
X* Subsystem_group:
X*
X*     Window System
X*
X* Related_keywords:
X*
X*     Public Defines
X*
X* Include_description:
X*
X*     Public defines for the Window System  widget tree creation from
X*     the Xrm database.
X*
X* Include_history:
X*
X*   mm/dd/yy  initials  action
X*   --------  --------  -------------------------------------------------------
X*   03/02/90   marbru   created
X*
X*******************************************************************************
X*/
X#ifndef _WsCreateXrm_h
X#define _WsCreateXrm_h
X
X
X/* -- Widget constructor registration routine */
X
Xextern void WsRegisterObjectClass ();
Xextern void WsRegisterConstructor ();
Xextern void WsRegisterCallback    ();
Xextern void WsRegisterXrmCallbacks();
X
X/* -- Widget creation routine */
X
Xextern void WsCreateXrmChildren  ();
X
X/* -- Convenience callbacks */
X
Xextern void WsCreateXrmChildrenCB();
Xextern void WsManageNamedChildrenCB();
Xextern void WsUnmanageNamedChildrenCB();
Xextern void WsSetWidgetResourceCB();
X
X#endif  /* _WsCreateXrm_h */
END_OF_FILE
if test 1153 -ne `wc -c <'WsCreateXrm.h'`; then
    echo shar: \"'WsCreateXrm.h'\" unpacked with wrong size!
fi
# end of 'WsCreateXrm.h'
fi
if test -f 'WsCreateXrmFunc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'WsCreateXrmFunc.c'\"
else
echo shar: Extracting \"'WsCreateXrmFunc.c'\" \(22340 characters\)
sed "s/^X//" >'WsCreateXrmFunc.c' <<'END_OF_FILE'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Module_name:
X*
X*     WsCreateXrmFunc.c
X*
X* Subsystem_group:
X*
X*     Window System, Widget tree creation from Xrm database
X*
X* Related_keywords: 
X*
X*     Widget, Creation
X*
X* Module_description:
X*
X*     This module contains the functions and convenience callbacks
X*     used to create and manage a widget tree using the Xrm databse.
X*     The Xrm database format used to define widget's children is
X*     as follows:
X*
X*     toplevel...widget.managed.child_n:   name,constructor[,n[onrecursive]]
X*     toplevel...widget.unmanged.child_n:  name,constructor[,n[onrecursive]]
X*
X*     Example:
X*     helloWorld.managed.child_0:             box,XmCreateRowColumn
X*     helloWorld.box.managed.child_0:         label,XmCreateLabel
X*     helloWorld.box.managed.child_1:         button,XmCreatePushButton
X*     helloWorld.box.label.labelString:       Hello, World !
X*     helloWorld.box.button.labelString:      Bye Bye, World !
X*     helloworld.box.button.activateCallback: push(EXIT)
X*
X*     Since (for portability reasons) we can not assume runtime binding,
X*     all widget classes or creation routines (constructors) must be 
X*     "registered"  by the application BEFORE widget tree creation.
X*
X*     The widget tree creation is performed by the WsCreateXrmChildren()
X*     function, which descends the widget tree recursively until no more
X*     children are found, or widget creation is flagged as "nonrecursive",
X*     or a non-composite widget/object is found.
X*
X*     Several convenience callbacks are provided here, more will probbably
X*     follow.
X*
X* Module_interface_summary: 
X*
X*
X*     Xt Widget/Object Class Registration Routine:
X*
X*       WsRegisterObjectClass(
X*	    WsAppContext  app,	    - application context
X*	    String	  name,	    - class name, case insensitive
X*	    WidgetClass   class )   - class record pointer
X*
X*
X*     Xt Widget/Object Contructor Registration Routine:
X*
X*       WsRegisterConstructor(
X*	    WsAppContext  app,	    - application context
X*	    String	  name,	    - constructor name, case insens.
X*	    (*Widget)()   const )   - constructor function pointer
X*
X*
X*     Standard callback registration routine (all the following callbacks)
X*
X*       WsRegisterXrmCallbacks ( 
X*           WsAppContext  app )     - application context
X*
X*     Convenience Callbacks:
X*
X*       WsCreateXrmChildrenCB   ()    - creates children for named widgets
X*       WsManageNamedChildrenCB ()    - manages named widgets
X*       WsUnmanageNamedChidrenCB()    - unmanages named widgets
X*       WsSetWidgetResourceCB   ()    - sets widget resource in named widgets
X*       WsLoadResourceFileCB    ()    - loads a new database file 
X*
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*
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 <strings.h>
X#include <ctype.h>
X
X/*  -- X Window System includes */
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X
X/*  -- Auto-trol Window System includes */
X
X/*
X*******************************************************************************
X* Private_constant_declarations.
X*******************************************************************************
X*/
X#undef  NUL
X#define NUL '\0'
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#define ADD_CLASSES      16             /* increment of class cache         */
X
X#define WsNxrmCreateCallback "xrmCreateCallback"
X#define WsCXrmCreateCallback "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*/
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
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
Xstatic int         classes_num = 0;
Xstatic int         classes_max = 0;
Xstatic ClCacheRec *classes_ptr = NULL;
X
X/*
X*******************************************************************************
X* Private_function_declarations.
X*******************************************************************************
X*/
X
X
X/*
X    -- Names to Widget List
X******************************************************************************
X    This routine converts a string of comma separated widget names
X    (or widget pathes) into a list of widget id's. Blank space ignored
X    If a NULL string is provided, the widget ID of reference widget
X    is put on the list
X    The widget search starts at the TOP of widget hierarchy (using the
X    top level shell as a reference widget), thus the widget pathname
X    must include all the widget parents (excluding the shell).
X*/
Xstatic void NamesToWidgetList ( w, client, widget_list, widget_count )
XWidget	    w;			/* reference widget */
Xcaddr_t	    client;		/* callback client data - string of names */
XWidget	   *widget_list;	/* returned widget list */
XCardinal   *widget_count;	/* returned widget count */
X{
X    char	  *string = (String)client;
X    char	   name[MAX_XRMSTRING];
X    register char *s;
X    register char *d;
X
X/*  -- default case, no string provided, return the calling widget */    
X    if (!string) 
X    {
X	widget_list[0] = w;
X	*widget_count  = 1;
X	return;
X    }
X
X/*  -- find the reference widget as the toplevel shell */
X    while ( XtParent(w) ) w = XtParent(w);
X
X/*  -- parse the input string "name.name,name.name,name.name.name" */
X    *widget_count = 0;
X    for ( d = name, s = string;  ; s++ )
X    {
X	if ( *s == ',' || *s == NUL )
X	{
X	    Widget widget;
X	    if ( *s == NUL && d == name ) return;
X	    *d = NUL;
X	    widget = XtNameToWidget ( w, name );
X	    if ( widget )
X	    {
X		widget_list[*widget_count] = widget;	
X	        (*widget_count)++;
X	    }
X	    else
X                XtStringConversionWarning (name, "Widget");
X	    d = name;
X	}
X	else if ( *s > ' ' )
X	{
X	    *d++ = *s;
X	}
X	else
X	;
X    } 
X}
X/*
X    -- Call Create Callback
X*******************************************************************************
X    This function calls the CreateCallback defined for the widget in Xrm
X    resource database. 
X    Note the  xrmCreateCallback "resource" is NOT a true widget resource,
X    there are no instance data associated with it, and only exists in the
X    Xrm resource database, used ONLY at widget creation time.
X*/
Xstatic Widget CallCreateCallback ( w )
XWidget  w;		/* child's parent */
X{
X    static XtResource res[] =
X    {
X      { WsNxrmCreateCallback, WsCXrmCreateCallback, XtRCallback, 
X        sizeof(XtCallbackList), 0, XtRImmediate, (caddr_t)NULL 
X      },
X    };
X    XtCallbackList  callback = NULL;
X
X    XtGetApplicationResources ( w, &callback, res, XtNumber(res), NULL, 0 );
X
X    /* If there was any callback list defined, invoke all callbacks on list */
X    if ( callback )
X    {
X	XtCallbackRec *cb = callback;
X	for ( cb = callback; cb->callback; cb++ )
X	    (*cb->callback) ( w, cb->closure, NULL );
X	    
X    }
X}
X
X/*
X    -- Create Database Child
X*******************************************************************************
X    This function checks the resource database for a presence of widget's
X    subresource in a form:
X
X     ...widget.type.child_nn:    name.constr_name[,n[onrecursive]]
X
X    where type is either "managed" or "unmanaged".
X
X    If such a resource is present, the child is created and, if nonrecursive
X    option is NOT present, the CreateDatabseChildren is called for this
X    child causing recursive tree creation. Creation stops if child_0 or
X    two subsequent children are not defined. Creation also stops at any
X    non-composite widget/object. Thus, popup-shells etc. must be created
X    as manager children.
X
X*/
Xstatic Widget CreateDatabaseChild ( w,  nn, type )
XWidget  w;		/* child's parent */
Xint     nn;		/* child # to look for */
XString  type;		/* child type: managed or unmanaged */
X{
X    static XtResource c_resource[] =
X    {
X      { NULL, NULL, XtRString, sizeof(String), 0, XtRImmediate, (caddr_t)NULL },
X    };
X    Boolean   recursive;
X    char      res_name[20];
X    String    string;
X
X    /* update our resource list to look for  type.child_n subresource */
X    sprintf ( res_name, "child_%d", nn );
X    /* toolkit quarkifies resource lists, (flagged by negative offset) */
X    if ( ((int)c_resource[0].resource_offset) < 0 )
X    {
X        XrmQuark qname = XrmStringToQuark(res_name);
X	c_resource[0].resource_name  = (String)qname;
X	c_resource[0].resource_class = (String)qname; /* no class used */
X    }
X    else
X    {
X	c_resource[0].resource_name  = res_name;
X	c_resource[0].resource_class = res_name;  /* no class allowed / used */
X    }
X    XtGetSubresources ( w, &string, type, type, c_resource, 1, NULL, 0 );
X
X    /* Xrm query returned a string for [un]managed.child_n resource, process */
X    if ( string )
X    {
X        void      WsCreateXrmChildren();
X	XrmQuark  quark;
X	Widget   (*found_const)() = NULL;
X	WidgetClass found_class   = NULL;
X	char      name  [MAX_XRMSTRING];
X	char      constr[MAX_XRMSTRING];
X	register  char *s;
X	register  char *d;
X        register  int  i;
X
X	/*  extract widget name */
X	for ( d=name, s=string; (*s && *s!=','); )
X	     *d++ = *s++;	      
X        *d = NUL;
X
X	/* check for missing class/constructor name */
X	if ( *s != ',' )
X	{
X	    char msg [MAX_ERRMSG];
X	    sprintf ( msg, 
X               "Resource db error, missing constructor specifier for %s", name );
X	    XtWarning( msg );
X	    return (Widget)NULL;
X	}
X	s++;
X
X	/* extract class/constructor name and force lowercase, no white space */
X	for ( d=constr; (*s && *s!=','); )
X	    if (*s > ' ')
X	     *d++ = (isupper(*s)) ? tolower(*s++) : *s++;	
X	    else
X	      s++;
X        *d = NUL;
X
X	/* check for non-recursive option */
X	recursive = ( *s==',' && (s[1]=='n' || s[1]=='N') ) ? FALSE : TRUE;
X
X	
X	/* try to locate class/constructor in our caches */
X	quark = XrmStringToQuark ( constr );
X	for (i=0; i<classes_num; i++)
X	   if ( classes_ptr[i].quark == quark )
X	   {
X		found_class = classes_ptr[i].class;
X		found_const = classes_ptr[i].constructor;
X	  	break;
X	   }
X
X	/* if we'w found a class or constructor, create child, call callback */
X	if (found_class || found_const )
X        {
X	    Widget child;
X	    if ( found_class )
X	        child = XtCreateWidget ( name,  found_class, w, NULL, 0 );
X	    else
X		child = (*found_const) ( w, name, NULL, 0 );
X
X	    CallCreateCallback ( child );
X	    if ( recursive ) WsCreateXrmChildren ( child );
X	    return (child);
X	}
X	else
X	{
X	    char msg[MAX_ERRMSG];
X	    sprintf ( msg,"Cannot create child %s using %s, unknown class/constructor",
X		      name, constr );
X	    XtWarning( msg );
X	    return (Widget)NULL;
X	}
X    }
X    else
X    {
X	return (Widget)NULL;
X    }
X}
X
X/*
X*******************************************************************************
X* Public_function_declarations.
X*******************************************************************************
X*/
X/*
X    -- Register Object Class
X*******************************************************************************
X    This procedure adds object class name to our list of registered
X    classes/constructors. So far very simplistic ... without checking for 
X    duplicate entries, no cache hashing scheme....no ties to app_context.
X*/
Xvoid WsRegisterObjectClass ( app, name, class )
XXtAppContext	app;	    /* not used (yet), must be present      */
XString          name;	    /* constructor name, case insensitive   */
XWidgetClass     class;      /* Xt object class pointer              */
X{
X    char           cr_name[MAX_XRMSTRING];
X    register char *s;
X    register char *d;
X
X    for ( d=cr_name, s=name; *s; s++)
X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
X    *d = '\0';
X
X    if (classes_num >= classes_max )
X    {
X	classes_max += ADD_CLASSES;
X	classes_ptr  = (ClCacheRec*) XtRealloc((char*)classes_ptr, 
X                             sizeof(ClCacheRec) * classes_max);
X    }
X    classes_ptr[classes_num].quark       = XrmStringToQuark ( cr_name );
X    classes_ptr[classes_num].constructor = NULL;
X    classes_ptr[classes_num].class       = class;
X    classes_num++;
X}
X
X/*
X    -- Register constructor
X*******************************************************************************
X    This procedure adds constructor procedure/name to our list of registered
X    classes/constructors. So far very simplistic ... without checking for 
X    duplicate entries, no cache hashing scheme....no ties to app_context.
X
X    Note the constructor is a "standard" widget creation routine
X     Widget WsCreateXyyyZyyy ( parent, name, args, nargs )
X*/
Xvoid WsRegisterConstructor ( app, name, constructor )
XXtAppContext	app;	    /* not used (yet), must be present      */
XString          name;	    /* constructor name, case insensitive   */
XWidget (*constructor) ();   /* pointer to a widget creation routine */
X{
X    char           cr_name[MAX_XRMSTRING];
X    register char *s;
X    register char *d;
X
X    for ( d=cr_name, s=name; *s; s++)
X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
X    *d = '\0';
X
X    if (classes_num >= classes_max )
X    {
X	classes_max += ADD_CLASSES;
X	classes_ptr  = (ClCacheRec*) XtRealloc((char*)classes_ptr, 
X                             sizeof(ClCacheRec) * classes_max);
X    }
X    classes_ptr[classes_num].quark       = XrmStringToQuark ( cr_name );
X    classes_ptr[classes_num].constructor = constructor;
X    classes_ptr[classes_num].class       = NULL;
X    classes_num++;
X}
X
X/*
X    -- Create Xrm Database Children
X*******************************************************************************
X    This routine creates widget children as defined in X reosurce databse.
X    We look for children defintion starting at child 0 (first looking
X    for managed, then unmanaged child). The child lookup terminates if
X    child_0 is not present, or two two subsequent child lookups failed 
X    (allowing to continue if one child was defined incorrectly).
X    
X    To reduce the databse search overhead, we only attempt to create
X    children for composite widgets and objects.
X*/
Xvoid WsCreateXrmChildren ( w )
XWidget w;
X{
X    Widget	 child;
X    Widget	 prev;
X    Widget	 managed[MAX_CHILDREN];
X    register int i,num;
X
X/*  -- check if the requested widget is a manager ( composite ) */
X    if (! ( XtIsSubclass( w, compositeWidgetClass ) 
X         || XtIsSubclass( w, compositeObjectClass ) /* not in R3 intrinsics */
X	 ) ) return;    
X    
X
X/*  -- look for children definition until we have 2 subsequent misses */
X    child = (Widget) 1;
X    prev  = (Widget) 0;		/* this makes the child_0 mandatory */
X
X    for ( i=0, num=0; (prev || child) ;i++)
X    {
X	child   = CreateDatabaseChild ( w, i, "managed" );
X	if ( child )
X	  managed[num++] = child;
X	else
X	  child = CreateDatabaseChild ( w, i, "unmanaged" );
X 	prev = child;
X    }
X    XtManageChildren(managed, num );
X}
X
X
X/*
X    -- Create Xrm Children callback
X*******************************************************************************
X
X    For each widget specified by the list of widget names in client data,
X    (or the widget invoking this callback if client data is NULL), this
X    callback creates any children defined in the Xrm database:
X
X    ....widget.managed.child_0:   name,constr_name[,n[onrecursive]]
X    ....widget.unmanaged.child_0: name,constr_name[,n[onrecursive]]
X
X    If resource above (child_0 - child_nn) exists, the callback creates
X    (and optionally manages) a child using a constructor routine registered
X    under "constr_name".
X    The creation process recursivly follows the widget tree, unless
X    the constructor is specified with the "nonrecursive" option, or
X    a non-composite widget/object is found.
X
X    The search for "child_n" resource stops if two subsequent children
X    or child_0 are not specified, or their creation fails (error).
X
X    After all children have been created, the string of widget names
X    is changed to an empty one ("\0"), to prevent duplicate widget
X    creation.
X
X*/
Xvoid WsCreateXrmChildrenCB ( 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    int		i;
X
X
X    /* for NULL client, we get back "w", for "\0" we get zero widget count */
X    NamesToWidgetList ( w, client, widget_list, &widget_count );
X
X    for ( i=0; i<widget_count; i++)
X        WsCreateXrmChildren(widget_list[i]);
X
X    /* prevent repeated invokation by changing string to empty "\0" one */
X    if ( client )
X        *client = NUL;	
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 WsManageNamedChildrenCB ( 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    NamesToWidgetList ( 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 WsUnmanageNamedChildrenCB ( 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    NamesToWidgetList ( w, client, widget_list, &widget_count );
X    XtUnmanageChildren  ( widget_list, widget_count );
X}
X
X
X/*
X    -- Set Widget Resource Callback
X*******************************************************************************
X    This callback loads invoking widget into the prescribed resource of the
X    named widget(s).
X    Typically, this callback is used to set the "XmNdefaultButton" resource,
X    and is invoked from button creation callback.
X
X    The client data argument has a format:
X        
X	resource_name,target_widget_name[,target_widget_name...]
X*/
Xvoid WsSetWidgetResourceCB ( w,  client, call )
XWidget w;
Xcaddr_t client;		/* client data, resource name, list of named children */
Xcaddr_t call;		/* call data,   not used */
X{
X    Widget*	   widget_list[MAX_CHILDREN];
X    Cardinal	   widget_count;
X    char	   resource[MAX_XRMSTRING];
X    register char *d,*s;
X    register int   i;
X    Arg            args[1];
X
X    for ( d=resource, s=client; (*s && *s!=','); s++ )
X        if (*s > ' ') *d++ = *s;
X    *d = NUL;
X
X    if (*s == ',' ) s++;
X    if (*s == NUL )
X    {
X	XtWarning("No widget names for WsSetWidgetresourceCB");
X	return;
X    }
X    NamesToWidgetList ( w, s, widget_list, &widget_count );
X
X    /* set the resource to set */
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
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 WsLoadResourceFileCB ( 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
X/*
X  -- WsRegisterXrmCallbacks
X*******************************************************************************
X*/
Xvoid WsRegisterXrmCallbacks ( app )
XXtAppContext app;
X{
X#define REG( name, cb, cl ) WsRegisterCallback ( app, name, cb, cl )
X
X    REG("CreateXrmChildrenCB",      WsCreateXrmChildrenCB,	NULL );
X    REG("ManageNamedChildrenCB",    WsManageNamedChildrenCB,	NULL );
X    REG("UnmanageNamedChildrenCB",  WsUnmanageNamedChildrenCB,	NULL );
X    REG("SetWidgetResourceCB",      WsSetWidgetResourceCB,	NULL );
X
X#undef REG
X}
END_OF_FILE
if test 22340 -ne `wc -c <'WsCreateXrmFunc.c'`; then
    echo shar: \"'WsCreateXrmFunc.c'\" unpacked with wrong size!
fi
# end of 'WsCreateXrmFunc.c'
fi
if test -f 'WsCvtStrToCallback.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'WsCvtStrToCallback.c'\"
else
echo shar: Extracting \"'WsCvtStrToCallback.c'\" \(10320 characters\)
sed "s/^X//" >'WsCvtStrToCallback.c' <<'END_OF_FILE'
X/*
X*******************************************************************************
X*
X* SCCS_data: %Z%%M% %I%(%G%)
X*
X* Module_name:
X*
X*     WsCvtStrToCallback
X*
X* Subsystem_group:
X*
X*     Window System, Widget Set, Converters
X*
X* Related_keywords: 
X*
X*     Converter
X*
X* Module_description:
X*
X*     This module contains the String To Callback X resource converter.
X*
X*     The converter parses the resource string in the format:
X*
X*       ...path:   name[(args)][,name[(args)]]...
X*
X*     where:  name:   specifies the registered callback function name
X*             args:   specifies the string passed to a callback as
X*		      "client data".
X*
X*     Multiple callbacks can be specified for a single callback list
X*     resource.  Any callbacks must be "registered" by the application
X*     prior converter invocation (.i.e.prior widget creation).
X*     If no "args" string is provided, the default "client data" 
X*     specified at callback registration are used.
X*
X* Module_interface_summary: 
X*
X*
X*     Resource converter is invoked indirectly by the toolkit. The
X*     converter is added to the toolkit by widgets calling
X*     WsAddStrToCallbackP() in the widget intialization code.
X*
X*     To register application callbacks, use:
X*
X*     WsRegisterCallback ( 
X*	    WsAppContext    app,	- application context
X*	    String	    name,	- register name, case insensitive
X*	    Callback	    callback,	- callback function pointer
X*	    ClientData      closure )	- default client data
X*
X* Module_history:
X*                                                  
X*   mm/dd/yy  initials  function  action
X*   --------  --------  --------  ---------------------------------------------
X*   02/26/90  MarBru    All       Created
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 <strings.h>
X#include <ctype.h>
X
X/*  -- X Window System includes */
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h> 
X
X/*  -- Auto-trol Window System includes */
X
X/*
X*******************************************************************************
X* Private_constant_declarations.
X*******************************************************************************
X*/
X#undef  NUL
X#define NUL '\0'
X
X/*
X*******************************************************************************
X* Private_type_declarations.
X*******************************************************************************
X*/
X#define MAX_XRMSTRING  1024		/* max length of the DB string	    */
X#define MAX_CALLBACKS    64		/* max number of callbacks per list */
X#define ADD_CALLBACKS	 16             /* increment of callback cache size */
X
X/*
X*******************************************************************************
X* Private_macro_definitions.
X*******************************************************************************
X*/
X
X/*
X*******************************************************************************
X* Private_data_definitions.
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
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
Xstatic int       callbacks_num = 0;
Xstatic int       callbacks_max = 0;
Xstatic CBCacheRec *callbacks_ptr = NULL;
X
X
X/*
X*******************************************************************************
X* Private_function_declarations.
X*******************************************************************************
X*/
X
X/*
X    -- Convert String To Callback
X*******************************************************************************
X    This conversion creates a callback list structure from the X resource
X    database string in format:
X
X    name(arg),name(arg).....
X
X    Note "name" is not case sensitive, while "arg" may be - it is passed to
X    a callback as client data as a null terminated string (first level
X    parenthesis stripped off).
X*/
Xvoid CvtStringToCallback (args, num_args, fromVal, toVal)
X
XXrmValue *args;
XCardinal *num_args;
XXrmValue *fromVal;
XXrmValue *toVal;
X{
X    typedef struct 
X    {
X	char *nsta,*nend;		/* callback name start, end */
X	char *asta,*aend;		/* argument string start, end */
X    } Segment;
X
X    static XtCallbackRec *cb;
X    XtCallbackRec	  callback_list[MAX_CALLBACKS];
X    int                   callback_num = 0;
X    String                string = (char *) fromVal->addr;
X    Segment               segs[MAX_CALLBACKS];	
X    Segment              *seg;
X    register char        *s;
X    register int          i,ipar;
X
X/*  -- assume error or undefined input argument */
X    toVal->size = 0;
X    toVal->addr = (caddr_t) NULL;
X    if (s == NULL) return;
X
X/*  -- parse input string finding segments   "name(arg)" comma separated */
X    ipar = 0;
X    seg  = segs;
X    seg->nsta = string;
X    seg->nend = seg->asta = seg->aend = (char*)NULL;
X
X    for ( s=string;  *s;  s++ )
X    {
X	switch (*s)
X	{
X	case ',':  if ( ipar > 0 ) break;  /* commas in arguments ignored  */
X		   if ( seg->nend == NULL ) seg->nend = s-1;  /* no argument */
X	           seg++;		   /* start the next segment */
X	           seg->nsta = (s[1]) ? s+1 : (char*)NULL;
X    		   seg->nend = seg->asta = seg->aend = (char*)NULL;
X		   break;		   
X
X	case '(':  if ( ipar++ == 0 ) { seg->nend = s-1; seg->asta = s+1; };
X	           break;
X		   
X	case ')':  if ( --ipar == 0 ) { seg->aend = s-1; };
X		   break;
X	deafult:   ;
X	}
X    }
X    seg++;		   /* start the terminating segment */
X    seg->nsta = (char*)NULL;
X
X    if (ipar)
X    {
X	XtStringConversionWarning (string, "Callback, unbalanced parenthesis");
X	return;
X    }
X
X
X/*  -- process individual callback string segments "name(arg)" */
X    for( seg = segs;  seg->nsta;   seg++)
X    {
X        char           	  cb_name[MAX_XRMSTRING];
X	XtCallbackProc 	  found = (XtCallbackProc)NULL;
X	XrmQuark       	  quark;
X	register char    *d;
X	register char    *end;
X
X	/* our callback cache names are case insensitive, no white space */
X	for ( s=seg->nsta, d=cb_name; s<=seg->nend; )
X	   if ( *s > ' ')
X             *d++ = (isupper(*s) ) ? tolower (*s++) : *s++;
X	   else
X	      s++;
X	*d   = NUL;
X
X        /* try to locate callback in our cache of callbacks */
X        quark = XrmStringToQuark (cb_name);
X	for (i=0; i<callbacks_num; i++)
X	    if ( callbacks_ptr[i].quark == quark )
X	    {
X	        register XtCallbackRec *rec = &callback_list[callback_num];
X		rec->callback = found = callbacks_ptr[i].callback;
X	        rec->closure  = callbacks_ptr[i].closure;
X		break;
X	    }
X
X	/* we have found a registered callback, process arguments */
X	if (found)
X	{
X	   register char *arg;
X	   register int   alen;
X	   register XtCallbackRec *rec = &callback_list[callback_num];
X	   
X	   if ( seg->asta )
X	   {
X	       alen = (int)seg->aend - (int)seg->asta +1;
X	       arg  = XtMalloc(alen+1);
X	       strncpy ( arg, seg->asta, alen );
X	       arg[alen+1]  = NUL;
X	       rec->closure = (caddr_t)arg;
X	   }
X	   callback_num++;
X        }
X	else
X	{
X           XtStringConversionWarning (cb_name, "Callback, unknown callback name");
X	}
X    } /* end for seg loop */
X
X/*  -- terminate the callback list */
X    {
X	register XtCallbackRec *rec = &callback_list[callback_num];
X        rec->callback = NULL;
X	rec->closure  = NULL;
X	callback_num++;
X    }
X
X/*  -- make a permanent copy of the new callback list, and return a pointer */
X    cb = (XtCallbackRec*)XtMalloc( callback_num * sizeof (XtCallbackRec) );
X    memcpy ( (char*)cb, (char*)callback_list,  
X              callback_num * sizeof (XtCallbackRec));
X    toVal->size = sizeof (XtCallbackRec*);
X    toVal->addr = (caddr_t)&cb;
X}
X
X/*
X*******************************************************************************
X* Public_function_declarations.
X*******************************************************************************
X*/
X
X/*
X    -- Add String To Callback Convertor
X*******************************************************************************
X*/
X
Xvoid WsAddStringToCallbackP ()
X{
X    static Boolean added = FALSE;
X    if ( !added )
X    {
X       XtAddConverter    (XtRString, 
X                          XtRCallback,
X                          CvtStringToCallback,
X                          (XtConvertArgList)NULL,
X                          (Cardinal)0);
X       added = TRUE;
X    }
X}
X
X
X/*
X    -- Register callback
X*******************************************************************************
X    This procedure adds callback procedure/name to our list of registered
X    callbacks. So far very simplistic ... without checking for duplicate
X    entries, no cache hashing scheme, no ties to app_context.
X*/
Xvoid WsRegisterCallback ( app, name, callback, closure )
XXtAppContext	app;	    /* not used (yet), must be present      */
XString          name;       /* callback name, case insensitive      */
XXtCallbackProc  callback;   /* callback function pointer            */
Xcaddr_t         closure;    /* default closure (client data)        */
X{
X    char           cb_name[MAX_XRMSTRING];
X    register char *s;
X    register char *d;
X
X    for ( d=cb_name, s=name; *s; s++)
X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
X    *d = '\0';
X
X    if (callbacks_num >= callbacks_max )
X    {
X	callbacks_max += ADD_CALLBACKS;
X	callbacks_ptr  = (CBCacheRec*) XtRealloc((char*)callbacks_ptr, 
X	                  sizeof(CBCacheRec) * callbacks_max);
X    }
X    callbacks_ptr[callbacks_num].quark    = XrmStringToQuark ( cb_name );
X    callbacks_ptr[callbacks_num].callback = callback;
X    callbacks_ptr[callbacks_num].closure  = closure;
X    callbacks_num++;
X}
END_OF_FILE
if test 10320 -ne `wc -c <'WsCvtStrToCallback.c'`; then
    echo shar: \"'WsCvtStrToCallback.c'\" unpacked with wrong size!
fi
# end of 'WsCvtStrToCallback.c'
fi
if test -f 'HelloWorld.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'HelloWorld.c'\"
else
echo shar: Extracting \"'HelloWorld.c'\" \(3743 characters\)
sed "s/^X//" >'HelloWorld.c' <<'END_OF_FILE'
X/*
X*******************************************************************************
X*   HelloWorld.c 
X*******************************************************************************
X    This program demonstrates usage of the Xrm (X resource management) databse
X    for a widget tree definition and management.
X    There is very little code in this example, since the entire user interface
X    definition is stored in the Xrm database, preferably in the application
X    class resource file:  ~/HelloWorld
X
X    ATTC NOTE: This example does NOT use Ws, since it's intended for use
X	       outside Auto-trol.
X/*
X*******************************************************************************
X*   Include_files.
X*******************************************************************************
X*/
X
X#include <Xm/Xm.h>		/* Motif public header file	*/
X#include <Xm/Label.h>		/* Motif label widget		*/
X#include <Xm/PushB.h>		/* Motif pushbutton widget	*/
X#include <Xm/BulletinB.h>	/* Motif bulletin board widget	*/
X#include <Xm/RowColumn.h>	/* Motif row column widget	*/
X#include "WsCreateXrm.h"	/* Window System Xrm Creation routines */
X
X/*
X*******************************************************************************
X*   Application callback declaration (callbacks should be in a separate file)
X*******************************************************************************
X*/
Xvoid pushCB();
X
X/* 
X*******************************************************************************
X*   MAIN function
X*******************************************************************************
X*/
X
Xmain ( argc, argv )
Xint    argc;
Xchar **argv;
X{   
X    Widget       app_shellW;		  /* application shell widget       */
X    XtAppContext app;
X
X/*  -- Intialize AWS creating the application shell */
X    app_shellW = XtInitialize ( "helloWorld","HelloWorld",
X				 NULL, 0, &argc, argv );
X    app        = XtWidgetToApplicationContext(app_shellW);
X
X/*  -- Register the string to callback converter, used for a pushbutton */
X    WsAddStringToCallbackP();
X
X/*  -- Register available Widget constructors */
X    WsRegisterConstructor ( app, "xmLabel",	    XmCreateLabel     );
X    WsRegisterConstructor ( app, "xmPushButton",    XmCreatePushButton);
X    WsRegisterConstructor ( app, "xmRowColumn",	    XmCreateRowColumn );
X    WsRegisterObjectClass ( app, "xmBulletinBoard", xmBulletinBoardWidgetClass);
X
X/*  -- Register available callbacks */
X    WsRegisterXrmCallbacks( app );
X    WsRegisterCallback    ( app, "push",  pushCB, NULL );
X
X
X/*  -- Create children of the toplevel shell defined by the Xrm database */
X    WsCreateXrmChildren   ( app_shellW );
X
X/*  -- Realize the widget tree and enter the main application loop */
X    XtRealizeWidget  ( app_shellW );
X    XtMainLoop       ( );
X}
X/*
X*******************************************************************************
X    Application callbacks (should be in a separate file)
X*******************************************************************************
X*/
X/*
X    -- Push callback
X*******************************************************************************
X    This callback is a state machine; the first invocation loads the text
X    specified as client data into XmNlabelString resource of invoking widget;
X    the next invocation exits the application.
X*/
Xvoid   pushCB ( w, client, call )
XWidget	    w;
Xcaddr_t	    client;
Xcaddr_t	    call;
X{
X    static Boolean first = TRUE;
X    
X    if ( first )
X    {
X        static Arg setargs[] = { XmNlabelString, NULL };
X	String  text = ( client ) ? (String) client : "No text in Xrdb" ;
X
X        setargs[0].value = (XtArgVal)XmStringCreateLtoR(text,XmSTRING_DEFAULT_CHARSET);
X	WsSetResources ( w, setargs, 1);
X	first = FALSE;
X    }
X    else
X    {
X	exit();
X    }    
X}
END_OF_FILE
if test 3743 -ne `wc -c <'HelloWorld.c'`; then
    echo shar: \"'HelloWorld.c'\" unpacked with wrong size!
fi
# end of 'HelloWorld.c'
fi
if test -f 'HelloWorld_Basic' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'HelloWorld_Basic'\"
else
echo shar: Extracting \"'HelloWorld_Basic'\" \(851 characters\)
sed "s/^X//" >'HelloWorld_Basic' <<'END_OF_FILE'
X#  HelloWorld - global resources
X#
X*fontList: 			-*-Helvetica-Medium-R-Normal--14*
X#  
X#  shell
X#
XHelloWorld.managed.child_0:  		box,xmRowColumn
X#
X#  box - the main container
X#
XHelloWorld.box.spacing:			2	
XHelloWorld.box.background:   		red
XHelloWorld.box.marginWidth:		4
XHelloWorld.box.marginHeight:		4	
XHelloWorld.box.entryAlignment:		alignment_center
XHelloWorld.box.managed.child_0:  	label,xmlabel 
XHelloWorld.box.managed.child_1:         button,xmpushbutton
X#
X#  label
X#
XHelloWorld.box.label.background:	white
XHelloWorld.box.label.foreground:	blue
XHelloWorld.box.label.labelString:	Hello, WORLD !
X#
X#  button
X#
XHelloWorld.box.button.background:	lightBlue
XHelloWorld.box.button.foreground:	white
XHelloWorld.box.button.location:         center
XHelloWorld.box.button.labelString:	Push ME
XHelloWorld.box.button.activateCallback: push(Push to EXIT)
X#
END_OF_FILE
if test 851 -ne `wc -c <'HelloWorld_Basic'`; then
    echo shar: \"'HelloWorld_Basic'\" unpacked with wrong size!
fi
# end of 'HelloWorld_Basic'
fi
if test -f 'HelloWorld_More' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'HelloWorld_More'\"
else
echo shar: Extracting \"'HelloWorld_More'\" \(2171 characters\)
sed "s/^X//" >'HelloWorld_More' <<'END_OF_FILE'
X#
X#  HelloWorld 
X#    box		main container
X#       lbl1		headline label - hello world
X#       box1		bulletin board for default button testing
X#          btn1		default button
X#       btn2            button controlling lbl2
X#       btn3            button controlling lbl2
X#       lbl2            footnote
X#
X#  global resources
X#
X*fontList:			        -*-Helvetica-Medium-R-Normal--14*
X#
X#  shell 
X#
XHelloworld.input:			true
XHelloWorld.managed.child_0:  		box,xmRowColumn
X#
X#  box - the main container
X#
XHelloWorld.box.layout:   		column
XHelloWorld.box.spacing:			8
XHelloWorld.box.background:   		red
XHelloWorld.box.marginWidth:		0
XHelloWorld.box.marginHeight:		0
XHelloWorld.box.entryAlignment:		alignment_center
XHelloWorld.box.managed.child_0:  	lbl1,xmLabel 
XHelloWorld.box.managed.child_1:         box1,xmBulletinBoard
XHelloWorld.box.managed.child_2:         btn2,xmPushButton
XHelloWorld.box.managed.child_3:         btn3,xmPushButton
XHelloWorld.box.managed.child_4:  	lbl2,xmLabel 
X#
X#  lbl1
X#
XHelloWorld.box.lbl1.background:		white
XHelloWorld.box.lbl1.foreground:		blue
XHelloWorld.box.lbl1.labelString:	Hello, WORLD !
X#
X#  box1
X#
XHelloWorld.box.box1.marginWidth:	8
XHelloWorld.box.box1.marginHeight:	8
XHelloWorld.box.box1.managed.child_0:    btn1,xmPushButton
X#
X#  btn1
X#
XHelloWorld.box.box1.btn1.labelString:	Push ME
XHelloWorld.box.box1.btn1.background:	lightBlue
XHelloWorld.box.box1.btn1.foreground:	red
XHelloWorld.box.box1.btn1.showAsDefault: 2
XHelloWorld.box.box1.btn1.xrmCreateCallback: SetWidgetResourceCB(defaultButton,box.box1)
XHelloWorld.box.box1.btn1.activateCallback:  push(Push to EXIT !)
X#
X#  btn2
X#
XHelloWorld.box.btn2.background:		lightBlue
XHelloWorld.box.btn2.foreground:		blue
XHelloWorld.box.btn2.labelString:	Remove Footnote
XHelloWorld.box.btn2.activateCallback: 	UnmanageNamedChildrenCB(box.lbl2)
X#
X#  btn3
X#
XHelloWorld.box.btn3.background:		lightBlue
XHelloWorld.box.btn3.foreground:		blue
XHelloWorld.box.btn3.labelString:	Add Footnote
XHelloWorld.box.btn3.activateCallback: 	ManageNamedChildrenCB(box.lbl2)
X#
X#  lbl2
X#
XHelloWorld.box.lbl2.background:		white
XHelloWorld.box.lbl2.foreground:		blue
XHelloWorld.box.lbl2.labelString:	Ain't it WONDERFULL ?
X#
END_OF_FILE
if test 2171 -ne `wc -c <'HelloWorld_More'`; then
    echo shar: \"'HelloWorld_More'\" unpacked with wrong size!
fi
# end of 'HelloWorld_More'
fi
echo shar: End of shell archive.
exit 0

dan
-----------------------------------------------------------
		    O'Reilly && Associates
		argv@sun.com / argv@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.