Enternot And: Leavenotify Events
Enternot And: Leavenotify Events
y_lastclick; Window managers also may need these events. Many window managers assign input focus (which
Time t lastc~ck; 1* Time of click (milliseconds)*1 designates the window that gets all keyboard events) to the window that currently contains the pointer.
Time DblClickTime 500; 1* Two clicks < .5 sec apart *1 Such window managers would want to change the focus as the pointer enters a window.
int DblClickspace = 10; 1* Clicks < 10 pixels apart *1
switch (theEvent.type)
EnterNot~ and LeaveNotify'Events
{
case ButtonPress: --=----
button_pressed True; You select these window crossing events by specifying EnterWindowMask and LeClveWindowMask
break; in the call to XSelectlnput. When EnterWindowMask is specified for a window, you receive an
EnterNotify event when the pointer enters the specified window. With LeaveWindowMask, a
LeaveNoti fy event is sent when the pointer leaves the window Thus, changing the cursor, for in-
1* If button was clicked once, this may be a double-click. stance, becomes easy. You change the cursor with an XDefineCursor in response to an EnterNoti fy
* We will call it a double-click if both clicks occurred
* within 0.5 sec of each other and their locations are
event.
* within a 10-pixel-by-10-pixel area
The server reports the information for EnterNotify and LeaveNotify events in the field named
*1
if (button_clicked) xcrossing in the XEvent union. This is an XCrossingEvent data strUcture, defined in <X11·/Xlib. h>
{ as the following:
button_pressed = Falsej
button_clicked = Falsej typedef struct
if«(theEvent.xbutton.time t_lastclick) <= {
DblClickTime) && int type; 1* EnterNotify or LeaveNotify *1
(abs(theEvent.xbutton.x - x_lastclick) <= unsigned long serial; 1* Last processed request number *1
DblClickSpace) && Bool send_event; 1* True = if from a SendEvent *1
(abs(theEvent.xbutton.y y_lastclick) <= Display *display; 1* Display where event occurred *1
DblClickSpace) ) Window window; 1* Window to which event reported*1
{ Window root; 1* Root window in that screen *1
1* It's a double-click. Call appropriate function to handle it *1 Window subwindowj 1* Child window involved in event*1
Time time; 1* Time in milliseconds *I
int x, y'; 1* Final position ·in event window*1
int x_root, 1* Pointer's final position in *1
YJoqtj 1* root window's coordinate frame*1
int mode; 1* One of the three constants:
1* If button was pressed, generate an XUI_BUTTON_CLICK message *1 NotifyNormal, NotifyGrab,
if (button_pressed) NotifyUngrab *I
{ int detail; 1* One of the five'constants:
1* A button click occurred. Remember position and time. *1 NotifyAncestor, NotifyVirtual,
t_lastclick theEvent.xbutton.time; NotifyInferior, NotifyNonLinear,
x_lastclick = theEvent.xbutton.Xj NotifyNonLinearVirtual *1
y_lastclick = theEvent.xbutton.y; Bool same_screen;l* Pointer/window in same screen?*1
button_clicked True; Bool focusj 1* Input focus on this window? *1
button_pressed = False; unsigned int state; I * State of key and buttons *I
} XCrossingEvent;
breakj
Most of the fields in the XCrossingEvent structure are similar to those in XButtonEvent. The x,
y coordinates al~ays represent the final position of the pointer after the crossing event, and state
gives you the state of the buttons and shift keys just before the event.
Wmdow Entry or Exit
The focus field is True if the window identified by the field window or one of its ancestors owns
Notification of the pointer entering and leaving a window is necessary for many tasks in a user in-
the keyboard focus. This can be useful if you want to indicate (perhaps by changing the border
terface. In a menu, you may want to somehow highlight the item (perhaps by displaying that win-
color) which of yout application's windows has the input focus (assuming your application uses
dow in reverse video) that currently contains the pointer. In an editor, you may change the cursor
multiple windows).
in the window displaying the text. For such tasks, you want to know when the mouse enters or
leaves a window.
XGetMotionEvents allocates an array of structures of type XTimeCoord, fills it with information
received from the X server, and returns the address of that buffer to the calling program. The
XTimeCoord structure is defined in <X11/Xlib. h> as follows:
typedef struct
{
Time time; /* Milliseconds since the X server started */
short x, y; /* Position relative to window specified in
the call to XGetMotionEvents */
The last argument you provide to XGetMotionEvents is the address of an integer, wherein it re-
turns the number of elements in the array holding the motion history. Each element of this array
givesyou the pointer's position at a certain time during its motion. The positions are relative to the
origin of the window you specifYin the second argument to XGetMotionEvents.
After you have used the positions reported in the motion history buffer, you have to remember to
releasethe memo sed by the buffer. You can do this by calling XFree.
~
/'
0 ¥-ents" (It'~'~I q I
mouse is important for the point-an -click parts of a GUI; the keyboard is indispensable for
text entry. Whether it is annotating a figure or typing in a program listing, a program must handle
keyboard input to get the job done.
As with the mouse burtonpress and button-release events, the X server generates a KeyPress event
when a key is pressed and a KeyRelease event when the key is released. All keys generate these
events (including, for instance, Shift, Ctr!, Alt, Caps Lock, and the functio keys)..AlI workstations
generate KeyPress events; some systems may not reliably report the KeyRelease event.. Because
there is usually no need to detect a KeyRelease, you should process keyboard input using the
KeyPress event only. That enables the application to work with all X servers.
Keys such as Shift, Ctrl, Alt, and Caps Lock (or Shift Lock) keys are known as~eys
because they modifY the meaning of the other keys. X supports up to five syst~
dent modifier keys:
I
Figure 8.4.
typedef struct .. F1F2
Tramlating keycode to F3 7 8 9
{
int type; 1* Event's type *I keysym and ASC.lI . , 4 5 6
unsigned long serial; 1* Last processed request number *1 characters. 1 2 3
I
Bool send_event; 1* True = if from a SendEvent *1 0
Display *display; 1* Display where event occurred *1
Windqw window; 1* Window to which event reported*1
Window root; 1* Root window in that screen *1 (1)KeyPress
Window sUbwindow; 1* Child window involved in event*1 event
Time time; 1* Time in milliseconds *I reports: theEvent,xkey.state = ShiftMask
t
int x, y; 1* Position in event window *1
int x_root, 1* Pointer's position in the *1
y_root; /* root window's coordinate frame*1
unsigned int state j 1* State of key and buttons *1
unsigned int keycode; 1* detail * I char bufferI10]:
int bufsize = 10;
Bool same_screen; 1* Pointer/window in same screen?*1 (2)Translate
keycode Keysym ks;
XKeyEvent; toKeysym and string XComposeStatus CS i
You can access the fields ofXKeyEvent through the xkey member of the XEvent union. For ex-
ample, if the event is received in a variable named theEvent of type XEvent, refer to the keycode
nchars = 1 - ••------ Number ofcharacters
resulting
after a KeyPress event as theEvent . xkey . key code. fromtranslating
thekey
Most of the fields in the XKeyEvent structure have the same meaning as identically named mem- bufferl0J =' 3 -••
------ ASCIIcharacters
corresponding
tothekey
bers in other event data structures. The two most important fields for processing keystrokes are state
and keycode. The state indicates the state (pressed or released) of the modifier keys, such as Shift, ks = XK_3 -••------- Device-independent
standardname forthekey
Ctrl, and Alt, as well as any system-dependent modifiers. The keycode is an integer with values
between 8 and 255 that uniquely identifies the key. You have to translate this code into ASCII
characters (or the ISO Latin-1 code of which ASCII is a subset) before using it. Keycode Translation with XLookupString
You can use a single function, XLookupString, to complete both steps of translating a keycode to
Keycode Mapping to keysym and Character String a keysym as well as to an ASCII text string (see Figure 8.4). A typical use of this 'functioriroight be -
as follows:
The X server decides the keycode to generate for a specific physical key. Each key, including the
modifiers, has a unique keycode. Although the keycode generated for the common alphanumeric
keys-may be the same for many workstations, it is not guaranteed to be so. Therefore, applications XEvent theEvent;
do not use the raw keycode. Instead, this server-dependent keycode is translated to meaningful char xlat[20j; 1* Room for string *1
characters by a two-step process: int nchar = 20; 1* Size of xlat *1
int count; 1* Chars. returned *1
1. As shown in Figure 8.4, the first step involves translating the keycode to a symbolic name, KeySym key; 1* keysym on return *1
XComposeStatus cs; 1* Compose key status· I
known as keysym. All meaningful combinations of a key and the modifiers have unique
keysyms, which are constants defined in the header file <X11/ keysym. h>. The keysym
resulting from a single keypress depends on the state of the modifier keys as well as the key
itself. For example, if you press the A key alone, you should get a lowercase a, but if you
Translation of keysym to String
With the function XRebindKeysym, you can assign an arbitrary ASCII text string to any key. Note
sWitch(theEvent.type) that this binding of a string to a key is local to your application. It does not ~ffect the other appli-
{ cations sharing the display. Therefore, you can use it without any apprehenSIOn.
case KeyPress:
{ Here is an example of binding the string HELPto the function key F1 and HELP INDEXto Ctrl-F1:
count =
XLookupString(&theEvent, xlat, nchar
&key, &cs); Display *theDisplay;
/* Add null byte to make [sqjxlat[sq] a valid C string */ KeySym modkeys[2];
xlat[count] = [sq]\0[sq];
What you do with the keysym or the text string generated by XLookupString is up to your appli-
cation. If you are accepting text from the user, you will probably use the text string only, perhaps
saving it in a buffer. On the other hand, if you want the application to quit when the user presses
Input Focus
The server can associate a pointer eyent with a specific windo~ by noting;fhich window contains
the pointer. There is no g06a way to decide the win do:, that s~_ouldreceive the key1?oardevents.
?
the Qkey, you can compare the returned keysym with the ones for uppercase and lowercase Q, (in- To solve the problem, X us~ concept ofJops. The WInd~ww:th t~e ~OC\!!i~~ ~resses,
cluding, for instance, Shift, Ctrl, Alt, Caps Lock, and the function keys)-XK_q and XK_Q,respec- regardless of the pointer's location (unless, of course, the pOInter s location alsoCOn:tro1st1le1ocus).
tively.
Because all applications displayi-ngi~ a workstatio~ have to share th,e ke}Lbo-<lr~,
i~ is ~mp?rta.P~to
The XComposeStatus structure passed to XLookupString is used to store certain status informa- have a well-defined mechanism for transfernng the input focus from ~ne applJ(;atl~n s.eWIndowto
another. In fact, such conventions do exist, in the form ofthe Inter-Client Commumcatwn Conven-
tion to support composing multiple key sequences. For example, the user might press a designated
tfomManual (ICCCM). These conventions have been followed earnestly since the release of XII ~4
Compose key, then a backquote ('), and finally an E to construct the capital letter E with the grave
accent. If you do not care about multikey characters, you can provide a NULLpointer in place of the in January 1990. What you need is a window manager tha~ fol.lo,,:"sthe ICC~M. Then you can give
argument. the window manager an appropriate hint about your applIcation s need for Input focus. After that,
your application should get the focus when the user selects your ~pplication' stop-level wi?dow.
The exact mechanism for transferring the focus depends on the WIndow manager. If the wmdow
Display *display; /* Display where event occurred */
manager uses a click-to-type model, the user indicates the focus window by clicking on it. Some Window window; /* Window to which event reported*/
window managers may follow the model whereby the input focus is always on the top-level window int mode; /* One of the three constants:
NotifyNormal, NotifyGrab,
with the pointer in it. NotifyUngrab */
int detail; /* One of the fiva constants:
NotifyAncestor, NotifyVirtual,
Hints to the Window Manager NotifyInferior, NotifyNonLinear,
NotifyNonLinearVirtual */
Application programs that need keyboard input should so indicate by setting the input field of the } XFocusChangeEv~nt;
XWMHintsstructure to True before calling XSetWMHints (or XSetWMProperties). Here is how this
You care about getting the focus because of an assignment by the user; therefore, you should care
might be done:
about only those FocusIn events with mode equal to NotifyNormal ..Furthermore, the focus al-
ways changes frbm another application's window to yo'ih application's top-level window. For this
if((p_xwmh XAllocWMHints(» == NULL)
case, the detail field will be Noti fyNonlinear. Thus, you can assign focus to a selected subwindow
{ of your application:
fprintf(stderr, "Error allocating Window
Manager hints!\n"); Display *theDisplay;
exit (1); Window theMain, kb_win;
XSelectInput(theDisplay, theMain, ExposureMask :
FocusChangeMask)j
/* Tell the window manager to put the window in its normal
* state and to transfer input focus to our window when
* the user does 50. Use XSetWMProperties or XSetWMHints to /* In event handling loop ... */
* inform the window manager. switch (theEvent.type)
*/ {
p_xwmh->flags = (InputHint:StateHint); case FocusIn:
p_xwmh->input = Truej /* Give focus to our keyboard handling subwindow */
p_xwmh->initial_state = NormalStatej if(theEvent.xfocus.mode == NotifyNormal &&
theEvent.xfocus.detail == NotifyNonlinear)
XSetInputFocus(theDisplay, kb_win, RevertToParent,
CurrentTime) j
XSelectlnput(theDisplay, w, ExposureMask :
StructureNotifyMaskl; The first step in displaying a menubar is to implement the menu. Each menu shows a number of
items in a window. The program has to initiate some action when the user presses the mouse but-
ton with the pointer inside one of the items. In the beginning of this chapter, you developed a button
window, multiple copies of which can be handled easily, as shown in Listing 8.4. You will reuse
that code and build the menu as an outer window with a number of buttons as subwindows.
The same code can handle a menubar as well as a pull-down menu. The difference between the two
if(theEvent.xany.window == w && is that the individual button windows are laid out horizontally in the menubar, but they are ar-
theEvent.type == ConfigureNotifyl ranged vertically in the pull-down menu.
XResizeWindow(theDisplay, w, theEvent.xconfigure.width, In keeping with the design of xbutton. c (Listing 8.3), the menu has a private data structure in
theEvent.xconfigure.heightl; which information about each copy of the menu is stored. The menu's data structure is divided
into two parts:
Because Conf igu reNot i fy events are generated for a variety of reasons, of which size change is one,
• Infoimation about each menu item is stored in a structure of type D_ITEM.
you should save the old size of the window and compare it with the size reported in the event.
• Information about the entire menu is stored in a structure of type D_MENU.
Listing 8.7 shows the file xmenu. c, which implements the menu window. The data structures D_ITEM
and D_MENU appear in that file.