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