Introduction to Motif
This afternoon I started writing a GUI frontend for an encryption toolkit I've been working on. I decided to use Motif (a toolkit I rather like for its portability and speed) and it occured to me that its not something you hear about much anymore. So I decided to write this simple introduction to Motif coding using my Linux GUI as an example. The main purpose of this tutorial is to illustrate many of the fundamental steps of nearly every Motif program. This document will get updated as I work on the front end, which will continue in the New Year.
An obvious place to start is the header files. Motif header files are found in the #include <Xm/...> subdirectories, with every Motif program using <Xm/Xm.h>. Each Motif widget has its own header file, which we have to include e.g. #include <Xm/PushB.h>. The Motif libraries need to be linked against when using these headers which is done with the -lXm and -lX11 compiler flags. Quite often gcc will complain when using these flags if the libraries are not where it expects. This can usually be fixed by adding a flag something like -L/usr/X11R6/lib.
Every Motif program is based around six basic steps:
- Initialize toolkit
- Create widgets
- Manage widgets
- Setup callbacks
- Realize the widgets
- Enter event handling loop
Initializing the toolkit can be done using XtInitialize(). This connects the program to the X display, sets up resources and creates a top level window. Usually after creating the top level window a form widget is created to place other widgets on. This can be done using XmCreateForm(). Example code:
Widget top_level, form;
top_level= XtInitialize(argv[0], "test", NULL, 0, &argc, argv);
form = XmCreateForm(top_level, "form", NULL, 0);
XtManageChild(form);
...
Creating other interactive widgets (buttons, text boxes etc) can also be done in different ways but I prefer using a specific function for each widget. These functions come in the form XmCreate() and take four arguments. These arguments are the parent widget, name of the created widget, widget argument list (or NULL) and the number of arguments in the list (or zero). The widget argument list is an array containing a list of Motif resource names and corresponding value. Each entry of the list is generated using XtSetArg() Example code:
Widget button_plugin;
Arg args[10];
XtSetArg(args[0], XmNheight, 35);
button_plugin = XmCreatePushButton(form, "Push Me", args, 1);
XtAddCallback(button_plugin, XmNactivateCallback,
(XtCallbackProc)browse_call, NULL);
XtManageChild(button_plugin);
...
To make a widget appear in the GUI you have to manage it using XtManageChild(). As you can see from my code I tend to manage each widget as I create it. The reason for this is purely a coding convienience. Similarly you can XtUnmanageChild() to remove a widget from a dialog.
The previous example also demonstrated the use of XtAddCallback() to add a callback control for a widget. The function is very self explanatory, except for the last argument which is client data which may be passed to the callback function.
Once you have created all your widgets and handling etc the program needs to realise the top level widget and enter the event handling loop. This is done with XtMainLoop(). Example code:
XtRealizeWidget(top_level);
XtMainLoop();
return 0;
}
And thats it! Its pretty stright forward when you break it all down. Next update will show positioning of widgets, creating file dialogs and a closer look at callbacks.
My complete source for my GUI so far is shown below.
* "xet.c" Version 0.1
*
* Copyright (C) 2005 Michael Cowan.
* http://www.phatindustries.net
* All Rights Reserved
*
*/
/*
* Exits the program.
*/
void quit_call() {
printf("Quitting program\n");
exit(0);
}
/*
* Displays 'About' dialog.
*/
void about_call(Widget button, char *text,
XmPushButtonCallbackStruct *cbs) {
Widget dialog, remove;
XmString xm_string;
Arg args[1];
xm_string = XmStringCreateLocalized("Created by Mike for PhatIndustries, 2005\n"
"http://www.phatindustries.net\n");
XtSetArg(args[0], XmNmessageString, xm_string);
dialog = XmCreateInformationDialog(button, "About", args, 1);
XmStringFree(xm_string);
remove = XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(remove);
remove = XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
XtUnmanageChild(remove);
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
/*
* Closes widget.
*/
void dialog_cancel(Widget widget, XtPointer client_data,
XmFileSelectionBoxCallbackStruct *selection) {
XtUnmanageChild(widget);
}
/*
* Handles file selection from a file select dialog.
*/
void browse_select(Widget widget, XtPointer client_data,
XmFileSelectionBoxCallbackStruct *selection) {
char *filename;
XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &filename);
printf("Filename: %s\n", filename);
XtUnmanageChild(widget);
}
/*
* Displays file selection dialog - no file filter
*/
void browse_call(Widget cascade_button, char *text,
XmPushButtonCallbackStruct *cbs) {
Widget dialog, remove;
XmString mask;
Arg args[1];
dialog = XmCreateFileSelectionDialog(cascade_button, "select", NULL, 0);
XtAddCallback(dialog, XmNokCallback, browse_select, NULL);
XtAddCallback(dialog, XmNcancelCallback, dialog_cancel, NULL);
// Remove HELP button
remove = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(remove);
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
/*
* Main entry point.
*/
main(int argc, char *argv[]) {
Widget top_level, pane, form;
Widget menu_bar, menu_quit, menu_about;
Widget label_plugin, text_plugin, button_plugin;
Widget label_hash, text_hash, button_hash;
Widget label_wordlist, text_wordlist, button_wordlist;
Widget toggle_bf, text_bf;
Widget label_output, text_output;
XmString xmLabel;
Arg args[10];
int nWidgetHeight = 32;
int nLabelWidth = 60;
int nTextWidth = 400;
// Initialize
top_level= XtInitialize(argv[0], "test", NULL, 0, &argc, argv);
form = XmCreateForm(top_level, "form", NULL, 0);
XtManageChild(form);
// Create menu, buttons and callbacks
XtSetArg(args[0], XmNrightAttachment, XmATTACH_FORM);
XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM);
menu_bar = XmCreateMenuBar(form, "main_list", args, 2);
XtManageChild(menu_bar);
XtSetArg(args[0], XmNmnemonic, 'A');;
menu_about = XmCreateCascadeButton(menu_bar, "About", args, 1);
XtAddCallback(menu_about, XmNactivateCallback,
(XtCallbackProc)about_call, NULL);
XtManageChild(menu_about);
XtSetArg(args[0], XmNmnemonic, 'Q');
menu_quit = XmCreateCascadeButton(menu_bar, "Quit", args, 1);
XtAddCallback(menu_quit, XmNactivateCallback, quit_call, NULL);
XtManageChild(menu_quit);
// Create 'Plugin' row
xmLabel = XmStringCreateSimple("Plugin:");
XtSetArg(args[0], XmNwidth, nLabelWidth);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, menu_bar);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_FORM);
XtSetArg(args[5], XmNlabelString, xmLabel);
label_plugin = XmCreateLabel(form, "label", args, 6);
XmStringFree(xmLabel);
XtManageChild(label_plugin);
XtSetArg(args[0], XmNheight, nWidgetHeight);
XtSetArg(args[1], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[2], XmNtopWidget, menu_bar);
XtSetArg(args[3], XmNrightAttachment, XmATTACH_FORM);
button_plugin = XmCreatePushButton(form, "...", args, 4);
XtAddCallback(button_plugin, XmNactivateCallback,
(XtCallbackProc)browse_call, NULL);
XtManageChild(button_plugin);
XtSetArg(args[0], XmNwidth, nTextWidth);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, menu_bar);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[5], XmNleftWidget, label_plugin);
XtSetArg(args[6], XmNrightAttachment, XmATTACH_WIDGET);
XtSetArg(args[7], XmNrightWidget, button_plugin);
text_plugin = XmCreateText(form, "text", args, 8);
XtManageChild(text_plugin);
// Create 'Hash' Row
xmLabel = XmStringCreateSimple("Hashs:");
XtSetArg(args[0], XmNwidth, nLabelWidth);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, text_plugin);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_FORM);
XtSetArg(args[5], XmNlabelString, xmLabel);
label_hash = XmCreateLabel(form, "label", args, 6);
XmStringFree(xmLabel);
XtManageChild(label_hash);
XtSetArg(args[0], XmNheight, nWidgetHeight);
XtSetArg(args[1], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[2], XmNtopWidget, text_plugin);
XtSetArg(args[3], XmNrightAttachment, XmATTACH_FORM);
button_hash = XmCreatePushButton(form, "...", args, 4);
XtManageChild(button_hash);
XtSetArg(args[0], XmNwidth, nTextWidth);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, text_plugin);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[5], XmNleftWidget, label_hash);
XtSetArg(args[6], XmNrightAttachment, XmATTACH_WIDGET);
XtSetArg(args[7], XmNrightWidget, button_hash);
text_hash = XmCreateText(form, "text", args, 8);
XtManageChild(text_hash);
// Create Options
XtSetArg(args[0], XmNwidth, 25);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, text_hash);
XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM);
text_bf = XmCreateText(form, "text", args, 5);
XtManageChild(text_bf);
XtSetArg(args[0], XmNheight, nWidgetHeight);
XtSetArg(args[1], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[2], XmNtopWidget, text_hash);
XtSetArg(args[3], XmNrightAttachment, XmATTACH_WIDGET);
XtSetArg(args[4], XmNrightWidget, text_bf);
toggle_bf = XmCreateToggleButton(form, "Brute Force", args, 5);
XtManageChild(toggle_bf);
xmLabel = XmStringCreateSimple("Word List:");
XtSetArg(args[0], XmNwidth, nLabelWidth);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, text_hash);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_FORM);
XtSetArg(args[5], XmNlabelString, xmLabel);
label_wordlist = XmCreateLabel(form, "label", args, 6);
XmStringFree(xmLabel);
XtManageChild(label_wordlist);
XtSetArg(args[0], XmNheight, nWidgetHeight);
XtSetArg(args[1], XmNheight, nWidgetHeight);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, text_hash);
XtSetArg(args[4], XmNrightAttachment, XmATTACH_WIDGET);
XtSetArg(args[5], XmNrightWidget, toggle_bf);
button_wordlist = XmCreatePushButton(form, "...", args, 6);
XtManageChild(button_wordlist);
XtSetArg(args[0], XmNheight, nWidgetHeight);
XtSetArg(args[1], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[2], XmNtopWidget, text_hash);
XtSetArg(args[3], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[4], XmNleftWidget, label_wordlist);
XtSetArg(args[5], XmNrightAttachment, XmATTACH_WIDGET);
XtSetArg(args[6], XmNrightWidget, button_wordlist);
text_wordlist = XmCreateText(form, "text", args, 7);
XtManageChild(text_wordlist);
// Create 'Output' row
xmLabel = XmStringCreateSimple("Output:");
XtSetArg(args[0], XmNlabelString, xmLabel);
XtSetArg(args[1], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[2], XmNtopWidget, text_wordlist);
XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM);
label_output = XmCreateLabel(form, "label", args, 4);
XmStringFree(xmLabel);
XtManageChild(label_output);
XtSetArg(args[0], XmNwidth, nTextWidth);
XtSetArg(args[1], XmNheight, nTextWidth);
XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
XtSetArg(args[3], XmNtopWidget, label_output);
XtSetArg(args[4], XmNleftAttachment, XmATTACH_FORM);
XtSetArg(args[5], XmNrightAttachment, XmATTACH_FORM);
XtSetArg(args[6], XmNbottomAttachment, XmATTACH_FORM);
XtSetArg(args[7], XmNwordWrap, TRUE);
XtSetArg(args[8], XmNeditMode, XmMULTI_LINE_EDIT);
text_output = XmCreateText(form, "text", args, 9);
XtManageChild(text_output);
// Display top level widget and enter GUI loop
XtRealizeWidget(top_level);
XtMainLoop();
return 0;
}
- FIN -
About this entry
You’re currently reading “Introduction to Motif,” an entry on ReloadSystems
- Published:
- 06.03.06 / 10pm
- Category:
- Motif
No comments
Jump to comment form | comments rss [?] | trackback uri [?]