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