Archive-name: motif-faq/part4
Last-modified: JULY 14, 1996
Posting-Frequency: monthly
Organization: Century Computing, Inc. <URL: http://www.cen.com/>
Version: 5.3



-----------------------------------------------------------------------------
Subject: 76)  How can I create a multi-colored window manager icon?

[Last modified: Oct 95]

Answer:  The only portable way to do this is with icon windows.  The WMShell
widget supports icon windows with its XmNiconWindow resource.  Set this to a
window  that your application has created.  The window could be the XtWindow()
of a realized shell widget.  The window must be created with the default
visual and colormap of its screen.  Other requirements on icon windows are
specified in section 4.1.9 of the X11R6 ICCCM.  Note that some window managers
provide alternate techniques for creating color icons; none of these are
standard or portable.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 77)  How can I keep my shell windows fixed in size?

[Last modified: Apr 95]

Answer:  In addition to the decoration controls mentioned in the previous few
subjects of this FAQ, you can also specify size hints for your shell widget's
windows with these resources:  XmNminWidth, XmNmaxWidth, XmNminHeight,
XmNmaxHeight.  If you set the min and max values to the same size, most window
managers will not allow the user to resize the window.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 78)  Why is XtGetValues of XmNx and XmNy of my toplevel shell wrong?

[Last modified: Oct 95]

Answer:  [Note: This answer is borrowed from the Xt FAQ,
ftp://ftp.x.org/contrib/faqs/FAQ-Xt, devoted to X Toolkit Intrinsics.]

XmNx and XmNy are the coordinates relative to your shell's parent window,
which is usually a window manager's frame window.  To translate to the root
coordinate space, use XtTranslateCoords().

-----------------------------------------------------------------------------
Subject: 79)  How do I get XmNx and XmNy positions to be honored correctly?

[Last modified: Mar 96]

Answer:  One answer is to pass the right hints to the window manager, perhaps
using XSetWMNormalHints.  Another approach comes from Shane Burgess
(shane@radionics.com) who writes:

By setting the XmNdefaultPosition resource to False, I've found that all my
XmNx & XmNy requests gets set correctly.

-----------------------------------------------------------------------------
Subject: 80)  How can my application know when the user has quit Mwm?

[Last modified: Feb 95]

Answer:  Looking for an answer to this one. ANY TAKERS? (Still looking.)

-----------------------------------------------------------------------------
Subject: 81)  How can I tell if the user has selected "Close" from the system
menu? How do I catch the "Close"?  I need to do some clean up before exiting.

[Last modified: Aug 95]

Answer:  Catching the mwm Close involves using XmAddWMProtocolCallback and
possibly setting the XmNdeleteResponse resource. Note that whether your
application involves multiple applicationShells vs. a single applicationShell
and multiple toplevelShells is significant. Following the two older code
fragments is a complete test application which can be compiled with different
#defines to alter the behavior.           This works with R4 Intrinsics

        #include <Xm/Protocols.h>

        void FinalCleanupCB(w, client_data, call_data)
        Widget   w;
        caddr_t  client_data, call_data;
        {
                /* tidy up stuff here */
                ...
                /* exit if you want to */
                exit (0);
        }

        main()
        {
                Atom wm_delete_window;

                ...
                XtRealizeWidget(toplevel);
                ...
                wm_delete_window =
                        XmInternAtom(XtDisplay(toplevel),
                                "WM_DELETE_WINDOW", False);
                XmAddWMProtocolCallback(toplevel, wm_delete_window,
                        FinalCleanupCB, NULL);
                XtMainLoop();
        }

This will still kill the application.  To turn this behaviour off so that the
application is not killed, set the shell resource XmNdeleteResponse to
XmDO_NOTHING.  This means that users cannot kill your application via the
system menu, and may be a bad thing.

If you are running R3, Bob Hays (bobhays@spss.com) has suggested this:
"Trapping on the delete window atom does not work as I cannot force my action
routine to the top of the action list for the activity desired, so the window
manager kills my window anyway BEFORE I can do anything about it.  And, to
make matters worse, the window manager (Motif in this case) tacks its atoms
and handlers onto the window at some unknown point down the line after the
creation of the shell widget as far as I can tell.  So....

I have a procedure as an action routine for ClientMessage.  Then, if I get a
property change event on the window manager protocols, I then tack on
WM_SAVE_YOURSELF.  If I get this request, I clean up (it seems to happen on
WM_DELETE_WINDOW, BTW, if you remove WM_DELETE_WINDOW from the WM protocols
atom) and exit.  Works great and is less filling overall:-)."

The following similar code fragment is from Dave Mink
(mink@cadcam.pms.ford.com):

void setupCloseCallback(Widget shell, XtCallbackProc closeProc)
{
    /* get window manager delete protocol atom */
    Atom deletewin_protocol = XmInternAtom(
        XtDisplay(shell), "WM_DELETE_WINDOW", True
        );
    /* turn off default delete response */
    XtVaSetValues( shell,
        XmNdeleteResponse, XmDO_NOTHING,
        NULL);
    /* add callback for window manager delete protocol */
    XmAddWMProtocolCallback(shell, deletewin_protocol, closeProc, NULL);
}


Here is a complete code example which can be compiled several different ways,
as per the comments in the code.


/*
 * MWM Close test program.
 *
 * Creates 4 shells, testing each of 3 different values of XmNdeleteResponse.
 * Compile will -DMULTIPLE_APP_SHELLS to make all 4 shells of type
 * applicationShellWidgetClass. Otherwise, first shell created is
 * applicationShellWidgetClass, but other 3 are topLevelShellWidgetClass.
 * Results differ. You can also experiment with #defining POPUP_SHELL,
 * BEFORE_CREATE, or AFTER_CREATE.
 *
 * Ken Sall (ksall@cen.com), Motif FAQ maintainer, Century Computing, Inc.
 */

#include <stdio.h>

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#include <X11/Shell.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>

#include <Xm/RowColumn.h> /* for popup */
#include <Xm/Label.h>

#include <X11/Protocols.h>
#include <X11/AtomMgr.h>
#include <X11/MwmUtil.h>

void CloseCB();
void popup_handler();

#ifdef MULTIPLE_APP_SHELLS
#define P1_TITLE        "P1: applicationShell: XmDO_NOTHING"
#define P2_TITLE        "P2: applicationShell: XmDESTROY"
#define P3_TITLE        "P3: applicationShell: XmUNMAP"
#define P4_TITLE        "P4: applicationShell: default"
#else
#define P1_TITLE        "P1: applicationShell: XmDO_NOTHING"
#define P2_TITLE        "P2: topLevelShell: XmDESTROY"
#define P3_TITLE        "P3: topLevelShell: XmUNMAP"
#define P4_TITLE        "P4: topLevelShell: XmDO_NOTHING"
#endif

void CloseCB (w, client_data, call_data)
Widget  w;              /*  widget id           */
caddr_t client_data;    /*  data from application   */
caddr_t call_data;      /*  data from widget class  */
{
    XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;

        printf ("caught Close from: %s\n", (char *)client_data );
        if (strcmp ( P1_TITLE, (char *)client_data ) == 0 )
                {
                /* do something */
                }
        else if (strcmp ( P2_TITLE, (char *)client_data ) == 0 )
                {
                /* do something else */
                }
        else if (strcmp ( P3_TITLE, (char *)client_data ) == 0 )
                {
                /* do something else */
                }
        else if (strcmp ( P4_TITLE, (char *)client_data ) == 0 )
                {
                /* do something else */
                }
        else    /* unreachable */
                {
                printf ("oops\n");
                }
}

void popup_handler()
{
        printf ("popup handler\n");
}

int main (argc,argv, envp)
    int  argc;
    char **argv;
    char **envp;
{
   XtAppContext  app_context;
   Display       *theDisplay;
   Widget        shell1, shell2, shell3, shell4;
   Widget        label, DrawWindow, WindowPopupMenu;
   Arg           al[10];
   int           ac;
   Atom          delwinAtom1, delwinAtom2, delwinAtom3, delwinAtom4;
   XmString      xms;

#ifdef MULTIPLE_APP_SHELLS
   printf ("This version will demonstrate a problem if you Close P2.\n");
   printf ("Since there are multiple appshells, closing (destroying) P2 cause the app to exit.\n");
#else
#ifdef POPUP_SHELL
   printf ("This version uses XtCreatePopupShell rather than XtAppCreateShell \n");
#else
   printf ("Compile with '-DMULTIPLE_APP_SHELLS' to demonstrate a problem.\n");
#endif
#endif

#ifdef BEFORE_CREATE
   printf ("This version adds the XmNdeleteResponse _before_ the shell is created.\n");
#else
   printf ("This version adds the XmNdeleteResponse _after the shell is created.\n");
#endif

   XtToolkitInitialize ();
   app_context = XtCreateApplicationContext ();

   theDisplay = XtOpenDisplay ( app_context, NULL,
                               "my_program", "ProgramClass",
                                NULL, 0, &argc, argv);

   /* ---------------------   BEGIN P1  -------------------- */
   ac = 0;
   XtSetArg(al[ac], XmNx, 0); ac++;
   XtSetArg(al[ac], XmNy, 0); ac++;
   XtSetArg(al[ac], XmNwidth, 350); ac++;
   XtSetArg(al[ac], XmNheight, 200); ac++;
   XtSetArg (al[ac], XmNtitle, P1_TITLE); ac++;
#ifdef BEFORE_CREATE
   XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
#endif

   /* The ONLY applicationShell unless MULTIPLE_APP_SHELLS is defined. */

   shell1 = XtAppCreateShell ("shell1", "ProgramClass",
                applicationShellWidgetClass, theDisplay, al, ac);

   /* Tell mwm to exec CloseCB when close is detected. */
   delwinAtom1 = XmInternAtom (XtDisplay(shell1),
                                    "WM_DELETE_WINDOW", False);
   XmAddWMProtocolCallback (shell1, delwinAtom1, CloseCB, P1_TITLE);

#ifndef BEFORE_CREATE
   XtVaSetValues( shell1, XmNdeleteResponse, XmDO_NOTHING, NULL);
#endif

   /* ---------------------   BEGIN P2  -------------------- */
   ac = 0;
   XtSetArg(al[ac], XmNx, 375); ac++;
   XtSetArg(al[ac], XmNy, 0); ac++;
   XtSetArg(al[ac], XmNwidth, 350); ac++;
   XtSetArg(al[ac], XmNheight, 200); ac++;
   XtSetArg (al[ac], XmNtitle, P2_TITLE); ac++;
#ifdef BEFORE_CREATE
   XtSetArg (al[ac], XmNdeleteResponse, XmDESTROY); ac++;
#endif

#ifdef MULTIPLE_APP_SHELLS
   shell2 = XtAppCreateShell ("shell2", "ProgramClass",
                applicationShellWidgetClass, theDisplay, al, ac);
#else
#ifdef POPUP_SHELL
   /*
    * NOTE use of XtCreatePopupShell (not XtCreateMAnagedWidget) and
    * topLevelShellWidgetClass (not applicationShellWidgetClass).
    * Parent of topLevelShell is applicationShell.
    * Use XtPopup rather than XtRealize for topLevelShell.
    */
   shell2 = XtCreatePopupShell ("shell2",
                topLevelShellWidgetClass, shell1, al, ac);
#else
   shell2 = XtAppCreateShell ("shell2", "ProgramClass",
                topLevelShellWidgetClass, theDisplay, al, ac);
#endif
#endif

   /* Tell mwm to exec CloseCB when close is detected. */
   delwinAtom2 = XmInternAtom (XtDisplay(shell2),
                                    "WM_DELETE_WINDOW", False);
   XmAddWMProtocolCallback (shell2, delwinAtom2, CloseCB, P2_TITLE);

#ifndef BEFORE_CREATE
   XtVaSetValues( shell2, XmNdeleteResponse, XmDESTROY, NULL);
#endif

   /* ---------------------   BEGIN P3  -------------------- */
   ac = 0;
   XtSetArg(al[ac], XmNx, 750); ac++;
   XtSetArg(al[ac], XmNy, 0); ac++;
   XtSetArg(al[ac], XmNwidth, 350); ac++;
   XtSetArg(al[ac], XmNheight, 200); ac++;
   XtSetArg (al[ac], XmNtitle, P3_TITLE); ac++;
#ifdef BEFORE_CREATE
   XtSetArg (al[ac], XmNdeleteResponse, XmUNMAP); ac++;
#endif

#ifdef MULTIPLE_APP_SHELLS
   shell3 = XtAppCreateShell ("shell3", "ProgramClass",
                applicationShellWidgetClass, theDisplay, al, ac);
#else
#ifdef POPUP_SHELL
   /* See comments for shell2 */
   shell3 = XtCreatePopupShell ("shell3",
                topLevelShellWidgetClass, shell1, al, ac);
#else
   shell3 = XtAppCreateShell ("shell3", "ProgramClass",
                topLevelShellWidgetClass, theDisplay, al, ac);
#endif
#endif

   /* Tell mwm to exec CloseCB when close is detected. */
   delwinAtom3 = XmInternAtom (XtDisplay(shell3),
                                    "WM_DELETE_WINDOW", False);
   XmAddWMProtocolCallback (shell3, delwinAtom3, CloseCB, P3_TITLE);

#ifndef BEFORE_CREATE
   XtVaSetValues( shell3, XmNdeleteResponse, XmUNMAP, NULL);
#endif

   /* ---------------------   BEGIN P4  -------------------- */
   ac = 0;
   XtSetArg(al[ac], XmNx, 0); ac++;
   XtSetArg(al[ac], XmNy, 250); ac++;
   XtSetArg(al[ac], XmNwidth, 350); ac++;
   XtSetArg(al[ac], XmNheight, 200); ac++;
   XtSetArg (al[ac], XmNtitle, P4_TITLE); ac++;
#ifdef BEFORE_CREATE
   XtSetArg (al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
#endif

#ifdef MULTIPLE_APP_SHELLS
   shell4 = XtAppCreateShell ("shell4", "ProgramClass",
                applicationShellWidgetClass, theDisplay, al, ac);
#else
#ifdef POPUP_SHELL
   /* See comments for shell2 */
   shell4 = XtCreatePopupShell ("shell4",
                topLevelShellWidgetClass, shell1, al, ac);
#else
   shell4 = XtAppCreateShell ("shell4", "ProgramClass",
                topLevelShellWidgetClass, theDisplay, al, ac);
#endif
#endif

   /* Tell mwm to exec CloseCB when close is detected. */
   delwinAtom4 = XmInternAtom (XtDisplay(shell4),
                                    "WM_DELETE_WINDOW", False);
   XmAddWMProtocolCallback (shell4, delwinAtom4, CloseCB, P4_TITLE);

#ifndef BEFORE_CREATE
   XtVaSetValues( shell4, XmNdeleteResponse, XmDO_NOTHING, NULL);
#endif

   /* just for fun */
   ac = 0;
   WindowPopupMenu = XmCreatePopupMenu(shell1, "PopupMenu", al, ac);
   XtAddEventHandler( shell1, ButtonPressMask, FALSE, popup_handler,
                      WindowPopupMenu);

   ac = 0;
   xms = (XmString) XmStringCreateLocalized ( "Button3 = popup; Button2 = DnD.");
   XtSetArg(al[ac], XmNlabelString, xms); ac++;
   XtSetArg(al[ac], XmNshadowThickness, 2); ac++;
   label = XmCreateLabel (shell1, "label", al, ac);
   XtManageChild ( label );

   XtRealizeWidget( shell1 );

   /* NOTE use of XtPopup rather than XtRealizeWidget for topLevels */

#ifdef MULTIPLE_APP_SHELLS
   XtRealizeWidget( shell2 );
   XtRealizeWidget( shell3 );
   XtRealizeWidget( shell4 );
#else
#ifdef POPUP_SHELL
   XtPopup ( shell2, XtGrabNone );
   XtPopup ( shell3, XtGrabNone );
   XtPopup ( shell4, XtGrabNone );
#else
   XtRealizeWidget( shell2 );
   XtRealizeWidget( shell3 );
   XtRealizeWidget( shell4 );
#endif
#endif

   XtAppMainLoop (app_context);
}

----------------------------------------------------------------------------
Subject: 82)  Is there an mwm virtual desktop manager?

[Last modified: Nov 94]

Answer:  David Kaelbling (drk@x.org) reports:  In OSF/Motif 2.0, mwm supports
both workspaces (see the f.cci function and the wsm demo for a sample
interface) and a virtual root window.  To manipulate the virtual screen
f.goto, f.pan, and f.track_pan were added, as were iconPinned and clientPinned
client resources.

Peter E. Wagner (pwagner@panix.com):  Imagine that your "desktop" extends
beyond the view provided by your monitor.  A virtual window manager gives you
access to the space beyond your viewport (i.e. your screen) by allowing you to
move the viewport to other areas of the extended desktop.

The first one is Solbourne's swm, which spawned vtwm/tvtwm/olvwm.

David B. Lewis created one.  suresh@unipalm.co.uk has further developed it
into the UniPalm product DOORS, which is only available as a source code
extension to the MOTIF window manager.  The price of the source and unlimited
right to distribute binaries is 10,000 pounds Sterling.  Alternately, source
and right to use within one company is 2,000 pounds Sterling.  Contact Peter
Dawe

Unipalm Limited                         Voice: +44 (0) 223 420002
216 The Science Park                    Fax:   +44 (0) 223 426868
CAMBRIDGE
CB4 4WA

An enhancement request for such an object has been filed with OSF.

Tim Failes (tim@aus.oz.au) of Advanced User Systems Pty Ltd writes:  IXI has a
fully supported product called Panorama which provides this facility.
Panorama allows the user to pan around the virtual work space, dynamically
change the size of the virtual workspace, and also access windows via an icon
box.  Panorama also includes a point-and-click tool for setting resources such
as colours, focus policy, etc. [IXI contact information appears in the "Where
can I get Motif?" subject. -ed]

-----------------------------------------------------------------------------
Subject: 83)  Why does mwm 1.2 crash on startup?

[Last modified: March 93]

Answer:  David Brooks wrote:  The commonest cause of early mwm demise is as
follows:

- You, or someone, built Xlib in the default way using the Xsi
  internationalization functions.

- Your Xlib wasn't installed completely (or at all).

- Early on, mwm calls the function XmbTextListToTextProperty, which calls
  _XConvertMBToCT, which looks for the Xsi locale database, finds it
  missing, ignores this fact and tries to dereference zero.

The workaround is to find the database *somewhere*, and point the environment
variable XNLSPATH at it.  For example, in my personal X source tree:

        setenv XNLSPATH /home/X11r5src/mit/lib/nls/Xsi

-----------------------------------------------------------------------------
Subject: 84)  How do I obtain the size of a unmanaged shell widget?

Answer:  In the code below, use getsize() for widgets which have been managed,
and getsize2() for newly created shell widgets which have not yet been
managed.

getsize2() takes two widget parameters because popup dialogs etc.  _consist_
of two separate widgets - the parent shell and the child bulletin board, form,
whatever.  This important distinction (somewhat glossed over in the Motif
manuals) is the cause of a large number of queries in comp.windows.x.motif.
XmCreate...Dialog() functions return the (bulletin board, form, whatever)
_child_ of the pair, not the parent shell.

getsize2() takes the _shell_ widget as it's first parameter, and the shell's
_child_ (the bulletin board, form, whatever) as it's second.  Thus, if you are
using code like widget = XmCreate...Dialog() to create your popup dialogs, use
code like getsize2(XtParent(widget),widget,&width,&height) to get the width
and height. If you use e.g. XmCreateDialogShell() or XtCreatePopupShell(),
then you are creating the the shell widget and it's child explicitly, and can
just pass them into getsize2() with no problem.

Note: getsize2() calls getsize().

/* getsize(widget,width,height);
 * Widget widget;
 * int *width,*height;
 *
 * returns the width and height of a managed widget */


void getsize(l,w,h) Widget l; int *w,*h; { Dimension w_,h_,b_;

static Arg size_args[] =
  {
  { XmNwidth,0 },
  { XmNheight,0 },
  { XmNborderWidth,0 },
  };

size_args[0].value = (XtArgVal)&w_; size_args[1].value = (XtArgVal)&h_;
size_args[2].value = (XtArgVal)&b_;

XtGetValues(l,size_args,3);

if (w) *w = w_ + b_; if (h) *h = h_ + b_; } /*
getsize2(shell,child,width,height);
 * Widget shell,child;
 * int *width,*height;
 *
 * returns the width, height of an unmanaged shell widget */

void getsize2(p,c,w,h) Widget p,c; int *w,*h; { XtSetMappedWhenManaged(p,0);

XtManageChild(c);

getsize(p,w,h);

XtUnmanageChild(c);

XtSetMappedWhenManaged(p,-1); } submitted by:  [ Huw Rogers  Communications
Software Engineer, NEC Corporation, Tokyo, Japan ] [ Email:
rogersh@ccs.mt.nec.co.jp  Fax: +81-3-5476-1005  Tel: +81-3-5476-1096 ]

-----------------------------------------------------------------------------
Subject: 85)  How can I create a shell widget with a non-default visual type?

[Last modified: Apr 95]

Answer:  You must specify the colormap, visual type, and depth for the shell
before it is realized.  If you don't specify all three resources (or specify
them incorrectly), you will probably get BadMatch protocol errors from your X
server.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 86)  Why do I get BadMatch errors from my menus when I use a non-
default visual type for my application shell?


[Last modified: Sept 95]

Answer:  Unfortunately, the visual type and depth attributes are copied
differently from parent to child.  To be safe you use non-default visuals on
any of your widgets and use these as parents for shell widgets (including
menus), you should set the visual type, depth, and colormap on the child
shells.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 87)  How do I popup a scrolled list on top of other widgets?

[Last modified: Sept 95 ]

Put it in an override redirect shell and do a XMapRaise on the shell's window.
That will do it.  If you're using Motif then just use a VendorShell with
XmNoverrideRedirect set to true.

Thanks to Doug Rand (drand@sgi.com)

-----------------------------------------------------------------------------
Subject: 88)  TOPIC: MOTIF DEVELOPMENT TOOLS (GUI BUILDERS and UIMS's)

-----------------------------------------------------------------------------
Subject: 89)* What GUI tools exist to assist in developing Motif applications?

[Last modified: July 96 ]

Answer:  [Note: July 96 update was only for X-Designer information changes.]

[A FAQ is not for "personal opinions" on these tools.  I don't think it is
appropriate to give such opinions through this particular posting, so I
haven't included any. I will include vendor-provided descriptions provided
they are concise and informative. See Subject 0 for contribution details.]

`Prototyping tools' and `code generation tools' come in two forms:

    GUI (Graphical User Interface) builder -
    those that can be used to design (and perhaps rehearse)
    the interface only ; and

    UIMS (User Interface Management Systems) -
    those that are a system supporting the development and
    execution of user interfaces.

However, this distinction can be somewhat arbitrary when specific tools are
categorized as either one or the other.  (Therefore, the classification below
should be taken with a kilogram of salt. :-)

A number of commercial and non-commercial tools of both kinds that will
support Motif are listed below. [NOTE: Vendors or individuals wishing to add
their product or tool to this list, or to change their entry, should email to
the maintainer of this FAQ.]

GUI builders:

        Builder Xcessory (bx)
        Druid
        ExoCODE/xm
        iXBUILD (formerly X Build)
        MOTIFATION
        WKSH (Windowing Korn Shell)
        X-Designer

UIMS:

        ALEX
        ezX User Interface Management System
        Galaxy
        MetaCard
        Serpent
        TAE Plus
        TeleUse
        UIMX
        VXP (Visual X windows Programming Interface)
        Widget Creation Library (Wcl)
        WINTERP
        XFaceMaker2


For users of the WWW, see also Brad A. Myers' `User Interface Software Tools'
list (which is not limited to Motif tools):
http://www.cs.cmu.edu/afs/cs.cmu.edu/user/bam/www/toolnames.html

Thanks to Robin Schald (wald@tfh-berlin.de) for updating the above URL.


Some contact addresses, presented in alphabetical order (without regard to GUI
or UIMS categorization), follow:


o  ALEX:  For more information contact Michael Karliner on (+44) 81 566 2307
or E-mail to alex@s-strat.co.uk.  ALEX Technologies, Waterman's Yard, 32a The
Mall, Ealing, London W5, UK.


o  Builder Xcessory (bx): is from ICS.  More details are available by sending
a request to info@ics.com.  Address:

        ICS Inc.,
        201 Broadway,
        Cambridge MA 02139,
        Tel. (617) 621-0060,
        Fax. (617) 621-9555
        http://www.ics.com/


o  Druid: is a commercial product. It currently supports Motif1.1 and 4 unix
platforms: SPARC, HP 9000, RS6000, and SGI. For further information contact:

        Mr. Fred Lee,
        Automated Systems (Pte) Limited,
        203 Henderson Road, #12-07/14,
        Henderson Industrial Park,
        Singapore 0315.
        FAX: (65)272-2029


Or: Dr. Gurminder Singh (gsingh@iss.nus.sg), Institute of Systems Science,
National University of Singapore


o  ExoCODE/xm:  By Expert Object Corp., 7250 Cicero Avenue, Lincolnwood, IL
60646 (708)676-5555.  Also:  ExoCODE, EXOC, 500 Hyacinth Place, Highland Park,
IL, 60035, (708) 926-8500, Motif or OpenLook or SunView.


o  ezX: Contact information:

        ezX User Interface Management System
        Sunrise Software, International
        170 Enterprise Center
        Middletown, RI 02840
        401-847-7868
        email: support@sunrise.com


o  Galaxy, Visix Software Inc., 11440 Commerce Park Drive, Reston, VA, 22091,
(800) 832-8668, Mac, Windows, Motif, OpenLook; very complete, Virtual Toolkit,
UIMS


o  iXBUILD (formerly X Build):

        iXOS Software GmbH,
        Bretonischer Ring 12,
        8011 Grasbrunn/Munich, Germany,
        email support@ixos.de or office@ixos.de,
        phone ++49-89-46005 0

or in the US:

        UniPress Software,
        2025 Lincoln Hwy.,
        Edison, NJ 08817,
        phone 1-800-222-0550


o  MetaCard: MetaCard 1.0 is supported on five popular UNIX/X11 platforms:
SPARC, Sun3, DECstation, HP-9000/300, and SCO ODT.  An HP-9000/700 port is
underway and should be available by the end of July.  [They] plan to support
IBM RS/6000, SGI Iris, and DG AViiON sometime fall '92.  For more information,
or to receive a free save-disabled but licensable copy of MetaCard, email to
info@metacard.com or call 303- 447-3936.  If you have anonymous FTP access to
the Internet, you can download the current engines, documentation, and an
unlicensed Home stack from ftp.metacard.com (128.138.213.21), directory
MetaCard.  Commercial users can get MetaCard from world.std.com
(192.74.137.5), directory pub/Metacard.  If you don't have an anonymous ftp
access, you can also download MetaCard from The World using kermit or xmodem
from the ~ftp/pub/MetaCard directory.  Sign up by calling 617-739-0202 (voice)
or via modem by dialing 617-739-9753 (7 bits even parity) and logging in as
new.

MetaCard 1.2 Beta 5 is now available for anonymous FTP from ftp.metacard.com
(directory MetaCard/1.2B5), and ftp.uu.net (directory vendor/MetaCard/1.2B5).

There is also a MetaCard mailing list.  To subscribe to the metacard-list,
send mail to listserv@grot.starconn.com with the following commands in the
body of the message:

      subscribe metacard-list firstname lastname
      quit

Replace "firstname lastname" with your name, not your e-mail address.


o  MOTIFATION:  PEM GmbH, Vaihinger Strasse 49, 7000 Stuttgart 80, Germany,
Tel: +49 (0) 711 713045, Fax: +49 (0) 711 713047 Email: basien@pem-
stuttgart.de.  Available for (Motif 1.2/1.1) on SunOS, Solaris 2.1, HP,
Interactive, ODT 3.0, Silicon Graphics, PCS, ...


o  Serpent:  The S/W is free (anonymous ftp) from ftp.sei.cmu.edu.  For more
info contact erik/robert at serpent-info@sei.cmu.edu.  NOTE: This is no longer
supported, and is apparently replaced by a commercial product called Alpha.


o  TAE Plus: TAE Plus is a mature, portable software development environment
that supports rapid prototyping, tailoring, and management of Motif-based
graphical user interfaces.  It particularly supports GUI development by non-
programmers and by programmers who are not well-versed in the details of X and
Motif.  Its code generator can produce C, C++, and Ada code and allows for
automatic merging of regenerated code with previously modified parts of the
interface code.  It supports generation of a UIL/Mrm representation of the
interface.

Scripting capabilities are provided to facilitate automatic testing, on-line
demos, and tutorials.  A record and playback feature lets you build scripts
simply by interacting with your GUI.  Dynamic Data Objects allow the developer
to create pictorial objects (e.g., a thermometer to show temperature), whose
dynamic portions (e.g., the mercury in the themometer) can change to reflect
changing data or be directly manipulated by the end-user. TAE Plus is
available on Sun, HP, IBM, SGI, and SCO Unix platforms.  Evaluation software
is available via anonymous ftp.

TAE Plus contact information:

        Century Computing, Inc.
        8101 Sandy Spring Road
        Laurel, MD 20707
        1-800-823-3228
        tae-info@cen.com
        http://www.cen.com/tae/


o  TeleUSE: (updated Sept. 95) Built around X Windows and OSF/Motif, TeleUSE's
comprehensive toolset gives you maximum control over every phase of graphical
user interface development, including static screen layout and design,
automatic implementation of callbacks, building the executable, and the
interactive test, debug, and maintenance cycles.  For more information, please
contact:

In North America and countries not specified below:

        Thomson Software Products (formerly Alsys)
        http://www.thomsoft.com/
        10251 Vista Sorrento Parkway, Suite 300
        San Diego, CA  92121
        619-457-2700 x244
        619-452-2117 (fax)
        guiinfo@thomsoft.com

        In France:  1 41 48 10 10
        In the UK:  0491 579 090
        In Sweden:  08 707 3060
        In Germany:  72 1 98653 0
        In Japan:  45 451 2412
        In Korea:  2 508 0098
        In India:  91 11 688 5974
        In Singapore:  65 481 8888
        In Australia:  6 257 1729

There's a TeleUSE FAQ:
        http://www.jagunet.com/dalmatian/TeleUSE.html (HTML)
        ftp://ftp.jagunet.com/pub/users/dalmatian/TeleUSE.FAQ (ASCII)


o  UIMX:

        Visual Edge Software Limited
        3870 Cote Vertu
        St Laurent, Quebec
        H4R 1V4
        Phone: (514) 332-6430
        Fax:   (514) 332-5914
or:
        Visual Edge Software Ltd.
        101 First Street, Suite 443
        Los Altos, CA 94022
        Phone: (415) 948-0753
        Fax:   (415) 948-0843


o  VXP (Visual X windows Programming Interface):

Yong Chen (stdyxc05@pip.shsu.edu) developed a Motif GUI builder called VXP --
Visual X windows Programming Interface. VXP has some UIMS capabilities. VXP is
now distributed as a freeware, and has been ported to SGI irix, HP hp-ux, Sun
OS4 and Solaris 2.x, DEC OSF/1, IBM AIX, Linux, SCO, NetBSD.  For more
information, visit VXP's WWW home page at

        http://www.shsu.edu/~stdyxc05/VXP/
or ftp at
        ftp.shsu.edu    /pub/VXP/


o  Widget Creation Library (Wcl):  The distribution is available in several
ways.  The preferred approach it for you to get the compressed tar file using
anonymous ftp from:


        ftp://ftp.x.org/R5contrib/Wcl-2.5.tar.Z  (X11R5 version)
        ftp://ftp.x.org/contrib/devel_tools/Wcl-2.7.tar.gz (X11R6 gzip)
        ftp://ftp.x.org/contrib/devel_tools/Wcl-2.7.tar.Z (X11R6 compressed)
or:
        ftp://ftp.crl.research.digital.com/pub/X11/contrib/devel_tools/Wcl-2.6.tar.Z
        ftp://ftp.crl.research.digital.com/pub/X11/contrib/devel_tools/Wcl-2.7.tar.Z
        ftp://ftp.crl.research.digital.com/pub/X11/contrib/devel_tools/Wcl-2.7.tar.gz


o  WINTERP: (Widget INTERPreter) An object-oriented rapid prototyping,
development and delivery environment for building extensible applications with
the OSF/Motif UI Toolkit and Xtango-based graphics/animation. By Niels Mayer
(mayer@netcom.com).  Mailing list: winterp-request@netcom.com. Available via
ftp from ftp.x.org:/contrib/devel_tools/winterp-2.xx.tar.gz (where 'xx' is
currently '03').

Key WINTERP Features:

        * High-level, Object-oriented interface to OSF/Motif and Xtoolkit.
        * High-level object-oriented 2.5D graphics&animation widget based
          on Xtango path transition animation system.
        * Ability to easily create new widget classes w/ complex graphical
          behavior using Xtango animation/graphics.
        * Automatic storeage management of all X/Xt/Motif data, Pixmaps,
          animations. Automatic resource conversion and management.
        * Asynchronous communications w/ other unix programs via
          expect-based subprocess facility.
        * Includes XmGraph to display graphs (both cyclic, acyclic,
          directed, undirected); graph nodes can be arbitrary widgets
          created by WINTERP; supports direct manipulation editing of graph.
        * GIF image support.
        * Lisp-eval server architecture supports inter-application
          communication.
        * Interactive programming via Gnu-Emacs or Motif-Text-widget interface.
        * Portable, small, fast, and free.


o  WKSH (Windowing Korn Shell):

        EXtensible Korn Shell (C language calling interface,
        dynamic library loading, etc.)
        Motif or OpenLook API
        X Toolkit Intrinsics
        WKSH Convenience Functions
        Fast Learning and Prototyping Feature (ksh interpreter)
Contact:
        Acacia Computer,
        PO Box 4376,
        Warren, NJ 07059,
        Phone: 908 548 6955,
        Email: uunet!aca1


or: Computer Aid Inc, 1-(800)-444-WKSH, or:


        Consensys Corp,
        Europe: +(44)-734-833241 (Roger Chalke), +(44)0734-835391 (Fax),
        US: (416)-940-2903, (416)-940-2903 (Fax).


WKSH was developed by USL. Binaries are available through Acacia Computer for
SUNOS, Solaris, SCO ODT, Intel SVR4.0


o  X-Designer:  a GUI builder for both Motif and Microsoft Windows.  From one
design C or C++ code can be generated for building with the X/Motif or the
Microsoft Foundation Class (MFC) libraries using only the native toolkits.

        Imperial Software Technology
        Berkshire House
        252 Kings Road
        Reading
        RG1 4HP
        UK
        TEL: +44 118 958 7055
        FAX: +44 118 958 9005

        120 Hawthorne Avenue, Suite 101
        Palo Alto, CA 94301 USA
        (415) 688 0200
        (415) 688 1054 (fax)

        sales@ist.co.uk
        URL: http://www.ist.co.uk


o  XFaceMaker2:

        NSL -  Non Standard Logics S.A.,
        57-59, rue Lhomond,
        75005  Paris - France,
        Phone: +33 (1) 43.36.77.50,
        Fax:   +33 (1) 43.36.59.78
        email: requests@nsl.fr or requests%nsl.fr@inria.fr for information.

Their North American office:

        Non Standard Logics, Inc.,
        4141 State Street, Suite B-11,
        Santa Barbara CA 93110,
        Tel: 805 964 9599,
        Fax: 805 964 4367

-----------------------------------------------------------------------------
Subject: 90)  TOPIC: GEOMETRY MANAGEMENT

[NOTE: Send me your ideas for answered questions pertaining to this topic.]

-----------------------------------------------------------------------------
Subject: 91)  Why is geometry management so important?

[Last modified: Sept 94]

Answer:  Geometry management is a key element of Motif applications for
reasons which include, but are not limited to, the following:


    The user should be able to re-size the shell and get
    some reasonable geometry response (other than clipping).

    The user should be able to tailor fonts and have the
    widgets adjust accordingly.  (Many people over 40 simply
    can't read small fonts without serious eye strain.)

    When the designers decide to change a label, the widgets
    should re-adjust accordingly.

    Some labels must be set dynamically and the widgets should
    re-layout accordingly.

    An internationalized application must work with several resource
    files, one for each supported natural language.  The labels in each
    file have different lengths and the application should adjust
    accordingly.


-----------------------------------------------------------------------------
Subject: 92)  What are good references for reading about geometry management?

[Last modified: Oct 94]

Answer:  See the BOOKS topics for detailed reference information.  "X Toolkit
Intrinsics Programming Manual" (Nye & O'Reilly) contains an entire chapter on
geometry management, as does "X Window System Toolkit" (Asente & Swick) on
which the O'Reilly book is based.  Another good reference is the discussion of
the "geometry_manager" and "query_geometry" methods in "X Toolkit Intrinsics
Reference Manual".

"Motif Programming Manual" (Heller & Ferguson) has a chapter devoted to Motif
Manager widgets.  Finally, the widget documentation for each geometry manager
widget typically describes its policy in detail.

-----------------------------------------------------------------------------
Subject: 93)  Why don't my labels resize in a RowColumn widget?  I have a
RowColumn widget in my application, with several rows and columns of XmLabels.
When I update the text in the labels, the label's width does not get updated.

[Last modified: Oct 94]

Answer:  Make sure all the ancestor widget resize mechanisms are enabled:

   - on shells, set XmNallowShellResize
   - on row column, set XmNresizeWidth and XmNresizeHeight
   - on bulletin board and form, set XmNresizePolicy

Also, set XmNrecomputeSize on the label itself.  The shell resource is off by
default; the others should be on by default.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 94)  Why do dialogs appear smaller under 1.2.3 and later?  The same
problem occurs with parts of a complex main window.  All of my dialogs which
were fine under 1.2.2 and earlier come up too small to work with under 1.2.3
(or later). Why?

A. Thanks to David Brooks (dbrooks@ics.com) for pointing me to Daniel
Dardailler (daniel@x.org) who wrote this scholarly treatise:

      Application's Geometry Management Advanced Guidelines:
      =====================================================
      (or "How to properly manage children of already realized parent")

Xt Background:
-------------

    XtCreateWidget:        call Initialize ;

    XtManageChild:         if (parent realized)
                              call ChangeManaged ;
                              call Realize ;

    XtRealizeWidget:       postorder ChangeManaged loop ;
                           preorder Window-creation loop ;


Creating a widget only invokes its Initialize method (its parent's
InsertPosition method too, but that has nothing to do with GM).
Composite widgets, by opposition to Primitive, does
not usually get a correct size at initialization time, since their
correct size is based on their children sizes, which do not exist yet
at this time.

Applications usually create an entire tree of managed but
unrealized widgets and then realize their top level widget, which recursively
realize every widgets in the tree. During the creation process, the
managing of the unrealized widgets is a no-op (only mark them managed).

When XtRealizeWidget(toplevel) happens, the change_managed methods of
all the composite widgets in the tree are called in bottom-to-top
order, thus giving each of them a chance to determine their own size
based on their children *current* sizes (composite or not).
Using the current size of the children in this situation is fine,
since they should also be the children's preferred size, not
yet constrained by the parents layout (post-order traversal).

When one create a widget inside an already realized parent, this is
a different story and the order of management vs realization is important.

Consider a MessageBox created in a realized Frame.
The MessageBox itself creates a bunch of managed children
inside its Initialize method.
If you manage the MessageBox right after its creation, the Frame
ChangeManaged will be called (since it is realized), and its will use
the MessageBox current size as its base for its own size.
Unfortunately, the MessageBox ChangeManaged proc has never been called!
so its current size is whatever the default is, usually a non-settable
value (needed for tracking real initial size setting).
The MessageBox ChangeManaged has not been called because its children
were created and managed at a time where it wasn't realized.

What to do ?

The first solution would be to have all the ChangeManaged methods in
Motif call XtQueryGeometry instead of using the current size if it's
not the first time (i.e. if they're already realized).
But this is a lot of code to change and a kind of expensive run-time
process as it results in non-linear traversal order of the realized
tree (looks like an O(n!) but I'm not sure).
It's not even guaranteed that it will always work fine, since it relies on
the assumption that the geometry queried is the same that the geometry
asked for any manager (I mean, it might be the case, but if it's not,
it's just more code to fix in a very "bc-sensitive" part of Xm).


This other solution lies into the application, and is to realize a
manager first and then to manage it.
By realizing it, you are forcing its ChangeManaged proc to be
called (XtRealizeWidget does that), it will get a correct size and
this size will be used by its parent ChangeManaged when
you'll manage the manager. By explicitly realizing the branch
before managing its root, you are reproducing the ordering that
is typical of most applications at startup.

So the trick is:

        XtCreateWidget(realize_parent, MessageBox);
        XtRealizeWidget(MessageBox);  /* needed */
        XtManageChild(MessageBox);

and the model is:

    "Always explicitly realize a composite widget child of an already
     realized parent before managing it if all its children have been
     already managed"

One can always realize every widget children of realized parents, that
won't hurt, but it's useless for Primitives and Composites that
get more children added later in the program.
Why? because Primitives get their correct size at initialization
time anyway and adding a child to a Composite will generate a geometry
request and a layout that will have the same effect as if the
ChangeManaged method had been called (well, nearly the same effect,
that a complication I will address later).

If we consider Motif, this trick is only useful for MessageBox,
SelectionBox and subclasses, and Scale, since those are the only
Composites that create managed children in their Initialize method and
don't usually get additional kids from the application.

However, any application that re-creates this order of actions will
need to apply the "realize<manage" method too.
For instance:

        XtCreateWidget(realize_parent, DrawingArea);
        XtRealizeWidget(DrawingArea);   /* not needed */
        XtManageChild(DrawingArea);
        XtCreateWidget(DrawingArea, any_child) ;
        XtManageChild(any_child);
but
        XtCreateWidget(realize_parent, DrawingArea);
        XtCreateWidget(DrawingArea, any_child) ;
        XtManageChild(any_child);
        XtRealizeWidget(DrawingArea);   /* needed */
        XtManageChild(DrawingArea);

Now this is becoming interesting: there are exceptions to the model :-)

The first one is the Xt Shell widget, which has what I consider to be a
bug, but what MIT has, until recently, always considered to be a specific
behavior overridable by a subclass (like our VendorShell):
the ChangeManaged method always resizes the child to its own size
when the Shell is realized.

A side effect of this behavior is that even the realized<managed trick
won't work for direct descendant of Shell widget:

        XtCreateWidget(realize_shell, MessageBox);
        XtRealizeWidget(MessageBox);  /* needless */
        XtManageChild(MessageBox);    /* will get resized anyway */

To get rid of this problem, one needs to add a regular manager
between the Shell and the MessageBox in this case, for the sake
of having this manager doing a request to the Shell from its
ChangeManaged proc. This request will then be handled by the Shell
geometry manager, not its ChangeManaged proc, and it will take into
account the child size.
Note that we could also change our VendorShell ChangeManaged code to not
systematically envelop the Xt Shell ChangeManaged class method, and
check for the already realized case, but I would rather wait
for an Xt fix instead (I'm working on it).

If you broader the scope of the Xt Shell situation, you find that there are
also some resources in Xm that come into effect upon geometry request
reception but are not used in the ChangeManaged method.

Take the PanedWindow constraint resource XmNallowResize for instance,
which controls the validity of a geometry request made by a PW child.

If you do:

        XtCreateWidget(realize_shell, PanedWindow);
        XtManageChild(PanedWindow);

        XtCreateWidget(PanedWindow, button);
        XtManageChild(button);

that works fine since the ChangeManaged of the PanedWindow will
handle the insertion of the button and allowResize won't be used.

But if you add a manager in this hierarchy:

        XtCreateWidget(realize_parent, PanedWindow);
        XtManageChild(PanedWindow);

        XtCreateWidget(PanedWindow, manager);
        XtManageChild(manager);

        XtCreateWidget(manager, button);
        XtManageChild(button);

That doesn't work anymore since the button management results in
its parent manager's ChangeManaged being called, which in turn makes a
*request* to the PanedWindow, resulting in a No reply because
of allowResize (set to False by default).

The PanedWindow parent wouldn't have been realized that everything
would have worked fine, since no request would have been made.
It really depends on the early realization scheme.

I think XmNresizable in Form is the only other resource to present
this problem. There is not much to do in those cases except than
setting the corresponding resource to True, which makes sense.


-----------------------------------------------------------------------------
Subject: 95)  How does the ScrolledWindow manage resizing?

[Last modified: June 95]

Answer:  The scrolled window should resize its immediate child when it is
resized.  The child is XmNworkWindow in the default application-defined
scrolling mode or XmNclipWindow in the automatic scrolling mode.  In either
case, you can then resize your row column.  If you set XmNadjustLast, the
children of a one column row column will be automatically resized.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 96)  Does the XmPanedWindow widget support horizontal paning?

[Last modified: June 95]

Answer:  In Motif 2.0 it does, but not in Motif 1.x.  There are, however, some
3rd party horizontal paned widgets listed in the Widget FAQ,
http://www.wri.com/~cwikla/widget/, by John Cwikla.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 97)  TOPIC: TEXT WIDGET

-----------------------------------------------------------------------------
Subject: 98)  How do XmTextField and a single line XmText widget differ?

[Last modified: Oct 94]

Answer:  XmTextField is designed to be a lightweight, single line text editor.
It does not provide as much functionality as does XmText in order to achieve
better performance.

Thanks to Kevin Till, kev@osf.org

-----------------------------------------------------------------------------
Subject: 99)  Why does  pressing RETURN in a text widget do nothing?  This
happens using Motif 1.0 when I have a text widget inside a bulletin board (or
form) inside a dialog shell. (In Motif 1.1 it is fixed for both text and list
widgets.)

Answer:  In single line mode, pressing the <return> key usually invokes the
activate() action, and in multi-line mode, the newline() action.  However,
whenever a widget is the child of a bulletin board widget which is the child
of a dialog shell, the bulletin board forces all of its children to translate
<return> to the bulletin board action Return() which is usually associated
with the default button of the dialog.  To restore the text actions of
activate() or newline(), you need to overide the Return() action of the
bulletin board.


        /* declarations */
        /* for a single line widget */
        char newTrans[] = "<Key>Return : activate()";
        /* for a multi line widget */
        char newTrans[] = "<Key>Return : newline()";
        XtTranslations transTable;

        /* in executable section */

        transTable = XtParseTranslationTable(newTrans);

        /* after creating but before managing text widget */

        XtOverrideTranslations(textWidget, transTable);


-----------------------------------------------------------------------------
Subject: 100)  When I add text to a scrolling text widget, how can I get the
new text to show?

[Last modified: Sept 94]

Answer:  Use the (fully supported) function XmTextShowPosition:

        void XmTextShowPosition(w, position)
        Widget w;
        XmTextPosition position;

where the position is the number of characters from the beginning of the
buffer of the text to be displayed. If you don't know how many characters are
in the buffer, use XmTextGetLastPosition.

        position = XmTextGetLastPosition(w)

-----------------------------------------------------------------------------
Subject: 101)  How do I scroll text to display the most recently added
information?

[Last modified: Aug 95]

Answer:  If you're using the XmScrolledText widget, use
XmTextSetTopCharacter() or XmTextScroll(). Thanks to Ken Lee,
kenton@rahul.net.

-----------------------------------------------------------------------------
Subject: 102)  Does the text widget support 16 bit character fonts?


[Last modified: November 92]

Answer:  R5 has support for 16 bit character sets, and Motif 1.2 uses that.
Neither Motif 1.0 nor 1.1 support 16 bit sets.

-----------------------------------------------------------------------------
Subject: 103)  How can I stop the text widget from echoing characters typed?
I need to turn off echo for password input.

Answer:  Use the XmNmodifyVerifyCallback to tell when input is received. Set
the `doit' field in the XmTextVerifyCallbackStruct to False to stop the echo.
(In Motif 1.0 this will cause a beep per character: Live with it, because at
1.1 you can turn it off.)  Note that password hiding is inherently insecure in
X - someone may have an X grab on the keyboard and be reading all characters
typed in anyway.

Another solution often proposed is to set the foreground and background
colours to be the same, effectively hiding the text.  This has a major flaw:
someone may select the text (triple click the mouse to get the line), and then
paste the password into say an xterm with *different* foreground and
background colours.  This immediately shows the password.

-----------------------------------------------------------------------------
Subject: 104)  How can I replace characters typed with say a `*'?  I want to
replace input for password entry.

[Last modified: May 95]

Answer:  The solution involves the use of XmNmodifyVerifyCallback and then
examining the XmTextVerifyCallbackStruct.  The following program from Dan
Heller and Paula Ferguson illustrates this:


/* Written by Dan Heller and Paula Ferguson.
 * Copyright 1994, O'Reilly & Associates, Inc.
 * Permission to use, copy, and modify this program without
 * restriction is hereby granted, as long as this copyright
 * notice appears in each copy of the program source code.
 * This program is freely distributable without licensing fees and
 * is provided without guarantee or warrantee expressed or implied.
 * This program is -not- in the public domain.
 */

/* password.c -- prompt for a password. All input looks like
 * a series of *'s.  Store the actual data typed by the user in
 * an internal variable.  Don't allow paste operations.  Handle
 * backspacing by deleting all text from insertion point to the
 * end of text.
 */
#include <Xm/Text.h>
#include <Xm/LabelG.h>
#include <Xm/RowColumn.h>
#include <ctype.h>

void check_passwd();
char *passwd; /* store user-typed passwd here. */

main(argc, argv)
int argc;
char *argv[];
{
    Widget        toplevel, text_w, rowcol;
    XtAppContext  app;

    XtSetLanguageProc (NULL, NULL, NULL);

    toplevel = XtVaAppInitialize (&app, "Demos",
        NULL, 0, &argc, argv, NULL, NULL);

    rowcol = XtVaCreateWidget ("rowcol",
        xmRowColumnWidgetClass, toplevel,
        XmNorientation, XmHORIZONTAL,
        NULL);

    XtVaCreateManagedWidget ("Password:",
        xmLabelGadgetClass, rowcol, NULL);
    text_w = XtVaCreateManagedWidget ("text_w",
        xmTextWidgetClass, rowcol, NULL);

    XtAddCallback(text_w, XmNmodifyVerifyCallback, check_passwd, NULL);
    XtAddCallback(text_w, XmNactivateCallback, check_passwd, NULL);

    XtManageChild (rowcol);
    XtRealizeWidget (toplevel);
    XtAppMainLoop (app);
}

/* check_passwd() -- handle the input of a password. */
void
check_passwd(text_w, client_data, call_data)
Widget        text_w;
XtPointer     client_data;
XtPointer     call_data;
{
    char *new;
    int len;
    XmTextVerifyCallbackStruct *cbs =
        (XmTextVerifyCallbackStruct *) call_data;

    if (cbs->reason == XmCR_ACTIVATE) {
        printf ("Password: %s\n", passwd);
        return;
    }

    if (cbs->startPos < cbs->currInsert) {   /* backspace */
        cbs->endPos = strlen (passwd);       /* delete from here to end */
        passwd[cbs->startPos] = 0;           /* backspace--terminate */
        return;
    }

    if (cbs->text->length > 1) {
        cbs->doit = False;  /* don't allow "paste" operations */
        return;             /* make the user *type* the password! */
    }

    new = XtMalloc (cbs->endPos + 2); /* new char + NULL terminator */
    if (passwd) {
        strcpy (new, passwd);
        XtFree (passwd);
    } else
        new[0] = NULL;
    passwd = new;
    strncat (passwd, cbs->text->ptr, cbs->text->length);
    passwd[cbs->endPos + cbs->text->length] = 0;

    for (len = 0; len < cbs->text->length; len++)
        cbs->text->ptr[len] = '*';
}

Thanks to OM1_JDA@pki-nbg.philips.de (Joerg Danne) for alerting me to updating
this code sample.

-----------------------------------------------------------------------------
END OF PART FOUR
