]> Dogcows Code - chaz/openbox/blob - openbox/event.c
comment typo
[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.mode == NotifyUngrab &&
312 e->xcrossing.detail == NotifyVirtual))
313 return TRUE;
314 break;
315 }
316 return FALSE;
317 }
318
319 static void event_process(XEvent *e)
320 {
321 Window window;
322 Client *client;
323 Menu *menu = NULL;
324
325 window = event_get_window(e);
326 if (!(client = g_hash_table_lookup(client_map, &window)))
327 menu = g_hash_table_lookup(menu_map, &window);
328 event_set_lasttime(e);
329 event_hack_mods(e);
330 if (event_ignore(e, client))
331 return;
332
333 /* deal with it in the kernel */
334 if (menu) {
335 event_handle_menu(menu, e);
336 return;
337 } else if (client)
338 event_handle_client(client, e);
339 else if (window == ob_root)
340 event_handle_root(e);
341 else if (e->type == MapRequest)
342 client_manage(window);
343 else if (e->type == ConfigureRequest) {
344 /* unhandled configure requests must be used to configure the
345 window directly */
346 XWindowChanges xwc;
347
348 xwc.x = e->xconfigurerequest.x;
349 xwc.y = e->xconfigurerequest.y;
350 xwc.width = e->xconfigurerequest.width;
351 xwc.height = e->xconfigurerequest.height;
352 xwc.border_width = e->xconfigurerequest.border_width;
353 xwc.sibling = e->xconfigurerequest.above;
354 xwc.stack_mode = e->xconfigurerequest.detail;
355
356 /* we are not to be held responsible if someone sends us an
357 invalid request! */
358 xerror_set_ignore(TRUE);
359 XConfigureWindow(ob_display, window,
360 e->xconfigurerequest.value_mask, &xwc);
361 xerror_set_ignore(FALSE);
362 }
363
364 if (moveresize_in_progress)
365 if (e->type == MotionNotify || e->type == ButtonRelease ||
366 e->type == ButtonPress ||
367 e->type == KeyPress || e->type == KeyRelease) {
368 moveresize_event(e);
369 return; /* no dispatch! */
370 }
371
372 /* user input (action-bound) events */
373 /*
374 if (e->type == ButtonPress || e->type == ButtonRelease ||
375 e->type == MotionNotify)
376 mouse_event(e, client);
377 else if (e->type == KeyPress || e->type == KeyRelease)
378 ;
379 */
380
381 /* dispatch the event to registered handlers */
382 dispatch_x(e, client);
383 }
384
385 static void event_handle_root(XEvent *e)
386 {
387 Atom msgtype;
388
389 switch(e->type) {
390 case ClientMessage:
391 if (e->xclient.format != 32) break;
392
393 msgtype = e->xclient.message_type;
394 if (msgtype == prop_atoms.net_current_desktop) {
395 unsigned int d = e->xclient.data.l[0];
396 if (d < screen_num_desktops)
397 screen_set_desktop(d);
398 } else if (msgtype == prop_atoms.net_number_of_desktops) {
399 unsigned int d = e->xclient.data.l[0];
400 if (d > 0)
401 screen_set_num_desktops(d);
402 } else if (msgtype == prop_atoms.net_showing_desktop) {
403 screen_show_desktop(e->xclient.data.l[0] != 0);
404 }
405 break;
406 case PropertyNotify:
407 if (e->xproperty.atom == prop_atoms.net_desktop_names)
408 screen_update_desktop_names();
409 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
410 screen_update_layout();
411 break;
412 }
413 }
414
415 static void event_handle_client(Client *client, XEvent *e)
416 {
417 XEvent ce;
418 Atom msgtype;
419 int i=0;
420
421 switch (e->type) {
422 case ButtonPress:
423 case ButtonRelease:
424 switch (frame_context(client, e->xbutton.window)) {
425 case Context_Maximize:
426 client->frame->max_press = (e->type == ButtonPress);
427 framerender_frame(client->frame);
428 break;
429 case Context_Close:
430 client->frame->close_press = (e->type == ButtonPress);
431 framerender_frame(client->frame);
432 break;
433 case Context_Iconify:
434 client->frame->iconify_press = (e->type == ButtonPress);
435 framerender_frame(client->frame);
436 break;
437 case Context_AllDesktops:
438 client->frame->desk_press = (e->type == ButtonPress);
439 framerender_frame(client->frame);
440 break;
441 case Context_Shade:
442 client->frame->shade_press = (e->type == ButtonPress);
443 framerender_frame(client->frame);
444 break;
445 default:
446 /* nothing changes with clicks for any other contexts */
447 break;
448 }
449 break;
450 case FocusIn:
451 focus_set_client(client);
452 case FocusOut:
453 #ifdef DEBUG_FOCUS
454 g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
455 client->window);
456 #endif
457 /* focus state can affect the stacking layer */
458 client_calc_layer(client);
459 frame_adjust_focus(client->frame);
460 break;
461 case EnterNotify:
462 if (client_normal(client)) {
463 if (ob_state == State_Starting) {
464 /* move it to the top of the focus order */
465 guint desktop = client->desktop;
466 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
467 focus_order[desktop] = g_list_remove(focus_order[desktop],
468 client);
469 focus_order[desktop] = g_list_prepend(focus_order[desktop],
470 client);
471 } else if (config_focus_follow) {
472 #ifdef DEBUG_FOCUS
473 g_message("EnterNotify on %lx, focusing window",
474 client->window);
475 #endif
476 client_focus(client);
477 }
478 }
479 break;
480 case ConfigureRequest:
481 /* compress these */
482 while (XCheckTypedWindowEvent(ob_display, client->window,
483 ConfigureRequest, &ce)) {
484 ++i;
485 /* XXX if this causes bad things.. we can compress config req's
486 with the same mask. */
487 e->xconfigurerequest.value_mask |=
488 ce.xconfigurerequest.value_mask;
489 if (ce.xconfigurerequest.value_mask & CWX)
490 e->xconfigurerequest.x = ce.xconfigurerequest.x;
491 if (ce.xconfigurerequest.value_mask & CWY)
492 e->xconfigurerequest.y = ce.xconfigurerequest.y;
493 if (ce.xconfigurerequest.value_mask & CWWidth)
494 e->xconfigurerequest.width = ce.xconfigurerequest.width;
495 if (ce.xconfigurerequest.value_mask & CWHeight)
496 e->xconfigurerequest.height = ce.xconfigurerequest.height;
497 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
498 e->xconfigurerequest.border_width =
499 ce.xconfigurerequest.border_width;
500 if (ce.xconfigurerequest.value_mask & CWStackMode)
501 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
502 }
503
504 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
505 if (client->iconic || client->shaded) return;
506
507 if (e->xconfigurerequest.value_mask & CWBorderWidth)
508 client->border_width = e->xconfigurerequest.border_width;
509
510 /* resize, then move, as specified in the EWMH section 7.7 */
511 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
512 CWX | CWY)) {
513 int x, y, w, h;
514 Corner corner;
515
516 x = (e->xconfigurerequest.value_mask & CWX) ?
517 e->xconfigurerequest.x : client->area.x;
518 y = (e->xconfigurerequest.value_mask & CWY) ?
519 e->xconfigurerequest.y : client->area.y;
520 w = (e->xconfigurerequest.value_mask & CWWidth) ?
521 e->xconfigurerequest.width : client->area.width;
522 h = (e->xconfigurerequest.value_mask & CWHeight) ?
523 e->xconfigurerequest.height : client->area.height;
524
525 switch (client->gravity) {
526 case NorthEastGravity:
527 case EastGravity:
528 corner = Corner_TopRight;
529 break;
530 case SouthWestGravity:
531 case SouthGravity:
532 corner = Corner_BottomLeft;
533 break;
534 case SouthEastGravity:
535 corner = Corner_BottomRight;
536 break;
537 default: /* NorthWest, Static, etc */
538 corner = Corner_TopLeft;
539 }
540
541 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
542 }
543
544 if (e->xconfigurerequest.value_mask & CWStackMode) {
545 switch (e->xconfigurerequest.detail) {
546 case Below:
547 case BottomIf:
548 stacking_lower(client);
549 break;
550
551 case Above:
552 case TopIf:
553 default:
554 stacking_raise(client);
555 break;
556 }
557 }
558 break;
559 case UnmapNotify:
560 if (client->ignore_unmaps) {
561 client->ignore_unmaps--;
562 break;
563 }
564 client_unmanage(client);
565 break;
566 case DestroyNotify:
567 client_unmanage(client);
568 break;
569 case ReparentNotify:
570 /* this is when the client is first taken captive in the frame */
571 if (e->xreparent.parent == client->frame->plate) break;
572
573 /*
574 This event is quite rare and is usually handled in unmapHandler.
575 However, if the window is unmapped when the reparent event occurs,
576 the window manager never sees it because an unmap event is not sent
577 to an already unmapped window.
578 */
579
580 /* we don't want the reparent event, put it back on the stack for the
581 X server to deal with after we unmanage the window */
582 XPutBackEvent(ob_display, e);
583
584 client_unmanage(client);
585 break;
586 case MapRequest:
587 g_message("MapRequest for 0x%lx", client->window);
588 if (!client->iconic) break; /* this normally doesn't happen, but if it
589 does, we don't want it! */
590 if (screen_showing_desktop)
591 screen_show_desktop(FALSE);
592 client_iconify(client, FALSE, TRUE);
593 if (!client->frame->visible)
594 /* if its not visible still, then don't mess with it */
595 break;
596 if (client->shaded)
597 client_shade(client, FALSE);
598 client_focus(client);
599 stacking_raise(client);
600 break;
601 case ClientMessage:
602 /* validate cuz we query stuff off the client here */
603 if (!client_validate(client)) break;
604
605 if (e->xclient.format != 32) return;
606
607 msgtype = e->xclient.message_type;
608 if (msgtype == prop_atoms.wm_change_state) {
609 /* compress changes into a single change */
610 while (XCheckTypedWindowEvent(ob_display, e->type,
611 client->window, &ce)) {
612 /* XXX: it would be nice to compress ALL messages of a
613 type, not just messages in a row without other
614 message types between. */
615 if (ce.xclient.message_type != msgtype) {
616 XPutBackEvent(ob_display, &ce);
617 break;
618 }
619 e->xclient = ce.xclient;
620 }
621 client_set_wm_state(client, e->xclient.data.l[0]);
622 } else if (msgtype == prop_atoms.net_wm_desktop) {
623 /* compress changes into a single change */
624 while (XCheckTypedWindowEvent(ob_display, e->type,
625 client->window, &ce)) {
626 /* XXX: it would be nice to compress ALL messages of a
627 type, not just messages in a row without other
628 message types between. */
629 if (ce.xclient.message_type != msgtype) {
630 XPutBackEvent(ob_display, &ce);
631 break;
632 }
633 e->xclient = ce.xclient;
634 }
635 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
636 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
637 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
638 FALSE);
639 } else if (msgtype == prop_atoms.net_wm_state) {
640 /* can't compress these */
641 g_message("net_wm_state %s %ld %ld for 0x%lx",
642 (e->xclient.data.l[0] == 0 ? "Remove" :
643 e->xclient.data.l[0] == 1 ? "Add" :
644 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
645 e->xclient.data.l[1], e->xclient.data.l[2],
646 client->window);
647 client_set_state(client, e->xclient.data.l[0],
648 e->xclient.data.l[1], e->xclient.data.l[2]);
649 } else if (msgtype == prop_atoms.net_close_window) {
650 g_message("net_close_window for 0x%lx", client->window);
651 client_close(client);
652 } else if (msgtype == prop_atoms.net_active_window) {
653 g_message("net_active_window for 0x%lx", client->window);
654 if (screen_showing_desktop)
655 screen_show_desktop(FALSE);
656 if (client->iconic)
657 client_iconify(client, FALSE, TRUE);
658 else if (!client->frame->visible)
659 /* if its not visible for other reasons, then don't mess
660 with it */
661 break;
662 if (client->shaded)
663 client_shade(client, FALSE);
664 client_focus(client);
665 stacking_raise(client);
666 } else if (msgtype == prop_atoms.net_wm_moveresize) {
667 g_message("net_wm_moveresize for 0x%lx", client->window);
668 if ((Atom)e->xclient.data.l[2] ==
669 prop_atoms.net_wm_moveresize_size_topleft ||
670 (Atom)e->xclient.data.l[2] ==
671 prop_atoms.net_wm_moveresize_size_top ||
672 (Atom)e->xclient.data.l[2] ==
673 prop_atoms.net_wm_moveresize_size_topright ||
674 (Atom)e->xclient.data.l[2] ==
675 prop_atoms.net_wm_moveresize_size_right ||
676 (Atom)e->xclient.data.l[2] ==
677 prop_atoms.net_wm_moveresize_size_right ||
678 (Atom)e->xclient.data.l[2] ==
679 prop_atoms.net_wm_moveresize_size_bottomright ||
680 (Atom)e->xclient.data.l[2] ==
681 prop_atoms.net_wm_moveresize_size_bottom ||
682 (Atom)e->xclient.data.l[2] ==
683 prop_atoms.net_wm_moveresize_size_bottomleft ||
684 (Atom)e->xclient.data.l[2] ==
685 prop_atoms.net_wm_moveresize_size_left ||
686 (Atom)e->xclient.data.l[2] ==
687 prop_atoms.net_wm_moveresize_move ||
688 (Atom)e->xclient.data.l[2] ==
689 prop_atoms.net_wm_moveresize_size_keyboard ||
690 (Atom)e->xclient.data.l[2] ==
691 prop_atoms.net_wm_moveresize_move_keyboard) {
692
693 moveresize_start(client, e->xclient.data.l[0],
694 e->xclient.data.l[1], e->xclient.data.l[3],
695 e->xclient.data.l[2]);
696 }
697 } else if (msgtype == prop_atoms.net_moveresize_window) {
698 int oldg = client->gravity;
699 int tmpg, x, y, w, h;
700
701 if (e->xclient.data.l[0] & 0xff)
702 tmpg = e->xclient.data.l[0] & 0xff;
703 else
704 tmpg = oldg;
705
706 if (e->xclient.data.l[0] & 1 << 8)
707 x = e->xclient.data.l[1];
708 else
709 x = client->area.x;
710 if (e->xclient.data.l[0] & 1 << 9)
711 y = e->xclient.data.l[2];
712 else
713 y = client->area.y;
714 if (e->xclient.data.l[0] & 1 << 10)
715 w = e->xclient.data.l[3];
716 else
717 w = client->area.y;
718 if (e->xclient.data.l[0] & 1 << 11)
719 h = e->xclient.data.l[4];
720 else
721 h = client->area.y;
722 client->gravity = tmpg;
723 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
724 client->gravity = oldg;
725 }
726 break;
727 case PropertyNotify:
728 /* validate cuz we query stuff off the client here */
729 if (!client_validate(client)) break;
730
731 /* compress changes to a single property into a single change */
732 while (XCheckTypedWindowEvent(ob_display, e->type,
733 client->window, &ce)) {
734 /* XXX: it would be nice to compress ALL changes to a property,
735 not just changes in a row without other props between. */
736 if (ce.xproperty.atom != e->xproperty.atom) {
737 XPutBackEvent(ob_display, &ce);
738 break;
739 }
740 }
741
742 msgtype = e->xproperty.atom;
743 if (msgtype == XA_WM_NORMAL_HINTS) {
744 client_update_normal_hints(client);
745 /* normal hints can make a window non-resizable */
746 client_setup_decor_and_functions(client);
747 }
748 else if (msgtype == XA_WM_HINTS)
749 client_update_wmhints(client);
750 else if (msgtype == XA_WM_TRANSIENT_FOR) {
751 client_update_transient_for(client);
752 client_get_type(client);
753 /* type may have changed, so update the layer */
754 client_calc_layer(client);
755 client_setup_decor_and_functions(client);
756 }
757 else if (msgtype == prop_atoms.net_wm_name ||
758 msgtype == prop_atoms.wm_name)
759 client_update_title(client);
760 else if (msgtype == prop_atoms.net_wm_icon_name ||
761 msgtype == prop_atoms.wm_icon_name)
762 client_update_icon_title(client);
763 else if (msgtype == prop_atoms.wm_class)
764 client_update_class(client);
765 else if (msgtype == prop_atoms.wm_protocols) {
766 client_update_protocols(client);
767 client_setup_decor_and_functions(client);
768 }
769 else if (msgtype == prop_atoms.net_wm_strut)
770 client_update_strut(client);
771 else if (msgtype == prop_atoms.net_wm_icon)
772 client_update_icons(client);
773 else if (msgtype == prop_atoms.kwm_win_icon)
774 client_update_kwm_icon(client);
775 default:
776 ;
777 #ifdef SHAPE
778 if (extensions_shape && e->type == extensions_shape_event_basep) {
779 client->shaped = ((XShapeEvent*)e)->shaped;
780 frame_adjust_shape(client->frame);
781 }
782 #endif
783 }
784 }
785
786 static void event_handle_menu(Menu *menu, XEvent *e)
787 {
788 MenuEntry *entry;
789
790 g_message("EVENT %d", e->type);
791 switch (e->type) {
792 case ButtonPress:
793 if (e->xbutton.button == 3)
794 menu_hide(menu);
795 break;
796 case ButtonRelease:
797 if (!menu->shown) break;
798
799 /* grab_pointer_window(FALSE, None, menu->frame);*/
800
801 entry = menu_find_entry(menu, e->xbutton.window);
802 if (entry) {
803 int junk;
804 Window wjunk;
805 guint ujunk, b, w, h;
806 XGetGeometry(ob_display, e->xbutton.window,
807 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
808 if (e->xbutton.x >= (signed)-b &&
809 e->xbutton.y >= (signed)-b &&
810 e->xbutton.x < (signed)(w+b) &&
811 e->xbutton.y < (signed)(h+b)) {
812 menu_entry_fire(entry);
813 }
814 }
815 break;
816 case EnterNotify:
817 case LeaveNotify:
818 g_message("enter/leave");
819 entry = menu_find_entry(menu, e->xcrossing.window);
820 if (entry) {
821 entry->hilite = e->type == EnterNotify;
822 menu_entry_render(entry);
823 }
824 break;
825 }
826 }
This page took 0.073868 seconds and 4 git commands to generate.