FileSelectionDialog is not necessary in most cases because the Motif toolkit provides FileSelectionDialog resources
that access most of the important resources of the children. You should only get handles to the children if you need to
change resources that are not involved in the file selection mechanisms.
7.5.3 Callback Routines
The XmNokCallback, XmNcancelCallback, XmNapplyCallback, XmNhelpCallback, and
XmNnoMatchCallback callbacks can be specified for a FileSelectionDialog as they are for SelectionDialog. The
callback routines take the usual parameters, but the callback structure passed in the call_data parameter is of type
XmFileSelectionBoxCallbackStruct. The structure is declared as follows:
typedef struct {
int reason;
XEvent *event;
XmString value;
int length;
XmString mask;
int mask_length;
XmString dir;
int dir_length;
XmString pattern;
int pattern_length;
} XmFileSelectionBoxCallbackStruct;
The value of the reason field is an integer value that specifies the reason that the callback routine was invoked. The
possible values are the same as those for a SelectionDialog:
XmCR_OK
XmCR_APPLY
XmCR_CANCEL
XmCR_HELP
XmCR_NO_MATCH
The value field contains the item that the user selected from the files list or typed into the selection text entry area.
The value corresponds to the XmNdirSpec resource and it does not necessarily have to match an item in the
directories or files lists. The mask field corresponds to the XmNdirMask resource; it represents a combination of the
entire pathname specification in the filter. The dir and pattern fields represent the two components that make up
the mask. All of these fields are compound strings; they can be converted to character strings using
XmStringGetLtoR().
7.5.4 File Searching
You can force a FileSelectionDialog to reinitialize the directory and file lists by calling
XmFileSelectionDoSearch(). This routine reads the directory filter and scans the -specified directory, which
is useful if you set the mask directly. The function takes the following form:
void
XmFileSelectionDoSearch(widget, dirmask)
XmFileSelectionBoxWidget widget;
XmString dirmask;
When the routine is called, the widget invokes its directory search procedure and sets the text in the filter text entry
area to the dirmask parameter. Calling XmFileSelectionDoSearch() has the same effect as setting the filter
and selecting the Filter button.
7 Selection Dialogs 7.5.3 Callback Routines
158
By default, the FileSelectionDialog searches the directory specified in the mask according to its internal searching
algorithm. You can replace this file searching procedure with your own routine by specifying a callback routine for
the XmNfileSearchProc resource. This resource is not a callback list, so you do not install it by calling
XtAddCallback(). Since the resource is just a single procedure, you specify it as a value like you would any other
resource, as shown in the following code fragment:
extern void my_search_proc();
XtVaSetValues (file_selection_dialog,
XmNfileSearchProc, my_search_proc,
NULL);
If you specify a search procedure, it is used to generate the list of filenames for the files list. A file search routine takes
the following form:
void
(* XmSearchProc) (widget, search_data)
Widget widget;
XtPointer *search_data;
The widget parameter is the actual FileSelectionBox widget and search_data is a callback structure of type
XmFileSelectionBoxCallbackStruct. This structure is just like the one used in the callback routines
discussed in the previous section. Do not be concerned with the value of the reason field in this situation because
none of the routines along the way use the value. The search function should scan the directory specified by the dir
field of the search_data parameter. The pattern should be used to filter the files within the directory. You can
get the complete filter from the mask field.
After the search procedure has determined the new list of files that it is going to use, it must set the
XmNfileListItems and XmNfileListItemCount resources to store the list into the List widget used by the
FileSelectionDialog. The routine must also set the XmN-listUpdated resource to True to indicate that it has
indeed done something, whether or not any files are found. The function can also set the XmNdirSpec resource to
reflect the full file specification in the selection text entry area, so that if the user selects the OK button, the specified
file is used. Although this step is optional, we recommend doing it in case the old value is no longer valid.
To understand why it may be necessary to have your own file search procedure, consider how you would customize a
FileSelectionDialog so that it only displays the writable files in an arbitrary directory. This customization might come
in handy for a save operation in an electronic mail application, where the user invokes a Save action that displays a
FileSelectionDialog that lists the files in which the user can save messages. Files that are not writable should not be
displayed in the dialog. the source code shows an example of how a file search procedure can be used to implement
this type of dialog. XtSetLanguageProc() is only available in X11R5; there is no corresponding function in
X11R4. XmStringCreateLocalized() is only available in Motif 1.2; XmStringCreateSimple() is the
corresponding function in Motif 1.1. XmFONTLIST_DEFAULT_TAG replaces XmSTRING_DEFAULT_CHARSET in
Motif 1.2.
/* file_sel.c −− file selection dialog displays a list of all the writable
* files in the directory described by the XmNmask of the dialog.
* This program demonstrates how to use the XmNfileSearchProc for
* file selection dialog widgets.
*/
#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/FileSB.h>
#include <Xm/DialogS.h>
#include <Xm/PushBG.h>
7 Selection Dialogs 7.5.3 Callback Routines
159
#include <Xm/PushB.h>
#include <X11/Xos.h>
#include <sys/stat.h>
void do_search(), new_file_cb();
/* routine to determine if a file is accessible, a directory,
* or writable. Return −1 on all errors or if the file is not
* writable. Return 0 if it's a directory or 1 if it's a plain
* writable file.
*/
int
is_writable(file)
char *file;
{
struct stat s_buf;
/* if file can't be accessed (via stat()) return. */
if (stat (file, &s_buf) == −1)
return −1;
else if ((s_buf.st_mode & S_IFMT) == S_IFDIR)
return 0; /* a directory */
else if (!(s_buf.st_mode & S_IFREG) || access (file, W_OK) == −1)
/* not a normal file or it is not writable */
return −1;
/* legitimate file */
return 1;
}
/* main() −− create a FileSelectionDialog */
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, dialog;
XtAppContext app;
extern void exit();
Arg args[5];
int n = 0;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
XtSetArg (args[n], XmNfileSearchProc, do_search); n++;
dialog = XmCreateFileSelectionDialog (toplevel, "Files", args, n);
XtSetSensitive (
XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON), False);
/* if user presses OK button, call new_file_cb() */
XtAddCallback (dialog, XmNokCallback, new_file_cb, NULL);
/* if user presses Cancel button, exit program */
XtAddCallback (dialog, XmNcancelCallback, exit, NULL);
XtManageChild (dialog);
XtAppMainLoop (app);
}
/* a new file was selected −− check to see if it's readable and not
* a directory. If it's not readable, report an error. If it's a
7 Selection Dialogs 7.5.3 Callback Routines
160
* directory, scan it just as tho the user had typed it in the mask
* Text field and selected "Search".
*/
void
new_file_cb(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
char *file;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) call_data;
/* get the string typed in the text field in char * format */
if (!XmStringGetLtoR (cbs−>value, XmFONTLIST_DEFAULT_TAG, &file))
return;
if (*file != '/') {
/* if it's not a directory, determine the full pathname
* of the selection by concatenating it to the "dir" part
*/
char *dir, *newfile;
if (XmStringGetLtoR (cbs−>dir, XmFONTLIST_DEFAULT_TAG, &dir)) {
newfile = XtMalloc (strlen (dir) + 1 + strlen (file) + 1);
sprintf (newfile, "%s/%s", dir, file);
XtFree( file);
XtFree (dir);
file = newfile;
}
}
switch (is_writable (file)) {
case 1 :
puts (file); /* or do anything you want */
break;
case 0 : {
/* a directory was selected, scan it */
XmString str = XmStringCreateLocalized (file);
XmFileSelectionDoSearch (widget, str);
XmStringFree (str);
break;
}
case −1 :
/* a system error on this file */
perror (file);
}
XtFree (file);
}
/* do_search() −− scan a directory and report only those files that
* are writable. Here, we let the shell expand the (possible)
* wildcards and return a directory listing by using popen().
* A *real* application should −not− do this; it should use the
* system's directory routines: opendir(), readdir() and closedir().
*/
void
do_search(widget, search_data)
Widget widget; /* file selection box widget */
XtPointer search_data;
{
char *mask, buf[BUFSIZ], *p;
XmString names[256]; /* maximum of 256 files in dir */
int i = 0;
7 Selection Dialogs 7.5.3 Callback Routines
161
FILE *pp, *popen();
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) search_data;
if (!XmStringGetLtoR (cbs−>mask, XmFONTLIST_DEFAULT_TAG, &mask))
return; /* can't do anything */
sprintf (buf, "/bin/ls %s", mask);
XtFree (mask);
/* let the shell read the directory and expand the filenames */
if (!(pp = popen (buf, "r")))
return;
/* read output from popen() −− this will be the list of files */
while (fgets (buf, sizeof buf, pp)) {
if (p = index (buf, '0))
*p = 0;
/* only list files that are writable and not directories */
if (is_writable (buf) == 1 &&
(names[i] = XmStringCreateLocalized (buf)))
i++;
}
pclose (pp);
if (i) {
XtVaSetValues (widget,
XmNfileListItems, names,
XmNfileListItemCount, i,
XmNdirSpec, names[0],
XmNlistUpdated, True,
NULL);
while (i > 0)
XmStringFree (names[−−i]);
} else
XtVaSetValues (widget,
XmNfileListItems, NULL,
XmNfileListItemCount, 0,
XmNlistUpdated, True,
NULL);
}
The program simply displays a FileSelectionDialog that only lists the files that are writable by the user. The
directories listed may or may not be writable. We are not testing that case here as it is handled by another routine that
deals specifically with directories, which are discussed in the next section. The XmNfileSearchProc is set to
do_search(), which is our own routine that creates the list of files for the files List widget. The function calls
is_writable() to determine if a file is accessible and if it is a directory or a regular file that is writable.
The callback routine for the OK button is set to new_file_cb() through the XmNokCallback resource. This
routine is called when a new file is selected in from the files list or new text is entered in the selection text entry area
and the OK button is pressed. The specified file is evaluated using is_writable() and acted on accordingly. If it
is a directory, the directory is scanned as if it had been entered in the filter text entry area. If the file cannot be read, an
error message is printed. Otherwise, the file is a legitimate selection and, for demonstration purposes, the filename is
printed to stdout.
Obviously, a real application would do something more appropriate in each case; errors would be reported using
ErrorDialogs and legitimate values would be used by the application. An example of such a program is given in
Chapter 14, Text Widgets, as file_browser.c. This program is an extension of the source code that takes a more
realistic approach to using a FileSelectionDialog. Of course, the intent of that program is to show how Text widgets
work, but its use of dialogs is consistent with the approach we are taking here. The FileSelectionDialog also provides
7 Selection Dialogs 7.5.3 Callback Routines
162

Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.