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