]> Dogcows Code - chaz/openbox/blob - openbox/event.c
dont refocus the focused window, that just causes so many problems (with alt-tab :)
[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 if (client != focus_client) {
585 focus_set_client(client);
586 frame_adjust_focus(client->frame, TRUE);
587 }
588 break;
589 case FocusOut:
590 #ifdef DEBUG_FOCUS
591 g_message("FocusOut on client for %lx", client->window);
592 #endif
593 /* are we a fullscreen window or a transient of one? (checks layer)
594 if we are then we need to be iconified since we are losing focus
595 */
596 if (client->layer == Layer_Fullscreen && !client->iconic &&
597 !client_search_focus_tree_full(client))
598 /* iconify fullscreen windows when they and their transients
599 aren't focused */
600 client_iconify(client, TRUE, TRUE);
601 frame_adjust_focus(client->frame, FALSE);
602 break;
603 case EnterNotify:
604 if (client_normal(client)) {
605 if (ob_state == State_Starting) {
606 /* move it to the top of the focus order */
607 guint desktop = client->desktop;
608 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
609 focus_order[desktop] = g_list_remove(focus_order[desktop],
610 client);
611 focus_order[desktop] = g_list_prepend(focus_order[desktop],
612 client);
613 } else if (config_focus_follow) {
614 #ifdef DEBUG_FOCUS
615 g_message("EnterNotify on %lx, focusing window",
616 client->window);
617 #endif
618 client_focus(client);
619 }
620 }
621 break;
622 case ConfigureRequest:
623 /* compress these */
624 while (XCheckTypedWindowEvent(ob_display, client->window,
625 ConfigureRequest, &ce)) {
626 ++i;
627 /* XXX if this causes bad things.. we can compress config req's
628 with the same mask. */
629 e->xconfigurerequest.value_mask |=
630 ce.xconfigurerequest.value_mask;
631 if (ce.xconfigurerequest.value_mask & CWX)
632 e->xconfigurerequest.x = ce.xconfigurerequest.x;
633 if (ce.xconfigurerequest.value_mask & CWY)
634 e->xconfigurerequest.y = ce.xconfigurerequest.y;
635 if (ce.xconfigurerequest.value_mask & CWWidth)
636 e->xconfigurerequest.width = ce.xconfigurerequest.width;
637 if (ce.xconfigurerequest.value_mask & CWHeight)
638 e->xconfigurerequest.height = ce.xconfigurerequest.height;
639 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
640 e->xconfigurerequest.border_width =
641 ce.xconfigurerequest.border_width;
642 if (ce.xconfigurerequest.value_mask & CWStackMode)
643 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
644 }
645
646 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
647 if (client->iconic || client->shaded) return;
648
649 if (e->xconfigurerequest.value_mask & CWBorderWidth)
650 client->border_width = e->xconfigurerequest.border_width;
651
652 /* resize, then move, as specified in the EWMH section 7.7 */
653 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
654 CWX | CWY)) {
655 int x, y, w, h;
656 Corner corner;
657
658 x = (e->xconfigurerequest.value_mask & CWX) ?
659 e->xconfigurerequest.x : client->area.x;
660 y = (e->xconfigurerequest.value_mask & CWY) ?
661 e->xconfigurerequest.y : client->area.y;
662 w = (e->xconfigurerequest.value_mask & CWWidth) ?
663 e->xconfigurerequest.width : client->area.width;
664 h = (e->xconfigurerequest.value_mask & CWHeight) ?
665 e->xconfigurerequest.height : client->area.height;
666
667 switch (client->gravity) {
668 case NorthEastGravity:
669 case EastGravity:
670 corner = Corner_TopRight;
671 break;
672 case SouthWestGravity:
673 case SouthGravity:
674 corner = Corner_BottomLeft;
675 break;
676 case SouthEastGravity:
677 corner = Corner_BottomRight;
678 break;
679 default: /* NorthWest, Static, etc */
680 corner = Corner_TopLeft;
681 }
682
683 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
684 }
685
686 if (e->xconfigurerequest.value_mask & CWStackMode) {
687 switch (e->xconfigurerequest.detail) {
688 case Below:
689 case BottomIf:
690 stacking_lower(CLIENT_AS_WINDOW(client));
691 break;
692
693 case Above:
694 case TopIf:
695 default:
696 stacking_raise(CLIENT_AS_WINDOW(client));
697 break;
698 }
699 }
700 break;
701 case UnmapNotify:
702 if (client->ignore_unmaps) {
703 client->ignore_unmaps--;
704 break;
705 }
706 client_unmanage(client);
707 break;
708 case DestroyNotify:
709 client_unmanage(client);
710 break;
711 case ReparentNotify:
712 /* this is when the client is first taken captive in the frame */
713 if (e->xreparent.parent == client->frame->plate) break;
714
715 /*
716 This event is quite rare and is usually handled in unmapHandler.
717 However, if the window is unmapped when the reparent event occurs,
718 the window manager never sees it because an unmap event is not sent
719 to an already unmapped window.
720 */
721
722 /* we don't want the reparent event, put it back on the stack for the
723 X server to deal with after we unmanage the window */
724 XPutBackEvent(ob_display, e);
725
726 client_unmanage(client);
727 break;
728 case MapRequest:
729 g_message("MapRequest for 0x%lx", client->window);
730 if (!client->iconic) break; /* this normally doesn't happen, but if it
731 does, we don't want it! */
732 if (screen_showing_desktop)
733 screen_show_desktop(FALSE);
734 client_iconify(client, FALSE, TRUE);
735 if (!client->frame->visible)
736 /* if its not visible still, then don't mess with it */
737 break;
738 if (client->shaded)
739 client_shade(client, FALSE);
740 client_focus(client);
741 stacking_raise(CLIENT_AS_WINDOW(client));
742 break;
743 case ClientMessage:
744 /* validate cuz we query stuff off the client here */
745 if (!client_validate(client)) break;
746
747 if (e->xclient.format != 32) return;
748
749 msgtype = e->xclient.message_type;
750 if (msgtype == prop_atoms.wm_change_state) {
751 /* compress changes into a single change */
752 while (XCheckTypedWindowEvent(ob_display, e->type,
753 client->window, &ce)) {
754 /* XXX: it would be nice to compress ALL messages of a
755 type, not just messages in a row without other
756 message types between. */
757 if (ce.xclient.message_type != msgtype) {
758 XPutBackEvent(ob_display, &ce);
759 break;
760 }
761 e->xclient = ce.xclient;
762 }
763 client_set_wm_state(client, e->xclient.data.l[0]);
764 } else if (msgtype == prop_atoms.net_wm_desktop) {
765 /* compress changes into a single change */
766 while (XCheckTypedWindowEvent(ob_display, e->type,
767 client->window, &ce)) {
768 /* XXX: it would be nice to compress ALL messages of a
769 type, not just messages in a row without other
770 message types between. */
771 if (ce.xclient.message_type != msgtype) {
772 XPutBackEvent(ob_display, &ce);
773 break;
774 }
775 e->xclient = ce.xclient;
776 }
777 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
778 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
779 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
780 FALSE);
781 } else if (msgtype == prop_atoms.net_wm_state) {
782 /* can't compress these */
783 g_message("net_wm_state %s %ld %ld for 0x%lx",
784 (e->xclient.data.l[0] == 0 ? "Remove" :
785 e->xclient.data.l[0] == 1 ? "Add" :
786 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
787 e->xclient.data.l[1], e->xclient.data.l[2],
788 client->window);
789 client_set_state(client, e->xclient.data.l[0],
790 e->xclient.data.l[1], e->xclient.data.l[2]);
791 } else if (msgtype == prop_atoms.net_close_window) {
792 g_message("net_close_window for 0x%lx", client->window);
793 client_close(client);
794 } else if (msgtype == prop_atoms.net_active_window) {
795 g_message("net_active_window for 0x%lx", client->window);
796 client_activate(client);
797 } else if (msgtype == prop_atoms.net_wm_moveresize) {
798 g_message("net_wm_moveresize for 0x%lx", client->window);
799 if ((Atom)e->xclient.data.l[2] ==
800 prop_atoms.net_wm_moveresize_size_topleft ||
801 (Atom)e->xclient.data.l[2] ==
802 prop_atoms.net_wm_moveresize_size_top ||
803 (Atom)e->xclient.data.l[2] ==
804 prop_atoms.net_wm_moveresize_size_topright ||
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_right ||
809 (Atom)e->xclient.data.l[2] ==
810 prop_atoms.net_wm_moveresize_size_bottomright ||
811 (Atom)e->xclient.data.l[2] ==
812 prop_atoms.net_wm_moveresize_size_bottom ||
813 (Atom)e->xclient.data.l[2] ==
814 prop_atoms.net_wm_moveresize_size_bottomleft ||
815 (Atom)e->xclient.data.l[2] ==
816 prop_atoms.net_wm_moveresize_size_left ||
817 (Atom)e->xclient.data.l[2] ==
818 prop_atoms.net_wm_moveresize_move ||
819 (Atom)e->xclient.data.l[2] ==
820 prop_atoms.net_wm_moveresize_size_keyboard ||
821 (Atom)e->xclient.data.l[2] ==
822 prop_atoms.net_wm_moveresize_move_keyboard) {
823
824 moveresize_start(client, e->xclient.data.l[0],
825 e->xclient.data.l[1], e->xclient.data.l[3],
826 e->xclient.data.l[2]);
827 }
828 } else if (msgtype == prop_atoms.net_moveresize_window) {
829 int oldg = client->gravity;
830 int tmpg, x, y, w, h;
831
832 if (e->xclient.data.l[0] & 0xff)
833 tmpg = e->xclient.data.l[0] & 0xff;
834 else
835 tmpg = oldg;
836
837 if (e->xclient.data.l[0] & 1 << 8)
838 x = e->xclient.data.l[1];
839 else
840 x = client->area.x;
841 if (e->xclient.data.l[0] & 1 << 9)
842 y = e->xclient.data.l[2];
843 else
844 y = client->area.y;
845 if (e->xclient.data.l[0] & 1 << 10)
846 w = e->xclient.data.l[3];
847 else
848 w = client->area.y;
849 if (e->xclient.data.l[0] & 1 << 11)
850 h = e->xclient.data.l[4];
851 else
852 h = client->area.y;
853 client->gravity = tmpg;
854 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
855 client->gravity = oldg;
856 }
857 break;
858 case PropertyNotify:
859 /* validate cuz we query stuff off the client here */
860 if (!client_validate(client)) break;
861
862 /* compress changes to a single property into a single change */
863 while (XCheckTypedWindowEvent(ob_display, e->type,
864 client->window, &ce)) {
865 /* XXX: it would be nice to compress ALL changes to a property,
866 not just changes in a row without other props between. */
867 if (ce.xproperty.atom != e->xproperty.atom) {
868 XPutBackEvent(ob_display, &ce);
869 break;
870 }
871 }
872
873 msgtype = e->xproperty.atom;
874 if (msgtype == XA_WM_NORMAL_HINTS) {
875 client_update_normal_hints(client);
876 /* normal hints can make a window non-resizable */
877 client_setup_decor_and_functions(client);
878 }
879 else if (msgtype == XA_WM_HINTS)
880 client_update_wmhints(client);
881 else if (msgtype == XA_WM_TRANSIENT_FOR) {
882 client_update_transient_for(client);
883 client_get_type(client);
884 /* type may have changed, so update the layer */
885 client_calc_layer(client);
886 client_setup_decor_and_functions(client);
887 }
888 else if (msgtype == prop_atoms.net_wm_name ||
889 msgtype == prop_atoms.wm_name ||
890 msgtype == prop_atoms.net_wm_icon_name ||
891 msgtype == prop_atoms.wm_icon_name)
892 client_update_title(client);
893 else if (msgtype == prop_atoms.wm_class)
894 client_update_class(client);
895 else if (msgtype == prop_atoms.wm_protocols) {
896 client_update_protocols(client);
897 client_setup_decor_and_functions(client);
898 }
899 else if (msgtype == prop_atoms.net_wm_strut)
900 client_update_strut(client);
901 else if (msgtype == prop_atoms.net_wm_icon ||
902 msgtype == prop_atoms.kwm_win_icon)
903 client_update_icons(client);
904 default:
905 ;
906 #ifdef SHAPE
907 if (extensions_shape && e->type == extensions_shape_event_basep) {
908 client->shaped = ((XShapeEvent*)e)->shaped;
909 frame_adjust_shape(client->frame);
910 }
911 #endif
912 }
913 }
914
915 static void event_handle_menu(Menu *menu, Client *client, XEvent *e)
916 {
917 MenuEntry *entry;
918
919 g_message("EVENT %d", e->type);
920 switch (e->type) {
921 case ButtonPress:
922 g_message("BUTTON PRESS");
923 if (e->xbutton.button == 3)
924 menu_hide(menu);
925 else if (e->xbutton.button == 1) {
926 entry = menu_find_entry(menu, e->xbutton.window);
927 if (!entry)
928 stacking_raise(MENU_AS_WINDOW(menu));
929 }
930 break;
931 case ButtonRelease:
932 g_message("BUTTON RELEASED");
933 if (!menu->shown) break;
934
935 /* grab_pointer_window(FALSE, None, menu->frame);*/
936
937 if (e->xbutton.button == 1) {
938 entry = menu_find_entry(menu, e->xbutton.window);
939 if (entry) {
940 int junk;
941 Window wjunk;
942 guint ujunk, b, w, h;
943 XGetGeometry(ob_display, e->xbutton.window,
944 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
945 if (e->xbutton.x >= (signed)-b &&
946 e->xbutton.y >= (signed)-b &&
947 e->xbutton.x < (signed)(w+b) &&
948 e->xbutton.y < (signed)(h+b)) {
949 menu_entry_fire(entry);
950 }
951 }
952 }
953
954 break;
955 case EnterNotify:
956 case LeaveNotify:
957 g_message("enter/leave");
958 entry = menu_find_entry(menu, e->xcrossing.window);
959 if (entry) {
960 if (menu->mouseover)
961 menu->mouseover(entry, e->type == EnterNotify);
962 else
963 menu_control_mouseover(entry, e->type == EnterNotify);
964
965 menu_entry_render(entry);
966 }
967 break;
968 }
969 }
970
971 void event_add_fd_handler(event_fd_handler *h) {
972 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
973 FD_SET(h->fd, &allset);
974 max_fd = MAX(max_fd, h->fd);
975 }
976
977 void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
978 {
979 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
980 }
981
982 void event_remove_fd(int n)
983 {
984 int tmpmax = 0;
985 FD_CLR(n, &allset);
986 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
987 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach, (gpointer)&tmpmax);
988 max_fd = MAX(x_fd, tmpmax);
989 }
990
991 void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
992 {
993 if (FD_ISSET( (int)n, &selset)) {
994 event_fd_handler *h = (event_fd_handler *)data;
995 g_assert(h->fd == (int)n);
996 h->handler(h->fd, h->data);
997 }
998 }
999
1000 void fd_event_handle()
1001 {
1002 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
1003 }
1004
1005 static void event_handle_dock(Dock *s, XEvent *e)
1006 {
1007 switch (e->type) {
1008 case ButtonPress:
1009 stacking_raise(DOCK_AS_WINDOW(s));
1010 break;
1011 case EnterNotify:
1012 dock_hide(FALSE);
1013 break;
1014 case LeaveNotify:
1015 dock_hide(TRUE);
1016 break;
1017 }
1018 }
1019
1020 static void event_handle_dockapp(DockApp *app, XEvent *e)
1021 {
1022 switch (e->type) {
1023 case MotionNotify:
1024 dock_app_drag(app, &e->xmotion);
1025 break;
1026 case UnmapNotify:
1027 if (app->ignore_unmaps) {
1028 app->ignore_unmaps--;
1029 break;
1030 }
1031 dock_remove(app, TRUE);
1032 break;
1033 case DestroyNotify:
1034 dock_remove(app, FALSE);
1035 break;
1036 case ReparentNotify:
1037 dock_remove(app, FALSE);
1038 break;
1039 case ConfigureNotify:
1040 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
1041 break;
1042 }
1043 }
This page took 0.085536 seconds and 5 git commands to generate.