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