Previous | Contents | Index |
XrmQGetResource(database_id, name_list_id, class_list_id, repr_type_id_return, repr_value_id_return) |
XrmStringToNameList(repr_name, repr_list_id_return) |
XrmStringToClassList(repr_class, repr_list_id_return) |
When mouse and keyboard events occur, the server usually delivers them to an appropriate client, determined by the window and the input focus. However, by using the functions described in this chapter, the client can control the delivery of pointer and keyboard events independently. See Chapter 9 for more information about event handling.
This chapter describes how to use grabs and includes the following topics:
When mouse buttons or keyboard keys are grabbed, events are sent to the grabbing client, rather than the client that owns the window.
This section describes how events are reported and other fundamentals
of grabbing routines.
11.1.1 Event Reporting
When calling a grab routine, it is possible to specify that pointer or keyboard events be reported by the server in synchronous or asynchronous mode. In asynchronous mode, event processing continues as usual.
If the client specifies synchronous mode, no further events of the type specified to be synchronous (either pointer, keyboard, or both) are processed. Depending on the type specified, the pointer and keyboard are considered to be frozen during this interval. Actual pointer and keyboard events are not lost, they are simply queued in the server for later processing. Further events are processed only when the grabbing client releases the grab or calls the ALLOW EVENTS routine.
Refer to Section 11.5 for more information about the ALLOW EVENTS
routine.
11.1.2 Active and Passive Grabs
There are two kinds of grabs: active and passive. An active grab occurs when a single client grabs the pointer or the keyboard explicitly. The routines GRAB POINTER and GRAB KEYBOARD perform active grabs.
A passive grab occurs when the client grabs a particular key or mouse button in a window. The routines GRAB BUTTON and GRAB KEY perform passive grabs. With passive grabs, the grab activates when the button or key is actually pressed. The passive grab terminates when the button or key is released. Passive grabs are convenient for implementing reliable popup menus.
For example, you can guarantee that the popup is mapped before the up pointer button event occurs by grabbing a button that requests synchronous behavior. The down event triggers the grab and freezes further processing of pointer events until the client maps the popup window. The client can then allow further event processing. The up event is then correctly processed, relative to the popup window.
When performing an active grab on the pointer or the keyboard, the routines take a time argument. The server maintains the time when the following occurs:
By using a time-stamp, the client can specify that its request should
not occur if another application has in the meanwhile taken control of
the keyboard, pointer, or selection. One predefined value called
CurrentTime is used in requests to represent the
current server time.
11.2 Pointer Grabs
To perform an active grab on the pointer, use the GRAB POINTER routine.
Example 11-1 illustrates how to use a pointer grab. The example creates two windows and actively grabs the pointer when MB2 is pressed. This changes the pointer cursor shape and confines the pointer cursor to window2.
Example 11-1 Grabbing the Pointer |
---|
#include <decw$include/cursorfont.h> . . . /***** Create the windows *****/ static void doCreateWindows( ) { int window1W = 400; int window1H = 400; int window1X = (XWidthOfScreen(screen)-window1W)>>1; int window1Y = (XHeightOfScreen(screen)-window1H)>>1; int window2W = 200; int window2H = 200; int window2X = 50; int window2Y = 50; XSetWindowAttributes xswa; /* Create the window1 window */ xswa.background_pixel = doDefineColor(1); (1) xswa.event_mask = ButtonPressMask; window1 = XCreateWindow(dpy, XRootWindowOfScreen(screen), window1X, window1Y, window1W, window1H, 0, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); /* Create the window2 window */ xswa.background_pixel = doDefineColor(2); xswa.event_mask = ButtonPressMask; window2 = XCreateWindow(dpy, window1, window2X, window2Y, window2W, window2H, 4, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); } . . . /***** Handle events *****/ static void doHandleEvents( ) { XEvent event; for ( ; ; ) { XNextEvent(dpy, &event); switch (event.type) { case ButtonPress: doButtonPress(&event); break; case ButtonRelease: doButtonRelease(&event); break; } } } /***** Grabbing the Pointer *****/ static void doButtonPress(eventP) XEvent *eventP; { if (eventP -> xbutton.button == Button2) { new_cursor = XCreateFontCursor (dpy, XC_sailboat); (2) XGrabPointer(dpy, window2, 0, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, window2, new_cursor, CurrentTime); } if (eventP ->xbutton.button == Button3) { (3) XUngrabPointer(dpy, CurrentTime); sys$exit (1); } } /***** Write the message *****/ static void doButtonRelease( ) Xevent *eventP; { (4) if (eventP -> xbutton.button == Button1){ XDrawImageString(dpy, window2, gc, 40, 75, message[state] strlen(message[state])); } } |
XGrabPointer(display, window_id, owner_events, event_mask, pointer_mode, keyboard_mode, confine_id, cursor_id, time) |
Because the owner_events argument is set to 0,
pointer events are reported with respect to the grabbing window, and
only if selected by an event mask. Therefore, in the example, the
grabbing client will receive only button press and button release
events. (If owner_events were set to 1, pointer events
would be reported as usual to the client.)
Because the
pointer_mode and keyboard_mode
arguments are set to GrabModeAsync, all pointer and
keyboard events are unaffected by the grab and processing of both event
types continue as usual.
XUngrabPointer(display, time) |
Clients can also modify the parameters of an active pointer grab by calling the CHANGE ACTIVE POINTER GRAB routine as long as the following is true:
Use the GRAB BUTTON routine to passively grab control of a single mouse button.
Example 11-2 illustrates how to grab a single mouse button. The example creates two windows. The button grab occurs when MB2 and the shift are pressed simultaneously.
Because the GRAB BUTTON routine performs a passive grab, the grab terminates whenever the button is released. To deactivate a button grab before the button release, call UNGRAB BUTTON. The UNGRAB BUTTON routine does not affect any active grab.
Example 11-2 Grabbing a Button |
---|
. . . XSetWindowAttributes xswa; /* Create the window1 window */ (1) xswa.event_mask = ButtonPressMask; window1 = XCreateWindow(dpy, XRootWindowOfScreen(screen), window1X, window1Y, window1W, window1H, 0, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); /* Create the window2 window */ xswa.event_mask = ButtonPressMask; window2 = XCreateWindow(dpy, window1, window2X, window2Y, window2W, window2H, 4, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); } . . . /***** Grab Button 2 *****/ static void doGrabButton( ) { (2) XGrabButton(dpy, Button2, ShiftMask, window1, 0, Button2MotionMask, GrabModeAsync, GrabModeAsync, window1, None); } /***** Handle events *****/ static void doHandleEvents( ) { XEvent event; for ( ; ; ) { XNextEvent(dpy, &event); switch (event.type) { case MotionNotify: doMotionNotify(&event); break; case ButtonPress: doButtonPress(&event); break; } } } /***** Motion notify event ******/ static void doMotionNotify(eventP) XEvent *eventP; { (3) int x = eventP->xbutton.x; int y = eventP->xbutton.y; XMoveWindow(dpy, window2, x, y); } /***** Button press event *****/ static void doButtonPress(eventP) XEvent *eventP; { if (eventP ->xbutton.button == Button3) { sys$exit (1); } } |
XGrabButton(display, button, modifiers, window_id, owner_events, event_mask, pointer_mode, keyboard_mode, confine_id, cursor_id) |
The event_mask argument specifies that pointer
motion events that occur while MB2 is down are to be reported to the
grabbing client.
Because the arguments
pointer_mode and keyboard_mode are
set to GrabModeAsync, both pointer and keyboard events
are reported normally. During the grab, the pointer is confined to
window1.
To grab the keyboard, use the GRAB KEYBOARD routine. The GRAB KEYBOARD routine actively grabs the keyboard. Use the UNGRAB KEYBOARD to release the keyboard and any queued events if the client has the keyboard actively grabbed from either GRAB KEY or GRAB KEYBOARD.
To grab a single key, use the GRAB KEY routine. The GRAB KEY routine establishes a passive grab on the keyboard.
Example 11-3 illustrates grabbing a key. The example creates two windows. The grab occurs when the F1 and Ctrl keys are pressed simultaneously.
Example 11-3 Grabbing a Key |
---|
#include <decw$include/keysym.h> . . . /***** Create the windows *****/ static void doCreateWindows( ) { int window1W = 400; int window1H = 400; int window1X = (XWidthOfScreen(screen)-window1W)>>1; int window1Y = (XHeightOfScreen(screen)-window1H)>>1; int window2W = 375; int window2H = 375; XSetWindowAttributes xswa; /* Create the window1 window */ xswa.event_mask = ButtonPressMask; window1 = XCreateWindow(dpy, XRootWindowOfScreen(screen), window1X, window1Y, window1W, window1H, 0, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); /* Create the window2 window */ xswa.event_mask = ButtonPressMask; window2 = XCreateWindow(dpy, window1, window2X, window2Y, window2W, window2H, 4, XDefaultDepthOfScreen(screen), InputOutput, XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa); } /***** Map the windows *****/ static void doMapWindows( ) { XMapWindow(dpy, window1); XMapWindow(dpy, window2); } /***** Grab the key ******/ static void doGrabKey( ) { (1) keycode_f1 = XKeysymToKeycode(dpy, XK_F1); (2) XGrabKey(dpy, keycode_f1, ControlMask, window2, 1, GrabModeAsync, GrabModeAsync); } /***** Handle events *****/ static void doHandleEvents( ) { XEvent event; for ( ; ; ) { XNextEvent(dpy, &event); switch (event.type) { case KeyPress: doKeyPress(&event); break; case ButtonPress: doButtonPress(&event); break; } } } /***** Key press event *****/ static void doKeyPress(eventP) XEvent *eventP; { (3) if (eventP ->xkey.keycode == keycode_f1){ XResizeWindow(dpy, window2, resize_w, resize_h); XDrawImageString(dpy, window1, gc, 100, 40, message[state], strlen(message[state])); XDrawImageString(dpy, window1, gc, 100, 60, message[state + 1], strlen(message[state + 1])); } } /***** Button press event *****/ static void doButtonPress(eventP) XEvent *eventP; { if (eventP ->xbutton.button == Button3) { sys$exit (1); } } |
keycode_return = XKeysymToKeycode(display, keysym_id) |
XGrabKey(display, keycode, modifiers, window_id, owner_events, pointer_mode, keyboard_mode) |
To allow events to be processed when the device has been frozen, use the ALLOW EVENTS routine. The ALLOW EVENTS routine is used to release some queued events if the client has caused a device to freeze. A device will freeze when the client performs a pointer or keyboard grab and specifies synchronous reporting of events. It will remain frozen until the client that issued the grab request issues an ALLOW EVENTS request.
The ALLOW EVENTS routine has the following format:
XAllowEvents(display, event_mode, time) |
In the following example, the client has established a grab on the pointer and has specified that all events are processed synchronously. By calling the ALLOW EVENTS routine and specifying the predefined value AsyncPointer for the event_mode argument, pointer event processing continues as usual.
. . . XGrabPointer(dpy, window1, 0, ButtonPressMask, GrabModeSync, GrabModeSync, none, window1, none, CurrentTime) XAllowEvents(dpy, AsyncPointer, CurrentTime) |
For more information about the ALLOW EVENTS routine and a list of the predefined arguments, see the X Window System.
Previous | Next | Contents | Index |