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