Any application needs to interact with the user. At the simplest level an application may need to inform, alert or warn the user about its current state. More advanced interaction may require the user to select or input data. Selecting files from a directory/file selection window is typical of an advanced example. Clearly, the provision of such interaction is the concern of the GUI. Motif provides a variety of Dialog widgets or Dialogs that facilitate most common user interaction requirements.
Motif Dialog widgets usually comprise of the following components:
More advanced Dialogs (e.g. selection dialogs) may significantly enhance this model.
Dialogs have many distinct uses, indeed the Motif Style Guide (Chapter 18) is specific in the use of each Dialog . The following Dialogs are provided by Motif:
To create a Dialog use one of the XmCreate.....Dialog() functions.
Dialogs do not usually appear immediately on screen after creation or when the the initial application GUI is realized. Indeed, if an application runs successfully certain Dialog widgets (Error or Warning Dialogs, in particular) may never be required. However, prudent applications should consider all practical avenues that an application would be expected to take and provide suitable information (via Dialogs) to the user.
It is advisable to create all Dialogs when the application is initialised and the overall GUI is setup. However, Dialogs will not be managed initially. Recall Section 4.7) when a widget is unmanaged by its parent it will always be invisible.
Therefore, Dialogs are usually created unmanaged and displayed when required in the program as described below:
This method has the advantage that we only need to create a Dialog once and can then manage or unmanage it when necessary.
Most Motif Dialogs have default callback resources attached to the common Ok and Cancel. One consequence of these default callbacks is that they will unmanage the widgets from which they were called. However, if the application provides alternative callback (or other) functions then responsibility for correctly managing and unmanaging them is given over to the programmer.
The use of many dialogs is very similar. We will study a few specific Dialogs in detail.
This dialog is used to inform the user of a possible mistake in the program or in interaction with the program.
A typical example might be when you select the quit button (or menu item) to terminate the program -- if this was selected mistakenly, and there is no warning prompt, you have problems.
The dialog1.c (Section 9.5) program attaches a pop-up WarningDialog when the quit menu option is selected (Fig 9.1). If you now select OK the program terminates, Cancel returns back to the program.
Fig. 9.1 WarningDialog and InformationDialog
Widgets
The function create_dialogs() in dialog1.c creates the WarningDialog in the following typical manner:
The callback function quit_pop_up() simply needs to XtManageChild() the given Dialog widget so that it is displayed as required by the application.
The InformationDialog Widget is essentially the same as the WarningDialog, except that InformationDialogs are intended to supply program information or help. In terms of Motif creation and management the widgets are identical except that the XmCreateInformationDialog() is used to create this class of Dialog. The main difference between the widgets to the user is visual. Motif employs different icons to distinguish between the two (Fig 9.1).
The program dialog1.c illustrates the creation and use of an InformationDialog Widget.
<Xm/MessageB.h>
header file.
#include <Xm/Xm.h> #include <Xm/MainW.h> #include <Xm/CascadeB.h> #include <Xm/MessageB.h> #include <Xm/PushB.h> /* Prototype functions */ void create_dialogs(void); /* callback for the pushbuttons. pops up dialog */ void info_pop_up(Widget , char *, XmPushButtonCallbackStruct *), quit_pop_up(Widget , char *, XmPushButtonCallbackStruct *); void info_activate(Widget ), quit_activate(Widget ); /* Global reference for dialog widgets */ Widget info, quit; Widget info_dialog, quit_dialog; main(int argc, char *argv[]) { XtAppContext app; Widget top_wid, main_w, menu_bar; top_wid = XtVaAppInitialize(&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); main_w = XtVaCreateManagedWidget("main_window", xmMainWindowWidgetClass, top_wid, XmNheight, 300, XmNwidth,300, NULL); menu_bar = (Widget) XmCreateMenuBar(main_w, "main_list", NULL, 0); XtManageChild(menu_bar); /* create quit widget + callback */ quit = XtVaCreateManagedWidget( "Quit", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'Q', NULL); /* Callback has data passed to */ XtAddCallback(quit, XmNactivateCallback, quit_pop_up, NULL); /* create help widget + callback */ info = XtVaCreateManagedWidget( "Info", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'I', NULL); XtAddCallback(info, XmNactivateCallback, info_pop_up, NULL); /* Create but do not show (manage) dialogs */ create_dialogs(); XtRealizeWidget(top_wid); XtAppMainLoop(app); } void create_dialogs() { /* Create but do not manage dialog widgets */ XmString xm_string; Arg args[1]; /* Create InformationDialog */ /* Label the dialog */ xm_string = XmStringCreateLocalized("Dialog widgets added to \ give info and check quit choice"); XtSetArg(args[0], XmNmessageString, xm_string); /* Create the InformationDialog */ info_dialog = XmCreateInformationDialog(info, "info", args, 1); XmStringFree(xm_string); XtAddCallback(info_dialog, XmNokCallback, info_activate, NULL); /* Create Warning DIalog */ /* label the dialog */ xm_string = XmStringCreateLocalized("Are you sure you want to quit?"); XtSetArg(args[0], XmNmessageString, xm_string); /* Create the WarningDialog */ quit_dialog = XmCreateWarningDialog(quit, "quit", args, 1); XmStringFree(xm_string); XtAddCallback(quit_dialog, XmNokCallback, quit_activate, NULL); } void info_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { XtManageChild(info_dialog); } void quit_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { XtManageChild(quit_dialog); } /* callback routines for dialogs */ void info_activate(Widget dialog) { printf("Info Ok was pressed.\n"); } void quit_activate(Widget dialog) { printf("Quit Ok was pressed.\n"); exit(0); }
These 3 Dialogs are similar to both the Information and Warning Dialogs. They are created and used in similar fashions. The main difference again being the icon used to depict the Dialog class as illustrated in Figs. 9.2 -- 9.4.
When you create a Dialog, Motif will create 3 buttons by default -- Ok, Cancel and Help. There are many occasions when it is not natural to require the use of three buttons within an application. For instance in dialog1.c we only really need the user to acknowledge the InformationDialog and no user should need any help to choose whether to quit our program.
Motif provides a mechanism to disable unwanted buttons in a Dialog.
To remove a button:
An example where we disable the Cancel and Help buttons on the InformationDialog and the Help button on the WarningDialog from the Dialogs created in program dialog1.c is shown in Fig. 9.5. The code that performs the task of deleting the Help from a widget, dialog is as follows:
Widget remove; remove = XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON); XtUnmanageChild(remove);
Fig. 9.5 Removed Dialog Button
The PromptDialog widget is slightly more advanced than the classes of Dialog widgets encountered so far. This widget allows the user to enter text (Fig. 9.6).
The function XmCreatePromptDialog() instantiates the Dialog. Typically two resources of a PromptDialog widget are required to be set. These resources are
Note: A Prompt Dialog is based on the SelectionBox widget and so we must
include <Xm/SelectioB.h>
header file.
This program, an extension of dialog1.c, creates a PromptDialog into which the user can enter text. The PromptDialog first displayed by this program is shown in Fig. 9.6. The text is echoed in an InformationDialog which is created in a Prompt callback function, prompt_activate().
Fig. 9.6 PromptDialog Widget
A PromptDialog Callback has the following structure
void prompt_callback(Widget widget, XtPointer client_data, XmSelectionBoxCallbackStruct *selection)
Normally, we will only be interested in obtaining the string entered to the PromptDialog. An element of the XmSelectionBoxCallbackStruct, value holds the (XmString data type) value.
In prompt.c, the callback for the prompt dialog (activated with Ok button) -- prompt_activate().
This function uses the selection->value
XmString to set up the
InformationDialog message String.
Note, that since a PromptDialog is a SelectionBox widget type we must use XmSelectionBoxGetChild() to find any buttons we may wish to remove from the PromptDialog. In prompt.c we remove the Help button in this way.
#include <Xm/Xm.h> #include <Xm/MainW.h> #include <Xm/CascadeB.h> #include <Xm/MessageB.h> #include <Xm/PushB.h> #include <Xm/SelectioB.h> /* Callback and other function prototypes */ void ScrubDial(Widget, int); void info_pop_up(Widget , char *, XmPushButtonCallbackStruct *), quit_pop_up(Widget , char *, XmPushButtonCallbackStruct *), prompt_pop_up(Widget , char *, XmPushButtonCallbackStruct *); void prompt_activate(Widget , caddr_t, XmSelectionBoxCallbackStruct *); void quit_activate(Widget); Widget top_wid; main(int argc, char *argv[]) { XtAppContext app; Widget main_w, menu_bar, info, prompt, quit;
top_wid = XtVaAppInitialize(&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); main_w = XtVaCreateManagedWidget("main_window", xmMainWindowWidgetClass, top_wid, XmNheight, 300, XmNwidth,300, NULL);
menu_bar = XmCreateMenuBar(main_w, "main_list", NULL, 0); XtManageChild(menu_bar); /* create prompt widget + callback */ prompt = XtVaCreateManagedWidget( "Prompt", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'P', NULL); /* Callback has data passed to */ XtAddCallback(prompt, XmNactivateCallback, prompt_pop_up, NULL);
/* create quit widget + callback */ quit = XtVaCreateManagedWidget( "Quit", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'Q', NULL); /* Callback has data passed to */ XtAddCallback(quit, XmNactivateCallback, quit_pop_up, "Are you sure you want to quit?");
/* create help widget + callback */ info = XtVaCreateManagedWidget( "Info", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'I', NULL); XtAddCallback(info, XmNactivateCallback, info_pop_up, "Select Prompt Option To Get Program Going."); XtRealizeWidget(top_wid); XtAppMainLoop(app); }
void prompt_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { Widget dialog, remove; XmString xm_string1, xm_string2; Arg args[3]; /* label the dialog */ xm_string1 = XmStringCreateLocalized("Enter Text Here:"); XtSetArg(args[0], XmNselectionLabelString, xm_string1); /* default text string */ xm_string2 = XmStringCreateLocalized("Default String");
XtSetArg(args[1], XmNtextString, xm_string2); /* set up default button for cancel callback */ XtSetArg(args[2], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); /* Create the WarningDialog */ dialog = XmCreatePromptDialog(cascade_button, "prompt", args, 3); XmStringFree(xm_string1); XmStringFree(xm_string2);
XtAddCallback(dialog, XmNokCallback, prompt_activate, NULL); /* Scrub Prompt Help Button */ remove = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON); XtUnmanageChild(remove); /* scrub HELP button */ XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
void info_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { Widget dialog; XmString xm_string; extern void info_activate(); Arg args[2]; /* label the dialog */ xm_string = XmStringCreateLocalized(text); XtSetArg(args[0], XmNmessageString, xm_string); /* set up default button for OK callback */ XtSetArg(args[1], XmNdefaultButtonType, XmDIALOG_OK_BUTTON);
/* Create the InformationDialog as child of cascade_button passed in */ dialog = XmCreateInformationDialog(cascade_button, "info", args, 2); ScrubDial(dialog, XmDIALOG_CANCEL_BUTTON); ScrubDial(dialog, XmDIALOG_HELP_BUTTON); XmStringFree(xm_string); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
void quit_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { Widget dialog; XmString xm_string; Arg args[1]; /* label the dialog */ xm_string = XmStringCreateLocalized(text); XtSetArg(args[0], XmNmessageString, xm_string); /* set up default button for cancel callback */ XtSetArg(args[1], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
/* Create the WarningDialog */ dialog = XmCreateWarningDialog(cascade_button, "quit", args, 1); ScrubDial(dialog, XmDIALOG_HELP_BUTTON); XmStringFree(xm_string); XtAddCallback(dialog, XmNokCallback, quit_activate, NULL); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
/* routine to remove a DialButton from a Dialog */ void ScrubDial(Widget wid, int dial) { Widget remove; remove = XmMessageBoxGetChild(wid, dial); XtUnmanageChild(remove); }
/* callback function for Prompt activate */ void prompt_activate(Widget widget, XtPointer client_data, XmSelectionBoxCallbackStruct *selection) { Widget dialog; Arg args[2]; XmString xm_string; /* compose InformationDialog output string */ /* selection->value holds XmString entered to prompt */ xm_string = XmStringCreateLocalized("You typed: "); xm_string = XmStringConcat(xm_string,selection->value);
XtSetArg(args[0], XmNmessageString, xm_string); /* set up default button for OK callback */ XtSetArg(args[1], XmNdefaultButtonType, XmDIALOG_OK_BUTTON); /* Create the InformationDialog to echo string grabbed from prompt */ dialog = XmCreateInformationDialog(top_wid, "prompt_message", args, 2); ScrubDial(dialog, XmDIALOG_CANCEL_BUTTON); ScrubDial(dialog, XmDIALOG_HELP_BUTTON); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
/* callback routines for quit ok dialog */ void quit_activate(Widget dialog) { printf("Quit Ok was pressed.\n"); exit(0); }
The purpose of both these widgets is to allow the user to select from a list (or in set of lists) displayed within the Dialog. The creation and use of Selection and FileSelection Dialogs is similar. The FileSelectionDialog (Fig. 9.7) allows the selection of files from a directory which has use in many applications (text editors, graphics programs etc.) The FileSelection Dialog provides a means for merely browsing directories and selecting file names. It is up to the application to read/write the file, or to use the file name appropriately. The SelectionDialog allows for more general selection. We will study the FileSelectionDialog as it is more complex and it is also more commonly used.
Fig. 9.7 The FileSelectionDialog Widget
To create a FileSelectionDialog , the
XmCreateFileSelectionDialog() function is
commonly used. You must include the <Xm/FileSB.h>
header file.
A FileSelectionDialog has many resources you can set to control the search of files: (All resources are XmString data types except where indicated.)
*.c
so as only to list C source files in the dialog.
<Xm/FileSB.h>
.
The search directory, directory mask and others can be altered from within the Dialog window.
The FileSelectionDialog has many child widgets under its control. It is sometimes useful to take control of these child widget in order to have greater control of their resources or callback or even to remove (XtUnmanageChild()) one. The function XmFileSelectionBoxGetChild() is used to return the ID of a specified child widget. The function takes two arguments:
<Xm/FileSB.h>
and include:
XmDIALOG_APPLY_BUTTON, XmDIALOG_LIST, XmDIALOG_CANCEL_BUTTON, XmDIALOG_LIST_LABEL, XmDIALOG_DEFAULT_BUTTON, TXmDIALOG_OK_BUTTON, XmDIALOG_DIR_LIST, XmDIALOG_SELECTION_LABEL, XmDIALOG_DIR_LIST_LABEL, XmDIALOG_SEPARATOR, XmDIALOG_FILTER_LABEL, XmDIALOG_TEXT, XmDIALOG_FILTER_TEXT, XmDIALOG_WORK_AREA, XmDIALOG_HELP_BUTTON.
The program file_select.c simply looks for C source
files in a directory -- the XmNdirMask resource is set to filter out only
*.c
files. If a file is selected it's listing is printed to standard
output.
#include <stdio.h> #include <Xm/Xm.h> #include <Xm/MainW.h> #include <Xm/CascadeB.h> #include <Xm/MessageB.h> #include <Xm/PushB.h> #include <Xm/FileSB.h> /* prototype callbacks and other functions */ void quit_pop_up(Widget , char *, XmPushButtonCallbackStruct *), void select_pop_up(Widget , char *, XmPushButtonCallbackStruct *); void ScrubDial(Widget, int); void select_activate(Widget , XtPointer , XmFileSelectionBoxCallbackStruct *) void quit_activate(Widget) void cancel(Widget , XtPointer , XmFileSelectionBoxCallbackStruct *); void error(char *, char *); File *fopen(); Widget top_wid; main(int argc, char *argv[]) { XtAppContext app; Widget main_w, menu_bar, file_select, quit; top_wid = XtVaAppInitialize(&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); main_w = XtVaCreateManagedWidget("main_window", xmMainWindowWidgetClass, top_wid, XmNheight, 300, XmNwidth,300, NULL);
menu_bar = XmCreateMenuBar(main_w, "main_list", NULL, 0); XtManageChild(menu_bar); /* create prompt widget + callback */ file_select = XtVaCreateManagedWidget( "Select", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'S', NULL);
/* Callback has data passed to */ XtAddCallback(file_select, XmNactivateCallback, select_pop_up, NULL); /* create quit widget + callback */ quit = XtVaCreateManagedWidget( "Quit", xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic, 'Q', NULL);
/* Callback has data passed to */ XtAddCallback(quit, XmNactivateCallback, quit_pop_up, "Are you sure you want to quit?"); XtRealizeWidget(top_wid); XtAppMainLoop(app); }
void select_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { Widget dialog, remove; XmString mask; Arg args[1]; /* Create the FileSelectionDialog */ mask = XmStringCreateLocalized("*.c"); XtSetArg(args[0], XmNdirMask, mask);
dialog = XmCreateFileSelectionDialog(cascade_button, "select", args, 1); XtAddCallback(dialog, XmNokCallback, select_activate, NULL); XtAddCallback(dialog, XmNcancelCallback, cancel, NULL); remove = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON); XtUnmanageChild(remove); /* delete HELP BUTTON */ XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
void quit_pop_up(Widget cascade_button, char *text, XmPushButtonCallbackStruct *cbs) { Widget dialog; XmString xm_string; Arg args[2]; /* label the dialog */ xm_string = XmStringCreateLocalized(text); XtSetArg(args[0], XmNmessageString, xm_string); /* set up default button for cancel callback */ XtSetArg(args[1], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
/* Create the WarningDialog */ dialog = XmCreateWarningDialog(cascade_button, "quit", args, 2); ScrubDial(dialog, XmDIALOG_HELP_BUTTON); XmStringFree(xm_string); XtAddCallback(dialog, XmNokCallback, quit_activate, NULL); XtManageChild(dialog); XtPopup(XtParent(dialog), XtGrabNone); }
/* routine to remove a DialButton from a Dialog */ void ScrubDial(Widget wid, int dial) { Widget remove; remove = XmMessageBoxGetChild(wid, dial); XtUnmanageChild(remove); }
/* callback function for Prompt activate */ void select_activate(Widget widget, XtPointer client_data, XmFileSelectionBoxCallbackStruct *selection) { /* function opens file (text) and prints to stdout */ FILE *fp; char *filename, line[200]; XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &filename);
if ( (fp = fopen(filename,"r")) == NULL) error("CANNOT OPEN FILE", filename); else { while ( !feof(fp) ) { fgets(line,200,fp); printf("%s\n",line); } fclose(fp); } }
void cancel(Widget widget, XtPointer client_data, XmFileSelectionBoxCallbackStruct *selection) { XtUnmanageChild(widget); /* undisplay widget */ } void error(char *s1, char *s2) { /* prints error to stdout */ printf("%s: %s\n", s1, s2); exit(-1); }
/* callback routines for quit ok dialog */ void quit_activate(Widget dialog) { printf("Quit Ok was pressed.\n"); exit(0); }
Motif allows the programmer to create new customised Dialogs. BulletinBoardDialogs and FormDialogs let you place widgets within them in a similar fashion to their corresponding BulletinBoard and Form widgets. We will, therefore, not deal with these further in this text.
Exercise 6981
Rewrite the error() function of the file_select.c program so that errors trapped by this program are displayed in an ErrorDialog widget and not simply printed to standard output.