[comp.lang.lisp.x] Applications of WINTERP -- part 1/2

mayer@hplabs.hpl.hp.com (Niels Mayer) (05/24/91)

(Note: I'm belatedly-replying to a message posted on comp.lang.lisp.x)

> From: sane@cs.uiuc.edu (Aamod Sane)
> Newsgroups: comp.lang.lisp.x
> Subject: Applications of WINTERP
> Date: 1 May 91 19:33:52 GMT
> Organization: University of Illinois, Dept. of Comp. Sci., Urbana, IL
> 
> I would like to get an overview of what winterp provides and how
> people have used it. The following indicates what I want. 
> 
> 	If asked to describe what emacs does I would say
> 
> 	1. Provide text buffers. You can insert, delete and regexp search.
> 	2. Provide a process interface with buffers as standard i/o
> 	3. Do file operations
> 	4. Provide a lisp interpreter
> 
> 	Interesting applications:
> 
> 	Language sensitive editing.
> 	Communicating with lisp and other interpreters
> 	Nice interfaces to compilers. etc....

				--------------------

> 	1. Provide text buffers. You can insert, delete and regexp search.

Emacs provides text buffers as the user interface presentation mechanism,
and uses a flexible buffer-mode based keybinding mechanism for multiplexing
UI input to the appropriate functions. Although the emacs text buffer is
primarily for editing text, it can be specialized for more specific
character-based UI functions, e.g browsing, context-sensitive-editing,
menus, forms, etc.

Winterp provides Motif widgets and associated X Toolkit functionality as
both the UI presentation and input mechanism. Anything that can be
displayed in a Motif widget can be presented by WINTERP. Input to widgets
in WINTERP may be processed via callbacks or event handlers. Callbacks are
essentially chunks of interpreted lisp code (closures) that get evaluated
when the appropriate input events occur.  Within the callback's closure,
locally bound variables (similar to functional parameters during a function
call) allow passing widget or application state on to the callback code.

In emacs, you have to build your UI objects (e.g. browsers) out of text
buffers; in WINTERP, you have available to you any UI construct provided by
the existing Motif widgets (new Motif widgets can be added quite easily via
trivial C source extensions to WINTERP). What kind of UI objects does
standard Motif provide? Pushbuttons, Togglebuttons, Labels, Menu Bars,
Popup/Pulldown/Cascade/Option Menus, Lists (simple text browser), Text
Editors, Error/Information/Status Dialogues, Command Entry/Selection
Dialogues, container widgets that do constraint-based layout of the widgets
they contain, etc.

One particularly useful feature of WINTERP is that the Motif widget classes
are real class-objects within the XLISP object system. This means that
widgets can be subclassed, methods altered or added, etc. Subclassing Motif
widgets in WINTERP is roughly analogous to creating a new buffer mode in
emacs.  Emacs' buffer-local-variables are analogous to adding new instance
variables via subclassing. Emacs' buffer-mode specific keybindings are
analogous to adding new methods and associated callbacks or event handlers
to a subclass. The main difference between WINTERP's design and emacs' is
that emacs establishes a large number of special lisp programming
constructs which implicitly create a kind of (buffer)-object oriented
system. WINTERP is explicit in its use of object orientation by making
pervasive use of the more general OOP constructs provided by XLISP.

By organizing both the user-interface AND the "application functionality"
in an object oriented style, WINTERP helps you build applications which are
both easy to prototype and maintain. Many programs become messy because of
the amount of code it takes to explicitly tie the "application
functionality" with the "UI". In WINTERP, by organizing your application
code around the user-interface objects, one can implicitly maintain the
association between the UI and the application. Because things are more
self-contained, it becomes easier to reuse previously created
UI/application modules.  Encapsulating each UI construct with the part of
the application interacting with it makes changes to any portion of the
application have fewer chances of side-effecting other portions.

Although emacs' buffer-modes also allows for such encapsulation, emacs's
namespace is flat for all functions that get called via a buffer-mode
specific key-binding. This can and does cause name-collisions between
different packages loaded into emacs. Rather than using functions, WINTERP
programmers may use methods in XLISP's object system to prevent name-space
collisions.  (Of course, there may still be name-space collisions between
subclassed widget-class-objects since class-objects may be stored as symbol
values ...)

> 	2. Provide a process interface with buffers as standard i/o

Currently, WINTERP provides a process interface through the SYSTEM, POPEN,
and PCLOSE primitives that have been added to Xlisp. These work adequately
for interfacing noninteractive and relatively short-lived unix commands to
WINTERP. POPEN/PCLOSE allow interfaces to unix data through pipes, which
can be read-from or written-to using XLISP's I/O primitives.

The next release of WINTERP will have an additional process interface that
is similar to emacs' process-filter and process-sentinel facilities. This
upcoming interface will enable WINTERP to interact with long-lived and/or
interactive unix processes without blocking the WINTERP process itself.
This will enable WINTERP to act as a more generalized GUI wrapper to a
variety of unix programs that were designed to talk to a dumb terminal.
Furthermore, this feature will allow WINTERP-built GUIs to remain "active"
to user input while the subprocess is busy.


> 	3. Do file operations

You can use the XLISP primitives
OPEN/CLOSE/READ/READ-CHAR/PEEK-CHAR/READ-LINE READ-BYTE, etc. WINTERP
extends Xlisp with primitives implementing scanf(3s)-like functionality.
Other file operations can be implemented via unix commands
(rm/mv/cp/chmod/chown/chgrp) through the SYSTEM primitive.  Other unix file
operations are easy to add -- for example, adding unlink(2) would take
about 10 lines of C code (which could be "programmed by example" from the
C-language wrapper that interfaces the SYSTEM primitive to the subroutine
system(3S)).


> 	4. Provide a lisp interpreter

WINTERP uses XLISP as its lisp interpreter. One big advantage of XLISP is
that it is more of a Common Lisp look-alike. Another advantage is the
consistency of pervasive use of XLISP's smalltalk-like objects system.

Other facilities provided by WINTERP:

	* Lisp evaluator is accessible through a server port (either 
	  a unix domain or internet domain socket). This provides a 
	  simple remote procedure call mechanism for winterp-based
	  applications.
	
	* arbitrary lisp code (similar to "callback") can be evaluated
	  after a certain amount of time. Recurrent timeouts may be set up
	  to server as a clock.

	* in future version: "callback" can be set up to fire upon
	  changes in window manager properties. This is useful for allowing
	  WINTERP-based applications to interact with window managers,
	  session managers, and other X applications using window manager
	  protocols. 

	* in future version: "callback" can be set up to fire upon input
	  to a socket, or when I/O to a file can occur.


> 	Interesting applications:
>
> 	Language sensitive editing.
> 	Communicating with lisp and other interpreters
> 	Nice interfaces to compilers. etc....

Those functions of emacs are essentially "applications" built out of
emacs-lisp primitives (they are part of emacs' lisp library). WINTERP
currently just provides the "primitives" and the lisp library is not nearly
as complete and far-reaching as emacs'. Currently, I provide an "examples"
directory which shows people how to build some simple applications, and
gives examples of how to use most widgets, widget callbacks, and other
features of Motif and the Xtoolkit.

I believe that all the functions listed above could be implemented in
Winterp-Lisp -- it's just a small matter of programming which I don't have
time for. Hopefully, since WINTERP is freely available, people will begin
making such programming-environment utilities on top of WINTERP. I invite
anybody's code contributions -- contributed submissions will be included
in the WINTERP "examples" directory or in the "contrib" directory.

Currently, the "contrib" section of WINTERP contains:
	(1) some improvements to winterp/src-client/winterp.el -- the
	emacs-lisp interface between emacs and WINTERP's eval-server.
	These improvements were submitted by Bob Weiner <rsw@cs.brown.edu>
	and Stephen Gildea <gildea@alexander.bbn.com>. Future releases will
	include other enhancements by Dave Wolfe <wolfe@sybase.com> and
	Richard Hess <cimshop!pleione!rhess@uunet.UU.NET>.
	(2) Emacs-lisp code that allows you to use emacs to more easily
	browse the WINTERP documentation, do name-completion on WINTERP's
	symbols.  The aforementioned emacs interfaces were contributed by Bob
	Weiner <rsw@cs.brown.edu>.

The next release of WINTERP will contain Richard Hess'
<cimshop!rhess@uunet.UU.NET> menu server code, which is best described in
Richard's own words:
	| From: cimshop!rhess@uunet.UU.NET (Richard L. Hess)
	| Newsgroups: comp.windows.x
	| Subject: Re: Winterp, do *you* use it?
	| Date: 23 May 91 00:04:20 GMT
	| Organization: Consilium Inc., Mountain View, California.
	| [...]
	| [WINTERP] can also serve as a platform for developing "custom" tools.
	| For example, I've built a "menu server" on top of WINTERP which
	| allows the user to create menu's in a "menu cache" and then pop
	| them up when needed by calling the server with the menu's "key".
	| This supports the creation of a collection of re-usable menus for
	| such things as command menus in GNU emacs or menu driven shell
	| scripts.  The "menu server" currently supports interfaces from GNU
	| Emacs and Perl (note: any menu in the server can be accessed by
	| either interface as long as you know the menu's "key").

Here's a description of the example programs and applications that are
included in the current release of WINTERP (from winterp-1.12/examples/README):

| The WINTERP examples directory contains example Winterp-Lisp code. Some of
| the files in this directory are complete applications, some are just test
| code, and some are "random" winterp-lisp forms that I ended up typing in
| the process of experimenting with Motif using WINTERP,
| 
| ==============================================================================
| 
| Applications & Utilities:
| ------------------------
| 
| * bitmap-br.lsp: loading this file defines function BROWSE-BITMAP-DIRECTORY.
| 	Given a directory containing only X bitmap files, calling
| 	function (BROWSE-BITMAP-DIRECTORY <bitmap_directory_path>)
| 	will create a browser of the bitmaps in directory
| 	<bitmap_directory_path>. Clicking on the bitmap image in the 
| 	browser will set your root window background to the specified
| 	bitmap.
| 
| * bitmap-br2.lsp: Similar to bitmap-br.lsp, except that simply loading this
| 	file will bring up a browser of the bitmaps in directory
| 	/usr/include/X11/bitmaps/*. Unlike bitmap-br.lsp, this file
| 	contains comments on what is happening in this simple application..
| 
| * calculator.lsp: A simple calculator. The layout on this example leaves
| 	much to be desired. Shows a use of widget subclassing.
| 	Just load this file to bring up application.
| 
| * colorsetr.lsp: each time you load this file, it will bring up a window
| 	containing a single slider for red, green, and blue colors. 
| 	You can use the sliders to create a colors, then
| 	click the button "Set Color On Selected Widget", followed by
| 	clicking on the widget whose color you want to set. 
| 	Once the color on a widget has been set, you may move the sliders
| 	to change that color value without having to reselect the widget.
| 	By bringing up multiple instances of the colorsetr.lsp application
| 	you can set multiple color planes in other winterp widgets...
| 	Note that this uses XM_GET_COLORS to generate top/bottom/shadow
| 	colors based on the background color you've dialed in. Unless you
| 	have a lot of planes on your display, this can cause you to run out
| 	of colors quickly. Note that this works only on Motif 1.1.
| 
| * fake-app.lsp: Example application using XM_MAIN_WINDOW_WIDGET_CLASS +
| 	XM_ROW_COLUMN_WIDGET_CLASS/:simple_menu_bar +
| 	XM_ROW_COLUMN_WIDGET_CLASS/:simple_pulldown_menu
| 	to create a window with a menubar and pulldowns, etc. Just load this
| 	file to see the application. Note that this works on Motif 1.1 only.
| 
| * graphcalc.lsp: A calculator with "direct manipulation" graphic display of
| 	previous results (a sort of graphical spreadsheet, perhaps). 
| 	Users may also enter expressions in infix notation and these will
| 	be displayed with disambiguation provided by precedence rules. To
| 	run the calculator, just load this file.  NOTE: this file requires
| 	version of WINTERP extended for HP's XmGraph widget (Motif 1.0
| 	only) which allows you to lay out other Motif widgets in an
| 	arbitrary directed graph with widgets connected by XmArg "gadgets".
| 	Since most of you don't have the HP XmGraph widget, this
| 	application is not very useful for you. However, this may serve as
| 	an interesting example of the use/abuse of subclassed Motif widgets.
| 	[graphcalc-options.lsp and graphcalc-options.lsp are application
| 	options	that may be loaded separately from graphcalc.lsp.
| 
| * grep-br.lsp: A file-search browser application that uses the unix
| 	grep(1) program to search through files. Type the 
| 	string or regular expression for searching into the XmText widget
| 	labeled "Search for string"; type the set of wildcarded set of
| 	files into the XmText widget labeled "From Files". After clicking
| 	on the "DO SEARCH" push-button. The matching lines output by grep
| 	will appear in the XmList widget. Double clicking on a line in the 
| 	XmList widget will display the file in the XmText view-area widget,
| 	with the matching line at the top of the widget. In addition to
| 	being a useful, yet simple, application, grep-br.lsp is also a
| 	good example of subclassing Motif widgets inside WINTERP.
| 
| * helloworld.lsp: 10 lines of Winterp-Lisp code is all that is needed
| 	to produce the canonical "Hello World" program in WINTERP.
| 
| * identifier.lsp: A useful UI debugging tool. Loading this file creates a
| 	panel that allows you to click on a widget to identify it, click on
| 	a widget to destroy it, or change the foreground and background
| 	colors of the widget you click on. For Motif 1.1, the "Identify
| 	Selected Widget" button becomes especially useful because it will
| 	print out the widget's fully qualified resource name -- this allows
| 	setting	up your X-resources on a per widget basis and allows you to
| 	better understand which widgets are affected by a particular
| 	setting in your ~/.Xdefaults...
| 
| * mail-br.lsp: Load this file to create a simple mail browser. 
| 	This creates a browser of the last 30 MH messages in your
| 	MH folder +inbox. This assumes that (1) you have MH, (2) you have
| 	folder +inbox, (3) "scan" is on your $PATH. (4) various other
| 	things I forgot...
| 
| * w_ctrlpnl.lsp: Loading this file creates a control panel for WINTERP,
| 	including a rudimentary way to edit and send lisp to winterp's
| 	xlisp evaluator without having to use the gnuemacs interface
| 	(src-client/winterp.el) or src-client/wl.c. The following
| 	user-interface actions are provided:
| 		** Double-Click file in file-selection-box puts file into
| 		   XmText widget for editing or viewing.
| 		** "Edit($EDITOR)": the selected file gets edited by the
| 		   editor set in environment variable $EDITOR. You may
| 		   override $EDITOR by setting Winterp-variable
| 		   *SYSTEM-EDITOR*.
| 		** "Load File": loads the selected file into WINTERP.
| 		** "Save File": this is a No-Op for now.
| 		** "Eval @ Point": evaluates the Winterp-Lisp expression
| 		   you've typed into the control-panel's XmText editor.
| 		   The cursor (point) must be WITHIN the expression's
| 		   parentheses in order for it to get evaluated. The
| 		   evaluated expression is highlighted in the XmText editor.
| 		   (This needs some fixing; If the cursor isn't at the
| 		   right place, you'll get an "error: index out of range".)
| 		** <- (left arrow): moves to front of the current
| 		   Lisp expression. Note that this function doesn't
| 		   quite work right (generates "error: index out of range"
| 		   if the cursor isn't at the right place).
| 		** -> (right arrow): moves to end of the current
| 		   Lisp expression. Note that this function doesn't
| 		   quite work right (generates "error: index out of range"
| 		   if the cursor isn't at the right place).
| 		** Debug (toggle): turns on/off entry into XLISP's
| 		   debugger when an error is signalled. For more
| 		   info, see XLISP variable *breakenable* in
| 		   ./../doc/xlisp.doc.
| 		** Trace (toggle): turns on/off printing of XLISP
| 		   backtrace when an error occurs and debugging is enabled.
| 		   For more info, see XLISP variable *tracenable* in
| 		   ./../doc/xlisp.doc.
| 		** GC Msgs (toggle): turns on/off printing of messages
| 		   when a garbage collection occurs. For more info, see
| 		   XLISP variable *gc-flag* in ./../doc/xlisp.doc.
| 		** Err-Cont: Invokes XLISP's '(continue)', which will
| 		   allow you to continue from a "continuable error"
| 		   if Debug is On.
| 		** Err-^Level: Invokes XLISP's '(clean-up)', which will
| 		   clean up from the current error, and pop you up one
| 		   level in the debugger's error stack.
| 		** Err-~Level: Invokes XLISP's '(top-level)', which will
| 		   clean up from the current error, and pop you back to
| 		   the top-level read/eval/print loop.
| 
| ==============================================================================
| 
| "Libraries:"
| -----------
| 
| * initialize.lsp: this file contains various XLISP definitions that are
| 	essential for proper lisp usage. This file also contains various
| 	personal customizations for WINTERP. You should do the following:
| 	(1) copy this file to <homedir>/.winterp
| 	(2) set resource "Winterp.lispInitFile: <homedir>/.winterp"
| 	(3) Customize sections commented out at the end of this file.
| 		* Uncomment "LOAD" statements
| 		* Add XLISP globals that one wants customized.
| 		* Load any other personal macros, etc.
| 
| * prov-req.lsp: a simple attempt at Common Lisp's provide/require
| 	functionality. Note that this uses the X11r4 routine
| 	XT_RESOLVE_PATHNAME (XtResolvePathname()), therefore you can only
| 	use this w/ Motif 1.1. Use this library if you need a way of 
| 	loading Winterp-Lisp files along a specified "search path".
| 	See documentation in file for details.
| 
| ==============================================================================
| 
| WINTERP/Motif Tests & Examples:
| ------------------------------
| 
| * Command.lsp: demonstrate XM_COMMAND_WIDGET_CLASS methods and callbacks.
| 	Just load this file to see widget.
| 
| * FileSB.lsp: demonstrate XM_FILE_SELECTION_BOX_WIDGET_CLASS methods and
| 	callbacks. Just load this file to see widget.
| 
| * Form1.lsp: demonstrate simple use of XM_FORM_WIDGET_CLASS. 
| 	This example is the same as formtest.c on p 88 of Doug Young's
| 	Motif book. Just load this file to see example.
| 
| * Form2.lsp: demonstrate use of XM_FORM_WIDGET_CLASS using
| 	:xmn_top_position and :xmn_bottom_position constraints. This is
| 	similar to formtest.c on p 91-92 of Doug Young's Motif book.
| 	Just load this file to see example.
| 	
| * Form3.lsp: demonstrate more complicated use of XM_FORM_WIDGET_CLASS to
| 	lay out a panel for our multimedia controller. Just load this file
| 	to see example.
| 
| * List.lsp: demonstrate XM_LIST_WIDGET_CLASS methods and callbacks. Shows
| 	off different selection modes available, and callback support
| 	for the different modes. Just load this file to see example.
| 
| * RowColumn.lsp: demonstrate usage of Motif 1.1's XmCreateSimple*()
| 	routines, namely XM_ROW_COLUMN_WIDGET_CLASS/:simple_radio_box
| 	XM_ROW_COLUMN_WIDGET_CLASS/:simple_check_box
| 	XM_ROW_COLUMN_WIDGET_CLASS/:simple_option_menu.
| 	Just load this file to see examples. Note that 
| 	XM_ROW_COLUMN_WIDGET_CLASS/:simple_option_menu invokes Motif 1.1's
| 	popup-menu bug (see ./../doc/BUGS for details).
| 
| * SHELL.lsp: tests out the following classes and methods on those classes
| 	OVERRIDE_SHELL_WIDGET_CLASS, TRANSIENT_SHELL_WIDGET_CLASS,
| 	TOP_LEVEL_SHELL_WIDGET_CLASS, APPLICATION_SHELL_WIDGET_CLASS,
| 	TOP_LEVEL_POPUP_SHELL_WIDGET_CLASS,
| 	APPLICATION_POPUP_SHELL_WIDGET_CLASS,
| 	OVERRIDE_POPUP_SHELL_WIDGET_CLASS,
| 	TRANSIENT_POPUP_SHELL_WIDGET_CLASS,
| 	XM_DIALOG_POPUP_SHELL_WIDGET_CLASS. Just load this file to see
| 	examples.
| 
| * Scale.lsp: shows use of XM_SCALE_WIDGET_CLASS. Just load this file to see
| 	example.
| 
| * SelectioB.lsp: tests XM_SELECTION_BOX_WIDGET_CLASS methods and callbacks.
| 	Just load this file to see examples.
| 
| * Text.lsp: tests XM_TEXT_WIDGET_CLASS methods and callbacks. Also
| 	demonstrates use of :CALL_ACTION_PROC to invoke a widget action
| 	procedure programmatically. Just load this file to see examples.
| 
| * accel.lsp: Example of Xtoolkit accelerator usage via
| 	method :INSTALL_ALL_ACCELERATORS. Load this file, and type letters
| 	[a-z] into any pushbutton widget. each pushbutton widget
| 	has a single accelerator, one of key [a-z]. Accelerators for
| 	all other pushbuttons get installed onto each pushbutton... The
| 	accelerator arms the pushbutton, and the pushbutton's arm
| 	callback enters the typed character into the text widget.
| 
| * callbacks.lsp: Demonstrates using callbacks and timeouts. Just
| 	load this file and click on the "start" or "stop" button...
| 
| * dialogshel.lsp: Demonstrates WINTERP's dialog shells, and what happens
| 	when you manage/unmanage them. You may either load this file in
| 	it's entirety, or interactively evaluate individual forms using
| 	gnu-emacs or w_ctrlpnl.lsp.
| 
| * getvalues.lsp: a random test to see whether the code
| 	in winterp/src-server/w_resources.c has any machine dependencies.
| 	Load this file, and if your stdout beeps and you see messages
| 	about "failed: ..." then please send the output to
| 	mayer@hplabs.hp.com. NOTE: the actual graphical result of loading
| 	this file is not pretty. In fact, it's not supposed to be pretty....
| 
| * hostlookup.lsp: A stupid example using X_REFRESH_DISPLAY to popup
| 	and display contents of a "working dialog" before a time-consuming
| 	subprocess begins to execute. Note that X_REFRESH_DISPLAY is only
| 	defined on HPUX WINTERPs. You may be able to get this working for
| 	your machine as well...	see
| 	src-server/w_utils.c:Wut_Prim_X_REFRESH_DISPLAY() and
| 	src-server/utils.c for details....
| 	
| * interact.lsp: This file is not meant to be loaded. Rather, you should
| 	interactively evaluate forms within the file while inside the
| 	gnu-emacs editor. Basically, this file demos playing around with
| 	some of WINTERP's interactive features using the GET_MOUSED_WIDGET
| 	primitive.
| 
| * mng-test.lsp: this file tests out managing and unmanaging widget
| 	arrays/lists. It is best used by interactively evaluating 
| 	individual expressions (via the gnu-emacs interface), rather than
| 	loading the entire file.
| 
| * pixmaps.lsp: Play around with pixmaps. These are just random individual
| 	forms I eval'd to play around and test pixmaps, pixmap garbage
| 	collection, image cacheing, etc. Many of the pixmaps mentioned in
| 	this file do not exist on your machine. Also, this file assumes
| 	that you've already loaded rc-shell.lsp.
| 
| * popen.lsp: examples of playing around with POPEN to collect data
| 	from UNIX.
| 
| * popup-menu.lsp: POPUP menu example. This is a 1-to-1 translation of the
| 	popup menu example in the Motif Programmer's Guide. Just 'load'
| 	this file to see the example. Note that for Motif 1.1, this example
| 	invokes window-manager "close" bug.  See ./../doc/BUGS for details.
| 
| * radiobox1.lsp: a straightforward example for creating a radio box. See
| 	radiobox2.lsp for a better way using a WINTERP-subclassed
| 	toggle-button. Just load this file to see the example.
| 
| * radiobox2.lsp: A better (?) way of creating a radio box, using
| 	subclassing of togglebutton. Note that this version doesn't waste
| 	as much memory as radiobox1.lsp because it defines a single
| 	entry-callback on the rowcolumn widget instead of forcing each
| 	toggle-button to have separate copies of very similar
| 	callback-closures.  Just load this file to see the example.
| 
| * rc-shell.lsp: Load this file to put up a shell containing a row-column
| 	manager. I use this as an experimentation area for playing around
| 	with individual widgets.
| 
| * scooter.lsp: a silly example that scoots (moves) windows around the
| 	screen while changing their colors. This can really tie up your
| 	X server and window manager, so be careful...
| 
| * trans.lsp: Tests of Xt translation, accelerator facilities. Also test
| 	winterp's "Lisp()" action, which allows you to call the lisp
| 	evaluator from a translation/accelerator table.
|  

-------------------------------------------------------------------------------
            Niels Mayer -- hplabs!mayer -- mayer@hplabs.hp.com
                  Human-Computer Interaction Department
                       Hewlett-Packard Laboratories
                              Palo Alto, CA.
                                   *