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