]> Dogcows Code - chaz/openbox/blob - openbox/event.c
remove debug print
[chaz/openbox] / openbox / event.c
1 #include "debug.h"
2 #include "openbox.h"
3 #include "dock.h"
4 #include "client.h"
5 #include "xerror.h"
6 #include "prop.h"
7 #include "config.h"
8 #include "screen.h"
9 #include "frame.h"
10 #include "menu.h"
11 #include "menuframe.h"
12 #include "keyboard.h"
13 #include "mouse.h"
14 #include "mainloop.h"
15 #include "framerender.h"
16 #include "focus.h"
17 #include "moveresize.h"
18 #include "stacking.h"
19 #include "extensions.h"
20 #include "event.h"
21
22 #include <X11/Xlib.h>
23 #include <X11/keysym.h>
24 #include <X11/Xatom.h>
25 #include <glib.h>
26
27 #ifdef USE_LIBSN
28 # include <libsn/sn.h>
29 #endif
30
31 #ifdef HAVE_SYS_SELECT_H
32 # include <sys/select.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 # include <signal.h>
36 #endif
37
38 #ifdef USE_SM
39 #include <X11/ICE/ICElib.h>
40 #endif
41
42 static void event_process(const XEvent *e, gpointer data);
43 static void event_handle_root(XEvent *e);
44 static void event_handle_menu(XEvent *e);
45 static void event_handle_dock(ObDock *s, XEvent *e);
46 static void event_handle_dockapp(ObDockApp *app, XEvent *e);
47 static void event_handle_client(ObClient *c, XEvent *e);
48
49 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
50 (e)->xfocus.detail == NotifyAncestor || \
51 (e)->xfocus.detail > NotifyNonlinearVirtual)
52 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
53 (e)->xfocus.detail == NotifyInferior || \
54 (e)->xfocus.detail == NotifyAncestor || \
55 (e)->xfocus.detail > NotifyNonlinearVirtual)
56
57 Time event_lasttime = 0;
58
59 /*! The value of the mask for the NumLock modifier */
60 unsigned int NumLockMask;
61 /*! The value of the mask for the ScrollLock modifier */
62 unsigned int ScrollLockMask;
63 /*! The key codes for the modifier keys */
64 static XModifierKeymap *modmap;
65 /*! Table of the constant modifier masks */
66 static const int mask_table[] = {
67 ShiftMask, LockMask, ControlMask, Mod1Mask,
68 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
69 };
70 static int mask_table_size;
71
72 #ifdef USE_SM
73 static void ice_handler(int fd, gpointer conn)
74 {
75 Bool b;
76 IceProcessMessages(conn, NULL, &b);
77 }
78
79 static void ice_watch(IceConn conn, IcePointer data, Bool opening,
80 IcePointer *watch_data)
81 {
82 static gint fd = -1;
83
84 if (opening) {
85 fd = IceConnectionNumber(conn);
86 ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
87 } else {
88 ob_main_loop_fd_remove(ob_main_loop, fd);
89 fd = -1;
90 }
91 }
92 #endif
93
94 #ifdef USE_LIBSN
95 static void sn_handler(const XEvent *e, gpointer display)
96 {
97 XEvent ec;
98 ec = *e;
99 sn_display_process_event(display, &ec);
100 }
101 #endif
102
103
104 void event_startup()
105 {
106 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
107
108 /* get lock masks that are defined by the display (not constant) */
109 modmap = XGetModifierMapping(ob_display);
110 g_assert(modmap);
111 if (modmap && modmap->max_keypermod > 0) {
112 size_t cnt;
113 const size_t size = mask_table_size * modmap->max_keypermod;
114 /* get the values of the keyboard lock modifiers
115 Note: Caps lock is not retrieved the same way as Scroll and Num
116 lock since it doesn't need to be. */
117 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
118 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
119 XK_Scroll_Lock);
120
121 for (cnt = 0; cnt < size; ++cnt) {
122 if (! modmap->modifiermap[cnt]) continue;
123
124 if (num_lock == modmap->modifiermap[cnt])
125 NumLockMask = mask_table[cnt / modmap->max_keypermod];
126 if (scroll_lock == modmap->modifiermap[cnt])
127 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
128 }
129 }
130
131 ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
132
133 #ifdef USE_SM
134 IceAddConnectionWatch(ice_watch, NULL);
135 #endif
136
137 #ifdef USE_LIBSN
138 ob_main_loop_x_add(ob_main_loop, sn_handler, ob_sn_display, NULL);
139 #endif
140 }
141
142 void event_shutdown()
143 {
144 XFreeModifiermap(modmap);
145 }
146
147 static Window event_get_window(XEvent *e)
148 {
149 Window window;
150
151 /* pick a window */
152 switch (e->type) {
153 case SelectionClear:
154 window = RootWindow(ob_display, ob_screen);
155 break;
156 case MapRequest:
157 window = e->xmap.window;
158 break;
159 case UnmapNotify:
160 window = e->xunmap.window;
161 break;
162 case DestroyNotify:
163 window = e->xdestroywindow.window;
164 break;
165 case ConfigureRequest:
166 window = e->xconfigurerequest.window;
167 break;
168 case ConfigureNotify:
169 window = e->xconfigure.window;
170 break;
171 default:
172 #ifdef XKB
173 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
174 switch (((XkbAnyEvent*)e)->xkb_type) {
175 case XkbBellNotify:
176 window = ((XkbBellNotifyEvent*)e)->window;
177 default:
178 window = None;
179 }
180 } else
181 #endif
182 window = e->xany.window;
183 }
184 return window;
185 }
186
187 static void event_set_lasttime(XEvent *e)
188 {
189 Time t = 0;
190
191 /* grab the lasttime and hack up the state */
192 switch (e->type) {
193 case ButtonPress:
194 case ButtonRelease:
195 t = e->xbutton.time;
196 break;
197 case KeyPress:
198 t = e->xkey.time;
199 break;
200 case KeyRelease:
201 t = e->xkey.time;
202 break;
203 case MotionNotify:
204 t = e->xmotion.time;
205 break;
206 case PropertyNotify:
207 t = e->xproperty.time;
208 break;
209 case EnterNotify:
210 case LeaveNotify:
211 t = e->xcrossing.time;
212 break;
213 default:
214 /* if more event types are anticipated, get their timestamp
215 explicitly */
216 break;
217 }
218
219 if (t > event_lasttime)
220 event_lasttime = t;
221 }
222
223 #define STRIP_MODS(s) \
224 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
225 /* kill off the Button1Mask etc, only want the modifiers */ \
226 s &= (ControlMask | ShiftMask | Mod1Mask | \
227 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
228
229 static void event_hack_mods(XEvent *e)
230 {
231 KeyCode *kp;
232 int i, k;
233
234 switch (e->type) {
235 case ButtonPress:
236 case ButtonRelease:
237 STRIP_MODS(e->xbutton.state);
238 break;
239 case KeyPress:
240 STRIP_MODS(e->xkey.state);
241 break;
242 case KeyRelease:
243 STRIP_MODS(e->xkey.state);
244 /* remove from the state the mask of the modifier being released, if
245 it is a modifier key being released (this is a little ugly..) */
246 kp = modmap->modifiermap;
247 for (i = 0; i < mask_table_size; ++i) {
248 for (k = 0; k < modmap->max_keypermod; ++k) {
249 if (*kp == e->xkey.keycode) { /* found the keycode */
250 /* remove the mask for it */
251 e->xkey.state &= ~mask_table[i];
252 /* cause the first loop to break; */
253 i = mask_table_size;
254 break; /* get outta here! */
255 }
256 ++kp;
257 }
258 }
259 break;
260 case MotionNotify:
261 STRIP_MODS(e->xmotion.state);
262 /* compress events */
263 {
264 XEvent ce;
265 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
266 e->type, &ce)) {
267 e->xmotion.x_root = ce.xmotion.x_root;
268 e->xmotion.y_root = ce.xmotion.y_root;
269 }
270 }
271 break;
272 }
273 }
274
275 static gboolean event_ignore(XEvent *e, ObClient *client)
276 {
277 switch(e->type) {
278 case FocusIn:
279 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
280 because of RevertToPointerRoot. If the focus ends up reverting to
281 pointer root on a workspace change, then the FocusIn event that we
282 want will be of type NotifyAncestor. This situation does not occur
283 for FocusOut, so it is safely ignored there.
284 */
285 if (INVALID_FOCUSIN(e) ||
286 client == NULL) {
287 #ifdef DEBUG_FOCUS
288 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
289 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
290 #endif
291 /* says a client was not found for the event (or a valid FocusIn
292 event was not found.
293 */
294 e->xfocus.window = None;
295 return TRUE;
296 }
297
298 #ifdef DEBUG_FOCUS
299 ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
300 e->xfocus.mode, e->xfocus.detail);
301 #endif
302 break;
303 case FocusOut:
304 if (INVALID_FOCUSOUT(e)) {
305 #ifdef DEBUG_FOCUS
306 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
307 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
308 #endif
309 return TRUE;
310 }
311
312 #ifdef DEBUG_FOCUS
313 ob_debug("FocusOut on %lx mode %d detail %d\n",
314 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
315 #endif
316
317 {
318 XEvent fe;
319 gboolean fallback = TRUE;
320
321 while (TRUE) {
322 if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window,
323 FocusOut, &fe))
324 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
325 break;
326 if (fe.type == FocusOut) {
327 #ifdef DEBUG_FOCUS
328 ob_debug("found pending FocusOut");
329 #endif
330 if (!INVALID_FOCUSOUT(&fe)) {
331 /* if there is a VALID FocusOut still coming, don't
332 fallback focus yet, we'll deal with it then */
333 XPutBackEvent(ob_display, &fe);
334 fallback = FALSE;
335 break;
336 }
337 } else {
338 #ifdef DEBUG_FOCUS
339 ob_debug("found pending FocusIn");
340 #endif
341 /* is the focused window getting a FocusOut/In back to
342 itself?
343 */
344 if (fe.xfocus.window == e->xfocus.window &&
345 !event_ignore(&fe, client)) {
346 /*
347 if focus_client is not set, then we can't do
348 this. we need the FocusIn. This happens in the
349 case when the set_focus_client(NULL) in the
350 focus_fallback function fires and then
351 focus_fallback picks the currently focused
352 window (such as on a SendToDesktop-esque action.
353 */
354 if (focus_client) {
355 #ifdef DEBUG_FOCUS
356 ob_debug("focused window got an Out/In back to "
357 "itself IGNORED both");
358 #endif
359 return TRUE;
360 } else {
361 event_process(&fe, NULL);
362 #ifdef DEBUG_FOCUS
363 ob_debug("focused window got an Out/In back to "
364 "itself but focus_client was null "
365 "IGNORED just the Out");
366 #endif
367 return TRUE;
368 }
369 }
370
371 /* once all the FocusOut's have been dealt with, if there
372 is a FocusIn still left and it is valid, then use it */
373 event_process(&fe, NULL);
374 /* secret magic way of event_process telling us that no
375 client was found for the FocusIn event. ^_^ */
376 if (fe.xfocus.window != None) {
377 fallback = FALSE;
378 break;
379 }
380 }
381 }
382 if (fallback) {
383 #ifdef DEBUG_FOCUS
384 ob_debug("no valid FocusIn and no FocusOut events found, "
385 "falling back");
386 #endif
387 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
388 }
389 }
390 break;
391 case EnterNotify:
392 case LeaveNotify:
393 /* NotifyUngrab occurs when a mouse button is released and the event is
394 caused, like when lowering a window */
395 /* NotifyVirtual occurs when ungrabbing the pointer */
396 if (e->xcrossing.mode == NotifyGrab ||
397 e->xcrossing.detail == NotifyInferior ||
398 (e->xcrossing.mode == NotifyUngrab &&
399 e->xcrossing.detail == NotifyVirtual)) {
400 #ifdef DEBUG_FOCUS
401 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
402 (e->type == EnterNotify ? "Enter" : "Leave"),
403 e->xcrossing.mode,
404 e->xcrossing.detail, client?client->window:0);
405 #endif
406 return TRUE;
407 }
408 #ifdef DEBUG_FOCUS
409 ob_debug("%sNotify mode %d detail %d on %lx",
410 (e->type == EnterNotify ? "Enter" : "Leave"),
411 e->xcrossing.mode,
412 e->xcrossing.detail, client?client->window:0);
413 #endif
414 break;
415 }
416 return FALSE;
417 }
418
419 static void event_process(const XEvent *ec, gpointer data)
420 {
421 Window window;
422 ObClient *client = NULL;
423 ObDock *dock = NULL;
424 ObDockApp *dockapp = NULL;
425 ObWindow *obwin = NULL;
426 XEvent ee, *e;
427
428 /* make a copy we can mangle */
429 ee = *ec;
430 e = &ee;
431
432 window = event_get_window(e);
433 if ((obwin = g_hash_table_lookup(window_map, &window))) {
434 switch (obwin->type) {
435 case Window_Dock:
436 dock = WINDOW_AS_DOCK(obwin);
437 break;
438 case Window_DockApp:
439 dockapp = WINDOW_AS_DOCKAPP(obwin);
440 break;
441 case Window_Client:
442 client = WINDOW_AS_CLIENT(obwin);
443 break;
444 case Window_Menu:
445 case Window_Internal:
446 /* not to be used for events */
447 g_assert_not_reached();
448 break;
449 }
450 }
451
452 event_set_lasttime(e);
453 event_hack_mods(e);
454 if (event_ignore(e, client))
455 return;
456
457 /* deal with it in the kernel */
458 if (client)
459 event_handle_client(client, e);
460 else if (dockapp)
461 event_handle_dockapp(dockapp, e);
462 else if (dock)
463 event_handle_dock(dock, e);
464 else if (window == RootWindow(ob_display, ob_screen))
465 event_handle_root(e);
466 else if (e->type == MapRequest)
467 client_manage(window);
468 else if (e->type == ConfigureRequest) {
469 /* unhandled configure requests must be used to configure the
470 window directly */
471 XWindowChanges xwc;
472
473 xwc.x = e->xconfigurerequest.x;
474 xwc.y = e->xconfigurerequest.y;
475 xwc.width = e->xconfigurerequest.width;
476 xwc.height = e->xconfigurerequest.height;
477 xwc.border_width = e->xconfigurerequest.border_width;
478 xwc.sibling = e->xconfigurerequest.above;
479 xwc.stack_mode = e->xconfigurerequest.detail;
480
481 /* we are not to be held responsible if someone sends us an
482 invalid request! */
483 xerror_set_ignore(TRUE);
484 XConfigureWindow(ob_display, window,
485 e->xconfigurerequest.value_mask, &xwc);
486 xerror_set_ignore(FALSE);
487 }
488
489 /* user input (action-bound) events */
490 if (e->type == ButtonPress || e->type == ButtonRelease ||
491 e->type == MotionNotify || e->type == KeyPress ||
492 e->type == KeyRelease)
493 {
494 if (menu_frame_visible)
495 event_handle_menu(e);
496 else if (moveresize_in_progress)
497 moveresize_event(e);
498 else {
499 ObFrameContext context;
500
501 context = frame_context(client, e->xany.window);
502
503 if (!keyboard_process_interactive_grab(e, &client, &context)) {
504 if (e->type == ButtonPress || e->type == ButtonRelease ||
505 e->type == MotionNotify)
506 mouse_event(client, context, e);
507 else if (e->type == KeyPress)
508 keyboard_event(client, e);
509 }
510 }
511 }
512 }
513
514 static void event_handle_root(XEvent *e)
515 {
516 Atom msgtype;
517
518 switch(e->type) {
519 case SelectionClear:
520 ob_debug("Another WM has requested to replace us. Exiting.\n");
521 ob_exit();
522 break;
523
524 case ClientMessage:
525 if (e->xclient.format != 32) break;
526
527 msgtype = e->xclient.message_type;
528 if (msgtype == prop_atoms.net_current_desktop) {
529 unsigned int d = e->xclient.data.l[0];
530 if (d < screen_num_desktops)
531 screen_set_desktop(d);
532 } else if (msgtype == prop_atoms.net_number_of_desktops) {
533 unsigned int d = e->xclient.data.l[0];
534 if (d > 0)
535 screen_set_num_desktops(d);
536 } else if (msgtype == prop_atoms.net_showing_desktop) {
537 screen_show_desktop(e->xclient.data.l[0] != 0);
538 }
539 break;
540 case PropertyNotify:
541 if (e->xproperty.atom == prop_atoms.net_desktop_names)
542 screen_update_desktop_names();
543 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
544 screen_update_layout();
545 break;
546 case ConfigureNotify:
547 #ifdef XRANDR
548 XRRUpdateConfiguration(e);
549 #endif
550 screen_resize();
551 break;
552 default:
553 ;
554 #ifdef VIDMODE
555 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
556 ob_debug("VIDMODE EVENT\n");
557 }
558 #endif
559 }
560 }
561
562 static void event_handle_client(ObClient *client, XEvent *e)
563 {
564 XEvent ce;
565 Atom msgtype;
566 int i=0;
567 ObFrameContext con;
568
569 switch (e->type) {
570 case VisibilityNotify:
571 client->frame->obscured = e->xvisibility.state != VisibilityUnobscured;
572 break;
573 case ButtonPress:
574 case ButtonRelease:
575 /* Wheel buttons don't draw because they are an instant click, so it
576 is a waste of resources to go drawing it. */
577 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
578 switch (frame_context(client, e->xbutton.window)) {
579 case OB_FRAME_CONTEXT_MAXIMIZE:
580 client->frame->max_press = (e->type == ButtonPress);
581 framerender_frame(client->frame);
582 break;
583 case OB_FRAME_CONTEXT_CLOSE:
584 client->frame->close_press = (e->type == ButtonPress);
585 framerender_frame(client->frame);
586 break;
587 case OB_FRAME_CONTEXT_ICONIFY:
588 client->frame->iconify_press = (e->type == ButtonPress);
589 framerender_frame(client->frame);
590 break;
591 case OB_FRAME_CONTEXT_ALLDESKTOPS:
592 client->frame->desk_press = (e->type == ButtonPress);
593 framerender_frame(client->frame);
594 break;
595 case OB_FRAME_CONTEXT_SHADE:
596 client->frame->shade_press = (e->type == ButtonPress);
597 framerender_frame(client->frame);
598 break;
599 default:
600 /* nothing changes with clicks for any other contexts */
601 break;
602 }
603 }
604 break;
605 case FocusIn:
606 #ifdef DEBUG_FOCUS
607 ob_debug("FocusIn on client for %lx\n", client->window);
608 #endif
609 if (client != focus_client) {
610 focus_set_client(client);
611 frame_adjust_focus(client->frame, TRUE);
612 }
613 break;
614 case FocusOut:
615 #ifdef DEBUG_FOCUS
616 ob_debug("FocusOut on client for %lx\n", client->window);
617 #endif
618 /* are we a fullscreen window or a transient of one? (checks layer)
619 if we are then we need to be iconified since we are losing focus
620 */
621 if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic &&
622 !client_search_focus_tree_full(client))
623 /* iconify fullscreen windows when they and their transients
624 aren't focused */
625 client_iconify(client, TRUE, TRUE);
626 frame_adjust_focus(client->frame, FALSE);
627 break;
628 case LeaveNotify:
629 con = frame_context(client, e->xcrossing.window);
630 switch (con) {
631 case OB_FRAME_CONTEXT_MAXIMIZE:
632 client->frame->max_hover = FALSE;
633 frame_adjust_state(client->frame);
634 break;
635 case OB_FRAME_CONTEXT_ALLDESKTOPS:
636 client->frame->desk_hover = FALSE;
637 frame_adjust_state(client->frame);
638 break;
639 case OB_FRAME_CONTEXT_SHADE:
640 client->frame->shade_hover = FALSE;
641 frame_adjust_state(client->frame);
642 break;
643 case OB_FRAME_CONTEXT_ICONIFY:
644 client->frame->iconify_hover = FALSE;
645 frame_adjust_state(client->frame);
646 break;
647 case OB_FRAME_CONTEXT_CLOSE:
648 client->frame->close_hover = FALSE;
649 frame_adjust_state(client->frame);
650 break;
651 default:
652 break;
653 }
654 break;
655 case EnterNotify:
656 con = frame_context(client, e->xcrossing.window);
657 switch (con) {
658 case OB_FRAME_CONTEXT_MAXIMIZE:
659 client->frame->max_hover = TRUE;
660 frame_adjust_state(client->frame);
661 break;
662 case OB_FRAME_CONTEXT_ALLDESKTOPS:
663 client->frame->desk_hover = TRUE;
664 frame_adjust_state(client->frame);
665 break;
666 case OB_FRAME_CONTEXT_SHADE:
667 client->frame->shade_hover = TRUE;
668 frame_adjust_state(client->frame);
669 break;
670 case OB_FRAME_CONTEXT_ICONIFY:
671 client->frame->iconify_hover = TRUE;
672 frame_adjust_state(client->frame);
673 break;
674 case OB_FRAME_CONTEXT_CLOSE:
675 client->frame->close_hover = TRUE;
676 frame_adjust_state(client->frame);
677 break;
678 case OB_FRAME_CONTEXT_FRAME:
679 if (client_normal(client)) {
680 if (ob_state() == OB_STATE_STARTING) {
681 /* move it to the top of the focus order */
682 guint desktop = client->desktop;
683 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
684 focus_order[desktop] = g_list_remove(focus_order[desktop],
685 client);
686 focus_order[desktop] = g_list_prepend(focus_order[desktop],
687 client);
688 } else if (config_focus_follow) {
689 #ifdef DEBUG_FOCUS
690 ob_debug("EnterNotify on %lx, focusing window\n",
691 client->window);
692 #endif
693 client_focus(client);
694 }
695 }
696 break;
697 default:
698 break;
699 }
700 break;
701 case ConfigureRequest:
702 /* compress these */
703 while (XCheckTypedWindowEvent(ob_display, client->window,
704 ConfigureRequest, &ce)) {
705 ++i;
706 /* XXX if this causes bad things.. we can compress config req's
707 with the same mask. */
708 e->xconfigurerequest.value_mask |=
709 ce.xconfigurerequest.value_mask;
710 if (ce.xconfigurerequest.value_mask & CWX)
711 e->xconfigurerequest.x = ce.xconfigurerequest.x;
712 if (ce.xconfigurerequest.value_mask & CWY)
713 e->xconfigurerequest.y = ce.xconfigurerequest.y;
714 if (ce.xconfigurerequest.value_mask & CWWidth)
715 e->xconfigurerequest.width = ce.xconfigurerequest.width;
716 if (ce.xconfigurerequest.value_mask & CWHeight)
717 e->xconfigurerequest.height = ce.xconfigurerequest.height;
718 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
719 e->xconfigurerequest.border_width =
720 ce.xconfigurerequest.border_width;
721 if (ce.xconfigurerequest.value_mask & CWStackMode)
722 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
723 }
724
725 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
726 if (client->iconic || client->shaded) return;
727
728 /* resize, then move, as specified in the EWMH section 7.7 */
729 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
730 CWX | CWY |
731 CWBorderWidth)) {
732 int x, y, w, h;
733 ObCorner corner;
734
735 if (e->xconfigurerequest.value_mask & CWBorderWidth)
736 client->border_width = e->xconfigurerequest.border_width;
737
738 x = (e->xconfigurerequest.value_mask & CWX) ?
739 e->xconfigurerequest.x : client->area.x;
740 y = (e->xconfigurerequest.value_mask & CWY) ?
741 e->xconfigurerequest.y : client->area.y;
742 w = (e->xconfigurerequest.value_mask & CWWidth) ?
743 e->xconfigurerequest.width : client->area.width;
744 h = (e->xconfigurerequest.value_mask & CWHeight) ?
745 e->xconfigurerequest.height : client->area.height;
746
747 {
748 int newx = x;
749 int newy = y;
750 int fw = w +
751 client->frame->size.left + client->frame->size.right;
752 int fh = h +
753 client->frame->size.top + client->frame->size.bottom;
754 client_find_onscreen(client, &newx, &newy, fw, fh,
755 client_normal(client));
756 if (e->xconfigurerequest.value_mask & CWX)
757 x = newx;
758 if (e->xconfigurerequest.value_mask & CWY)
759 y = newy;
760 }
761
762 switch (client->gravity) {
763 case NorthEastGravity:
764 case EastGravity:
765 corner = OB_CORNER_TOPRIGHT;
766 break;
767 case SouthWestGravity:
768 case SouthGravity:
769 corner = OB_CORNER_BOTTOMLEFT;
770 break;
771 case SouthEastGravity:
772 corner = OB_CORNER_BOTTOMRIGHT;
773 break;
774 default: /* NorthWest, Static, etc */
775 corner = OB_CORNER_TOPLEFT;
776 }
777
778 client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
779 TRUE);
780 }
781
782 if (e->xconfigurerequest.value_mask & CWStackMode) {
783 switch (e->xconfigurerequest.detail) {
784 case Below:
785 case BottomIf:
786 stacking_lower(CLIENT_AS_WINDOW(client));
787 break;
788
789 case Above:
790 case TopIf:
791 default:
792 stacking_raise(CLIENT_AS_WINDOW(client));
793 break;
794 }
795 }
796 break;
797 case UnmapNotify:
798 if (client->ignore_unmaps) {
799 client->ignore_unmaps--;
800 break;
801 }
802 client_unmanage(client);
803 break;
804 case DestroyNotify:
805 client_unmanage(client);
806 break;
807 case ReparentNotify:
808 /* this is when the client is first taken captive in the frame */
809 if (e->xreparent.parent == client->frame->plate) break;
810
811 /*
812 This event is quite rare and is usually handled in unmapHandler.
813 However, if the window is unmapped when the reparent event occurs,
814 the window manager never sees it because an unmap event is not sent
815 to an already unmapped window.
816 */
817
818 /* we don't want the reparent event, put it back on the stack for the
819 X server to deal with after we unmanage the window */
820 XPutBackEvent(ob_display, e);
821
822 client_unmanage(client);
823 break;
824 case MapRequest:
825 ob_debug("MapRequest for 0x%lx\n", client->window);
826 if (!client->iconic) break; /* this normally doesn't happen, but if it
827 does, we don't want it! */
828 if (screen_showing_desktop)
829 screen_show_desktop(FALSE);
830 client_iconify(client, FALSE, TRUE);
831 if (!client->frame->visible)
832 /* if its not visible still, then don't mess with it */
833 break;
834 if (client->shaded)
835 client_shade(client, FALSE);
836 client_focus(client);
837 stacking_raise(CLIENT_AS_WINDOW(client));
838 break;
839 case ClientMessage:
840 /* validate cuz we query stuff off the client here */
841 if (!client_validate(client)) break;
842
843 if (e->xclient.format != 32) return;
844
845 msgtype = e->xclient.message_type;
846 if (msgtype == prop_atoms.wm_change_state) {
847 /* compress changes into a single change */
848 while (XCheckTypedWindowEvent(ob_display, client->window,
849 e->type, &ce)) {
850 /* XXX: it would be nice to compress ALL messages of a
851 type, not just messages in a row without other
852 message types between. */
853 if (ce.xclient.message_type != msgtype) {
854 XPutBackEvent(ob_display, &ce);
855 break;
856 }
857 e->xclient = ce.xclient;
858 }
859 client_set_wm_state(client, e->xclient.data.l[0]);
860 } else if (msgtype == prop_atoms.net_wm_desktop) {
861 /* compress changes into a single change */
862 while (XCheckTypedWindowEvent(ob_display, client->window,
863 e->type, &ce)) {
864 /* XXX: it would be nice to compress ALL messages of a
865 type, not just messages in a row without other
866 message types between. */
867 if (ce.xclient.message_type != msgtype) {
868 XPutBackEvent(ob_display, &ce);
869 break;
870 }
871 e->xclient = ce.xclient;
872 }
873 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
874 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
875 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
876 FALSE);
877 } else if (msgtype == prop_atoms.net_wm_state) {
878 /* can't compress these */
879 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
880 (e->xclient.data.l[0] == 0 ? "Remove" :
881 e->xclient.data.l[0] == 1 ? "Add" :
882 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
883 e->xclient.data.l[1], e->xclient.data.l[2],
884 client->window);
885 client_set_state(client, e->xclient.data.l[0],
886 e->xclient.data.l[1], e->xclient.data.l[2]);
887 } else if (msgtype == prop_atoms.net_close_window) {
888 ob_debug("net_close_window for 0x%lx\n", client->window);
889 client_close(client);
890 } else if (msgtype == prop_atoms.net_active_window) {
891 ob_debug("net_active_window for 0x%lx\n", client->window);
892 client_activate(client, FALSE);
893 } else if (msgtype == prop_atoms.net_wm_moveresize) {
894 ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
895 if ((Atom)e->xclient.data.l[2] ==
896 prop_atoms.net_wm_moveresize_size_topleft ||
897 (Atom)e->xclient.data.l[2] ==
898 prop_atoms.net_wm_moveresize_size_top ||
899 (Atom)e->xclient.data.l[2] ==
900 prop_atoms.net_wm_moveresize_size_topright ||
901 (Atom)e->xclient.data.l[2] ==
902 prop_atoms.net_wm_moveresize_size_right ||
903 (Atom)e->xclient.data.l[2] ==
904 prop_atoms.net_wm_moveresize_size_right ||
905 (Atom)e->xclient.data.l[2] ==
906 prop_atoms.net_wm_moveresize_size_bottomright ||
907 (Atom)e->xclient.data.l[2] ==
908 prop_atoms.net_wm_moveresize_size_bottom ||
909 (Atom)e->xclient.data.l[2] ==
910 prop_atoms.net_wm_moveresize_size_bottomleft ||
911 (Atom)e->xclient.data.l[2] ==
912 prop_atoms.net_wm_moveresize_size_left ||
913 (Atom)e->xclient.data.l[2] ==
914 prop_atoms.net_wm_moveresize_move ||
915 (Atom)e->xclient.data.l[2] ==
916 prop_atoms.net_wm_moveresize_size_keyboard ||
917 (Atom)e->xclient.data.l[2] ==
918 prop_atoms.net_wm_moveresize_move_keyboard) {
919
920 moveresize_start(client, e->xclient.data.l[0],
921 e->xclient.data.l[1], e->xclient.data.l[3],
922 e->xclient.data.l[2]);
923 }
924 } else if (msgtype == prop_atoms.net_moveresize_window) {
925 int oldg = client->gravity;
926 int tmpg, x, y, w, h;
927
928 if (e->xclient.data.l[0] & 0xff)
929 tmpg = e->xclient.data.l[0] & 0xff;
930 else
931 tmpg = oldg;
932
933 if (e->xclient.data.l[0] & 1 << 8)
934 x = e->xclient.data.l[1];
935 else
936 x = client->area.x;
937 if (e->xclient.data.l[0] & 1 << 9)
938 y = e->xclient.data.l[2];
939 else
940 y = client->area.y;
941 if (e->xclient.data.l[0] & 1 << 10)
942 w = e->xclient.data.l[3];
943 else
944 w = client->area.width;
945 if (e->xclient.data.l[0] & 1 << 11)
946 h = e->xclient.data.l[4];
947 else
948 h = client->area.height;
949 client->gravity = tmpg;
950
951 {
952 int newx = x;
953 int newy = y;
954 int fw = w +
955 client->frame->size.left + client->frame->size.right;
956 int fh = h +
957 client->frame->size.top + client->frame->size.bottom;
958 client_find_onscreen(client, &newx, &newy, fw, fh,
959 client_normal(client));
960 if (e->xclient.data.l[0] & 1 << 8)
961 x = newx;
962 if (e->xclient.data.l[0] & 1 << 9)
963 y = newy;
964 }
965
966 client_configure(client, OB_CORNER_TOPLEFT,
967 x, y, w, h, FALSE, TRUE);
968
969 client->gravity = oldg;
970 }
971 break;
972 case PropertyNotify:
973 /* validate cuz we query stuff off the client here */
974 if (!client_validate(client)) break;
975
976 /* compress changes to a single property into a single change */
977 while (XCheckTypedWindowEvent(ob_display, client->window,
978 e->type, &ce)) {
979 Atom a, b;
980
981 /* XXX: it would be nice to compress ALL changes to a property,
982 not just changes in a row without other props between. */
983
984 a = ce.xproperty.atom;
985 b = e->xproperty.atom;
986
987 if (a == b)
988 continue;
989 if ((a == prop_atoms.net_wm_name ||
990 a == prop_atoms.wm_name ||
991 a == prop_atoms.net_wm_icon_name ||
992 a == prop_atoms.wm_icon_name)
993 &&
994 (b == prop_atoms.net_wm_name ||
995 b == prop_atoms.wm_name ||
996 b == prop_atoms.net_wm_icon_name ||
997 b == prop_atoms.wm_icon_name)) {
998 continue;
999 }
1000 if ((a == prop_atoms.net_wm_icon ||
1001 a == prop_atoms.kwm_win_icon)
1002 &&
1003 (b == prop_atoms.net_wm_icon ||
1004 b == prop_atoms.kwm_win_icon))
1005 continue;
1006
1007 XPutBackEvent(ob_display, &ce);
1008 break;
1009 }
1010
1011 msgtype = e->xproperty.atom;
1012 if (msgtype == XA_WM_NORMAL_HINTS) {
1013 client_update_normal_hints(client);
1014 /* normal hints can make a window non-resizable */
1015 client_setup_decor_and_functions(client);
1016 } else if (msgtype == XA_WM_HINTS) {
1017 client_update_wmhints(client);
1018 } else if (msgtype == XA_WM_TRANSIENT_FOR) {
1019 client_update_transient_for(client);
1020 client_get_type(client);
1021 /* type may have changed, so update the layer */
1022 client_calc_layer(client);
1023 client_setup_decor_and_functions(client);
1024 } else if (msgtype == prop_atoms.net_wm_name ||
1025 msgtype == prop_atoms.wm_name ||
1026 msgtype == prop_atoms.net_wm_icon_name ||
1027 msgtype == prop_atoms.wm_icon_name) {
1028 client_update_title(client);
1029 } else if (msgtype == prop_atoms.wm_class) {
1030 client_update_class(client);
1031 } else if (msgtype == prop_atoms.wm_protocols) {
1032 client_update_protocols(client);
1033 client_setup_decor_and_functions(client);
1034 }
1035 else if (msgtype == prop_atoms.net_wm_strut) {
1036 client_update_strut(client);
1037 }
1038 else if (msgtype == prop_atoms.net_wm_icon ||
1039 msgtype == prop_atoms.kwm_win_icon) {
1040 client_update_icons(client);
1041 }
1042 default:
1043 ;
1044 #ifdef SHAPE
1045 if (extensions_shape && e->type == extensions_shape_event_basep) {
1046 client->shaped = ((XShapeEvent*)e)->shaped;
1047 frame_adjust_shape(client->frame);
1048 }
1049 #endif
1050 }
1051 }
1052
1053 static void event_handle_dock(ObDock *s, XEvent *e)
1054 {
1055 switch (e->type) {
1056 case ButtonPress:
1057 stacking_raise(DOCK_AS_WINDOW(s));
1058 break;
1059 case EnterNotify:
1060 dock_hide(FALSE);
1061 break;
1062 case LeaveNotify:
1063 dock_hide(TRUE);
1064 break;
1065 }
1066 }
1067
1068 static void event_handle_dockapp(ObDockApp *app, XEvent *e)
1069 {
1070 switch (e->type) {
1071 case MotionNotify:
1072 dock_app_drag(app, &e->xmotion);
1073 break;
1074 case UnmapNotify:
1075 if (app->ignore_unmaps) {
1076 app->ignore_unmaps--;
1077 break;
1078 }
1079 dock_remove(app, TRUE);
1080 break;
1081 case DestroyNotify:
1082 dock_remove(app, FALSE);
1083 break;
1084 case ReparentNotify:
1085 dock_remove(app, FALSE);
1086 break;
1087 case ConfigureNotify:
1088 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
1089 break;
1090 }
1091 }
1092
1093 ObMenuFrame* find_active_menu()
1094 {
1095 GList *it;
1096 ObMenuFrame *f;
1097
1098 for (it = menu_frame_visible; it; it = g_list_next(it)) {
1099 f = it->data;
1100 if (f->selected)
1101 break;
1102 }
1103 return it ? it->data : NULL;
1104 }
1105
1106 static void event_handle_menu(XEvent *ev)
1107 {
1108 ObMenuFrame *f;
1109 ObMenuEntryFrame *e;
1110
1111 switch (ev->type) {
1112 case ButtonRelease:
1113 if (!(f = menu_frame_under(ev->xbutton.x_root,
1114 ev->xbutton.y_root)))
1115 menu_frame_hide_all();
1116 else {
1117 if ((e = menu_entry_frame_under(ev->xbutton.x_root,
1118 ev->xbutton.y_root)))
1119 menu_entry_frame_execute(e,
1120 !(ev->xbutton.state & ControlMask));
1121 }
1122 break;
1123 case MotionNotify:
1124 if ((f = menu_frame_under(ev->xmotion.x_root,
1125 ev->xmotion.y_root))) {
1126 menu_frame_move_on_screen(f);
1127 if ((e = menu_entry_frame_under(ev->xmotion.x_root,
1128 ev->xmotion.y_root)))
1129 menu_frame_select(f, e);
1130 }
1131 break;
1132 case KeyPress:
1133 if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
1134 menu_frame_hide_all();
1135 else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
1136 ObMenuFrame *f;
1137 if ((f = find_active_menu()))
1138 menu_entry_frame_execute(f->selected,
1139 !(ev->xkey.state & ControlMask));
1140 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
1141 ObMenuFrame *f;
1142 if ((f = find_active_menu()) && f->parent)
1143 menu_frame_select(f, NULL);
1144 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
1145 ObMenuFrame *f;
1146 if ((f = find_active_menu()) && f->child)
1147 menu_frame_select_next(f->child);
1148 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
1149 ObMenuFrame *f;
1150 if ((f = find_active_menu()))
1151 menu_frame_select_previous(f);
1152 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
1153 ObMenuFrame *f;
1154 if ((f = find_active_menu()))
1155 menu_frame_select_next(f);
1156 }
1157 break;
1158 }
1159 }
This page took 0.084809 seconds and 4 git commands to generate.