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


-----------------------------------------------------------------------------
Subject: 105)  How can I best add a large piece of text to a scrolled text
widget?

[Last modified: Sept 94]

[NOTE: This problem is probably only relevant for Motif 1.0 which probably no
one is using anymore. If you know this to still be a problem, send mail to
ksall@cen.com. I'll probably remove this question otherwise.]

In some versions of Motif 1.0 even using XmTextSetString, it insists on adding
the text one line at a time, adjusting the scroll bar each time. It looks
awful and is slow.

Answer:  If you don't have this problem, use XmTextSetString to set all of the
text in the widget.  If you do have this slowdown problem even using
XmTextSetString, unmanage the widget, add the text and then manage it again.
This may cause the window to blink, but you have to put up with that or switch
to a different version of Motif.

-----------------------------------------------------------------------------
Subject: 106)  How can I highlight text in the Text widget?

Answer:  argv@zipcode.com (Dan Heller) wrote:

If you don't need font or color changes, you can do all this using a Text
widget very easily [in Motif 1.1, anyway].

        loop() {
            pos = offset_of_pattern_in_text_widget(pattern, text_w);
            search_len = strlen(pattern);
            XmTextSetHighlight(text_w, pos, pos+search_len,
                        XmHIGHLIGHT_SELECTED);
        }


There are two choices for highlighting: reverse video (HIGHLIGHT_SELECTED) and
underlined (HIGHLIGHT_SECONDARY_SELECTED).  Be careful that your users won't
confuse your highlights with actual selections!

-----------------------------------------------------------------------------
Subject: 107)  How can I select all of the text in a widget programmatically?
So that some initial text is displayed, but anything typed replaces it.

[Last modified: July 95]

Answer:  XmTextSetSelection(Text1, 0, XmTextGetLastPosition(Text1), event-
>xbutton.time);

where Text1 is the widget in question (obviously) and event is some event that
triggered this call.  You can use XtLastTimestampProcessed( display) instead
of xbutton.time if you don't happen to have an event pointer handy.

Jon A. Christopher (jac8792@tam2000.tamu.edu) writes:

I have had difficulty getting this to work as described (even though it agrees
with the documentation).  I believe that it may be because I usually change
the TextField to some value and then try to select it.  I haven't looked at
the internals of the TextField widget, but it must only select the text if the
text hasn't changed since the time specified.  Ususally the
"LastTimestampProcessed" will be be *before* you modify the text, and the
selection is therefore ignored.  I'd suggest using the CurrentTime variable.
This is an X variable which, if used will make sure that your text is always
selected.

-----------------------------------------------------------------------------
Subject: 108)  How can I change colours of text in the Text widget?  I want
some of the text in one colour, some in another.

[Last modified: June 95]

Answer:  In Motif 1.x, you can't.  Text stores an ordinary string, and points
where `highlights' of various types begin and end.  These highlights are all
the control you have over components of the text.

However, in Motif 2.0, XmStrings may be different colors in the same widget.

Thanks to Ken Lee, kenton@rahul.net, for the update.

-----------------------------------------------------------------------------
Subject: 109)  How can I change the font of text in the Text widget?  I want
some of the text in one font, some in another.

[Last modified: Sept 94]

Answer:  You can't in Text (see the previous question).  If you wanted
readonly text, you could do it by using a label instead.  Label uses
XmStrings, which can contain multiple character sets in the one string.

If you are using Motif 2.0, however, XmStrings are now permitted in XmText
widgets, which solves this particular problem.

-----------------------------------------------------------------------------
Subject: 110)  Is there an emacs binding for the text widget?

Answer:  This set is due to Kee Hinckley (nazgul@utopia.com):

*XmText.translations: #override\n\
        Ctrl <Key>b:            backward-character()\n\
        Alt <Key>b:             backward-word()\n\
        Meta <Key>b:            backward-word()\n\
        Shift Alt <Key>b:       backward-word(extend)\n\
        Shift Meta <Key>b:      backward-word(extend)\n\
        Alt <Key>[:             backward-paragraph()\n\
        Meta <Key>[:            backward-paragraph()\n\
        Shift Alt <Key>[:       backward-paragraph(extend)\n\
        Shift Meta <Key>[:      backward-paragraph(extend)\n\
        Alt <Key><:             beginning-of-file()\n\
        Meta <Key><:            beginning-of-file()\n\
        Ctrl <Key>a:            beginning-of-line()\n\
        Shift Ctrl <Key>a:      beginning-of-line(extend)\n\
        Ctrl <Key>osfInsert:    copy-clipboard()\n\
        Shift <Key>osfDelete:   cut-clipboard()\n\
        Shift <Key>osfInsert:   paste-clipboard()\n\
        Alt <Key>>:             end-of-file()\n\
        Meta <Key>>:            end-of-file()\n\
        Ctrl <Key>e:            end-of-line()\n\
        Shift Ctrl <Key>e:      end-of-line(extend)\n\
        Ctrl <Key>f:            forward-character()\n\
        Alt <Key>]:             forward-paragraph()\n\
        Meta <Key>]:            forward-paragraph()\n\
        Shift Alt <Key>]:       forward-paragraph(extend)\n\
        Shift Meta <Key>]:      forward-paragraph(extend)\n\
        Ctrl Alt <Key>f:        forward-word()\n\
        Ctrl Meta <Key>f:       forward-word()\n\
        Ctrl <Key>d:            kill-next-character()\n\
        Alt <Key>BackSpace:     kill-previous-word()\n\
        Meta <Key>BackSpace:    kill-previous-word()\n\
        Ctrl <Key>w:            key-select() kill-selection()\n\
        Ctrl <Key>y:            unkill()\n\
        Ctrl <Key>k:            kill-to-end-of-line()\n\
        Alt <Key>Delete:        kill-to-start-of-line()\n\
        Meta <Key>Delete:       kill-to-start-of-line()\n\
        Ctrl <Key>o:            newline-and-backup()\n\
        Ctrl <Key>j:            newline-and-indent()\n\
        Ctrl <Key>n:            next-line()\n\
        Ctrl <Key>osfLeft:      page-left()\n\
        Ctrl <Key>osfRight:     page-right()\n\
        Ctrl <Key>p:            previous-line()\n\
        Ctrl <Key>g:            process-cancel()\n\
        Ctrl <Key>l:            redraw-display()\n\
        Ctrl <Key>osfDown:      next-page()\n\
        Ctrl <Key>osfUp:        previous-page()\n\
        Ctrl <Key>space:        set-anchor()


! If you'd like the Delete key to work like backspace instead of deleting
! backwards, add the following definition to the lines above.
!       <Key>osfDelete: delete-previous-character()\n\

! These aren't included because they could intefere with
| menu accelerators (or vice versa)
!       Alt <Key>p:             backward-paragraph()\n\
!       Meta <Key>p:            backward-paragraph()\n\
!       Shift Alt<Key>p:        backward-paragraph(extend)\n\
!       Shift Meta<Key>p:       backward-paragraph(extend)\n\
!       Alt <Key>w:             copy-clipboard()\n\
!       Meta <Key>w:            copy-clipboard()\n\
!       Ctrl Alt <Key>w:        cut-clipboard()\n\
!       Ctrl Meta <Key>w:       cut-clipboard()\n\
!       Alt <Key>y:             paste-clipboard()\n\
!       Meta <Key>y:            paste-clipboard()\n\
!       Alt <Key>f:             forward-word()\n\
!       Meta <Key>f:            forward-word()\n\
!       Alt <Key>n:             forward-paragraph()\n\
!       Meta <Key>n:            forward-paragraph()\n\
!       Shift Alt <Key>n:       forward-paragraph(extend)\n\
!       Shift Meta <Key>n:      forward-paragraph(extend)\n\
!       Shift Alt <Key>f:       forward-word(extend)\n\
!       Shift Meta <Key>f:      forward-word(extend)\n\
!       Alt <Key>d:             kill-next-word()\n\
!       Meta <Key>d:            kill-next-word()\n\
!       Alt <Key>h:             select-all()\n\
!       Meta <Key>h:            select-all()\n\

Similar sets of translations have been suggested by others.

-----------------------------------------------------------------------------
Subject: 111)  What if I have problems with the backspace/delete keys?

[Last modified: Dec 94]

Answer:  mclarnon@maths.ox.ac.uk (Gerald.McLarnon) writes:

I am running a precompiled program based on motif and am having some problems
with the backspace/delete keys. Following the instructions of the faq I put th
e following lines in my .Xdefaults file

     *XmText.translations: #override                    <Key>osfDelete:
delete-previous-character()
     *XmTextField.translations: #override                    <Key>osfDelete:
delete-previous-character()
  This meant that in dialogue boxes (such as 'Open File') the delete key
  deleted to the left, but not in the main application window.

  Any hints for someone who isn't much of an X-pert?

David Kaelbling <drk@x.org> replied:

There are a couple possibilities.  In addition to the precedence of loading
resource files (explained in section 2.3 of the X11R5 X Toolkit Intrinsics
manual), resource values in the database are chosen based on a "most explicit
match" algorithm (i.e. those with the most qualifiers on the left hand side
win -- see section 15.2 of the X11R5 Xlib - C Library manual).  So if this
application's app-defaults file or fallback resources says
*Foo*XmText.translations:... that value will be used instead of yours.

Find the app-defaults file for your application and look to see if it
specifies translations for text widgets in the main application; if it does
you'll need to make yours at least as explicit.

If the app-defaults file isn't the problem then the application may be hard-
wiring the translations.  If that's the case you'll probably have to change
your virtual key bindings so that the key you think of as osfDelete is really
osfBackSpace.  You can do that for an individual application by setting its
defaultVirtualBindings resource, or for all Motif applications with a
$HOME/.motifbind file ("man xmbind" and "man VirtualBindings" give more detail
and alternatives).  In either case you'll need to specify a complete list of
virtual key bindings; there is no equivalent to #override.  To find out your
current virtual key bindings run "xprop -root | fgrep BINDINGS" and clean up
the result.

-----------------------------------------------------------------------------
Subject: 112)  How can I use a file as the text source for a Text widget?

Answer:  You can't do it directly like you can with the Athena Text widget.
Instead, read the text from the file into a string (all of it!) and then use
XmTextSetString.  Alternatively, read blocks of characters and add them at the
end of the text using XmTextInsertString.  The following is an excerpt from
Dan Heller's "file_browser.c":

    /* file_browser.c -- use a ScrolledText object to view the
     * contents of arbitrary files chosen by the user from a
     * FileSelectionDialog or from a single-line text widget.
     */

    ...
    struct stat statb;

    /* make sure the file is a regular text file and open it */
    if (stat(filename, &statb) == -1 ||
            (statb.st_mode & S_IFMT) != S_IFREG ||
            !(fp = fopen(filename, "r"))) {
        if ((statb.st_mode & S_IFMT) == S_IFREG)
            perror(filename); /* send to stderr why we can't read it */
        else
            fprintf(stderr, "%s: not a regular file\n", filename);
        XtFree(filename);
        return;
    }

    /* put the contents of the file in the Text widget by allocating
     * enough space for the entire file, reading the file into the
     * allocated space, and using XmTextFieldSetString() to show the file.
     */
    if (!(text = XtMalloc((unsigned)(statb.st_size+1)))) {
        fprintf(stderr, "Can't alloc enough space for %s", filename);
        XtFree(filename);
        fclose(fp);
        return;
    }

    if (!fread(text, sizeof(char), statb.st_size+1, fp))
        fprintf(stderr, "Warning: may not have read entire file!\n");

    text[statb.st_size] = 0; /* be sure to NULL-terminate */

    /* insert file contents in Text widget */
    XmTextSetString(text_w, text);


-----------------------------------------------------------------------------
Subject: 113)  How can put Text in overstrike mode instead of insert?

[Last modified: Mar 95]

Answer:  (Be sure to read the update after the first answer. This is also a
second update which cautions against the approach.)

There is no direct way. This was posted by Edmond Pitt (ejp@bohra.cpg.oz) The
correct answer to the question is to put the following in a modifyVerify
callback, where 'mvcb' is the XmTextVerifyCallbackStruct, and 'overstriking'
is defined by you:

    if (overstriking && mvcb->text->length == 1)
    {
        _XmTextDisableRedisplay(w,FALSE);
        XtCallActionProc(w,"delete-next-character",mvcb->event,0);
        _XmTextEnableRedisplay(w);
    }

_XmText{Dis,En}ableRedisplay() are XmText{Dis,En}ableRedisplay() in 1.0, but
X11R3 has no XtCallActionProc() anyway. For this environment you need my 1.0.3
Text widget patches posted last year & available on request.

An update was provided by Ingeborg (inca@osf.org):

In 1.2 and later releases, there is an action function toggle-overstrike()
which will toggle between overstrike and insert mode. Before 1.2.3, there is
no visual difference, and at most one character will get overstruck. In 1.2.3,
a block cursor was added as a visual cue to that the widget is in overstrike
mode, and the code was fixed to overstrike the actual number of characters
input (this makes a difference if you have preediting - for example in
japanese).

There is no default binding in 1.2, but the recommended key is osfInsert
without modifiers.  No resource exists.


Ed Kaltenbach (kaltenba@ataway.aptec.com) wrote:

    I was simulating overstrike mode in the Text Field widget by using
    the delete_next_character solution listed in subject 71.
    When the software is compiled with Motif 1.2.2, the modifyVerify
    callback does not get called for the last character when XmNmaxLength
    is specified.  It seems that the check if maxLength has been reached
    is done before the modifyVerify gets called and it keeps the modifyVerify
    from being called.  Is this a Motif bug? Does anybody have a solution that
    will work with Versions 1.1 and 1.2 of Motif?


Phil Day <phil@cfmu.eurocontrol.be> responded to Ed (and apologized for only
sending pseudocode!):

I've had the same problem, and for my money it's a bug.  My workaround is to
make all text widgets (I don't use textfield because of some other problems in
the past) have XmNmaxLength > XmNcolumns, so that the modifyVerify callback
gets a chance to do its stuff.

If you only want to support overstrike for typing, 1 extra charater is enough,
but if you want to support cut-and-paste for any length string you need
maxLength = 2*columns.  In the modifyVerify you have to check the result is <
columns.

I've tried using the Motif 1.2 support for overstrike, but this just seems to
work on a kind of pending-delete and only works for the single charater
replacement caes (that's my main argument for calling it a bug).

I don't use delete-next-character (I can't remember why just now, but I know I
had some problem with it).  Instead I have something like the following:

modifyVerify()
{
        if (acceptable)
                XmReplaceText(...)

        cd->doit = False;
        // we've just done it, we don't wnat Motif to !

    XtVaSetValues (w,
                   XmNverifyBell, False,
                   NULL);
        // Otherwise we'll get a beep.
}

valueChanged()
{

    XtVaSetValues (w,
                   XmNverifyBell, True,
                   NULL);
        // turned off in modifyVerify

}

Glenn Mandelkern <gmandel@Corp.Megatest.Com> writes about a problem with the
above solution.


    We have been running our software on Sparc 20's, under Motif 1.1
    and Motif 1.2, X11R5, Solaris 2.4.
    Unfortunately, some colleagues and I have found a disturbing side effect
    when following this suggestion.  Calling XtVaSetValues() in the
    modifyVerifyCallback causes the Text widget to flash.

    The O'Reilly guides say not to call XtVaSetValues() during text
    modification callbacks.  Motif Volume 6 has this on page 511 and
    Motif Volume 6A has it on page 496.

    I myself thought it would be fairly trivial to just switch the bell
    on and off.  But since XtVaSetValues() calls XmText's set_values() method,
    my guess is that its set_values() does something that causes this.

    So when you enter characters, the Text widget flashes.  It also slows
    down the performance of the Text widget.  You'll see this on a multi-line
    Text widget, especially with it occupying a full screen with text.

    If you want to see this, take the editor.c program in Volume 6 or 6A,
    then add a modifyVerifyCallback to the text_output widget.  Then inside
    that callback, call XtVaSetValues with the XmNverifyBell like above.

    This is a common "mistake", one which I've done more than once.
    I remember also that when I did not have the XtVaSetValues() in place,
    I got the beeps.

    So now we've reworked the application as follows:
        1.  The Text widget is initially created with XmNverifyBell
            set to False.

        2.  We ring the bell using XBell() when we detect a condition
            for which we want to veto text modifications.

    For our application, this provides the wanted feedback and gets rid
    of the flashes.


-----------------------------------------------------------------------------
Subject: 114)  How can I make the Delete key do a Backspace?  Related
question: How can I swap Delete and Backspace?

[Last modified: Oct 94]

Answer:  Put this in your .Xdefaults

    *XmText.translations: #override <Key>osfDelete: delete-previous-character()


Additional information from David Kaelbling <drk@x.org>:

You can also supply an arbitrary file name to xmbind (so you can conditionally
run xmbind from your .xinitrc file based on the hostname, architecture,
xdpyinfo output, or whatever).

Some people prefer to use xmodmap to swap the keysyms for all applications,
but what you're doing will work fine if you specify all of the virtual key
bindings.  The current bindings are stored on the root window -- use "xprop
-root" and look for a _MOTIF_BINDINGS or _MOTIF_DEFAULT_BINDINGS property.
OSF/Motif is also distributed with a "bindings" directory containing all the
fallback virtkey binding files.

There are several ways to do display-specific customization: make

-----------------------------------------------------------------------------
Subject: 115)  Can I change the tab stops in the XmText widget?

[Last modified: May 95]

Answer:  No.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 116)  TOPIC: LIST WIDGET

-----------------------------------------------------------------------------
Subject: 117)  Should I create an XmList widget as a child of automatic
XmScrolledWindow or use the XmCreateScrolledList() convenience function?

Answer:  With most implementations, the convenience function use internal
hooks to give somewhat better scrolling performance.

Thanks to Ken Lee, kenton@rahul.net

-----------------------------------------------------------------------------
Subject: 118)  How do I best put a new set of items into a list?

Answer:  Set the new list count and list by XtSetArgs and install them by
XtSetValues.

    XmString list[SIZE];
    int list_size;

    XtSetArg (args[n], XmNitemCount, list_size); n++;
    XtSetArg (args[n], XmNitems, list); n++;
    XtSetValues (w, args, n);


or similarly with XtVaSetValues:


    XtVaSetValues (w,
       XmNitemCount, list_size,
       XmNitems, list,
       NULL);


Each time the list is reset by this the old contents are freed by the widget
and the new supplied list is copied.  Do *not* free the old list of items
yourself as this would result in the space being freed twice.  It is not
necessary to remove the items one at a time, nor to "zero" out the list first.

-----------------------------------------------------------------------------
Subject: 119)  Can I have strings with different fonts in a list?

[Last modified: Sept 95]

Answer:  Yes. The strings are XmStrings. Each one can be created using a
different character set using a different font.

However, arjav@caip.rutgers.edu (ARJAV PARIKH) wrote:

If a string is added to the listbox, the font in the listbox overrides the
font set using XmCreateString.  The Command widget label retains the font set
using XmCreateString.  I read in the MOTIF FAQ that it is possible to add
strings with multiple fonts to the listbox.  I learned from one of the tech
support persons that internal code of the listbox overrides the font.

Madhusudan Poolu (madhu@corp.sgi.com) replied:

You need to create a fontlist for your font and  add it to your listbox widget
using XtVaSetValues ( wList, XmNfontList, yourFontList, NULL).  This technique
can also be used to display multi-font strings in a list box.

-----------------------------------------------------------------------------
Subject: 120)  Can I get a bitmap to show in a list item like I can in a
Label?  I want to place a bitmap along with some normal text in my list items.

[Last modified: Jan 96]

Answer:  Andrew Lister (lister@bain.oz.au) writes:  The XbaeMatrix widget
allows a bitmaps in a cell.  There will be support for colour pixmaps to be
displayed in version 4.4 which should be available very soon. (The XbaeMatrix
can be made to look and behave like a list widget.  The widget is compatible
with Motif 1.2 and Motif 2.0.)  You can get the latest version of XbaeMatrix
from the directory:
        ftp://ftp.x.org/contrib/widgets/motif/

Alan Peery (peery@isc.tamu.edu) writes:  Motif 2.0 introduced the "container"
widget, which offers 2-D icon and text layout similar to that found in many
file management programs.  It could probably be used as a 1-D list widget
also.

A previous source wrote: In Motif 1.x, you cannot do this.  The list contains
XmStrings, and these only allow text in various character sets. The workaround
is to define your font containing the icons you want. Then you can create a
fontlist containing your icon font and the font you want the text in, and then
make your items multi-segment XmStrings where the first segment contains the
code of the icon you want with a charset that matches the icon font in your
fontlist and the second segment with a charset matching the text font.


-----------------------------------------------------------------------------
Subject: 121)  Can I have items with different colors in a list?

[Last modified: Jan 96]

Answer:  Andrew Lister (lister@bain.oz.au) writes:  The XbaeMatrix widget can
have a different foreground and background in each cell, row or column.  (The
XbaeMatrix can be made to look and behave like a list widget.  The widget is
compatible with Motif 1.2 and Motif 2.0.)  You can get the latest version of
XbaeMatrix from the directory:
        ftp://ftp.x.org/contrib/widgets/motif/

Ken Lee wrote:  Not in Motif 1.x.  The list contains XmStrings, and these only
allow text in various character sets.

However, in Motif 2.0 you _can_ have multiple colors in the same list since
colored XmStrings are supported.

Thanks to Ken Lee, kenton@rahul.net, for the update.

If you're using Motif 1.2, another possibility is to use IXI Premier Motif
(1.2) library has this extension built into the List widget, along with a few
others. See http://www.ixi.com/


Thanks to richardo@x.co.uk (Nhi Vanye)

-----------------------------------------------------------------------------
Subject: 122)  How can I line up columns in a list?

[Last modified: Jan 96]

Answer:  Andrew Lister (lister@bain.oz.au) writes:  The XbaeMatrix can do this
too, for both fixed and non fixed width fonts.  (The XbaeMatrix can be made to
look and behave like a list widget.  The widget is compatible with Motif 1.2
and Motif 2.0.)  You can get the latest version of XbaeMatrix from the
directory:
        ftp://ftp.x.org/contrib/widgets/motif/

-----------------------------------------------------------------------------
Subject: 123)  Can I grey out an item in a list?  I want to make insensitive
items in a list so that they cannot be selected.

Answer:

W. Scott Meeks of OSF wrote:

Unfortunately, you can't do it directly since the list items aren't individual
widgets.  We've had other requests for this technology, but it didn't make the
cut for 1.2; it should be in some future release.

However, you can probably fake it in your application with some difficulty.
First, a list item is an XmString, so you can specify a different charset for
the item than for other items in the list and then specify a font in the
list's fontlist that matches the charset and gives you the visual you want.
The next problem is making the item unselectable.  One idea would be to have
the application keep track of the insensitive items and the items currently
selected.  Then you would set up a selection callback that when called would
check the item selected against the list of insensitive items and if the
selected item matched would deselect that item and reselect the previously
selected items.  Otherwise it would just update the application's list of
selected items.  The major drawback with this approach is that you'll get
flashing whenever the list selects an item and your application immediately
de-selects.  Unfortunately I can't think of a way around this without mucking
with the list internals.

Another alternative suggested is to use instead a column of say read only text
widgets which you can make insensitive.

-----------------------------------------------------------------------------
Subject: 124)  Can I have multi-line items in a list?
[Last modified: August 92]

Answer:  Motif 1.0 and 1.1 both have problems with multi-line items in a list.
They should work okay in Motif 1.2.

-----------------------------------------------------------------------------
Subject: 125)  How can I tell the position of selected items in a list?

[Last modified: Oct 92]

Answer:  W. Scott Meeks wrote:

1) All XmList selection callbacks get an XmListCallbackStruct which includes
the item selected and its position.  In addition, the multiple and extended
selection callbacks also get a list of the selected items.  This approach
requires that your application saves this information if you need it outside
of the immediate callback.

2) At any time you can XtGetValues the XmNselectedItems and
XmNselectedItemCount resources.  The problem with this approach is that
identical items may or may not show up in multiple times in this list and the
position in the selectedItems list may not relate directly to the position in
the items list.

3) You can call XmListGetSelectedPos on the list widget.  This will return a
list of the positions of all selected items.

-----------------------------------------------------------------------------
Subject: 126)  TOPIC: FILE SELECTION BOX WIDGET

-----------------------------------------------------------------------------
Subject: 127)  What is libPW.a and do I need it?  My manual says I need to
link in libPW.a to use the File Selection Box.  I can't find it on my system.

[Last modified: Sept 94]

Answer:  The libPW.a is the Programmers Workbench library which is an ATT
product not included in Berkeley based systems, hence it is not found in SunOS
or Ultrix, but is found on HP-UX (a Berkeley/ATT hybrid which chose ATT in
this case).  It contains the regex(3) routines (regcmp, regex).  Some systems
which don't have these in the libc.a need to link with -lPW.  Some systems
which have the regex(3) routines in there also have the libPW.a.  If you have
regex(3) in libc, and it works, don't link with libPW.  If you don't have
regex(3) in libc, and you don't have a libPW, then check some sites on the net
for public domain replacements (several exist), or call your vendor.

In most versions of Motif (see the doco), you can compile FileSB.c with
-DNO_REGEX if you don't have it.


Casper H.S. Dik (asper@fwi.uva.nl), Faculty of Mathematics & Computer Science,
University of Amsterdam, sent this update for Solaris 2.x users:

The regex and regcmp function are part of libgen in SVR4.  Motif applications
should be linked with -lgen. (However, some SVR4 implementations, especially
those of vendors that once shipped SVR3 still contain libPW.)

On Solaris 2.x system, you'll need libgen which is located in /usr/ccs/lib.

-----------------------------------------------------------------------------
Subject: 128)  What are these compile errors: Undefined symbol _regcmp and
_regex?

[Last modified: Sept 94]

Answer:  You need to link in the libPW or libgen library - see previous
question.


-----------------------------------------------------------------------------
Subject: 129)  What's wrong with the Motif 1.0 File Selection Box?  I can't
set the directory, change the directory or get the file mask to work.

Answer:  The 1.0 File Selection Box is broken, and these don't work.  They
weren't fixed until Motif 1.04.  Use these later versions of 1.0 or switch to
Motif 1.1 where it changed a lot.

Joe Hildebrand has a work-around for some of this: Before popping up an
XmFileSelectionDialog, change to the directory you want.  When a file is
selected, check if it is a directory, so that we can change to it.  i.e.

static void show_file_box_CB(w, client_data, call_data)
   Widget               w;
   Widget               client_data;
   XmAnyCallbackStruct  *call_data;
{
   chdir("/users/hildjj/files");
   XtManageChild(client_data);
}

static void val_save(w, client_data, call_data)
   Widget       w;
   Widget       client_data;
   XmSelectionBoxCallbackStruct *call_data;
{
   struct stat buf;  /* struct stat is defined in stat.h */
   char *filename;

   /* get the file name from the FileSelectionBox */
   filename = SmX(call_data->value);

   /* get the status of the file named filename, and put it into buf */
   if (!stat(filename, &buf))
   {
      /* if it's a directory */
      /* if it's a directory */
      if(S_ISDIR(buf.st_mode))
      {
         /* change to that directory, and update the FileSelectionBox */
        chdir(filename);
        XmFileSelectionDoSearch(w, NULL);
      }
      else
         /* if it's a regular file */
         if(S_ISREG(buf.st_mode))
            /* ask if it should be overwritten */
            XtManageChild(valbox);
         else
            /* it's another kind of file.  What type, i can't think of,
               but it might happen */
            pop_up_error_box(client_data, "Error saving file");
   }
   else  /* we couldn't get the file status */
   {
      /* if it's because the file doesn't exist, we're golden */
      if (errno == ENOENT)
         save_file();
      else   /* there is some other problem getting the status.
                e.g. bad path */
         pop_up_error_box(client_data, "Error saving file");
   }
}

this still doesn't implement the file masking stuff.


-----------------------------------------------------------------------------
Subject: 130)  What's wrong with the FileSelectionBox under Solaris?

[Last modified: Apr 95]

Answer:  Jim Guyton (guyton@burton.cs.colorado.edu) writes:

While not strictly a Motif problem, this one had me confused for [awhile].

If under Solaris the entries in a FileSelectionBox look strange and seem to be
missing the first two characters of many filenames, then be sure you're
linking -lc before -lucb.

If on the other hand, the filenames look strange and seem to have two garbage
characters in front of every filename, be sure to link -lucb before -lc.

There are two versions of readdir().  The one in -lucb returns a structure
that has the filename at an offset of 8 bytes (which matches
/usr/ucbinclude/sys/dir.h).

But the version in -lc returns the filename at an offset of 10 bytes (which
matches /usr/include/dirent.h).

So depending on how Motif was built for your Solaris, vs. how you link your
application, your filenames could be two bytes off in either direction.

-----------------------------------------------------------------------------
Subject: 131)  TOPIC: FORM WIDGET


-----------------------------------------------------------------------------
Subject: 132)  Why don't labels in a Form resize when the label is changed?
I've got some labels in a form. The labels don't resize whenever the label
string resource is changed. As a result, the operator has to resize the window
to see the new label contents. I am using Motif 1.1.

Answer:  This problem may happen to any widget inside a Form widget. The
problem was that the Form will resize itself when it gets geometry requests
from its children. If its preferred size is not allowed, the Form will
disallow all geometry requests from its children. The workaround is that you
should set any ancestor of the Form to be resizable. For the shell which
contains the Form you should set the shell resource XmNallowShellResize to be
True (by default, it is set to FALSE).  There is currently an inconsistency on
how resizing is being done, and it may get fixed in Motif 1.2.

db@sunbim.be (Danny Backx) wrote:


Basically what you have to do is set the XmNresizePolicy on the Form to
XmRESIZE_NONE.  The facts seem to be that XmRESIZE_NONE does NOT mean "do not
allow resizes".  You may also have to set XmNresizable on the form to True.

-----------------------------------------------------------------------------
Subject: 133)  How can I center a widget in a form?

[Last modified: Oct 95]

Answer:  One of Motif's trickier questions.  The problems are that: Form gives
no support for centering, only for edge attachments, and the widget must stay
in the center if the form or the widget is resized.  Just looking at
horizontal centering (vertical is similar) some solutions are:

 a.  Use the table widget instead of Form.

 b.  A hack free solution is from Dan Heller:

     /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
      * This program is freely distributable without licensing fees and
      * is provided without guarantee or warranty expressed or implied.
      * This program is -not- in the public domain.  This program is
      * taken from the Motif Programming Manual, O'Reilly Volume 6.
      */

     /* corners.c -- demonstrate widget layout management for a
      * BulletinBoard widget.  There are four widgets each labeled
      * top-left, top-right, bottom-left and bottom-right.  Their
      * positions in the bulletin board correspond to their names.
      * Only when the widget is resized does the geometry management
      * kick in and position the children in their correct locations.
      */
     #include <Xm/BulletinB.h>
     #include <Xm/PushBG.h>

     char *corners[] = {
         "Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right",
     };

     static void resize();

     main(argc, argv)
     int argc;
     char *argv[];
     {
         Widget toplevel, bboard;
         XtAppContext app;
         XtActionsRec rec;
         int i;

         /* Initialize toolkit and create toplevel shell */
         toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
             &argc, argv, NULL, NULL);

         /* Create your standard BulletinBoard widget */
         bboard = XtVaCreateManagedWidget("bboard",
             xmBulletinBoardWidgetClass, toplevel, NULL);

         /* Set up a translation table that captures "Resize" events
          * (also called ConfigureNotify or Configure events).  If the
          * event is generated, call the function resize().
          */
         rec.string = "resize";
         rec.proc = resize;
         XtAppAddActions(app, &rec, 1);
         XtOverrideTranslations(bboard,
             XtParseTranslationTable("<Configure>: resize()"));

         /* Create children of the dialog -- a PushButton in each corner. */
         for (i = 0; i < XtNumber(corners); i++)
             XtVaCreateManagedWidget(corners[i],
                 xmPushButtonGadgetClass, bboard, NULL);

         XtRealizeWidget(toplevel);
         XtAppMainLoop(app);
     }

     /* resize(), the routine that is automatically called by Xt upon the
      * delivery of a Configure event.  This happens whenever the widget
      * gets resized.
      */
     static void
     resize(w, event, args, num_args)
     CompositeWidget w;   /* The widget (BulletinBoard) that got resized */
     XConfigureEvent *event;  /* The event struct associated with the event */
     String args[]; /* unused */
     int *num_args; /* unused */
     {
         WidgetList children;
         int width = event->width;
         int height = event->height;
         Dimension w_width, w_height;
         short margin_w, margin_h;

         /* get handle to BulletinBoard's children and marginal spacing */
         XtVaGetValues(w,
             XmNchildren, &children,
             XmNmarginWidth, &margin_w,
             XmNmarginHeight, &margin_h,
             NULL);

         /* place the top left widget */
         XtVaSetValues(children[0],
             XmNx, margin_w,
             XmNy, margin_h,
             NULL);

         /* top right */
         XtVaGetValues(children[1], XmNwidth, &w_width, NULL);

         /* To Center a widget in the middle of the BulletinBoard (or Form),
          * simply call:
          *   XtVaSetValues(widget,
               XmNx,    (width - w_width)/2,
               XmNy,    (height - w_height)/2,
               NULL);
          * and return.
          */
         XtVaSetValues(children[1],
             XmNx, width - margin_w - w_width,
             XmNy, margin_h,
             NULL);

         /* bottom left */
         XtVaGetValues(children[2], XmNheight, &w_height, NULL);
         XtVaSetValues(children[2],
             XmNx, margin_w,
             XmNy, height - margin_h - w_height,
             NULL);

         /* bottom right */
         XtVaGetValues(children[3],
             XmNheight, &w_height,
             XmNwidth, &w_width,
             NULL);
         XtVaSetValues(children[3],
             XmNx, width - margin_w - w_width,
             XmNy, height - margin_h - w_height,
             NULL);
     }

 c.  No uil solution has been suggested, because of the widget size problem.

 d.  Cameron Hayne (hayne@crim.ca) suggests another solution:

     Attach the widget with XmATTACH_POSITION but offset it by half of its
     width.  You will likely have to create the widget first and then query it
     to find out its width. Thus the following function is useful - you can
     call it immediately after the widget is created.

     void    center_it(Widget wgt)
     {
             Dimension       width;
             XtVaGetValues(wgt, XmNwidth, &width, NULL);
             XtVaSetValues(wgt, XmNleftAttachment, XmATTACH_POSITION,
                             XmNleftPosition, 50,  /* assumes fractionBase is 100 */
                             XmNleftOffset, -width/2, NULL);
     }

     The idea is: get the size of the widget and then offset it by half that
     much from position 50.  The above function will likely only work for
     primitive widgets if you call it immediately after the widget is created.
     For manager widgets you will likely have to wait to call the center_it()
     function until after the widget has been realized since it is only then
     that a manager widget's size is finally determined.  (Refer to discussion
     by Daniel Dardailler "Application's Geometry Management Advanced
     Guidelines" in this FAQ.)

-----------------------------------------------------------------------------
Subject: 134)  How do I line up two columns of widgets of different types?  I
have a column of say label widgets, and a column of text widgets and I want to
have them lined up horizontally. The problem is that they are of different
heights. Just putting them in a form or rowcolumn doesn't line them up
properly because the label and text widgets are of different height.

If you want the geometry to look like this

          -------------------------------------
         |          -------------------------- |
         |a label  |Some text                 ||
         |          -------------------------- |
                           ------------------- |
         |a longer label  |Some more text     ||
         |                 ------------------- |
         |                    ---------------- |
         |a very long label  |Even more text  ||
         |                    ---------------- |
          -------------------------------------

try

/* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
 * This program is freely distributable without licensing fees and
 * is provided without guarantee or warranty expressed or implied.
 * This program is -not- in the public domain.  This program is
 * taken from the Motif Programming Manual, O'Reilly Volume 6.
 */

/* text_form.c -- demonstrate how attachments work in Form widgets.
 * by creating a text-entry form type application.
 */

#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/Form.h>

char *prompts[] = {
    "Name:", "Phone:", "Address:",
    "City:", "State:", "Zip:",
};

main(argc, argv)
int argc;
char *argv[];
{
    Widget toplevel, mainform, subform, label, text;
    XtAppContext app;
    char buf[32];
    int i;

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

    mainform = XtVaCreateWidget("mainform",
        xmFormWidgetClass, toplevel,
        NULL);

    for (i = 0; i < XtNumber(prompts); i++) {
        subform = XtVaCreateWidget("subform",
            xmFormWidgetClass,   mainform,
            /* first one should be attached for form */
            XmNtopAttachment,    i? XmATTACH_WIDGET : XmATTACH_FORM,
            /* others are attached to the previous subform */
            XmNtopWidget,        subform,
            XmNleftAttachment,   XmATTACH_FORM,
            XmNrightAttachment,  XmATTACH_FORM,
            NULL);
        label = XtVaCreateManagedWidget(prompts[i],
            xmLabelGadgetClass,  subform,
            XmNtopAttachment,    XmATTACH_FORM,
            XmNbottomAttachment, XmATTACH_FORM,
            XmNleftAttachment,   XmATTACH_FORM,
            XmNalignment,        XmALIGNMENT_BEGINNING,
            NULL);
        sprintf(buf, "text_%d", i);
        text = XtVaCreateManagedWidget(buf,
            xmTextWidgetClass,   subform,
            XmNtopAttachment,    XmATTACH_FORM,
            XmNbottomAttachment, XmATTACH_FORM,
            XmNrightAttachment,  XmATTACH_FORM,
            XmNleftAttachment,   XmATTACH_WIDGET,
            XmNleftWidget,       label,
            NULL);
        XtManageChild(subform);
    }
    /* Now that all the forms are added, manage the main form */
    XtManageChild(mainform);

    XtRealizeWidget(toplevel);
    XtAppMainLoop(app);
}

If you resize horizontally it stretches the text widgets.  If you resize
vertically it leaves space under the bottom (if you don't resize, this is not
problem).

If you want the text widgets to be lined up on the left, as in

          ----------------------------------------
         |                    ------------------- |
         |          a label  |Some text          ||
         |                    ------------------- |
                              ------------------- |
         |   a longer label  |Some more text     ||
         |                    ------------------- |
         |                    ------------------- |
         |a very long label  |Even more text     ||
         |                    ------------------- |
          ----------------------------------------

try this

/* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
 * This program is freely distributable without licensing fees and
 * is provided without guarantee or warranty expressed or implied.
 * This program is -not- in the public domain.  This program is
 * taken from the Motif Programming Manual, O'Reilly Volume 6.
 */

/* text_entry.c -- This demo shows how the RowColumn widget can be
 * configured to build a text entry form.  It displays a table of
 * right-justified Labels and Text widgets that extend to the right
 * edge of the Form.
 */
#include <Xm/LabelG.h>
#include <Xm/RowColumn.h>
#include <Xm/Text.h>

char *text_labels[] = {
    "Name:", "Phone:", "Address:", "City:", "State:", "Zip:",
};

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

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

    rowcol = XtVaCreateWidget("rowcolumn",
        xmRowColumnWidgetClass, toplevel,
        XmNpacking,        XmPACK_COLUMN,
        XmNnumColumns,     XtNumber(text_labels),
        XmNorientation,    XmHORIZONTAL,
        XmNisAligned,      True,
        XmNentryAlignment, XmALIGNMENT_END,
        NULL);

    /* simply loop thru the strings creating a widget for each one */
    for (i = 0; i < XtNumber(text_labels); i++) {
        XtVaCreateManagedWidget(text_labels[i],
            xmLabelGadgetClass, rowcol,
            NULL);
        sprintf(buf, "text_%d", i);
        XtVaCreateManagedWidget(buf,
            xmTextWidgetClass, rowcol,
            NULL);
    }

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

This makes all objects exactly the same size.  It does not resize in nice
ways.

If you want the text widgets lined up on the left, and the labels to be the
size of the longest string, resizing nicely both horizontally and vertically,
as in

         -------------------------------------
        |                    ---------------- |
        |          a label  |Some text       ||
        |                    ---------------- |
                             ---------------- |
        |   a longer label  |Some more text  ||
        |                    ---------------- |
        |                    ---------------- |
        |a very long label  |Even more text  ||
        |                    ---------------- |
         -------------------------------------


Answer:  Do this:  to get the widgets lined up horizontally, use a form but
place the widgets using XmATTACH_POSITION.  In the example, attach the top of
the first label to the form, the bottomPosition to 33 (33% of the height).
Attach the topPosition of the second label to 33 and the bottomPosition to 66.
Attach the topPosition of the third label to 66 and the bottom of the label to
the form.  Do the same with the text widgets.

To get the label widgets lined up vertically, use the right attachment of
XmATTACH_OPPOSITE_WIDGET: starting from the one with the longest label, attach
widgets on the right to each other. In the example, attach the 2nd label to
the third, and the first to the second.  To get the text widgets lined up,
just attach them on the left to the labels.  To get the text in the labels
aligned correctly, use XmALIGNMENT_END for the XmNalignment resource.

        /* geometry for label 2
        */
        n = 0;
        XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNtopPosition, 66); n++;
        XtSetValues (label[2], args, n);

        /* geometry for label 1
        */
        n = 0;
        XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNbottomPosition, 66); n++;
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNtopPosition, 33); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
        XtSetArg (args[n], XmNrightWidget, label[2]); n++;
        XtSetValues (label[1], args, n);

        /* geometry for label 0
        */
        n = 0;
        XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNbottomPosition, 33); n++;
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
        XtSetArg (args[n], XmNrightWidget, label[1]); n++;
        XtSetValues (label[0], args, n);

        /* geometry for text 0
        */
        n = 0;
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNbottomPosition, 33); n++;
        XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
        XtSetArg (args[n], XmNleftWidget, label[0]); n++;
        XtSetValues (text[0], args, n);

        /* geometry for text 1
        */
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNtopPosition, 33); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNbottomPosition, 66); n++;
        XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
        XtSetArg (args[n], XmNleftWidget, label[1]); n++;
        XtSetValues (text[1], args, n);

        /* geometry for text 2
        */
        XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
        XtSetArg (args[n], XmNtopPosition, 66); n++;
        XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
        XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
        XtSetArg (args[n], XmNleftWidget, label[2]); n++;
        XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
        XtSetValues (text[2], args, n);


-----------------------------------------------------------------------------
Subject: 135)  TOPIC: PUSHBUTTON WIDGET

-----------------------------------------------------------------------------
Subject: 136)  Why can't I use accelerators on buttons not in a menu?

[Last modified: Sept 94]

Answer:

It is apparently a difficult feature to implement, but OSF are considering
this for the future. It is problematic trying to use the Xt accelerators since
the Motif method interferes with this.  one workaround suggested is to
duplicate your non-menu button by a button in a menu somewhere, which does
have a menu-accelerator installed.  When the user invokes what they think is
the accelerator for the button they can see Motif actually invokes the button
on the menu that they can't see at the time. Another method is described below
and was contributed by Harald Albrecht of Institute of Geometry and Practical
Mathematics Rhine Westphalia Technical University Aachen (RWTH Aachen),
Germany


albrecht@igpm.rwth-aachen.de wrote (Jul 8, 1993):

NOTE: Pointers to a more recent solution by the same author follow this code
sample.

My work-around of this problem looks like this: (I've written that code for a
Motif Object Library in C++ so please forgive me for being object orientated!)
The hack consists of a rewritten message loop which checks for keypresses
<MAlt>+<key>. If MessageLoop() finds such a keypress HandleAcc() ist called
and the widget tree is searched for a suitable widget with the right mnemonic.


// --------------------------------------------------------------------------
// traverse the widget tree starting with the given widget.
//
BOOL TraverseWidgetTree(Widget w, char *pMnemonic, XKeyEvent *KeyEvent)
{
    Widget               wChild;
    WidgetList           ChildList;
    int                  NumChilds, Child;
    KeySym               LabelMnemonic;
    char                 *pMnemonicString;

// Check if the widget is a subclass of label -- then it may have an
// accelerator attached...
    if ( XtIsSubclass(w, xmLabelWidgetClass) ) {
// ok. Now: get the widget's mnemonic, convert it to ASCII and compare
// it with the Key we're looking for.
        XtVaGetValues(w, XmNmnemonic, &LabelMnemonic, NULL);
        pMnemonicString = XKeysymToString(LabelMnemonic);
        if ( pMnemonicString &&
             (strcasecmp(pMnemonicString, pMnemonic) == 0) ) {
            // stimulate the keypress
            XmProcessTraversal((Widget)w, XmTRAVERSE_CURRENT);
            KeyEvent->type      = KeyPress;
            KeyEvent->window    = XtWindow(w);
            KeyEvent->subwindow = XtWindow(w);
            KeyEvent->state     = 0;
            KeyEvent->keycode   =
                XKeysymToKeycode(XtDisplay(w), XK_space);
            XSendEvent(XtDisplay(w), XtWindow(w),
                       True,
                       ButtonPressMask, (XEvent*) KeyEvent);
            KeyEvent->type      = KeyRelease;
            XSendEvent(XtDisplay(w), XtWindow(w),
                       True,
                       ButtonReleaseMask, (XEvent*) KeyEvent);
            return True;
        }
    }
// if this widget is a subclass of Composite check all the widget's
// childs.
    if ( XtIsSubclass(w, compositeWidgetClass) ) {
// if we're in a menu (or something like that) forget this leaf of the
// widget tree!
        if ( XtIsSubclass(w, xmRowColumnWidgetClass) ) {
            unsigned char RowColumnType;
            XtVaGetValues(w, XmNrowColumnType, &RowColumnType, NULL);
            if ( RowColumnType != XmWORK_AREA ) return False;
        }
        XtVaGetValues(w, XmNchildren, &ChildList,
                         XmNnumChildren, &NumChilds, NULL);
        for ( Child = 0; Child < NumChilds; ++Child ) {
            wChild = ChildList[Child];
            if ( TraverseWidgetTree(wChild, pMnemonic, KeyEvent) )
                return True;
        }
    }
    return False;
} // TraverseWidgetTree
// --------------------------------------------------------------------------
// handle accelerators (keypress MAlt + key)
//
#define MAX_MAPPING 10
BOOL HandleAcc(Widget w, XEvent *event)
{
           Widget         widget, OldWidget;
    static char           keybuffer[MAX_MAPPING];
           int            CharCount;
    static XComposeStatus composeStatus;

// convert KeyPress to ASCII
    CharCount = XLookupString((XKeyEvent*) event,
                              keybuffer, sizeof(keybuffer),
                              NULL, &composeStatus);
    keybuffer[CharCount] = 0;
// Only one char is alright -- then search the widget tree for a widget
// with the right mnemonic
    if ( CharCount == 1 ) {
        keybuffer[0] = tolower(keybuffer[0]);
        widget = w;
        while ( (widget != NULL) &&
                !XtIsSubclass(widget, shellWidgetClass) ) {
            OldWidget = widget; widget = XtParent(widget);
        }
        if ( !widget ) widget = OldWidget;
        return TraverseWidgetTree(widget,
                                  keybuffer, (XKeyEvent*) event);
    }
    return False; // no-one found.
} // HandleAcc
// --------------------------------------------------------------------------
// modified message loop
// loops until the Boolean pFlag points to is set to False
void MessageLoop(Boolean *pFlag)
{
    XEvent nextEvent;

    while ( *pFlag ) {
        if ( XtAppPending(AppContext) ) {
            XtAppNextEvent(AppContext, &nextEvent);
            if ( nextEvent.type == KeyPress ) {
// Falls es ein Tastendruck ist, bei dem auch noch die ALT-Taste
// (=Modifier 1) gedrueckt ist, koennte es ein Accelerator sein!
                if ( nextEvent.xkey.state & Mod1Mask )
                    if ( HandleAcc(XtWindowToWidget(nextEvent.xkey.display,
                                                    nextEvent.xkey.window),
                                   &nextEvent) )
                        continue; // Mitteilung konnte ausgeliefert werden
                                  // und darf daher nicht den ueblichen
                                  // Weg gehen!
            }
            XtDispatchEvent(&nextEvent);
        }
    }
} // TApplication::MessageLoop


Harald Albrecht albrecht@igpm.rwth-aachen.de Institute of Geometry and
Practical Mathematics Rhine Westphalia Technical University Aachen (RWTH
Aachen), Germany

NOTE: Harald Albrecht has re-designed his solution so that you can assign
hotkeys to *every* widget by placing a label near that widget. Get the code
from:

  ftp.informatik.rwth-aachen.de (137.226.112.172)
  in: /pub/packages/Mnemonic/Mnemonic.tar.gz

or from the WWW:

   file://134.130.161.30/arc/pub/unix/html/motifcorner.html

-----------------------------------------------------------------------------
Subject: 137)  TOPIC: ICON WIDGET and PIXMAPS

-----------------------------------------------------------------------------
Subject: 138)  How can I add multi-colored icons to my application?

[Last modified: Sept 94]

Answer:  Get the Xpm (X PixMap file format) widgets.  There is a tutorial in
the directory ftp.x.org:/contrib/docs/xpm_tut and source code in the directory
ftp.x.org:/contrib/libraries.  Documentation is part of the tar file found in
/contrib/libraries.  The /contrib/libraries directory also contains xpm.FAQ.

There is also a mailing list: xpm-talk@sophia.inria.fr.

-----------------------------------------------------------------------------
Subject: 139)  Can I use XmGetPixmap in Motif 1.2 to create colored images?

[Last modified: Oct 95]

Answer:  Doug Rand (drand@sgi.com) writes:

XmGetPixmap only converts XBM [X bitmap] files in 1.2.  In 2.0 it supports XPM
[X Pixmap] files.  You can register a more capable converter and set the
pixmap via resources as a workaround.  You can also use libXpm
directly...[Note that] even now there isn't a "standard" color pixmap file
format.  There are several.  It is relatively recently that many people have
settled on XPM.  But even so not everyone has done this.

-----------------------------------------------------------------------------
Subject: 140)  Why does XpmCreatePixmapFromData fail with a pixmap containing
a large number of colors?  XpmCreatePixmapFromData gives me a -4 errno (which
is XpmColorFailed) when I try using a pixmap with 242 colors

[Last modified: Oct 95]

Answer:  Ramiro Estrugo (restrugo@fateware.com) writes:

  If you are allocating 242 colors in an 8 bit display, then you are likely to
run out of colors.  If you carefully read the Xpm manual, you will notice that
one of the Xpm values that you can modify is the "closeness".  This value will
control the actual closness of the colors allocated by the Xpm library.
According to the Xpm manual:

  o The "closeness" field(s) (when set) control if and how colors
    are found when they failed to be allocated.  If the color cannot
    be allocated, Xpm looks in the colormap for a color that matches
    the desired closeness.

  o The value is an integer in the range 0 (black) - 65535 (white)

  o A closeness of less than 10000 will cause only "close" colors to
    match.

  o A cliseness of more than 50000 will allow quite disimilar colors
    to match.

  o A closeness of more than 65535 will allow any color to match.

  o A value of 40000 seems reasonable for many situations requiring
    reasonable but not perfect color matches.

Try it and your application is less likely to die or look "ugly" due to the
lack of colors.  The worst that can happed is that the colors you get are not
100% what you wanted them to be.  Most of the time, you might not even notice
the difference.  This is usually due to badly designed icons or duplicate
color entries (close rgb values) in .xpm files.

NOTE: for even more control over Xpm color allocation, you can control the
closeness of each RGB color component individually.

For example:

XpmAttributes   attrib;
int             valuemask;
attrib.valuemask |= XpmCloseness;
attrib.closeness = 40000;

/* also */

attrib.valuemask |= XpmRGBCloseness;
attrib.red_closeness = RED_CLOSENESS;
attrib.green_closeness = GREEN_CLOSENESS;
attrib.blue_closeness = BLUE_CLOSENESS;
pix = XpmCreateXYZFromABC(...,&attrib);

Also, look in the Xpm documentation for more color control parameters.

-----------------------------------------------------------------------------
Subject: 141)  How can I convert a Sun/GIF/TIFF image to a pixmap?

[Last modified: Oct 94]

Answer:  An application called "xv" (interactive image display for the X
Window System) is useful for displaying and converting many image formats.
>From the man page:

     xv is an X11 program that displays images in the GIF,  JPEG,
     TIFF,  PBM, PGM, PPM, X11 bitmap, PDS/VICAR, Sun Rasterfile,
     and PM formats on 1-, 2-, 4-, 6-, 8-, 16-, 24-, and 32-bit X
     displays.   xv  will also read compress-ed versions of these
     files.

You can get "xv" (shareware by John Bradley et al) from:

        ftp://ftp.cis.upenn.edu/pub/xv
or:
        ftp://ftp.x.org/R5contrib/xv-3.01.tar.gz

Another useful conversion package is "pbm" (portable bitmap file format) by
Jef Poskanzer et al, available from:

        ftp://ftp.x.org/R5contrib/netpbm-1mar1994.tar.gz
or:
        ftp://ftp.x.org/R5contrib/pbmplus10dec91.tar.Z (much older :-)

You might also want to check the X11 FAQ for additional conversion options:

        ftp://ftp.x.org/contrib/faqs/FAQ

-----------------------------------------------------------------------------
END OF PART FIVE
