]> Dogcows Code - chaz/openbox/blob - openbox/event.c
ignore another type of crossing event, caused when leaving gtk popup menus
[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 default:
148 #ifdef XKB
149 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
150 switch (((XkbAnyEvent*)&e)->xkb_type) {
151 case XkbBellNotify:
152 window = ((XkbBellNotifyEvent*)&e)->window;
153 default:
154 window = None;
155 }
156 } else
157 #endif
158 window = e->xany.window;
159 }
160 return window;
161 }
162
163 static void event_set_lasttime(XEvent *e)
164 {
165 /* grab the lasttime and hack up the state */
166 switch (e->type) {
167 case ButtonPress:
168 case ButtonRelease:
169 event_lasttime = e->xbutton.time;
170 break;
171 case KeyPress:
172 event_lasttime = e->xkey.time;
173 break;
174 case KeyRelease:
175 event_lasttime = e->xkey.time;
176 break;
177 case MotionNotify:
178 event_lasttime = e->xmotion.time;
179 break;
180 case PropertyNotify:
181 event_lasttime = e->xproperty.time;
182 break;
183 case EnterNotify:
184 case LeaveNotify:
185 event_lasttime = e->xcrossing.time;
186 break;
187 default:
188 event_lasttime = CurrentTime;
189 break;
190 }
191 }
192
193 #define STRIP_MODS(s) \
194 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
195 /* kill off the Button1Mask etc, only want the modifiers */ \
196 s &= (ControlMask | ShiftMask | Mod1Mask | \
197 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
198
199 static void event_hack_mods(XEvent *e)
200 {
201 KeyCode *kp;
202 int i, k;
203
204 switch (e->type) {
205 case ButtonPress:
206 case ButtonRelease:
207 STRIP_MODS(e->xbutton.state);
208 break;
209 case KeyPress:
210 STRIP_MODS(e->xkey.state);
211 break;
212 case KeyRelease:
213 STRIP_MODS(e->xkey.state);
214 /* remove from the state the mask of the modifier being released, if
215 it is a modifier key being released (this is a little ugly..) */
216 kp = modmap->modifiermap;
217 for (i = 0; i < mask_table_size; ++i) {
218 for (k = 0; k < modmap->max_keypermod; ++k) {
219 if (*kp == e->xkey.keycode) { /* found the keycode */
220 /* remove the mask for it */
221 e->xkey.state &= ~mask_table[i];
222 /* cause the first loop to break; */
223 i = mask_table_size;
224 break; /* get outta here! */
225 }
226 ++kp;
227 }
228 }
229 break;
230 case MotionNotify:
231 STRIP_MODS(e->xmotion.state);
232 /* compress events */
233 {
234 XEvent ce;
235 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
236 e->type, &ce)) {
237 e->xmotion.x_root = ce.xmotion.x_root;
238 e->xmotion.y_root = ce.xmotion.y_root;
239 }
240 }
241 break;
242 }
243 }
244
245 static gboolean event_ignore(XEvent *e, Client *client)
246 {
247 switch(e->type) {
248 case FocusIn:
249 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
250 because of RevertToPointerRoot. If the focus ends up reverting to
251 pointer root on a workspace change, then the FocusIn event that we
252 want will be of type NotifyAncestor. This situation does not occur
253 for FocusOut, so it is safely ignored there.
254 */
255 if (INVALID_FOCUSIN(e) ||
256 client == NULL) {
257 #ifdef DEBUG_FOCUS
258 g_message("FocusIn on %lx mode %d detail %d IGNORED", e->xfocus.window,
259 e->xfocus.mode, e->xfocus.detail);
260 #endif
261 /* says a client was not found for the event (or a valid FocusIn
262 event was not found.
263 */
264 e->xfocus.window = None;
265 return TRUE;
266 }
267
268 #ifdef DEBUG_FOCUS
269 g_message("FocusIn on %lx mode %d detail %d", e->xfocus.window,
270 e->xfocus.mode, e->xfocus.detail);
271 #endif
272 break;
273 case FocusOut:
274 if (INVALID_FOCUSOUT(e)) {
275 #ifdef DEBUG_FOCUS
276 g_message("FocusOut on %lx mode %d detail %d IGNORED",
277 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
278 #endif
279 return TRUE;
280 }
281
282 #ifdef DEBUG_FOCUS
283 g_message("FocusOut on %lx mode %d detail %d",
284 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
285 #endif
286
287 /* Try process a FocusIn first, and if a legit one isn't found, then
288 do the fallback shiznit. */
289 {
290 XEvent fe;
291 gboolean fallback = TRUE;
292
293 while (TRUE) {
294 if (!XCheckTypedEvent(ob_display, FocusOut, &fe))
295 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
296 break;
297 if (fe.type == FocusOut) {
298 #ifdef DEBUG_FOCUS
299 g_message("found pending FocusOut");
300 #endif
301 if (!INVALID_FOCUSOUT(&fe)) {
302 /* if there is a VALID FocusOut still coming, don't
303 fallback focus yet, we'll deal with it then */
304 XPutBackEvent(ob_display, &fe);
305 fallback = FALSE;
306 break;
307 }
308 } else {
309 #ifdef DEBUG_FOCUS
310 g_message("found pending FocusIn");
311 #endif
312 /* once all the FocusOut's have been dealt with, if there
313 is a FocusIn still left and it is valid, then use it */
314 event_process(&fe);
315 /* secret magic way of event_process telling us that no
316 client was found for the FocusIn event. ^_^ */
317 if (fe.xfocus.window != None) {
318 fallback = FALSE;
319 break;
320 }
321 }
322 }
323 if (fallback) {
324 #ifdef DEBUG_FOCUS
325 g_message("no valid FocusIn and no FocusOut events found, "
326 "falling back");
327 #endif
328 focus_fallback(Fallback_NoFocus);
329 }
330 }
331 break;
332 case EnterNotify:
333 case LeaveNotify:
334 /* NotifyUngrab occurs when a mouse button is released and the event is
335 caused, like when lowering a window */
336 /* NotifyVirtual occurs when ungrabbing the pointer,
337 NotifyNonlinearVirtual occurs when closing a gtk app's menu */
338 if (e->xcrossing.mode == NotifyGrab ||
339 e->xcrossing.detail == NotifyInferior ||
340 (e->xcrossing.mode == NotifyUngrab &&
341 (e->xcrossing.detail == NotifyVirtual ||
342 e->xcrossing.detail == NotifyNonlinearVirtual))) {
343 #ifdef DEBUG_FOCUS
344 g_message("EnterNotify mode %d detail %d on %lx IGNORED",
345 e->xcrossing.mode,
346 e->xcrossing.detail, client?client->window:0);
347 #endif
348 return TRUE;
349 }
350 #ifdef DEBUG_FOCUS
351 g_message("EnterNotify mode %d detail %d on %lx", e->xcrossing.mode,
352 e->xcrossing.detail, client?client->window:0);
353 #endif
354 break;
355 }
356 return FALSE;
357 }
358
359 static void event_process(XEvent *e)
360 {
361 Window window;
362 Client *client;
363 Menu *menu = NULL;
364
365 window = event_get_window(e);
366 if (!(client = g_hash_table_lookup(client_map, &window)))
367 menu = g_hash_table_lookup(menu_map, &window);
368 event_set_lasttime(e);
369 event_hack_mods(e);
370 if (event_ignore(e, client))
371 return;
372
373 /* deal with it in the kernel */
374 if (menu) {
375 event_handle_menu(menu, e);
376 return;
377 } else if (client)
378 event_handle_client(client, e);
379 else if (window == ob_root)
380 event_handle_root(e);
381 else if (e->type == MapRequest)
382 client_manage(window);
383 else if (e->type == ConfigureRequest) {
384 /* unhandled configure requests must be used to configure the
385 window directly */
386 XWindowChanges xwc;
387
388 xwc.x = e->xconfigurerequest.x;
389 xwc.y = e->xconfigurerequest.y;
390 xwc.width = e->xconfigurerequest.width;
391 xwc.height = e->xconfigurerequest.height;
392 xwc.border_width = e->xconfigurerequest.border_width;
393 xwc.sibling = e->xconfigurerequest.above;
394 xwc.stack_mode = e->xconfigurerequest.detail;
395
396 /* we are not to be held responsible if someone sends us an
397 invalid request! */
398 xerror_set_ignore(TRUE);
399 XConfigureWindow(ob_display, window,
400 e->xconfigurerequest.value_mask, &xwc);
401 xerror_set_ignore(FALSE);
402 }
403
404 if (moveresize_in_progress)
405 if (e->type == MotionNotify || e->type == ButtonRelease ||
406 e->type == ButtonPress ||
407 e->type == KeyPress || e->type == KeyRelease) {
408 moveresize_event(e);
409 return; /* no dispatch! */
410 }
411
412 /* user input (action-bound) events */
413 /*
414 if (e->type == ButtonPress || e->type == ButtonRelease ||
415 e->type == MotionNotify)
416 mouse_event(e, client);
417 else if (e->type == KeyPress || e->type == KeyRelease)
418 ;
419 */
420
421 /* dispatch the event to registered handlers */
422 dispatch_x(e, client);
423 }
424
425 static void event_handle_root(XEvent *e)
426 {
427 Atom msgtype;
428
429 switch(e->type) {
430 case ClientMessage:
431 if (e->xclient.format != 32) break;
432
433 msgtype = e->xclient.message_type;
434 if (msgtype == prop_atoms.net_current_desktop) {
435 unsigned int d = e->xclient.data.l[0];
436 if (d < screen_num_desktops)
437 screen_set_desktop(d);
438 } else if (msgtype == prop_atoms.net_number_of_desktops) {
439 unsigned int d = e->xclient.data.l[0];
440 if (d > 0)
441 screen_set_num_desktops(d);
442 } else if (msgtype == prop_atoms.net_showing_desktop) {
443 screen_show_desktop(e->xclient.data.l[0] != 0);
444 }
445 break;
446 case PropertyNotify:
447 if (e->xproperty.atom == prop_atoms.net_desktop_names)
448 screen_update_desktop_names();
449 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
450 screen_update_layout();
451 break;
452 }
453 }
454
455 static void event_handle_client(Client *client, XEvent *e)
456 {
457 XEvent ce;
458 Atom msgtype;
459 int i=0;
460
461 switch (e->type) {
462 case ButtonPress:
463 case ButtonRelease:
464 switch (frame_context(client, e->xbutton.window)) {
465 case Context_Maximize:
466 client->frame->max_press = (e->type == ButtonPress);
467 framerender_frame(client->frame);
468 break;
469 case Context_Close:
470 client->frame->close_press = (e->type == ButtonPress);
471 framerender_frame(client->frame);
472 break;
473 case Context_Iconify:
474 client->frame->iconify_press = (e->type == ButtonPress);
475 framerender_frame(client->frame);
476 break;
477 case Context_AllDesktops:
478 client->frame->desk_press = (e->type == ButtonPress);
479 framerender_frame(client->frame);
480 break;
481 case Context_Shade:
482 client->frame->shade_press = (e->type == ButtonPress);
483 framerender_frame(client->frame);
484 break;
485 default:
486 /* nothing changes with clicks for any other contexts */
487 break;
488 }
489 break;
490 case FocusIn:
491 focus_set_client(client);
492 case FocusOut:
493 #ifdef DEBUG_FOCUS
494 g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
495 client->window);
496 #endif
497 /* focus state can affect the stacking layer */
498 client_calc_layer(client);
499 frame_adjust_focus(client->frame);
500 break;
501 case EnterNotify:
502 if (client_normal(client)) {
503 if (ob_state == State_Starting) {
504 /* move it to the top of the focus order */
505 guint desktop = client->desktop;
506 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
507 focus_order[desktop] = g_list_remove(focus_order[desktop],
508 client);
509 focus_order[desktop] = g_list_prepend(focus_order[desktop],
510 client);
511 } else if (config_focus_follow) {
512 #ifdef DEBUG_FOCUS
513 g_message("EnterNotify on %lx, focusing window",
514 client->window);
515 #endif
516 client_focus(client);
517 }
518 }
519 break;
520 case ConfigureRequest:
521 /* compress these */
522 while (XCheckTypedWindowEvent(ob_display, client->window,
523 ConfigureRequest, &ce)) {
524 ++i;
525 /* XXX if this causes bad things.. we can compress config req's
526 with the same mask. */
527 e->xconfigurerequest.value_mask |=
528 ce.xconfigurerequest.value_mask;
529 if (ce.xconfigurerequest.value_mask & CWX)
530 e->xconfigurerequest.x = ce.xconfigurerequest.x;
531 if (ce.xconfigurerequest.value_mask & CWY)
532 e->xconfigurerequest.y = ce.xconfigurerequest.y;
533 if (ce.xconfigurerequest.value_mask & CWWidth)
534 e->xconfigurerequest.width = ce.xconfigurerequest.width;
535 if (ce.xconfigurerequest.value_mask & CWHeight)
536 e->xconfigurerequest.height = ce.xconfigurerequest.height;
537 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
538 e->xconfigurerequest.border_width =
539 ce.xconfigurerequest.border_width;
540 if (ce.xconfigurerequest.value_mask & CWStackMode)
541 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
542 }
543
544 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
545 if (client->iconic || client->shaded) return;
546
547 if (e->xconfigurerequest.value_mask & CWBorderWidth)
548 client->border_width = e->xconfigurerequest.border_width;
549
550 /* resize, then move, as specified in the EWMH section 7.7 */
551 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
552 CWX | CWY)) {
553 int x, y, w, h;
554 Corner corner;
555
556 x = (e->xconfigurerequest.value_mask & CWX) ?
557 e->xconfigurerequest.x : client->area.x;
558 y = (e->xconfigurerequest.value_mask & CWY) ?
559 e->xconfigurerequest.y : client->area.y;
560 w = (e->xconfigurerequest.value_mask & CWWidth) ?
561 e->xconfigurerequest.width : client->area.width;
562 h = (e->xconfigurerequest.value_mask & CWHeight) ?
563 e->xconfigurerequest.height : client->area.height;
564
565 switch (client->gravity) {
566 case NorthEastGravity:
567 case EastGravity:
568 corner = Corner_TopRight;
569 break;
570 case SouthWestGravity:
571 case SouthGravity:
572 corner = Corner_BottomLeft;
573 break;
574 case SouthEastGravity:
575 corner = Corner_BottomRight;
576 break;
577 default: /* NorthWest, Static, etc */
578 corner = Corner_TopLeft;
579 }
580
581 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
582 }
583
584 if (e->xconfigurerequest.value_mask & CWStackMode) {
585 switch (e->xconfigurerequest.detail) {
586 case Below:
587 case BottomIf:
588 stacking_lower(client);
589 break;
590
591 case Above:
592 case TopIf:
593 default:
594 stacking_raise(client);
595 break;
596 }
597 }
598 break;
599 case UnmapNotify:
600 if (client->ignore_unmaps) {
601 client->ignore_unmaps--;
602 break;
603 }
604 client_unmanage(client);
605 break;
606 case DestroyNotify:
607 client_unmanage(client);
608 break;
609 case ReparentNotify:
610 /* this is when the client is first taken captive in the frame */
611 if (e->xreparent.parent == client->frame->plate) break;
612
613 /*
614 This event is quite rare and is usually handled in unmapHandler.
615 However, if the window is unmapped when the reparent event occurs,
616 the window manager never sees it because an unmap event is not sent
617 to an already unmapped window.
618 */
619
620 /* we don't want the reparent event, put it back on the stack for the
621 X server to deal with after we unmanage the window */
622 XPutBackEvent(ob_display, e);
623
624 client_unmanage(client);
625 break;
626 case MapRequest:
627 g_message("MapRequest for 0x%lx", client->window);
628 if (!client->iconic) break; /* this normally doesn't happen, but if it
629 does, we don't want it! */
630 if (screen_showing_desktop)
631 screen_show_desktop(FALSE);
632 client_iconify(client, FALSE, TRUE);
633 if (!client->frame->visible)
634 /* if its not visible still, then don't mess with it */
635 break;
636 if (client->shaded)
637 client_shade(client, FALSE);
638 client_focus(client);
639 stacking_raise(client);
640 break;
641 case ClientMessage:
642 /* validate cuz we query stuff off the client here */
643 if (!client_validate(client)) break;
644
645 if (e->xclient.format != 32) return;
646
647 msgtype = e->xclient.message_type;
648 if (msgtype == prop_atoms.wm_change_state) {
649 /* compress changes into a single change */
650 while (XCheckTypedWindowEvent(ob_display, e->type,
651 client->window, &ce)) {
652 /* XXX: it would be nice to compress ALL messages of a
653 type, not just messages in a row without other
654 message types between. */
655 if (ce.xclient.message_type != msgtype) {
656 XPutBackEvent(ob_display, &ce);
657 break;
658 }
659 e->xclient = ce.xclient;
660 }
661 client_set_wm_state(client, e->xclient.data.l[0]);
662 } else if (msgtype == prop_atoms.net_wm_desktop) {
663 /* compress changes into a single change */
664 while (XCheckTypedWindowEvent(ob_display, e->type,
665 client->window, &ce)) {
666 /* XXX: it would be nice to compress ALL messages of a
667 type, not just messages in a row without other
668 message types between. */
669 if (ce.xclient.message_type != msgtype) {
670 XPutBackEvent(ob_display, &ce);
671 break;
672 }
673 e->xclient = ce.xclient;
674 }
675 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
676 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
677 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
678 FALSE);
679 } else if (msgtype == prop_atoms.net_wm_state) {
680 /* can't compress these */
681 g_message("net_wm_state %s %ld %ld for 0x%lx",
682 (e->xclient.data.l[0] == 0 ? "Remove" :
683 e->xclient.data.l[0] == 1 ? "Add" :
684 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
685 e->xclient.data.l[1], e->xclient.data.l[2],
686 client->window);
687 client_set_state(client, e->xclient.data.l[0],
688 e->xclient.data.l[1], e->xclient.data.l[2]);
689 } else if (msgtype == prop_atoms.net_close_window) {
690 g_message("net_close_window for 0x%lx", client->window);
691 client_close(client);
692 } else if (msgtype == prop_atoms.net_active_window) {
693 g_message("net_active_window for 0x%lx", client->window);
694 if (screen_showing_desktop)
695 screen_show_desktop(FALSE);
696 if (client->iconic)
697 client_iconify(client, FALSE, TRUE);
698 else if (!client->frame->visible)
699 /* if its not visible for other reasons, then don't mess
700 with it */
701 break;
702 if (client->shaded)
703 client_shade(client, FALSE);
704 client_focus(client);
705 stacking_raise(client);
706 } else if (msgtype == prop_atoms.net_wm_moveresize) {
707 g_message("net_wm_moveresize for 0x%lx", client->window);
708 if ((Atom)e->xclient.data.l[2] ==
709 prop_atoms.net_wm_moveresize_size_topleft ||
710 (Atom)e->xclient.data.l[2] ==
711 prop_atoms.net_wm_moveresize_size_top ||
712 (Atom)e->xclient.data.l[2] ==
713 prop_atoms.net_wm_moveresize_size_topright ||
714 (Atom)e->xclient.data.l[2] ==
715 prop_atoms.net_wm_moveresize_size_right ||
716 (Atom)e->xclient.data.l[2] ==
717 prop_atoms.net_wm_moveresize_size_right ||
718 (Atom)e->xclient.data.l[2] ==
719 prop_atoms.net_wm_moveresize_size_bottomright ||
720 (Atom)e->xclient.data.l[2] ==
721 prop_atoms.net_wm_moveresize_size_bottom ||
722 (Atom)e->xclient.data.l[2] ==
723 prop_atoms.net_wm_moveresize_size_bottomleft ||
724 (Atom)e->xclient.data.l[2] ==
725 prop_atoms.net_wm_moveresize_size_left ||
726 (Atom)e->xclient.data.l[2] ==
727 prop_atoms.net_wm_moveresize_move ||
728 (Atom)e->xclient.data.l[2] ==
729 prop_atoms.net_wm_moveresize_size_keyboard ||
730 (Atom)e->xclient.data.l[2] ==
731 prop_atoms.net_wm_moveresize_move_keyboard) {
732
733 moveresize_start(client, e->xclient.data.l[0],
734 e->xclient.data.l[1], e->xclient.data.l[3],
735 e->xclient.data.l[2]);
736 }
737 } else if (msgtype == prop_atoms.net_moveresize_window) {
738 int oldg = client->gravity;
739 int tmpg, x, y, w, h;
740
741 if (e->xclient.data.l[0] & 0xff)
742 tmpg = e->xclient.data.l[0] & 0xff;
743 else
744 tmpg = oldg;
745
746 if (e->xclient.data.l[0] & 1 << 8)
747 x = e->xclient.data.l[1];
748 else
749 x = client->area.x;
750 if (e->xclient.data.l[0] & 1 << 9)
751 y = e->xclient.data.l[2];
752 else
753 y = client->area.y;
754 if (e->xclient.data.l[0] & 1 << 10)
755 w = e->xclient.data.l[3];
756 else
757 w = client->area.y;
758 if (e->xclient.data.l[0] & 1 << 11)
759 h = e->xclient.data.l[4];
760 else
761 h = client->area.y;
762 client->gravity = tmpg;
763 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
764 client->gravity = oldg;
765 }
766 break;
767 case PropertyNotify:
768 /* validate cuz we query stuff off the client here */
769 if (!client_validate(client)) break;
770
771 /* compress changes to a single property into a single change */
772 while (XCheckTypedWindowEvent(ob_display, e->type,
773 client->window, &ce)) {
774 /* XXX: it would be nice to compress ALL changes to a property,
775 not just changes in a row without other props between. */
776 if (ce.xproperty.atom != e->xproperty.atom) {
777 XPutBackEvent(ob_display, &ce);
778 break;
779 }
780 }
781
782 msgtype = e->xproperty.atom;
783 if (msgtype == XA_WM_NORMAL_HINTS) {
784 client_update_normal_hints(client);
785 /* normal hints can make a window non-resizable */
786 client_setup_decor_and_functions(client);
787 }
788 else if (msgtype == XA_WM_HINTS)
789 client_update_wmhints(client);
790 else if (msgtype == XA_WM_TRANSIENT_FOR) {
791 client_update_transient_for(client);
792 client_get_type(client);
793 /* type may have changed, so update the layer */
794 client_calc_layer(client);
795 client_setup_decor_and_functions(client);
796 }
797 else if (msgtype == prop_atoms.net_wm_name ||
798 msgtype == prop_atoms.wm_name)
799 client_update_title(client);
800 else if (msgtype == prop_atoms.net_wm_icon_name ||
801 msgtype == prop_atoms.wm_icon_name)
802 client_update_icon_title(client);
803 else if (msgtype == prop_atoms.wm_class)
804 client_update_class(client);
805 else if (msgtype == prop_atoms.wm_protocols) {
806 client_update_protocols(client);
807 client_setup_decor_and_functions(client);
808 }
809 else if (msgtype == prop_atoms.net_wm_strut)
810 client_update_strut(client);
811 else if (msgtype == prop_atoms.net_wm_icon)
812 client_update_icons(client);
813 else if (msgtype == prop_atoms.kwm_win_icon)
814 client_update_kwm_icon(client);
815 default:
816 ;
817 #ifdef SHAPE
818 if (extensions_shape && e->type == extensions_shape_event_basep) {
819 client->shaped = ((XShapeEvent*)e)->shaped;
820 frame_adjust_shape(client->frame);
821 }
822 #endif
823 }
824 }
825
826 static void event_handle_menu(Menu *menu, XEvent *e)
827 {
828 MenuEntry *entry;
829
830 g_message("EVENT %d", e->type);
831 switch (e->type) {
832 case ButtonPress:
833 if (e->xbutton.button == 3)
834 menu_hide(menu);
835 break;
836 case ButtonRelease:
837 if (!menu->shown) break;
838
839 /* grab_pointer_window(FALSE, None, menu->frame);*/
840
841 entry = menu_find_entry(menu, e->xbutton.window);
842 if (entry) {
843 int junk;
844 Window wjunk;
845 guint ujunk, b, w, h;
846 XGetGeometry(ob_display, e->xbutton.window,
847 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
848 if (e->xbutton.x >= (signed)-b &&
849 e->xbutton.y >= (signed)-b &&
850 e->xbutton.x < (signed)(w+b) &&
851 e->xbutton.y < (signed)(h+b)) {
852 menu_entry_fire(entry);
853 }
854 }
855 break;
856 case EnterNotify:
857 case LeaveNotify:
858 g_message("enter/leave");
859 entry = menu_find_entry(menu, e->xcrossing.window);
860 if (entry) {
861 entry->hilite = e->type == EnterNotify;
862 menu_entry_render(entry);
863 }
864 break;
865 }
866 }
This page took 0.071872 seconds and 5 git commands to generate.