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