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