-*-Outline-*- ================= = W I N T E R P = ================= T H E O S F / M O T I F _W_I D G E T _I_N_T_E_R_P_R E T E R An interactive object-oriented user interface language for rapid prototyping, development and delivery of extensible applications with Motif GUIs and Xtango graphics/animation. Version 2.10 beta November 23, 1997 by Niels P. Mayer E-Mail Address: winterp@nielsmayer.com URL: http://nielsmayer.com WINTERP Home Page URL: http://nielsmayer.com/winterp DOWNLOAD WINTERP UPDATES FROM FOLLOWING SITES: http://nielsmayer.com/winterp ftp://ftp.x.org/contrib/devel_tools/winterp* $Header: /users/npm/src/widgit/doc/RCS/winterp.doc,v 2.32 1994/12/07 22:51:25 npm Exp npm $ * Acknowledgements: ** Many Thanks to *** Allan Kuchinsky, Allan Shepherd, Martin Griss at Hewlett-Packard Laboratories, Palo Alto, for their support and management throughout my career at Hewlett-Packard Laboratories. Special thanks to Allan Kuchinsky for loaning me an HP9000s380 workstation used to develop much of WINTERP 2.0, and for letting me work on WINTERP while employed at HP. *** Jay Glicksman, and J. Marty Tenenbaum at Enterprise Integration Technologies (http://www.eit.com) for their support and interest in WINTERP. *** David Betz, Tom Almy and other comp.lang.lisp.x contributors for XLISP and XLISP-PLUS. *** John Stasko and Doug Hayes for the Xtango animation/graphics library. *** Luis Miguel and Doug Young for the XmGraph widget. *** David Harrison, Martin Brunecky, and Kee Hinckley for the Table widget. *** Don Libes, for the expect library. *** Alfred Kayser, John Bradley and Patrick J. Naughton for GIF code. Copyright (c) 1994-1996, Enterprise Integration Technologies Corp. and Niels Mayer. WINTERP 1.15-1.99, Copyright (c) 1993, Niels P. Mayer. WINTERP 1.0-1.14, Copyright (c) 1989-1992 Hewlett-Packard Co. and Niels Mayer. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Enterprise Integration Technologies, Hewlett-Packard Company, or Niels Mayer not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Enterprise Integration Technologies, Hewlett-Packard Company, and Niels Mayer makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ENTERPRISE INTEGRATION TECHNOLOGIES, HEWLETT-PACKARD COMPANY AND NIELS MAYER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE AND DOCUMENTATION, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ENTERPRISE INTEGRATION TECHNOLOGIES, HEWLETT-PACKARD COMPANY OR NIELS MAYER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE AND DOCUMENTATION * 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" its 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 its 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 feasibility 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 originally built WINTERP as a platform for 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. One example of such a system using WINTERP as platform is the STRUDEL extensible e-mail-based groupware system described in: Allan Shepherd, Niels Mayer, and Allan Kuchinsky. STRUDEL: An Extensible Electronic Conversation Toolkit. In David Marca and Geoffrey Bock, editors, GROUPWARE: Software for Computer-Supported Cooperative Work, IEEE Computer Society Press, 1992, pp. 505-518. (originally, in proceedings Conference on Computer-Supported Cooperative Work, Los Angeles, October 1990, pp. 93-104.) In STRUDEL, WINTERP's Lisp interpreter and Motif U.I. primitives provide the 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, and text. Users 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. Currently a small team of EIT engineers including myself are using WINTERP to create a multimedia authoring environment for creating World Wide Web (e.g. Mosaic) documents. The system, WWWeasel, facilitates internet publishing for people wanting to do on-line catalogs, on-line information services, and shared design notebooks as required by the members of the EIT's CommerceNet joint venture. It provides "two-view" ("WYSIWYG" and structure/outline) editing of HTML documents, and makes use of SGI IndigoMagic desktop drag and drop for composing multimedia elements. For details, see the upcoming publication: Jay Glicksman, Glenn Kramer, and Niels Mayer. "Internet Publishing via the World Wide Web". In proceedings Groupware '94, August 1994. San Jose, CA. An on-line version of the above paper is available via the World-Wide-Web: http://www.eit.com/papers/gpware94/paper.html Also available, slides of Jay Glicksman and Niels Mayer's presentation: http://www.eit.com/presentations/gpware94/s1.html The slides pertaining to the authoring environment (including more up-to-date screen snapshots of the application) are: http://www.eit.com/presentations/gpware94/s11.html through http://www.eit.com/presentations/gpware94/s34.html) A more legible snapshot of the WWW Authoring Environment's Link/Anchor browser, which is implemented using XmGraph, is available at http://www.eit.com/software/winterp/link-anchor-br.gif Also, a paper by Kate Weber of SGI compares WWWeasel to other Unix HTML authoring environments in development or production. For details, see: http://reality.sgi.com/employees/katew/katew.paper.html ** 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 publicly; 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 might be a good choice nowadays, but when I was developing WINTERP it was still under development, and would not be a good choice as a stable platform. Even now, 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, "professional" Common Lisp programs cannot be distributed for free -- this means that potential early adopters of new technologies 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 new technologies 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 "heavyweight" experimental software. ** Interactive GUI programming with WINTERP -- the XLISP eval server. When running a Winterp-Lisp application "script", the WINTERP program runs just like a normal C and Motif program under X windows. The advantage WINTERP has over other user-interface pseudo-languages (like Motif's UIL or Brunecky&Smythe's WCL) is that you can interactively create or modify user interfaces while one's application is up and running. This is essential for rapid prototyping; this is the reason why WINTERP is a rapid prototyping environment and UIL and WCL aren't. Many other UI languages including many Lisp interfaces to X (CLX, Garnet, etc), have separate "modes" for when they are responding to X and evaluating language input. The problems with such systems is that they do not allow for interactive prototyping -- when X is active, programmatic changes cannot be made, and when the language-evaluator is active, programmatic changes cannot be visualized. WINTERP allows for interactive X programming because its language-input is implemented via a server socket; programmatic input is treated as an event that is dispatched from the X event loop. The clients of WINTERP's evaluation server are editors/programming-environments such as GNUEMACS, or 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. The GNUEMACS editor provides a very elegant and useful environment for editing Lisp programs and interacting with WINTERP's Lisp eval-server. Emacs' Lisp-mode will automatically indent your code (Control-Meta-Q == indent-sexp) and help you catch unmatched parentheses. The file ./../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's emacs interface, each fragment of Winterp-Lisp code written into the editor can, at the touch of a button, be evaluated; programmatic changes affecting the user-interface can be visualized 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. (I strongly recommend that those that don't know how to use Gnu-Emacs should learn how -- you'll never be sorry, and besides, Emacs is really the only editor appropriate for doing Lisp programming. Even commercial Common Lisp vendors tend to use Gnu-Emacs as the preferred editing environment for their products, simply because Gnu-Emacs is the best Emacs implementation running on Unix. Another big advantage to gnu-emacs is that it runs under Xwindows directly, which means that you can select the Winterp-Lisp expression you want to evaluate by pointing at it with the mouse... For those that do not have Gnu-Emacs on their systems, or who do not want to learn Gnu-Emacs to use WINTERP, a rudimentary alternative is provided: see the Winterp-Lisp file ./../examples/w_ctrlpnl.lsp as well as the descriptipon of the WINTERP Control Panel Below.) The WINTERP distribution contains a simple client program 'wl' (in ./../src-client/wl) which sends the Lisp s-expression given on its command line to the Lisp server for evaluation. 'wl' may be embedded in other programs that need to talk to WINTERP-based applications. 'wl' can also be called (e.g., via system(2)) from such programs -- that is essentially how WINTERP gets gnuemacs to talk to it when using the Emacs-Lisp interface ./../src-client/winterp.el. WINTERP's RPC capabilities can enable better tool integration: different tools in one's environment can easily communicate with an application built upon WINTERP. Furthermore, multiple WINTERP applications across a network may intercommunicate with each other, exchange data, etc using these facilities (see 'wl-tcpip'). * Prerequisites and Assumptions. This documentation assumes that you understand object oriented programming concepts, understand the rudiments of Lisp programming, and know how to make application user-interfaces using the Xtoolkit. If not, you should be able to learn things quite easily by studying and interactively evaluating the various bits of Winterp-Lisp code in the ./../examples directory. For documentation on XLISP features see the files ./../doc/xlisp.doc, ./../doc/XlispRef.doc and ./../doc/XlispOOP.doc . This guide assumes that you already have documentation on Motif and the Xtoolkit. A good overview of programming with widgets is Doug Young's "X Window Systems: Programming and Applications with Xt." I also expect that you have the Motif programming guide, the Motif manual pages, etc. This document will hopefully allow you to understand how to translate the examples and topics discussed in those programming guides into WINTERP-Lisp. Names in Xtoolkit and Motif contain mixed case. Since XLISP symbols are case-insensitive, all the Motif/Xtoolkit names in WINTERP contain an underscore in place of a lowercase-to-uppercase transition in the name, eg, xmPushButtonWidgetClass becomes XM_PUSH_BUTTON_WIDGET_CLASS, and the resource XmNinput becomes :XMN_INPUT. All the Xtoolkit/Motif C names are listed in close proximity to the Winterp-Lisp names for equivalent functions. Therefore, to look up the Xtoolkit name "XtFoo", use your editor to search (in Gnu-Emacs, use i-search) for occurences of "XtFoo" in this document. This document is written in plain-text so as to make it easier to use on-line -- if you are viewing it in emacs, you will find some of the outline-mode commands useful. WINTERP version 2.0 Supports OSF/Motif 1.2.3, OSF/Motif 1.1, and 1.1.3. It might still support Motif 1.0, but I haven't tested it. Different features in these versions of Motif are enabled via #ifdefs in the source code. This document is also "#ifdef'd" so as to indicate which names and functionality apply to Motif 1.0, and to indicate new functionality brought on by Motif 1.1, 1.2, etc. Descriptions in this document that apply only to Motif 1.1 (and Motif 1.1.1) are bracketed by "#ifdef MOTIF_1.1" and "#endif /* MOTIF_1.1 */". Description pertaining only to Motif 1.0 are bracketed by "#ifdef MOTIF_1.0" and "#endif /* MOTIF_1.0 */". Additionally, other optional functionality is switched by other #ifdefs in the source. This documentation reflects those #ifdefs as well, so that you can know what features of WINTERP correspond to the features compiled into your WINTERP. For example, the following #ifdefs are used in this document SGI_DROP_POCKET_WIDGET, WINTERP_TABLE_WIDGET, WINTERP_XTANGO_WIDGET, HP_GRAPH_WIDGET, WINTERP_EXPECT_SUBPROCESS. ============================================================================== * Setting up and running WINTERP: ** Install the 'WINTERP' distribution: Pick up the latest WINTERP distribution via anonymous ftp from host ftp.x.org. do "cd /contrib/devel_tools" and "binary" and retrieve ('get') the latest WINTERP distribution, which will be available as file winterp-2.xx.tar.Z and/or winterp-2.xx.tar.gz. Back on your system, as root cd to /usr/local and do zcat winterp-2.xx.tar.Z | tar xvf - or if you got a .gz (Gnu Zip) file, do: gunzip -c winterp-2.xx.tar.gz | tar xvf - The preferred default location for installing the entire WINTERP distribution is in /usr/local/winterp. If you can, please install the WINTERP distribution in that location (that is, uncompress/untar the tar file while cd'd to /usr/local/). There are some settings in the configuration of WINTERP which assume you've put the distribution in /usr/local/winterp; in particular, you should at least install the following directories from the WINTERP distribution: /usr/local/winterp/examples/*.lsp /usr/local/winterp/examples/interactive/*.lsp /usr/local/winterp/examples/lib-utils/*.lsp /usr/local/winterp/examples/lib-widgets/*.lsp /usr/local/winterp/examples/xlisp-2.1d/*.lsp /usr/local/winterp/examples/xtango/*.lsp /usr/local/winterp/doc/* /usr/local/winterp/src-client/* If you decide you must install WINTERP elsewhere, you must at least tell WINTERP where the "examples" directory is located. Assuming is the location for the top-level of the WINTERP distribution, you must set resource "Winterp.lispLibDir: /examples/" Alternately, you may specify the command-line argument "-lib_dir /examples/" each time you run 'winterp'. Note that the ".lispLibDir" resource is set to /usr/local/winterp/examples/ in the application default file /src-server/Winterp.ad. If you install that application default file and your is not /usr/local/winterp then you *MUST* edit the application-default file, setting the ".lispLibDir" resource to the appropriate value. See <> for details. ** Compiling and installing WINTERP via Imakefile and 'xmkmf': *** Compiling: If your system is set up appropriately, has Motif headers and libraries (version 1.1 or 1.2, preferably >= 1.1.4, or >= 1.2.3), and has xmkmf/imake configured correctly for Motif, you should be able to build a working WINTERP with the following: cd xmkmf make World (note, after doing "make World" you may do further compilations without remaking the makefiles by just doing "make") *** Install 'winterp' and 'wl' executables, manual pages, app-defaults: If compilation was successful, do make install make intall.man to install the 'wl' 'winterp' binaries, the Winterp.ad application defaults file, and the 'winterp' 'wl' and 'wl-tcpip' manual pages. The places where the software is installed is dependent on your imake/xmkmf configuration. ******************************************************************* * * IMPORTANT NOTE: IF IS NOT INSTALLED IN * * /usr/local/winterp, THEN YOU MUST SET RESOURCE Winterp.lispLibDir * * IN THE WINTERP APPLICATION DEFAULTS FILE THAT WAS INSTALLED ABOVE * * VIA 'make install'. SEE <> * * FOR DETAILS. * ********************************************************************* *** Forcing Imake to work with Motif: Some manufacturers actually provide complete working systems! SGI's Irix 5.2 'mmkmf' (Motif 'xmkmf') and DEC's OSF1 'xmkmf' will actually build Motif programs like WINTERP without requiring any configuration edits whatsoever. Other manufacturers will require you to either update your xmkmf/imake system to include Motif header and library file paths. Some systems (HP) don't provide xmkmf/imake at all, and this may force you to use the X Consortium xmkmf/imake, which doesn't know anything about Motif. Finally, some systems (e.g. Sun, prior to Solaris 2.3) don't include Motif, forcing you to install Motif separately from the rest of your X -- this again may mean that your imake won't know where your Motif is installed. If your system places Motif headers and libraries in locations other than your compiler/linker's default search paths, then you will need to (1) update your imake configuration files to handle paths to Motif libraries and headers; or (2) modify some of the 'Imakefile's in WINTERP, specifying: SYS_LIBRARIES -- specify Motif libraries and compatible X Xt libs. INCLUDES -- paths to Motif/X/Xt headers. See WINTERP's Imakefiles for examples of how this is handled. For example, HPUX places Motif in unusual locations. To handle that, note the sections in the Imakefiles within "#ifdef HPArchitecture". /src-server/Imakefile sets SYS_LIBRARIES specially if it notices you're compiling on HPUX. All the other Imakefiles also contain "#ifdef HPArchitecture" sections to special case the setting of the include search path via "INCLUDES": /src-server/Imakefile /src-server/widgets/Imakefile /src-server/xlisp/Imakefile /src-server/xtango/Imakefile Please see <> and <> for further details on compilation. *** Compilation options: To add/remove WINTERP compilation options, you should edit /src-server/Imakefile and then redo everything: cd xmkmf make World Propagation of your compilation option settings in Imakefile will only take place if you do the complete 'xmkmf' and 'make World' sequence. The compilation options are documented directly in the Imakefile. See the comments (XCOMM) in /src-server/Imakefile for further information on the following compilation options: WANT_DROP_POCKET_WIDGET = -DSGI_DROP_POCKET_WIDGET WANT_TABLE_WIDGET = -DWINTERP_TABLE_WIDGET WANT_XTANGO_WIDGET = -DWINTERP_XTANGO_WIDGET WANT_XMGRAPH_WIDGET = -DHP_GRAPH_WIDGET WANT_EXPECT_SUBPROCESS = -DWINTERP_EXPECT_SUBPROCESS WANT_INET_SERVER = -DWINTERP_WANT_INET_SERVER WANT_UNIX_SERVER = -DWINTERP_WANT_UNIX_SERVER WANT_STDIN_SERVER = -DWINTERP_WANT_STDIN_SERVER ** Compiling and installing WINTERP via Makefile.* and 'make': *** Compiling: To compile WINTERP, go to directory and execute 'make -f Makefile.' where Makefile. represents a machine-specific makefile: Makefile.solar -- Sun4 running Solaris 2.4 with 2.4 SDK (C compiler, X11, and Motif-1.2 development environment) Makefile.sun4 -- Sun4 running SunOS 4.1.3 and Sun's 'cc' (Note: since SunOS doesn't include Motif nor a standard X11, you'll need to install Motif/X11r5 and modify these makefiles, setting INCLUDES and LIBS appropriately for your installation of Motif and X11.) Makefile.sungc -- Sun4 running SunOS 4.1.3 and GNU 'gcc'. (Note: since SunOS doesn't include Motif nor a standard X11, you'll need to install Motif/X11r5 and modify these makefiles, setting INCLUDES and LIBS appropriately for your installation of Motif and X11.) Makefile.irix5 -- SGI running Irix 5.2 w/ Iris Development Option 5.2 (SGI's X/Motif-1.2/cc environment). Makefile.osf1 -- DEC Alpha running OSF1 v 2.0 with DEC's X/Motif (1.2) and C development environment. Makefile.Ultrx -- DEC DECStation running Ultrix 4.3 and DEC's X/Motif (1.1) and C development environment. Makefile.NeXT -- NeXT-Step 3.0 running Pencom's Co-Xist X/Motif (1.2) environment. Makefile.hpux9 -- HP 9000-s[378]00 running HPUX 9.X and HP's X/Motif (1.2) and C development environment. Makefile.hpux8 -- HP 9000-s[378]00 running HPUX 8.X and HP's X/Motif (1.1) and C development environment. Makefile.linux -- 386/486 PC running Linux OS and gcc 2.5.8 compiler. *** Install 'winterp' and 'wl' executables: Install the 'winterp' and 'wl' binaries somewhere on your UN*X execution path ($PATH). For example, if /usr/local/bin/ is on your $PATH, you can do the following: cd /src-server make -f Makefile. install ##or "cp winterp /usr/local/bin" cd /src-client make -f Makefile. install ##or "cp wl /usr/local/bin" You may want to install the manual pages in the appropriate man-page directory on your system. WINTERP includes the following manual pages in /doc/: winterp.man, wl.man, wl-tcpip.man, libexpect.man, XmGraph.man, XmArc.man. (xmkmf/imake "make install" installs winterp.man, wl.man, and wl-tcpip.man by default). See <> for hints on installing the WINTERP application default file located at /src-server/Winterp.ad. Xmkmf/imake compilation "make install" installs Winterp.ad appropriately. *** Porting to other systems: WINTERP should compile on any Unix system that supports X, Motif, and sockets. Previous versions of WINTERP have been reported to run on ** HPUX, for s3xx, s4xx, s7xx, and s8xx architectures ** SGI Irix 5.X. ** AIX 3.X ** Ultrix. ** SunOS 4.1 on Sun 4 or Sun 3 architecture. ** Solaris. ** NeXT. ** Data General AViiON (m88k, DG/UX 4.30, GNU C 1.37.23) ** Intel System V3.2 ** Apollo Domain ** Harris Nighthawk, etc. To attempt compilation on systems other than the systems for which a Makefile. exists, you should use the aforementioned Makefile. as a "template" for constructing a new makefile apprpriate for your system. Alternately, you may have better luck by using xmkmf/imake as discussed in <>. Pick machine type as a prototype for your template -- for example Makefile.solar might be a good starting point for a SYSVR4 system, whereas Makefile.sunos might be a good starting point for a BSD based system. Lets call that template file Makefile. and the Makefile for the new system you're porting to Makefile.. First, copy the following files: /Makefile. to /Makefile. /src-client/Makefile. to /src-client/Makefile. /src-server/Makefile. to /src-server/Makefile. /src-server/expect/Makefile. to /src-server/expect/Makefile. /src-server/widgets/Makefile. to /src-server/widgets/Makefile. /src-server/xlisp/Makefile. to /src-server/xlisp/Makefile. /src-server/xtango/Makefile. to /src-server/xtango/Makefile. In each Make-file you will have to modify the Make variable MAKEFILE, changing "Makefile." to "Makefile.". Additionally, you may have to modify the Make variables OSDEP_CFLAGS, INCLUDES, and for /src-server/Makefile. you'll also need to set LIBS. See comments in the makefiles for details on those variables. If your system can run in a SYSV versus BSD "world" you should compile assuming BSD, due to WINTERP's usage of sockets. You might want to do this for Apollo Domain, MIPS, or AIX. For example, AIX 3.1 requires that you add "-D_BSD" to OSDEP_FLAGS, and add -lbsd to "LIBS". If you've tested/run WINTERP on a new architecture/os and have a new set of Makefiles for that architecure/machine, please mail your makefiles to winterp@nielsmayer.com *** Compilation problems? If you have problems compiling WINTERP on your machine, please send your queries to winterp@nielsmayer.com In your mail, you should include prcise details regarding the problem, or failing that, at least contains a copy of the error-output from compilation, link, or runtime. And be sure to tell exactly what kind of hardware and operating system platform you are using, as well as the Motif version and patchlevel, etc. I've received a lot of mail from people whose problems stemmed from the fact that they had never compiled Motif applications on their machine before. Please do not send me (or the WINTERP mailing list) mail asking how to build your first Motif program because (1) I don't have the time to be a free Motif consultant; (2) My schedule is such that I may not be able to get back to you within a timeframe that you might consider "soon enough." Please remember that this is free software -- I try to support it as best I can, but you should look at it as unsupported, or at least erratically supported software. If you have a compilation problem, please, at least, make sure that Motif libraries (version 1.1, or 1.2) are installed on your machine. Beyond that, at least take some time to verify that the errors you are seeing are not a result of mis-compilation. Typical problems include * Using the wrong X or Motif headers; * Having incompatible versions of the Xtoolkit and Motif headers/libraries. (see Make-file variable LIBS and INCLUDES); * Having incorrect values for C pre-processor symbols (see Make-file variable OSDEP_CFLAGS); * Having incorrect C compiler flags (see OSDEP_CFLAGS). If you have not compiled a Motif program on your system, then you should try compiling an existing, known-working 10-50 line Motif C program. You should be able to at least find a few Motif C examples in your vendor's distribution of Motif -- these can be especially useful because the Makefiles will tell you which Makefile variables need to be customized for your particular vendor's hardware and software., e.g. OSDEP_CFLAGS, INCLUDES, and LIBS. If you are using Motif source straight from OSF (rather than a vendor-supplied library), you should find such example programs in the Motif distribution. Alternately, take a look at the Imake configuration files to figure out which OSDEP_CFLAGS, INCLUDES, and LIBS need to be set in WINTERP's Makefiles. *** Further Information about X/Motif, Porting, Platforms, and Other Info. Please check the Motif and X frequently asked questions (FAQ) lists which are available from the X Consortium as well as a variety of other HTTP and FTP sites.If for some reason 'ftp://ftp.x.org/contrib/faqs/Motif-FAQ' or 'ftp://ftp.x.org/contrib/faqs/FAQ' don't work for you, try your favorite internet search (webcrawlers, spiders, archie etc) techniques to find other redistribution sites. Please check these FAQs, as well as any platform-specific FAQS for information on the availability of Motif implementations for your platform. Certainly everything I would know about this subject comes from those sources, it might be better to look at these resources first before sending mail to the author or the WINTERP mailing list. *** Compilation options: To add/remove WINTERP compilation options, you should edit the appropriate /src-server/Makefile. and then 'make' again. The compilation options are documented directly in the Makefile.. See the comments /src-server/Makefile. for further information on the following compilation options: WANT_DROP_POCKET_WIDGET = -DSGI_DROP_POCKET_WIDGET WANT_TABLE_WIDGET = -DWINTERP_TABLE_WIDGET WANT_XTANGO_WIDGET = -DWINTERP_XTANGO_WIDGET WANT_XMGRAPH_WIDGET = -DHP_GRAPH_WIDGET WANT_EXPECT_SUBPROCESS = -DWINTERP_EXPECT_SUBPROCESS WANT_INET_SERVER = -DWINTERP_WANT_INET_SERVER WANT_UNIX_SERVER = -DWINTERP_WANT_UNIX_SERVER WANT_STDIN_SERVER = -DWINTERP_WANT_STDIN_SERVER ** Set up X resources and application defaults files: To get the author's preferred set of Motif resources, install the file /src-server/Winterp.ad into /Winterp where is typically /usr/local/winterp, and is typically /usr/lib/X11/app-defaults. This installation is done by default if you've used xmkmf/imake and done a 'make install' -- for details, see <>. Alternately, you may just set up a private application-resource file for WINTERP by copying file 'Winterp.ad' to 'Winterp' and placing it somewhere on the path described by UN*X environment variable XUSERFILESEARCHPATH (See X(1) for details). NOTE: file Winterp.ad contains a full set of resource bindings for the Motif widget set, as preferred by the author. These settings include pointer focus (see "*keyboardFocusPolicy"), "emacs-like" bindings for the Text widgets, font settings (see *fontList ...), color settings (see "*background", "*foreground"), etc. Users of B&W X displays will definitely want to remove all the color settings in this file. Since only the "Winterp.*" bindings are Winterp-Specific, you may want to comment out all other bindings if your tastes in default Motif bindings are significantly different from mine... The following resources are critical for correct operation of WINTERP and must at least be set correctly in some resource file loaded by WINTERP (e.g. /usr/lib/X11/app-defaults/Winterp, ~/Winterp, ~/.Xdefaults, etc) or through WINTERP's associated command-line settings (-lib_dir and -enable_unix_server). !! Note: change /usr/local/winterp/examples/ if you did not install !! the WINTERP distribution in the default location !! / == /usr/local/winterp/ Winterp.lispLibDir: /usr/local/winterp/examples/ !! Default: Winterp.enableUnixServer: false !! You need to set this to true if you intend to use 'wl' or the GNU !! Emacs interface in /src-client/winterp.el Winterp.enableUnixServer: true ** ~/.winterp -- WINTERP session startup file: To set up a default WINTERP session startup file, do: 'cp /examples/00.winterp.lsp ~/.winterp' and edit and uncomment any variable values or environment setttings that you deem necessary. See comments in the file for details. A user will have a ~/.winterp file if he/she has personal preferences or special environment settings differing from the default. Examples include the need to set system-wide variables, such as directories where important system files are kept, customizations and variable settings for any applications loaded into WINTERP, etc. As a minimum, this file should contain *AT* *LEAST* '(REQUIRE "lib-utils/initialize")' since that provides the expected default settings for WINTERP's XLISP environment. This file is loaded each time WINTERP is started up, setting up the user's default environment for WINTERP, for both the case of "standalone" and "interactive" operation. (WINTERP's modes of operation are described in <>, sections > and <>). If the user omits the ~/.winterp file (or that file causes an XLISP error) then WINTERP will load /lib-utils/initialize.lsp, which sets up a default WINTERP/XLISP environment. A warning message is issued for cases when ~/.winterp cannot be loaded, however, the system does not require this file to be present. ** ~/.winterpapp -- WINTERP development session startup file. To set up a default WINTERP development session startup file, do: 'cp /examples/01.winterp.lsp ~/.winterpapp' and edit and uncomment/comment-out any variable values or environment setttings deemed necessary. See comments in the file for details. ~/.winterpapp contains the default development environment. This file is loaded each time WINTERP is started up without an initialization file as specified by X resource 'Winterp.lispInitFile' or command line argument '-init_file'; typically, when WINTERP is running without an initialization file, it means that it is being used as a development/prototyping environment (see <> below). The default ~/.winterpapp (/examples/01.winterp.lsp) loads the following files which are useful for WINTERP application development as well as general interactive use of WINTERP as an application exectution environment: (require "lib-utils/redir-err") (require "lib-utils/err-hook") (require "w_ctrlpnl") "w_ctrlpnl" is a simple control panel for WINTERP providing a file browser for loading/editing/saving Winterp-Lisp files, and an editor allowing interactive evaluation of the s-expression under the editor cursor. Other editor commands include traversing forwards/backwards through s-expressions, and formatting your code. Other XLISP commands include control over the XLISP debugger and WINTERP/XLISP evaluation error dialogues. For details, see <>. "lib-utils/redir-err" pops up a dialog box any time error output gets sent to stderr. Typically, WINTERP runs under a terminal emulator, and any error output would appear there, potentially never to be seen by the user. Loading "lib-utils/redir-err" causes any such output to be immediately apparent to the user. This notification is especially useful when running subprocesses under WINTERP -- their stderr output is noticed by WINTERP. "lib-utils/err-hook" pops up a dialog box any time an XLISP evaluation error occurs. The dialog box contains an XLISP "trace back" (see baktrace command) allowing one to see where an evaluation error occurs. If the user omits the ~/.winterpapp file, WINTERP will issue a warning message, but will otherwise continue to run normally. Note that ~/.winterp is loaded prior to loading ~/.winterpapp, thereby allowing any system-wide environment or variable settings to be made prior to loading any development environment application files. (See <<~/.winterp -- WINTERP session startup file:>> for details.) ** Run WINTERP!: Assuming you've successfully compiled and installed WINTERP and also have set up WINTERP's configuration files correctly, as per <>, <<~/.winterp -- WINTERP session startup file:>> and <<~/.winterpapp -- WINTERP development session startup file.>> you are now ready to run WINTERP. In particular, the following assumes that you've installed ~/.winterpapp so that WINTERP loads the "WINTERP Control Panel" (w_ctrlpnl) on startup. (1) Go to the WINTERP examples directory, which should be installed at /usr/local/winterp/examples -- "cd /examples" (2) go to a terminal emulator and type "winterp" to the shell. (Assumes that WINTERP has been installed and is on your directory search path $PATH). A startup message should be displayed, and the WINTERP control panel should pop up (assuming you've set up ~/.winterpapp correctly). (3) In the "WINTERP Control Panel" file selection box, select a file, e.g. "fake-app1.lsp", via single left click on that item. (4) Click "Load File" button. The application's window should pop up shortly. (5) Continue selecting files in the file browser, then load them with "Load File" button. Some other interesting examples include: * /examples/bitmap-br.lsp: Select a directory in the file browser and click "Browse Dir" to get a browser of the selected directory of X bitmaps. programmatically, one can create bitmap browsers by evaling (BROWSE-BITMAP-DIRECTORY ). * 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.. * /examples/calculator.lsp: a simple calculator. The layout on this example leaves much to be desired. Shows a use of widget subclassing. * /examples/calendar.lsp: Browser interface to unix 'cal' -- display a calendar. * /examples/dircmp.lsp: A directory comparison browser. Select a directory in each file selection box (must double-click on "Directories" list entry on type in a new path into "Filter" and hit . Then click on "Compare Dirs." button. A list of files only in directory-1, only in directory-2, and a list of different files will appear. Double-click on an entry in "different files" and a "diff" listing will appear in "Differences. Then double click on an entry in "Differences" and the differing files will appear in the two text display areas, with the difference line highlighted. * /examples/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 highlighted. In addition to being a useful, yet simple, application, grep-br.lsp is also a good example of subclassing Motif widgets inside WINTERP. For example setting "Search Regexp" to "^(def" and "Wildcarded Files" to "*.lsp" will return all lines beginning with "(def" in the Winterp-Lisp files specified by *.lsp (in the current directory). * /examples/helloworld.lsp: 10 lines of Winterp-Lisp code is all that is needed to produce the canonical "Hello World" program in WINTERP. * /examples/mail-br.lsp: Assuming you have the MH mailer installed and on your search paths ("scan" in particular) and have mail in MH format this application gives you a browser of the last 30 messages in your MH +inbox. Double clicking on an entry in the list will display the associated mail message in the text display area. ** Some useful WINTERP development tools: *** /examples/grph-whier.lsp: Load this file to display/inspect widget hierarchies created in WINTERP. The name grph-whier.lsp stands for graphical widget hierarchy. After you bring up the application, click the "Show Widget Hierarchy Of..." button. The cursor will become a cross-hair, indicating that you should click on some other WINTERP-generated window. A tree of the widget hierarchy will subsequently be ppresented. By clicking on the elements in the tree, one is given useful information on that widget, including: -- fully qualified X-resource name -- the associated widget-ID and parent widget-ID -- the widget's class and superclass -- dimensions of the widget -- instance variables on the widget (for inspecting subclassed widgets). -- class variables on the widget. -- a list of methods available on the widget's class. (doesn't list the superclass methods). *** /examples/identifier2.lsp: Load this file to bring up a simple "Widget operations" panel. * click on "Identify Selected Widget" then click the cross-hair cursor on some WINTERP-generated widget. Information about the selected widget will be printed to stdout, including a fully qualified resource name that may subsequently be used in setting up X-resource files for the selected application. * Click on "Destroy Selected Widget" then click the cross-hair cursor on some WINTERP-generated widget. The widget will be destroyed. Use at your own risk -- using this could potentially render some WINTERP-generated applications useless. * Click on "Display Translations of Sel. Widget" then click the cross-hair cursor on some WINTERP-generated widget. Information on the translation tables of the selected widget will be printed to stdout. This is useful for finding out what bindings are available on a particular widget. * Click on "Display Accelerators of Sel. Widget" then click the cross-hair cursor on some WINTERP-generated widget. This will display the list of accelerators bound on the selected widget, if any. * Type a string name of a color into "Set Foreground Color of Selected Widget" or "Set Background Color of Selected Widget" in order to change the colors on the selected widget. After typing the color in, hit and click the cross-hair cursor on the desired WINTERP-generated widget whose colors you want to alter. *** /examples/grph-sexpr.lsp: Click on "graph methods of selected widget" then click the cross-hair on the widget whose methods you want to inspect. A tree display of each method's code on that widget is presented. This is only interesting on widgets containing Winterp-Lisp methods, e.g. click on the text editor widget in the WINTERP Control Panel. Can you say hack? *** /examples/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 colors interactively, 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 or later. ============================================================================== * Running WINTERP -- usage, command-line flags, application resources. WINTERP can be run either in "standalone" or "interactive" modes. ** Standalone mode: When running standalone, WINTERP interprets a "script" describing a particular UI/application, but otherwise behaves just like a traditional C/Motif program. WINTERP may be run "standalone" by setting command-line flags -no_unix_server -no_inet_server -no_stdin_server or setting the following X resources to false: .enableUnixServer .enableInetServer and .enableStdinServer . In some cases, one may want to specify the following additional command-line arguments when running "standalone" to force WINTERP to behave more like a traditional C/Motif application: -no_init_msgs, -no_xterr_brk, -no_xtwarn_brk, and -no_xerr_brk. The same effect may also be achieved by setting the associated X resources to false: .enableInitMsgs, .enableXtErrorBreak, .enableXtWarningBreak, and .enableXErrorBreak . In order to run a Winterp-Lisp program standalone, you need to set the command-line argument "-init_file ", or set resource .lispInitFile. To have an application come up "standalone" with its own set of resources, you may use the command-line argument "-class " to tell WINTERP to load resources from the application defaults file ; on most systems, this file would be /usr/lib/X11/app-defaults/. An app-defaults file may be placed in other directories specified by UN*X environment variable XUSERFILESEARCHPATH (see X(1) for details, and see also environment variables XAPPLRESDIR and XFILESEARCHPATH). Some of the applications in /usr/local/winterp/examples/*.lsp contain code which checks for the existence of environment variable WINTERP_STANDALONE_APP. If these applications find this environment variable then they know they are running as standalone applications under WINTERP. When this environment variable is set, and a WINTERP standalone application is terminated either explicitly, or through a "window manager quit" (e.g. mwm's f.kill action) WINTERP itself will terminate. If the UN*X environment variable WINTERP_STANDALONE_APP is not set, quitting these applications will just delete the windows associated with the application, but continue to leave WINTERP running (so that any other applications it is running continue). If you run a "standalone" application without setting environment variable WINTERP_STANDALONE_APP, then the windows associated with the application will disappear when you quit the application but a non-interactive 'winterp' will continue to run and will need to be explicitly terminated via kill(1). The following Winterp-Lisp applications check for WINTERP_STANDALONE_APP /usr/local/winterp/examples/{calendar.lsp, dircmp.lsp, grep-br.lsp, /man-br.lsp, timesheet.lsp, xbiff.lsp, modem-dialer.lsp, and tk-challenge/Application.lsp. Directory /usr/local/winterp/bin contains some scripts to run some of the aforementioned applications: win-dialer, win-dircmp, win-grep, win-man-br, win-xbiff, and win-calendar. The following is an example of the 'win-grep' script, which loads "grep-br.lsp" as a standalone application. | #!/bin/sh | | WINTERP_STANDALONE_APP=TRUE | export WINTERP_STANDALONE_APP | | exec /usr/local/bin/winterp -init_file grep-br.lsp \ | -lib_dir /usr/local/winterp/examples/ \ | -no_stdin_serv -no_unix_serv -no_inet_serv \ | -no_init_msgs $* & ** Interactive mode: WINTERP may be interactively programmed via the built-in Xlisp evaluator; WINTERP thus provides a development and execution environment for designing, building, debugging, integrating and extending GUI-based applications. In "interactive" mode, WINTERP's Xlisp evaluator may be accessed through a terminal, or through the INET- or UNIX- domain sockets. Interactive access to WINTERP is controlled by the command line arguments -no_stdin_server, -enable_stdin_server, -no_inet_server, -enable_inet_server, -no_unix_server and -enable_unix_server. Resources .enableStdinServer, .enableInetServer, and .enableUnixServer also control interactive access to WINTERP. A variety of means of interacting with WINTERP is described below in sections: <>; <>; <>; <>; <>, and <>. ** Interacting with WINTERP via the terminal: Typically, when developing applications with WINTERP, one runs it under a terminal emulator, e.g. xterm(1); the "stdin eval server" in WINTERP listens to "stdin" from the terminal and evaluates any expressions entered by the user; results of evaluation are printed on stdout and unless one has done '(require "lib-utils/redir-err")', error messages will also print to the terminal. The "stdin eval server" is a new feature of WINTERP 2.0. It is enabled by default, but may need to be disabled on a very few machines or operating sytems. If you experience trouble with WINTERP's "stdin eval server", you may disable it via command-line argument -enable_stdin_serv, or by setting resource .enableStdinServer to false. (Note that the author has not has any trouble running the "stdin eval server" on all the Unix machines that WINTERP was tested on -- however, it is known that the XtAppAddInput() call upon which this functionality is predicated does not behave well on some systems (SCO??) when told to listen for new input on the file descriptor associated with "stdin"). One reason to use the "stdin eval server" in WINTERP is that it operates seamlessly with the XLISP "break loop", which is a special read/eval/print loop which is invoked by XLISP when an error occurs, allowing easier debugging of Winterp-Lisp programs. In order to prevent re-entrancy bugs, X events are not processed while in the XLISP "break loop" which means that you cannot use the UN*X domain or INET domain servers, nor the GNU Emacs interface (winterp.el), nor the "WINTERP Control Panel" to interact with WINTERP. The "break loop" is a special read/eval/print loop allowing users to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function 'continue', XLISP will continue from a correctable error -- for example if get an undefined function error, then define the function and 'continue' XLISP will continue execution from the point where the error occurred. If the user invokes the function 'clean-up' (or types Control-D), XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in the "break loop", the standard WINTERP "X> " prompt is replaced with one of "1> ", "2> ", ... "n> " where n represents the "breaklevel", the nesting level of the "break loops", each level corresponding to a single error occurrence. IMPORTANT NOTE ON BREAK LOOP: In WINTERP, controlling the "break loop" can only be done via the terminal under which WINTERP is running. WINTERP does not respond or process any X events while in the XLISP "break loop". In other words, if an error occurs while "Error Break-Loop" or "Error Trace-Back" radio buttons are set, the "WINTERP Control Panel" will not be responsive to the mouse or keyboard. To exit the break loop and regain X interactivity, the use must invoke function 'top-level' or type Control-C into the controlling terminal. For more information on the XLISP "break loop" see /doc/xlisp.doc section "BREAK COMMAND LOOP", functions 'clean-up', 'top-level', and 'continue', and variables *BREAKENABLE*, *TRACENABLE*, and *TRACELIMIT*. Note that the "break loop" and read/eval/print key-bindings listed in /doc/xlisp.doc do not apply to WINTERP. The only keybindings that work are: * the standard tty editing commands, e.g. Control-H, Control-U, etc. See stty(1) for details. * Control-C -- equivalent to calling function 'top-level' * Control-D -- equivalent to calling function 'clean-up' Note also that unlike XLISP, entering Control-D into the standard read-eval-print loop of WINTERP will not exit the evaluator. however it will disable the "stdin eval server". This is done so that WINTERP can be run in a pipeline, evaluating input on stdin. When an EOF occurs, XtAppAddInput() infinite-loops, so WINTERP catches this and disables the infinite loop. The simplest way to invoke a "break loop" upon error is to select the "Error Break-Loop" or "Error Trace-Back" radio buttons in the "WINTERP Control Panel". For details, see the section below <> especially sections <<"Error Break-Loop" radio button:>> and <<"Error Trace-Back" radio button:>>. -------------------- Although the "stdin eval server" is a convenient and quick way of interacting with the XLISP interpreter, it may not be the best way of developing programs in WINTERP -- it is far easier to develop one's code in a text editor and use commands to interactively and incrementally send individual expressions to WINTERP. Although editor- based interaction with WINTERP is useful for developing programs, it is often easiest to use the "stdin eval server" to load, test, debug, and experiment with programs you've developed within an editor. The WINTERP distribution contains three different means of interacting with the interpreter directly from a text editor. The "WINTERP Control Panel" allowing interactive development of programs using simple Motif-based text editor and various other Motif widgetry for controlling WINTERP. For details, see the section <>. For GNU Emacs users, this distribution also includes two Emacs-Lisp files providing for two different ways of programming WINTERP via GNU Emacs (for details, see the sections <> and <>). ** Interacting with WINTERP via the "WINTERP Control Panel": The Winterp-Lisp file ./../examples/w_ctrlpnl.lsp is a simple control panel for WINTERP providing a file browser for loading/editing/saving Winterp-Lisp files, and an editor allowing interactive evaluation of the s-expression under the editor cursor. Other editor commands include traversing forwards/backwards through s-expressions, and formatting your code. Other XLISP commands include control over the XLISP debugger and WINTERP/XLISP evaluation error dialogues. The "WINTERP Control Panel" is entirely written in Winterp-Lisp; it is typically loaded from your ~/.winterpapp file, which is automatically loaded by WINTERP when it is started without a -init_file command-line argument or .lispInitFile resource. (see <<~/.winterpapp -- WINTERP development session startup file.>> for details). *** Directory Selection: Double click on an item in the "Directories" XmList widget, or enter a wildcarded filename (e.g. /usr/local/winterp/examples/*.lsp) in the "Filter" XmText widget and hit . If the directory is valid and has files in it, then the files in that direcory will appear in the "Files" XmList widget. *** File Selection: To select a file in the "Files" XmList widget, single click on it. Alternately you may set the file selection by entering a fully qualified pathname to the file in the "Selection" XmText widget. The "Edit($EDITOR)", "Load File", "Show File", and "Save File" perform their function on the selected file. Double clicking an item in the "Files" XmList widget is equivalent to selecting a file and clicking "Show File", causing the file to be displayed in the XmText editor widget. *** "Edit($EDITOR)" button: The selected file gets edited by the editor set in environment variable $EDITOR. You may override $EDITOR by setting variable *SYSTEM-EDITOR* in your ~/.winterp file. In the XmText editor widget, Control-Meta-E calls this function. *** "Load File" button: The selected file gets loaded into XLISP/WINTERP. This function allows the "WINTERP Control Panel" to start up other WINTERP applications, set up the environment, or load libraries. WINTERP expects the selected file to be a Winterp-Lisp file; unknown results will occur if the file is of the wrong type, typically, Lisp evaluation or reader errors. In the XmText editor widget, Control-Meta-L calls this function. *** "Show File" button: The selected file is presented in the XmText editor widget. The user may then edit the file, or interactively evaluate Winterp-Lisp s-expressions with "Eval(<-->)". Double clicking on a file in the "Files" XmList widget does the equivalent of "Show File", displaying the file in the XmText widget. *** "Save File" button: Saves the contents of the XmText editor widget; a File Selection Box dialog is popped up allowing the user to enter the filename; the default filepath for saving is that of the current file listed under "Selection" in the "WINTERP Control Panel". In the XmText editor widget, Control-Meta-S calls this function. *** "Eval(<-->)" button: Evaluates the s-expression at the current cursor position in the XmText editor widget. This command searches backwards and forwards for the matching parentheses surrounding the current position of the cursor and sends that expression off to XLISP's reader and evaluator. The results of the evaluation gets printed to stdout and is visible in the terminal emulator running WINTERP. For best results, place the cursor on the opening parenthesis If an error occurs in searching for the matching parentheses surrounding the XmText curor, the program will beep, without evaluating any Winterp-Lisp expressions. In the XmText editor widget, Control-Meta-X calls this function. (the same binding is used in Gnu-Emacs). BUG: if an evaluation error occurs, the error backtrace (which occurs wnen "Error Dialog" or "Error Trace-Back" radio buttons are selected) will contain some spurious function call frames from the WINTERP Control Panel itself -- you should ignore all the call frames printed below the following: "Function: #" *** "(<---" button: Moves the XmText cursor back from the current position to the opening parenthesis at the current level of parentheses. This command is useful for moving back through Winterp-Lisp s-expressions one expression at a time. If an error occurs in searching for the matching parentheses surrounding the XmText curor, the program will beep, without moving the cursor. In the XmText editor widget, Control-Meta-B calls this function. (the same binding as used in Gnu-Emacs). *** "--->)" button: Moves the XmText cursor forward from the current position to the opening parenthesis at the current level of parentheses. This command is useful for moving forwards through Winterp-Lisp s-expressions one expression at a time. If an error occurs in searching for the matching parentheses surrounding the XmText curor, the program will beep, without moving the cursor. In the XmText editor widget, Control-Meta-F calls this function. (the same binding as used in Gnu-Emacs). *** "Format(<-->)" button: Formats the text within the s-expression at the XmText widget's cursor position by running it through an XLISP "pretty printer". This function uses the same mechanism/rules for determining the extent of the current s-expression as used by "Eval(<-->)". If an error occurs in searching for the matching parentheses surrounding the XmText curor, the program will beep, without moving the cursor. In the XmText editor widget, Control-Meta-Q calls this function. (the same binding as used in Gnu-Emacs). BUG: Calling "Format" converts all Winterp-Lisp symbols to uppercase (XLISP symbols are case insensitive, so case information is lost when text is read/parsed by XLISP. Note that case for data is preserved (e.g. CHAR, STRING, etc). *** "Debug Off" radio button: When this debug option is selected, XLISP global variable *BREAKENABLE*, and WINTERP global variable *ERRHOOK* are both set to NIL. When an XLISP evaluation error occurs, or a WINTERP, Motif, or X11 error happens, processing of the current function/method terminates and an error message is printed on the terminal. *** "Error Dialog" radio button: When this debug option is selected, XLISP global variable *BREAKENABLE* is set to NIL, and WINTERP global variable *ERRHOOK* is bound to the error hook dialog function from /examples/lib-utils/err-hook.lsp. When an XLISP evaluation error occurs, or a WINTERP, Motif, or X11 error happens, processing of the current function/method terminates, an error message is printed on the terminal, and a dialog box pops up listing the error message and printing the stack trace from the error-causing function/method all the way up to the top-level invocation that caused the error. The error dialog button "Close Window" can be clicked to remove the dialog (since "Close Window" is the default button, you can also just hit in the dialog window. The error dialog button "Save Backtrace" will save the stack trace to a file entered by the user into a file selection dialog box. Button "Exit Application" will terminate WINTERP -- typically this is only for cases where severe errors have occurred. *** "Error Break-Loop" radio button: When this debug option is selected, XLISP global variable *BREAKENABLE* is set to T, XLISP global variable *TRACENABLE* is set to NIL, and WINTERP global variable *ERRHOOK* is set to NIL. When an XLISP evaluation error occurs, or a WINTERP, Motif, or X11 error happens, processing of the current function/method terminates, an error message is printed and the XLISP "break loop" is entered. For more information on the "break loop" see section above <>, it is especially important that you read the portion titled <> if you're wondering why X windows from WINTERP no longer respond to X when you're in the break loop. *** "Error Trace-Back" radio button: When this debug option is selected, XLISP global variable *BREAKENABLE* is set to T, XLISP global variable *TRACENABLE* is set to T, and WINTERP global variable *ERRHOOK* is set to NIL. When an XLISP evaluation error occurs, or a WINTERP, Motif, or X11 error happens, processing of the current function/method terminates, an error message is printed, a stack-trace is printed, and the XLISP "break loop" is entered. The stack trace printed in this case is just like the stack trace that pops up when "Error Dialog" is selected (see above). It lists the call to the error-causing function/method all the way up to the top-level invocation that caused the error. For more information on the "break loop" see section above <>, it is especially important that you read the portion titled <> if you're wondering why X windows from WINTERP no longer respond to X when you're in the break loop. *** Function 'debug': Evaluating '(debug)' will set *BREAKENABLE*, subsequent XLISP evaluation errors will cause the XLISP "break loop" to be entered. This function from w_ctrlpnl.lsp overrides the one in lib-utils/initialize.lsp, causing the "WINTERP Control Panel" radiobuttons to indicate the state of the debugger. *** Function 'nodebug': Evaluating '(nodebug)' will clear *BREAKENABLE* and *ERRHOOK*, such that XLISP evaluation or WINTERP/Motif/X11 errors will not invoke the "break loop" nor the "Error Dialog" box warning of errors. This function from w_ctrlpnl.lsp overrides the one in lib-utils/initialize.lsp, causing the "WINTERP Control Panel" radiobuttons to indicate the state of the debugger. *** Function 'ctrlpnl': Evaluating '(ctrlpnl)' will deiconize or raise the "WINTERP Control Panel" window. Useful for cases when one is interacting with WINTERP via the "stdin eval server" and one wants to pop up an interface for evaluating or loading Winterp-Lisp files. ** Interacting with WINTERP via GNU Emacs' "winterp" mode: The gnuemacs interface to WINTERP makes the following assumptions: (1) You're using GNUEMACS version 18.54 or later (I've used winterp.el with versions of gnuemacs as old as 18.44, but you may need to load a >18.54 version of lisp/shell.el). (2) You've installed the WINTERP-Lisp client program 'wl' somewhere on your UX*X search path (see $PATH). (3) You are running WINTERP on the same host as GNU Emacs, and you've enabled WINTERP's unix domain socket by setting resource <> to 'true' or by adding <<[-enable_unix_server]:>> to the command-line. (4) The WINTERP-server ('winterp') is running and sending stderr and stdout to a reasonable place such as a terminal emulator. To use WINTERP's GNUEMACS interface, you must first load the file ./../src-client/winterp.el into gnuemacs. You may do this manually by using the command 'M-X load-file' specifying the file 'winterp.el' with the appropriate path information prepended. Alternately, you may include the form '(load "winterp")' in your $HOME/.emacs file, where is the appropriate path to the file ./../src-client/winterp.el. Once winterp.el is loaded, you should visit a WINTERP-Lisp file using GNUEMACS command 'M-X find-file' (C-x C-f). A file with suffix '.lsp' denotes a XLISP or WINTERP-Lisp file, and these will automatically put the associated editor buffer "Lisp mode" -- the GNUEMACS mode line will indicate the mode as '(Lisp)'. Within a Lisp-mode buffer, the following additional commands and keybindings are defined: *** winterp-send-defun (Control-Meta-X): The Lisp s-expression at the "point" (cursor) is sent to the WINTERP-server for evaluation. *** winterp-send-buffer: The current buffer is sent to the WINTERP-server for evaluation. *** winterp-send-exit: (C-c C-d): Sends a Control-D == EOF to XLISP, which exists the current breaklevel. If XLISP is not at a breaklevel, then this command will exit XLISP and cause the WINTERP-server to terminate. Additional commands that are useful in GNUEMACS' Lisp-mode: *** indent-sexp (Control-Meta-Q): Formats and indents the s-expression under the "point" (cursor). *** indent-for-comment (M-;): Will place a Lisp comment character at the appropriate column in your Lisp-source. If a comment already exists on the current line, this will reindent the comment. *** forward-list: (Control-Meta-N): Moves the "point" forward across a balanced group of parentheses. This is useful for moving the cursor to the next form. *** backward-list: (Control-Meta-P): Moves the "point" backward across a balanced group of parentheses. This is useful for moving the cursor to the previous form. *** forward-sexp: (Control-Meta-F): Moves the "point" forward across one balanced expression. *** backward-sexp (Control-Meta-B): Moves the "point" backward across one balanced expression. *** NOTE: The author has found it useful to bind commands backward-list, forward-list, and winterp-send-buffer to "function" keys F6, F7, and F8, respectively, because these commands are used often when using GNUEMACS to interface with WINTERP. *** DEBUGGING-TIP: If you are using WINTERP's GNUEMACS interface and functions such as winterp-send-defun are not working correctly, you should check the GNUEMACS buffer *winterp-client-shell* for error output from the program 'wl'. WINTERP's GNUEMACS interface requires that the winterp client program 'wl' works correctly -- see the documentation on 'wl' above for information. ** Interacting with WINTERP via GNU Emacs' "inferior lisp" mode. /src-client/win-cmulisp.el provides code to have WINTERP run as a GNU Emacs subprocess, with Emacs' Lisp mode providing Emacs' standard means of interaction with a Lisp system. Although this is the standard way of interacting with a lisp subprocess through emacs, the author prefers the old way of interacting with WINTERP, which is described in <> Those preferring to use GNU Emacs 18's "comint/cmulisp" package, or GNU Emacs 19 standard inferior lisp interface should add the following to their ~/.emacs: (load "/src-client/win-cmulisp") (Where is typically /usr/local/winterp.). Following the load of 'win-cmulisp', one may start up WINTERP as an emacs subprocess, by doing "M-X run-winterp". This will create a buffer in emacs in which WINTERP's "stdin eval server" receives and displays input/output. In emacs 18, this buffer is named "*cmulisp*"; in Emacs 19, the buffer is named *inferior-lisp*. In addition to displaying the results of WINTERP evaluations, this buffer can also be used to edit and send lisp expressions to the WINTERP subprocess of emacs. The following commands are available in the *cmulisp*/*inferior-lisp* buffer: m-p Cycle backwards in input history m-n Cycle forwards m-c-r Search backwards in input history return Send input to inferior lisp c-a Beginning of line; skip prompt. c-d Delete char unless at end of buff. c-c c-u ^u c-c c-w ^w c-c c-c ^c c-c c-z ^z c-c c-\ ^\ c-c c-o Delete last batch of process output c-c c-r Show last batch of process output If you are using GNU Emacs to edit Winterp-Lisp files, one may interactively edit and evaluate code via GNU Emacs' lisp mode, which provides the following useful bindings: c-m-x This binding is a gnu convention. c-c c-e Send the current defun to Lisp process. c-x c-e Send the previous sexp to Lisp process. c-c c-r Send the current region to Lisp process. c-c c-z Switch to the Lisp process buffer. c-c c-l Prompt for a buffer to load, default to current. ** Interacting with WINTERP via UN*X Domain Sockets, and the 'wl' client: The WINTERP client program 'wl' (stands for Winterp-Lisp) sends the XLISP expression given on its command line to the WINTERP server. 'wl' hangs until WINTERP has evaluated the s-expression given on 'wl's command-line. After the s-expression is successfully evaluated by WINTERP, 'wl' prints to stdout the results of the evaluation, and sets exit status 0. If an evaluation error occurs, an error messsage is output to stderr, and exit status gets set to 127. In contrast to the TCP/IP socket (see 'wl-tcpip'), the Unix Domain Socket is secure. People on other workstations cannot access a Unix domain socket via the netoork. Since the Unix Domain socket is a UN*X file, security on multi-user machines is achieved via traditional file-protection techniques -- WINTERP creates the file unreadable/unwritable by others. By default, WINTERP compiles with the Unix-Domain eval server enabled. If for some reason your machine or OS does not support Unix Domain Sockets, you may turn off compilation of these features. Do this by (1) removing "-DWINTERP_WANT_UNIX_SERVER" in the associated /src-server/Makefile.* makefile; or (2) make equivalent change to the Imakefile or its generated Makefile in that directory; or (3) edit /src-server/config.h... The Unix Domain Socket can also be enabled/disabled via X resource <>, or via command-line arguments <<-no_unix_server>> or <<-enable_unix_server>>. ** Interacting with WINTERP via INET Domain Sockets, and the 'wl-tcpip' client: The WINTERP client program 'wl-tcpip' (stands for Winterp-Lisp) sends the XLISP expression given on its command line to the WINTERP inet-domain server. 'wl-tcpip' hangs until WINTERP has evaluated the s-expression given on 'wl-tcpip's command-line. After the s-expression is successfully evaluated by WINTERP, 'wl-tcpip' prints to stdout the results of the evaluation, and sets exit status 0. If an evaluation error occurs, an error messsage is output to stderr, and exit status gets set to 127. By default, WINTERP compiles without the INET-Domain eval server capability. One may enable the TCP/IP socket capability by recompiling WINTERP with the line "#define WINTERP_WANT_INET_SERVER" added to ../src-server/config.h, or by setting "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the appropriate makefiles. Even when WINTERP is compiled with this option, the TCP/IP socket will not be enabled by default. This socket may be enabled/disabled via a command line options <<-no_inet_server>> <<-enable_inet_server>> or by setting X resource <>. Note that the TCP/IP client program, 'wl-tcpip', is not compiled by default because most WINTERP installations don't need it. The reason for disabling the TCP/IP socket is due to reasons of security. If you run WINTERP on a known port number, without any security precautions (see inetd.sec(4)), you are giving people open access to your account -- for example, others users will be able to execute programs on your account through the SYSTEM, POPEN, EXP_SPAWN, and EXP_POPEN primitives. By default, the program 'wl-tcpip' attempts to connect to the WINTERP server through your machine's loopback address, which it assumes is 127.0.0.1. If that is not your loopback address (isn't that IP address standard??), then you may have to specify 'localhost' or the hostname of your machine. 'wl-tcpip' will be able to connect to the WINTERP server more quickly if it can get an IP address without having to do a gethostbyname(). That's why I hardcoded the loopback address into wl-tcpip.c... (If this lookup is too slow, and you are running 'winterp' and 'wl-tcpip' locally, you may prefer using the Unix Domain Socket server mentioned below.) ** Compilation options -- 'stdin eval server', UN*X and INET domain sockets: WINTERP has a number of compilation and run-time options configuring how the eval-server is set up. Options can be enabled/disabled by editing src-server/Imakefile and then doing cd xmkmf make World Alternately, one may also just edit the above variable settings in the makefile approrpriate for your machine and OS (src-server/Makefile.*), followed by recompilation. Options are enabled when the variables below are set: WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER WANT_UNIX_SERVER= -DWINTERP_WANT_UNIX_SERVER WANT_STDIN_SERVER= -DWINTERP_WANT_STDIN_SERVER Options are disabled when the variables are set to "" The default compilation of WINTERP enables only 'stdin eval server' and UN*X domain socket eval server. To add 'inet eval server' edit the appropriate makefile and recompile as outlined above. ** WINTERP Resources (~/.Xdefaults): WINTERP is a standard Xtoolkit program. Any widgets you create will be affected by resource-manager settings just like they would in a normal program. In addition to resources for individual widgets, the following set up WINTERP's global application-resources. The default values are listed inside '[' and ']'. *** Winterp.lispInitFile: [~/.winterpapp] By default, ~/.winterpapp is the XLISP initialization file that WINTERP attempts to load when it starts up. Setting resource .lispInitFile overrides that default and loads the file given by the resource value. The file is loaded using the same search paths as primitives LOAD and REQUIRE -- see <> and <>. Note: For delivering applications that know how to load their own lisp files, I suggest writing a script that does whatever you need it to and then executes "winterp -class ". The command line argument -class causes WINTERP to use application-default file /usr/lib/X11/app-defaults/. That file in turn contains any resources needed by , with the resource Winterp.lispInitFile set to 's initialization file. That file in turn loads the application itself. *** Winterp.lispLibDir: [./] This resource sets the path to the default directory used by the LOAD and REQUIRE primitive. If you give an unqualified filename to LOAD/REQUIRE it will attempt to load /.lsp . By default, this directory is WINTERP's current working directory `pwd`. I suggest that you set this resource to "/winterp/examples/" , where is the fully qualified pathname to the WINTERP distribution files. *** Winterp.lispLoadPath: <:-separated-list-of-paths-to-load-dir> This resource sets the search-path used by the LOAD and REQUIRE primitives. The value of environment variable XLPATH overrides this resource. If you give an unqualified filename to LOAD/REQUIRE, they will attempt to load /.lsp , where is one of the paths in <:-separated-list-of-paths-to-load-dir>. If no match occurs, then <> is searched, and finally `pwd`... *** Winterp.lispTranscriptFile: [] If you set this, XLISP will use the DRIBBLE primitive to write out a transcript of your interactions with the Lisp interpreter. By default, this is not done. *** Winterp.enableInitMsgs: [true] By default, this resource is set to "true", causing WINTERP to send its initialization messages to the standard output. WINTERP-based applications may want to put an application specific initialization message; for such cases WINTERP's initialization messages may be disabled by setting this resource to "false". *** Winterp.initMessageString: [] By default, this resource is set to a dynamic-generated string based on argv[0], -class, etc. The string value of this resource represents the message displayed by WINTERP's default window at startup time. *** Winterp.enableXtErrorBreak: [true] By default, WINTERP will signal an XLISP break when the Xtoolkit signals an error (via XtError()). When this resource is "true", Xtoolkit errors will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the error will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Setting the resource to "false" will cause WINTERP not to signal an XLISP break when the Xtoolkit signals an error (via XtError()); when this argument is specified, Xtoolkit errors will print an error message on stderr and cause WINTERP to exit. *** Winterp.enableXtWarningBreak: [false] By default, this resource is "FALSE", meaning that WINTERP will not signal an XLISP break when the Xtoolkit gives a warning (via XtWarning()) -- the error message will appear on stderr and execution will continue. When this resource is "TRUE", Xtoolkit warnings will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the warning will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Note that I've seen problems when setting enableXtWarningBreak: TRUE, thus the default value of FALSE. This is done because some XtWarnings were not meant to be broken out-of and can leave Motif in a weird state, causing possible subsequent strange behavior, core-dumps, etc. An example of this problem is associated with a Motif 1.1 popup menu bug. When a shell associated with a popup menu is destroyed, the following spurious warning is printed error: X Toolkit Warning: Attempt to remove non-existant passive grab When enableXtWarningBreak is set to TRUE, and the above warning occurs, subsequent attempts to close a window through the window manager will result in the error: XIO: fatal IO error 32 (Broken pipe) on X server... *** Winterp.enableXErrorBreak: [true] By default, WINTERP will signal an an XLISP break when the X server or X library signals an error (via XError()). When this resource is "true", X errors will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the error will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Setting the resource to "false" will cause WINTERP not to signal an XLISP break when the X library/server signals an error (via XError()); when this argument is specified, X errors will print an error message on stderr and cause WINTERP to exit. *** Winterp.enableStdinServer: [true] By default, this resource is set to "true", meaning that WINTERP listens for input on stdin, doing a read-eval-print for every s-expression entered. Setting this resource to "false" will disable the stdin eval server. Disabling the stdin server might be desired for standalone WINTERP-based applications, or to prevent errors on systems that don't support XtAppAddInput() on stdin. Note that this resource is only available on WINTERPs compiled with "-DWINTERP_WANT_STDIN_SERVER" *** Winterp.enableUnixServer: [true] By default, this resource is set to "true", meaning that WINTERP will set up a Unix Domain Socket for input to WINTERP's eval-server. Setting this resource to "false" will disable the eval-server. Note that this resource is only available on WINTERPs compiled "-DWINTERP_WANT_UNIX_SERVER" *** Winterp.unixSocketFilepath: [/tmp/.winterp_serv] This resource sets the pathname for the Unix Domain Socket eval-server. By default, ".unixSocketFilepath" is "/tmp/.winterp_serv", you may want to specify a different ".unixSocketFilepath" if multiple 'winterp' applications are running. Alternately, you may want to hide the Unix Domain Socket from other users if you are on a multi-user machine. Note that specifying environment variable WINTERP_UNIX_SOCKET_FILEPATH overrides ".unixSocketFilepath". Note that this resource is only available on WINTERPs compiled with "#define WINTERP_WANT_UNIX_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_UNIX_SERVER= -DWINTERP_WANT_UNIX_SERVER" in the makefiles. -DWINTERP_WANT_UNIX_SERVER is defined by default in WINTERP. *** Winterp.enableInetServer: [false] By default, this resource is set to "false", meaning that WINTERP will not set up a TCP/IP socket for input to WINTERP's eval-server. Setting this resource to "true" will enable the TCP/IP eval-server. Note that this resource is only available on WINTERPs compiled with "#define WINTERP_WANT_INET_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the makefiles. *** Winterp.servicePort: [23751] 23751 is the default port number of the TCP/IP server. If you change this, you'll also have to change the port number that the winterp client 'wl-tcp' uses to connect with WINTERP -- see the '-p' option of 'wl-tcpip'. Resource ".servicePort" in 'winterp' as well as the service-port used by 'wl-tcpip' may be set via environment variable WINTERP_INET_PORTNUM. Note that this resource is only available on WINTERPs compiled with "#define WINTERP_WANT_INET_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the makefiles. *** Winterp.serviceName: [widget_interp] "widget_interp" is the default service name for WINTERP's TCP/IP server if ".servicePort" is set to 0. This resource specifies the service name used by the TCP/IP server. Note that this resource is only available on WINTERPs compiled with "#define WINTERP_WANT_INET_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the makefiles. ** Usage: The WINTERP Lisp server (./../src-server/winterp): Calling the 'winterp' executable with appropriate arguments will invoke the WINTERP program itself and set up the eval-server according to the arguments described below. If invoked with no eval-servers enabled, WINTERP is running "standalone", running the Winterp-Lisp application described in the file argument to '-init_file' on the command-line (or equiv. resource). A 'stdin', 'unix-domain' and 'inet-domain' eval-server can be set up via resources or X defaults. WINTERP handles some UN*X signals: While evaluating, if a Control-C (SIGINT) is entered on WINTERP's controlling terminal, XLISP will abort back up to the top-level evaluator. This is useful for interrupting infinite loops, infinite recursions, and other errors where WINTERP may hang. If WINTERP is terminated with a SIGTERM or SIGHUP, it will clean-up after itself and exit. Other signals, such as SIGKILL, SIGQUIT are not handled, their receipt terminates WINTERP without cleaning up it's Unix-domain socket, etc. When WINTERP terminates, its exit status indicates the reason for termination: 0 -- normal termination 128 -- XLISP fatal error. 1-127 -- WINTERP killed by SIGNAL, the exit status number represents the signal number *** usage: winterp [-class ] [-init_file ] [-transcript_file ] [-lib_dir ] [-load_path <:-separated-list-of-paths-to-load-dir>] [-no_init_msgs] [-enable_init_msgs] [-init_message ] [-no_xterr_brk] [-enable_xterr_brk] [-no_xtwarn_brk] [-enable_xtwarn_brk] [-no_xerr_brk] [-enable_xerr_brk] #ifdef WINTERP_WANT_STDIN_SERVER [-no_stdin_server] [-enable_stdin_server] #endif /* WINTERP_WANT_STDIN_SERVER */ #ifdef WINTERP_WANT_INET_SERVER [-serv_port ] [-serv_name ] [-no_inet_server] [-enable_inet_server] #endif /* WINTERP_WANT_INET_SERVER */ #ifdef WINTERP_WANT_UNIX_SERVER [-no_unix_server] [-enable_unix_server] [-unix_socket_file ] #endif /* WINTERP_WANT_UNIX_SERVER */ [... Xtoolkit options ...] NOTE: the #ifdef/#endif bracketed portions above refer to options that are optionally built-in when WINTERP is compiled. By default, the WINTERP_WANT_INET_SERVER portions are not compiled in with WINTERP, but the WINTERP_WANT_UNIX_SERVER are. This is explained in more detail above in the section <> above. *** [-class ]: This optional argument pair must occur first in the list of command-line arguments. This argument pair tells winterp the name of the application defaults file to use (e.g. /usr/lib/X11/app-defaults/, and also sets the default class for all WINTERP top level shells. Note that should begin with a capital letter. If no [-class ] parameter is given, the application 'winterp' will default to class "Winterp" and will look for an application-default file in /usr/lib/X11/app-defaults/Winterp. *** [... Xtoolkit options ...]: 'winterp' works just like a standard Xtoolkit/Motif application, and handles all the command line options allowed by the Xtoolkit, e.g. -bg, -fg, -font -display, -geometry, -iconic, -title, -name, -xrm, etc... For more information on these options, see the X11r4 document "X Toolkit Intrinsics -- C Language Interface" chapter 2.3 "Parsing the Command Line". Alternately, see the appropriate watered down documentation provided in the Motif users guide. *** [-init_file ]: this optional argument tells WINTERP to load the Winterp-Lisp file upon startup. Setting this argument pair does the same thing as supplying the resource "Winterp.lispInitFile: " (see <> above for details). *** [-lib_dir ]: this optional argument pair sets the default path used by the Xlisp LOAD and REQUIRE primitive for loading files that are not qualified by a directory path. Setting this argument pair does the same thing as supplying the resource "Winterp.lispLibDir: " (see <> above for details). *** [-load_path <:-separated-list-of-paths-to-load-dir>]: this optional argument pair sets the search path used by LOAD and REQUIRE primitive for loading files without fully qualified pathnames. Setting this argument pair does the same thing as supplying the resource "Winterp.lispLoadPath: <:-separated-list-of-paths-to-load-dir>" (see <> above for details). *** [-transcript_file ]: this optional argument sets the file used by the Xlisp DRIBBLE primitive. Setting this argument pair does the same thing as supplying the resource "Winterp.lispTranscriptFile: " (see <> above for details). *** [-no_init_msgs]: specifying this argument prevents WINTERP from printing initialization messages to the standard output. Setting this argument does the same thing as supplying the resource "Winterp.enableInitMsgs: false" (see <> above for details). *** [-enable_init_msgs]: specifying this argument enables printing of initialization messages from WINTERP -- this is enabled by default. Setting this argument does the same thing as supplying the resource "Winterp.enableInitMsgs: true" (see <> above for details). *** [-init_message ]: Specifies the string displayed in the WINTERP "default window" which flashes on the screen when WINTERP start up. Setting this argument does the same thing as supplying the resource <>> (see <> above for details). NOTE: display of initialization message-box is is not disabled by "enableInitMsgs: FALSE" *** [-no_xterr_brk]: specifying this argument will cause WINTERP not to call an XLISP break when the Xtoolkit signals an error (via XtError()); when this argument is specified, Xtoolkit errors will print an error message on stderr and cause WINTERP to exit. Setting this argument does the same thing as supplying the resource "Winterp.enableXtErrorBreak: false" (see <> above for details). *** [-enable_xterr_brk]: specifying this argument will cause WINTERP to call an XLISP break when the Xtoolkit signals an error (via XtError()) -- this is enabled by default. When this argument is specified, Xtoolkit errors will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the error will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Setting this argument does the same thing as supplying the resource "Winterp.enableXtErrorBreak: true" (see <> above for details). *** [-no_xtwarn_brk]: specifying this argument will cause WINTERP not to call an XLISP break when the Xtoolkit gives a warning (via XtWarning()); when this argument is specified, Xtoolkit warnings will print an error message on stderr and continue executing. Setting this argument does the same thing as supplying the resource "Winterp.enableXtWarningBreak: false" (see <> above for details). *** [-enable_xtwarn_brk]: specifying this argument will cause WINTERP to call an XLISP break when the Xtoolkit gives a warning (via XtWarning()) -- this is enabled by default. When this argument is specified, Xtoolkit warnings will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the error will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Setting this argument does the same thing as supplying the resource "Winterp.enableXtWarningBreak: true" (see <> above for details). *** [-no_xerr_brk]: specifying this argument will cause WINTERP not to call an XLISP break when the X library/server signals an error (via XError()); when this argument is specified, X errors will print an error message on stderr and cause WINTERP to exit. Setting this argument does the same thing as supplying the resource "Winterp.enableXErrorBreak: false" (see <> above for details). *** [-enable_xerr_brk]: specifying this argument will cause WINTERP to call an XLISP break when the X signals an error (via XError()) -- this is enabled by default. When this argument is specified, X errors will print an error message and signal a Lisp error -- the Lisp call-sequence (or callback) that caused the error will terminate, however WINTERP will be able to execute other callbacks, input from the XLISP eval-server, etc. Setting this argument does the same thing as supplying the resource "Winterp.enableXErrorBreak: true" (see <> above for details). NOTE: The following command line options are only available if WINTERP was compiled with "#define WINTERP_WANT_STDIN_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_STDIN_SERVER= -DWINTERP_WANT_STDIN_SERVER" in the makefiles. By default, WINTERP compiles with the Unix Domain Socket server enabled, so these arguments will be available in the default WINTERP. *** [-no_stdin_server]: specifying this argument disables WINTERP's stdin eval-server. Setting this argument does the same thing as supplying the resource "Winterp.enableStdinServer: false" (see <> above for details). Disabling the stdin server might be desired for standalone WINTERP-based applications, or to prevent errors on systems that don't support XtAppAddInput() on stdin. *** [-enable_stdin_server]: specifying this argument enables WINTERP's stdin eval-server, which means that WINTERP/XLISP will attempt to interactively evaluate s-expressions typed into WINTERP's controlling terminal. Setting this argument does the same thing as supplying the resource "Winterp.enableStdinServer: true" (see <> above for details). NOTE: The following command line options are only available if WINTERP was compiled with "#define WINTERP_WANT_UNIX_SERVER" in file "./../src-server/config.h" or if WINTERP was compiled with "WANT_UNIX_SERVER= -DWINTERP_WANT_UNIX_SERVER" in the makefiles. By default, WINTERP compiles with the Unix Domain Socket server enabled, so these arguments will be available in the default WINTERP. *** [-no_unix_server]: specifying this argument disables WINTERP's Unix Domain Socket eval-server. Setting this argument does the same thing as supplying the resource "Winterp.enableUnixServer: false" (see <> above for details). *** [-enable_unix_server]: specifying this argument enables WINTERP's Unix Domain Socket eval-server -- this is the default. Setting this argument does the same thing as supplying the resource "Winterp.enableUnixServer: true" (see <> above for details). *** [-unix_socket_file ]: specifying this argument pair sets the Unix Domain Socket specified by . By default, is "/tmp/.winterp_serv", you may want to specify a different if multiple 'winterp' applications are running. Alternately, you may want to hide the Unix Domain Socket from other users if you are on a multi-user machine. Setting this argument does the same thing as supplying the resource "Winterp.unixSocketFilepath: " (see <> above for details). Note that specifying environment variable WINTERP_UNIX_SOCKET_FILEPATH overrides this command line argument (as well as resource ".unixSocketFilepath"). NOTE: The following command line options are only available if WINTERP was compiled with "#define WINTERP_WANT_INET_SERVER" in file "./../src-server/config.h", or if WINTERP was compiled with "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the makefiles. By default WINTERP does not compile with the TCP/IP server capabilities because they are a potential security hole. *** [-no_inet_server]: specifying this argument disables WINTERP's TCP/IP eval-server -- this is the default. Setting this argument does the same thing as supplying the resource "Winterp.enableInetServer: false" (see <> above for details). *** [-enable_inet_server]: specifying this argument enables WINTERP's TCP/IP eval-server. Setting this argument does the same thing as supplying the resource "Winterp.enableInetServer: true" (see <> above for details). *** [-serv_port ]: setting this optional argument pair does the same thing as supplying the resource "Winterp.servicePort: " (see <> above). Note that specifying environment variable WINTERP_INET_PORTNUM overrides this command line argument (as well as resource ".servicePort"). *** [-serv_name ]: setting this optional argument pair does the same thing as supplying the resource "Winterp.serviceName: " (see <> above). ** Usage: the WINTERP-Lisp Unix Domain Socket client (./../src-client/wl): *** usage: wl [-f ] [] The optional argument sets the pathname for the Unix Domain Socket eval-server. By default, is "/tmp/.winterp_serv", you may want to specify a different if multiple 'winterp' applications are running. Alternately, you may want to hide the Unix Domain Socket from other users if you are on a multi-user machine. Note that you may specify via environment variable WINTERP_UNIX_SOCKET_FILEPATH. The environment variable sets for both 'wl' and 'winterp'. The argument is a single Lisp s-expression to be sent to WINTERP's Lisp listener. If no argument is given, 'wl' sends an EOF (==Control-D) to XLISP, which causes WINTERP to terminate. Note that the must be quoted with ['] so that the shell does not attempt to interpret the parentheses as shell commands. 'wl' will "hang" waiting for WINTERP to finish the evaluation. When the evaluation completes, 'wl' prints the results of the evaluation to stdout, and returns exit status 0. If an error occurs in evaluation, an exit status of 128 is returned and the following is printed to stderr: "wl: an evaluation error occured in WINTERP server." Finally, if some other error occurs, e.g. network error, unable to bind socket, etc, then exit status of 1 is returned and an eror message will appear on stderr. If evaluation via 'wl' causes an error and *BREAKENABLE* is set (including by selecting "Error Break-Loop" or "Error Trace-Back" in the "WINTERP Control Panel), then 'wl' will hang until the break-loop exits, typically because the user has invoked functions 'clean-up', 'top-level', or 'continue', or typed Control-C or Control-D into WINTERP's controlling terminal. Example: invoking the following in a UN*X command shell: wl '(load "rc-shell")' while there is a WINTERP running with a unix domain socket enable, will cause WINTERP to load the file "rc-shell" and pop up the widgetry associated with loading that file. ** Usage: the WINTERP-Lisp TCP/IP client (./../src-client/wl-tcpip): *** usage: wl-tcpip [-h ] [-p ] [] The optional argument allows you to specify the host upon which the WINTERP's eval-server is running. By default, 'wl-tcpip' attempts to connect to a WINTERP server running at IP address 127.0.0.1. See the note below for further details. The hostname may also be specified by setting environment variable WINTERP_INET_HOSTNAME. The optional argument specifies a different port number for WINTERP's eval-server. The default is 23751; you may want to change the default (along with WINTERP's "Winterp.servicePort" resource) if 23751 is already defined in /etc/services. You will also need to change if you are running multiple instances of WINTERP on the same machine. You may "simultaneously" set the argument for 'wl-tcpip' as well as <> resource in 'winterp' by setting environment variable WINTERP_INET_PORTNUM to the desired port number. The argument is a single Lisp s-expression to be sent to WINTERP's Lisp listener. If no argument is given, 'wl' sends an EOF (==Control-D) to XLISP, which causes WINTERP to terminate. Note that the must be quoted with ['] so that the shell does not attempt to interpret the parentheses as shell commands. 'wl-tcpip' will "hang" waiting for WINTERP to finish the evaluation. When the evaluation completes, 'wl-tcpip' prints the results of the evaluation to stdout, and returns exit status 0. If an error occurs in evaluation, an exit status of 128 is returned and the following is printed to stderr: "wl-tcpip: an evaluation error occured in WINTERP server." Finally, if some other error occurs, e.g. network error, unable to bind socket, etc, then exit status of 1 is returned and an eror message will appear on stderr. If evaluation via 'wl-tcpip' causes an error and *BREAKENABLE* is set (including by selecting "Error Break-Loop" or "Error Trace-Back" in the "WINTERP Control Panel), then 'wl-tcpip' will hang until the break-loop exits, typically because the user has invoked functions 'clean-up', 'top-level', or 'continue', or typed Control-C or Control-D into WINTERP's controlling terminal. Example: invoking the following in a UN*X command shell: wl-tcpip '(load "rc-shell")' while there is a WINTERP running with an inet domain socket enabled, will cause WINTERP to load the file "rc-shell" and pop up the widgetry associated with loading that file. NOTE-0: 'wl-tcpip' is not compiled in the WINTERP distribution by default -- cd /src-client/ and do "cc -O -o wl-tcpip wl-tcpip.c" to compile it. Likewise, the 'winterp' binary itself does not compile with the TCP/IP server feature. To get the TCP/IP server, you must recompile WINTERP after setting "#define WINTERP_WANT_INET_SERVER" in ./../src-server/config.h, or you should set "WANT_INET_SERVER= -DWINTERP_WANT_INET_SERVER" in the appropriate makefiles. after recompilation run 'winterp' with the resource "Winterp.enableInetServer: true". NOTE-1: By default, 'wl-tcpip' uses the IP address 127.0.0.1 as the hostname. This is the standard "loopback" or localhost address on all UN*X machines I've worked with. If your setup defines hostname "localhost" as a different I.P. address, you may need to specify 'localhost' or `hostname` as . You may see significant speed increases in 'wl-tcpip' by replacing "127.0.0.1" in ./../src-server/config.h with the appropriate IP address and recompiling 'wl-tcpip.c' -- hostname lookup on some machines can be slow. If you are really concerned about the speed of making local connections, between 'winterp' and 'wl-tcpip', you should consider using 'wl' as described above. ============================================================================== * 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 ./../doc/xlisp.doc and ./../doc/XlispRef.doc for a more precise definition of the object system. Further examples may be found in file ./../doc/XlispOOP.doc, Tim Mikkelsen's "XLISP 2.0 OBJECTS PRIMER." 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 : (SEND :NEW ) 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 (SEND CLASS :NEW '( ... ) ['( ... )]) '( ... (ivarN>) are a list of symbols. Each names an instance variable of the class. '( ... )]) 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 : (SEND a_class_instance :ANSWER <:msg> ) where <:msg> is a keyword symbol (a symbol with a ':' prefix) representing the message; are the arguments given along with the message. See the documentation on "lambda lists" in winterp/doc/xlisp.doc for details. 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 :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 its *parent class* (aka, the *superclass*): (send Class :NEW '( ... ) '( ... ) ) ( ... ) is a list of new instance variables in the subclass; ( ... ) is a list of new class variables in the subclass; 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: The current implementation of the Motif widget class xmListWidgetClass makes it less-than-straightforward to create "browsers" of dynamic information. 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 array 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 'thing' was 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 'thing' 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 from superclass : (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 will contain an instance variable 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 to the list of arbitrary objects to be displayed. 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 ;; ;; ) ;; is a list of BROWSER_OBJECTs as described above. ;; -- a keyword, either :MANAGED or :UNMANAGED ;; -- a STRING giving the X-resource name for the widget ;; -- a WIDGET, the parent managing this widget. ;; -- these are the arguments that ;; will be passed on to the list widget ;; (send List_Browser :answer :ISNEW '(items_list managed_k widget_name widget_parent &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 (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)) ) ;; Call :ISNEW on the XM_LIST_WIDGET_CLASS superclass; ;; This actually creates the Motif widget, by calling ;; XmCreateScrolledList()... (apply #'send-super :isnew managed_k :scrolled widget_name widget_parent :XMN_SELECTION_POLICY :browse_select :XMN_ITEMS display_items :XMN_ITEM_COUNT items_end_idx args) ) ;; 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 XmCreateScrolledList(). The APPLY of '&rest args' allow us to splice in the optional sequence of X-resource name/value pairs passed to the :ISNEW method to the superclass :ISNEW method 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 to correspond with the items displayed. We do this by intercepting those messages to the superclass of class and handle them in 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 some of the examples programs in WINTERP's examples directory. The directory ./../examples/lib-widgets/ contains a number of subclassed widgets which give other examples of the kinds of things you can do with WINTERP's object oriented programming features. In particular: ** ./../examples/lib-widgets/application.lsp: Defines WINTERP:APPLICATION-WIDGET-CLASS a subclass of XM_MAIN_WINDOW_WIDGET_CLASS which encapsulates most of the framework for creating applications, including the simple creation of menubars, a message area, etc. An example of using WINTERP:APPLICATION-WIDGET-CLASS is ./../examples/lib-widgets/fake-app1.lsp. ** ./../examples/lib-widgets/object-br.lsp: Defines Object_Browser_Widget_Class, which is a subclass of String_Browser_Widget_Class, which in turn is a subclass of XM_LIST_WIDGET_CLASS. Object_Browser_Widget_Class is useful for creating information browsers over collections of objects. Example uses include ./../examples/grep-br.lsp which provides a file search browser based on the UN*X "grep" command; ./../examples/mail-br.lsp is a simple mail browser based on the MH scan command; ./../examples/dircmp.lsp is a directory and file comparison browser based on UN*X commands "cmp" and "diff". ** ./../examples/lib-widgets/simple-RC.lsp: Defines WINTERP:RADIO-BOX-WIDGET-CLASS, WINTERP:OPTION-MENU-WIDGET-CLASS, WINTERP:MENU-BAR-WIDGET-CLASS, WINTERP:POPUP-MENU-WIDGET-CLASS, WINTERP:PULLDOWN-MENU-WIDGET-CLASS, WINTERP:CHECK-BOX-WIDGET-CLASS. These provide for simplified creation of common UI functions. ============================================================================== * UN*X Subprocesses: #ifdef WINTERP_EXPECT_SUBPROCESS The 'expect' library in WINTERP provides the ability to control multiple asynchronous UN*X subprocesses. The subprocesses talk to the WINTERP process through ptys; WINTERP and XLISP can read/ write to the pty, which appears as a bidirectional stream to any stream primitive. See also routines XT_ADD_INPUT/:READ_LINE_TO_STRING and XT_ADD_INPUT/:READ_SEXP_TO_USTREAM. Examples using subprocesses: ** winterp/examples/subcalc.lsp: Demo of spawning an interactive subprocess and interacting with the subrpocess through XT_ADD_INPUT/:READ_LINE_TO_STRING. Subprocess can be off doing a long calculation while WINTERP GUI remains active. ** winterp/examples/subshell.lsp: Demo of spawning an interactive shell subprocess and interacting with the subrpocess through XT_ADD_INPUT. Subprocess can be off doing a long computation while WINTERP GUI remains active. ** winterp/examples/modem-dialer.lsp: Dials phone numbers on a Hayes-Compatible modem by running kermit(1) as an asynchronous subprocess. Hayes-compatible commands may be sent to the modem directly by entering text in the edit-field widget directly below the menu bar. The app. provides a browser of people/phone-numbers -- in the browser, double-left click (or single-middle click) on the person to dial his/her number (details on mouse and key bindings below). Put your database of people in file "$HOME/people.lsp" (see variable *MODEM-DIALER-FILEPATH* below) ** winterp/examples/lib-widgets/clock-disp.lsp: Define Clock_Display_Widget_Class, a subclass of XM_LABEL_GADGET_CLASS which displays the time in Month/Date/Year Hour:Minute format. This makes use of the Unix 'date' command "date '+\#(%y %m %d %H %M)'" -- if this doesn't work on your system, it's because your unix isn't SVID2, XPG2, XPG3, or POSIX.2 compliant and can't understand the special '+' formatting option for 'date'. ** Function EXP_SPAWN (exp_spawnv()): (EXP_SPAWN [ [[] ...] ) --> returns a STREAM (with no buffering, however) returns NIL if an error occurs... -- a string, the full path and name of the executable. -- a string corresponding to argv[0] in the spawned executable, this should typically be the same as . -- optional string arguments corresponding to argv[i] passed to the spawned executable. Call EXP_GET_PID after calling EXP_SPAWN to find out process ID. To shut down the subprocess, call CLOSE on the returned STREAM, followed by a call to EXP_WAIT. Prior to calling EXP_SPAWN, if EXP_STTY_INIT is called, the string arg to that function is interpreted in the style of stty(1) arguments as further configuration for any pty used by future spawn commands. For example, exp_stty_init = "sane" repeats the default initialization. If EXP_STTY_INIT was never called prior to calling EXP_SPAWN, then the pty is initialized the same way as the user's tty. When this is not possible (i.e., expect was not started with a controlling terminal), spawn uses the tty settings that correspond to "stty sane". Note: it is ok to write to the EXP_SPAWN-created subprocess with FORMAT, PRINT, PRIN1, PRINC PPRINT, TERPRI, WRITE-CHAR, and WRITE-BYTE. However, one must be very careful in reading from the STREAM created by EXP_SPAWN -- because you can't know how many characters are "ready for reading", you shouldn't use READ, READ-LINE, FSCANF-FIXNUM FSCANF-FLONUM or FSCANF-STRING because they might cause WINTERP to lock-up waiting to read a character that may never arrive. For reading, you should use XT_ADD_INPUT/:READ, XT_ADD_INPUT/:READ_LINE_TO_STRING, or XT_ADD_INPUT/:READ_SEXP_TO_USTREAM. Description of exp_spawnv: ------------------------- exp_spawnv forks a new process so that its stdin, stdout, and stderr can be written and read by the current process. file is the name of a file to be executed. The arg pointers are null-terminated strings. Following the style of execve(), arg0 (or argv[0]) is customarily a duplicate of the name of the file. If the process is successfully created, a file descriptor is returned which corresponds to the process's stdin, stdout and stderr. A stream may be associated with the file descriptor by using fdopen(). (This should almost certainly be followed by setbuf() to unbuffer the I/O.) Closing the file descriptor will typically be detected by the process as an EOF. Once such a process exits, it should be waited upon (via wait) in order to free up the kernel process slot. (Some systems allow you to avoid this if you ignore the SIGCHLD signal). After a process is started, the variable exp_pid is set to the process-id of the new process. The spawn functions uses a pty to communicate with the process. By default, the pty is initialized the same way as the user's tty. When this is not possible (i.e., expect was not started with a controlling terminal), spawn uses the tty settings that correspond to "stty sane". If the variable exp_stty_init is defined, it is interpreted in the style of stty arguments as further configuration for any pty used by future spawn commands. For example, exp_stty_init = "sane"; repeats the default initialization. ** Function EXP_POPEN (exp_popen()): (EXP_POPEN ) --> returns a STREAM (FILE*) or NIL Unlike POPEN, EXP_POPEN allows for reading/writing to the subprocess; executing doesn't block WINTERP. Call EXP_GET_PID after calling EXP_POPEN to find out process ID. To shut down the subprocess, call CLOSE on the returned STREAM, followed by a call to EXP_WAIT. Prior to calling EXP_POPEN, if EXP_STTY_INIT is called, the string arg to that function is interpreted in the style of stty(1) arguments as further configuration for any pty used by future spawn commands. For example, exp_stty_init = "sane" repeats the default initialization. If EXP_STTY_INIT was never called prior to calling EXP_POPEN, then the pty is initialized the same way as the user's tty. When this is not possible (i.e., expect was not started with a controlling terminal), spawn uses the tty settings that correspond to "stty sane". Note: it is ok to write to the EXP_SPAWN-created subprocess with FORMAT, PRINT, PRIN1, PRINC, PPRINT, TERPRI, WRITE-CHAR, and WRITE-BYTE. However, one must be very careful in reading from the STREAM created by EXP_SPAWN -- because you can't know how many characters are "ready for reading", you shouldn't use READ, READ-LINE, FSCANF-FIXNUM FSCANF-FLONUM or FSCANF-STRING because they might cause WINTERP to lock-up waiting to read a character that may never arrive. For reading, you should use XT_ADD_INPUT/:READ, XT_ADD_INPUT/:READ_LINE_TO_STRING, or XT_ADD_INPUT/:READ_SEXP_TO_USTREAM. Description of exp_popen: ------------------------- Similar to exp_spawnv above, exp_popen is yet another interface, styled after popen(). It takes a Bourne shell command line, and returns a stream that corresponds to the process's stdin, stdout and stderr. ** Function EXP_GET_PID (exp_pid): (EXP_GET_PID) --> FIXNUM representing the process ID of the last EXP_POPEN or EXP_SPAWN. Description of exp_pid: ----------------------- After a process is started, the variable exp_pid is set to the process-id of the new process. (EXP_GET_PID) retrieves that value. ** Function EXP_STTY_INIT (exp_stty_init): (EXP_STTY_INIT ) --> returns NIL. If EXP_STTY_INIT is called prior to calling EXP_POPEN or EXP_SPAWN, is interpreted in the style of stty(1) arguments as further configuration for any pty used by future EXP_POPEN or EXP_SPAWN commands. For example, (EXP_STTY_INIT "sane") -- repeats the default initialization. (EXP_STTY_INIT "-echo -echoe -echok") -- turns off echoing of text written to the subprocess. If EXP_STTY_INIT was never called prior to calling EXP_POPEN or EXP_SPAWN, then the pty is initialized the same way as the user's tty. When this is not possible (i.e., WINTERP was not started with a controlling terminal), spawn uses the tty settings that correspond to "stty sane". ** Function EXP_WAIT (wait(2)): (EXP_WAIT) --> returns dotted pair (pid . exit-status) on success; returns dotted pair (-1 . sys_errlist[errno]) on failure. Call this after calling CLOSE on stream returned by EXP_SPAWN or EXP_POPEN. If the process hasn't existed or gotten killed (see EXP_KILL), this call will hang. Interrupt WINTERP with ^C from the controlling terminal to unhang an erroneous EXP_WAIT. ** Function EXP_KILL (kill(2)): (EXP_KILL ) --> returns NIL Calls kill(2) returning NIL if successful. Signals an error otherwise. See kill(2) for details/semantics. is either a FIXNUM or a STRING. See "/usr/include/sys/signal.h" on your system for appropriate values for . Alternately, you can specify a STRING name for the signal -- the string name is the same as the SIG* names in "/usr/include/sys/signal.h", but without the "SIG" prefix. For example (EXP_KILL "INT") sends a SIGINT to . is a FIXNUM representing a process ID. Process id FIXNUMs are returned, for example, by EXP_GET_PID. #endif /* WINTERP_EXPECT_SUBPROCESS */ ** Function POPEN: (POPEN :direction ) is a string which is sent to shell /bin/sh and is executed as command. a keyword symbol, :input means a stream is created that reads from stdout of ; :output means a stream is created that writes to stdin of . (:input is the default.) returns a stream, or NIL if the pipe or /bin/sh process couldn't be created. This function start a process and open a pipe as a read/write stream. ** Function PCLOSE: (PCLOSE ) a stream object created by POPEN returns T if the command executed successfully, else returns the integer exit status of . This function closes a pipe stream as opened by POPEN. ** Function SYSTEM: (SYSTEM ) is a string which is sent to shell /bin/sh and is executed as command. returns T if the command executed successfully, else returns the integer exit status of . This function runs a process, sending output (if any) to stdout/stderr. ============================================================================== * Input callbacks -- call callback when input available for reading: XT_ADD_INPUT in WINTERP extends the functionality of interfacing to files, pipes, fifos, sockets, subprocesses, etc. :READ_LINE_TO_STRING option for XT_ADD_INPUT simplifies interfacing to line-oriented data sources. :READ_SEXP_TO_USTREAM facilitates communications between lisp programs. The former fires a callback once per line of input, whereas the latter fires a callback once per complete Lisp s-expression (matching levels of parentheses). Examples utilizing XT_ADD_INPUT include: ** winterp/examples/xtaddinput.lsp: ** winterp/examples/fifo-read.lsp: See also the following examples discussed above: <> <> <> <> ** XT_ADD_INPUT (XtAppAddInput()): This primitive takes two forms of arguments: (XT_ADD_INPUT ) or --> returns: (XT_ADD_INPUT ) --> returns: is a XLISP stream (not a u-stream though). There are three possibilities for : (1) == {:READ, :WRITE, :EXCEPT} These correspond to XtAppAddInput() options XtInputReadMask, XtInputWriteMask, XtInputExceptMask options: :READ -- input-fd is ready to be read. The reader must be a nonblocking read, e.g. 'read-char', 'read-byte', 'fscanf-string'. WARNING: do not use 'read-line' or 'read' as these will cause WINTERP to deadlock, requiring you to kill the process! :WRITE -- input-fd is ready to be written (this is almost always true -- there's really no reason to use XT_ADD_INPUT/:write). :EXCEPT -- an exception condition has occured on input-fd. (2) == :READ_LINE_TO_STRING In this case, will get called with symbol FDINPUTCB_STRING bound to a string representing a line of text. Use this to read text from a stream line-by-line, calling only once per line read from . Note: this routine will signal an error if the line being read ends up being longer than 1023 characters. (3) == :READ_SEXP_TO_USTREAM In this case, will get called with symbol FDINPUTCB_USTREAM bound to an unnamed stream representing the s-expression just read. This option may be used to read-in parentheses-bounded expressions, calling only once per read s-expression. Within one can pass the value of FDINPUTCB_USTREAM on to 'READ' for parsing, 'GET-OUTPUT-STREAM-STRING' to return a string representation of the s-expr, etc. is a list of lisp expressions that are evaluated when the fdinputcb occurs. During the fdinputcb, the lexical environment that existed for the call to XT_ADD_INPUT will be used for value and functional bindings. Additionally, the symbol FDINPUTCB_OBJ is bound to the that caused the fdinputcb. FDINPUTCB_FILE is bound to argument from the call to XT_ADD_INPUT. Additionally, FDINPUTCB_STRING or FDINPUTCB_USTREAM may get bound if is :READ_LINE_TO_STRING or :READ_SEXP_TO_USTREAM. The form (XT_ADD_INPUT ) may be used to more efficiently reschedule previously removed fdinputcbs. Instead of creating a new closure around the same each time a recurrent fdinputcb is rescheduled, this second form for XT_ADD_INPUT allows you to take the from a previously removed fdinputcb and reschedule a new fdinputcb using the closure setup by the initial call to (XT_ADD_INPUT ). During the execution of , the symbol FDINPUTCB_OBJ is bound to so that you don't need to keep around a global variable for each recurrent fdinputcb. The returned may be passed into the functions (XT_REMOVE_INPUT ), or (XT_ADD_INPUT ). WARNING: prior to closing associated with a XT_ADD_INPUT, once must call XT_REMOVE_INPUT on the . Likewise in for subprocesses, one should remove the input callback and close the associated if the associated subprocess exits. ** XT_REMOVE_INPUT (XtRemoveInput()): (XT_REMOVE_INPUT ) --> returns T. is the value returned by XT_ADD_INPUT. This routine removes an input callback previously scheduled with XT_ADD_INPUT. ** INPUT_ACTIVE_P : (INPUT_ACTIVE_P ) --> returns T if is still scheduled, returns NIL if input source was deactivated by XT_REMOVE_INPUT. is the value returned by XT_ADD_INPUT. ============================================================================== * XLISP STREAM EXTENSIONS: ** Function FSCANF-FIXNUM: (FSCANF-FIXNUM ) a stream object created via OPEN or POPEN. Will give an error for "unnamed streams". a format string containing a single conversion directive that will result in an integer valued conversion %d, %u, %o, %x, %ld, %lu, %lo and %lx style conversions are acceptable for this routine. See the manual page for fscanf(3x) for details. returns an integer if fscanf(3x) reports that the conversion specified by succeeded. Returns NIL if the conversion wasn't successful, or if EOF was reached. This function reads a fixnum value from a stream using fscanf(3x). WARNING: specifying a that will result in the conversion of a result larger than sizeof(long) will result in corrupted memory and core dumps. ** Function FSCANF-STRING (FSCANF-STRING ) a stream object created via OPEN or POPEN. Will give an error for "unnamed streams". a format string containing a single conversion directive that will result in a string valued conversion. %s, %c, and %[...] style conversions are acceptable for this routine. See the manual page for fscanf(3x) for details. returns a string if fscanf(3x) reports that the conversion specified by succeeded. Returns NIL if the conversion wasn't successful, or if EOF was reached. This function reads a string value from a stream using fscanf(3x). WARNING: specifying a that will result in the conversion of a result larger than 1024 characters will result in corrupted memory and core dumps. ** Function FSCANF-FLONUM: (FSCANF-FLONUM ) a stream object created via OPEN or POPEN. Will give an error for "unnamed streams". a format string containing a single conversion directive that will result in a FLONUM valued conversion. %e %f or %g are valid conversion specifiers for this routine. See the manual page for fscanf(3x) for details. returns a float if fscanf(3x) reports that the conversion specified by succeeded. Returns NIL if the conversion wasn't successful, or if EOF was reached. This function reads a float from a stream using fscanf(3x). WARNING: specifying a that will result in the conversion of a result larger than sizeof(float) will result in corrupted memory and core dumps. ** Function FFLUSH: (FFLUSH ) --> returns T on success, else error Calls fflush(3S) on ** Function REDIRECT_STDERR: (REDIRECT_STDERR) --> returns an input-stream suitable for reading. The returned input-stream represents the text sent to the unix standard error (stderr), both for the WINTERP application and for any subprocesses invoked by WINTERP. This is typically used to trap error output from subprocesses and pop up a dialog indicating a problem. The stream can be used for reading by existing XLISP/WINTERP reading primitives, e.g. READ-LINE, READ-CHAR, FSCANF-FIXNUM, FSCANF-STRING, FSCANF-FLONUM, etc. The returned input-stream is non-blocking, which means you may read more than one character at a time without worrying about a deadlock. However, note that just because you've been able to read N characters in one read operation, doesn't mean you've read all characters output on STDERR. To retrieve the full contents, you need to keep on reading until you've hit EOF. Instead of polling the stream (till hitting EOF) to see if more chars have been read, it is better to add an input callback via XT_ADD_INPUT and have the callback code read from the input-stream whenever there are characters to be read. ** Function REDIRECT_STDOUT: (REDIRECT_STDOUT) --> returns an input-stream suitable for reading. This is just like REDIRECT_STDERR except that the returned input-stream represents the text sent to the unix standard output (stdout). ============================================================================== * XLISP extensions: ** Function LOAD: Just a note on the way files are searched for from the XLISP 'LOAD' primitive. When a Winterp-Lisp file is 'LOAD'ed, the following path searching occurs in looking for the file to load. If the file begins with a '/' or '.' then that file is loaded, otherwise, the following search behavior takes place: (1) The Unix environment variable "XLPATH" is consulted and searched. XLPATH is a colon-separated sequence of paths. (2) if that isn't set, the X resource Winterp.lispLoadPath is consulted to retrieve a sequence of paths comprised of colon-separated paths (e.g. /users/mayer/:/users/mayer/tmp:/users/mayer/winterp/). This path is then searched. (3) If the file isn't found on that path, the resource <> is consulted to find another directory for the module. That directory is searched. (4) Finally, if the file isn't found anywhere on the aforementioned paths, the current directory is searched for the requested file. (5) Finally, if no file is found, LOAD returns NIL. ** Function REQUIRE: (REQUIRE ) --> returns T if the requested module got loaded from a file. returns NIL if the requested module had previously been loaded (that is, (PROVIDE ) had been called). If the module couldn't be loaded, will signal an error. is a STRING, specifying the name of the file to load. can be the full path to the file (e.g. "/users/mayer/foo.lsp"), or a filename plus extension (e.g. "lib-utils/unixstuf.lsp", or "foo.lsp"), or a filename without extension (e.g. "lib-utils/unixstuf" or "foo"). REQUIRE is typically used to load "libraries" in WINTERP. Library files which are to be loaded by REQUIRE should have a (PROVIDE ) at the end which tells REQUIRE the desired module has been loaded succesfully. REQUIRE will not load a file which has previously been PROVIDED, thus achieving the effect of only loading a given module once, even if a particular module is REQUIRE'd multiple times throughout the files that comprise a given application. When REQUIRE determines that hasn't previously been loaded, it uses the same mechanism and load paths as used by the XLISP LOAD command. First, the Unix environment variable "XLPATH" is consulted; if that isn't set, the X resource Winterp.lispLoadPath is consulted to retrieve a sequence of paths comprised of colon-separated paths (e.g. /users/mayer/:/users/mayer/tmp:/users/mayer/winterp/). If the required module isn't found on that path, the resource Winterp.lispLibDir is consulted to find another directory for the module. Finally, if the required module isn't found anywhere on the aforementioned paths, the current directory is searched for the requested file. If no file is found, an XLISP error is signalled. Note that (REQUIRE "lib-utils/unixstuf.lsp") will load file "unixstuf.lsp" even if (PROVIDE "lib-utils/unixstuf") had been called by a previous successful LOAD or REQUIRE of that file. (REQUIRE "lib-utils/unixstuf.lsp") will load the same file twice, because "lib-utils/unixstuf.lsp" is not equal to "lib-utils/unixstuf". To avoid confusion on this you should always specify for PROVIDE and REQUIRE without the ".lsp" extension -- ".lsp" is the filename that will get loaded by (REQUIRE )... The global variable *MODULES* is set to a list of which have been previously PROVIDE'd... ** Function PROVIDE: (PROVIDE ) --> returns NIL if has already been PROVIDE'd; T if wasn't previously PROVIDE'd. is a STRING, specifying the name of a module/file that has been loaded succesfully. is typically a filename plus extension (e.g. "lib-utils/unixstuf.lsp", or "foo.lsp"), or a filename without extension (e.g. "lib-utils/unixstuf" or "foo"). PROVIDE and REQUIRE are typically used to load "libraries" in WINTERP. Library files which are to be loaded by REQUIRE should have a (PROVIDE ) at the end which tells REQUIRE the desired module has been loaded succesfully. REQUIRE will not load a file which has previously been PROVIDED, thus achieving the effect of only loading a given module once, even if a particular module is REQUIRE'd multiple times throughout the files that comprise a given application. Note that (REQUIRE "lib-utils/unixstuf.lsp") will load file "unixstuf.lsp" even if (PROVIDE "lib-utils/unixstuf") had been called by a previous successful LOAD or REQUIRE of that file (REQUIRE "lib-utils/unixstuf.lsp") will load the same file twice, because "lib-utils/unixstuf.lsp" is not equal to "lib-utils/unixstuf". To avoid confusion on this you should always specify for PROVIDE and REQUIRE without the ".lsp" extension -- ".lsp" is the filename that will get loaded by (REQUIRE )... The global variable *MODULES* is set to a list of which have been previously PROVIDE'd... ** Function COPY-ARRAY: (copy-array []) COPY INTO A PREALLOC'd ARRAY the array to copy from the array to copy to, preallocated by MAKE-ARRAY the integer offset in for beginning the copy If is omitted, this defaults to 0. returns . ** Function ARRAY-INSERT-POS: (array-insert-pos ) INSERT A NEW ELEMENT IN ARRAY an array into which we want to insert a new element the integer index in for inserted element; < 0 will cause the new element to be appended. any lisp value returns a new array that is one element longer than ; ** Function ARRAY-DELETE-POS: (array-delete-pos ) DELETE AN ELEMENT FROM AN ARRAY an array into which we want to delete an element the integer index for the element to delete in ; < 0 will delete the last element of the array. returns a new array that is one element shorter than ** Function READ_EVAL_PRINT: (READ_EVAL_PRINT ) --> returns T if success, NIL if hit EOF, or FIXNUM if error. This gives programmatic access to the top-level read/eval/print routine. By top-level, I mean that it will act like the top-level R.E.P w/r/t using the global environment and setting up error and breakloop returns. ** Function TRACE (new names to trace): (TRACE ) The XLISP trace function prints information prior and subsequent to calling the code associated with . WINTERP extends XLISP trace by permitting to be one of the following symbols: (1) a callback resource-name keyword, e.g. (trace :XMN_ACTIVATE_CALLBACK) -- any time an activate callback fires in any widget, some information is printed on the callback, the associated call_data symbols, etc. (2) EVHANDLER: an event handler, set up by method WIDGET_CLASS/:ADD_EVENT_HANDLER, e.g.: (trace EVHANDLER) -- any time an event-handler fires, info is printed. (3) FDINPUTCB: An input callback, from XT_ADD_INPUT, e.g. (trace FDINPUTCB) -- any time an input callback fires, info is printed. (4) XT_TIMEOUT: A timeout, from XT_ADD_TIMEOUT, e.g. (trace XT_TIMEOUT) -- any time a timeout callback fires, info is printed. (5) LISP_ACTION_PROC: A "Lisp()" action procedure, e.g. (trace LISP_ACTION_PROC) -- prints info any time the "Lisp()" action procedure fires from an entry in a widget translation or accelerator table. ** Function TYPEP, COERCE, TYPE-OF (new XLISP-PLUS primitive types): These functions now accept the following new primitive types added to XLISP-PLUS by WINTERP: CALLBACK_OBJ EVHANDLER_OBJ FDINPUTCB_OBJ PIPE PIXEL PIXMAP PIXMAP_REFOBJ (an internal object...) TANGOIMAGE_OBJ TANGO_PATH TANGO_TRANS TIMEOUT_OBJ WIDGET_OBJ WINDOW XEVENT XIMAGE XM_FONT_LIST (not implemented) XM_STRING XT_ACCELERATORS XT_RESOURCE (an internal object...) XT_TRANSLATIONS ============================================================================== * XT_ADD_TIMEOUT / XT_REMOVE_TIMEOUT == XtAppAddTimeout() / XtRemoveTimeout() (XT_ADD_TIMEOUT ) --> returns a is a FIXNUM, the number of milliseconds before the timeout fires. is a list of Lisp expressions that are evaluated when the timeout occurs. During the timeout, the lexical environment that existed for the call to XT_ADD_TIMEOUT will be used for value and functional bindings. Additionally, the symbol TIMEOUT_OBJ is bound to the timeout object that caused the timeout. A variant of the above form allows efficient scheduling of recurrent timeouts when called from within (XT_ADD_TIMEOUT TIMEOUT_OBJ) Instead of creating a new closure around the same each time a recurrent timeout is rescheduled, this second form for XT_ADD_TIMEOUT allows you to take the TIMEOUT_OBJ from a previously expired timeout and reschedule a new timeout using the closure setup by the initial call to (XT_ADD_TIMEOUT ). During the execution of , the symbol TIMEOUT_OBJ is bound to so that you don't need to keep around a global variable for each recurrent timeout. The timeout scheduled by XT_ADD_TIMEOUT may be removed by passing into the primitive XT_REMOVE_TIMEOUT: (XT_REMOVE_TIMEOUT ) is the value returned by XT_ADD_TIMEOUT. To test whether the timeout associated with a has expired, use: (TIMEOUT_ACTIVE_P ) --> returns T if is still scheduled; returns NIL if has expired or if the timeout was inactivated by XT_REMOVE_TIMEOUT. ============================================================================== * Widget Primitives: ** Function WIDGETOBJP: (WIDGETOBJP ) --> returns T if argument is a WIDGETOBJ, else NIL. WIDGETOBJP is a type predicate testing to see if a value is a widget or gadget object. ** XT_MANAGE_CHILDREN == XtManageChildren(): (XT_MANAGE_CHILDREN ) --> returns T. Given , an ARRAY or list of WIDGETOBJs, all of which must be children of the same parent, this primitive will add those widgets to their parent-widget's managed list, which means they will become visible (if mapped) and will take up space within the managing widget. If the shell widget ancestor of has been :REALIZE'd, calling XT_MANAGE_CHILDREN on a sequence of child widgets is more efficient than specifying the :MANAGED option to each child-widget creation form, or sending the :MANAGE message to each child-widget created. Note that the efficiency argument above is moot if the shell widget ancestor of has not been :REALIZE'd. An error will be signaled if the widgets passed to this routine do not all have the same parent. ** XT_UNMANAGE_CHILDREN == XtUnmanageChildren(): (XT_UNMANAGE_CHILDREN ) --> returns T. Given , an ARRAY or LIST of WIDGETOBJs, all of which must be children of the same parent, this primitive will remove those widgets from their parent-widget's managed list, which means they will no longer be visible or take up space. Calling XT_UNMANAGE_CHILDREN on a sequence of child widgets is more efficient than sending the :UNMANAGE message to each child-widget. An error will be signaled if the widgets passed to this routine do not all have the same parent. #ifdef MOTIF_1.2 ** Function XM_GET_DESTINATION (XmGetDestination()) [Motif >= 1.2 only]: (XM_GET_DESTINATION) --> Returns a WIDGETOBJ, "the widget to be used as the current destination for quick paste and certain clipboard operations." Returns NIL if "there is no current destination". See XmGetDestination.3X manual page for details. #endif /* MOTIF_1.2 */ ** GET_MOUSED_WIDGET -- primitive for visually interacting with widgets. (GET_MOUSED_WIDGET) --> returns the WIDGETOBJ designated by the user. Evaluating GET_MOUSED_WIDGET will change the cursor to a crossbar, indicating that the user is to 'click' the mouse on a widget managed by WINTERP. GET_MOUSED_WIDGET will then return the WIDGETOBJ corresponding to the selected widget. You can use this primitive to visually alter widgets displayed by WINTERP, for example, evaluating the following form will invert the colors on any widget you click (note -- you can't change the colors on a gadget): (let ((widget (get_moused_widget)) foreground background ) (send widget :get_values :XMN_FOREGROUND 'foreground :XMN_BACKGROUND 'background ) (send widget :set_values :XMN_FOREGROUND background :XMN_BACKGROUND foreground )) You may use this primitive for sending arbitrary messages to arbitrary widgets "visually". This primitive can be used to implement "builder-like" and "hypercard-like" features with WINTERP. For additional examples using this primitive, see ./../examples/interact.lsp Note: GET_MOUSED_WIDGET will work on any kind of widget, not only widgets created at the Lisp level in WINTERP. This means that you can use it to modify widgets inside a composite widget (e.g., the scrollbar in a scrolled text or list widget). Furthermore, if you take an existing C-implemented Motif application and link it in with WINTERP such that your application uses WINTERP's event handling loop in main(), then you can use GET_MOUSED_WIDGET to modify the widgets created in your own C-implemented application code! KNOWN BUG -- you cannot use get_moused_widget primitive on widgets within a menu system. Even if you manage to post a menu that stays posted and then call this function, the "grab" from the menu prevents this primitive from working... Note: if you are using Motif 1.1 and want GET_MOUSED_WIDGET's functionality with the additional ability to control the mouse sprite, see also XM_TRACKING_LOCATE. #ifdef MOTIF_1.1 ** XM_TRACKING_LOCATE == XmTrackingLocate() [Motif >= 1.1 only]: (XM_TRACKING_LOCATE []) --> Returns a WIDGETOBJ that was selected by the user. Returns NIL if the window of the buttonpress is not a widget. "XmTrackingLocate provides a modal interface for selection of a component. It is intended to support context help. The function grabs the pointer and returns the widget in which a button press occurs." (taken from XmTrackingLocate.3X man-page). is the widget "to use as the basis of the modal interaction" specifies the shape of the cursor for this interaction. the value of this FIXNUM specifies a font whose name/value is defined in /usr/include/X11/cursorfont.h. For example Use FIXNUM value 34 to define a cross-hair (#define XC_crosshair 34). If the last arg supplied, , is non-NIL, then the interaction will be confined to . If this arg is not supplied, is treated as NIL. Note: See also WINTERP's GET_MOUSED_WIDGET primitive, which offers similar functionality to XM_TRACKING_LOCATE but predates it (XM_TRACKING_LOCATE is new to Motif 1.1). #endif /* MOTIF_1.1 */ ============================================================================== * X Location Primitives: ** GET_MOUSE_LOCATION == XQueryPointer(): (GET_MOUSE_LOCATION) --> returns dotted pair (root-x . root-y) representing the x,y location of the mouse sprite with respect to the root window. To access root-x, use 'car' and to access root-y, use 'cdr'. ** GET_EVENT_COORDS (GET_EVENT_COORDS ) --> Returns ( . ) or signals error is an XEvent* as returned via symbol CALLBACK_XEVENT (bound via :ADD_CALLBACK or :SET_CALLBACK method), ACTION_XEVENT (bound in in the Lisp(...) ActionProc from a translation table), and EVHANDLER_XEVENT (bound via :ADD_EVHANDLER or :SET_EVHANDLER method). TODO: add GET_EVENT_BUTTON, GET_EVENT_TIME, etc?, and remove EVHANDLER_TIME and EVHANDLER_BUTTON symbols from XtAddEventHandler()? ============================================================================== * Xt Translation and Accelerators: ** Action Procedure Lisp() -- call XLISP evaluator from a translation table. WINTERP has a built-in ActionProc named "Lisp" that allows you to call arbitrary Lisp functions from a translation or accelerator table. The arguments passed on to ActionProc "Lisp" become the elements in the Lisp form passed on to the evaluator when the action is fired. For example, a translation/accelerator table containing an entry ": Lisp(Lisp-function arg1 arg2 arg3)" will end up evaluating the Lisp form '(Lisp-function arg1 arg2 arg3)' whenever an EnterWindow event is processed. In the lexical scope of the action invocation, ACTION_WIDGET gets bound to the widget causing the action, and ACTION_XEVENT gets bound to the event. See ./../examples/trans.lsp for examples. KNOWN-BUG: I haven't found a way of escaping characters passed on to the translation/action table parsers to allow Lisp strings or lips lists to be passed on to the Lisp evaluator that is called by this function. Using the evaluator through an action proc is still useful, just don't try to pass in very complex Lisp forms. ** XT_PARSE_TRANSLATION_TABLE == XtParseTranslationTable(): (XT_PARSE_TRANSLATION_TABLE ) --> returns a XT_TRANSLATIONS node This primitive compiles into a translation table and returns the compiled table. For more information on the syntax of the string representation of translation tables, see the X11r4 documentation "X Toolkit Intrinsics -- C Language Interface": "Appendix B: Translation Table Syntax" and "Chapter 10: Translation Management". NOTE: the memory allocated by XtParseTranslationTable() isn't freed anywhere yet -- I can't find any documentation that says you're supposed to free this. For now this may be a memory leak. ** XT_PARSE_ACCELERATOR_TABLE == XtParseAcceleratorTable(): (XT_PARSE_ACCELERATOR_TABLE ) --> returns a XT_ACCELERATORS node This primitive compiles into an accelerator table and returns the compiled table. For more information on the syntax of the string representation of accelerator tables, see the X11r4 documentation "X Toolkit Intrinsics -- C Language Interface": "Appendix B: Translation Table Syntax" and "Chapter 10: Translation Management". NOTE: the memory allocated by XtParseAcceleratorTable() isn't freed anywhere yet -- I can't find any documentation that says you're supposed to free this. For now this may be a memory leak. ============================================================================== * XBM/GIF Images and Pixmaps: ** Function GIF_TO_PIXMAP (GIF_TO_PIXMAP [:verbose]) --> returns a PIXMAP node... is the full pathname to a GIF file. [:verbose] -- if this optional argument is present, then information on the pixmap will be printed to WINTERP's stdout. Information on the size and depth of the GIF is printed, along with information on color allocation. Function GIF_TO_PIXMAP returns a PIXMAP representing the GIF file. This function will allocate colors from the global colormap so that the pixmap may be used as argument to any widget pixmap resource. Note that automatic memory management of colors takes place here -- the system will not deallocate any colors allocated by GIF_TO_PIXMAP until the Pixmap and any widgets displaying the pixmap are destroyed. If you're not using a GIF pixmap, make sure to not leave it "hanging" onto a global variable or within a closure as it will prevent it from getting deallocated. As your system runs out of colors, this primitive will substitute the closest matching color for any color that couldn't be allocated. Sometimes this will look ok, sometimes it doesn't. To get back your colors, be sure to destroy any widgets presenting GIF images, and don't leave uneeded references to GIF Pixmap values in any global variables or closures. ** Function XM_GET_PIXMAP == XmGetPixmap(): (XM_GET_PIXMAP ) --> returns a PIXMAP node. is a string representing a XImage that has been cached via XM_INSTALL_IMAGE. If such an XImage isn't found, then is treated as the filename for a X10 or X11 bitmap file. You need to give a full pathname to the bitmap file, or alternately, you may set the environment variable XBMLANGPATH to the directories to be searched for bitmap files. XBMLANGPATH defaults to /usr/lib/X11/%L/bitmaps/%N/%B:/usr/lib/X11/%L/bitmaps/%B:/usr/lib/X11/bitmaps/%B:/usr/include/X11/bitmaps/%B In additions to images you have installed, Motif features 10 preinstalled images: "background", "25_foreground", "50_foreground", "75_foreground", "vertical", "horizontal", "slant_right", "slant_left", "menu_cascade", "menu_checkmark". and may be strings representing color names, or values of type PIXEL. (generated by X_ALLOC_COLOR, or via widget-method :get_values on :XMN_FOREGROUND or :XMN_BACKGROUND resources). This function returns a value of type PIXMAP, which is suitable for passing on to any Pixmap-valued widget resource so as to display an image inside a widget. Note that there is no interface to XmDestroyPixmap()-- unreferenced pixmaps are automatically destroyed by WINTERP during garbage collection. ** XM_INSTALL_IMAGE == XmInstallImage(): (XM_INSTALL_IMAGE ) --> returns T if success, NIL if a NULL , or duplicate is given. This primitive installs an XIMAGE node for use by Motif's Image and Pixmap cacheing routines. is an XIMAGE node as returned by XM_GET_XIMAGE_FROM_FILE; is a STRING, the name under which the is cached. ** XM_UNINSTALL_IMAGE == XmUninstallImage(): (XM_UNINSTALL_IMAGE ) --> returns T if success, NIL if a NULL , or cannot be found in the image cache. This primitive removes an XIMAGE from Motif's Image cache, freeing up the storage associated with the XImage. is an XIMAGE node as returned by XM_GET_XIMAGE_FROM_FILE ** XM_GET_XIMAGE_FROM_FILE == _XmGetImageFromFile(): (XM_GET_XIMAGE_FROM_FILE ) --> returns an XIMAGE node if an XImage was successfully retrieved from the given bitmap file; NIL if This primitive reads an X10 or X11 bitmap file and returns an XImage structure associated with that file. is a STRING, the full path name to the file containing the XImage data. ============================================================================== * Primitives for manipulating XM_STRINGs: Because Motif's XmStrings are such a complete pain to deal with, I've tried to make it so you can pretend XmStrings don't exist at all by providing automatic string-->XmString conversions for setting resources and for various widget methods. Alas, there are cases where you need to retrieve STRING values from an XM_STRING, create special XM_STRINGs, convert compound text to XM_STRINGs (or vice versa), or need to compare two XM_STRINGS. For such cases, I've interfaced most of Motif's XmString functionality... #ifdef MOTIF_1.1 ** XM_CVT_CT_TO_XM_STRING == XmCvtCTToXmString() [Motif >= 1.1 only]: (XM_CVT_CT_TO_XM_STRING ) --> returns an XM_STRING representing . is an XLISP STRING type but it is encoded using compound text format, which is described in the X Consortium Standard "Compound Text Encoding". #endif /* MOTIF_1.1 */ #ifdef MOTIF_1.1 ** XM_CVT_XM_STRING_TO_CT == XmCvtXmStringToCT() [Motif >= 1.1 only]: (XM_CVT_XM_STRING_TO_CT ) --> returns a STRING. This function converts XM_STRING type argument to a STRING encoded in compound text format. Compound text format is described in the X Consortium Standard "Compound Text Encoding". #endif /* MOTIF_1.1 */ ** XM_STRING_BYTE_COMPARE == XmStringByteCompare(): (XM_STRING_BYTE_COMPARE ) --> returns T if the XM_STRING args are byte-for-byte equal, else NIL. A Note from XmStringByteCompare.3X manual page: "In general, if two compound strings are created with the same (char *) string using XmStringCreateSimple() (replaced by XmStringCreateLocalized() in Motif 1.2) in the same language environment, the compound strings compare as equal. If two compound strings are created with the same (char *) string and the same character set other than XmSTRING_DEFAULT_CHARSET using XmStringCreate, the strings compare as equal. The result of comparing a compound string created with XmStringCreate against a compound string created with XmStringCreateSimple()/XmStringCreateLocalized() is undefined. In some cases, once a compound string is put into a widget, that string is converted into an internal form to allow faster processing. Part of the conversion process strips out unnecessary or redundant information. If an application then does an XtGetValues to retrieve a compound string from a widget (specifically, Label and all of its subclasses), it is not guaranteed that the compound string returned is byte-for-byte the same as the string given to the widget originally." ** XM_STRING_COMPARE == XmStringCompare(): (XM_STRING_COMPARE ) --> returns T if the two XM_STRING args are "semantically equal", else NIL. A note from the XmStringCompare.3X manual page: "XmStringCompare returns a Boolean value indicating the results of a semantically equivalent comparison of two compound strings. Semantically equivalent means that the strings have the same text components, directions, and separators. If character sets are specified, they must be equal as well. In general, if two compound strings are created with the same (char *) string using XmStringCreateSimple() (replaced by XmStringCreateLocalized() in Motif 1.2) in the same language environment, the compound strings compare as equal. If two compound strings are created with the same (char *) string and the same character set other than XmSTRING_DEFAULT_CHARSET using XmStringCreate, the strings compare as equal. The result of comparing a compound string created with XmStringCreate against a compound string created with XmStringCreateSimple()/XmStringCreateLocalized() is undefined." ** XM_STRING_CONCAT == XmStringConcat(): (XM_STRING_CONCAT ) --> returns a new XM_STRING which is the concatenation of XM_STRINGs and . ** XM_STRING_COPY == XmStringCopy(): (XM_STRING_COPY ) --> returns a new XM_STRING, a copy of ** XM_STRING_CREATE == XmStringCreate(), XmStringCreateLocalized(), XmStringCreateSimple(), XmStringenerate(): (XM_STRING_CREATE []) --> returns an XM_STRING version of string . Create a compound string from STRING . Optional argument is a STRING specifying an XmStringCharSet. If the argument is omitted, XmFONTLIST_DEFAULT_TAG is used as a default value when using Motif versions >= 1.2. In Motif 1.1 or 1.0, XmSTRING_DEFAULT_CHARSET is used as the default value. With Motif 2.0 XM_STRING_CREATE is considered obsolete. You should consider using XM_STRING_GENERATE and rendition-based XM_STRING routines. In Motif 2.0 when this function is called with no is supplied, Motif 2.0's XmStringGenerate() is called with a null rendition and a charset tag of FONTLIST_DEFAULT_TAG_STRING (aka XmFONTLIST_DEFAULT_TAG) and a XmStringGenerate() XmTextType of XmCHARSET_TEXT. If is supplied (in Motif 2.0), then XmStringCreateLtoR() is called because Motif 2.0.0 seems to have a bug w/r/t calling XmStringGenerate() with a fontlist tag rather than a rendition tag.... Note that calling XM_STRING_CREATE with no argument is equivalent to calling Motif 1.1's XmStringCreateSimple(); In Motif 1.2, calling XM_STRING_CREATE with no argument is equivalent to calling XmStringCreateLocalized(). Example values for would be "", which is equivalent to the C Motif constant XmSTRING_DEFAULT_CHARSET; another typical value is "ISO8859-1", which is equivalent to the C Motif constants XmSTRING_ISO8859_1, XmSTRING_OS_CHARSET, and XmFALLBACK_CHARSET. For Motif 1.1, potential values for are: "" (default) "ISO8859-1" "ISO8859-2" "ISO8859-3" "ISO8859-4" "ISO8859-5" "ISO8859-6" "ISO8859-7" "ISO8859-8" "ISO8859-9" "JISX0201.1976-0" "GB2312.1980-0" "GB2312.1980-1" "JISX0208.1983-0" "JISX0208.1983-1" "KSC5601.1987-0" "KSC5601.1987-1". For Motif 1.2, the default has changed to XmFONTLIST_DEFAULT_TAG, thus would be the string "FONTLIST_DEFAULT_TAG_STRING". ** XM_STRING_CREATE_L_TO_R == XmStringCreateLtoR(), XmStringGenerate(): (XM_STRING_CREATE_L_TO_R []) --> returns an XM_STRING version of string . Create a left-to-right compound string from STRING . This function imposes the semantic of scanning for \n characters in the text. When one is found, the text up to that point is put into a segment followed by a separator component. No final separator component is appended to the end of the compound string. The direction defaults to left-to-right. This function assumes that the encoding is single octet rather than double octet per character of text. For Motif 2.0, XmStringCreateLtoR() is superceded by XmStringGenerate() with XmStringCreateLtoR() considered obsolete. You should consider using XM_STRING_GENERATE and rendition-based XM_STRING routines. In fact, with Motif 2.0, when you call XM_STRING_CREATE_L_TO_R you are actually calling the same function as XM_STRING_CREATE, which in turn is calling XmStringCreateLtoR() if is given, and otherwise XmStringGenerate() is called. XmStringGenerate() has essentially the same semantics as XmStringCreateLtoR() with the exception that tab characters are converted to tab tags in the XmString. See XM_STRING_CREATE and XM_STRING_GENERATE for details. Optional argument is a STRING specifying an XmStringCharSet. If the argument is omitted, XmFONTLIST_DEFAULT_TAG is used as a default value when using Motif versions >= 1.2. In Motif 1.1 or 1.0, XmSTRING_DEFAULT_CHARSET is used as the default value. Example values for would be "", which is equivalent to the C Motif constant XmSTRING_DEFAULT_CHARSET; another typical value is "ISO8859-1", which is equivalent to the C Motif constants XmSTRING_ISO8859_1, XmSTRING_OS_CHARSET, and XmFALLBACK_CHARSET. For Motif 1.1, other potential values for are: "" "ISO8859-1" "ISO8859-2" "ISO8859-3" "ISO8859-4" "ISO8859-5" "ISO8859-6" "ISO8859-7" "ISO8859-8" "ISO8859-9" "JISX0201.1976-0" "GB2312.1980-0" "GB2312.1980-1" "JISX0208.1983-0" "JISX0208.1983-1" "KSC5601.1987-0" "KSC5601.1987-1". For Motif 1.2, the default has changed to XmFONTLIST_DEFAULT_TAG, thus would be the string "FONTLIST_DEFAULT_TAG_STRING". Note that there also exists a Motif function XmStringLtoRCreate() -- at the time of this writing XmStringCreateLtoR() and XmStringLtoRCreate() are the same, therefore I'm only providing WINTERP primitive XM_STRING_CREATE_L_TO_R. ** XM_STRING_DIRECTION_CREATE == XmStringDirectionCreate(): (XM_STRING_DIRECTION_CREATE :STRING_DIRECTION_L_TO_R) --> returns an XM_STRING with a single L->R direction component. (XM_STRING_DIRECTION_CREATE :STRING_DIRECTION_R_TO_L) --> returns an XM_STRING with a single R->L direction component ** XM_STRING_EMPTY == XmStringEmpty(): (XM_STRING_EMPTY ) --> returns T if all segments in XM_STRING are zero length or if there are no text segments. Otherwise returns NIL. ** XM_STRING_GET_L_TO_R == XmStringGetLtoR(): (XM_STRING_GET_L_TO_R []) --> returns a STRING, or NIL if no matching character set found. This function will fetch the first text segment of the XM_STRING which matches the character set , and returns that as a STRING. Optional argument is a STRING specifying an XmStringCharSet. If the argument is omitted, XmFONTLIST_DEFAULT_TAG is used as a default value when using Motif versions >= 1.2. In Motif 1.1 or 1.0, XmSTRING_DEFAULT_CHARSET is used as the default value. Example values for would be "", which is equivalent to the C Motif constant XmSTRING_DEFAULT_CHARSET; another typical value is "ISO8859-1", which is equivalent to the C Motif constants XmSTRING_ISO8859_1, XmSTRING_OS_CHARSET, and XmFALLBACK_CHARSET. For Motif 1.1, potential values for are: "" (default) "ISO8859-1" "ISO8859-2" "ISO8859-3" "ISO8859-4" "ISO8859-5" "ISO8859-6" "ISO8859-7" "ISO8859-8" "ISO8859-9" "JISX0201.1976-0" "GB2312.1980-0" "GB2312.1980-1" "JISX0208.1983-0" "JISX0208.1983-1" "KSC5601.1987-0" "KSC5601.1987-1". For Motif 1.2, the default has changed to XmFONTLIST_DEFAULT_TAG, thus would be the string "FONTLIST_DEFAULT_TAG_STRING". #ifdef MOTIF_1.1 ** XM_STRING_HAS_SUBSTRING == XmStringHasSubstring() [Motif >= 1.1 only]: (XM_STRING_HAS_SUBSTRING ) --> returns T if XM_STRING is a substring of XM_STRING , else returns NIL. #endif /* MOTIF_1.1 */ ** XM_STRING_LENGTH == XmStringLength(): (XM_STRING_LENGTH ) --> returns a FIXNUM representing the number of bytes in including all tags, direction indicators, and separators. 0 is returned if the compound string has an invalid structure. ** XM_STRING_LINE_COUNT == XmStringLineCount(): (XM_STRING_LINE_COUNT ) --> returns a FIXNUM representing the number of lines in XM_STRING . The effect of XM_STRING_LINE_COUNT is to count lines in the XM_STRING argument. Actually, it returns the number of separators plus one... ** XM_STRING_SEGMENT_CREATE == XmStringSegmentCreate(): (XM_STRING_SEGMENT_CREATE [] ) --> returns a XM_STRING with the specified components: , a STRING; , an optional STRING specifying a character set , a symbol, either :STRING_DIRECTION_L_TO_R, or :STRING_DIRECTION_R_TO_L; , a boolean; if non-NIL, a separator will be added immediately following the component. For Motif 2.0, this function is considered obsolete and is superseded by a combination of XM_STRING_GENERATE, one or more XM_STRING_COMPONENT_CREATE with XmSTRING_COMPONENT_DIRECTION and XmSTRING_COMPONENT_SEPARATOR components, all combined via XM_STRING_CONCAT. For Motif 1.1, potential values for are: "" (default) "ISO8859-1" "ISO8859-2" "ISO8859-3" "ISO8859-4" "ISO8859-5" "ISO8859-6" "ISO8859-7" "ISO8859-8" "ISO8859-9" "JISX0201.1976-0" "GB2312.1980-0" "GB2312.1980-1" "JISX0208.1983-0" "JISX0208.1983-1" "KSC5601.1987-0" "KSC5601.1987-1" ** XM_STRING_SEPARATOR_CREATE == XmStringSeparatorCreate(): (XM_STRING_SEPARATOR_CREATE) --> returns an XM_STRING with a single component, a separator. For Motif 2.0, this function is considered obsolete and is superseded by XM_STRING_COMPONENT_CREATE with a component type XmSTRING_COMPONENT_SEPARATOR, length of 0, and NULL value. ============================================================================== * X Color Facilities: #ifdef MOTIF_1.1 ** XM_GET_COLORS == XmGetColors() [Motif >= 1.1 only]: (XM_GET_COLORS ) --> returns an array of 5 PIXEL values #(