]> Dogcows Code - chaz/openbox/blob - openbox/event.c
e9e85f0be2c3ef7efbc576f9955573aba888aa57
[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(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 (client)
505 event_handle_client(client, e);
506 else if (dockapp)
507 event_handle_dockapp(dockapp, e);
508 else if (dock)
509 event_handle_dock(dock, e);
510 else if (window == ob_root)
511 event_handle_root(e);
512 else if (e->type == MapRequest)
513 client_manage(window);
514 else if (e->type == ConfigureRequest) {
515 /* unhandled configure requests must be used to configure the
516 window directly */
517 XWindowChanges xwc;
518
519 xwc.x = e->xconfigurerequest.x;
520 xwc.y = e->xconfigurerequest.y;
521 xwc.width = e->xconfigurerequest.width;
522 xwc.height = e->xconfigurerequest.height;
523 xwc.border_width = e->xconfigurerequest.border_width;
524 xwc.sibling = e->xconfigurerequest.above;
525 xwc.stack_mode = e->xconfigurerequest.detail;
526
527 /* we are not to be held responsible if someone sends us an
528 invalid request! */
529 xerror_set_ignore(TRUE);
530 XConfigureWindow(ob_display, window,
531 e->xconfigurerequest.value_mask, &xwc);
532 xerror_set_ignore(FALSE);
533 }
534
535 if (menu_visible)
536 if (e->type == MotionNotify || e->type == ButtonRelease ||
537 e->type == ButtonPress ||
538 e->type == KeyPress || e->type == KeyRelease) {
539 event_handle_menu(client, e);
540
541 return; /* no dispatch! */
542 }
543
544 if (moveresize_in_progress)
545 if (e->type == MotionNotify || e->type == ButtonRelease ||
546 e->type == ButtonPress ||
547 e->type == KeyPress || e->type == KeyRelease) {
548 moveresize_event(e);
549
550 return; /* no dispatch! */
551
552 }
553
554 /* user input (action-bound) events */
555 /*
556 if (e->type == ButtonPress || e->type == ButtonRelease ||
557 e->type == MotionNotify)
558 mouse_event(e, client);
559 else if (e->type == KeyPress || e->type == KeyRelease)
560 ;
561 */
562
563 /* dispatch the event to registered handlers */
564 dispatch_x(e, client);
565 }
566
567 static void event_handle_root(XEvent *e)
568 {
569 Atom msgtype;
570
571 switch(e->type) {
572 case ClientMessage:
573 if (e->xclient.format != 32) break;
574
575 msgtype = e->xclient.message_type;
576 if (msgtype == prop_atoms.net_current_desktop) {
577 unsigned int d = e->xclient.data.l[0];
578 if (d < screen_num_desktops)
579 screen_set_desktop(d);
580 } else if (msgtype == prop_atoms.net_number_of_desktops) {
581 unsigned int d = e->xclient.data.l[0];
582 if (d > 0)
583 screen_set_num_desktops(d);
584 } else if (msgtype == prop_atoms.net_showing_desktop) {
585 screen_show_desktop(e->xclient.data.l[0] != 0);
586 }
587 break;
588 case PropertyNotify:
589 if (e->xproperty.atom == prop_atoms.net_desktop_names)
590 screen_update_desktop_names();
591 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
592 screen_update_layout();
593 break;
594 case ConfigureNotify:
595 #ifdef XRANDR
596 XRRUpdateConfiguration(e);
597 #endif
598 if (e->xconfigure.width != screen_physical_size.width ||
599 e->xconfigure.height != screen_physical_size.height)
600 screen_resize(e->xconfigure.width, e->xconfigure.height);
601 break;
602 default:
603 ;
604 #ifdef VIDMODE
605 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
606 g_message("VIDMODE EVENT");
607 }
608 #endif
609 }
610 }
611
612 static void event_handle_client(Client *client, XEvent *e)
613 {
614 XEvent ce;
615 Atom msgtype;
616 int i=0;
617
618 switch (e->type) {
619 case ButtonPress:
620 case ButtonRelease:
621 /* Wheel buttons don't draw because they are an instant click, so it
622 is a waste of resources to go drawing it. */
623 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
624 switch (frame_context(client, e->xbutton.window)) {
625 case Context_Maximize:
626 client->frame->max_press = (e->type == ButtonPress);
627 framerender_frame(client->frame);
628 break;
629 case Context_Close:
630 client->frame->close_press = (e->type == ButtonPress);
631 framerender_frame(client->frame);
632 break;
633 case Context_Iconify:
634 client->frame->iconify_press = (e->type == ButtonPress);
635 framerender_frame(client->frame);
636 break;
637 case Context_AllDesktops:
638 client->frame->desk_press = (e->type == ButtonPress);
639 framerender_frame(client->frame);
640 break;
641 case Context_Shade:
642 client->frame->shade_press = (e->type == ButtonPress);
643 framerender_frame(client->frame);
644 break;
645 default:
646 /* nothing changes with clicks for any other contexts */
647 break;
648 }
649 }
650 break;
651 case FocusIn:
652 #ifdef DEBUG_FOCUS
653 g_message("FocusIn on client for %lx", client->window);
654 #endif
655 if (client != focus_client) {
656 focus_set_client(client);
657 frame_adjust_focus(client->frame, TRUE);
658 }
659 break;
660 case FocusOut:
661 #ifdef DEBUG_FOCUS
662 g_message("FocusOut on client for %lx", client->window);
663 #endif
664 /* are we a fullscreen window or a transient of one? (checks layer)
665 if we are then we need to be iconified since we are losing focus
666 */
667 if (client->layer == Layer_Fullscreen && !client->iconic &&
668 !client_search_focus_tree_full(client))
669 /* iconify fullscreen windows when they and their transients
670 aren't focused */
671 client_iconify(client, TRUE, TRUE);
672 frame_adjust_focus(client->frame, FALSE);
673 break;
674 case EnterNotify:
675 if (client_normal(client)) {
676 if (ob_state == State_Starting) {
677 /* move it to the top of the focus order */
678 guint desktop = client->desktop;
679 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
680 focus_order[desktop] = g_list_remove(focus_order[desktop],
681 client);
682 focus_order[desktop] = g_list_prepend(focus_order[desktop],
683 client);
684 } else if (config_focus_follow) {
685 #ifdef DEBUG_FOCUS
686 g_message("EnterNotify on %lx, focusing window",
687 client->window);
688 #endif
689 client_focus(client);
690 }
691 }
692 break;
693 case ConfigureRequest:
694 /* compress these */
695 while (XCheckTypedWindowEvent(ob_display, client->window,
696 ConfigureRequest, &ce)) {
697 ++i;
698 /* XXX if this causes bad things.. we can compress config req's
699 with the same mask. */
700 e->xconfigurerequest.value_mask |=
701 ce.xconfigurerequest.value_mask;
702 if (ce.xconfigurerequest.value_mask & CWX)
703 e->xconfigurerequest.x = ce.xconfigurerequest.x;
704 if (ce.xconfigurerequest.value_mask & CWY)
705 e->xconfigurerequest.y = ce.xconfigurerequest.y;
706 if (ce.xconfigurerequest.value_mask & CWWidth)
707 e->xconfigurerequest.width = ce.xconfigurerequest.width;
708 if (ce.xconfigurerequest.value_mask & CWHeight)
709 e->xconfigurerequest.height = ce.xconfigurerequest.height;
710 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
711 e->xconfigurerequest.border_width =
712 ce.xconfigurerequest.border_width;
713 if (ce.xconfigurerequest.value_mask & CWStackMode)
714 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
715 }
716
717 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
718 if (client->iconic || client->shaded) return;
719
720 if (e->xconfigurerequest.value_mask & CWBorderWidth)
721 client->border_width = e->xconfigurerequest.border_width;
722
723 /* resize, then move, as specified in the EWMH section 7.7 */
724 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
725 CWX | CWY)) {
726 int x, y, w, h;
727 Corner corner;
728
729 x = (e->xconfigurerequest.value_mask & CWX) ?
730 e->xconfigurerequest.x : client->area.x;
731 y = (e->xconfigurerequest.value_mask & CWY) ?
732 e->xconfigurerequest.y : client->area.y;
733 w = (e->xconfigurerequest.value_mask & CWWidth) ?
734 e->xconfigurerequest.width : client->area.width;
735 h = (e->xconfigurerequest.value_mask & CWHeight) ?
736 e->xconfigurerequest.height : client->area.height;
737
738 switch (client->gravity) {
739 case NorthEastGravity:
740 case EastGravity:
741 corner = Corner_TopRight;
742 break;
743 case SouthWestGravity:
744 case SouthGravity:
745 corner = Corner_BottomLeft;
746 break;
747 case SouthEastGravity:
748 corner = Corner_BottomRight;
749 break;
750 default: /* NorthWest, Static, etc */
751 corner = Corner_TopLeft;
752 }
753
754 client_configure(client, corner, x, y, w, h, FALSE, TRUE);
755 }
756
757 if (e->xconfigurerequest.value_mask & CWStackMode) {
758 switch (e->xconfigurerequest.detail) {
759 case Below:
760 case BottomIf:
761 stacking_lower(CLIENT_AS_WINDOW(client));
762 break;
763
764 case Above:
765 case TopIf:
766 default:
767 stacking_raise(CLIENT_AS_WINDOW(client));
768 break;
769 }
770 }
771 break;
772 case UnmapNotify:
773 if (client->ignore_unmaps) {
774 client->ignore_unmaps--;
775 break;
776 }
777 client_unmanage(client);
778 break;
779 case DestroyNotify:
780 client_unmanage(client);
781 break;
782 case ReparentNotify:
783 /* this is when the client is first taken captive in the frame */
784 if (e->xreparent.parent == client->frame->plate) break;
785
786 /*
787 This event is quite rare and is usually handled in unmapHandler.
788 However, if the window is unmapped when the reparent event occurs,
789 the window manager never sees it because an unmap event is not sent
790 to an already unmapped window.
791 */
792
793 /* we don't want the reparent event, put it back on the stack for the
794 X server to deal with after we unmanage the window */
795 XPutBackEvent(ob_display, e);
796
797 client_unmanage(client);
798 break;
799 case MapRequest:
800 g_message("MapRequest for 0x%lx", client->window);
801 if (!client->iconic) break; /* this normally doesn't happen, but if it
802 does, we don't want it! */
803 if (screen_showing_desktop)
804 screen_show_desktop(FALSE);
805 client_iconify(client, FALSE, TRUE);
806 if (!client->frame->visible)
807 /* if its not visible still, then don't mess with it */
808 break;
809 if (client->shaded)
810 client_shade(client, FALSE);
811 client_focus(client);
812 stacking_raise(CLIENT_AS_WINDOW(client));
813 break;
814 case ClientMessage:
815 /* validate cuz we query stuff off the client here */
816 if (!client_validate(client)) break;
817
818 if (e->xclient.format != 32) return;
819
820 msgtype = e->xclient.message_type;
821 if (msgtype == prop_atoms.wm_change_state) {
822 /* compress changes into a single change */
823 while (XCheckTypedWindowEvent(ob_display, e->type,
824 client->window, &ce)) {
825 /* XXX: it would be nice to compress ALL messages of a
826 type, not just messages in a row without other
827 message types between. */
828 if (ce.xclient.message_type != msgtype) {
829 XPutBackEvent(ob_display, &ce);
830 break;
831 }
832 e->xclient = ce.xclient;
833 }
834 client_set_wm_state(client, e->xclient.data.l[0]);
835 } else if (msgtype == prop_atoms.net_wm_desktop) {
836 /* compress changes into a single change */
837 while (XCheckTypedWindowEvent(ob_display, e->type,
838 client->window, &ce)) {
839 /* XXX: it would be nice to compress ALL messages of a
840 type, not just messages in a row without other
841 message types between. */
842 if (ce.xclient.message_type != msgtype) {
843 XPutBackEvent(ob_display, &ce);
844 break;
845 }
846 e->xclient = ce.xclient;
847 }
848 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
849 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
850 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
851 FALSE);
852 } else if (msgtype == prop_atoms.net_wm_state) {
853 /* can't compress these */
854 g_message("net_wm_state %s %ld %ld for 0x%lx",
855 (e->xclient.data.l[0] == 0 ? "Remove" :
856 e->xclient.data.l[0] == 1 ? "Add" :
857 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
858 e->xclient.data.l[1], e->xclient.data.l[2],
859 client->window);
860 client_set_state(client, e->xclient.data.l[0],
861 e->xclient.data.l[1], e->xclient.data.l[2]);
862 } else if (msgtype == prop_atoms.net_close_window) {
863 g_message("net_close_window for 0x%lx", client->window);
864 client_close(client);
865 } else if (msgtype == prop_atoms.net_active_window) {
866 g_message("net_active_window for 0x%lx", client->window);
867 client_activate(client);
868 } else if (msgtype == prop_atoms.net_wm_moveresize) {
869 g_message("net_wm_moveresize for 0x%lx", client->window);
870 if ((Atom)e->xclient.data.l[2] ==
871 prop_atoms.net_wm_moveresize_size_topleft ||
872 (Atom)e->xclient.data.l[2] ==
873 prop_atoms.net_wm_moveresize_size_top ||
874 (Atom)e->xclient.data.l[2] ==
875 prop_atoms.net_wm_moveresize_size_topright ||
876 (Atom)e->xclient.data.l[2] ==
877 prop_atoms.net_wm_moveresize_size_right ||
878 (Atom)e->xclient.data.l[2] ==
879 prop_atoms.net_wm_moveresize_size_right ||
880 (Atom)e->xclient.data.l[2] ==
881 prop_atoms.net_wm_moveresize_size_bottomright ||
882 (Atom)e->xclient.data.l[2] ==
883 prop_atoms.net_wm_moveresize_size_bottom ||
884 (Atom)e->xclient.data.l[2] ==
885 prop_atoms.net_wm_moveresize_size_bottomleft ||
886 (Atom)e->xclient.data.l[2] ==
887 prop_atoms.net_wm_moveresize_size_left ||
888 (Atom)e->xclient.data.l[2] ==
889 prop_atoms.net_wm_moveresize_move ||
890 (Atom)e->xclient.data.l[2] ==
891 prop_atoms.net_wm_moveresize_size_keyboard ||
892 (Atom)e->xclient.data.l[2] ==
893 prop_atoms.net_wm_moveresize_move_keyboard) {
894
895 moveresize_start(client, e->xclient.data.l[0],
896 e->xclient.data.l[1], e->xclient.data.l[3],
897 e->xclient.data.l[2]);
898 }
899 } else if (msgtype == prop_atoms.net_moveresize_window) {
900 int oldg = client->gravity;
901 int tmpg, x, y, w, h;
902
903 if (e->xclient.data.l[0] & 0xff)
904 tmpg = e->xclient.data.l[0] & 0xff;
905 else
906 tmpg = oldg;
907
908 if (e->xclient.data.l[0] & 1 << 8)
909 x = e->xclient.data.l[1];
910 else
911 x = client->area.x;
912 if (e->xclient.data.l[0] & 1 << 9)
913 y = e->xclient.data.l[2];
914 else
915 y = client->area.y;
916 if (e->xclient.data.l[0] & 1 << 10)
917 w = e->xclient.data.l[3];
918 else
919 w = client->area.y;
920 if (e->xclient.data.l[0] & 1 << 11)
921 h = e->xclient.data.l[4];
922 else
923 h = client->area.y;
924 client->gravity = tmpg;
925 client_configure(client, Corner_TopLeft, x, y, w, h, FALSE, TRUE);
926 client->gravity = oldg;
927 }
928 break;
929 case PropertyNotify:
930 /* validate cuz we query stuff off the client here */
931 if (!client_validate(client)) break;
932
933 /* compress changes to a single property into a single change */
934 while (XCheckTypedWindowEvent(ob_display, e->type,
935 client->window, &ce)) {
936 /* XXX: it would be nice to compress ALL changes to a property,
937 not just changes in a row without other props between. */
938 if (ce.xproperty.atom != e->xproperty.atom) {
939 XPutBackEvent(ob_display, &ce);
940 break;
941 }
942 }
943
944 msgtype = e->xproperty.atom;
945 if (msgtype == XA_WM_NORMAL_HINTS) {
946 client_update_normal_hints(client);
947 /* normal hints can make a window non-resizable */
948 client_setup_decor_and_functions(client);
949 }
950 else if (msgtype == XA_WM_HINTS)
951 client_update_wmhints(client);
952 else if (msgtype == XA_WM_TRANSIENT_FOR) {
953 client_update_transient_for(client);
954 client_get_type(client);
955 /* type may have changed, so update the layer */
956 client_calc_layer(client);
957 client_setup_decor_and_functions(client);
958 }
959 else if (msgtype == prop_atoms.net_wm_name ||
960 msgtype == prop_atoms.wm_name ||
961 msgtype == prop_atoms.net_wm_icon_name ||
962 msgtype == prop_atoms.wm_icon_name)
963 client_update_title(client);
964 else if (msgtype == prop_atoms.wm_class)
965 client_update_class(client);
966 else if (msgtype == prop_atoms.wm_protocols) {
967 client_update_protocols(client);
968 client_setup_decor_and_functions(client);
969 }
970 else if (msgtype == prop_atoms.net_wm_strut)
971 client_update_strut(client);
972 else if (msgtype == prop_atoms.net_wm_icon ||
973 msgtype == prop_atoms.kwm_win_icon)
974 client_update_icons(client);
975 default:
976 ;
977 #ifdef SHAPE
978 if (extensions_shape && e->type == extensions_shape_event_basep) {
979 client->shaped = ((XShapeEvent*)e)->shaped;
980 frame_adjust_shape(client->frame);
981 }
982 #endif
983 }
984 }
985
986 static void event_handle_menu(Client *client, XEvent *e)
987 {
988 static MenuEntry *over = NULL;
989 MenuEntry *entry;
990 Menu *top;
991 GSList *it;
992
993 top = g_slist_nth_data(menu_visible, 0);
994
995 g_message("EVENT %d", e->type);
996 switch (e->type) {
997 case KeyPress:
998 if (over) {
999 if (over->parent->mouseover)
1000 over->parent->mouseover(over, FALSE);
1001 else
1002 menu_control_mouseover(over, FALSE);
1003 menu_entry_render(over);
1004 }
1005 /*
1006 if (top->hide)
1007 top->hide(top);
1008 else
1009 */
1010 menu_hide(top);
1011 break;
1012 case ButtonPress:
1013 if (e->xbutton.button > 3) break;
1014
1015 g_message("BUTTON PRESS");
1016 break;
1017 case ButtonRelease:
1018 if (e->xbutton.button > 3) break;
1019
1020 g_message("BUTTON RELEASED");
1021
1022 for (it = menu_visible; it; it = g_slist_next(it)) {
1023 Menu *m = it->data;
1024 if (e->xbutton.x_root >= m->location.x - ob_rr_theme->bwidth &&
1025 e->xbutton.y_root >= m->location.y - ob_rr_theme->bwidth &&
1026 e->xbutton.x_root < m->location.x + m->size.width +
1027 ob_rr_theme->bwidth &&
1028 e->xbutton.y_root < m->location.y + m->size.height +
1029 ob_rr_theme->bwidth) {
1030 if ((entry = menu_find_entry_by_pos(it->data,
1031 e->xbutton.x_root -
1032 m->location.x,
1033 e->xbutton.y_root -
1034 m->location.y))) {
1035 menu_entry_fire(entry);
1036 }
1037 break;
1038 }
1039 }
1040 if (!it) {
1041 if (over) {
1042 if (over->parent->mouseover)
1043 over->parent->mouseover(over, FALSE);
1044 else
1045 menu_control_mouseover(over, FALSE);
1046 }
1047 menu_entry_render(over);
1048 /*
1049 if (top->hide)
1050 top->hide(top);
1051 else
1052 */
1053 menu_hide(top);
1054 }
1055
1056 break;
1057 case MotionNotify:
1058 g_message("motion");
1059 for (it = menu_visible; it; it = g_slist_next(it)) {
1060 Menu *m = it->data;
1061 if ((entry = menu_find_entry_by_pos(it->data,
1062 e->xmotion.x_root -
1063 m->location.x,
1064 e->xmotion.y_root -
1065 m->location.y))) {
1066 if (over && entry != over) {
1067 if (over->parent->mouseover)
1068 over->parent->mouseover(over, FALSE);
1069 else
1070 menu_control_mouseover(over, FALSE);
1071 menu_entry_render(over);
1072 }
1073
1074 over = entry;
1075 if (over->parent->mouseover)
1076 over->parent->mouseover(over, TRUE);
1077 else
1078 menu_control_mouseover(over, TRUE);
1079 menu_entry_render(over);
1080 break;
1081 }
1082 }
1083 if (!it && over) {
1084 if (over->parent->mouseover)
1085 over->parent->mouseover(over, FALSE);
1086 else
1087 menu_control_mouseover(over, FALSE);
1088 menu_entry_render(over);
1089 over = NULL;
1090 }
1091 break;
1092 }
1093 }
1094
1095 void event_add_fd_handler(event_fd_handler *h) {
1096 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
1097 FD_SET(h->fd, &allset);
1098 max_fd = MAX(max_fd, h->fd);
1099 }
1100
1101 static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
1102 {
1103 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
1104 }
1105
1106 static void find_max_fd()
1107 {
1108 int tmpmax = -1;
1109 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach, (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(Dock *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(DockApp *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.100536 seconds and 4 git commands to generate.