Intrinsics of the X Toolkit

Programmers can configure the Intrinsics toolkit so that X Window users can personalize computing environments.


February 01, 1991
URL:http://www.drdobbs.com/parallel/intrinsics-of-the-x-toolkit/184408501

Figure 1


Copyright © 1991, Dr. Dobb's Journal

FEB91: INTRINSICS OF THE X TOOLKIT

INTRINSICS OF THE X TOOLKIT

A toolkit for configuring your user interface

Todd Lainhart

Todd is the technical project leader for the User Interface Management Group at Cadre Technologies Inc. He can be reached at Cadre Technologies, 222 Richmond Street, Providence, RI 02903; on CompuServe at 71560,443 or at sun!cadreri!twl.


The computer user interface has made evolutionary leaps in the last decade. Character display terminals are being obsoleted by bitmapped graphics displays. The WIMP (overlapping Windows, trashcan Icons, pop-up Menus and Pointing device, or mouse) model for user computing is overshadowing the blinking hardware cursor. In the workstation world, there are now toolkits available for developing to the X Window System that allow maximum flexibility in enabling users to configure not only the look of their applications, but also how that application will respond to events. In effect, users are offered the ability to program their own interface.

This article discusses the use of one such toolkit, the Intrinsics, and how, through studied application of resources and translation tables, the application developer can allow users personalized configuration of their computing environment. To demonstrate the power of these facilities, I've included a sample application: a simple text editor, written using the OSF/Motif Toolkit.

Quick Tour of X11

The X Window System, or X11 (X Version 11), is a hardware-independent windowing system for workstations with bitmap displays. Developed at MIT and DEC, and available on practically all Unix-based platforms, X manages I/O to the workstation's display locally and across a heterogeneous networking environment.

The fact that X can manage I/O across a network is a major reason for its power and immediate acceptance into the workstation community. At the heart of the X specification is a networking model that supports distributed computing on top of such protocols as TCP/IP and DECnet, all of which is invisible to the application programmer or user.

The model for application design with X is that of client/server. The X server is a process that runs on the host display and services application requests for I/O from potentially many clients running on that same host system, or perhaps running remotely on a different vendor's workstation on another part of the network (even across phone lines). The application interface to the X protocol is via the Xlib layer, a C-callable set of subroutines bound to the application, which sends window-management and graphics-display requests to the X server. While this layer is complete in that it allows the application full access to the X programming environment, it offers little abstraction for the developer, so that even trivial applications require excessive amounts of code just to react to incoming events.

The Intrinsics

There are a number of toolkits available on top of Xlib that abstract away the low-level details, and allow the developer to better concentrate on building the application. XView, InterViews, Serpent, and CLUE are available in the public domain, while the CommonView and XVT toolkits are available commercially. Probably the most widely used toolkit, and the toolkit I wish to discuss here, is known as the "Intrinsics," also referred to as Xt or the X Toolkit. The Intrinsics is a standard defined by the X Consortium -- all platform vendors that ship an X server with their hardware are bound by that standard to ship a version of Xlib and the Intrinsics that are usable in that environment.

Strictly speaking, the X Toolkit is the union of two subroutine libraries: The Intrinsics, an abstraction of Xlib that presents a particular model for application/user-interface design, and the widget set Xaw (Athena Widget set), which is built upon the Intrinsics. The widget is a generic user-interface object. As defined by the Intrinsics, however, a widget is a reusable hierarchically-derived user-interface component that encapsulates an X window (or collection of X windows), state data, and the methods to manipulate those windows and data.

Although the Athena Widget set is shipped with the X Toolkit, developers are not bound by the Intrinsics to develop applications with it. Typically, commercial application developers will replace Xaw with another widget set, such as OSF/Motif or the Open Look Toolkit for greater functionality and ease of development. So in part, the Intrinsics act as an Xlib framework or programming interface on which to build and use widget-based toolkits. For the remainder of this article, when I refer to the X Toolkit, I'll actually be referring to the Intrinsics and the OSF/Motif toolkit. I'll be using the OSF/Motif toolkit simply because it's available on a large number of Unix-based workstations.

X Toolkit Using the Layered Approach

When developing an application using the X Toolkit, that application will actually touch all levels of the X programming environment. Figure 1 shows the model used most often to describe the relationship between an application and the toolkit layers. Using the Motif toolkit, you create all of your high-level widgets, interface with the system clipboard, and work with internationalized strings. At the Intrinsics level, you establish the event dispatching mechanisms, and perhaps assign resources to your application widgets. Finally, you program directly to Xlib in order to dispatch IPC calls to cooperating applications, or to draw a circle in the application's canvas.

Applications written for X at the lowest levels are event driven, synchronous, and procedural. If you're familiar with Windows or PM programming, you'll recognize an application written strictly at the Xlib level: Somewhere there is a significant switch/case statement, with appropriate procedure calls made to respond to each incoming event. With an application containing many windows, this can be a difficult program to understand and maintain. The Intrinsics, thankfully, present an entirely different and more useful model of event-driven programming; one that is apparently asynchronous and object oriented.

A Typical Application

The listings accompanying this article describe a simple text editor -- Text-edit -- written with the Motif toolkit. The editor is horizontally and vertically scrollable and supports cutting and pasting. Like all Intrinsics-based programs, there is an initialization section, a section where all of the prominent widgets are created, a section for registering all callbacks and event handlers, and finally the event-dispatch loop.

Listing One is the Xdefaults file. Listing Two contains main( ), and the descriptions of all high-level widgets. Listing Three contains all callbacks defined by this application. Listing Four contains code for interfacing to the Motif clipboard. Listings Five and Six are the header files that export the routines defined in listings Three and Four, respectively.

main( ) begins with a call to initialize the Intrinsics, XtInitialize( ). Along with stripping the command line of options that are significant to the Intrinsics, XtInitialize( ) registers this program and its class with the Resource Manager and the Translations Manager. Next, using the Motif toolkit subroutine, XmCreateScrolledText( ), we create the most interesting widget of this program -- a multiline scrollable text editor with default selection and navigation behavior. I've specified resources (widget attributes) that are specific to this widget, along with their values (such as horizontal and vertical scrolling) and multiline text-editing facilities. This is achieved, in part, via the macro, XtSetArg( ).

Following this, a pop-up menu associated with the text widget is created to handle cutting and pasting text and writing text from and to a file. An event handler is then added to the text widget via XtAddEventHandler( ), which declares the application-defined procedure DisplayTextEditMenu to be called in response to a referenced event -- in this case, a mouse button press. DisplayTextEditMenu manages the display and selectability of the pop-up menu.

Finally, the application is mapped to the display screen via the call to XtRealizeWidget( ) and XtMainLoop( ) is entered. XtMainLoop( ) responds to events passed to it by the X server and dispatches these events to the appropriate widget, invoking any callbacks and event handlings as registered by that widget.

Resources

Like the design of X11, the Intrinsics subscribes to the philosophy of mechanism, not policy. Nowhere in the X11 specification or implementation are there guidelines for user-interface design or policies: A robust environment is offered to allow the development of a user interface as specified by the designer. The Intrinsics adheres to this philosophy by specifying a policy by which widgets and user-interface components are to be designed and used. Widgets are designed to be reusable, and are highly configurable, primarily through the use of resources and translation tables.

A resource may specify window width or height, foreground and background colors, text labels, or even what key is bound to the cut function in a text editing widget. A widget attribute is a name-value pair.

At application startup, the Intrinsics resource manager is responsible for assigning resources to appropriate widgets. These resources may either be hardcoded, appear on the application's command line, or appear as ASCII text in one of several files. The resources configurable for each widget are listed in that widget's man page description. And because widget design is based on inheritance, a widget (and thus the designer or user) has access to all the resources of its superclasses.

A resource may be specified in one of several places. The search tree is as follows. First, the application looks for the class name of the application. A robust, stand-alone application should place any user-configurable options in this file. If this file is not found, several other locations are queried, including assorted environment variables. Failing all of these, the .Xdefaults file is read and parsed for resources applicable to the running application.

.Xdefaults is the standard mechanism in modifying the attributes for multiple applications per user session. In the TextEdit example, I've decided to assign resources in my .Xdefaults file (see Listing One). Note that the syntax for specifying the widget to which I'll assign resources allows the use of wild-cards, instance names, and class names. The resource manager depends upon every application and widget to have a name (instance) and belong to a class. Typographical conventions require the instance name to begin in lowercase and the class name to begin in uppercase. Resource names work similarly: borderColor refers to the borderColor resource of a particular widget, while BorderColor refers to all borderColor resources for referenced widgets that support this resource.

Resources are known and specified to the resource manager as strings. These strings and the manifest constants (as they are known to the C compiler) are found in StringDefs.h. Resources introduced by the Motif toolkit are found in Xm.h. Resource instance names are preceded by the XtN or XmN prefix and resource class names are preceded by XtC or XmC. When specifying resources via C code, the left-hand side of the resource definition is used (for example, XmNborderColor). When specifying resources via an ASCII file, such as Xdefaults, the right-hand side is referenced (as in borderColor) and quotes are omitted.

Resources can be assigned values in such a way that either all text widgets for the application will have 80 columns and 24 rows, or just the bottom text widget will have 80 columns and only 5 rows. Values are assigned to specific widgets, by addressing those widgets via a naming tree. In keeping with object-oriented design principles, widgets are created in a hierarchical fashion. Each widget must have a parent (except for the root or top-level widget created by XtInitialize) by which it is managed. When referring to a specific widget's resources, that widget is addressed in the .Xdefaults file by describing the names of all the widgets in its hierarchy (or "widget tree"). The name of the widget is passed to its creation routine in the "name argument." In our example, textEdit is the name of the text widget as instantiated by XmCreateScrolledText in Listing Two.

Note that there are orders of precedence to resource specification. Specific resource descriptions (such as myfile.textEdit.row: 53) will override more general descriptions. Command-line and hardcoded specifications take an even higher precedence. Also note that any errors in parsing the resource specification will be silently ignored by the resource manager!

In Textedit, I've made the decision to allow resource configurability for only the text widget. I've hardcoded the scrollVertical and scrollHorizontal resources to be true, which enables horizontal and vertical scrolling. Note however, that I have allowed the user to configure the rows and columns resources, as well as the .Xdefaults file resources for resizing height and width of the textedit window. I've not made any assignments for background or foreground colors, but they also could be configured. It's important to note that if user configurability is to be allowed, the user must know the naming tree and type of the widget to be configured.

Resources such as borderColor and backgroundColor may not seem very interesting. However, these are only the beginning of the configurable resources available for the Motif widget set. Resources are available for setting the directory setting and directory mask for file-search dialog boxes and for describing text editing modes for text-edit widgets. You'll have to make a decision as to which resources should be exposed to the user and which you want hidden and setable only by the application.

Translation Tables

Motif and the Intrinsics support resource translations. The Intrinsics translation manager allows user-specified mapping between key or mouse events and action procedures. Most widgets support some form of default translation action procedures. The Motif XmText widget supports action procedures such as backword-word( ), forward-word( ), delete-previous-word( ), and delete-next-word( ). Because translations are resources, they may be specified in the same locations as other resources, using a similar syntax. That is, the widget having its translations modified is referenced either explicitly via its naming tree, or using wildcards. Once a path to a specific widget has been described, the mapping between key and mouse events and action procedures can be detailed, as in Listing One.

In my text editor, I decided to change the behavior of the default cursor navigation keys. I used Ctrl-A and Ctrl-E to move my insertion-point cursor to the beginning and end of the current line, respectively. Looking through the man page for XmText, I notice that the internal functions beginning-of-line( ) and end-of-line( ) are available. The syntax for translation specification is similar to any other resource-specification syntax. The first line of the specification starts with override. This informs the translation manager that I wish for all default translations to remain intact, with the following translations overriding any previously defined translations.

Products Mentioned

X11R4 MIT Software Center E32-300 28 Carlton Street Cambridge, MA 02139 617-258-8330 $400 U.S., $500 overseas Format: 3 9-track 1/2" 6250 BPI tapes in tar format, using Berkeley C; includes manuals. Also available on UUCP from UUNET or via anonymous FTP at the following hosts:

  Location    Hostname             Address          Directory
-------------------------------------------------------------

West        gatekeeper.dec.com   128.45.9.52      pub/X.V11R4
East        UUNET.uu.net    192.12.141.129   X/X.V11R4
NEast       expo.lcs.mit.edu     18.30.0.212      pub/X.V11R4
Midwest     cygnusX1.cs.utk.edu  128.169.201.12   pub/X.V11R4
South       dinorah.wustl.edu    129.252.118.101  pub/X.V11R4

The value section of the name value pair must fit on one line, and translation syntax must include newlines to separate the different specifications. Therefore, I must add a newline character (using C syntax) at the end of each line, followed by an escape of the actual newline. Following override, I've defined the keys that I wish to set and the action to be invoked. Key names (for example, Right, Left) for your specific installation are described in keysymdefs.h. Reserved modifiers such as Ctrl, and <Key> are found in the man pages for the Intrinsics library.

With the exception of one subroutine, all the default translations are defined by the XmText widget. Because a user-configurable way to exit the editor was needed, and no default mechanisms for exiting the application exist (except killing the process), I created an action routine and added it to the default-actions table via XtAddAction( ). By associating this routine with the named string "exit," the translation manager is allowed upon startup to scan the resource database for this action and associate it with ExitApp.

Summary

Figure 2 presents a generic makefile that assumes default locations for the X11 and Xm include files and libraries. Depending upon your installation, you may have to make some modifications. Note that I've taken some trouble to locate all callback functions and the procedures accessing the clipboard in a separate file. I've done this for clarity: The requirements for good object-oriented design for asynchronous event-driven programs of this type actually suggest a different packaging scheme.

Figure 2: A generic makefile

  # Makefile to build textedit

  # Macros

  CC=/bin/cc
  DEBUG=-g
  INCLUDE DIRS=-I /usr/include/Xm -I /usr/include/X11
  SYS_DEFS=$(SYS_T) $(RUN_T) -DSYSV
  CC_SWITCHES= -c $(SYS_DEFS) $(INCLUDE_DIRS) $(DEBUG)

  LD=/bin/ld
  LIBDIRS=-L/usr/X11/lib
  LIBS=-1Xm -1Xtm -1Xaw -1X11
  LD_SWITCHES=$(LIBDIRS) $(LIBS)

  # Inference rules
  .SUFFIXES: .c .o .ln

  .c.o:
           $(CC) $(CC_SWITCHES) $<

  OBJS=\
      xm_main.o\
      xm_clipboard.o\
      xm_callbacks.o

  # Targets
  all:    textedit

  textedit:  $(OBJS)
            $(LD) -o $@ $(OBJS) $(LD_SWITCHES)

      xm_main.o:            xm_callbacks.h

      xm_callbacks.o:       xm_clipboard.h

  #   Misc targets
  clean:
             -rm *.bak *.o

  lint:
             lint $(INCLUDE_DIRS) -DSYSV *.c

There is a lot of information for the budding Intrinsics programmer to digest when creating applications with this toolkit. Certainly, there is too much information to cover thoroughly here, so I've included a bibliography of some excellent texts to get you started. There should, however, be enough information to whet your interest, and to get you started in more involved programming projects using the X toolkit.

Acknowledgments

Thanks to David K. Taylor and Paul Caswell of Cadre Technologies Inc. for their comments and review.

Bibliography

Nye, Adrian and Tim O'Reilly. X Toolkit Intrinsics Programming Manual. Wilmington, Mass.: O'Reilly & Associates, 1990.

- - -. X Toolkit Intrinsics Reference Manual. Wilmington, Mass.: O'Reilly & Associates, 1990.

Young, Douglas A. The X Window System, Programming and Applications with Xt: OSF/Motif Edition. Englewood Cliffs, N.J.: Prentice-Hall, 1990.



_INTRINSICS OF THE X TOOLKIT_
by Todd Lainhart


[LISTING ONE]



!
! Resource specifications for simple text editor
!
*textEdit.rows: 24
*textEdit.columns:  80
*textEdit.resizeWidth:  False
*textEdit.resizeHeight: False
*textEdit.translations: #override \n\
                        Ctrl<Key>Right: forward-word()  \n\
                        Ctrl<Key>Left:  backward-word() \n\
                        Ctrl<Key>a:     beginning-of-line() \n\
                        Ctrl<Key>e:     end-of-line() \n\
                        Ctrl<Key>a, Ctrl<Key>a:  beginning-of-file() \n\
                        Ctrl<Key>e, Ctrl<Key>e:  end-of-file()







[LISTING TWO]



/*~PKG**********************************************************************
 *  Package Name: xm_main.c
 *  Synopsis: Implements a simple text editor using the Motif toolkit.
 *  Features Supported: Not much.
 *  References: Xt Programming and Apps by Doug Young.
 *  Xm Programming Reference and Guide by OSF.
 *  Xt Programming Reference and Guide by O'Reilly.
 *  Usage: Bind this with a couple of other support objs.
 *  Known Bugs/Deficiencies:
 *  Modification History: 11/01/90    twl  original
 */

/**************************************************************************
 *  Header files included. */
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/RowColumn.h>
#include <Xm/PushBG.h>
#include <Xm/FileSB.h>
#include <Xm/SelectioB.h>
#include "xm_callbacks.h"

/**************************************************************************
 *  Constants and variables local to this package. */

/* These widgets are the popup menu items, externalized here so that
 * functions within this package can have access (for the setting/unsetting
 * of selectability.  */
static Widget CopyMenuItem;
static Widget CutMenuItem;
static Widget PasteMenuItem;
static Widget PasteFileMenuItem;
static Widget WriteFileMenuItem;

static void   ExitApp();

/* The actions table for declaring new translations. */
static
XtActionsRec actionTable[] =
{
    { "exit", ExitApp },
};

/**************************************************************************
 *  Procedure:  ExitApp
 *  Synopsis: Action procedure for exiting application
 *  Assumptions: None.
 *  Features Supported:
 *  Known Bugs/Deficiencies: We're not interested in checking state of the editor before going down.
 *      Regardless of the circumstances, down we go.
 *  Modification History: 11/01/90  twl     original
 ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
ExitApp( Widget parent, XEvent *event, String *actionArgs, Cardinal argNdx )
{

    XtCloseDisplay( XtDisplay( parent ) );
    exit( 0 );
}

/**************************************************************************
 *  Procedure:  DisplayTextEditMenu
 *  Synopsis: Event handler to display the text body popup menu.
 *  Assumptions:  The parent is a Text Widget.
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
DisplayTextEditMenu( textBody, popupMenu, xEvent )

    Widget  textBody;           /* Owner of the event handler */
    Widget  popupMenu;          /* Data passed by the registering procedure */
    XEvent *xEvent;             /* Passed to all event handlers */
{

    Arg     argList[25];        /* Resource argument list */
    int     argNdx;             /* Index into resource list */

    int     menuButton;         /* MENU button assigned to popup */
    char   *selectedText;       /* The text selected for the widget invoking


    /* We're assuming that the owning widget of this event handler is of
     * type XmCText. If not, get out. */
    if ( !XmIsText( textBody ) )
    {
        printf( "DisplayTextEditMenu: Not Text\n" );
        exit( 1 );
    }

    /* We're also assuming that the the data passed by the event handler
     * is a popup menu widget.  If not, get out. */
    if ( !XmIsRowColumn( popupMenu ) )
    {
        printf( "DisplayTextEditMenu: Not RowColumn\n" );
        exit( 1 );
    }

    /* Check to see if the button that caused this event is the menu
     * button.  If not, get out. */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNwhichButton, &menuButton ); argNdx++;
    XtGetValues( popupMenu, argList, argNdx );
    if ( xEvent->xbutton.button != menuButton )
    {
        return;
    }

    /* We need to set the selectability of the menu items here. For most menu
     * items, that involves checking to see if any text has been selected. */
    selectedText = XmTextGetSelection( textBody );

    /* The Copy menu item. */
    if ( selectedText != NULL )
    {
        XtSetSensitive( CopyMenuItem, TRUE );
    }
    else
    {
        XtSetSensitive( CopyMenuItem, FALSE );
    }

    /* The Cut menu item. */
    if ( selectedText != NULL )
    {
        XtSetSensitive( CutMenuItem, TRUE );
    }
    else
    {
        XtSetSensitive( CutMenuItem, FALSE );
    }

    /* The Paste menu item.  See if there's something in the clipboard,
     * and set sensitivity accordingly. */
    if ( selectedText == NULL )
    {
        if ( ClipboardIsEmpty( textBody ) )
        {
            XtSetSensitive( PasteMenuItem, FALSE );
        }
        else
        {
            XtSetSensitive( PasteMenuItem, TRUE );
        }
    }
    else
    {
        XtSetSensitive( PasteMenuItem, FALSE );
    }

    /* The PasteFile menu item.  Let's say that we can only paste from a file
     *  if no text has been selected. */
    if ( selectedText == NULL )
    {
        XtSetSensitive( PasteFileMenuItem, TRUE );
    }
    else
    {
        XtSetSensitive( PasteFileMenuItem, FALSE );
    }

    /* The WriteFile menu item. */
    if ( selectedText != NULL )
    {
        XtSetSensitive( WriteFileMenuItem, TRUE );
    }
    else
    {
        XtSetSensitive( WriteFileMenuItem, FALSE );
    }

    XmMenuPosition( popupMenu, xEvent );
    XtManageChild( popupMenu );

}

/*~PROC********************************************************************
 *  Procedure: CreateTextEditPopup
 *  Synopsis: Creates the Popup menu displayed over the text edit area.
 *      Callbacks are also defined here.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should perhaps be considered.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static Widget
CreateTextEditPopup( Widget parent )
{

    Widget  textPopup;      /* Created popup returned */
    Arg     argList[25];    /* Resource argument list */
    int     argNdx;         /* Index into argument list */

    Widget  fileDialog;     /* File selection dialog box */
    Widget  promptDialog;   /* Text input prompt */

    /* We assume a text edit widget as parent.  If not, get out. */
    if ( !XmIsText( parent ) )
    {
        printf( "CreateTextEditPopup: Not Text\n" );
        exit( 1 );
    }

    /* Create the popup menu.  We'll tell Xt to manage it at the time that
     * it needs to be displayed. */
    textPopup = XmCreatePopupMenu( parent, "textPopup", NULL, 0 );

    /* Add the menu items (buttons). */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNlabelString, XmStringCreateLtoR( "Copy", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    CopyMenuItem = XmCreatePushButtonGadget( textPopup, "copyMenuItem", argList, argNdx );
    XtManageChild( CopyMenuItem );

    argNdx = 0;
    XtSetArg( argList[argNdx], XmNlabelString, XmStringCreateLtoR( "Cut", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    CutMenuItem = XmCreatePushButtonGadget( textPopup, "cutMenuItem", argList, argNdx );
    XtManageChild( CutMenuItem );

    argNdx = 0;
    XtSetArg( argList[argNdx], XmNlabelString, XmStringCreateLtoR( "Paste", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    PasteMenuItem = XmCreatePushButtonGadget( textPopup, "pasteMenuItem", argList, argNdx );
    XtManageChild( PasteMenuItem );

    argNdx = 0;
    XtSetArg( argList[argNdx], XmNlabelString, XmStringCreateLtoR( "Paste From File...", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    PasteFileMenuItem = XmCreatePushButtonGadget( textPopup, "pasteFileMenuItem", argList, argNdx );
    XtManageChild( PasteFileMenuItem );

    argNdx = 0;
    XtSetArg( argList[argNdx], XmNlabelString, XmStringCreateLtoR( "Write To File...", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    WriteFileMenuItem = XmCreatePushButtonGadget( textPopup, "writeFileMenuItem", argList, argNdx );
    XtManageChild( WriteFileMenuItem );

    /* Add the File Selection dialog, to be invoked by PasteFileMenu button. */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL ); argNdx++;
    XtSetArg( argList[argNdx], XmNdialogTitle, XmStringCreateLtoR( "Paste From File", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    XtSetArg( argList[argNdx], XmNselectionLabelString, XmStringCreateLtoR( "Directory", XmSTRING_DEFAULT_CHARSET ) ); argNdx++ ;
    XtSetArg( argList[argNdx], XmNautoUnmanage, True ); argNdx++;
    fileDialog = XmCreateFileSelectionDialog( parent, "fileDialog", argList, argNdx );

    /* Add a selection dialog, to be invoked by the WriteFileMenu button. */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL ); argNdx++;
    XtSetArg( argList[argNdx], XmNdialogTitle, XmStringCreateLtoR( "Write To File", XmSTRING_DEFAULT_CHARSET ) ); argNdx++;
    XtSetArg( argList[argNdx], XmNselectionLabelString, XmStringCreateLtoR( "File", XmSTRING_DEFAULT_CHARSET ) ); argNdx++ ;
    XtSetArg( argList[argNdx], XmNtextColumns, 32 ); argNdx++;
    promptDialog = XmCreatePromptDialog( parent, "promptDialog", argList, argNdx );

    /* Add callbacks for the menu buttons. */
    XtAddCallback( CopyMenuItem,      XmNactivateCallback, CopyCB,      parent );
    XtAddCallback( CutMenuItem,       XmNactivateCallback, CutCB,       parent );
    XtAddCallback( PasteMenuItem,     XmNactivateCallback, PasteCB,     parent );
    XtAddCallback( PasteFileMenuItem, XmNactivateCallback, PasteFileCB, fileDialog );
    XtAddCallback( WriteFileMenuItem, XmNactivateCallback, WriteFileCB, promptDialog );

    /* Add callbacks for the dialog box buttons. */
    XtAddCallback( fileDialog,   XmNokCallback,     FileDialogOKCB,   parent );
    XtAddCallback( fileDialog,   XmNcancelCallback, UnMapDialogCB,    fileDialog );
    XtAddCallback( fileDialog,   XmNhelpCallback,   UnMapDialogCB,    fileDialog );
    XtAddCallback( promptDialog, XmNokCallback,     PromptDialogOKCB, parent );
    XtAddCallback( promptDialog, XmNcancelCallback, UnMapDialogCB,    promptDialog );
    XtAddCallback( promptDialog, XmNhelpCallback,   UnMapDialogCB,    promptDialog );

    return( textPopup );

}

/*~PROC********************************************************************
 *  Procedure: main
 *  Synopsis: Initializes the Intrinsics, creates all of the higher-level widgets
 *  necessary to make the application happen, and enters the main loop.
 *  Assumptions:
 *  Usage: Command-line arguments are ignored (for now).
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
main( int argc, char *argv[] )
{

    Widget  topShell;         /* Top level shell created by the Intrinsics */
    Widget  textEdit;         /* Main edit Text Widget */
    Widget  textMenu;         /* Popup menu associated with the text editor */

    Arg     argList[25];        /* Resource argument list */
    int     argNdx;             /* Index into resource list */

    /* Initialize the Intrinsics. */
    topShell = XtInitialize( argv[0], "Editor", NULL, 0, &argc, argv );

    /* Create the scrolled Text Widget */
    argNdx = 0;
    XtSetArg(argList[argNdx], XmNscrollVertical,   True );              argNdx++;
    XtSetArg(argList[argNdx], XmNscrollHorizontal, True );              argNdx++;
    XtSetArg(argList[argNdx], XmNeditMode,         XmMULTI_LINE_EDIT ); argNdx++;

    textEdit = XmCreateScrolledText( topShell, "textEdit", argList, argNdx );
    XtManageChild( textEdit );

    /* Create the context-sensitive popup menu for this Widget */
    textMenu = CreateTextEditPopup( textEdit );

    /* Add the event handler to the Text Widget, invoking the popup menu. */
    XtAddEventHandler( textEdit, ButtonPressMask, FALSE, DisplayTextEditMenu, textMenu );

    /* Register new actions to be associated with our app. */
    XtAddActions( actionTable, XtNumber( actionTable ) );

    /* Map the editor, and enter the event dispatch loop. */
    XtRealizeWidget( topShell );
    XtMainLoop();

}






[LISTING THREE]


/*~PKG*********************************************************************
 *  Package Name: xm_callbacks.c
 *  Synopsis: Common text manipulation callbacks.
 *  Features Supported:
 *  References: Xt Programming and Apps by Doug Young.
 *         Xm Programming Reference and Guide by OSF.
 *         Xt Programming Reference and Guide by O'Reilly.
 *  Usage: Include "xm_callbacks.h"
 *  Known Bugs/Deficiencies:
 *  Modification History: 11/01/90    twl  original
 */

/*~HDR*********************************************************************
 *  Header files included.
 */
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <X11/Xatom.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/FileSB.h>

#include "xm_clipboard.h"

/*~PROC********************************************************************
 *  Procedure:  MapDialogCB
 *  Synopsis: Maps the referenced dialog box.
 *  Assumptions: The parent has been realized.
 *      The widget passed to this callback is a subclass of dialogshell.
 *  Features Supported:
 *  Known Bugs/Deficiencies:
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
MapDialogCB( source, dialog, callbackData )

    Widget source;                      /* Source of the callback */
    Widget dialog;                      /* Data passed to the callback by the register procedure */
    XmAnyCallbackStruct *callbackData;  /* Generic data passed to all callback procedures */
{

    XtManageChild( dialog );

}

/*~PROC********************************************************************
 *  Procedure:  UnMapDialogCB
 *  Synopsis: Unmaps the referenced dialog box.
 *  Assumptions:  The parent has been realized.
 *      The widget passed to this callback is a subclass of dialogshell.
 *  Features Supported:
 *  Known Bugs/Deficiencies:
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
UnMapDialogCB( source, dialog, callbackData )

    Widget source;                      /* Source of the callback */
    Widget dialog;                      /* Data passed to the callback by the register procedure */
    XmAnyCallbackStruct *callbackData;  /* Generic data passed to all callback procedures */
{

    XtUnmanageChild( dialog );

}

/*~PROC********************************************************************
 *  Procedure:  CutCB
 *  Synopsis: Callback procedure for cutting text from the referenced text
 *  widget to the clipboard.  Callback for the "Cut" menu item.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: Cursor should change to a wait state.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
CutCB( source, textID, callbackData )

    Widget source;                      /* Source of the callback */
    Widget textID;                      /* Data passed to the callback by the register procedure */
    XmAnyCallbackStruct *callbackData;  /* Generic data passed to all callback procedures */
{

    XClientMessageEvent clientMessage;  /* X client message structure */
    Time                timestamp;      /* X Event time */
    int                 clipStat;       /* Return status of clipboard call */

    /* Get the event timestamp */
    timestamp = ((XButtonEvent *)callbackData->event)->time;

    /* Copy the selected text to the clipboard. */
    clipStat = CopyToClipboard( textID, timestamp );

    /* Delete the selected text from the Text Widget */
    if ( clipStat == True )
    {
        clientMessage.type         = ClientMessage;
        clientMessage.display      = XtDisplay( textID );
        clientMessage.message_type = XmInternAtom( XtDisplay( textID ), "KILL_SELECTION", FALSE );
        clientMessage.window       = XtWindow( textID );
        clientMessage.format       = 32;
        clientMessage.data.l[0]    = XA_PRIMARY;
        XSendEvent( XtDisplay( textID ), clientMessage.window, TRUE, NoEventMask, &clientMessage );
    }

}

/*~PROC********************************************************************
 *  Procedure:  CopyCB
 *  Synopsis: Callback procedure for copying text from the referenced text
 *  widget to the clipboard.  Callback for the "Copy" menu item.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: The cursor should change into a waiting cursor.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
CopyCB( source, textID, clientData )

    Widget source;                      /* Source of the callback */
    Widget textID;                      /* Data passed to the callback as defined by the registering procedure */
    XmAnyCallbackStruct *clientData;    /* Generic data passed to all callback procedures */

{
    Time     eventTime;                 /* Time stamp for the clipboard */

    /* Get the time the event occurred */
    eventTime = ((XButtonEvent *)clientData->event)->time;

    /* Copy the selected text (if any) to the clipboard */
    CopyToClipboard( textID, eventTime );

}

/*~PROC********************************************************************
 *  Procedure:  PasteCB
 *  Synopsis: Callback procedure for pasting text from the referenced text widget
 *      to the clipboard.  Callback for the "Paste" menu item.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
PasteCB( source, textID, callbackData )

    Widget  source;                     /* Owner of the callback */
    Widget  textID;                     /* Data passed to the callback routine by */
                                        /* the registering procedure */
    XmAnyCallbackStruct *callbackData;  /* Data passed to all callbacks */

{
    char    *pasteText;         /* That text which is to be retrieved from the paste buffer */
    Time     eventTime;         /* Time stamp for the clipboard routines */
    Arg      argList[25];       /* Resource retrieval array */
    int      argNdx;            /* Index into resource array */

    XmTextPosition textCursorPos; /* Position of Text Widget insertion cursor */

    /* Get the time the event occurred (for transaction timestamping) */
    eventTime = ((XButtonEvent *)callbackData->event)->time;

    /* Get the latest text from the clipboard. */
    pasteText = RetrieveFromClipboard( textID, eventTime );

    /* See if we have a hit.  If not, get out. */
    if ( pasteText == NULL )
    {
        return;
    }

    /* Get the insertion point of the text Widget */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNcursorPosition, &textCursorPos ); argNdx++;
    XtGetValues( textID, argList, argNdx );

    /* ...and insert the text */
    XmTextReplace( textID, textCursorPos, textCursorPos, pasteText );

    XtFree( pasteText );

}

/*~PROC********************************************************************
 *  Procedure:  PasteFileCB
 *  Synopsis: Callback procedure for the Paste from File... menu item.
 *      Currently, just the dialog box is displayed.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
PasteFileCB( source, dialog, callbackData )

    Widget  source;                     /* Owner of the callback */
    Widget  dialog;                     /* Data passed to the callback routine by */
                                        /* the registering procedure */
    XmAnyCallbackStruct *callbackData;  /* Data passed to all callbacks */

{
    XtManageChild( dialog );
}

/*~PROC********************************************************************
 *  Procedure:  WriteFileCB
 *  Synopsis: Callback procedure for the Write to File... menu item.
 *      Currently, just the dialog box is displayed.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
WriteFileCB( source, dialog, callbackData )

    Widget  source;                     /* Owner of the callback */
    Widget  dialog;                     /* Data passed to the callback routine by */
                                        /* the registering procedure */
    XmAnyCallbackStruct *callbackData;  /* Data passed to all callbacks */

{
    XtManageChild( dialog );
}

/*~PROC********************************************************************
 *  Procedure:  FileDialogOKCB
 *  Synopsis: Callback procedure for the activation of the OK button on the file selection
 *      dialog box.
 *  Assumptions: The file to be pasted is ASCII.
 *      The source of the callback is a file selection dialog box.
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *      The file to be pasted is not checked for type (should be ASCII).
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
FileDialogOKCB( source, textID, callbackData )

    Widget                            source;       /* Owner of the callback */
    Widget                            textID;       /* Data passed to the callback routine */
    XmFileSelectionBoxCallbackStruct *callbackData; /* Data passed to all file selection callbacks */
{
    char       *pasteFile;              /* Filename returned from the dialog */
    int         pasteFileLen;           /* Length of referenced file */
    char       *pasteText;              /* Contents of reference file */
    struct stat statBuf;                /* Buffer for stat() results */
    FILE       *fileDesc;               /* UNIX file descriptor */

    Arg         argList[25];            /* Resource retrieval array */
    int         argNdx;                 /* Index into resource array */

    XmTextPosition textCursorPos;    /* Position of Text Widget insertion cursor */

    if ( !XmIsText( textID ) )
    {
        printf( "FileDialogOKCB: Not Text Widget\n" );
        exit( 1 );
    }

    if ( !XmIsFileSelectionBox( source ) )
    {
        printf( "FileDialogOKCB: Not dialog box\n" );
        exit( 1 );
    }

    /* Get the filename */
    XmStringGetLtoR( callbackData->value, XmSTRING_DEFAULT_CHARSET, &pasteFile );

    /* Open the file */
    fileDesc = fopen( pasteFile, "r" );
    if ( fileDesc == NULL )
    {
        /* Display an error prompt, and get out */
        printf( "FileDialogOKCB: File not available for read\n" );
        exit( 1 );
    }

    /* Get its length, read the contents, and close it up. */
    stat( pasteFile, &statBuf );
    pasteFileLen = statBuf.st_size;
    pasteText  = XtMalloc( pasteFileLen );
    fread( pasteText, sizeof( char ), pasteFileLen, fileDesc );
    fclose( fileDesc );

    /* Paste the contents at the current insertion point. */
    argNdx = 0;
    XtSetArg( argList[argNdx], XmNcursorPosition, &textCursorPos ); argNdx++;
    XtGetValues( textID, argList, argNdx );
    XmTextReplace( textID, textCursorPos, textCursorPos, pasteText );

    /* Free up resources */
    XtFree( pasteFile );
    XtFree( pasteText );

    /* Bring down the dialog box */
    XtUnmanageChild( source );

}

/*~PROC********************************************************************
 *  Procedure:  PromptDialogOKCB
 *  Synopsis: Callback procedure for the activation of the OK button on the prompt
 *      dialog box.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: External resources should be considered.
 *      Minimal error checking on file creation and write.
 *  Modification History: 08/20/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
PromptDialogOKCB( source, textID, callbackData )

    Widget                        source;       /* Owner of the callback */
    Widget                        textID;       /* Data passed to the callback routine */
    XmSelectionBoxCallbackStruct *callbackData; /* Data passed to all selection callbacks */
{

    char       *writeFile;              /* Filename returned from the dialog */
    int         writeFileLen;           /* Length of referenced file */
    char       *writeText;              /* Contents of reference file */
    struct stat statBuf;                /* Buffer for stat() results */
    FILE       *fileDesc;               /* UNIX file descriptor */

    char       *selectedText;           /* That text which is marked as selected in textID */

    if ( !XmIsText( textID ) )
    {
        printf( "PromptDialogOKCB: Not Text Widget\n" );
        exit( 1 );
    }

    /* If no text selected, we can leave. */
    selectedText = XmTextGetSelection( textID );
    if ( selectedText == NULL )
    {
        return;
    }

    /* Get the filename */
    XmStringGetLtoR( callbackData->value, XmSTRING_DEFAULT_CHARSET, &writeFile );

    /* Open the file */
    fileDesc = fopen( writeFile, "w" );
    if ( fileDesc == NULL )
    {
        /* Display an error, and get out */
        printf( "PromptDialogOKCB: Error on file creation\n" );
        exit( 1 );
    }

    /* Write the file, and close it up */
    fwrite( selectedText, sizeof( char ), strlen( selectedText ), fileDesc );
    if ( fclose( fileDesc ) != NULL )
    {
        /* Display an error, and get out */
        printf( "PromptDialogOKCB: Error on file close\n" );
        exit( 1 );
    }

}






[LISTING FOUR]


/*~PKG*********************************************************************
 *  Package Name: xm_clipboard.c
 *  Synopsis: Implements clipboard store and retrieve procedures.
 *  Features Supported:
 *  References: Xt Programming and Apps by Doug Young.
 *      Xm Programming Reference and Guide by OSF.
 *      Xt Programming Reference and Guide by O'Reilly.
 *  Usage: Include "xm_clipboard.h"
 *  Known Bugs/Deficiencies:
 *  Modification History: 11/01/90    twl  original
 */

/*~HDR*********************************************************************
 *  Header files included.  */
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/CutPaste.h>

/*~LOC*DATA****************************************************************
 *  Constants and variables local to this package.  */

#define CBLABEL "TextEdit"

/*~PROC********************************************************************
 *  Procedure:  CopyToClipboard
 *  Synopsis: Retrieve selected text from reference textID, and copy it to the system
 *      clipboard.  Returns True if successful, False if not.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: Text only supported.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
CopyToClipboard( Widget textID, Time timestamp )
{

    char    *selectedText;      /* That text which is marked as selected in textID */
    int      clipStat;          /* Return value from XmClipboard routines */
    XmString clipLabel;         /* The label used to identify the clipboard string */
    long     clipID, copyID;    /* The handles used in identifying clipboard transactions */

    /* Sanity check. */
    if ( !XmIsText( textID ) )
    {
        printf( "CopyToClipboard: Not Text Widget\n" );
        exit( 1 );
    }

    /* If no text selected, we can leave. */
    selectedText = XmTextGetSelection( textID );
    if ( selectedText == NULL )
    {
        return( False );
    }

    /* Create the label that appears in the clipboard. */
    clipLabel = XmStringCreateLtoR( CBLABEL, XmSTRING_DEFAULT_CHARSET );

    /* Poll the clipboard, asking for permission to start. */
    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardStartCopy( XtDisplay( textID ), XtWindow( textID ),
                                         clipLabel, timestamp, textID, NULL,
                                         &clipID );
    }

    /* Copy the data to the clipboard until successful. */
    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardCopy( XtDisplay( textID ), XtWindow( textID ), clipID,
                                    XtRString, selectedText, (long)strlen( selectedText ), 0
                                    ©ID );

    }

    /* End the transaction... */
    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardEndCopy( XtDisplay( textID ), XtWindow( textID ), clipID );

    }

    /* ... cleanup, and leave. */
    XtFree( selectedText );
    XmStringFree( clipLabel );

    return( True );
}

/*~PROC********************************************************************
 *  Procedure:  RetrieveFromClipboard
 *  Synopsis: Return text from the clipboard.
 *  Assumptions: The caller assumes responsibility for freeing returned string.
 *  Features Supported:
 *  Known Bugs/Deficiencies: Text only supported.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *
RetrieveFromClipboard( Widget textID, Time timestamp )
{

    char    *pasteText;         /* That text which is to be retrieved from the paste buffer */
    int      pasteTextLen;      /* Length of text in clipboard */
    int      clipStat;          /* Return value from XmClipboard routines */
    XmString clipLabel;         /* The label used to identify the clipboard string */
    long     clipID, privateID; /* The handles used in identifying clipboard transactions */
    long     outlen;            /* Length of data retrieved from clipboard */

    /* Check to be sure that we have a text Widget */
    if ( !XmIsText( textID ) )
    {
        printf( "RetrieveFromClipboard: Widget not Text\n" );
        exit( 1 );
    }

    /* Start our clipboard transaction */
    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )

    {
        clipStat = XmClipboardStartRetrieve( XtDisplay( textID ), XtWindow( textID ),
                                             timestamp );
    }

    /* Get the length of the clipboard contents */
    clipStat     = ClipboardLocked;
    pasteTextLen = 0;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardInquireLength( XtDisplay( textID ), XtWindow( textID ),
                                             XmRString, &pasteTextLen );
        if ( clipStat == ClipboardNoData )
        {
            return( NULL );
        }
    }

    /* Retrieve the data (allocating a string buffer) */
    pasteText = XtMalloc( pasteTextLen + 1 );

    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardRetrieve( XtDisplay( textID ), XtWindow( textID ),
                                        XmRString, pasteText, pasteTextLen,
                                        &outlen, &privateID );
    }

    /* End the clipboard session... */
    clipStat = ClipboardLocked;
    while( clipStat == ClipboardLocked )
    {
        clipStat = XmClipboardEndRetrieve( XtDisplay( textID ), XtWindow( textID ) );
    }

    /* ... and return the clipboard contents. */
    return( pasteText );

}

/*~PROC********************************************************************
 *  Procedure:  ClipboardIsEmpty
 *  Synopsis: Returns FALSE, if no items in the clipboard.
 *  Assumptions:
 *  Features Supported:
 *  Known Bugs/Deficiencies: Text only supported.  Returns False (no data) if clipboard is locked.
 *  Modification History: 11/01/90  twl     original
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
ClipboardIsEmpty( Widget w )
{

    int clipStat;       /* Clipboard status value */
    int textLength;     /* Length of text in clipboard */

    clipStat = XmClipboardInquireLength( XtDisplay( w ), XtWindow( w ), XmRString,
                                         &textLength );

    if ( clipStat == ClipboardSuccess )
    {
        return( False );
    }
    else
    {
        return( True );
    }
}






[LISTING FIVE]


#ifndef XM_CALLBACKS_H
#define XM_CALLBACKS_H
/*************************************************************************
 *  Include File Name: xm_callbacks.h
 *  Contents: Interface to the callbacks package.
 *  This include file is dependent on the following include file(s):
 *    None.
 *  Modification History: 11/01/90  twl     original
 */


/*~EXP*PROC****************************************************************
 *  Procedures and functions exported by this package. */
extern void
MapDialogCB( Widget source, Widget dialog, XmAnyCallbackStruct *callbackData );

extern void
UnMapDialogCB( Widget source, Widget dialog, XmAnyCallbackStruct *callbackData );

extern void
CutCB( Widget source, Widget textID, XmAnyCallbackStruct *callbackData );

extern void
CopyCB( Widget source, Widget textID, XmAnyCallbackStruct *callbackData );

extern void
PasteCB( Widget source, Widget textID, XmAnyCallbackStruct *callbackData );

extern void
PasteFileCB( Widget source, Widget textID, XmAnyCallbackStruct *callbackData );

extern void
WriteFileCB( Widget source, Widget textID, XmAnyCallbackStruct *callbackData );

extern void
FileDialogOKCB( Widget source, Widget textID, XmFileSelectionBoxCallbackStruct *callbackData );

extern void
PromptDialogOKCB( Widget source, Widget textID, XmSelectionBoxCallbackStruct *callbackData );

#endif






[LISTING SIX]



#ifndef XM_CLIPBOARD_H
#define XM_CLIPBOARD_H
/*************************************************************************
 *
 *  Include File Name: xm_clipboard.h
 *
 *  Contents:
 *    Interface to the Clipboard package.
 *
 *  This include file is dependent on the following include file(s):
 *    None.
 *
 *  Modification History:
 *    11/01/90  twl     original
 */


/*~EXP*PROC****************************************************************
 *
 *  Procedures and functions exported by this package.
 */
extern int
CopyToClipboard( Widget textID, Time timestamp );

extern char *
RetrieveFromClipboard( Widget textID, Time timestamp );

extern int
ClipboardIsEmpty( Widget w );

#endif






[LISTING SEVEN]


#
# Makefile to build textedit
#

#
# Macros
#

CC=/bin/cc
DEBUG=-g
INCLUDE_DIRS=-I /usr/include/Xm -I /usr/include/X11
SYS_DEFS=$(SYS_T) $(RUN_T) -DSYSV
CC_SWITCHES= -c $(SYS_DEFS) $(INCLUDE_DIRS) $(DEBUG)

LD=/bin/ld
LIBDIRS=-L/usr/X11/lib
LIBS=-lXm -lXtm -lXaw -lX11
LD_SWITCHES=$(LIBDIRS) $(LIBS)

#
# Inference rules
#
.SUFFIXES: .c .o .ln

.c.o:
   $(CC) $(CC_SWITCHES) $<

OBJS=\
    xm_main.o\
    xm_clipboard.o\
    xm_callbacks.o

#
# Targets
#

all:    textedit

textedit:  $(OBJS)
   $(LD) -o $@ $(OBJS) $(LD_SWITCHES)

xm_main.o:      xm_callbacks.h

xm_callbacks.o: xm_clipboard.h

#-------------------------
#   Misc targets
#-------------------------
clean:
   -rm *.bak *.o

lint:
   lint $(INCLUDE_DIRS) -DSYSV *.c


Copyright © 1991, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.