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