void
file_cb(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
extern void OpenNewFile(), SaveFile();
int item_no = (int) client_data;
if (item_no == 0) /* the "new" button */
OpenNewFile ();
else if (item_no == 1) /* the "save" button */
SaveFile();
else /* the "Quit" button */
exit (0);
}
The callback routines for menu items should be as simple as possible from a structural point of view. A well−designed
application should have application−specific entry points such as OpenNewFile() and SaveFile(), as shown in
the previous example. These routines should be defined in separate files that are not necessarily associated with the
user−interface portion of the program. The use of modular programming techniques helps considerably when an
application is being maintained by a large group of people or when it needs to be ported to other user−interface
platforms.
5.2.3 A Sample Application
Let's examine an example program that integrates what we have discussed so far. Example 4−3 modifies the behavior
of our first example, which displayed an arbitrary pixmap, by allowing the user to change the bitmap dynamically
using a Motif FileSelectionDialog. The program also allows the user to dynamically change the color of the bitmap
using a PulldownMenu. As you can see by the size of the program, adding these two simple features is not trivial.
Many functions and widgets are required in order to make the program functional. As you read the example, don't
worry about unknown widgets or details that we haven't addressed just yet; we will discuss them afterwards. For now,
just try to identify the familiar parts and see how everything works together. 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.
/* dynapix.c −− Display a bitmap in a MainWindow, but allow the user
* to change the bitmap and its color dynamically. The design of the
* program is structured on the pulldown menus of the menubar and the
* callback routines associated with them. To allow the user to choose
* a new bitmap, the "Open" button pops up a FileSelectionDialog where
* a new bitmap file can be chosen.
*/
#include <Xm/MainW.h>
#include <Xm/Label.h>
#include <Xm/MessageB.h>
#include <Xm/FileSB.h>
/* Globals: the toplevel window/widget and the label for the bitmap.
* "colors" defines the colors we use, "cur_color" is the current
* color being used, and "cur_bitmap" references the current bitmap file.
*/
Widget toplevel, label;
String colors[] = { "Black", "Red", "Green", "Blue" };
Pixel cur_color;
char cur_bitmap[1024] = "xlogo64"; /* make large enough for full pathnames */
5 The Main Window 5.2.3 A Sample Application
92
main(argc, argv)
int argc;
char *argv[];
{
Widget main_w, menubar, menu, widget;
XtAppContext app;
Pixmap pixmap;
XmString file, edit, help, open, quit, red, green, blue, black;
void file_cb(), change_color(), help_cb();
XtSetLanguageProc (NULL, NULL, NULL);
/* Initialize toolkit and parse command line options. */
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
/* main window contains a MenuBar and a Label displaying a pixmap */
main_w = XtVaCreateManagedWidget ("main_window",
xmMainWindowWidgetClass, toplevel,
XmNscrollBarDisplayPolicy, XmAS_NEEDED,
XmNscrollingPolicy, XmAUTOMATIC,
NULL);
/* Create a simple MenuBar that contains three menus */
file = XmStringCreateLocalized ("File");
edit = XmStringCreateLocalized ("Edit");
help = XmStringCreateLocalized ("Help");
menubar = XmVaCreateSimpleMenuBar (main_w, "menubar",
XmVaCASCADEBUTTON, file, 'F',
XmVaCASCADEBUTTON, edit, 'E',
XmVaCASCADEBUTTON, help, 'H',
NULL);
XmStringFree (file);
XmStringFree (edit);
/* don't free "help" compound string yet −− reuse it later */
/* Tell the menubar which button is the help menu */
if (widget = XtNameToWidget (menubar, "button_2"))
XtVaSetValues (menubar, XmNmenuHelpWidget, widget, NULL);
/* First menu is the File menu −− callback is file_cb() */
open = XmStringCreateLocalized ("Open...");
quit = XmStringCreateLocalized ("Quit");
XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb,
XmVaPUSHBUTTON, open, 'N', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, quit, 'Q', NULL, NULL,
NULL);
XmStringFree (open);
XmStringFree (quit);
/* Second menu is the Edit menu −− callback is change_color() */
black = XmStringCreateLocalized (colors[0]);
red = XmStringCreateLocalized (colors[1]);
green = XmStringCreateLocalized (colors[2]);
blue = XmStringCreateLocalized (colors[3]);
menu = XmVaCreateSimplePulldownMenu (menubar, "edit_menu", 1, change_color,
XmVaRADIOBUTTON, black, 'k', NULL, NULL,
XmVaRADIOBUTTON, red, 'R', NULL, NULL,
XmVaRADIOBUTTON, green, 'G', NULL, NULL,
5 The Main Window 5.2.3 A Sample Application
93
XmVaRADIOBUTTON, blue, 'B', NULL, NULL,
XmNradioBehavior, True, /* RowColumn resources to enforce */
XmNradioAlwaysOne, True, /* radio behavior in Menu */
NULL);
XmStringFree (black);
XmStringFree (red);
XmStringFree (green);
XmStringFree (blue);
/* Initialize menu so that "black" is selected. */
if (widget = XtNameToWidget (menu, "button_0"))
XtVaSetValues (widget, XmNset, True, NULL);
/* Third menu is the help menu −− callback is help_cb() */
XmVaCreateSimplePulldownMenu (menubar, "help_menu", 2, help_cb,
XmVaPUSHBUTTON, help, 'H', NULL, NULL,
NULL);
XmStringFree (help); /* we're done with it; now we can free it */
XtManageChild (menubar);
/* user can still specify the initial bitmap */
if (argv[1])
strcpy (cur_bitmap, argv[1]);
/* initialize color */
cur_color = BlackPixelOfScreen (XtScreen (toplevel)),
/* create initial bitmap */
pixmap = XmGetPixmap (XtScreen (toplevel), cur_bitmap,
cur_color, WhitePixelOfScreen (XtScreen (toplevel)));
if (pixmap == XmUNSPECIFIED_PIXMAP) {
puts ("can't create initial pixmap");
exit (1);
}
/* Now create label using pixmap */
label = XtVaCreateManagedWidget ("label", xmLabelWidgetClass, main_w,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, pixmap,
NULL);
/* set the label as the "work area" of the main window */
XtVaSetValues (main_w,
XmNmenuBar, menubar,
XmNworkWindow, label,
NULL);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* Any item the user selects from the File menu calls this function.
* It will either be "Open" (item_no == 0) or "Quit" (item_no == 1).
*/
void
file_cb(widget, client_data, call_data)
Widget widget; /* menu item that was selected */
XtPointer client_data; /* the index into the menu */
XtPointer call_data; /* unused */
{
5 The Main Window 5.2.3 A Sample Application
94
static Widget dialog; /* make it static for reuse */
extern void load_pixmap();
int item_no = (int) client_data;
if (item_no == 1) /* the "quit" item */
exit (0);
/* "Open" was selected. Create a Motif FileSelectionDialog w/callback */
if (!dialog) {
dialog = XmCreateFileSelectionDialog (toplevel, "file_sel", NULL, 0);
XtAddCallback (dialog, XmNokCallback, load_pixmap, NULL);
XtAddCallback (dialog, XmNcancelCallback, XtUnmanageChild, NULL);
}
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
}
/* The OK button was selected from the FileSelectionDialog (or, the user
* double−clicked on a file selection). Try to read the file as a bitmap.
* If the user changed colors, we call this function directly from change_color()
* to reload the pixmap. In this case, we pass NULL as the callback struct
* so we can identify this special case.
*/
void
load_pixmap(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
Pixmap pixmap;
char *file = NULL;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) call_data;
if (cbs) {
if (!XmStringGetLtoR (cbs−>value, XmFONTLIST_DEFAULT_TAG, &file))
return; /* internal error */
(void) strcpy (cur_bitmap, file);
XtFree (file); /* free allocated data from XmStringGetLtoR() */
}
pixmap = XmGetPixmap (XtScreen (toplevel), cur_bitmap,
cur_color, WhitePixelOfScreen (XtScreen (toplevel)));
if (pixmap == XmUNSPECIFIED_PIXMAP)
printf ("Can't create pixmap from %s0, cur_bitmap);
else {
Pixmap old;
XtVaGetValues (label, XmNlabelPixmap, &old, NULL);
XmDestroyPixmap (XtScreen (toplevel), old);
XtVaSetValues (label,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, pixmap,
NULL);
}
}
/* called from any of the "Edit" menu items. Change the color of the
* current bitmap being displayed. Do this by calling load_pixmap().
*/
void
5 The Main Window 5.2.3 A Sample Application
95
change_color(widget, client_data, call_data)
Widget widget; /* menu item that was selected */
XtPointer client_data; /* the index into the menu */
XtPointer call_data; /* unused */
{
XColor xcolor, unused;
Display *dpy = XtDisplay (label);
Colormap cmap = DefaultColormapOfScreen (XtScreen (label));
int item_no = (int) client_data;
if (XAllocNamedColor (dpy, cmap, colors[item_no], &xcolor, &unused) == 0 ||
cur_color == xcolor.pixel)
return;
cur_color = xcolor.pixel;
load_pixmap (widget, NULL, NULL);
}
#define MSG "Use the FileSelection dialog to find bitmap files to0isplay in the scrolling area in the main window. Use0he edit menu to display the bitmap in different colors."
/* The help button in the help menu from the menubar was selected.
* Display help information defined above for how to use the program.
* This is done by creating a Motif information dialog box. Again,
* make the dialog static so we can reuse it.
*/
void
help_cb(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
static Widget dialog;
if (!dialog) {
Arg args[5];
int n = 0;
XmString msg = XmStringCreateLtoR (MSG, XmFONTLIST_DEFAULT_TAG);
XtSetArg (args[n], XmNmessageString, msg); n++;
dialog = XmCreateInformationDialog (toplevel, "help_dialog", args, n);
}
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
}
The output of the program is shown in the figure.
5 The Main Window 5.2.3 A Sample Application
96

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

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.