11.2.1 Handling Input Events
Since the callback approach to event handling is the simplest, we'll begin by discussing that approach. the source code
shows an extremely simple drawing program that associates a line drawing function with the XmNinputCallback
resource. Pressing any of the pointer buttons marks the starting point of a line; releasing the button marks the
endpoint. You can only draw straight lines. Even though the default translation table for the DrawingArea widget
selects key events and these events are passed to the callback function, the callback function itself ignores them and
thus key events have no effect.
To demonstrate the complications inherent in using the DrawingArea widget as a manager, the program also displays
a PushButton gadget that clears the window. A single callback function, drawing_area_callback(), uses both
the reason and the event fields of the XmDrawingAreaCallbackStruct to determine whether to draw a line
or to clear the window.
This simple application draws directly into the DrawingArea widget; the contents of its window is not saved
anywhere. The program does not support redrawing, since its purpose is strictly to demonstrate the way input handling
can be managed using the XmNinputCallback. If the window is exposed due to the movement of other windows,
the contents of the window is not redrawn. A more realistic drawing application would need code to handle both
expose and resize actions. The current application simply clears the window on resize to further illustrate that the
DrawingArea does not retain what is in its window. XtSetLanguageProc() is only available in X11R5; there is
no corresponding function in X11R4.
/* drawing.c −− extremely simple drawing program that introduces
* the DrawingArea widget. This widget provides a window for
* drawing and some callbacks for getting input and other misc
* events. It's also a manager, so it can have children.
* There is no geometry management, tho.
*/
#include <Xm/DrawingA.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, drawing_a, pb;
XtAppContext app;
XGCValues gcv;
GC gc;
void drawing_area_callback();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL,
XmNwidth, 400,
XmNheight, 300,
NULL);
/* Create a DrawingArea widget. */
drawing_a = XtVaCreateWidget ("drawing_a",
xmDrawingAreaWidgetClass, toplevel,
NULL);
/* add callback for all mouse and keyboard input events */
XtAddCallback (drawing_a, XmNinputCallback, drawing_area_callback, NULL);
11 The DrawingArea Widget 11.2.1 Handling Input Events
284
/* Since we're going to be drawing, we will be using Xlib routines
* and therefore need a graphics context. Create a GC and attach
* to the DrawingArea's XmNuserData to avoid having to make global
* variable. (Avoiding globals is a good design principle to follow.)
*/
gcv.foreground = BlackPixelOfScreen (XtScreen (drawing_a));
gc = XCreateGC (XtDisplay (drawing_a),
RootWindowOfScreen (XtScreen (drawing_a)), GCForeground, &gcv);
XtVaSetValues (drawing_a, XmNuserData, gc, NULL);
/* add a pushbutton the user can use to clear the canvas */
pb = XtVaCreateManagedWidget ("Clear",
xmPushButtonGadgetClass, drawing_a,
NULL);
/* if activated, call same callback as XmNinputCallback. */
XtAddCallback (pb, XmNactivateCallback, drawing_area_callback, NULL);
XtManageChild (drawing_a);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* Callback routine for DrawingArea's input callbacks and the
* PushButton's activate callback. Determine which it is by
* testing the cbs−>reason field.
*/
void
drawing_area_callback(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
static Position x, y;
XmDrawingAreaCallbackStruct *cbs =
(XmDrawingAreaCallbackStruct *) call_data;
XEvent *event = cbs−>event;
if (cbs−>reason == XmCR_INPUT) {
/* activated by DrawingArea input event −− draw lines.
* Button Down events anchor the initial point and Button
* Up draws from the anchor point to the button−up point.
*/
if (event−>xany.type == ButtonPress) {
/* anchor initial point (i.e., save its value) */
x = event−>xbutton.x;
y = event−>xbutton.y;
} else if (event−>xany.type == ButtonRelease) {
/* draw full line; get GC and use in XDrawLine() */
GC gc;
XtVaGetValues (widget, XmNuserData, &gc, NULL);
XDrawLine (event−>xany.display, cbs−>window, gc, x, y,
event−>xbutton.x, event−>xbutton.y);
x = event−>xbutton.x;
y = event−>xbutton.y;
}
}
if (cbs−>reason == XmCR_ACTIVATE)
/* activated by pushbutton −− clear parent's window */
XClearWindow (event−>xany.display, XtWindow (XtParent (widget)));
11 The DrawingArea Widget 11.2.1 Handling Input Events
285
}
The output of the program is shown in the figure.
Output of drawing.c
The callback routine that is used for the XmNinputCallback takes the form of a standard callback routine. The
DrawingArea provides a XmDrawingAreaCallbackStruct for all of its callbacks. This structure is defined as
follows:
typedef struct {
int reason;
XEvent *event;
Window window;
} XmDrawingAreaCallbackStruct;
The reason field identifies the type of occurrence that caused the callback to be invoked. For the
XmNinputCallback, the value is XmCR_INPUT. The event field of the callback structure describes the event
that caused the callback to be invoked. In older versions of the Motif toolkit, the pointer may be NULL if reason is
XmCR_RESIZE. The window field is the window associated with the DrawingArea widget−−this is the same value
returned by calling XtWindow() on the widget.
Since the event itself is passed in as part of the callback structure, we can look at the type field of the event for more
information than is provided by the callback reason alone. (See Volume One, Xlib Programming Manual, for a
detailed description of XEvent structures and how to use them.) In fact, since there are many possible events that can
be associated with the reason XmCR_INPUT, you have to look at the event structure if you need any detail about what
actually happened. shows the possible event types for each of the DrawingArea callbacks. tab(@), linesize(2); l | l | l
lfCW | lfCW | lfCW. Callback@Reason@Event Type(s)
_
XmNexposeCallback@XmCR_EXPOSE@Expose XmNresizeCallback@XmCR_RESIZE@ConfigureNotify
11 The DrawingArea Widget 11.2.1 Handling Input Events
286
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.