360 likes | 602 Views
A Simple Motif Widget. This is a shell widget with a label widget contained in it. The basic steps involved in creating and displaying this or any other Motif widget are essentially the same. Basic Steps in a Motif Application.
E N D
A Simple Motif Widget This is a shell widget with a label widget contained in it. The basic steps involved in creating and displaying this or any other Motif widget are essentially the same.
Basic Steps in a Motif Application • InitializeXt. Open a connection to the X server and create a data structure called an application context. • Create a shell, to serve as a container for all other widgets in program (can be combined with step 1) • Create widgets, using parameterized calls to Xt routines • Register callbacks, which are the functions to be called in response to some user input
Basic Steps in a Motif Application (cont'd) • Manage all widgets, that is, associate container widgets with their children to keep track of their size and position • Realize all widgets, that is, create an X window on the screen and have the widget display itself • Handle events. Enter an event loop to receive events from the X server. Events are removed from a queue and dispatched to the appropriate widget for handling (that is, a callback occurs)
The "Hello World" C++/Xt/Motif Program // hello.C, Hello World using C++ and Motif #include <Xm/Xm.h> #include <Xm/Label.h> void main ( int argc, char **argv ) { Widget label, shell; XtAppContext app; XmString xmstr; Arg args[10]; int n; // Initialize the Intrinsics shell = XtAppInitialize (&app, "Hello", NULL, 0, &argc, argv, NULL, NULL, 0 ); ...
Notes on the First Part • All include files are relative to /usr/include/ • Xm/Xm.h includes X11/Intrinsic.h and X11/Xlib.h • Xm.h defines Motif widgets (names start with ``Xm'') • Intrinsic.h defines X Toolkit widgets (names start with ``Xt'') • Xlib.h defines X basics (names start with ``X'') • The call to XtAppInitialize combines steps 1 and 2
"Hello World" Program (cont'd) ... // Create a compound string to display the Hello message xmstr = XmStringCreateLocalized ( "Hello World" ); // Create a label widget to display the string n = 0; XtSetArg ( args[n], XmNlabelString, xmstr ); n++; label = XtCreateManagedWidget ( "label", xmLabelWidgetClass, shell, args, n ); // Free the compound string when it is no longer needed XmStringFree ( xmstr ); XtRealizeWidget ( shell ); XtAppMainLoop ( app ); }
Notes on the Second Part • The call to XtCreateManagedWidget combines steps 3 and 5 • There is no step 4 in this example (no ``callbacks'') • The call to XtRealizeWidget is step 6 • The call to XtAppMainLoop is step 7
Initialization (Steps 1 and 2) Xt initialization function prototype: Widget XtAppInitialize ( XtAppContext *appContext, //1 const String className, //2 XrmOptionDescList options, //3 Cardinal numOptions, //4 Cardinal *argc, //5 char **argv, //6 const String *fallbackResources, //7 ArgList args, //8 Cardinal numArgs ); //9 XtAppInitialize is a convenience function.
XtAppInitialize Arguments • Reference argument to hold application context data structure • Application's class name, which is usually the program name upper cased • Used if application-specific command line arguments are allowed by the application • ditto • Used to search for standard command line args • ditto
XtAppInitialize Arguments (cont'd) • Used if additional customizable widget parameters (resources) are required as fallbacks • Allows the program to specify additional arguments (not the user) to be passed to the shell widget • ditto
Compound Strings • Motif has defined an abstraction called compound string to allow for international character sets and eliminate dependency on ASCII • The easiest way to create a Motif compound string is with XmStringCreateLocalized: xmstr = XmStringCreateLocalized("Hello World");
Creating Widgets (Step 3) The simplest way to create a widget (prototype): Widget XtCreateWidget (const String name, //1 WidgetClass widgetclass, //2 Widget parent, //3 ArgList args, //4 Cardinal numArgs ); //5
XtCreateWidget Arguments • Name of the widget to be created (in our example, "label") • Class pointer for the widget (xmLabelWidgetClass) • Parent of the new widget (in our example, "shell") • To specify additional widget arguments • ditto
Managing Widgets (Step 5) • Every widget except the shell must be managed by its parent • After creating a widget with XtCreateWidget, you can manage it with another Xt call (XtManageChild) • Or, you can do it all at once with XtCreateManagedWidget, which accepts the same arguments as XtCreateWidget.
Giving Widgets Additional Info • The first 3 arguments to XtCreateWidget (or XtCreateManagedWidget) are required for every widget class • However, different widget classes have different parameters associated with them (called resources). • For example, a label widget cannot be created without a string that it is to display • Specific widget resources are passed to XtCreateWidget through an ArgList.
Giving Widgets Additional Info (cont'd) • An ArgList is an array of type Arg • An Arg is a pair consisting of the name of a widget's customizable parameter and also the value of the parameter • In our example, name: XmNlabelString value: Motif string "Hello World" • It is often convenient to use the macro XtSetArg to add a name/value pair to an ArgList.
Using XtSetArg In our example: 0 . . . 9 args Arg args[10]; int n; . . . n = 0; XtSetArg ( args[n], XmNlabelString, xmstr ); n++; label = XtCreateManagedWidget("label", XmLabelWidgetClass, shell, args, n ); To find widget resource names and widget class pointers, consult the online Motif reference sheet.
Another Example We can also specify the width and height of the label in pixels: Arg args[10]; int n; . . . n = 0; XtSetArg ( args[n], XmNlabelString, xmstr ); n++; XtSetArg ( args[n], XmNwidth, 400 ); n++; XtSetArg ( args[n], XmNheight, 300 ); n++; label = XtCreateManagedWidget("label", XmLabelWidgetClass, shell, args, n ); 0 1 2 . . . 9 args
New Larger Label Widget Note: Font sizes are usually specified using the X Resource Manager and Database, covered later. Also, the look-and-feel of the frame surrounding the widget is different because a different window manager was used.
Creating Widgets Using the vararg Version label = XtVaCreateManagedWidget ( ``label'', xmLabelWidgetClass, shell, XmNlabelString, xmstr, XmNwidth, 200, XmNheight, 300, NULL );
Notes on XtVaCreateManagedWidget • Note the Va in the name • First three arguments the same as before • After that come resource/value pairs • The list of pairs must be terminated with NULL
Using XtVaSetValues ToSeparate Widget Creation from Setting Widget Resource Values label = XtVaCreateManagedWidget ( ``label'', xmLabelWidgetClass, shell, NULL); XtVaSetValues(label, XmNlabelString, xmstr, XmNwidth, 200, XmNheight, 300, NULL );
Realizing Widgets (Step 6) • Before a widget can be seen, it must create an X window in which to display itself (called realizing the widget) • Use XtRealizeWidget for this: void XtRealizeWidget ( Widget w ); • XtRealizeWidget recursively realizes its argument and all children. In the example: XtRealizeWidget ( shell );
Entering the Event Loop (Step 7) Xt implements the event loop like this: void XtAppMainLoop ( XtAppContext app ) { for ( ; ; ) { Xevent event; XtAppNextEvent ( app, &event ); XtDispatchEvent ( &event ); } }
Notes On The Event Loop • The event loop has no explicit return • XtAppNextEvent waits until an event is available in the application's event queue When one or more events are available, it removes the first event and returns • XtDispatchEvent finds the window in which the event occurred and sends the event to that window's widget (a callback) Starting the event loop in the example: XtAppMainLoop( app );
Compiling and Running hello.C 12% g++ -o hello hello.C -lXm -lXt -lX11 13% hello Load libraries must be specified using -l option. The widget will be displayed in the upper left hand corner of the screen. The "hello" program will not terminate until the user clicks the menu bar and quits the widget.
Handling Events A widget with a pushbutton instead of a label: Note that the widget is shaded in such as way as to make it appear to protrude from the screen. Suppose we want this application to quit when the "Push Me" button is clicked.
Callback Functions • Each widget supports a specified set of callbacks, which trigger functions to be called when certain events are detected by the widget • There are three types of callbacks for the pushbutton widget: • XmNarmCallback: when mouse button is clicked while mouse cursor is on button • XmNactivateCallback: when mouse button is released while mouse cursor is on button • XmNdisarmCallback: when mouse button is released after mouse cursor moves off button Callbacks for all widgets are in reference sheet.
Associating a Function with a Callback void XtAddCallback ( Widget widget, //1 const String callbackName, //2 XtCallbackProc proc, //3 XtPointer clientData); //4 • The widget to be associated with the callback • Name of the callback • The actual callback function • Optional application-defined data to be passed to the callback function when called
Prototype of a Callback Function void <funcname> (Widget w, // 1 XtPointer clientData, // 2 XtPointer callData); // 3 • This is the function called by the X server back to the client application. It passes the following information back to the client: • The widget for which the callback was called • The clientData specified by the client application in the call to XtAddCallback. • Data provided by the widget, usually concerning the nature of the X event that triggered the callback
A Simple Callback that Quits void quitCallback (Widget w, XtPointer clientData, XtPointer callData) { exit ( 0 ); } • Note that a simple callback like this does not use its parameters • To avoid compiler warnings about unused parameters, leave the parameter type but omit names: void quitCallback (Widget, XtPointer, XtPointer) ...
Pushbutton Example // pushme.C, Using callback functions in C++ #include <stdlib.h> // Needed for exit prototype #include <Xm/Xm.h> #include <Xm/PushB.h> static void quitCallback ( Widget, XtPointer, XtPointer ); void main ( int argc, char **argv ) { Widget button, shell; XtAppContext app; XmString xmstr; // Initialize the Intrinsics shell = XtAppInitialize ( &app, "Pushme", NULL, 0, &argc, argv, NULL, NULL, 0 ); ...
Pushbutton Example (cont'd) . . . // Create a compound string xmstr = XmStringCreateLocalized ( "Push Me" ); // Create an XmPushButton widget to display the string button = XtVaCreateManagedWidget ( "button", xmPushButtonWidgetClass, shell, XmNlabelString, xmstr, NULL ); // Free the compound string after the XmPushButton // has copied it XmStringFree ( xmstr ); ...
Pushbutton Example (cont'd) . . . // Register the quitCallback callback function // to be called when the button is pushed XtAddCallback ( button, XmNactivateCallback, quitCallback, NULL ); // No client data needed // Realize all widgets and enter the main event loop XtRealizeWidget ( shell ); XtAppMainLoop ( app ); } // Callback invoked when button is activated void quitCallback ( Widget, XtPointer, XtPointer ) { exit ( 0 ); }
Notes on the Pushbutton Example • Includes a different widget header file (Xm/PushB.h) • Incorporates the quitCallback prototype • Has a call to XtAddCallback • Defines the quitCallback function
The Architectural Impact of Event Driven Programming • Applications run asynchronously with respect to the server (and with respect to other applications) • Program cannot suspend while waiting for input (as with scanf), because it cannot receive events • No user-friendly way to interrupt an application (control-C will not work) • A program task should not take longer than the user's perception of a "reasonable" response time • If a task is not done quickly, events will pile up in the queue and the user will encounter windows not redrawn correctly (or worse)