VMS DECwindows Guide to Xlib (Release 4) Programming: MIT C Binding


Previous Contents Index

  1. XrmRepresentation is a typedef defined in DECW$INCLUDE:XRESOURCE.H and declares type as a quark.
  2. The client-defined doGetResource routine calls the Q GET RESOURCE routine and retrieves a resource from the database. The routine passes a fully-qualified name and class in the form of quarks. If a match occurs, the routine returns the address member of the value data structure.
    The Q GET RESOURCE routine has the following format:

    XrmQGetResource(database_id, name_list_id, class_list_id,
    repr_type_id_return, repr_value_id_return)

  3. The STRING TO NAME LIST routine converts a string with one or more components to a quark list.
    The STRING TO NAME LIST routine has the following format:

    XrmStringToNameList(repr_name, repr_list_id_return)

  4. The STRING TO CLASS LIST routine converts a string with one or more components to a quark list.
    The STRING TO CLASS LIST routine has the following format:

    XrmStringToClassList(repr_class, repr_list_id_return)

  5. The client-defined doGetResource routine returns the value 600, which is converted to an integer by the C Library routine atoi.


Chapter 11
Using Grabs

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:

11.1 Grab Fundamentals

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])); 
    } 
} 

  1. By using the set window attributes data structure, the client specifies an interest in button press events for both window1 and window2. See Chapter 3 for more information about setting window attributes.
  2. When MB2 is pressed, the client calls the GRAB POINTER routine, which actively grabs the pointer, changes the pointer cursor shape and confines it to window2. If the pointer cursor is not in window2, the pointer cursor is automatically moved to the closest edge of window2 just before the grab activates.
    The GRAB POINTER routine has the following format:

    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.

  3. When MB3 is pressed, the client calls the UNGRAB POINTER routine, which terminates the grab, and the program exits.
    The UNGRAB POINTER routine has the following format:

    XUngrabPointer(display, time)

  4. The grabbing client has specified an interest in button release events so that when MB1 is released, the client writes a message in window2. Refer to Chapter 8 for more information about writing text.

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:

11.3 Button Grabs

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); 
    } 
} 

  1. By using the set window attributes data structure, the client specifies an interest in button press events for both window1 and window2. See Chapter 3 for more information about setting window attributes.
  2. The client-defined routine doGrabButton calls the GRAB BUTTON routine to perform a passive grab on MB2 while the shift key and MB2 are pressed and the pointer cursor is in window1.
    The GRAB BUTTON routine has the following format:

    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.

  3. The client-defined routine doMotionNotify uses the x and y members of the motion event data structure as the coordinates to move window2. See Chapter 9 for more information about the motion event data structure.

11.4 Key and Keyboard Grabs

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); 
    } 
} 

  1. The client calls the KEYSYM TO KEYCODE routine that converts a specified key symbol to a defined keycode. If the specified key symbol is not defined for any key, the routine returns zero.
    The KEYSYM TO KEYCODE routine has the following format:

    keycode_return = XKeysymToKeycode(display, keysym_id)

  2. The client establishes a passive grab when the F1 and Ctrl keys are pressed simultaneously. Because the pointer_mode and keyboard_mode arguments are set to GrabModeAsync, all events are reported normally.
    The GRAB KEY routine has the following format:

    XGrabKey(display, keycode, modifiers, window_id, owner_events,
    pointer_mode, keyboard_mode)

  3. The client tests to see that the keycode member of the key event data structure equals the keycode, as specified by the grabbing client. If so, the window is resized and a message is written. See Chapter 9 for more information about the key event data structure. Refer to Chapter 8 for more information about writing text.

11.5 Allowing Events

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