]> Dogcows Code - chaz/openbox/blob - openbox/event.c
042a76dc93d04037286b84bf9ce4941f35e63ca5
[chaz/openbox] / openbox / event.c
1 #include "openbox.h"
2 #include "client.h"
3 #include "xerror.h"
4 #include "prop.h"
5 #include "config.h"
6 #include "screen.h"
7 #include "frame.h"
8 #include "menu.h"
9 #include "framerender.h"
10 #include "focus.h"
11 #include "stacking.h"
12 #include "extensions.h"
13 #include "timer.h"
14 #include "dispatch.h"
15
16 #include <X11/Xlib.h>
17 #include <X11/keysym.h>
18 #include <X11/Xatom.h>
19 #ifdef HAVE_SYS_SELECT_H
20 # include <sys/select.h>
21 #endif
22
23 static void event_process(XEvent *e);
24 static void event_handle_root(XEvent *e);
25 static void event_handle_client(Client *c, XEvent *e);
26 static void event_handle_menu(Menu *menu, XEvent *e);
27
28 Time event_lasttime = 0;
29
30 /*! The value of the mask for the NumLock modifier */
31 unsigned int NumLockMask;
32 /*! The value of the mask for the ScrollLock modifier */
33 unsigned int ScrollLockMask;
34 /*! The key codes for the modifier keys */
35 static XModifierKeymap *modmap;
36 /*! Table of the constant modifier masks */
37 static const int mask_table[] = {
38 ShiftMask, LockMask, ControlMask, Mod1Mask,
39 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
40 };
41 static int mask_table_size;
42
43 void event_startup()
44 {
45 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
46
47 /* get lock masks that are defined by the display (not constant) */
48 modmap = XGetModifierMapping(ob_display);
49 g_assert(modmap);
50 if (modmap && modmap->max_keypermod > 0) {
51 size_t cnt;
52 const size_t size = mask_table_size * modmap->max_keypermod;
53 /* get the values of the keyboard lock modifiers
54 Note: Caps lock is not retrieved the same way as Scroll and Num
55 lock since it doesn't need to be. */
56 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
57 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
58 XK_Scroll_Lock);
59
60 for (cnt = 0; cnt < size; ++cnt) {
61 if (! modmap->modifiermap[cnt]) continue;
62
63 if (num_lock == modmap->modifiermap[cnt])
64 NumLockMask = mask_table[cnt / modmap->max_keypermod];
65 if (scroll_lock == modmap->modifiermap[cnt])
66 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
67 }
68 }
69 }
70
71 void event_shutdown()
72 {
73 XFreeModifiermap(modmap);
74 }
75
76 void event_loop()
77 {
78 fd_set selset;
79 XEvent e;
80 int x_fd;
81 struct timeval *wait;
82 gboolean had_event = FALSE;
83
84 while (TRUE) {
85 /*
86 There are slightly different event retrieval semantics here for
87 local (or high bandwidth) versus remote (or low bandwidth)
88 connections to the display/Xserver.
89 */
90 if (ob_remote) {
91 if (!XPending(ob_display))
92 break;
93 } else {
94 /*
95 This XSync allows for far more compression of events, which
96 makes things like Motion events perform far far better. Since
97 it also means network traffic for every event instead of every
98 X events (where X is the number retrieved at a time), it
99 probably should not be used for setups where Openbox is
100 running on a remote/low bandwidth display/Xserver.
101 */
102 XSync(ob_display, FALSE);
103 if (!XEventsQueued(ob_display, QueuedAlready))
104 break;
105 }
106 XNextEvent(ob_display, &e);
107
108 event_process(&e);
109 had_event = TRUE;
110 }
111
112 if (!had_event) {
113 timer_dispatch((GTimeVal**)&wait);
114 x_fd = ConnectionNumber(ob_display);
115 FD_ZERO(&selset);
116 FD_SET(x_fd, &selset);
117 select(x_fd + 1, &selset, NULL, NULL, wait);
118 }
119 }
120
121 static Window event_get_window(XEvent *e)
122 {
123 Window window;
124
125 /* pick a window */
126 switch (e->type) {
127 case MapRequest:
128 window = e->xmap.window;
129 break;
130 case UnmapNotify:
131 window = e->xunmap.window;
132 break;
133 case DestroyNotify:
134 window = e->xdestroywindow.window;
135 break;
136 case ConfigureRequest:
137 window = e->xconfigurerequest.window;
138 break;
139 default:
140 #ifdef XKB
141 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
142 switch (((XkbAnyEvent*)&e)->xkb_type) {
143 case XkbBellNotify:
144 window = ((XkbBellNotifyEvent*)&e)->window;
145 default:
146 window = None;
147 }
148 } else
149 #endif
150 window = e->xany.window;
151 }
152 return window;
153 }
154
155 static void event_set_lasttime(XEvent *e)
156 {
157 /* grab the lasttime and hack up the state */
158 switch (e->type) {
159 case ButtonPress:
160 case ButtonRelease:
161 event_lasttime = e->xbutton.time;
162 break;
163 case KeyPress:
164 event_lasttime = e->xkey.time;
165 break;
166 case KeyRelease:
167 event_lasttime = e->xkey.time;
168 break;
169 case MotionNotify:
170 event_lasttime = e->xmotion.time;
171 break;
172 case PropertyNotify:
173 event_lasttime = e->xproperty.time;
174 break;
175 case EnterNotify:
176 case LeaveNotify:
177 event_lasttime = e->xcrossing.time;
178 break;
179 default:
180 event_lasttime = CurrentTime;
181 break;
182 }
183 }
184
185 #define STRIP_MODS(s) \
186 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
187 /* kill off the Button1Mask etc, only want the modifiers */ \
188 s &= (ControlMask | ShiftMask | Mod1Mask | \
189 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
190
191 static void event_hack_mods(XEvent *e)
192 {
193 KeyCode *kp;
194 int i, k;
195
196 switch (e->type) {
197 case ButtonPress:
198 case ButtonRelease:
199 STRIP_MODS(e->xbutton.state);
200 break;
201 case KeyPress:
202 STRIP_MODS(e->xkey.state);
203 break;
204 case KeyRelease:
205 STRIP_MODS(e->xkey.state);
206 /* remove from the state the mask of the modifier being released, if
207 it is a modifier key being released (this is a little ugly..) */
208 kp = modmap->modifiermap;
209 for (i = 0; i < mask_table_size; ++i) {
210 for (k = 0; k < modmap->max_keypermod; ++k) {
211 if (*kp == e->xkey.keycode) { /* found the keycode */
212 /* remove the mask for it */
213 e->xkey.state &= ~mask_table[i];
214 /* cause the first loop to break; */
215 i = mask_table_size;
216 break; /* get outta here! */
217 }
218 ++kp;
219 }
220 }
221 break;
222 case MotionNotify:
223 STRIP_MODS(e->xmotion.state);
224 /* compress events */
225 {
226 XEvent ce;
227 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
228 e->type, &ce)) {
229 e->xmotion.x_root = ce.xmotion.x_root;
230 e->xmotion.y_root = ce.xmotion.y_root;
231 }
232 }
233 break;
234 }
235 }
236
237 static gboolean event_ignore(XEvent *e, Client *client)
238 {
239 switch(e->type) {
240 case FocusIn:
241 #ifdef DEBUG_FOCUS
242 g_message("FocusIn on %lx mode %d detail %d", window,
243 e->xfocus.mode, e->xfocus.detail);
244 #endif
245 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
246 because of RevertToPointerRoot. If the focus ends up reverting to
247 pointer root on a workspace change, then the FocusIn event that we
248 want will be of type NotifyAncestor. This situation does not occur
249 for FocusOut, so it is safely ignored there.
250 */
251 if (e->xfocus.detail == NotifyInferior ||
252 e->xfocus.detail > NotifyNonlinearVirtual ||
253 client == NULL) {
254 /* says a client was not found for the event (or a valid FocusIn
255 event was not found.
256 */
257 e->xfocus.window = None;
258 return TRUE;
259 }
260
261 #ifdef DEBUG_FOCUS
262 g_message("FocusIn on %lx", window);
263 #endif
264 break;
265 case FocusOut:
266 #ifdef DEBUG_FOCUS
267 g_message("FocusOut on %lx mode %d detail %d", window,
268 e->xfocus.mode, e->xfocus.detail);
269 #endif
270 if (e->xfocus.mode == NotifyGrab ||
271 e->xfocus.detail == NotifyInferior ||
272 e->xfocus.detail == NotifyAncestor ||
273 e->xfocus.detail > NotifyNonlinearVirtual) return TRUE;
274
275 #ifdef DEBUG_FOCUS
276 g_message("FocusOut on %lx", window);
277 #endif
278 /* Try process a FocusIn first, and if a legit one isn't found, then
279 do the fallback shiznit. */
280 {
281 XEvent fi, fo;
282 gboolean isfo = FALSE;
283
284 if (XCheckTypedEvent(ob_display, FocusIn, &fi)) {
285 event_process(&fi);
286
287 /* when we have gotten a fi/fo pair, then see if there are any
288 more fo's coming. if there are, then don't fallback just yet
289 */
290 if ((isfo = XCheckTypedEvent(ob_display, FocusOut, &fo)))
291 XPutBackEvent(ob_display, &fo);
292
293 /* secret magic way of event_process telling us that no client
294 was found for the FocusIn event. ^_^ */
295 if (!isfo && fi.xfocus.window == None)
296 focus_fallback(Fallback_NoFocus);
297 if (fi.xfocus.window == e->xfocus.window)
298 return TRUE;
299 } else
300 focus_fallback(Fallback_NoFocus);
301 }
302 break;
303 case EnterNotify:
304 case LeaveNotify:
305 /* NotifyUngrab occurs when a mouse button is released and the event is
306 caused, like when lowering a window */
307 /* NotifyVirtual occurs when ungrabbing the pointer */
308 if (e->xcrossing.mode == NotifyGrab ||
309 e->xcrossing.detail == NotifyInferior ||
310 e->xcrossing.detail == NotifyVirtual)
311 return TRUE;
312 break;
313 }
314 return FALSE;
315 }
316
317 static void event_process(XEvent *e)
318 {
319 Window window;
320 Client *client;
321 Menu *menu = NULL;
322
323 window = event_get_window(e);
324 if (!(client = g_hash_table_lookup(client_map, &window)))
325 menu = g_hash_table_lookup(menu_map, &window);
326 event_set_lasttime(e);
327 event_hack_mods(e);
328 if (event_ignore(e, client))
329 return;
330
331 /* deal with it in the kernel */
332 if (menu) {
333 event_handle_menu(menu, e);
334 return;
335 } else if (client)
336 event_handle_client(client, e);
337 else if (window == ob_root)
338 event_handle_root(e);
339 else if (e->type == MapRequest)
340 client_manage(window);
341 else if (e->type == ConfigureRequest) {
342 /* unhandled configure requests must be used to configure the
343 window directly */
344 XWindowChanges xwc;
345
346 xwc.x = e->xconfigurerequest.x;
347 xwc.y = e->xconfigurerequest.y;
348 xwc.width = e->xconfigurerequest.width;
349 xwc.height = e->xconfigurerequest.height;
350 xwc.border_width = e->xconfigurerequest.border_width;
351 xwc.sibling = e->xconfigurerequest.above;
352 xwc.stack_mode = e->xconfigurerequest.detail;
353
354 /* we are not to be held responsible if someone sends us an
355 invalid request! */
356 xerror_set_ignore(TRUE);
357 XConfigureWindow(ob_display, window,
358 e->xconfigurerequest.value_mask, &xwc);
359 xerror_set_ignore(FALSE);
360 }
361
362 /* user input (action-bound) events */
363 /*
364 if (e->type == ButtonPress || e->type == ButtonRelease ||
365 e->type == MotionNotify)
366 mouse_event(e, client);
367 else if (e->type == KeyPress || e->type == KeyRelease)
368 ;
369 */
370
371 /* dispatch the event to registered handlers */
372 dispatch_x(e, client);
373 }
374
375 static void event_handle_root(XEvent *e)
376 {
377 Atom msgtype;
378
379 switch(e->type) {
380 case ClientMessage:
381 if (e->xclient.format != 32) break;
382
383 msgtype = e->xclient.message_type;
384 if (msgtype == prop_atoms.net_current_desktop) {
385 unsigned int d = e->xclient.data.l[0];
386 if (d < screen_num_desktops)
387 screen_set_desktop(d);
388 } else if (msgtype == prop_atoms.net_number_of_desktops) {
389 unsigned int d = e->xclient.data.l[0];
390 if (d > 0)
391 screen_set_num_desktops(d);
392 } else if (msgtype == prop_atoms.net_showing_desktop) {
393 screen_show_desktop(e->xclient.data.l[0] != 0);
394 }
395 break;
396 case PropertyNotify:
397 if (e->xproperty.atom == prop_atoms.net_desktop_names)
398 screen_update_desktop_names();
399 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
400 screen_update_layout();
401 break;
402 }
403 }
404
405 static void event_handle_client(Client *client, XEvent *e)
406 {
407 XEvent ce;
408 Atom msgtype;
409 int i=0;
410
411 switch (e->type) {
412 case ButtonPress:
413 case ButtonRelease:
414 switch (frame_context(client, e->xbutton.window)) {
415 case Context_Maximize:
416 client->frame->max_press = (e->type == ButtonPress);
417 framerender_frame(client->frame);
418 break;
419 case Context_Close:
420 client->frame->close_press = (e->type == ButtonPress);
421 framerender_frame(client->frame);
422 break;
423 case Context_Iconify:
424 client->frame->iconify_press = (e->type == ButtonPress);
425 framerender_frame(client->frame);
426 break;
427 case Context_AllDesktops:
428 client->frame->desk_press = (e->type == ButtonPress);
429 framerender_frame(client->frame);
430 break;
431 case Context_Shade:
432 client->frame->shade_press = (e->type == ButtonPress);
433 framerender_frame(client->frame);
434 break;
435 default:
436 /* nothing changes with clicks for any other contexts */
437 break;
438 }
439 break;
440 case FocusIn:
441 focus_set_client(client);
442 case FocusOut:
443 #ifdef DEBUG_FOCUS
444 g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
445 client->window);
446 #endif
447 /* focus state can affect the stacking layer */
448 client_calc_layer(client);
449 frame_adjust_focus(client->frame);
450 break;
451 case EnterNotify:
452 if (client_normal(client)) {
453 if (ob_state == State_Starting) {
454 /* move it to the top of the focus order */
455 guint desktop = client->desktop;
456 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
457 focus_order[desktop] = g_list_remove(focus_order[desktop],
458 client);
459 focus_order[desktop] = g_list_prepend(focus_order[desktop],
460 client);
461 } else if (config_focus_follow) {
462 #ifdef DEBUG_FOCUS
463 g_message("EnterNotify on %lx, focusing window",
464 client->window);
465 #endif
466 client_focus(client);
467 }
468 }
469 break;
470 case ConfigureRequest:
471 /* compress these */
472 while (XCheckTypedWindowEvent(ob_display, client->window,
473 ConfigureRequest, &ce)) {
474 ++i;
475 /* XXX if this causes bad things.. we can compress config req's
476 with the same mask. */
477 e->xconfigurerequest.value_mask |=
478 ce.xconfigurerequest.value_mask;
479 if (ce.xconfigurerequest.value_mask & CWX)
480 e->xconfigurerequest.x = ce.xconfigurerequest.x;
481 if (ce.xconfigurerequest.value_mask & CWY)
482 e->xconfigurerequest.y = ce.xconfigurerequest.y;
483 if (ce.xconfigurerequest.value_mask & CWWidth)
484 e->xconfigurerequest.width = ce.xconfigurerequest.width;
485 if (ce.xconfigurerequest.value_mask & CWHeight)
486 e->xconfigurerequest.height = ce.xconfigurerequest.height;
487 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
488 e->xconfigurerequest.border_width =
489 ce.xconfigurerequest.border_width;
490 if (ce.xconfigurerequest.value_mask & CWStackMode)
491 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
492 }
493
494 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
495 if (client->iconic || client->shaded) return;
496
497 if (e->xconfigurerequest.value_mask & CWBorderWidth)
498 client->border_width = e->xconfigurerequest.border_width;
499
500 /* resize, then move, as specified in the EWMH section 7.7 */
501 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
502 CWX | CWY)) {
503 int x, y, w, h;
504 Corner corner;
505
506 x = (e->xconfigurerequest.value_mask & CWX) ?
507 e->xconfigurerequest.x : client->area.x;
508 y = (e->xconfigurerequest.value_mask & CWY) ?
509 e->xconfigurerequest.y : client->area.y;
510 w = (e->xconfigurerequest.value_mask & CWWidth) ?
511 e->xconfigurerequest.width : client->area.width;
512 h = (e->xconfigurerequest.value_mask & CWHeight) ?
513 e->xconfigurerequest.height : client->area.height;
514
515 switch (client->gravity) {
516 case NorthEastGravity:
517 case EastGravity:
518 corner = Corner_TopRight;
519 break;
520 case SouthWestGravity:
521 case SouthGravity:
522 corner = Corner_BottomLeft;
523 break;
524 case SouthEastGravity:
525 corner = Corner_BottomRight;
526 break;
527 default: /* NorthWest, Static, etc */
528 corner = Corner_TopLeft;
529 }
530
531 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
532 }
533
534 if (e->xconfigurerequest.value_mask & CWStackMode) {
535 switch (e->xconfigurerequest.detail) {
536 case Below:
537 case BottomIf:
538 stacking_lower(client);
539 break;
540
541 case Above:
542 case TopIf:
543 default:
544 stacking_raise(client);
545 break;
546 }
547 }
548 break;
549 case UnmapNotify:
550 if (client->ignore_unmaps) {
551 client->ignore_unmaps--;
552 break;
553 }
554 client_unmanage(client);
555 break;
556 case DestroyNotify:
557 client_unmanage(client);
558 break;
559 case ReparentNotify:
560 /* this is when the client is first taken captive in the frame */
561 if (e->xreparent.parent == client->frame->plate) break;
562
563 /*
564 This event is quite rare and is usually handled in unmapHandler.
565 However, if the window is unmapped when the reparent event occurs,
566 the window manager never sees it because an unmap event is not sent
567 to an already unmapped window.
568 */
569
570 /* we don't want the reparent event, put it back on the stack for the
571 X server to deal with after we unmanage the window */
572 XPutBackEvent(ob_display, e);
573
574 client_unmanage(client);
575 break;
576 case MapRequest:
577 g_message("MapRequest for 0x%lx", client->window);
578 if (!client->iconic) break; /* this normally doesn't happen, but if it
579 does, we don't want it! */
580 if (screen_showing_desktop)
581 screen_show_desktop(FALSE);
582 client_iconify(client, FALSE, TRUE);
583 if (!client->frame->visible)
584 /* if its not visible still, then don't mess with it */
585 break;
586 if (client->shaded)
587 client_shade(client, FALSE);
588 client_focus(client);
589 stacking_raise(client);
590 break;
591 case ClientMessage:
592 /* validate cuz we query stuff off the client here */
593 if (!client_validate(client)) break;
594
595 if (e->xclient.format != 32) return;
596
597 msgtype = e->xclient.message_type;
598 if (msgtype == prop_atoms.wm_change_state) {
599 /* compress changes into a single change */
600 while (XCheckTypedWindowEvent(ob_display, e->type,
601 client->window, &ce)) {
602 /* XXX: it would be nice to compress ALL messages of a
603 type, not just messages in a row without other
604 message types between. */
605 if (ce.xclient.message_type != msgtype) {
606 XPutBackEvent(ob_display, &ce);
607 break;
608 }
609 e->xclient = ce.xclient;
610 }
611 client_set_wm_state(client, e->xclient.data.l[0]);
612 } else if (msgtype == prop_atoms.net_wm_desktop) {
613 /* compress changes into a single change */
614 while (XCheckTypedWindowEvent(ob_display, e->type,
615 client->window, &ce)) {
616 /* XXX: it would be nice to compress ALL messages of a
617 type, not just messages in a row without other
618 message types between. */
619 if (ce.xclient.message_type != msgtype) {
620 XPutBackEvent(ob_display, &ce);
621 break;
622 }
623 e->xclient = ce.xclient;
624 }
625 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
626 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
627 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
628 FALSE);
629 } else if (msgtype == prop_atoms.net_wm_state) {
630 /* can't compress these */
631 g_message("net_wm_state %s %ld %ld for 0x%lx",
632 (e->xclient.data.l[0] == 0 ? "Remove" :
633 e->xclient.data.l[0] == 1 ? "Add" :
634 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
635 e->xclient.data.l[1], e->xclient.data.l[2],
636 client->window);
637 client_set_state(client, e->xclient.data.l[0],
638 e->xclient.data.l[1], e->xclient.data.l[2]);
639 } else if (msgtype == prop_atoms.net_close_window) {
640 g_message("net_close_window for 0x%lx", client->window);
641 client_close(client);
642 } else if (msgtype == prop_atoms.net_active_window) {
643 g_message("net_active_window for 0x%lx", client->window);
644 if (screen_showing_desktop)
645 screen_show_desktop(FALSE);
646 if (client->iconic)
647 client_iconify(client, FALSE, TRUE);
648 else if (!client->frame->visible)
649 /* if its not visible for other reasons, then don't mess
650 with it */
651 break;
652 if (client->shaded)
653 client_shade(client, FALSE);
654 client_focus(client);
655 stacking_raise(client);
656 }
657 break;
658 case PropertyNotify:
659 /* validate cuz we query stuff off the client here */
660 if (!client_validate(client)) break;
661
662 /* compress changes to a single property into a single change */
663 while (XCheckTypedWindowEvent(ob_display, e->type,
664 client->window, &ce)) {
665 /* XXX: it would be nice to compress ALL changes to a property,
666 not just changes in a row without other props between. */
667 if (ce.xproperty.atom != e->xproperty.atom) {
668 XPutBackEvent(ob_display, &ce);
669 break;
670 }
671 }
672
673 msgtype = e->xproperty.atom;
674 if (msgtype == XA_WM_NORMAL_HINTS) {
675 client_update_normal_hints(client);
676 /* normal hints can make a window non-resizable */
677 client_setup_decor_and_functions(client);
678 }
679 else if (msgtype == XA_WM_HINTS)
680 client_update_wmhints(client);
681 else if (msgtype == XA_WM_TRANSIENT_FOR) {
682 client_update_transient_for(client);
683 client_get_type(client);
684 /* type may have changed, so update the layer */
685 client_calc_layer(client);
686 client_setup_decor_and_functions(client);
687 }
688 else if (msgtype == prop_atoms.net_wm_name ||
689 msgtype == prop_atoms.wm_name)
690 client_update_title(client);
691 else if (msgtype == prop_atoms.net_wm_icon_name ||
692 msgtype == prop_atoms.wm_icon_name)
693 client_update_icon_title(client);
694 else if (msgtype == prop_atoms.wm_class)
695 client_update_class(client);
696 else if (msgtype == prop_atoms.wm_protocols) {
697 client_update_protocols(client);
698 client_setup_decor_and_functions(client);
699 }
700 else if (msgtype == prop_atoms.net_wm_strut)
701 client_update_strut(client);
702 else if (msgtype == prop_atoms.net_wm_icon)
703 client_update_icons(client);
704 else if (msgtype == prop_atoms.kwm_win_icon)
705 client_update_kwm_icon(client);
706 default:
707 ;
708 #ifdef SHAPE
709 if (extensions_shape && e->type == extensions_shape_event_basep) {
710 client->shaped = ((XShapeEvent*)e)->shaped;
711 frame_adjust_shape(client->frame);
712 }
713 #endif
714 }
715 }
716
717 static void event_handle_menu(Menu *menu, XEvent *e)
718 {
719 MenuEntry *entry;
720
721 g_message("EVENT %d", e->type);
722 switch (e->type) {
723 case ButtonPress:
724 if (e->xbutton.button == 3)
725 menu_hide(menu);
726 break;
727 case ButtonRelease:
728 if (!menu->shown) break;
729
730 /* grab_pointer_window(FALSE, None, menu->frame);*/
731
732 entry = menu_find_entry(menu, e->xbutton.window);
733 if (entry) {
734 int junk;
735 Window wjunk;
736 guint ujunk, b, w, h;
737 XGetGeometry(ob_display, e->xbutton.window,
738 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
739 if (e->xbutton.x >= (signed)-b &&
740 e->xbutton.y >= (signed)-b &&
741 e->xbutton.x < (signed)(w+b) &&
742 e->xbutton.y < (signed)(h+b)) {
743 menu_entry_fire(entry);
744 }
745 }
746 break;
747 case EnterNotify:
748 case LeaveNotify:
749 g_message("enter/leave");
750 entry = menu_find_entry(menu, e->xcrossing.window);
751 if (entry) {
752 entry->hilite = e->type == EnterNotify;
753 menu_entry_render(entry);
754 }
755 break;
756 }
757 }
This page took 0.068404 seconds and 3 git commands to generate.