[comp.windows.x] UIL or NOT to UIL

marbru@auto-trol.UUCP (Martin Brunecky) (03/14/90)

    A  few  weeks  ago,  comp.windows.x  carried  a  discussion  of  the
    advantages and disadvantages of UIL.  Some people suggested that UIL
    is essentially useless, that the  X  resource  database  is  enough,
    while  others  have  pointed out that there are things you cannot do
    with the database alone,  such  as  definition  of  a  widget  tree,
    callbacks, compound strings etc.

    Prompted by this discussion, I have put together some code which, in
    my  belief,  extends  the  the X Resource Database so that an ENTIRE
    USER INTERFACE can be defined (and customized) within the  database.
    This  avoidins  the  need  for  multiple  sources  of user interface
    definition by replacing UIL.  I am posting an overview of this "POOR
    MAN'S  UIL"  here  to  get  some  feedback  on.   If there is enough
    interest, I can post the code, which has been tested with Motif  and
    other widgets on SPARC, Ultrix/RISC and VMS/VAX, on comp.sources.x.


    To start, let me present a simple example of an application-class  X
    resource file for a Motif based HelloWorld:

    #
    # shell - an application shell, containing RowColumn organizer
    #
    HelloWorld.managed.child_0:             box,xmRowColumn
    #
    #  box - the main container, contains label and button
    #
    Helloworld.box.spacing:                 8
    HelloWorld.box.managed.child_0:         label,xmLabel
    HelloWorld.box.managed.child_1:         button,xmPushButton
    #
    #  label
    #
    HelloWorld.box.label.labelString:       Hello, WORLD !
    #
    #  button
    #
    HelloWorld.box.button.labelString:      Push ME
    HelloWorld.box.button.activateCallback: push(Push again to EXIT)
    #

    Except for the top-level shell creation, there is NO widget creation
    code  in  my HelloWorld.  The entire widget tree definition is shown
    above.  For any widget, I can specify any number  of  children  with
    all  their  resources, and all recursively.  Callbacks are specified
    in a similar way, by passing a string argument as call  data.   Note
    the  example  is  a  starting  point:   It  does  NOT  show  all the
    functionality such as  deffered  subtree  creation,  manage/unmanage
    callbacks, etc...


    APPLICATION CODE IMPACT

    A runtime interpreter must be able to translate X resource  database
    strings  into  widget  classes  (or  widget  creation routines), and
    callbacks.  Even though some systems (VMS for example) allow dynamic
    binding, the current implementation uses registration routines:

        WsRegisterObjectClass ( app, "xmlabel",      xmLabel           );
        WsRegisterObjectClass ( app, "xmpushbutton", xmPushButton      );
        WsRegisterConstructor ( app, "xmRowColumn",  XmCreateRowColumn );

        WsRegisterCallback    ( app, "push",  pushCB, NULL );

    In environments supporting shareable images, all toolkit classes and
    constructors may be registered during toolkit initialization.

    To initiate creation of the widget tree from the definitions  stored
    in the X resource database, an application must (either directly, or
    by means of a callback) invoke the routine:

                      WsCreateXrmChildren ( widget );


    WIDGET TREE CREATION MECHANISM

    The WsCreateXrmChildren routine scans the X  resource  database  for
    widget subresources in the following format:

    path...widget.[un]managed.child_n:    name,class[,nonrecursive]

    For each such subresource, the routine creates a child as  specified
    by   the   name   and  object  class  (or  the  creation  routine  -
    constructor).  Creation recursively descends the widget tree, unless
    stopped  by  "nonrecursive" option.  The latter may be used to defer
    sub-tree    creation,    using    a    callback    which     invokes
    WsCreateXrmChildren (for example, WsCreateXrmChildrenCB).

    When a child is created,  WsCreateXrmChildren  checks  the  resource
    database  for xrmCreateCallback resource for the child, and executes
    such callbacks if present.  This mechanism allows  the  delivery  of
    child's  widget  ID  to  other,  already existing widgets (such as a
    Motif defaultButton resource in dialog boxes).


    CALLBACK STRING CONVERSION

    A string to callback converter is provided with  the  package.   The
    converter  builds an XtCallbackList using registered callback names.
    Any callback on the list may have an optional  string  argument.   A
    pointer  to  the  string  is  used  as  callback client data.  If no
    argument  (string)  is  provided,  the  default  client  data  value
    provided  at  registration  time  is  used.   The  callback resource
    specification in the X resource database has the following format:

       path...widget.callbackName:   name[(args)][,name[(args)]]...

    where name is the callback name assigned by WsRegisterCallback,  and
    args presents an arbitrary string.


    WIDGET TREE CONTROL CALLBACKS

    The package provides basic callbacks for widget tree  control.   The
    callbacks  take  a  (list  of)  widget  names as "client data".  The
    widget name is qualified according to Xrm rules: box.label.
    The following is list of the provided callbacks:

     o  CreateXrmChildrenCB ( widgetName, widgetname ...)
        creates children of the named widgets  as  specified  in  the  X
        resource database

     o  ManageNamedChildrenCB ( widgetName, widgetName ...)
        manages a (list of) named widget(s)

     o  UnmanageNamedChildrenCB ( widgetName, widgetName, ...  )
        unmanages a (list of) named widget(s).

     o  SetWidgetResourceCB ( resourceName, widgetname, ...  )
        sets the specified resource in a (list of)  named  widget(s)  to
        the widget id of the widget invoking the callback.

    Consider the callbacks above as a starting  point.   More  callbacks
    can  be  provided  to  control  popup/popdown,  to  load  additional
    resource files and much more.


    COMPARISON WITH UIL

    The X resource database user interface definition, here (for lack of
    better  names)  referred  to  as  WsXc, performs essentialy the same
    function as UIL.  A complete comparison with UIL  can  not  be  done
    without  additional  input.   Here  I  try  only  to mention several
    important differences between UIL and WsXc.

    Implementation:
    A UIL application uses multiple user  interface  definition  sources
    (application  code,  UIL  file,  compiled UID file and an X resource
    file).  WsXc requires only application code and an X resource  file,
    and  the  application  code  would be limited to callback functions.
    The UIL approach is based on a compiler generating intermediate code
    which  is  interpreted  by Mrm at runtime.  WsXc is purely a runtime
    interpreter.

    Performance:
    Since UIL uses pre-compiled, machine specific data, the widget  tree
    creation  should  be  faster  than that for WsXc.  However, even UIL
    widget creation accesses the X resource database for  resources  NOT
    explicitly  specified  by  the  UIL  file.  Since MOST resources are
    usually NOT explictly specified, the overhead depends  more  on  the
    Xrm  database  volume,  than  on  the  widget  creation method used.
    Preliminary experience  with  WsXc  is  favorable.   However,  final
    judgement requires much more experience than is currently available.

    Extensibility.
    Adding new widgets to UIL, even with the new Motif WML facility,  is
    not an easy process.  Adding new data types (resource representation
    types) to UIL is sometimes impossible.  On the  contarry,  there  is
    nothing  special  about adding additional widgets to WsXc.  The same
    method also applies to adding new data types.  The only  requirement
    is  the  addition  of  a  convertor from string to a particular data
    type.

    Syntax Checking:
    The UIL compiler can perform rigorous  syntax  checking  for  widget
    resources,  thus  assisting in user interface development.  WsXc can
    not catch any syntax errors in resource pathname specification, such
    resources  are  simply  ignored.   However, errors in resource value
    specification can be caught by the resource converter.  In addition,
    a  simple tool that acquires a widget's resource list and performs X
    resource file syntax checking can be provided.

    Value Computations:
    The UIL compiler can compute  the  geometry  of  individual  widgets
    using  arbitrary  arithmetic  expressions.  Geometry values in the X
    resource database can not,  currently,  contain  expressions.   But,
    since  Xrm  uses  cpp, a string substitution could be applied.  This
    limitation is a resource converter issue.  A more intelligent string
    to   integer   converter   could  evaluate  arithmetic  expressions,
    including X resource database value substitution.  Besides, geometry
    configuration should be left to the geometry manager widgets and not
    hardcoded.

    Resource Conversions:
    UIL supports resource conversions  such  as  colors,  pixelmaps  and
    compound strings.  Many of the conversions are performed at runtime,
    using resource converters, the same as WsXc.   For  some  resources,
    such  as Compound Strings, UIL compile time conversion provides some
    runtime savings.  In addition, the current string to compound string
    resource converters are not intelligent enough to allow an unlimited
    compound string specification in an X resource file.
-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                   marbru@auto-trol.COM
(303) 252-2499                    {...}ncar!ico!auto-trol!marbru
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404 

nazgul@alphalpha.com (Kee Hinckley) (03/20/90)

In article <777@auto-trol.UUCP> marbru@auto-trol.COM () writes:
>    definition by replacing UIL.  I am posting an overview of this "POOR
>    MAN'S  UIL"  here  to  get  some  feedback  on.   If there is enough
>    interest, I can post the code, which has been tested with Motif  and
>    other widgets on SPARC, Ultrix/RISC and VMS/VAX, on comp.sources.x.
...

A couple concerns.

1)  The major thing which keeps me from totally dumping UIL is compound
string support.  In fact however, UIL doesn't even provide the kind of
support that I need (how do I use UIL to put up the message:
    Sorry, there is no mail from John.
Where "John" is English and everything else is Farsi?).  I think the
real solution there is a message-catalog-style UIL interface.  Presumbably
you could do something like this in the Xresources file using some kind
of character encoding for the international strings, and special escape
sequences for program input strings, but I don't know how easy it would
be, and it probably wouldn't be useful without a program to construct
them.  This isn't really specific to your UIL replacement of course, just
a general concern.

2) Consider the following (somewhat fragmented) XmForm code, how would
your solution handle it.

/*
 * The first issue here is that we have massive references to other
 * widgets.  That presumbably can be handled?
 */

    SETARG(XmNtopAttachment, XmATTACH_FORM);
    SETARG(XmNleftAttachment, XmATTACH_FORM);
    leftWidget = XmCreateLabelGadget(form, "Name:", args, i);
    XtManageChild(leftWidget);
    
    SETARG(XmNleftAttachment, XmATTACH_WIDGET);
    SETARG(XmNleftWidget, leftWidget);
    SETARG(XmNrightAttachment, XmATTACH_FORM);
    rightWidget = XmCreateForm(form, "name", args, i);
    XtManageChild(rightWidget);

/* ATTACH_OPPOSITE is a misnomer.  It actually means ALIGN_EDGES. */

    SETARG(XmNtopAttachment, XmATTACH_WIDGET);
    SETARG(XmNtopWidget, rightWidget);
    SETARG(XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET);
    SETARG(XmNrightWidget, leftWidget);
    leftWidget = XmCreateLabelGadget(form, "Address:", args, i);
    XtManageChild(leftWidget);
    
/*
 * The second issue is with convenience routines which create widgets
 * behind your back.  Note here that the widget pointer I have to use
 * to set the constraint resources is a hidden parent of ScrollText.
 *
 * By the by.  Does anyone know how this works in UIL?  I haven't tested
 * it yet. My guess is that it either doesn't work, or is hard-coded into
 * the UIL code (let's hear it for extensibility!).  There is actually
 * a way to do it without hardcoding - namely you check to see if the
 * parent of a widget is the same as the parent you gave it, if not you
 * keep moving up the widget ree until you find the parent pointer, then
 * use the one just below it.  That way works even if the implementation
 * changes, whereas the code below would probably break.
 */
    SETARG(XmNeditMode, XmMULTI_LINE_EDIT);
    rightWidget = XmCreateScrolledText(form, "address", args, i);

    SETARG(XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET);
    SETARG(XmNtopWidget, leftWidget);
    SETARG(XmNleftAttachment, XmATTACH_WIDGET);
    SETARG(XmNleftWidget, leftWidget);
    SETARG(XmNrightAttachment, XmATTACH_FORM);
    XtSetValues(XtParent(rightWidget), args, i);
    XtManageChild(rightWidget);


Incidentally.  OSF did at one point consider using an extended
Xresources form as an alternative to UIL, but was convinced (I forget
the exact reasons) that it wasn't appropriate (too hacky?).

							-kee
-- 
+-----------------------------------------------------------------------------+
| Alphalpha Software, Inc. | Voice/Fax: 617/646-7703 |   Home: 617/641-3805   |
| 148 Scituate St.         | Smart fax, dial number. |                        |
| Arlington, MA 02174      | Dumb fax, dial number,  |   BBS:  617/641-3722   |
| nazgul@alphalpha.com     | wait for ring, press 3. |   300/1200/2400 baud   |
+-----------------------------------------------------------------------------+

marbru@auto-trol.UUCP (Martin Brunecky) (03/22/90)

In article <1990Mar19.161533.13651@alphalpha.com> nazgul@alphalpha.com (Kee Hinckley) writes:
>     In article <777@auto-trol.UUCP> marbru@auto-trol.COM () writes:
>>    definition by replacing UIL.  I am posting an overview of this "POOR
>>    MAN'S  UIL"  here  to  get  some  feedback.
>
>1)  The major thing which keeps me from totally dumping UIL is compound
>string support.  In fact however, UIL doesn't even provide the kind of
>support that I need ...(text deleted)... Presumbably
>you could do something like this in the Xresources file using some kind
>of character encoding for the international strings, and special escape
>sequences for program input strings, but I don't know how easy it would
>be, and it probably wouldn't be useful without a program to construct
>them.

    It can be character encoding, but it can be a message reference
    as well, where the string in X resource is just a reference to
    a compound string stored somewhere else, and (presumably) created
    with a (native language specific) compound string editor.
    The beauty of X resource converters is that they'r simple, and can
    be overloaded. Sure, it would be great to have a unified way of
    defining compound strings in X resource files, but it has to wait
    till we decide what a compound string is. Since I don't work for
    an OpenEverything-) company, I'v got to wait rather than set-up
    s standard.
    The entire Compound String can of worm is too big to be resolved
    overnight. And UIL definition has the same problem as any other
    programming language ( and X resource database ). Unless you assume
    UIL compilers working with "native" character set, i.e. Chinese
    editor, Chinese UIL compiler, you will always need some kind of
    character encoding.
>
>2) Consider the following (somewhat fragmented) XmForm code, how would
>your solution handle it.
>
>/*
> * The first issue here is that we have massive references to other
> * widgets.  That presumbably can be handled?
> */
>    ( ... code deleted ... )
>
     There is no problem defining existing widgets as resources to
     other widgets - just a string to widget converter. Sorry I did
     not mention one.

     The problem is what to do in cases like yours, where resources
     are not known until all involved widgets are created.
     For simple cases (such as a default button), I did provide
     WsSetWidgetResourceCB callback. This callback sets a specified
     resource of a specified widget to invoking widget's ID.

     For your case I'd need a more generic one, specifying widget ID to
     to set. Easy to do. I did not think of one, since to accomplish your 
     task we have WsMatrixBox, which does all you need with 2-3 resources,
     without all that ugly code.
     ( AttachedBox is not the best solution to the problem, in fact,
      I believe it discourages people from using and writing constraint 
      widgets ).
>/*
> * The second issue is with convenience routines which create widgets
> * behind your back.  Note here that the widget pointer I have to use
> * to set the constraint resources is a hidden parent of ScrollText.

     I have a very strong opinion about "confusion routines" which
     create widgets behind your back, but I can't post it here -).

     With the X resource database, there is no problem, since the
     "hidden" widget always has a name (somehow constructed by the
     confusion routine). And since there is a name, and a known place
     in widget hierarchy, you can define any resources you wish.

>
>Incidentally.  OSF did at one point consider using an extended
>Xresources form as an alternative to UIL, but was convinced (I forget
>the exact reasons) that it wasn't appropriate (too hacky?).
>
     Wasn't the real reason some OSF member was already using UIL
     and wanted to make it a "standard" ?

-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                   marbru@auto-trol.COM
(303) 252-2499                    {...}ncar!ico!auto-trol!marbru
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404 

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (03/22/90)

    Sure, it would be great to have a unified way of
    defining compound strings in X resource files, but it has to wait
    till we decide what a compound string is.

Try the MIT X Consortium's Compound Text standard.