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