[comp.windows.x] WINTERP Questions

parker@zaphod.mpr.ca (Ross Parker) (12/16/89)

I've just finished building winterp (version 1.0), and it
looks pretty neat...

I'm *not* a lisp hacker (nor an emacs user.... no flames!),
and have a couple of questions. The documentation that came
with winterp is a little skimpy (as can be expected - I'm
not complaining). I got the idea from the doc that it is
possible to write out C code, but I couldn't figure out
how to do it. Is it easy? If so, can it be explained in
a paragraph or so?

If winterp will allow me to build applications the way I
think it will, I'm willing to become a lisp hacker in order
to use it!

Thanks,

Ross Parker				parker@mpre.mpr.ca
(604)293-5495				uunet!ubc-cs!mpre!parker

mayer%hplnpm@HPLABS.HP.COM (Niels P. Mayer) (12/20/89)

Newsflash! WINTERP now has documentation! 
see expo.lcs.mit.edu:contrib/winterp.tar.Z for details....

In article <1971@eric.mpr.ca> parker@zaphod.mpr.ca (Ross Parker) writes:
>I've just finished building winterp (version 1.0), and it
>looks pretty neat...

Thanks! Please send me any enhancements you make.

>and have a couple of questions. The documentation that came
>with winterp is a little skimpy (as can be expected - I'm
>not complaining).

I just updated the file on expo with approx 200kbytes of plaintext
documentation.  Hope this will make you happy. The documentation is no
substitute for the standard Motif documentation, the Xtoolkit
documentation, or Doug Young's upcoming Motif Book. The documentation
should serve as a good supplement to the official Motif documetation and
should help you in translating example code from C to WINTERP-Lisp syntax.

> I got the idea from the doc that it is
>possible to write out C code, but I couldn't figure out
>how to do it. Is it easy? If so, can it be explained in
>a paragraph or so?

The documentation explains some of the philosophy behind writing hybrid
Lisp/C programs. XLISP makes it very easy to merge in new C-implemented
primitives and methods into an application. JonnyG did a good job of
explaining in one paragraph what needs to be done, and which things you
should look at. 

Writing Lisp callable C code in WINTERP is easy once you get the hang of
it. All of the WINTERP source code should serve as an example of how to
implement methods and primitives in C. As JonnyG said, the toughest part is
remembering to protect newly created objects from getting garbage
collected. Also take a look at ./winterp/src-server/w_funtab.{c,h} to see
how to add new methods and functions to XLISP's functiontable.

I was going to write up a document on how to add new primitives to XLISP
and WINTERP, but I didn't find the time. Send me mail if you're interested
and I'll mail you something if I ever get around to documenting that aspect
of WINTERP.

> Are winterp lisp functions only capable of calling other
> winterp lisp functions, or can I build a library of 'C'
> callbacks that are called by winterp lisp functions?

Winterp lisp functions can call other lisp-implemented functions, or they
can call C-implemented functions. Similarly, methods for particular object
classes can be implemented in C or in Lisp. 

You can then call these C-implemented lisp primitives via callbacks
(XtAddCallback()), event handlers (XtAdd{Raw}Eventhandler()), and timeouts
(XtAddTimeout()) . I've even provided a special ActionProc "Lisp()" which
will allow you to call the lisp evaluator through translation and
accelerator tables (it's lotsa fun)...

				-- Niels Mayer
				   Hewlett-Packard Laboratories
				   Human-Computer Interaction Department.

PS: If anybody sends e-mail questions about WINTERP, be forewarned that I
will not be able to answer e-mail until after the first week of January --
I will be on vacation, and I'm leaving tonight.

mayer%hplnpm@HPLABS.HP.COM (Niels P. Mayer) (12/20/89)

Since there seems to be growing interest in WINTERP, and since I'm not
going to be around for the next few weeks to answer questions, here's yet
another attempt at explaining what, how, and why WINTERP is what it is...

The following is an excerpt from the WINTERP documentation in
./winterp/doc/winterp.doc:

==============================================================================
				  WINTERP:
  An object-oriented rapid prototyping, development and delivery environment
  for building user-customizable applications with the OSF Motif UI Toolkit.

* Introduction

** Why a Widget INTERPreter?

WINTERP is an interpretive, interactive environment for rapid prototyping
applications using the OSF Motif UI Toolkit. The name "WINTERP" stands for
Widget INTERPreter, and that's exactly what WINTERP is -- an interpretive
language that allows programmers to interactively create interfaces using
the capabilities of the Motif widgets and the X11 toolkit intrinsics.
Widgets in the Xtoolkit are dynamic and "interpretive" by nature of their
object-oriented, message passing style of design; they become maximally
useful when driven by an interactive environment like WINTERP.

Neither traditional C Xtoolkit applications, nor UIL applications really
take advantage of the interpretive nature of the Xtoolkit. When programming
in C, one is forced to go through tedious compile+edit+test cycles even for
making a trivial change. X and the Xtoolkit provide a fancy widget resource
manager that allow you to shorten the compile+edit+test cycle -- the
Xtoolkit "reinterprets" it's resource settings as a whole each time the
application is brought up; compile+edit+test is shortened to edit+test.
UIL extends the level of data-interpretation a little bit further by
allowing the system to read a structured description of the widget
hierarchy and resources. UIL claims this will allow applications to be
written in such a way that the interface can be drastically altered by
changing the description file. In reality, only the most trivial sorts of
layout changes are possible with UIL because it is not a programming
language, and thus cannot allow you alter the program semantics that are
invariably intertwined with the semantics of the user interface.
Furthermore, UIL still uses compilation, rather than interpretation, which
means application prototyping is still as tedious as ever.  WINTERP
provides both an interpretive interface to the Xtoolkit widgets, and a real
programming language -- this makes it ideal for prototyping and/or
customizing the layout, look, AND functionality of an application.

WINTERP's interpreter is based on David Betz's popular XLISP, a small,
fast, C-implemented interpreter with Common Lisp syntax and extensions for
object oriented programming. Full-blown Lisp systems such as Common Lisp
have proven to be very effective prototyping environments and are commonly
used as platforms for building User-Interface Management Systems (UIMS).
WINTERP attempts to deliver the advantages of Lisp to those that cannot
afford the expenses, both monetary and computational, of large systems like
Common Lisp.

Lisp is traditionally associated with unwieldy, large, slow and expensive
systems -- Lisp's flexibility has it's costs. One solution to these
problems has been to create special operating systems and hardware to
better support Lisp: The Lisp Machine -- a very expensive, and very
specialized system.  Lisp Machines are losing ground to the general purpose
workstation running UN*X: such machines can be built at relatively low cost
with enough compatibility between vendors that a growing number of UN*X
applications can be run on a variety of hardware vendor platforms.
Unfortunately, attempts at building Lisp-based applications that are good
citizens on UN*X workstations have generally failed because systems such as
Common Lisp (CL) create huge, resource-hungry processes that swap/thrash
out all other applications -- not acceptable if you are trying to create an
application that works alongside other applications running in a
multiprocessing system like UN*X.  While CL platforms will continue to make
excellent prototyping platforms, delivery of applications embedded in a CL
environment is unacceptable. Attempts at recoding CL prototypes under a
delivery platform (e.g. just using UN*X & C) is time consuming, and changes
the feel and the flexibility of an application: applications prototyped
with Common Lisp assume and make use of the underlying features of the Lisp
system; these assumptions must be removed from the design or be recoded in
the delivery language.

Fortunately, another class of Lisp application has been successful in a
general purpose computational environment -- a hybrid architecture of Lisp
and C giving the flexibility of a Lisp system while allowing delivery of a
relatively small and efficient process. Under UN*X, Richard Stallman has
created a highly-customizable editor-based programming environment called
GNUEMACS -- this is a system that delivers to the UN*X user a text editor
oriented UI that is the foundation of the Lisp Machine programming
environment. Similarly, under MSD*S successful programs like AUTOCAD
contain a Lisp customization language embedded in a CAD program.  The
approach taken by such hybrid applications is that a small mini-Lisp
interpreter serves to "glue" together efficient C-implemented primitives
that make up an application.  User-customization and prototyping under such
a hybrid system amounts to using the Lisp interpreter to reconfigure
C-implemented building blocks in order to change, modify, or improve the
functionality of the system. Such an application architecture follows the
"80/20 heuristics" for program execution -- low level routines that take up
most of the computational resources are coded in C, and are therefore fast,
and efficient in memory use (no garbage collections caused by low-level
code). The Lisp interpreter is relatively slow in comparison to a compiled
C program, but it only serves to flexibly glue together components of the
"outer loop" of a program.

WINTERP was written as a platform for building such hybrid Lisp/C systems;
XLISP makes this possible because, unlike large Common Lisp systems,
integrating arbitrary C-implemented functionality with the Lisp interpreter
is easy.  WINTERP itself is an example of the feasability of hybrid
programming techniques -- WINTERP's X/Motif functionality is achieved
through XLISP interfaces to the C-implemented Motif toolkit. WINTERP is
thus aimed at the class of application that cannot afford to carry along
all the excesses of Common Lisp, but does require an embedded programming
language for user-customization.

WINTERP supports an evolutionary program lifecycle: WINTERP application
writers will rapidly prototype new functionality by using the mini-Lisp
interpreter to interactively refine the layout, looks, and functionality of
the user interface.  Once functionality has stabilized, a programmer will
be able to improve the application's efficiency by reimplementing the
functionality in C while maintaining the same Lisp programmatic interface
to the rest of the system. These new primitives will then serve as the
building blocks for the next layer of prototyping and customization... The
end result, if designed carefully, is a relatively small and fast
application that provides the right set of building blocks and hooks to
permit end-users to customize the look and feel of the application.

WINTERP is also useful for rapid prototyping applications that do not need
to be delivered with an embedded customization language. Systems with such
delivery goals may still use the aforementioned application lifecycle. As
the application matures and Lisp prototype code stabilizes, the program can
gradually be recoded entirely into C, eventually allowing a "normal" C
program to be delivered.


** Why I built WINTERP:

I built WINTERP as a platform for our project in designing, building, and
evaluating Computer Supported Cooperative Work (CSCW) and Collaborative
Multimedia Systems. The usefulness of such systems can rarely be
demonstrated by demoing "laboratory curiosity" applications; evaluating
such technologies requires applications be delivered to early adopters of
the technology with a minimum of extraneous overhead (e.g. runtime
licenses, huge systems) and that the delivered application be customizable
so that it can be integrated into the environment of a particular
workgroup.

The project's immediate goal is to develop STRUDEL, a highly configurable
mail/calendar/information management system to enable computer supported
cooperative work.  We intend for STRUDEL to become the "GNUEMACS of
groupware systems".  The Lisp interpreter will permit the system to be
customized to support special modes of communication for particular
workgroup environments much in the same way that emacs-Lisp is used to
customize the editor to support special editing modes for particular
programming environments.

In STRUDEL, WINTERP's Lisp interpreter and Motif U.I. primitives will be
used as a description language for creating and processing active/graphical
e-mail forms. Such forms can be sent (as textual programs) through standard
e-mail channels, and the receiving STRUDEL system will interpret the
WINTERP-Lisp forms description language and display a form letter
containing a user interface built from arbitrary combinations of widgets,
bitmaps, as well as voice and video "widgets".  Users will be able to
choose from a library of email forms that are designed to track specific
types of conversations -- scheduling meetings and resources, software
defect tracking, fleshing out design issues, etc.  Workgroups can extend
the library of forms to help capture and manage recurrent conversations
that are not covered by STRUDEL's standard forms library.


** Why XLISP?

I implemented WINTERP on top of XLISP because it is reliable, small, and
free, thus allowing delivery of applications such as STRUDEL (see above)
with a minimum of overhead (licenses, slow systems requiring specialized
hardware) to potential early adopters of groupware technologies. XLISP has
been around since 1985, and has evolved considerably since it first
appeared publically; because it has been in use for some time it has also
had most bugs shaken out of the system through widespread use. Furthermore,
the newsgroup comp.lang.Lisp.x has been an effective channel for exchanging
information and patches to XLISP. XLISP was designed to be run on PC's;
because it was designed with a limited environment in mind, it has turned
out to be quite fast and memory- efficient while remaining portable across
a variety of architectures ranging from 16 bit PC's to workstations.  And
of course, XLISP's simple object system has enabled an elegant interface to
the object oriented structure of the Xtoolkit and the Motif widgets.
Finally, XLISP is free, thanks to the generosity of David Betz.

Many people have asked "Why not scheme?", or "why not emacs-Lisp?"... the
above paragraph should answer that. David Betz's XSCHEME is still under
development, and would not be a good choice as a stable platform. In
particular, XSCHEME does not (yet) have the debugging capabilities of
XLISP.  Other Scheme implementations were too large, and too complicated to
work with given the sorts of changes I needed to make. GNUEMACS' emacs-Lisp
fit the bill in many ways, but unfortunately the code is very intertwined
with GNUEMACS' editor functionality, and the Free Software Foundation's
Copyleft is far too restrictive to be used in potential products built from
WINTERP's technology.

"Professional" Common-Lisp systems have many nice features, but
unfortunately, they are big, slow, expensive, and make bad delivery
platforms.  Most CL systems do not come with source code, which makes it
difficult to alter the way these systems work in significant ways (as I
have done with XLISP in WINTERP). Even with source code, CL impedes the use
of hybrid programming techniques mentioned above -- CL systems are often
only implemented in C at the lowest levels, thus making it difficult to
patch in high-level C-implemented functionality that can be used
transparently from Lisp. Finally, Common Lisp programs cannot be
distributed for free -- this means that potential early adopters of our
STRUDEL technology would have to pay CL license fees, attach codeword
modules to their computers (to ensure that license fees have been paid),
and other such "hassles". People eager to try out our STRUDEL technology
may have second thoughts about becoming "early adopters" if they have to
spend money and time (convincing their management to give them the money
and time ...) in order to try out experimental software.


** Interacting with WINTERP's Lisp Listener.

WINTERP is a Lisp server, that is, the XLISP interpreter in the program
named 'WINTERP' accepts Lisp commands through a TCP socket. WINTERP's
clients are an editor such as GNUEMACS, and any other program running on
other UN*X machines on a network. Such capabilities are extremely useful in
allowing "remote procedure calls" (RPC) to a WINTERP-based application.
WINTERP's "RPC" capabilities can enable better tool integration: different
tools in one's environment can easily communicate with an application built
upon WINTERP. For example, in the aforementioned STRUDEL project, we expect
to integrate the groupware toolkit with traditional, stand alone software
revision control and source control tools so that designers can keep better
track of conversations on-, commitments about-, and issues surrounding-
version ownership, defect and enhancement resolution, etc.

The WINTERP distribution contains a simple client program 'wl' (in
./winterp/src-client/wl) which sends the Lisp s-expression given on its
command line to the Lisp server for evaluation. The best way to interact
with WINTERP's serverized Lisp listener is through it's GNUEMACS interface:

The GNUEMACS editor provides a very elegant and useful environment for
editing Lisp programs. Emacs' Lisp-mode will automatically indent your code
(C-M-Q == indent-sexp) and help you catch unmatched parentheses. The file
./winterp/src-client/winterp.el extends Emacs' Lisp-mode by providing a
command that allows you to send the current Lisp form you are editing off
to WINTERP for evaluation. This allows truly interactive programming
because you need not exit the editor to see the results of your "program";
with WINTERP, you can see the graphical results of interactive changes to
a program immediately. Note that WINTERP is architecturally separate from
the GNUEMACS editor -- interfaces to other editors are possible, but are
not provided in the standard WINTERP distribution.



* Introduction to XLISP objects and Widgets.

WINTERP uses XLISP's object system as its interface to the class hierarchy
of widgets provided by Motif. Specifically, each Motif widget class is
represented by one or more object classes in WINTERP.  In order to best
understand the capabilities of WINTERP's Motif interface, a brief review of
the XLISP object system is in order. You may also want to consult the XLISP
documentation ./winterp/doc/xLisp.doc for a more precise definition of the
object system.

XLISP Classes describe the type of a particular object by declaring a set
of variables held in each object. These "instance variables" may only be
accessed by "methods" that respond to "messages" sent to the object.
Methods are defined for particular classes, and functionality of other
classes may be incorporated into new classes via "inheritance". From
XLISP, Motif widget classes look just like normal XLISP objects -- that
means that you can easily extend the functionality of Motif widgets by
adding your own methods to a particular widget class. You may also use
inheritance to attach your own data structures to widgets. The result is
that WINTERP provides a very clean way to interactively rapid-prototype an
application, while also providing mechanisms for code structuring and reuse.
The latter is necessary in evolving from prototype to a structured,
maintainable, and customizable deliverable.


** Creating new objects.

Create a new instance of a class by sending the message :NEW to
<a_class_instance>:

	(SEND <a_class_instance> :NEW <parameters>)

<a_class_instance> is in fact an instance of class CLASS. Class CLASS allows
you to define new class instances by specifying the instance variables and
parent class of a particular class.


** Declaring a class.

To declare a "base class" object, that is, an object with no parent object,
just send message :NEW to the object <CLASS>

	(SEND CLASS :NEW '(<ivar0> ... <ivarN>)
			 ['(<cvar0> ... <cvarM>)])

'(<ivar0> ... (ivarN>) are a list of symbols. Each <ivar-i> names an
instance variable of the class. '(<cvar0> ... <cvarM>)]) are an optional
list of variables that are shared among all instances of that particular
class.


** Defining methods.

When a "message" is sent to an object, XLISP searches for a "method" to
answer the message. A method is a piece of Lisp code that is executed when
a particular message is sent to an object. Within the code of a method, all
object instance and class variables are accessible. Furthermore, the symbol
'self' is bound to the object the message was sent to.

Methods are defined by sending the message :ANSWER to <a_class_instance>:

	(SEND a_class_instance :ANSWER <:msg> <parameters> <code>)

where <:msg> is a keyword symbol (a symbol with a ':' prefix) representing
the message; <parameters> are the arguments given along with the message.
See the documentation on "lambda lists" in /winterp/doc/xLisp.doc p.12 for
details.  <code> is a list of s-expressions which get evaluated in response
to a message. The lexical environment that existed for the call to :ANSWER
will be used for value and functional bindings during method evaluation.

If you need to remember what the syntax is, consider the memory-helper
    "this class :ANSWERs to :MESSAGE..." == (send <cls> :ANSWER :MESSAGE ...)


** Inheritance

So far, the object system we just described supports *encapsulation*.
Encapsulation is good programming practice because it helps localize and
detangle complexity. Unfortunately, encapsulation runs counter to
flexibility because making flexible use of an object may require that
certain groups of instance variables be accessed by different layers of new
functionality. Most often, one wants to *reuse* aspects of a particular
class in creating code that specializes and alters the functionality of
that class. A compromise between encapsulation and flexibility is found by
using *inheritance* in an object system. Inheritance is used to allow a
 *subclass* to specialize the functionality of it's *parent class* (aka,
the *superclass*):

	(send Class :NEW '(<ivar0> ... <ivarN>)
                         '(<cvar0> ... <cvarM>)
			 <superclass>)

(<ivar0> ... <ivarN>) is a list of new instance variables in the subclass;
(<cvar0> ... <cvarN>) is a list of new class variables in the subclass;
<superclass> is a class instance representing the parent from which
the new subclass inherits variables and methods.

"Inheritance" is occurring because all the instance variables of all the
parent classes of the new subclass become the variables of each subclass
instance. Furthermore, all methods defined on a parent class may also be
used on a subclass instance. Note that while a subclass' methods can access
the variables defined on the parent classes, the reverse isn't true.


** Object initialization.

As mentioned earlier, new object instances are created by sending the
message :NEW to a class object. Sending the message :NEW to a class
automatically sends message :ISNEW to the newly created instance. By
default :ISNEW on an instance is a no-op method defined on class 'Object',
which is the implicit [(grand)*]parent of all instances. If you want to
initialize the instance/class variables of a particular class, you must
define an :ISNEW method on the class.  Any parameters originally sent to
the :NEW method will be passed on to the :ISNEW method and may be used to
initialize an object to outside-world parameters.


** Example of using OOP features of XLISP with Motif widgets:

As currently implemented, the Motif class xmListWidgetClass makes it a bit
baroque to create browsers (hopefully this will change in Motif 1.1).  The
problem is that a "browser" is a kind of application that lends itself to
object oriented techniques that are not always straightforward to support
in C. One often has a collection of 'things' that one wants to display in a
'list' and perform actions on the 'thing' corresponding to the visual
selection of an element in the displayed list. xmListWidgetClass will
display an arrray of XmStrings in a list. When one or more elements in the
list are selected, XmStrings corresponding to the selected elements are
returned. Since the XmStrings you put into the list widget are not the
XmStrings you get out, you must call XmStringCompare on each element of the
collection of 'things' to find out which ones are selected.  Presumably,
you'll want to do more than just get back an XmString...  normally one will
want to access data structures associated with the XmString so as to perform
an action dependent on those structures. This could be done with a lookup
table, but there's also a better way...

WINTERP allows us to subclass the Motif list widget so as to make it have
the kind of functionality we want. This subclass will contain an additional
instance variable 'items' which is an array of arbitrary XLISP objects to
be displayed in a textual browser made from the list widget. These objects
can have completely different internal representations -- the only
requirement is that they follow the protocol of being able to respond to
the messages :DISPLAY_STRING and :DEFAULT_ACTION. :DISPLAY_STRING returns a
string representation of the object to be displayed in the browser.
:DEFAULT_ACTION is the action to be performed when a list item is browsed
(by double clicking on the item).

The following creates the subclass <List_Browser> from superclass
<XM_LIST_WIDGET_CLASS>:

	(setq List_Browser 
		(send Class :NEW		;create a class inst
			'(items)		;new instance vars
			'()			;no class vars
			XM_LIST_WIDGET_CLASS))	;superclass

So now all instances of <List_Browser> will contain an instance variable
<items> and will respond to all the messages understood by the
XM_LIST_WIDGET_CLASS. We want our list browser to behave as described
above, so we define an :ISNEW method to initialize instance variable
<items> to the list of arbitrary objects to be displayed.  <items> gets
initialized to an array of objects, the list widget is created, and a
XmNdefaultActionCallback is setup so that a double click will send the
message :DEFAULT_ACTION to the browsed item:

	;; (send List_Browser :new <items_list> <args-for-the-list-widget>)
	;; <items_list> is a list of BROWSER_OBJECTs as described above.
	;; <args-for-the-list-widget> -- these are the arguments that
	;;       will be passed on to the list widget
	;;
	(send List_Browser :answer :isnew '(items_list &rest args)
	      '(
		(let* (
		       (items_end_idx (length items_list))
		       (display_items (make-array items_end_idx)))

		  ;; initialize the 'items' instance variable so that it
		  ;; holds all the BROWSER_OBJECTs passed in <items_list>
		  (setq items (make-array items_end_idx)) ;create the array
		  (do (                         ;copy elts from list to array
		       (i    0          (1+ i))
		       (elts items_list (cdr elts)))
		      ;; loop till no more elts
		      ((null elts))
		      ;; loop body
		      (setf (aref items i) (car elts))
		      (setf (aref display_items i) 
			    (send (car elts) :display_string))
		      )

		  ;; initialize the widget, passing in the browser items.
		  (apply 'send-super `(:isnew
				       ,@args
				       :xmn_selection_policy :browse_select
				       :xmn_items ,display_items
				       :xmn_item_count ,items_end_idx
				       ))
		  )

		;; set up a callback on the list widget initialized above such
		;; that a double click on the browser-item will send the
		;; message :default_action to the BROWSER_OBJECT.
		(send-super :add_callback :xmn_default_action_callback
			    '(callback_item_position)
			    '((send (aref items (1- callback_item_position))
				    :default_action))
			    )
		)
	      )


In the above code, SEND-SUPER works just like send, except that it doesn't
require you to give it the object to send the message to.  Instead, it
implicitly assumes that it will be called from within a method, and will
automatically send the message to a superclass of the object's class.  The
(apply 'send-super ...) form is actually calling the :ISNEW (instance
initializer) method on XM_LIST_WIDGET_CLASS, which actually creates the
widget via XmCreateList() or XmCreateScrolledList(). The APPLY '`'
(BACKQUOTE) and '&rest args' (LAMBDA LIST) features of Lisp allow us to
splice in the argument list passed to the instance of List_Browser into the
function that actually creates the widget. Finally, method :add_callback is
the WINTERP equivalent of XtAddCallback(). See the documentation on methods
on WIDGET_CLASS for more details.

The Motif List widget also defines a number of "methods" implemented as C
routines such as XmListAddItem(), XmListAddItemUnselected(),
XmListDeleteItem(), and XmListDeletePos(). In WINTERP, we define these as
methods :ADD_ITEM, :ADD_ITEM_UNSELECTED, :DELETE_ITEM, and :DELETE_POS
respectively. Since these methods modify the collection of objects
represented by the list widget, we must update the internal array of
objects <items> to correspond with the items displayed. We do this by
intercepting those messages to the superclass of class <List_Browser> and
handle them in <List_Browser> so as to update the appropriate data:

	(send List_Browser :answer :ADD_ITEM '(item position)
	      '(
		(setq items (array-insert-pos items (1- position) item))
		(send-super :add_item 
			    (send item :display_string) 
			    position)
		)
	      )

	(send List_Browser :answer :ADD_ITEM_UNSELECTED '(item position)
	      '(
		(setq items (array-insert-pos items (1- position) item))
		(send-super :add_item_unselected 
			    (send item :display_string)
			    position)
		)
	      )

	(send List_Browser :answer :DELETE_ITEM '(item)
	      '(
		;; this is too lame to implement... requires that we compare
		;; item with the result of :display_string done on every elt
		;; of ivar 'items'
		(error "Message :DELETE_ITEM not supported in List_Browser")
		)
	      )

	(send List_Browser :answer :DELETE_POS '(position)
	      '(
		(setq items (array-delete-pos items (1- position)))
		(send-super :delete_pos position)
	       )
	     )

To see how this subclassed list browser is used, and also to see how one
might write a sample application in WINTERP using the object oriented
features of XLISP, see ./winterp/examples/grep-br.lsp.  That file
implements a simple search browser based on the UN*X command 'grep'. See
also ./winterp/examples/mail-br.lsp to see how you can build a simple
mh-based mail browser. Finally, as another example of subclassing Motif
widgets, see ./winterp/examples/radiobox2.lsp.
==============================================================================