]> Dogcows Code - chaz/openbox/blob - openbox/event.c
only look for FocusOut events on the same window
[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 (!XCheckTypedWindowEvent(ob_display, FocusOut,
295 e->xfocus.window,&fe))
296 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
297 break;
298 if (fe.type == FocusOut) {
299 #ifdef DEBUG_FOCUS
300 g_message("found pending FocusOut");
301 #endif
302 if (!INVALID_FOCUSOUT(&fe)) {
303 /* if there is a VALID FocusOut still coming, don't
304 fallback focus yet, we'll deal with it then */
305 XPutBackEvent(ob_display, &fe);
306 fallback = FALSE;
307 break;
308 }
309 } else {
310 #ifdef DEBUG_FOCUS
311 g_message("found pending FocusIn");
312 #endif
313 /* once all the FocusOut's have been dealt with, if there
314 is a FocusIn still left and it is valid, then use it */
315 event_process(&fe);
316 /* secret magic way of event_process telling us that no
317 client was found for the FocusIn event. ^_^ */
318 if (fe.xfocus.window != None) {
319 fallback = FALSE;
320 break;
321 }
322 }
323 }
324 if (fallback) {
325 #ifdef DEBUG_FOCUS
326 g_message("no valid FocusIn and no FocusOut events found, "
327 "falling back");
328 #endif
329 focus_fallback(Fallback_NoFocus);
330 }
331 }
332 break;
333 case EnterNotify:
334 case LeaveNotify:
335 /* NotifyUngrab occurs when a mouse button is released and the event is
336 caused, like when lowering a window */
337 /* NotifyVirtual occurs when ungrabbing the pointer */
338 if (e->xcrossing.mode == NotifyGrab ||
339 e->xcrossing.detail == NotifyInferior ||
340 (e->xcrossing.mode == NotifyUngrab &&
341 e->xcrossing.detail == NotifyVirtual)) {
342 #ifdef DEBUG_FOCUS
343 g_message("%sNotify mode %d detail %d on %lx IGNORED",
344 (e->type == EnterNotify ? "Enter" : "Leave"),
345 e->xcrossing.mode,
346 e->xcrossing.detail, client?client->window:0);
347 #endif
348 return TRUE;
349 }
350 #ifdef DEBUG_FOCUS
351 g_message("%sNotify mode %d detail %d on %lx",
352 (e->type == EnterNotify ? "Enter" : "Leave"),
353 e->xcrossing.mode,
354 e->xcrossing.detail, client?client->window:0);
355 #endif
356 break;
357 }
358 return FALSE;
359 }
360
361 static void event_process(XEvent *e)
362 {
363 Window window;
364 Client *client;
365 Menu *menu = NULL;
366
367 window = event_get_window(e);
368 if (!(client = g_hash_table_lookup(client_map, &window)))
369 menu = g_hash_table_lookup(menu_map, &window);
370 event_set_lasttime(e);
371 event_hack_mods(e);
372 if (event_ignore(e, client))
373 return;
374
375 /* deal with it in the kernel */
376 if (menu) {
377 event_handle_menu(menu, e);
378 return;
379 } else if (client)
380 event_handle_client(client, e);
381 else if (window == ob_root)
382 event_handle_root(e);
383 else if (e->type == MapRequest)
384 client_manage(window);
385 else if (e->type == ConfigureRequest) {
386 /* unhandled configure requests must be used to configure the
387 window directly */
388 XWindowChanges xwc;
389
390 xwc.x = e->xconfigurerequest.x;
391 xwc.y = e->xconfigurerequest.y;
392 xwc.width = e->xconfigurerequest.width;
393 xwc.height = e->xconfigurerequest.height;
394 xwc.border_width = e->xconfigurerequest.border_width;
395 xwc.sibling = e->xconfigurerequest.above;
396 xwc.stack_mode = e->xconfigurerequest.detail;
397
398 /* we are not to be held responsible if someone sends us an
399 invalid request! */
400 xerror_set_ignore(TRUE);
401 XConfigureWindow(ob_display, window,
402 e->xconfigurerequest.value_mask, &xwc);
403 xerror_set_ignore(FALSE);
404 }
405
406 if (moveresize_in_progress)
407 if (e->type == MotionNotify || e->type == ButtonRelease ||
408 e->type == ButtonPress ||
409 e->type == KeyPress || e->type == KeyRelease) {
410 moveresize_event(e);
411
412 return; /* no dispatch! */
413
414 }
415
416 /* user input (action-bound) events */
417 /*
418 if (e->type == ButtonPress || e->type == ButtonRelease ||
419 e->type == MotionNotify)
420 mouse_event(e, client);
421 else if (e->type == KeyPress || e->type == KeyRelease)
422 ;
423 */
424
425 /* dispatch the event to registered handlers */
426 dispatch_x(e, client);
427 }
428
429 static void event_handle_root(XEvent *e)
430 {
431 Atom msgtype;
432
433 switch(e->type) {
434 case ClientMessage:
435 if (e->xclient.format != 32) break;
436
437 msgtype = e->xclient.message_type;
438 if (msgtype == prop_atoms.net_current_desktop) {
439 unsigned int d = e->xclient.data.l[0];
440 if (d < screen_num_desktops)
441 screen_set_desktop(d);
442 } else if (msgtype == prop_atoms.net_number_of_desktops) {
443 unsigned int d = e->xclient.data.l[0];
444 if (d > 0)
445 screen_set_num_desktops(d);
446 } else if (msgtype == prop_atoms.net_showing_desktop) {
447 screen_show_desktop(e->xclient.data.l[0] != 0);
448 }
449 break;
450 case PropertyNotify:
451 if (e->xproperty.atom == prop_atoms.net_desktop_names)
452 screen_update_desktop_names();
453 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
454 screen_update_layout();
455 break;
456 }
457 }
458
459 static void event_handle_client(Client *client, XEvent *e)
460 {
461 XEvent ce;
462 Atom msgtype;
463 int i=0;
464
465 switch (e->type) {
466 case ButtonPress:
467 case ButtonRelease:
468 switch (frame_context(client, e->xbutton.window)) {
469 case Context_Maximize:
470 client->frame->max_press = (e->type == ButtonPress);
471 framerender_frame(client->frame);
472 break;
473 case Context_Close:
474 client->frame->close_press = (e->type == ButtonPress);
475 framerender_frame(client->frame);
476 break;
477 case Context_Iconify:
478 client->frame->iconify_press = (e->type == ButtonPress);
479 framerender_frame(client->frame);
480 break;
481 case Context_AllDesktops:
482 client->frame->desk_press = (e->type == ButtonPress);
483 framerender_frame(client->frame);
484 break;
485 case Context_Shade:
486 client->frame->shade_press = (e->type == ButtonPress);
487 framerender_frame(client->frame);
488 break;
489 default:
490 /* nothing changes with clicks for any other contexts */
491 break;
492 }
493 break;
494 case FocusIn:
495 focus_set_client(client);
496 case FocusOut:
497 #ifdef DEBUG_FOCUS
498 g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
499 client->window);
500 #endif
501 /* focus state can affect the stacking layer */
502 client_calc_layer(client);
503 frame_adjust_focus(client->frame);
504 break;
505 case EnterNotify:
506 if (client_normal(client)) {
507 if (ob_state == State_Starting) {
508 /* move it to the top of the focus order */
509 guint desktop = client->desktop;
510 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
511 focus_order[desktop] = g_list_remove(focus_order[desktop],
512 client);
513 focus_order[desktop] = g_list_prepend(focus_order[desktop],
514 client);
515 } else if (config_focus_follow) {
516 #ifdef DEBUG_FOCUS
517 g_message("EnterNotify on %lx, focusing window",
518 client->window);
519 #endif
520 client_focus(client);
521 }
522 }
523 break;
524 case ConfigureRequest:
525 /* compress these */
526 while (XCheckTypedWindowEvent(ob_display, client->window,
527 ConfigureRequest, &ce)) {
528 ++i;
529 /* XXX if this causes bad things.. we can compress config req's
530 with the same mask. */
531 e->xconfigurerequest.value_mask |=
532 ce.xconfigurerequest.value_mask;
533 if (ce.xconfigurerequest.value_mask & CWX)
534 e->xconfigurerequest.x = ce.xconfigurerequest.x;
535 if (ce.xconfigurerequest.value_mask & CWY)
536 e->xconfigurerequest.y = ce.xconfigurerequest.y;
537 if (ce.xconfigurerequest.value_mask & CWWidth)
538 e->xconfigurerequest.width = ce.xconfigurerequest.width;
539 if (ce.xconfigurerequest.value_mask & CWHeight)
540 e->xconfigurerequest.height = ce.xconfigurerequest.height;
541 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
542 e->xconfigurerequest.border_width =
543 ce.xconfigurerequest.border_width;
544 if (ce.xconfigurerequest.value_mask & CWStackMode)
545 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
546 }
547
548 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
549 if (client->iconic || client->shaded) return;
550
551 if (e->xconfigurerequest.value_mask & CWBorderWidth)
552 client->border_width = e->xconfigurerequest.border_width;
553
554 /* resize, then move, as specified in the EWMH section 7.7 */
555 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
556 CWX | CWY)) {
557 int x, y, w, h;
558 Corner corner;
559
560 x = (e->xconfigurerequest.value_mask & CWX) ?
561 e->xconfigurerequest.x : client->area.x;
562 y = (e->xconfigurerequest.value_mask & CWY) ?
563 e->xconfigurerequest.y : client->area.y;
564 w = (e->xconfigurerequest.value_mask & CWWidth) ?
565 e->xconfigurerequest.width : client->area.width;
566 h = (e->xconfigurerequest.value_mask & CWHeight) ?
567 e->xconfigurerequest.height : client->area.height;
568
569 switch (client->gravity) {
570 case NorthEastGravity:
571 case EastGravity:
572 corner = Corner_TopRight;
573 break;
574 case SouthWestGravity:
575 case SouthGravity:
576 corner = Corner_BottomLeft;
577 break;
578 case SouthEastGravity:
579 corner = Corner_BottomRight;
580 break;
581 default: /* NorthWest, Static, etc */
582 corner = Corner_TopLeft;
583 }
584
585 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
586 }
587
588 if (e->xconfigurerequest.value_mask & CWStackMode) {
589 switch (e->xconfigurerequest.detail) {
590 case Below:
591 case BottomIf:
592 stacking_lower(client);
593 break;
594
595 case Above:
596 case TopIf:
597 default:
598 stacking_raise(client);
599 break;
600 }
601 }
602 break;
603 case UnmapNotify:
604 if (client->ignore_unmaps) {
605 client->ignore_unmaps--;
606 break;
607 }
608 client_unmanage(client);
609 break;
610 case DestroyNotify:
611 client_unmanage(client);
612 break;
613 case ReparentNotify:
614 /* this is when the client is first taken captive in the frame */
615 if (e->xreparent.parent == client->frame->plate) break;
616
617 /*
618 This event is quite rare and is usually handled in unmapHandler.
619 However, if the window is unmapped when the reparent event occurs,
620 the window manager never sees it because an unmap event is not sent
621 to an already unmapped window.
622 */
623
624 /* we don't want the reparent event, put it back on the stack for the
625 X server to deal with after we unmanage the window */
626 XPutBackEvent(ob_display, e);
627
628 client_unmanage(client);
629 break;
630 case MapRequest:
631 g_message("MapRequest for 0x%lx", client->window);
632 if (!client->iconic) break; /* this normally doesn't happen, but if it
633 does, we don't want it! */
634 if (screen_showing_desktop)
635 screen_show_desktop(FALSE);
636 client_iconify(client, FALSE, TRUE);
637 if (!client->frame->visible)
638 /* if its not visible still, then don't mess with it */
639 break;
640 if (client->shaded)
641 client_shade(client, FALSE);
642 client_focus(client);
643 stacking_raise(client);
644 break;
645 case ClientMessage:
646 /* validate cuz we query stuff off the client here */
647 if (!client_validate(client)) break;
648
649 if (e->xclient.format != 32) return;
650
651 msgtype = e->xclient.message_type;
652 if (msgtype == prop_atoms.wm_change_state) {
653 /* compress changes into a single change */
654 while (XCheckTypedWindowEvent(ob_display, e->type,
655 client->window, &ce)) {
656 /* XXX: it would be nice to compress ALL messages of a
657 type, not just messages in a row without other
658 message types between. */
659 if (ce.xclient.message_type != msgtype) {
660 XPutBackEvent(ob_display, &ce);
661 break;
662 }
663 e->xclient = ce.xclient;
664 }
665 client_set_wm_state(client, e->xclient.data.l[0]);
666 } else if (msgtype == prop_atoms.net_wm_desktop) {
667 /* compress changes into a single change */
668 while (XCheckTypedWindowEvent(ob_display, e->type,
669 client->window, &ce)) {
670 /* XXX: it would be nice to compress ALL messages of a
671 type, not just messages in a row without other
672 message types between. */
673 if (ce.xclient.message_type != msgtype) {
674 XPutBackEvent(ob_display, &ce);
675 break;
676 }
677 e->xclient = ce.xclient;
678 }
679 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
680 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
681 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
682 FALSE);
683 } else if (msgtype == prop_atoms.net_wm_state) {
684 /* can't compress these */
685 g_message("net_wm_state %s %ld %ld for 0x%lx",
686 (e->xclient.data.l[0] == 0 ? "Remove" :
687 e->xclient.data.l[0] == 1 ? "Add" :
688 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
689 e->xclient.data.l[1], e->xclient.data.l[2],
690 client->window);
691 client_set_state(client, e->xclient.data.l[0],
692 e->xclient.data.l[1], e->xclient.data.l[2]);
693 } else if (msgtype == prop_atoms.net_close_window) {
694 g_message("net_close_window for 0x%lx", client->window);
695 client_close(client);
696 } else if (msgtype == prop_atoms.net_active_window) {
697 g_message("net_active_window for 0x%lx", client->window);
698 if (screen_showing_desktop)
699 screen_show_desktop(FALSE);
700 if (client->iconic)
701 client_iconify(client, FALSE, TRUE);
702 else if (!client->frame->visible)
703 /* if its not visible for other reasons, then don't mess
704 with it */
705 break;
706 if (client->shaded)
707 client_shade(client, FALSE);
708 client_focus(client);
709 stacking_raise(client);
710 } else if (msgtype == prop_atoms.net_wm_moveresize) {
711 g_message("net_wm_moveresize for 0x%lx", client->window);
712 if ((Atom)e->xclient.data.l[2] ==
713 prop_atoms.net_wm_moveresize_size_topleft ||
714 (Atom)e->xclient.data.l[2] ==
715 prop_atoms.net_wm_moveresize_size_top ||
716 (Atom)e->xclient.data.l[2] ==
717 prop_atoms.net_wm_moveresize_size_topright ||
718 (Atom)e->xclient.data.l[2] ==
719 prop_atoms.net_wm_moveresize_size_right ||
720 (Atom)e->xclient.data.l[2] ==
721 prop_atoms.net_wm_moveresize_size_right ||
722 (Atom)e->xclient.data.l[2] ==
723 prop_atoms.net_wm_moveresize_size_bottomright ||
724 (Atom)e->xclient.data.l[2] ==
725 prop_atoms.net_wm_moveresize_size_bottom ||
726 (Atom)e->xclient.data.l[2] ==
727 prop_atoms.net_wm_moveresize_size_bottomleft ||
728 (Atom)e->xclient.data.l[2] ==
729 prop_atoms.net_wm_moveresize_size_left ||
730 (Atom)e->xclient.data.l[2] ==
731 prop_atoms.net_wm_moveresize_move ||
732 (Atom)e->xclient.data.l[2] ==
733 prop_atoms.net_wm_moveresize_size_keyboard ||
734 (Atom)e->xclient.data.l[2] ==
735 prop_atoms.net_wm_moveresize_move_keyboard) {
736
737 moveresize_start(client, e->xclient.data.l[0],
738 e->xclient.data.l[1], e->xclient.data.l[3],
739 e->xclient.data.l[2]);
740 }
741 } else if (msgtype == prop_atoms.net_moveresize_window) {
742 int oldg = client->gravity;
743 int tmpg, x, y, w, h;
744
745 if (e->xclient.data.l[0] & 0xff)
746 tmpg = e->xclient.data.l[0] & 0xff;
747 else
748 tmpg = oldg;
749
750 if (e->xclient.data.l[0] & 1 << 8)
751 x = e->xclient.data.l[1];
752 else
753 x = client->area.x;
754 if (e->xclient.data.l[0] & 1 << 9)
755 y = e->xclient.data.l[2];
756 else
757 y = client->area.y;
758 if (e->xclient.data.l[0] & 1 << 10)
759 w = e->xclient.data.l[3];
760 else
761 w = client->area.y;
762 if (e->xclient.data.l[0] & 1 << 11)
763 h = e->xclient.data.l[4];
764 else
765 h = client->area.y;
766 client->gravity = tmpg;
767 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
768 client->gravity = oldg;
769 }
770 break;
771 case PropertyNotify:
772 /* validate cuz we query stuff off the client here */
773 if (!client_validate(client)) break;
774
775 /* compress changes to a single property into a single change */
776 while (XCheckTypedWindowEvent(ob_display, e->type,
777 client->window, &ce)) {
778 /* XXX: it would be nice to compress ALL changes to a property,
779 not just changes in a row without other props between. */
780 if (ce.xproperty.atom != e->xproperty.atom) {
781 XPutBackEvent(ob_display, &ce);
782 break;
783 }
784 }
785
786 msgtype = e->xproperty.atom;
787 if (msgtype == XA_WM_NORMAL_HINTS) {
788 client_update_normal_hints(client);
789 /* normal hints can make a window non-resizable */
790 client_setup_decor_and_functions(client);
791 }
792 else if (msgtype == XA_WM_HINTS)
793 client_update_wmhints(client);
794 else if (msgtype == XA_WM_TRANSIENT_FOR) {
795 client_update_transient_for(client);
796 client_get_type(client);
797 /* type may have changed, so update the layer */
798 client_calc_layer(client);
799 client_setup_decor_and_functions(client);
800 }
801 else if (msgtype == prop_atoms.net_wm_name ||
802 msgtype == prop_atoms.wm_name)
803 client_update_title(client);
804 else if (msgtype == prop_atoms.net_wm_icon_name ||
805 msgtype == prop_atoms.wm_icon_name)
806 client_update_icon_title(client);
807 else if (msgtype == prop_atoms.wm_class)
808 client_update_class(client);
809 else if (msgtype == prop_atoms.wm_protocols) {
810 client_update_protocols(client);
811 client_setup_decor_and_functions(client);
812 }
813 else if (msgtype == prop_atoms.net_wm_strut)
814 client_update_strut(client);
815 else if (msgtype == prop_atoms.net_wm_icon)
816 client_update_icons(client);
817 else if (msgtype == prop_atoms.kwm_win_icon)
818 client_update_kwm_icon(client);
819 default:
820 ;
821 #ifdef SHAPE
822 if (extensions_shape && e->type == extensions_shape_event_basep) {
823 client->shaped = ((XShapeEvent*)e)->shaped;
824 frame_adjust_shape(client->frame);
825 }
826 #endif
827 }
828 }
829
830 static void event_handle_menu(Menu *menu, XEvent *e)
831 {
832 MenuEntry *entry;
833
834 g_message("EVENT %d", e->type);
835 switch (e->type) {
836 case ButtonPress:
837 if (e->xbutton.button == 3)
838 menu_hide(menu);
839 break;
840 case ButtonRelease:
841 if (!menu->shown) break;
842
843 /* grab_pointer_window(FALSE, None, menu->frame);*/
844
845 entry = menu_find_entry(menu, e->xbutton.window);
846 if (entry) {
847 int junk;
848 Window wjunk;
849 guint ujunk, b, w, h;
850 XGetGeometry(ob_display, e->xbutton.window,
851 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
852 if (e->xbutton.x >= (signed)-b &&
853 e->xbutton.y >= (signed)-b &&
854 e->xbutton.x < (signed)(w+b) &&
855 e->xbutton.y < (signed)(h+b)) {
856 menu_entry_fire(entry);
857 }
858 }
859 break;
860 case EnterNotify:
861 case LeaveNotify:
862 g_message("enter/leave");
863 entry = menu_find_entry(menu, e->xcrossing.window);
864 if (entry) {
865 entry->hilite = e->type == EnterNotify;
866 menu_entry_render(entry);
867 }
868 break;
869 }
870 }
This page took 0.070486 seconds and 5 git commands to generate.