[December 25, 1995]

This is a snapshot of the the current state of eXene.  Its main
claim to fame is that it compiles under version 107; it is a
working version, and isn't documented.  It does have some major
improvements over Version 0.4 (released with SML/NJ 0.93), some
of which are briefly discussed below (you should also look at
the CHANGES file).


-------------------------------------------------------------------
AUTHENTICATION

EXene now has hooks for authentication, which at least work with
the xdm protocol that many X terminals use.  Look at the files
xauth-sig.sml and xauth.sml in graph-util.


-------------------------------------------------------------------
WIDGETS

The eXene widget set is undergoing major changes. Although the
new set will be largely upward compatible with the old (version 0.4)
in terms of function and use, the new set will have new widgets,
old widgets will have new features, the widgets will have a 
Motif-like 3D look, and the widgets will use X resources to allow
customization, especially of such visual aspects as color and font.

USING RESOURCES:

The use of resources allows us to make the creation of widgets
more uniform. By convention, the creation function for a widget will 
have the form

    val gadget : (Widget.root * Widget.view * Widget.arg list)
                      [ -> {optional additional arguments ] -> gadget

The root argument, as before, corresponds to a screen in X terminology.
The view argument provides a "view" of the widget as parameterized
by X resources. At present, a view is the pair 

    type view = Styles.style_view * Styles.style

The style can be viewed as a database of string values keyed by regular 
expressions, following the conventions of standard X resource files. 
Thus, a typical entry might be

    plotos*TextEntry.background:      red

The style_view corresponds to a collection of names and aliases the 
widget will use for itself when it looks up resources in the style.
If widgetB is to be a child of widgetA, a programmer will typically
make a style_view for widgetB by extending the style_view of widgetA
(using Styles.extendView and Styles.extendName) with some specific
name for widgetB. In addition, if widgetB belongs to some logical
class, names for the logical class can be added to widgetB's
style_view as aliases.

For example, suppose we have a pair widget (we don't) that takes two
child widgets and displays them next to each other.

    val pair : (Widget.root * Widget.view * Widget.arg list) ->
                  (Widget.widget * Widget.widget) -> pair

and suppose we have a style and have constructed a style_view for
the pair widget:

    val style : style
    val pairName : style_view

We want to create two text buttons that will be put into the pair widget.
We will name one button "leftButton" and the other "rightButton". In
addition, for our application, the left button will belong to a special
class of alarm buttons. We would then do the following:

    structure Styles = S
    structure Button = B

    val rightButtonName = S.extendView (pairName, "rightButton")
    val leftButtonName = 
          S.prependAlias (S.extendView (pairName, "leftButton"), "Alarm")

    val leftButton = B.widgetOf (B.textBtn (root, (leftButtonName,style), []))
    val rightButton = B.widgetOf (B.textBtn (root, (rightButtonName,style), []))
    val pair = pair (root, (pairName,style), []) (leftButton, rightButton)

Concerning the style, usually a single style is created for an application
and is passed unchanged to all the widgets. At present, a style can 
be created from a list of strings using Widget.styleFromStrings. In the
near future, we will provide functions for creating styles using
user and application default resource files, the X resource database and
command line arguments.

As noted above, the first argument used to create a widget is the triple

    (Widget.root * Widget.view * Widget.arg list)

We've discussed the first two components. The argument list allows the
programmer to have specific control over the resources of a widget. Normally,
a widget uses the style in the view to find its resources. The end user
determines the style by altering her X resource database. However,
for a given application, certain parameters of a widget might be critical
enough that the user should not be able to affect them. In these cases,
the programmer can specify these parameters using the argument list. The
attributes specified in the argument list override the style provided
in the view.

At present, an arg is a name-value pair

    type arg = Attrs.attr_name * Attrs.attr_value

Obviously, attr_name corresponds to the name of the resource and
attr_value corresponds to its value. (The Attrs structure provides
internal representation of the names and values used in styles.
In addition, it provides a collection of common attr_names.) Thus, if a
programmer insists that a button have a red background, she can use

    structure Attrs = A

    val bttn = B.textBtn (root,view,[(A.attr_background, A.AV_Str "red")])

For further information on the creation of styles and style_views,
see the styles directory.

NEW STARTUP:

To simplify the startup of an eXene application, there is a new
module RunEXene that provides a function that takes a function of
type Widget.root -> unit, looks for the shell environment variable
EXENE_DISPLAY to specify the display, starts CML, creates a root,
and then calls the function provided.

As is still the case, if EXENE_DISPLAY specifies a remote display, it
must use the numerical address:

  EXENE_DISPLAY=135.3.113.34:0.0

not

  EXENE_DISPLAY=wren:0.0

EXAMPLE:

Below is a sketch of a typical eXene application called "draw":

  structure S = Styles

  val defaults = [
          "draw*background:           gray80",
          "draw*foreground:           black",
          "draw*selectColor:          yellow",
          "draw*Button.background:    gray70",
          "draw*font:                 -Adobe-Helvetica-Bold-R-Normal--*-120-*"
        ]

  fun main root = let
        val style = Widget.styleFromStrings (root, defaults)
        val name = S.mkView {name = S.styleName ["draw"], aliases = []}
          (* make widget name hierarchy *)
          (* create widgets button up *)
        val layout = ...   (* top-level widget *)

        val shellArgs = [
                (Attrs.attr_title,Attrs.AV_Str "draw")),
                (Attrs.attr_iconName,Attrs.AV_Str "draw")
              ]
 
        val shell = Shell.shell (root,(name,style),shellArgs) layout
        in
          Shell.init shell
        end

  fun doit () = RunEXene.run main

CAVEATS:

This version of the eXene widgets represents the widgets as they are
right now. There are many bugs; many of the widgets have not been
converted to a 3D look or to use resources; there will probably be
additional changes in the design.

The use of resources is neither complete nor uniform. There will probably
be some convention by which a widget will automatically add some class
name to its style_view. Widgets that create internal subwidgets (e.g.,
scrollPorts) do not as yet provide them with new style_views.

The idea of the argument list used at widget creation is right, but its
form is not. A flat name-value list does not allow a programmer to
control the resources of specific internal widgets. The name component
of an argument needs to reflect the hierarchy. This suggests replacing
the type of name with a list of names, a list of strings or perhaps
strings following the conventions of resource databases, i.e.,
   "plotos*TextEntry.background"

There is no new documentation reflecting the new interfaces and features.
At this point, even comments are minimal. If a widget supports resources, 
these can be deduced from a list of attribute names and default values
found in the source file.

