]> Dogcows Code - chaz/openbox/blob - openbox/event.c
02ead5b2615d9137e037f71f9d949af09deb47fe
[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 case ConfigureNotify:
148 window = e->xconfigure.window;
149 break;
150 default:
151 #ifdef XKB
152 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
153 switch (((XkbAnyEvent*)&e)->xkb_type) {
154 case XkbBellNotify:
155 window = ((XkbBellNotifyEvent*)&e)->window;
156 default:
157 window = None;
158 }
159 } else
160 #endif
161 window = e->xany.window;
162 }
163 return window;
164 }
165
166 static void event_set_lasttime(XEvent *e)
167 {
168 /* grab the lasttime and hack up the state */
169 switch (e->type) {
170 case ButtonPress:
171 case ButtonRelease:
172 event_lasttime = e->xbutton.time;
173 break;
174 case KeyPress:
175 event_lasttime = e->xkey.time;
176 break;
177 case KeyRelease:
178 event_lasttime = e->xkey.time;
179 break;
180 case MotionNotify:
181 event_lasttime = e->xmotion.time;
182 break;
183 case PropertyNotify:
184 event_lasttime = e->xproperty.time;
185 break;
186 case EnterNotify:
187 case LeaveNotify:
188 event_lasttime = e->xcrossing.time;
189 break;
190 default:
191 event_lasttime = CurrentTime;
192 break;
193 }
194 }
195
196 #define STRIP_MODS(s) \
197 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
198 /* kill off the Button1Mask etc, only want the modifiers */ \
199 s &= (ControlMask | ShiftMask | Mod1Mask | \
200 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
201
202 static void event_hack_mods(XEvent *e)
203 {
204 KeyCode *kp;
205 int i, k;
206
207 switch (e->type) {
208 case ButtonPress:
209 case ButtonRelease:
210 STRIP_MODS(e->xbutton.state);
211 break;
212 case KeyPress:
213 STRIP_MODS(e->xkey.state);
214 break;
215 case KeyRelease:
216 STRIP_MODS(e->xkey.state);
217 /* remove from the state the mask of the modifier being released, if
218 it is a modifier key being released (this is a little ugly..) */
219 kp = modmap->modifiermap;
220 for (i = 0; i < mask_table_size; ++i) {
221 for (k = 0; k < modmap->max_keypermod; ++k) {
222 if (*kp == e->xkey.keycode) { /* found the keycode */
223 /* remove the mask for it */
224 e->xkey.state &= ~mask_table[i];
225 /* cause the first loop to break; */
226 i = mask_table_size;
227 break; /* get outta here! */
228 }
229 ++kp;
230 }
231 }
232 break;
233 case MotionNotify:
234 STRIP_MODS(e->xmotion.state);
235 /* compress events */
236 {
237 XEvent ce;
238 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
239 e->type, &ce)) {
240 e->xmotion.x_root = ce.xmotion.x_root;
241 e->xmotion.y_root = ce.xmotion.y_root;
242 }
243 }
244 break;
245 }
246 }
247
248 static gboolean event_ignore(XEvent *e, Client *client)
249 {
250 switch(e->type) {
251 case FocusIn:
252 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
253 because of RevertToPointerRoot. If the focus ends up reverting to
254 pointer root on a workspace change, then the FocusIn event that we
255 want will be of type NotifyAncestor. This situation does not occur
256 for FocusOut, so it is safely ignored there.
257 */
258 if (INVALID_FOCUSIN(e) ||
259 client == NULL) {
260 #ifdef DEBUG_FOCUS
261 g_message("FocusIn on %lx mode %d detail %d IGNORED", e->xfocus.window,
262 e->xfocus.mode, e->xfocus.detail);
263 #endif
264 /* says a client was not found for the event (or a valid FocusIn
265 event was not found.
266 */
267 e->xfocus.window = None;
268 return TRUE;
269 }
270
271 #ifdef DEBUG_FOCUS
272 g_message("FocusIn on %lx mode %d detail %d", e->xfocus.window,
273 e->xfocus.mode, e->xfocus.detail);
274 #endif
275 break;
276 case FocusOut:
277 if (INVALID_FOCUSOUT(e)) {
278 #ifdef DEBUG_FOCUS
279 g_message("FocusOut on %lx mode %d detail %d IGNORED",
280 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
281 #endif
282 return TRUE;
283 }
284
285 #ifdef DEBUG_FOCUS
286 g_message("FocusOut on %lx mode %d detail %d",
287 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
288 #endif
289
290 {
291 XEvent fe;
292 gboolean fallback = TRUE;
293
294 while (TRUE) {
295 if (!XCheckTypedWindowEvent(ob_display, FocusOut,
296 e->xfocus.window,&fe))
297 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
298 break;
299 if (fe.type == FocusOut) {
300 #ifdef DEBUG_FOCUS
301 g_message("found pending FocusOut");
302 #endif
303 if (!INVALID_FOCUSOUT(&fe)) {
304 /* if there is a VALID FocusOut still coming, don't
305 fallback focus yet, we'll deal with it then */
306 XPutBackEvent(ob_display, &fe);
307 fallback = FALSE;
308 break;
309 }
310 } else {
311 #ifdef DEBUG_FOCUS
312 g_message("found pending FocusIn");
313 #endif
314 /* is the focused window getting a FocusOut/In back to
315 itself? */
316 if (fe.xfocus.window == e->xfocus.window &&
317 !event_ignore(&fe, client)) {
318 #ifdef DEBUG_FOCUS
319 g_message("focused window got an Out/In back to "
320 "itself IGNORED both");
321 #endif
322 return TRUE;
323 }
324
325 /* once all the FocusOut's have been dealt with, if there
326 is a FocusIn still left and it is valid, then use it */
327 event_process(&fe);
328 /* secret magic way of event_process telling us that no
329 client was found for the FocusIn event. ^_^ */
330 if (fe.xfocus.window != None) {
331 fallback = FALSE;
332 break;
333 }
334 }
335 }
336 if (fallback) {
337 #ifdef DEBUG_FOCUS
338 g_message("no valid FocusIn and no FocusOut events found, "
339 "falling back");
340 #endif
341 focus_fallback(Fallback_NoFocus);
342 }
343 }
344 break;
345 case EnterNotify:
346 case LeaveNotify:
347 /* NotifyUngrab occurs when a mouse button is released and the event is
348 caused, like when lowering a window */
349 /* NotifyVirtual occurs when ungrabbing the pointer */
350 if (e->xcrossing.mode == NotifyGrab ||
351 e->xcrossing.detail == NotifyInferior ||
352 (e->xcrossing.mode == NotifyUngrab &&
353 e->xcrossing.detail == NotifyVirtual)) {
354 #ifdef DEBUG_FOCUS
355 g_message("%sNotify mode %d detail %d on %lx IGNORED",
356 (e->type == EnterNotify ? "Enter" : "Leave"),
357 e->xcrossing.mode,
358 e->xcrossing.detail, client?client->window:0);
359 #endif
360 return TRUE;
361 }
362 #ifdef DEBUG_FOCUS
363 g_message("%sNotify mode %d detail %d on %lx",
364 (e->type == EnterNotify ? "Enter" : "Leave"),
365 e->xcrossing.mode,
366 e->xcrossing.detail, client?client->window:0);
367 #endif
368 break;
369 }
370 return FALSE;
371 }
372
373 static void event_process(XEvent *e)
374 {
375 Window window;
376 Client *client;
377 Menu *menu = NULL;
378
379 window = event_get_window(e);
380 if (!(client = g_hash_table_lookup(client_map, &window)))
381 menu = g_hash_table_lookup(menu_map, &window);
382
383 event_set_lasttime(e);
384 event_hack_mods(e);
385 if (event_ignore(e, client))
386 return;
387
388 /* deal with it in the kernel */
389 if (menu) {
390 event_handle_menu(menu, e);
391 return;
392 } else if (client)
393 event_handle_client(client, e);
394 else if (window == ob_root)
395 event_handle_root(e);
396 else if (e->type == MapRequest)
397 client_manage(window);
398 else if (e->type == ConfigureRequest) {
399 /* unhandled configure requests must be used to configure the
400 window directly */
401 XWindowChanges xwc;
402
403 xwc.x = e->xconfigurerequest.x;
404 xwc.y = e->xconfigurerequest.y;
405 xwc.width = e->xconfigurerequest.width;
406 xwc.height = e->xconfigurerequest.height;
407 xwc.border_width = e->xconfigurerequest.border_width;
408 xwc.sibling = e->xconfigurerequest.above;
409 xwc.stack_mode = e->xconfigurerequest.detail;
410
411 /* we are not to be held responsible if someone sends us an
412 invalid request! */
413 xerror_set_ignore(TRUE);
414 XConfigureWindow(ob_display, window,
415 e->xconfigurerequest.value_mask, &xwc);
416 xerror_set_ignore(FALSE);
417 }
418
419 if (moveresize_in_progress)
420 if (e->type == MotionNotify || e->type == ButtonRelease ||
421 e->type == ButtonPress ||
422 e->type == KeyPress || e->type == KeyRelease) {
423 moveresize_event(e);
424
425 return; /* no dispatch! */
426
427 }
428
429 /* user input (action-bound) events */
430 /*
431 if (e->type == ButtonPress || e->type == ButtonRelease ||
432 e->type == MotionNotify)
433 mouse_event(e, client);
434 else if (e->type == KeyPress || e->type == KeyRelease)
435 ;
436 */
437
438 /* dispatch the event to registered handlers */
439 dispatch_x(e, client);
440 }
441
442 static void event_handle_root(XEvent *e)
443 {
444 Atom msgtype;
445
446 switch(e->type) {
447 case ClientMessage:
448 if (e->xclient.format != 32) break;
449
450 msgtype = e->xclient.message_type;
451 if (msgtype == prop_atoms.net_current_desktop) {
452 unsigned int d = e->xclient.data.l[0];
453 if (d < screen_num_desktops)
454 screen_set_desktop(d);
455 } else if (msgtype == prop_atoms.net_number_of_desktops) {
456 unsigned int d = e->xclient.data.l[0];
457 if (d > 0)
458 screen_set_num_desktops(d);
459 } else if (msgtype == prop_atoms.net_showing_desktop) {
460 screen_show_desktop(e->xclient.data.l[0] != 0);
461 }
462 break;
463 case PropertyNotify:
464 if (e->xproperty.atom == prop_atoms.net_desktop_names)
465 screen_update_desktop_names();
466 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
467 screen_update_layout();
468 break;
469 case ConfigureNotify:
470 #ifdef XRANDR
471 XRRUpdateConfiguration(e);
472 #endif
473 if (e->xconfigure.width != screen_physical_size.width ||
474 e->xconfigure.height != screen_physical_size.height)
475 screen_resize(e->xconfigure.width, e->xconfigure.height);
476 break;
477 default:
478 ;
479 #ifdef VIDMODE
480 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
481 g_message("VIDMODE EVENT");
482 }
483 #endif
484 }
485 }
486
487 static void event_handle_client(Client *client, XEvent *e)
488 {
489 XEvent ce;
490 Atom msgtype;
491 int i=0;
492
493 switch (e->type) {
494 case ButtonPress:
495 case ButtonRelease:
496 switch (frame_context(client, e->xbutton.window)) {
497 case Context_Maximize:
498 client->frame->max_press = (e->type == ButtonPress);
499 framerender_frame(client->frame);
500 break;
501 case Context_Close:
502 client->frame->close_press = (e->type == ButtonPress);
503 framerender_frame(client->frame);
504 break;
505 case Context_Iconify:
506 client->frame->iconify_press = (e->type == ButtonPress);
507 framerender_frame(client->frame);
508 break;
509 case Context_AllDesktops:
510 client->frame->desk_press = (e->type == ButtonPress);
511 framerender_frame(client->frame);
512 break;
513 case Context_Shade:
514 client->frame->shade_press = (e->type == ButtonPress);
515 framerender_frame(client->frame);
516 break;
517 default:
518 /* nothing changes with clicks for any other contexts */
519 break;
520 }
521 break;
522 case FocusIn:
523 #ifdef DEBUG_FOCUS
524 g_message("FocusIn on client for %lx", client->window);
525 #endif
526 focus_set_client(client);
527 frame_adjust_focus(client->frame, TRUE);
528 break;
529 case FocusOut:
530 #ifdef DEBUG_FOCUS
531 g_message("FocusOut on client for %lx", client->window);
532 #endif
533 /* are we a fullscreen window or a transient of one? (checks layer)
534 if we are then we need to be iconified since we are losing focus
535 */
536 if (client->layer == Layer_Fullscreen && !client->iconic &&
537 !client_search_focus_tree_full(client))
538 /* iconify fullscreen windows when they and their transients
539 aren't focused */
540 client_iconify(client, TRUE, TRUE);
541 frame_adjust_focus(client->frame, FALSE);
542 break;
543 case EnterNotify:
544 if (client_normal(client)) {
545 if (ob_state == State_Starting) {
546 /* move it to the top of the focus order */
547 guint desktop = client->desktop;
548 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
549 focus_order[desktop] = g_list_remove(focus_order[desktop],
550 client);
551 focus_order[desktop] = g_list_prepend(focus_order[desktop],
552 client);
553 } else if (config_focus_follow) {
554 #ifdef DEBUG_FOCUS
555 g_message("EnterNotify on %lx, focusing window",
556 client->window);
557 #endif
558 client_focus(client);
559 }
560 }
561 break;
562 case ConfigureRequest:
563 /* compress these */
564 while (XCheckTypedWindowEvent(ob_display, client->window,
565 ConfigureRequest, &ce)) {
566 ++i;
567 /* XXX if this causes bad things.. we can compress config req's
568 with the same mask. */
569 e->xconfigurerequest.value_mask |=
570 ce.xconfigurerequest.value_mask;
571 if (ce.xconfigurerequest.value_mask & CWX)
572 e->xconfigurerequest.x = ce.xconfigurerequest.x;
573 if (ce.xconfigurerequest.value_mask & CWY)
574 e->xconfigurerequest.y = ce.xconfigurerequest.y;
575 if (ce.xconfigurerequest.value_mask & CWWidth)
576 e->xconfigurerequest.width = ce.xconfigurerequest.width;
577 if (ce.xconfigurerequest.value_mask & CWHeight)
578 e->xconfigurerequest.height = ce.xconfigurerequest.height;
579 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
580 e->xconfigurerequest.border_width =
581 ce.xconfigurerequest.border_width;
582 if (ce.xconfigurerequest.value_mask & CWStackMode)
583 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
584 }
585
586 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
587 if (client->iconic || client->shaded) return;
588
589 if (e->xconfigurerequest.value_mask & CWBorderWidth)
590 client->border_width = e->xconfigurerequest.border_width;
591
592 /* resize, then move, as specified in the EWMH section 7.7 */
593 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
594 CWX | CWY)) {
595 int x, y, w, h;
596 Corner corner;
597
598 x = (e->xconfigurerequest.value_mask & CWX) ?
599 e->xconfigurerequest.x : client->area.x;
600 y = (e->xconfigurerequest.value_mask & CWY) ?
601 e->xconfigurerequest.y : client->area.y;
602 w = (e->xconfigurerequest.value_mask & CWWidth) ?
603 e->xconfigurerequest.width : client->area.width;
604 h = (e->xconfigurerequest.value_mask & CWHeight) ?
605 e->xconfigurerequest.height : client->area.height;
606
607 switch (client->gravity) {
608 case NorthEastGravity:
609 case EastGravity:
610 corner = Corner_TopRight;
611 break;
612 case SouthWestGravity:
613 case SouthGravity:
614 corner = Corner_BottomLeft;
615 break;
616 case SouthEastGravity:
617 corner = Corner_BottomRight;
618 break;
619 default: /* NorthWest, Static, etc */
620 corner = Corner_TopLeft;
621 }
622
623 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
624 }
625
626 if (e->xconfigurerequest.value_mask & CWStackMode) {
627 switch (e->xconfigurerequest.detail) {
628 case Below:
629 case BottomIf:
630 stacking_lower(client);
631 break;
632
633 case Above:
634 case TopIf:
635 default:
636 stacking_raise(client);
637 break;
638 }
639 }
640 break;
641 case UnmapNotify:
642 if (client->ignore_unmaps) {
643 client->ignore_unmaps--;
644 break;
645 }
646 client_unmanage(client);
647 break;
648 case DestroyNotify:
649 client_unmanage(client);
650 break;
651 case ReparentNotify:
652 /* this is when the client is first taken captive in the frame */
653 if (e->xreparent.parent == client->frame->plate) break;
654
655 /*
656 This event is quite rare and is usually handled in unmapHandler.
657 However, if the window is unmapped when the reparent event occurs,
658 the window manager never sees it because an unmap event is not sent
659 to an already unmapped window.
660 */
661
662 /* we don't want the reparent event, put it back on the stack for the
663 X server to deal with after we unmanage the window */
664 XPutBackEvent(ob_display, e);
665
666 client_unmanage(client);
667 break;
668 case MapRequest:
669 g_message("MapRequest for 0x%lx", client->window);
670 if (!client->iconic) break; /* this normally doesn't happen, but if it
671 does, we don't want it! */
672 if (screen_showing_desktop)
673 screen_show_desktop(FALSE);
674 client_iconify(client, FALSE, TRUE);
675 if (!client->frame->visible)
676 /* if its not visible still, then don't mess with it */
677 break;
678 if (client->shaded)
679 client_shade(client, FALSE);
680 client_focus(client);
681 stacking_raise(client);
682 break;
683 case ClientMessage:
684 /* validate cuz we query stuff off the client here */
685 if (!client_validate(client)) break;
686
687 if (e->xclient.format != 32) return;
688
689 msgtype = e->xclient.message_type;
690 if (msgtype == prop_atoms.wm_change_state) {
691 /* compress changes into a single change */
692 while (XCheckTypedWindowEvent(ob_display, e->type,
693 client->window, &ce)) {
694 /* XXX: it would be nice to compress ALL messages of a
695 type, not just messages in a row without other
696 message types between. */
697 if (ce.xclient.message_type != msgtype) {
698 XPutBackEvent(ob_display, &ce);
699 break;
700 }
701 e->xclient = ce.xclient;
702 }
703 client_set_wm_state(client, e->xclient.data.l[0]);
704 } else if (msgtype == prop_atoms.net_wm_desktop) {
705 /* compress changes into a single change */
706 while (XCheckTypedWindowEvent(ob_display, e->type,
707 client->window, &ce)) {
708 /* XXX: it would be nice to compress ALL messages of a
709 type, not just messages in a row without other
710 message types between. */
711 if (ce.xclient.message_type != msgtype) {
712 XPutBackEvent(ob_display, &ce);
713 break;
714 }
715 e->xclient = ce.xclient;
716 }
717 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
718 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
719 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
720 FALSE);
721 } else if (msgtype == prop_atoms.net_wm_state) {
722 /* can't compress these */
723 g_message("net_wm_state %s %ld %ld for 0x%lx",
724 (e->xclient.data.l[0] == 0 ? "Remove" :
725 e->xclient.data.l[0] == 1 ? "Add" :
726 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
727 e->xclient.data.l[1], e->xclient.data.l[2],
728 client->window);
729 client_set_state(client, e->xclient.data.l[0],
730 e->xclient.data.l[1], e->xclient.data.l[2]);
731 } else if (msgtype == prop_atoms.net_close_window) {
732 g_message("net_close_window for 0x%lx", client->window);
733 client_close(client);
734 } else if (msgtype == prop_atoms.net_active_window) {
735 g_message("net_active_window for 0x%lx", client->window);
736 client_activate(client);
737 } else if (msgtype == prop_atoms.net_wm_moveresize) {
738 g_message("net_wm_moveresize for 0x%lx", client->window);
739 if ((Atom)e->xclient.data.l[2] ==
740 prop_atoms.net_wm_moveresize_size_topleft ||
741 (Atom)e->xclient.data.l[2] ==
742 prop_atoms.net_wm_moveresize_size_top ||
743 (Atom)e->xclient.data.l[2] ==
744 prop_atoms.net_wm_moveresize_size_topright ||
745 (Atom)e->xclient.data.l[2] ==
746 prop_atoms.net_wm_moveresize_size_right ||
747 (Atom)e->xclient.data.l[2] ==
748 prop_atoms.net_wm_moveresize_size_right ||
749 (Atom)e->xclient.data.l[2] ==
750 prop_atoms.net_wm_moveresize_size_bottomright ||
751 (Atom)e->xclient.data.l[2] ==
752 prop_atoms.net_wm_moveresize_size_bottom ||
753 (Atom)e->xclient.data.l[2] ==
754 prop_atoms.net_wm_moveresize_size_bottomleft ||
755 (Atom)e->xclient.data.l[2] ==
756 prop_atoms.net_wm_moveresize_size_left ||
757 (Atom)e->xclient.data.l[2] ==
758 prop_atoms.net_wm_moveresize_move ||
759 (Atom)e->xclient.data.l[2] ==
760 prop_atoms.net_wm_moveresize_size_keyboard ||
761 (Atom)e->xclient.data.l[2] ==
762 prop_atoms.net_wm_moveresize_move_keyboard) {
763
764 moveresize_start(client, e->xclient.data.l[0],
765 e->xclient.data.l[1], e->xclient.data.l[3],
766 e->xclient.data.l[2]);
767 }
768 } else if (msgtype == prop_atoms.net_moveresize_window) {
769 int oldg = client->gravity;
770 int tmpg, x, y, w, h;
771
772 if (e->xclient.data.l[0] & 0xff)
773 tmpg = e->xclient.data.l[0] & 0xff;
774 else
775 tmpg = oldg;
776
777 if (e->xclient.data.l[0] & 1 << 8)
778 x = e->xclient.data.l[1];
779 else
780 x = client->area.x;
781 if (e->xclient.data.l[0] & 1 << 9)
782 y = e->xclient.data.l[2];
783 else
784 y = client->area.y;
785 if (e->xclient.data.l[0] & 1 << 10)
786 w = e->xclient.data.l[3];
787 else
788 w = client->area.y;
789 if (e->xclient.data.l[0] & 1 << 11)
790 h = e->xclient.data.l[4];
791 else
792 h = client->area.y;
793 client->gravity = tmpg;
794 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
795 client->gravity = oldg;
796 }
797 break;
798 case PropertyNotify:
799 /* validate cuz we query stuff off the client here */
800 if (!client_validate(client)) break;
801
802 /* compress changes to a single property into a single change */
803 while (XCheckTypedWindowEvent(ob_display, e->type,
804 client->window, &ce)) {
805 /* XXX: it would be nice to compress ALL changes to a property,
806 not just changes in a row without other props between. */
807 if (ce.xproperty.atom != e->xproperty.atom) {
808 XPutBackEvent(ob_display, &ce);
809 break;
810 }
811 }
812
813 msgtype = e->xproperty.atom;
814 if (msgtype == XA_WM_NORMAL_HINTS) {
815 client_update_normal_hints(client);
816 /* normal hints can make a window non-resizable */
817 client_setup_decor_and_functions(client);
818 }
819 else if (msgtype == XA_WM_HINTS)
820 client_update_wmhints(client);
821 else if (msgtype == XA_WM_TRANSIENT_FOR) {
822 client_update_transient_for(client);
823 client_get_type(client);
824 /* type may have changed, so update the layer */
825 client_calc_layer(client);
826 client_setup_decor_and_functions(client);
827 }
828 else if (msgtype == prop_atoms.net_wm_name ||
829 msgtype == prop_atoms.wm_name ||
830 msgtype == prop_atoms.net_wm_icon_name ||
831 msgtype == prop_atoms.wm_icon_name)
832 client_update_title(client);
833 else if (msgtype == prop_atoms.wm_class)
834 client_update_class(client);
835 else if (msgtype == prop_atoms.wm_protocols) {
836 client_update_protocols(client);
837 client_setup_decor_and_functions(client);
838 }
839 else if (msgtype == prop_atoms.net_wm_strut)
840 client_update_strut(client);
841 else if (msgtype == prop_atoms.net_wm_icon)
842 client_update_icons(client);
843 else if (msgtype == prop_atoms.kwm_win_icon)
844 client_update_kwm_icon(client);
845 default:
846 ;
847 #ifdef SHAPE
848 if (extensions_shape && e->type == extensions_shape_event_basep) {
849 client->shaped = ((XShapeEvent*)e)->shaped;
850 frame_adjust_shape(client->frame);
851 }
852 #endif
853 }
854 }
855
856 static void event_handle_menu(Menu *menu, XEvent *e)
857 {
858 MenuEntry *entry;
859
860 g_message("EVENT %d", e->type);
861 switch (e->type) {
862 case ButtonPress:
863 g_message("BUTTON PRESS");
864 if (e->xbutton.button == 3)
865 menu_hide(menu);
866 break;
867 case ButtonRelease:
868 g_message("BUTTON RELEASED");
869 if (!menu->shown) break;
870
871 /* grab_pointer_window(FALSE, None, menu->frame);*/
872
873 entry = menu_find_entry(menu, e->xbutton.window);
874 if (entry) {
875 int junk;
876 Window wjunk;
877 guint ujunk, b, w, h;
878 XGetGeometry(ob_display, e->xbutton.window,
879 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
880 if (e->xbutton.x >= (signed)-b &&
881 e->xbutton.y >= (signed)-b &&
882 e->xbutton.x < (signed)(w+b) &&
883 e->xbutton.y < (signed)(h+b)) {
884 menu_entry_fire(entry);
885 }
886
887 break;
888 case EnterNotify:
889 case LeaveNotify:
890 g_message("enter/leave");
891 entry = menu_find_entry(menu, e->xcrossing.window);
892 if (entry) {
893 if (menu->mouseover)
894 menu->mouseover(entry, e->type == EnterNotify);
895 else
896 menu_control_mouseover(entry, e->type == EnterNotify);
897
898 menu_entry_render(entry);
899 }
900 break;
901 }
902 }
903 }
This page took 0.078445 seconds and 4 git commands to generate.