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