+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ event.c for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003 Ben Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "event.h"
#include "debug.h"
+#include "window.h"
#include "openbox.h"
#include "dock.h"
#include "client.h"
#include "screen.h"
#include "frame.h"
#include "menu.h"
+#include "menuframe.h"
#include "keyboard.h"
#include "mouse.h"
+#include "mainloop.h"
#include "framerender.h"
#include "focus.h"
#include "moveresize.h"
+#include "group.h"
#include "stacking.h"
#include "extensions.h"
-#include "timer.h"
-#include "dispatch.h"
-#include "event.h"
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <glib.h>
-#ifdef USE_LIBSN
-# include <libsn/sn.h>
-#endif
-
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
+#ifdef XKB
+# include <X11/XKBlib.h>
+#endif
#ifdef USE_SM
#include <X11/ICE/ICElib.h>
#endif
-static void event_process(XEvent *e);
+typedef struct
+{
+ gboolean ignored;
+} ObEventData;
+
+static void event_process(const XEvent *e, gpointer data);
+static void event_client_dest(ObClient *client, gpointer data);
static void event_handle_root(XEvent *e);
+static void event_handle_menu(XEvent *e);
static void event_handle_dock(ObDock *s, XEvent *e);
static void event_handle_dockapp(ObDockApp *app, XEvent *e);
static void event_handle_client(ObClient *c, XEvent *e);
-static void event_handle_menu(ObClient *c, XEvent *e);
-static void fd_event_handle();
-#ifdef USE_SM
-static void ice_watch(IceConn conn, IcePointer data, Bool opening,
- IcePointer *watch_data);
-#endif
-static void find_max_fd();
+static void event_handle_group(ObGroup *g, XEvent *e);
+
+static gboolean focus_delay_func(gpointer data);
+static void focus_delay_client_dest(ObClient *client, gpointer data);
+
+static gboolean menu_hide_delay_func(gpointer data);
#define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
(e)->xfocus.detail == NotifyAncestor || \
(e)->xfocus.detail == NotifyAncestor || \
(e)->xfocus.detail > NotifyNonlinearVirtual)
-Time event_lasttime = 0;
+/* The most recent time at which an event with a timestamp occured. */
+static Time event_lasttime = 0;
+/* The time for the current event being processed
+ (it's the event_lasttime for events without times, if this is a bug then
+ use CurrentTime instead, but it seems ok) */
+Time event_curtime = CurrentTime;
/*! The value of the mask for the NumLock modifier */
-unsigned int NumLockMask;
+guint NumLockMask;
/*! The value of the mask for the ScrollLock modifier */
-unsigned int ScrollLockMask;
+guint ScrollLockMask;
/*! The key codes for the modifier keys */
static XModifierKeymap *modmap;
/*! Table of the constant modifier masks */
-static const int mask_table[] = {
+static const gint mask_table[] = {
ShiftMask, LockMask, ControlMask, Mod1Mask,
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
};
-static int mask_table_size;
+static gint mask_table_size;
-static fd_set selset, allset;
-#ifdef USE_SM
-static IceConn ice_conn;
-static int ice_fd;
-#endif
-static int max_fd, x_fd;
-static GData *fd_handler_list;
+static guint ignore_enter_focus = 0;
+static gboolean menu_can_hide;
#ifdef USE_SM
+static void ice_handler(gint fd, gpointer conn)
+{
+ Bool b;
+ IceProcessMessages(conn, NULL, &b);
+}
+
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
IcePointer *watch_data)
{
+ static gint fd = -1;
+
if (opening) {
- g_assert (ice_fd < 0);
- ice_conn = conn;
- ice_fd = IceConnectionNumber(conn);
- FD_SET(ice_fd, &allset);
+ fd = IceConnectionNumber(conn);
+ ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
} else {
- FD_CLR(ice_fd, &allset);
- ice_fd = -1;
+ ob_main_loop_fd_remove(ob_main_loop, fd);
+ fd = -1;
}
- find_max_fd();
}
#endif
-void event_startup()
+void event_startup(gboolean reconfig)
{
+ if (reconfig) return;
+
mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
/* get lock masks that are defined by the display (not constant) */
modmap = XGetModifierMapping(ob_display);
g_assert(modmap);
if (modmap && modmap->max_keypermod > 0) {
- size_t cnt;
- const size_t size = mask_table_size * modmap->max_keypermod;
- /* get the values of the keyboard lock modifiers
- Note: Caps lock is not retrieved the same way as Scroll and Num
- lock since it doesn't need to be. */
- const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
- const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
- XK_Scroll_Lock);
-
- for (cnt = 0; cnt < size; ++cnt) {
- if (! modmap->modifiermap[cnt]) continue;
-
- if (num_lock == modmap->modifiermap[cnt])
- NumLockMask = mask_table[cnt / modmap->max_keypermod];
- if (scroll_lock == modmap->modifiermap[cnt])
- ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
- }
+ size_t cnt;
+ const size_t size = mask_table_size * modmap->max_keypermod;
+ /* get the values of the keyboard lock modifiers
+ Note: Caps lock is not retrieved the same way as Scroll and Num
+ lock since it doesn't need to be. */
+ const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
+ const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
+ XK_Scroll_Lock);
+
+ for (cnt = 0; cnt < size; ++cnt) {
+ if (! modmap->modifiermap[cnt]) continue;
+
+ if (num_lock == modmap->modifiermap[cnt])
+ NumLockMask = mask_table[cnt / modmap->max_keypermod];
+ if (scroll_lock == modmap->modifiermap[cnt])
+ ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
+ }
}
- FD_ZERO(&allset);
- max_fd = x_fd = ConnectionNumber(ob_display);
- FD_SET(x_fd, &allset);
+ ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
#ifdef USE_SM
- ice_fd = -1;
IceAddConnectionWatch(ice_watch, NULL);
#endif
- g_datalist_init(&fd_handler_list);
-}
-
-void event_shutdown()
-{
- XFreeModifiermap(modmap);
- g_datalist_clear(&fd_handler_list);
+ client_add_destructor(focus_delay_client_dest, NULL);
+ client_add_destructor(event_client_dest, NULL);
}
-void event_loop()
+void event_shutdown(gboolean reconfig)
{
- XEvent e;
- struct timeval *wait;
- gboolean had_event = FALSE;
-
- while (XPending(ob_display)) {
- XNextEvent(ob_display, &e);
-
-#ifdef USE_LIBSN
- sn_display_process_event(ob_sn_display, &e);
-#endif
-
- event_process(&e);
- had_event = TRUE;
- }
-
- if (!had_event) {
- timer_dispatch((GTimeVal**)&wait);
- selset = allset;
- select(max_fd + 1, &selset, NULL, NULL, wait);
-
- /* handle the X events as soon as possible? */
- if (FD_ISSET(x_fd, &selset))
- return;
+ if (reconfig) return;
#ifdef USE_SM
- if (ice_fd >= 0 && FD_ISSET(ice_fd, &selset)) {
- Bool b;
- IceProcessMessages(ice_conn, NULL, &b);
- }
+ IceRemoveConnectionWatch(ice_watch, NULL);
#endif
- fd_event_handle();
- }
+ client_remove_destructor(focus_delay_client_dest);
+ client_remove_destructor(event_client_dest);
+ XFreeModifiermap(modmap);
}
static Window event_get_window(XEvent *e)
window = RootWindow(ob_display, ob_screen);
break;
case MapRequest:
- window = e->xmap.window;
- break;
+ window = e->xmap.window;
+ break;
case UnmapNotify:
- window = e->xunmap.window;
- break;
+ window = e->xunmap.window;
+ break;
case DestroyNotify:
- window = e->xdestroywindow.window;
- break;
+ window = e->xdestroywindow.window;
+ break;
case ConfigureRequest:
- window = e->xconfigurerequest.window;
- break;
+ window = e->xconfigurerequest.window;
+ break;
case ConfigureNotify:
window = e->xconfigure.window;
break;
default:
#ifdef XKB
- if (extensions_xkb && e->type == extensions_xkb_event_basep) {
- switch (((XkbAnyEvent*)e)->xkb_type) {
- case XkbBellNotify:
- window = ((XkbBellNotifyEvent*)e)->window;
- default:
- window = None;
- }
+ if (extensions_xkb && e->type == extensions_xkb_event_basep) {
+ switch (((XkbAnyEvent*)e)->xkb_type) {
+ case XkbBellNotify:
+ window = ((XkbBellNotifyEvent*)e)->window;
+ default:
+ window = None;
+ }
} else
#endif
window = e->xany.window;
switch (e->type) {
case ButtonPress:
case ButtonRelease:
- t = e->xbutton.time;
- break;
+ t = e->xbutton.time;
+ break;
case KeyPress:
- t = e->xkey.time;
- break;
+ t = e->xkey.time;
+ break;
case KeyRelease:
- t = e->xkey.time;
- break;
+ t = e->xkey.time;
+ break;
case MotionNotify:
- t = e->xmotion.time;
- break;
+ t = e->xmotion.time;
+ break;
case PropertyNotify:
- t = e->xproperty.time;
- break;
+ t = e->xproperty.time;
+ break;
case EnterNotify:
case LeaveNotify:
- t = e->xcrossing.time;
- break;
+ t = e->xcrossing.time;
+ break;
default:
/* if more event types are anticipated, get their timestamp
explicitly */
break;
}
- if (t > event_lasttime)
+ if (t > event_lasttime) {
event_lasttime = t;
+ event_curtime = event_lasttime;
+ } else if (t == 0) {
+ event_curtime = event_lasttime;
+ } else {
+ event_curtime = t;
+ }
}
#define STRIP_MODS(s) \
- s &= ~(LockMask | NumLockMask | ScrollLockMask), \
- /* kill off the Button1Mask etc, only want the modifiers */ \
- s &= (ControlMask | ShiftMask | Mod1Mask | \
+ s &= ~(LockMask | NumLockMask | ScrollLockMask), \
+ /* kill off the Button1Mask etc, only want the modifiers */ \
+ s &= (ControlMask | ShiftMask | Mod1Mask | \
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
static void event_hack_mods(XEvent *e)
{
+#ifdef XKB
+ XkbStateRec xkb_state;
+#endif
KeyCode *kp;
- int i, k;
+ gint i, k;
switch (e->type) {
case ButtonPress:
case ButtonRelease:
STRIP_MODS(e->xbutton.state);
- break;
+ break;
case KeyPress:
STRIP_MODS(e->xkey.state);
- break;
+ break;
case KeyRelease:
STRIP_MODS(e->xkey.state);
- /* remove from the state the mask of the modifier being released, if
- it is a modifier key being released (this is a little ugly..) */
- kp = modmap->modifiermap;
- for (i = 0; i < mask_table_size; ++i) {
- for (k = 0; k < modmap->max_keypermod; ++k) {
- if (*kp == e->xkey.keycode) { /* found the keycode */
- /* remove the mask for it */
- e->xkey.state &= ~mask_table[i];
- /* cause the first loop to break; */
- i = mask_table_size;
- break; /* get outta here! */
- }
- ++kp;
- }
- }
- break;
+ /* remove from the state the mask of the modifier being released, if
+ it is a modifier key being released (this is a little ugly..) */
+#ifdef XKB
+ if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) {
+ e->xkey.state = xkb_state.compat_state;
+ break;
+ }
+#endif
+ kp = modmap->modifiermap;
+ for (i = 0; i < mask_table_size; ++i) {
+ for (k = 0; k < modmap->max_keypermod; ++k) {
+ if (*kp == e->xkey.keycode) { /* found the keycode */
+ /* remove the mask for it */
+ e->xkey.state &= ~mask_table[i];
+ /* cause the first loop to break; */
+ i = mask_table_size;
+ break; /* get outta here! */
+ }
+ ++kp;
+ }
+ }
+ break;
case MotionNotify:
STRIP_MODS(e->xmotion.state);
- /* compress events */
+ /* compress events */
{
XEvent ce;
while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
e->xmotion.x_root = ce.xmotion.x_root;
e->xmotion.y_root = ce.xmotion.y_root;
}
- }
- break;
+ }
+ break;
}
}
static gboolean event_ignore(XEvent *e, ObClient *client)
{
switch(e->type) {
+ case EnterNotify:
+ case LeaveNotify:
+ if (e->xcrossing.detail == NotifyInferior)
+ return TRUE;
+ break;
case FocusIn:
/* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
because of RevertToPointerRoot. If the focus ends up reverting to
want will be of type NotifyAncestor. This situation does not occur
for FocusOut, so it is safely ignored there.
*/
- if (INVALID_FOCUSIN(e) ||
+ if (INVALID_FOCUSIN(e) ||
client == NULL) {
#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
- e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+ ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
/* says a client was not found for the event (or a valid FocusIn
event was not found.
#endif
break;
case FocusOut:
- if (INVALID_FOCUSOUT(e)) {
+ if (INVALID_FOCUSOUT(e)) {
#ifdef DEBUG_FOCUS
ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
ob_debug("FocusOut on %lx mode %d detail %d\n",
e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
-
{
XEvent fe;
gboolean fallback = TRUE;
while (TRUE) {
- if (!XCheckTypedWindowEvent(ob_display, FocusOut,
- e->xfocus.window,&fe))
+ if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window,
+ FocusOut, &fe))
if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
break;
if (fe.type == FocusOut) {
#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusOut");
+ ob_debug("found pending FocusOut\n");
#endif
if (!INVALID_FOCUSOUT(&fe)) {
/* if there is a VALID FocusOut still coming, don't
}
} else {
#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusIn");
+ ob_debug("found pending FocusIn\n");
#endif
/* is the focused window getting a FocusOut/In back to
itself?
if (focus_client) {
#ifdef DEBUG_FOCUS
ob_debug("focused window got an Out/In back to "
- "itself IGNORED both");
+ "itself IGNORED both\n");
#endif
return TRUE;
} else {
- event_process(&fe);
+ event_process(&fe, NULL);
#ifdef DEBUG_FOCUS
ob_debug("focused window got an Out/In back to "
"itself but focus_client was null "
- "IGNORED just the Out");
+ "IGNORED just the Out\n");
#endif
return TRUE;
}
}
- /* once all the FocusOut's have been dealt with, if there
- is a FocusIn still left and it is valid, then use it */
- event_process(&fe);
- /* secret magic way of event_process telling us that no
- client was found for the FocusIn event. ^_^ */
- if (fe.xfocus.window != None) {
- fallback = FALSE;
- break;
+ {
+ ObEventData d;
+
+ /* once all the FocusOut's have been dealt with, if
+ there is a FocusIn still left and it is valid, then
+ use it */
+ event_process(&fe, &d);
+ if (!d.ignored) {
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusIn was OK, so don't fallback\n");
+#endif
+ fallback = FALSE;
+ break;
+ }
}
}
}
if (fallback) {
#ifdef DEBUG_FOCUS
ob_debug("no valid FocusIn and no FocusOut events found, "
- "falling back");
+ "falling back\n");
#endif
focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
}
}
- break;
- case EnterNotify:
- case LeaveNotify:
- /* NotifyUngrab occurs when a mouse button is released and the event is
- caused, like when lowering a window */
- /* NotifyVirtual occurs when ungrabbing the pointer */
- if (e->xcrossing.mode == NotifyGrab ||
- e->xcrossing.detail == NotifyInferior ||
- (e->xcrossing.mode == NotifyUngrab &&
- e->xcrossing.detail == NotifyVirtual)) {
-#ifdef DEBUG_FOCUS
- ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
- (e->type == EnterNotify ? "Enter" : "Leave"),
- e->xcrossing.mode,
- e->xcrossing.detail, client?client->window:0);
-#endif
- return TRUE;
- }
-#ifdef DEBUG_FOCUS
- ob_debug("%sNotify mode %d detail %d on %lx",
- (e->type == EnterNotify ? "Enter" : "Leave"),
- e->xcrossing.mode,
- e->xcrossing.detail, client?client->window:0);
-#endif
- break;
+ break;
}
return FALSE;
}
-static void event_process(XEvent *e)
+static void event_process(const XEvent *ec, gpointer data)
{
Window window;
+ ObGroup *group = NULL;
ObClient *client = NULL;
ObDock *dock = NULL;
ObDockApp *dockapp = NULL;
- ObMenu *menu = NULL;
ObWindow *obwin = NULL;
+ XEvent ee, *e;
+ ObEventData *ed = data;
+
+ /* make a copy we can mangle */
+ ee = *ec;
+ e = ⅇ
window = event_get_window(e);
- if ((obwin = g_hash_table_lookup(window_map, &window))) {
- switch (obwin->type) {
- case Window_Dock:
- dock = WINDOW_AS_DOCK(obwin);
- break;
- case Window_DockApp:
- dockapp = WINDOW_AS_DOCKAPP(obwin);
- break;
- case Window_Menu:
- menu = WINDOW_AS_MENU(obwin);
- break;
- case Window_Client:
- client = WINDOW_AS_CLIENT(obwin);
- break;
- case Window_Internal:
- /* not to be used for events */
- g_assert_not_reached();
- break;
+ if (!(e->type == PropertyNotify &&
+ (group = g_hash_table_lookup(group_map, &window))))
+ if ((obwin = g_hash_table_lookup(window_map, &window))) {
+ switch (obwin->type) {
+ case Window_Dock:
+ dock = WINDOW_AS_DOCK(obwin);
+ break;
+ case Window_DockApp:
+ dockapp = WINDOW_AS_DOCKAPP(obwin);
+ break;
+ case Window_Client:
+ client = WINDOW_AS_CLIENT(obwin);
+ break;
+ case Window_Menu:
+ case Window_Internal:
+ /* not to be used for events */
+ g_assert_not_reached();
+ break;
+ }
}
- }
event_set_lasttime(e);
event_hack_mods(e);
- if (event_ignore(e, client))
+ if (event_ignore(e, client)) {
+ if (ed)
+ ed->ignored = TRUE;
return;
+ } else if (ed)
+ ed->ignored = FALSE;
/* deal with it in the kernel */
- if (client)
- event_handle_client(client, e);
+ if (group)
+ event_handle_group(group, e);
+ else if (client)
+ event_handle_client(client, e);
else if (dockapp)
- event_handle_dockapp(dockapp, e);
+ event_handle_dockapp(dockapp, e);
else if (dock)
- event_handle_dock(dock, e);
+ event_handle_dock(dock, e);
else if (window == RootWindow(ob_display, ob_screen))
- event_handle_root(e);
+ event_handle_root(e);
else if (e->type == MapRequest)
- client_manage(window);
+ client_manage(window);
else if (e->type == ConfigureRequest) {
- /* unhandled configure requests must be used to configure the
- window directly */
- XWindowChanges xwc;
-
- xwc.x = e->xconfigurerequest.x;
- xwc.y = e->xconfigurerequest.y;
- xwc.width = e->xconfigurerequest.width;
- xwc.height = e->xconfigurerequest.height;
- xwc.border_width = e->xconfigurerequest.border_width;
- xwc.sibling = e->xconfigurerequest.above;
- xwc.stack_mode = e->xconfigurerequest.detail;
+ /* unhandled configure requests must be used to configure the
+ window directly */
+ XWindowChanges xwc;
+
+ xwc.x = e->xconfigurerequest.x;
+ xwc.y = e->xconfigurerequest.y;
+ xwc.width = e->xconfigurerequest.width;
+ xwc.height = e->xconfigurerequest.height;
+ xwc.border_width = e->xconfigurerequest.border_width;
+ xwc.sibling = e->xconfigurerequest.above;
+ xwc.stack_mode = e->xconfigurerequest.detail;
- /* we are not to be held responsible if someone sends us an
- invalid request! */
- xerror_set_ignore(TRUE);
- XConfigureWindow(ob_display, window,
- e->xconfigurerequest.value_mask, &xwc);
- xerror_set_ignore(FALSE);
+ /* we are not to be held responsible if someone sends us an
+ invalid request! */
+ xerror_set_ignore(TRUE);
+ XConfigureWindow(ob_display, window,
+ e->xconfigurerequest.value_mask, &xwc);
+ xerror_set_ignore(FALSE);
}
- if (menu_visible)
- if (e->type == MotionNotify || e->type == ButtonRelease ||
- e->type == ButtonPress ||
- e->type == KeyPress || e->type == KeyRelease) {
- event_handle_menu(client, e);
-
- return; /* no dispatch! */
- }
-
- if (moveresize_in_progress)
- if (e->type == MotionNotify || e->type == ButtonRelease ||
- e->type == ButtonPress ||
- e->type == KeyPress || e->type == KeyRelease) {
- moveresize_event(e);
-
- return; /* no dispatch! */
-
- }
-
/* user input (action-bound) events */
if (e->type == ButtonPress || e->type == ButtonRelease ||
e->type == MotionNotify || e->type == KeyPress ||
e->type == KeyRelease)
{
- ObFrameContext context;
-
- context = frame_context(client, e->xany.window);
-
- if (!keyboard_process_interactive_grab(e, &client, &context)) {
+ if (menu_frame_visible)
+ event_handle_menu(e);
+ else {
+ if (!keyboard_process_interactive_grab(e, &client)) {
+ if (moveresize_in_progress) {
+ moveresize_event(e);
+
+ /* make further actions work on the client being
+ moved/resized */
+ client = moveresize_client;
+ }
- if (e->type == ButtonPress || e->type == ButtonRelease ||
- e->type == MotionNotify)
- mouse_event(client, context, e);
- else if (e->type == KeyPress)
- keyboard_event(client, e);
+ menu_can_hide = FALSE;
+ ob_main_loop_timeout_add(ob_main_loop,
+ config_menu_hide_delay * 1000,
+ menu_hide_delay_func,
+ NULL, NULL);
+
+ if (e->type == ButtonPress || e->type == ButtonRelease ||
+ e->type == MotionNotify)
+ mouse_event(client, e);
+ else if (e->type == KeyPress)
+ keyboard_event((focus_cycle_target ? focus_cycle_target :
+ (focus_hilite ? focus_hilite : client)),
+ e);
+ }
}
}
-
- /* dispatch the event to registered handlers */
- dispatch_x(e, client);
}
static void event_handle_root(XEvent *e)
switch(e->type) {
case SelectionClear:
ob_debug("Another WM has requested to replace us. Exiting.\n");
- ob_exit();
+ ob_exit_replace();
break;
case ClientMessage:
- if (e->xclient.format != 32) break;
-
- msgtype = e->xclient.message_type;
- if (msgtype == prop_atoms.net_current_desktop) {
- unsigned int d = e->xclient.data.l[0];
- if (d < screen_num_desktops)
- screen_set_desktop(d);
- } else if (msgtype == prop_atoms.net_number_of_desktops) {
- unsigned int d = e->xclient.data.l[0];
- if (d > 0)
- screen_set_num_desktops(d);
- } else if (msgtype == prop_atoms.net_showing_desktop) {
- screen_show_desktop(e->xclient.data.l[0] != 0);
- }
- break;
+ if (e->xclient.format != 32) break;
+
+ msgtype = e->xclient.message_type;
+ if (msgtype == prop_atoms.net_current_desktop) {
+ guint d = e->xclient.data.l[0];
+ if (d < screen_num_desktops)
+ screen_set_desktop(d);
+ } else if (msgtype == prop_atoms.net_number_of_desktops) {
+ guint d = e->xclient.data.l[0];
+ if (d > 0)
+ screen_set_num_desktops(d);
+ } else if (msgtype == prop_atoms.net_showing_desktop) {
+ screen_show_desktop(e->xclient.data.l[0] != 0);
+ } else if (msgtype == prop_atoms.ob_control) {
+ if (e->xclient.data.l[0] == 1)
+ ob_reconfigure();
+ else if (e->xclient.data.l[0] == 2)
+ ob_restart();
+ }
+ break;
case PropertyNotify:
- if (e->xproperty.atom == prop_atoms.net_desktop_names)
- screen_update_desktop_names();
- else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
- screen_update_layout();
- break;
+ if (e->xproperty.atom == prop_atoms.net_desktop_names)
+ screen_update_desktop_names();
+ else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
+ screen_update_layout();
+ break;
case ConfigureNotify:
#ifdef XRANDR
XRRUpdateConfiguration(e);
break;
default:
;
-#ifdef VIDMODE
- if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
- ob_debug("VIDMODE EVENT\n");
- }
-#endif
+ }
+}
+
+static void event_handle_group(ObGroup *group, XEvent *e)
+{
+ GSList *it;
+
+ g_assert(e->type == PropertyNotify);
+
+ for (it = group->members; it; it = g_slist_next(it))
+ event_handle_client(it->data, e);
+}
+
+void event_enter_client(ObClient *client)
+{
+ g_assert(config_focus_follow);
+
+ if (client_normal(client) && client_can_focus(client)) {
+ if (config_focus_delay) {
+ ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
+ ob_main_loop_timeout_add(ob_main_loop,
+ config_focus_delay,
+ focus_delay_func,
+ client, NULL);
+ } else
+ focus_delay_func(client);
}
}
{
XEvent ce;
Atom msgtype;
- int i=0;
+ gint i=0;
ObFrameContext con;
switch (e->type) {
/* Wheel buttons don't draw because they are an instant click, so it
is a waste of resources to go drawing it. */
if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
- switch (frame_context(client, e->xbutton.window)) {
+ con = frame_context(client, e->xbutton.window);
+ con = mouse_button_frame_context(con, e->xbutton.button);
+ switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_press = (e->type == ButtonPress);
framerender_frame(client->frame);
break;
case FocusIn:
#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on client for %lx\n", client->window);
+ ob_debug("FocusIn on client for %lx (client %lx) mode %d detail %d\n",
+ e->xfocus.window, client->window,
+ e->xfocus.mode, e->xfocus.detail);
#endif
if (client != focus_client) {
focus_set_client(client);
frame_adjust_focus(client->frame, TRUE);
+ client_calc_layer(client);
}
break;
case FocusOut:
#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on client for %lx\n", client->window);
+ ob_debug("FocusOut on client for %lx (client %lx) mode %d detail %d\n",
+ e->xfocus.window, client->window,
+ e->xfocus.mode, e->xfocus.detail);
#endif
- /* are we a fullscreen window or a transient of one? (checks layer)
- if we are then we need to be iconified since we are losing focus
- */
- if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic &&
- !client_search_focus_tree_full(client))
- /* iconify fullscreen windows when they and their transients
- aren't focused */
- client_iconify(client, TRUE, TRUE);
+ focus_hilite = NULL;
frame_adjust_focus(client->frame, FALSE);
- break;
+ client_calc_layer(client);
+ break;
case LeaveNotify:
con = frame_context(client, e->xcrossing.window);
switch (con) {
client->frame->close_hover = FALSE;
frame_adjust_state(client->frame);
break;
+ case OB_FRAME_CONTEXT_FRAME:
+ if (config_focus_follow && config_focus_delay)
+ ob_main_loop_timeout_remove_data(ob_main_loop,
+ focus_delay_func,
+ client, TRUE);
+ break;
default:
break;
}
break;
case EnterNotify:
+ {
+ gboolean nofocus = FALSE;
+
+ if (ignore_enter_focus) {
+ ignore_enter_focus--;
+ nofocus = TRUE;
+ }
+
con = frame_context(client, e->xcrossing.window);
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
frame_adjust_state(client->frame);
break;
case OB_FRAME_CONTEXT_FRAME:
- if (client_normal(client)) {
- if (ob_state() == OB_STATE_STARTING) {
- /* move it to the top of the focus order */
- guint desktop = client->desktop;
- if (desktop == DESKTOP_ALL) desktop = screen_desktop;
- focus_order[desktop] = g_list_remove(focus_order[desktop],
- client);
- focus_order[desktop] = g_list_prepend(focus_order[desktop],
- client);
- } else if (config_focus_follow) {
+ if (e->xcrossing.mode == NotifyGrab ||
+ e->xcrossing.mode == NotifyUngrab)
+ {
#ifdef DEBUG_FOCUS
- ob_debug("EnterNotify on %lx, focusing window\n",
- client->window);
+ ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n",
+ (e->type == EnterNotify ? "Enter" : "Leave"),
+ e->xcrossing.mode,
+ e->xcrossing.detail, client?client->window:0);
#endif
- client_focus(client);
- }
+ } else {
+#ifdef DEBUG_FOCUS
+ ob_debug("%sNotify mode %d detail %d on %lx, "
+ "focusing window: %d\n",
+ (e->type == EnterNotify ? "Enter" : "Leave"),
+ e->xcrossing.mode,
+ e->xcrossing.detail, (client?client->window:0),
+ !nofocus);
+#endif
+ if (!nofocus && config_focus_follow)
+ event_enter_client(client);
}
break;
default:
break;
}
break;
+ }
case ConfigureRequest:
- /* compress these */
- while (XCheckTypedWindowEvent(ob_display, client->window,
- ConfigureRequest, &ce)) {
+ /* compress these */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ ConfigureRequest, &ce)) {
++i;
- /* XXX if this causes bad things.. we can compress config req's
- with the same mask. */
- e->xconfigurerequest.value_mask |=
- ce.xconfigurerequest.value_mask;
- if (ce.xconfigurerequest.value_mask & CWX)
- e->xconfigurerequest.x = ce.xconfigurerequest.x;
- if (ce.xconfigurerequest.value_mask & CWY)
- e->xconfigurerequest.y = ce.xconfigurerequest.y;
- if (ce.xconfigurerequest.value_mask & CWWidth)
- e->xconfigurerequest.width = ce.xconfigurerequest.width;
- if (ce.xconfigurerequest.value_mask & CWHeight)
- e->xconfigurerequest.height = ce.xconfigurerequest.height;
- if (ce.xconfigurerequest.value_mask & CWBorderWidth)
- e->xconfigurerequest.border_width =
- ce.xconfigurerequest.border_width;
- if (ce.xconfigurerequest.value_mask & CWStackMode)
- e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
- }
-
- /* if we are iconic (or shaded (fvwm does this)) ignore the event */
- if (client->iconic || client->shaded) return;
-
- /* resize, then move, as specified in the EWMH section 7.7 */
- if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
- CWX | CWY |
+ /* XXX if this causes bad things.. we can compress config req's
+ with the same mask. */
+ e->xconfigurerequest.value_mask |=
+ ce.xconfigurerequest.value_mask;
+ if (ce.xconfigurerequest.value_mask & CWX)
+ e->xconfigurerequest.x = ce.xconfigurerequest.x;
+ if (ce.xconfigurerequest.value_mask & CWY)
+ e->xconfigurerequest.y = ce.xconfigurerequest.y;
+ if (ce.xconfigurerequest.value_mask & CWWidth)
+ e->xconfigurerequest.width = ce.xconfigurerequest.width;
+ if (ce.xconfigurerequest.value_mask & CWHeight)
+ e->xconfigurerequest.height = ce.xconfigurerequest.height;
+ if (ce.xconfigurerequest.value_mask & CWBorderWidth)
+ e->xconfigurerequest.border_width =
+ ce.xconfigurerequest.border_width;
+ if (ce.xconfigurerequest.value_mask & CWStackMode)
+ e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
+ }
+
+ /* if we are iconic (or shaded (fvwm does this)) ignore the event */
+ if (client->iconic || client->shaded) return;
+
+ /* resize, then move, as specified in the EWMH section 7.7 */
+ if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
+ CWX | CWY |
CWBorderWidth)) {
- int x, y, w, h;
- ObCorner corner;
+ gint x, y, w, h;
+ ObCorner corner;
if (e->xconfigurerequest.value_mask & CWBorderWidth)
client->border_width = e->xconfigurerequest.border_width;
- x = (e->xconfigurerequest.value_mask & CWX) ?
- e->xconfigurerequest.x : client->area.x;
- y = (e->xconfigurerequest.value_mask & CWY) ?
- e->xconfigurerequest.y : client->area.y;
- w = (e->xconfigurerequest.value_mask & CWWidth) ?
- e->xconfigurerequest.width : client->area.width;
- h = (e->xconfigurerequest.value_mask & CWHeight) ?
- e->xconfigurerequest.height : client->area.height;
+ x = (e->xconfigurerequest.value_mask & CWX) ?
+ e->xconfigurerequest.x : client->area.x;
+ y = (e->xconfigurerequest.value_mask & CWY) ?
+ e->xconfigurerequest.y : client->area.y;
+ w = (e->xconfigurerequest.value_mask & CWWidth) ?
+ e->xconfigurerequest.width : client->area.width;
+ h = (e->xconfigurerequest.value_mask & CWHeight) ?
+ e->xconfigurerequest.height : client->area.height;
{
- int newx = x;
- int newy = y;
- int fw = w +
- client->frame->size.left + client->frame->size.right;
- int fh = h +
- client->frame->size.top + client->frame->size.bottom;
+ gint newx = x;
+ gint newy = y;
+ gint fw = w +
+ client->frame->size.left + client->frame->size.right;
+ gint fh = h +
+ client->frame->size.top + client->frame->size.bottom;
client_find_onscreen(client, &newx, &newy, fw, fh,
- client_noral(self));
+ FALSE);
if (e->xconfigurerequest.value_mask & CWX)
x = newx;
if (e->xconfigurerequest.value_mask & CWY)
y = newy;
}
-
- switch (client->gravity) {
- case NorthEastGravity:
- case EastGravity:
- corner = OB_CORNER_TOPRIGHT;
- break;
- case SouthWestGravity:
- case SouthGravity:
- corner = OB_CORNER_BOTTOMLEFT;
- break;
- case SouthEastGravity:
- corner = OB_CORNER_BOTTOMRIGHT;
- break;
- default: /* NorthWest, Static, etc */
- corner = OB_CORNER_TOPLEFT;
- }
-
- client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
+
+ switch (client->gravity) {
+ case NorthEastGravity:
+ case EastGravity:
+ corner = OB_CORNER_TOPRIGHT;
+ break;
+ case SouthWestGravity:
+ case SouthGravity:
+ corner = OB_CORNER_BOTTOMLEFT;
+ break;
+ case SouthEastGravity:
+ corner = OB_CORNER_BOTTOMRIGHT;
+ break;
+ default: /* NorthWest, Static, etc */
+ corner = OB_CORNER_TOPLEFT;
+ }
+
+ client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
TRUE);
- }
-
- if (e->xconfigurerequest.value_mask & CWStackMode) {
- switch (e->xconfigurerequest.detail) {
- case Below:
- case BottomIf:
- stacking_lower(CLIENT_AS_WINDOW(client));
- break;
-
- case Above:
- case TopIf:
- default:
- stacking_raise(CLIENT_AS_WINDOW(client));
- break;
- }
- }
- break;
+ }
+
+ if (e->xconfigurerequest.value_mask & CWStackMode) {
+ switch (e->xconfigurerequest.detail) {
+ case Below:
+ case BottomIf:
+ client_lower(client);
+ break;
+
+ case Above:
+ case TopIf:
+ default:
+ client_raise(client);
+ break;
+ }
+ }
+ break;
case UnmapNotify:
- if (client->ignore_unmaps) {
- client->ignore_unmaps--;
- break;
- }
- client_unmanage(client);
- break;
+ if (client->ignore_unmaps) {
+ client->ignore_unmaps--;
+ break;
+ }
+ client_unmanage(client);
+ break;
case DestroyNotify:
- client_unmanage(client);
- break;
+ client_unmanage(client);
+ break;
case ReparentNotify:
- /* this is when the client is first taken captive in the frame */
- if (e->xreparent.parent == client->frame->plate) break;
-
- /*
- This event is quite rare and is usually handled in unmapHandler.
- However, if the window is unmapped when the reparent event occurs,
- the window manager never sees it because an unmap event is not sent
- to an already unmapped window.
- */
-
- /* we don't want the reparent event, put it back on the stack for the
- X server to deal with after we unmanage the window */
- XPutBackEvent(ob_display, e);
+ /* this is when the client is first taken captive in the frame */
+ if (e->xreparent.parent == client->frame->plate) break;
+
+ /*
+ This event is quite rare and is usually handled in unmapHandler.
+ However, if the window is unmapped when the reparent event occurs,
+ the window manager never sees it because an unmap event is not sent
+ to an already unmapped window.
+ */
+
+ /* we don't want the reparent event, put it back on the stack for the
+ X server to deal with after we unmanage the window */
+ XPutBackEvent(ob_display, e);
- client_unmanage(client);
- break;
+ client_unmanage(client);
+ break;
case MapRequest:
ob_debug("MapRequest for 0x%lx\n", client->window);
if (!client->iconic) break; /* this normally doesn't happen, but if it
- does, we don't want it! */
- if (screen_showing_desktop)
- screen_show_desktop(FALSE);
- client_iconify(client, FALSE, TRUE);
- if (!client->frame->visible)
- /* if its not visible still, then don't mess with it */
- break;
- if (client->shaded)
- client_shade(client, FALSE);
- client_focus(client);
- stacking_raise(CLIENT_AS_WINDOW(client));
- break;
+ does, we don't want it!
+ it can happen now when the window is on
+ another desktop, but we still don't
+ want it! */
+ client_activate(client, FALSE, TRUE);
+ break;
case ClientMessage:
- /* validate cuz we query stuff off the client here */
- if (!client_validate(client)) break;
-
- if (e->xclient.format != 32) return;
-
- msgtype = e->xclient.message_type;
- if (msgtype == prop_atoms.wm_change_state) {
- /* compress changes into a single change */
- while (XCheckTypedWindowEvent(ob_display, e->type,
- client->window, &ce)) {
- /* XXX: it would be nice to compress ALL messages of a
- type, not just messages in a row without other
- message types between. */
- if (ce.xclient.message_type != msgtype) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
- e->xclient = ce.xclient;
- }
- client_set_wm_state(client, e->xclient.data.l[0]);
- } else if (msgtype == prop_atoms.net_wm_desktop) {
- /* compress changes into a single change */
- while (XCheckTypedWindowEvent(ob_display, e->type,
- client->window, &ce)) {
- /* XXX: it would be nice to compress ALL messages of a
- type, not just messages in a row without other
- message types between. */
- if (ce.xclient.message_type != msgtype) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
- e->xclient = ce.xclient;
- }
+ /* validate cuz we query stuff off the client here */
+ if (!client_validate(client)) break;
+
+ if (e->xclient.format != 32) return;
+
+ msgtype = e->xclient.message_type;
+ if (msgtype == prop_atoms.wm_change_state) {
+ /* compress changes into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ /* XXX: it would be nice to compress ALL messages of a
+ type, not just messages in a row without other
+ message types between. */
+ if (ce.xclient.message_type != msgtype) {
+ XPutBackEvent(ob_display, &ce);
+ break;
+ }
+ e->xclient = ce.xclient;
+ }
+ client_set_wm_state(client, e->xclient.data.l[0]);
+ } else if (msgtype == prop_atoms.net_wm_desktop) {
+ /* compress changes into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ /* XXX: it would be nice to compress ALL messages of a
+ type, not just messages in a row without other
+ message types between. */
+ if (ce.xclient.message_type != msgtype) {
+ XPutBackEvent(ob_display, &ce);
+ break;
+ }
+ e->xclient = ce.xclient;
+ }
if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
(unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
FALSE);
- } else if (msgtype == prop_atoms.net_wm_state) {
- /* can't compress these */
- ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
+ } else if (msgtype == prop_atoms.net_wm_state) {
+ /* can't compress these */
+ ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
(e->xclient.data.l[0] == 0 ? "Remove" :
e->xclient.data.l[0] == 1 ? "Add" :
e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
e->xclient.data.l[1], e->xclient.data.l[2],
client->window);
- client_set_state(client, e->xclient.data.l[0],
- e->xclient.data.l[1], e->xclient.data.l[2]);
- } else if (msgtype == prop_atoms.net_close_window) {
- ob_debug("net_close_window for 0x%lx\n", client->window);
- client_close(client);
- } else if (msgtype == prop_atoms.net_active_window) {
- ob_debug("net_active_window for 0x%lx\n", client->window);
- client_activate(client, FALSE);
- } else if (msgtype == prop_atoms.net_wm_moveresize) {
- ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
+ client_set_state(client, e->xclient.data.l[0],
+ e->xclient.data.l[1], e->xclient.data.l[2]);
+ } else if (msgtype == prop_atoms.net_close_window) {
+ ob_debug("net_close_window for 0x%lx\n", client->window);
+ client_close(client);
+ } else if (msgtype == prop_atoms.net_active_window) {
+ ob_debug("net_active_window for 0x%lx source=%s\n",
+ client->window,
+ (e->xclient.data.l[0] == 0 ? "unknown" :
+ (e->xclient.data.l[0] == 1 ? "application" :
+ (e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
+ /* XXX make use of data.l[1] and [2] ! */
+ client_activate(client, FALSE,
+ (e->xclient.data.l[0] == 0 ||
+ e->xclient.data.l[0] == 2));
+ } else if (msgtype == prop_atoms.net_wm_moveresize) {
+ ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
if ((Atom)e->xclient.data.l[2] ==
prop_atoms.net_wm_moveresize_size_topleft ||
(Atom)e->xclient.data.l[2] ==
e->xclient.data.l[2]);
}
} else if (msgtype == prop_atoms.net_moveresize_window) {
- int oldg = client->gravity;
- int tmpg, x, y, w, h;
+ gint oldg = client->gravity;
+ gint tmpg, x, y, w, h;
if (e->xclient.data.l[0] & 0xff)
tmpg = e->xclient.data.l[0] & 0xff;
client->gravity = tmpg;
{
- int newx = x;
- int newy = y;
- int fw = w +
- client->frame->size.left + client->frame->size.right;
- int fh = h +
- client->frame->size.top + client->frame->size.bottom;
+ gint newx = x;
+ gint newy = y;
+ gint fw = w +
+ client->frame->size.left + client->frame->size.right;
+ gint fh = h +
+ client->frame->size.top + client->frame->size.bottom;
client_find_onscreen(client, &newx, &newy, fw, fh,
- client_normal(self));
+ client_normal(client));
if (e->xclient.data.l[0] & 1 << 8)
x = newx;
if (e->xclient.data.l[0] & 1 << 9)
y = newy;
}
-
+
client_configure(client, OB_CORNER_TOPLEFT,
x, y, w, h, FALSE, TRUE);
client->gravity = oldg;
}
- break;
+ break;
case PropertyNotify:
- /* validate cuz we query stuff off the client here */
- if (!client_validate(client)) break;
+ /* validate cuz we query stuff off the client here */
+ if (!client_validate(client)) break;
- /* compress changes to a single property into a single change */
- while (XCheckTypedWindowEvent(ob_display, e->type,
- client->window, &ce)) {
- /* XXX: it would be nice to compress ALL changes to a property,
- not just changes in a row without other props between. */
- if (ce.xproperty.atom != e->xproperty.atom) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
- }
-
- msgtype = e->xproperty.atom;
- if (msgtype == XA_WM_NORMAL_HINTS) {
- client_update_normal_hints(client);
- /* normal hints can make a window non-resizable */
- client_setup_decor_and_functions(client);
- }
- else if (msgtype == XA_WM_HINTS)
- client_update_wmhints(client);
- else if (msgtype == XA_WM_TRANSIENT_FOR) {
- client_update_transient_for(client);
- client_get_type(client);
- /* type may have changed, so update the layer */
- client_calc_layer(client);
- client_setup_decor_and_functions(client);
- }
- else if (msgtype == prop_atoms.net_wm_name ||
- msgtype == prop_atoms.wm_name ||
- msgtype == prop_atoms.net_wm_icon_name ||
- msgtype == prop_atoms.wm_icon_name)
- client_update_title(client);
- else if (msgtype == prop_atoms.wm_class)
- client_update_class(client);
- else if (msgtype == prop_atoms.wm_protocols) {
- client_update_protocols(client);
- client_setup_decor_and_functions(client);
- }
- else if (msgtype == prop_atoms.net_wm_strut) {
- client_update_strut(client);
+ /* compress changes to a single property into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ Atom a, b;
+
+ /* XXX: it would be nice to compress ALL changes to a property,
+ not just changes in a row without other props between. */
+
+ a = ce.xproperty.atom;
+ b = e->xproperty.atom;
+
+ if (a == b)
+ continue;
+ if ((a == prop_atoms.net_wm_name ||
+ a == prop_atoms.wm_name ||
+ a == prop_atoms.net_wm_icon_name ||
+ a == prop_atoms.wm_icon_name)
+ &&
+ (b == prop_atoms.net_wm_name ||
+ b == prop_atoms.wm_name ||
+ b == prop_atoms.net_wm_icon_name ||
+ b == prop_atoms.wm_icon_name)) {
+ continue;
+ }
+ if ((a == prop_atoms.net_wm_icon ||
+ a == prop_atoms.kwm_win_icon)
+ &&
+ (b == prop_atoms.net_wm_icon ||
+ b == prop_atoms.kwm_win_icon))
+ continue;
+
+ XPutBackEvent(ob_display, &ce);
+ break;
+ }
+
+ msgtype = e->xproperty.atom;
+ if (msgtype == XA_WM_NORMAL_HINTS) {
+ client_update_normal_hints(client);
+ /* normal hints can make a window non-resizable */
+ client_setup_decor_and_functions(client);
+ } else if (msgtype == XA_WM_HINTS) {
+ client_update_wmhints(client);
+ } else if (msgtype == XA_WM_TRANSIENT_FOR) {
+ client_update_transient_for(client);
+ client_get_type(client);
+ /* type may have changed, so update the layer */
+ client_calc_layer(client);
+ client_setup_decor_and_functions(client);
+ } else if (msgtype == prop_atoms.net_wm_name ||
+ msgtype == prop_atoms.wm_name ||
+ msgtype == prop_atoms.net_wm_icon_name ||
+ msgtype == prop_atoms.wm_icon_name) {
+ client_update_title(client);
+ } else if (msgtype == prop_atoms.wm_class) {
+ client_update_class(client);
+ } else if (msgtype == prop_atoms.wm_protocols) {
+ client_update_protocols(client);
+ client_setup_decor_and_functions(client);
+ }
+ else if (msgtype == prop_atoms.net_wm_strut) {
+ client_update_strut(client);
+ }
+ else if (msgtype == prop_atoms.net_wm_icon ||
+ msgtype == prop_atoms.kwm_win_icon) {
+ client_update_icons(client);
+ }
+ else if (msgtype == prop_atoms.sm_client_id) {
+ client_update_sm_client_id(client);
}
- else if (msgtype == prop_atoms.net_wm_icon ||
- msgtype == prop_atoms.kwm_win_icon)
- client_update_icons(client);
default:
;
#ifdef SHAPE
}
}
-static void event_handle_menu(ObClient *client, XEvent *e)
+static void event_handle_dock(ObDock *s, XEvent *e)
{
- ObMenuEntry *entry;
- ObMenu *top;
- GList *it = NULL;
-
- top = g_list_nth_data(menu_visible, 0);
-
- ob_debug("EVENT %d\n", e->type);
switch (e->type) {
- case KeyPress:
- menu_control_keyboard_nav(e->xkey.keycode);
- break;
case ButtonPress:
- ob_debug("BUTTON PRESS\n");
-
+ if (e->xbutton.button == 1)
+ stacking_raise(DOCK_AS_WINDOW(s), FALSE);
+ else if (e->xbutton.button == 2)
+ stacking_lower(DOCK_AS_WINDOW(s), FALSE);
break;
- case ButtonRelease:
- ob_debug("BUTTON RELEASED\n");
-
- for (it = menu_visible; it; it = g_list_next(it)) {
- ObMenu *m = it->data;
- if (e->xbutton.x_root >= m->location.x - ob_rr_theme->bwidth &&
- e->xbutton.y_root >= m->location.y - ob_rr_theme->bwidth &&
- e->xbutton.x_root < m->location.x + m->size.width +
- ob_rr_theme->bwidth &&
- e->xbutton.y_root < m->location.y + m->size.height +
- ob_rr_theme->bwidth) {
- if ((entry = menu_find_entry_by_pos(it->data,
- e->xbutton.x_root -
- m->location.x,
- e->xbutton.y_root -
- m->location.y))) {
- m->selected(entry, e->xbutton.button,
- e->xbutton.x_root,
- e->xbutton.y_root);
- break;
- }
- break;
- }
- }
-
- /* will call the menu_hide() for each submenu as well */
- if (!it)
- menu_control_keyboard_nav(ob_keycode(OB_KEY_ESCAPE));
-
+ case EnterNotify:
+ dock_hide(FALSE);
break;
+ case LeaveNotify:
+ dock_hide(TRUE);
+ break;
+ }
+}
+
+static void event_handle_dockapp(ObDockApp *app, XEvent *e)
+{
+ switch (e->type) {
case MotionNotify:
- ob_debug("motion\n");
- for (it = menu_visible; it; it = g_list_next(it)) {
- ObMenu *m = it->data;
- if ((entry = menu_find_entry_by_pos(it->data,
- e->xmotion.x_root -
- m->location.x,
- e->xmotion.y_root -
- m->location.y))) {
- if (m->over && m->over->data != entry)
- m->mouseover(m->over->data, FALSE);
-
- m->mouseover(entry, TRUE);
- break;
- }
+ dock_app_drag(app, &e->xmotion);
+ break;
+ case UnmapNotify:
+ if (app->ignore_unmaps) {
+ app->ignore_unmaps--;
+ break;
}
-
+ dock_remove(app, TRUE);
+ break;
+ case DestroyNotify:
+ dock_remove(app, FALSE);
+ break;
+ case ReparentNotify:
+ dock_remove(app, FALSE);
+ break;
+ case ConfigureNotify:
+ dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
break;
}
}
-void event_add_fd_handler(event_fd_handler *h) {
- g_datalist_id_set_data(&fd_handler_list, h->fd, h);
- FD_SET(h->fd, &allset);
- max_fd = MAX(max_fd, h->fd);
+ObMenuFrame* find_active_menu()
+{
+ GList *it;
+ ObMenuFrame *ret = NULL;
+
+ for (it = menu_frame_visible; it; it = g_list_next(it)) {
+ ret = it->data;
+ if (ret->selected)
+ break;
+ ret = NULL;
+ }
+ return ret;
}
-static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
+ObMenuFrame* find_active_or_last_menu()
{
- *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
+ ObMenuFrame *ret = NULL;
+
+ ret = find_active_menu();
+ if (!ret && menu_frame_visible)
+ ret = menu_frame_visible->data;
+ return ret;
}
-static void find_max_fd()
-{
- int tmpmax = -1;
- g_datalist_foreach(&fd_handler_list, find_max_fd_foreach,
- (gpointer)&tmpmax);
- max_fd = MAX(x_fd, tmpmax);
-#ifdef USE_SM
- max_fd = MAX(ice_fd, max_fd);
-#endif
+static void event_handle_menu(XEvent *ev)
+{
+ ObMenuFrame *f;
+ ObMenuEntryFrame *e;
+
+ switch (ev->type) {
+ case ButtonRelease:
+ if (menu_can_hide) {
+ if ((e = menu_entry_frame_under(ev->xbutton.x_root,
+ ev->xbutton.y_root)))
+ menu_entry_frame_execute(e, ev->xbutton.state);
+ else
+ menu_frame_hide_all();
+ }
+ break;
+ case MotionNotify:
+ if ((f = menu_frame_under(ev->xmotion.x_root,
+ ev->xmotion.y_root))) {
+ menu_frame_move_on_screen(f);
+ if ((e = menu_entry_frame_under(ev->xmotion.x_root,
+ ev->xmotion.y_root)))
+ menu_frame_select(f, e);
+ }
+ {
+ ObMenuFrame *a;
+
+ a = find_active_menu();
+ if (a && a != f &&
+ a->selected->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
+ {
+ menu_frame_select(a, NULL);
+ }
+ }
+ break;
+ case KeyPress:
+ if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
+ menu_frame_hide_all();
+ else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
+ ObMenuFrame *f;
+ if ((f = find_active_menu()))
+ menu_entry_frame_execute(f->selected, ev->xkey.state);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
+ ObMenuFrame *f;
+ if ((f = find_active_or_last_menu()) && f->parent)
+ menu_frame_select(f, NULL);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
+ ObMenuFrame *f;
+ if ((f = find_active_or_last_menu()) && f->child)
+ menu_frame_select_next(f->child);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
+ ObMenuFrame *f;
+ if ((f = find_active_or_last_menu()))
+ menu_frame_select_previous(f);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
+ ObMenuFrame *f;
+ if ((f = find_active_or_last_menu()))
+ menu_frame_select_next(f);
+ }
+ break;
+ }
}
-void event_remove_fd(int n)
+static gboolean menu_hide_delay_func(gpointer data)
{
- FD_CLR(n, &allset);
- g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
- find_max_fd();
+ menu_can_hide = TRUE;
+ return FALSE; /* no repeat */
}
-static void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
+static gboolean focus_delay_func(gpointer data)
{
- if (FD_ISSET( (int)n, &selset)) {
- event_fd_handler *h = (event_fd_handler *)data;
- g_assert(h->fd == (int)n);
- h->handler(h->fd, h->data);
+ ObClient *c = data;
+
+ if (focus_client != c) {
+ client_focus(c);
+ if (config_focus_raise)
+ client_raise(c);
}
+ return FALSE; /* no repeat */
}
-static void fd_event_handle()
+static void focus_delay_client_dest(ObClient *client, gpointer data)
{
- g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
+ ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
+ client, TRUE);
}
-static void event_handle_dock(ObDock *s, XEvent *e)
+static void event_client_dest(ObClient *client, gpointer data)
{
- switch (e->type) {
- case ButtonPress:
- stacking_raise(DOCK_AS_WINDOW(s));
- break;
- case EnterNotify:
- dock_hide(FALSE);
- break;
- case LeaveNotify:
- dock_hide(TRUE);
- break;
- }
+ if (client == focus_hilite)
+ focus_hilite = NULL;
}
-static void event_handle_dockapp(ObDockApp *app, XEvent *e)
+void event_halt_focus_delay()
{
- switch (e->type) {
- case MotionNotify:
- dock_app_drag(app, &e->xmotion);
- break;
- case UnmapNotify:
- if (app->ignore_unmaps) {
- app->ignore_unmaps--;
- break;
- }
- dock_remove(app, TRUE);
- break;
- case DestroyNotify:
- dock_remove(app, FALSE);
- break;
- case ReparentNotify:
- dock_remove(app, FALSE);
- break;
- case ConfigureNotify:
- dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
- break;
+ ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
+}
+
+void event_ignore_queued_enters()
+{
+ GSList *saved = NULL, *it;
+ XEvent *e;
+
+ XSync(ob_display, FALSE);
+
+ /* count the events */
+ while (TRUE) {
+ e = g_new(XEvent, 1);
+ if (XCheckTypedEvent(ob_display, EnterNotify, e)) {
+ ObWindow *win;
+
+ win = g_hash_table_lookup(window_map, &e->xany.window);
+ if (win && WINDOW_IS_CLIENT(win))
+ ++ignore_enter_focus;
+
+ saved = g_slist_append(saved, e);
+ } else {
+ g_free(e);
+ break;
+ }
+ }
+ /* put the events back */
+ for (it = saved; it; it = g_slist_next(it)) {
+ XPutBackEvent(ob_display, it->data);
+ g_free(it->data);
}
+ g_slist_free(saved);
}