/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
event.c for the Openbox window manager
- Copyright (c) 2004 Mikael Magnusson
+ Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003 Ben Jansens
This program is free software; you can redistribute it and/or modify
gboolean ignored;
} ObEventData;
+typedef struct
+{
+ ObClient *client;
+ Time time;
+} ObFocusDelayData;
+
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_client(ObClient *c, XEvent *e);
static void event_handle_group(ObGroup *g, XEvent *e);
+static void focus_delay_dest(gpointer data);
+static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
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 > NotifyNonlinearVirtual)
-#define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
- (e)->xfocus.detail == NotifyInferior || \
- (e)->xfocus.detail == NotifyAncestor || \
- (e)->xfocus.detail > NotifyNonlinearVirtual)
-
-Time event_lasttime = 0;
+/* The time for the current event being processed */
+Time event_curtime = CurrentTime;
/*! The value of the mask for the NumLock modifier */
guint NumLockMask;
#endif
client_add_destructor(focus_delay_client_dest, NULL);
- client_add_destructor(event_client_dest, NULL);
}
void event_shutdown(gboolean reconfig)
#endif
client_remove_destructor(focus_delay_client_dest);
- client_remove_destructor(event_client_dest);
XFreeModifiermap(modmap);
}
return window;
}
-static void event_set_lasttime(XEvent *e)
+static void event_set_curtime(XEvent *e)
{
- Time t = 0;
+ Time t = CurrentTime;
/* grab the lasttime and hack up the state */
switch (e->type) {
break;
}
- if (t > event_lasttime)
- event_lasttime = t;
+ event_curtime = t;
}
#define STRIP_MODS(s) \
}
}
-static gboolean event_ignore(XEvent *e, ObClient *client)
+static gboolean wanted_focusevent(XEvent *e)
{
- switch(e->type) {
- case EnterNotify:
- case LeaveNotify:
- if (e->xcrossing.detail == NotifyInferior)
+ gint mode = e->xfocus.mode;
+ gint detail = e->xfocus.detail;
+ Window win = e->xany.window;
+
+ if (e->type == FocusIn) {
+
+ /* These are ones we never want.. */
+
+ /* This means focus was given by a keyboard/mouse grab. */
+ if (mode == NotifyGrab)
+ return FALSE;
+ /* This means focus was given back from a keyboard/mouse grab. */
+ if (mode == NotifyUngrab)
+ return FALSE;
+
+ /* These are the ones we want.. */
+
+ if (win == RootWindow(ob_display, ob_screen)) {
+ /* This means focus reverted off of a client */
+ if (detail == NotifyPointerRoot || detail == NotifyDetailNone ||
+ detail == NotifyInferior)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* This means focus moved from the root window to a client */
+ if (detail == NotifyVirtual)
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
- pointer root on a workspace change, then the FocusIn event that we
- want will be of type NotifyAncestor. This situation does not occur
- for FocusOut, so it is safely ignored there.
- */
- 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);
-#endif
- /* says a client was not found for the event (or a valid FocusIn
- event was not found.
- */
- e->xfocus.window = None;
+ /* This means focus moved from one client to another */
+ if (detail == NotifyNonlinearVirtual)
return TRUE;
- }
-#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
- e->xfocus.mode, e->xfocus.detail);
-#endif
- break;
- case FocusOut:
- 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);
-#endif
+ /* This means focus reverted off of a client */
+ if (detail == NotifyInferior)
return TRUE;
- }
-#ifdef DEBUG_FOCUS
- 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, e->xfocus.window,
- FocusOut, &fe))
- if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
- break;
- if (fe.type == FocusOut) {
-#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusOut\n");
-#endif
- if (!INVALID_FOCUSOUT(&fe)) {
- /* if there is a VALID FocusOut still coming, don't
- fallback focus yet, we'll deal with it then */
- XPutBackEvent(ob_display, &fe);
- fallback = FALSE;
- break;
- }
- } else {
-#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusIn\n");
-#endif
- /* is the focused window getting a FocusOut/In back to
- itself?
- */
- if (fe.xfocus.window == e->xfocus.window &&
- !event_ignore(&fe, client)) {
- /*
- if focus_client is not set, then we can't do
- this. we need the FocusIn. This happens in the
- case when the set_focus_client(NULL) in the
- focus_fallback function fires and then
- focus_fallback picks the currently focused
- window (such as on a SendToDesktop-esque action.
- */
- if (focus_client) {
-#ifdef DEBUG_FOCUS
- ob_debug("focused window got an Out/In back to "
- "itself IGNORED both\n");
-#endif
- return TRUE;
- } else {
- 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\n");
-#endif
- return TRUE;
- }
- }
-
- {
- 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\n");
-#endif
- focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
- }
- }
+ /* Otherwise.. */
+ return FALSE;
+ } else {
+ g_assert(e->type == FocusOut);
+
+
+ /* These are ones we never want.. */
+
+ /* This means focus was taken by a keyboard/mouse grab. */
+ if (mode == NotifyGrab)
+ return FALSE;
+
+ /* Focus left the root window revertedto state */
+ if (win == RootWindow(ob_display, ob_screen))
+ return FALSE;
+
+ /* These are the ones we want.. */
+
+ /* This means focus moved from a client to the root window */
+ if (detail == NotifyVirtual)
+ return TRUE;
+ /* This means focus moved from one client to another */
+ if (detail == NotifyNonlinearVirtual)
+ return TRUE;
+
+ /* Otherwise.. */
+ return FALSE;
+ }
+}
+
+static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg)
+{
+ return e->type == FocusIn && wanted_focusevent(e);
+}
+
+static gboolean event_ignore(XEvent *e, ObClient *client)
+{
+ switch(e->type) {
+ case FocusIn:
+ case FocusOut:
+ if (!wanted_focusevent(e))
+ return TRUE;
break;
}
return FALSE;
}
}
- event_set_lasttime(e);
+ event_set_curtime(e);
event_hack_mods(e);
if (event_ignore(e, client)) {
if (ed)
ed->ignored = FALSE;
/* deal with it in the kernel */
- if (group)
+
+ if (menu_frame_visible &&
+ (e->type == EnterNotify || e->type == LeaveNotify))
+ {
+ /* crossing events for menu */
+ event_handle_menu(e);
+ } else if (e->type == FocusIn) {
+ if (e->xfocus.detail == NotifyPointerRoot ||
+ e->xfocus.detail == NotifyDetailNone) {
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to root\n");
+ /* Focus has been reverted to the root window or nothing
+ FocusOut events come after UnmapNotify, so we don't need to
+ worry about focusing an invalid window
+ */
+ focus_fallback(TRUE);
+ } else if (e->xfocus.detail == NotifyInferior) {
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to parent\n");
+ /* Focus has been reverted to parent, which is our frame window,
+ or the root window
+ FocusOut events come after UnmapNotify, so we don't need to
+ worry about focusing an invalid window
+ */
+ focus_fallback(TRUE);
+ } else if (client && client != focus_client) {
+ frame_adjust_focus(client->frame, TRUE);
+ focus_set_client(client);
+ client_calc_layer(client);
+ }
+ } else if (e->type == FocusOut) {
+ gboolean nomove = FALSE;
+ XEvent ce;
+
+ ob_debug_type(OB_DEBUG_FOCUS, "FocusOut Event\n");
+
+ /* Look for the followup FocusIn */
+ if (!XCheckIfEvent(ob_display, &ce, look_for_focusin, NULL)) {
+ /* There is no FocusIn, this means focus went to a window that
+ is not being managed, or a window on another screen. */
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to a black hole !\n");
+ /* nothing is focused */
+ focus_set_client(NULL);
+ } else if (ce.xany.window == e->xany.window) {
+ /* If focus didn't actually move anywhere, there is nothing to do*/
+ nomove = TRUE;
+ } else {
+ /* Focus did move, so process the FocusIn event */
+ ObEventData ed = { .ignored = FALSE };
+ event_process(&ce, &ed);
+ if (ed.ignored) {
+ /* The FocusIn was ignored, this means it was on a window
+ that isn't a client. */
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Focus went to an unmanaged window 0x%x !\n",
+ ce.xfocus.window);
+ focus_fallback(TRUE);
+ }
+ }
+
+ if (client && !nomove) {
+ frame_adjust_focus(client->frame, FALSE);
+ client_calc_layer(client);
+ }
+ } else if (group)
event_handle_group(group, e);
else if (client)
event_handle_client(client, e);
ob_main_loop_timeout_add(ob_main_loop,
config_menu_hide_delay * 1000,
menu_hide_delay_func,
- NULL, NULL);
+ NULL, g_direct_equal, NULL);
if (e->type == ButtonPress || e->type == ButtonRelease ||
- e->type == MotionNotify)
+ e->type == MotionNotify) {
mouse_event(client, e);
- else if (e->type == KeyPress)
+ } else if (e->type == KeyPress) {
keyboard_event((focus_cycle_target ? focus_cycle_target :
- (focus_hilite ? focus_hilite : client)),
- e);
+ client), e);
+ }
}
}
}
+ /* if something happens and it's not from an XEvent, then we don't know
+ the time */
+ event_curtime = CurrentTime;
}
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(0);
+ ob_exit_replace();
break;
case ClientMessage:
msgtype = e->xclient.message_type;
if (msgtype == prop_atoms.net_current_desktop) {
guint d = e->xclient.data.l[0];
- if (d < screen_num_desktops)
+ if (d < screen_num_desktops) {
+ event_curtime = e->xclient.data.l[1];
+ ob_debug("SWITCH DESKTOP TIME: %d\n", event_curtime);
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 (client_normal(client) && client_can_focus(client)) {
if (config_focus_delay) {
+ ObFocusDelayData *data;
+
ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
+
+ data = g_new(ObFocusDelayData, 1);
+ data->client = client;
+ data->time = event_curtime;
+
ob_main_loop_timeout_add(ob_main_loop,
config_focus_delay,
focus_delay_func,
- client, NULL);
- } else
- focus_delay_func(client);
+ data, focus_delay_cmp, focus_delay_dest);
+ } else {
+ ObFocusDelayData data;
+ data.client = client;
+ data.time = event_curtime;
+ focus_delay_func(&data);
+ }
}
}
}
}
break;
- case FocusIn:
-#ifdef DEBUG_FOCUS
- 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 (client %lx) mode %d detail %d\n",
- e->xfocus.window, client->window,
- e->xfocus.mode, e->xfocus.detail);
-#endif
- focus_hilite = NULL;
- frame_adjust_focus(client->frame, FALSE);
- client_calc_layer(client);
- break;
case LeaveNotify:
con = frame_context(client, e->xcrossing.window);
switch (con) {
frame_adjust_state(client->frame);
break;
case OB_FRAME_CONTEXT_FRAME:
+ if (keyboard_interactively_grabbed())
+ break;
if (config_focus_follow && config_focus_delay)
ob_main_loop_timeout_remove_data(ob_main_loop,
focus_delay_func,
- client);
+ client, FALSE);
break;
default:
break;
frame_adjust_state(client->frame);
break;
case OB_FRAME_CONTEXT_FRAME:
+ if (keyboard_interactively_grabbed())
+ break;
if (e->xcrossing.mode == NotifyGrab ||
e->xcrossing.mode == NotifyUngrab)
{
-#ifdef DEBUG_FOCUS
- 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
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "%sNotify mode %d detail %d on %lx IGNORED\n",
+ (e->type == EnterNotify ? "Enter" : "Leave"),
+ e->xcrossing.mode,
+ e->xcrossing.detail, client?client->window:0);
} 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
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "%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);
if (!nofocus && config_focus_follow)
event_enter_client(client);
}
client->frame->size.left + client->frame->size.right;
gint fh = h +
client->frame->size.top + client->frame->size.bottom;
+ /* make this rude for size-only changes but not for position
+ changes.. */
+ gboolean moving = ((e->xconfigurerequest.value_mask & CWX) ||
+ (e->xconfigurerequest.value_mask & CWY));
+
client_find_onscreen(client, &newx, &newy, fw, fh,
- client_normal(client));
+ !moving);
if (e->xconfigurerequest.value_mask & CWX)
x = newx;
if (e->xconfigurerequest.value_mask & CWY)
switch (e->xconfigurerequest.detail) {
case Below:
case BottomIf:
- client_lower(client);
+ /* Apps are so rude. And this is totally disconnected from
+ activation/focus. Bleh. */
+ /*client_lower(client);*/
break;
case Above:
case TopIf:
default:
- client_raise(client);
+ /* Apps are so rude. And this is totally disconnected from
+ activation/focus. Bleh. */
+ /*client_raise(client);*/
break;
}
}
client->ignore_unmaps--;
break;
}
+ ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d "
+ "ignores left %d\n",
+ client->window, e->xunmap.event, e->xunmap.from_configure,
+ client->ignore_unmaps);
client_unmanage(client);
break;
case DestroyNotify:
+ ob_debug("DestroyNotify for window 0x%x\n", client->window);
client_unmanage(client);
break;
case ReparentNotify:
X server to deal with after we unmanage the window */
XPutBackEvent(ob_display, e);
+ ob_debug("ReparentNotify for window 0x%x\n", client->window);
client_unmanage(client);
break;
case MapRequest:
it can happen now when the window is on
another desktop, but we still don't
want it! */
- client_activate(client, FALSE);
+ client_activate(client, FALSE, TRUE);
break;
case ClientMessage:
/* validate cuz we query stuff off the client here */
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);
+ 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[2] ! */
+ event_curtime = e->xclient.data.l[1];
+ 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);
+ ob_debug("net_wm_moveresize for 0x%lx direction %d\n",
+ client->window, e->xclient.data.l[2]);
if ((Atom)e->xclient.data.l[2] ==
prop_atoms.net_wm_moveresize_size_topleft ||
(Atom)e->xclient.data.l[2] ==
e->xclient.data.l[1], e->xclient.data.l[3],
e->xclient.data.l[2]);
}
+ else if ((Atom)e->xclient.data.l[2] ==
+ prop_atoms.net_wm_moveresize_cancel)
+ moveresize_end(TRUE);
} else if (msgtype == prop_atoms.net_moveresize_window) {
gint oldg = client->gravity;
gint tmpg, x, y, w, h;
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))
+ if (a == prop_atoms.net_wm_icon &&
+ b == prop_atoms.net_wm_icon)
continue;
XPutBackEvent(ob_display, &ce);
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) {
+ else if (msgtype == prop_atoms.net_wm_icon) {
client_update_icons(client);
}
+ else if (msgtype == prop_atoms.net_wm_user_time) {
+ client_update_user_time(client);
+ }
else if (msgtype == prop_atoms.sm_client_id) {
client_update_sm_client_id(client);
}
switch (e->type) {
case ButtonPress:
if (e->xbutton.button == 1)
- stacking_raise(DOCK_AS_WINDOW(s), FALSE);
+ stacking_raise(DOCK_AS_WINDOW(s));
else if (e->xbutton.button == 2)
- stacking_lower(DOCK_AS_WINDOW(s), FALSE);
+ stacking_lower(DOCK_AS_WINDOW(s));
break;
case EnterNotify:
dock_hide(FALSE);
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);
+ menu_entry_frame_execute(e, ev->xbutton.state,
+ ev->xbutton.time);
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);
+ case EnterNotify:
+ if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
+ if (e->ignore_enters)
+ --e->ignore_enters;
+ else
+ menu_frame_select(e->frame, e);
}
+ break;
+ case LeaveNotify:
+ if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
+ (f = find_active_menu()) && f->selected == e &&
+ e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
{
- ObMenuFrame *a;
-
- a = find_active_menu();
- if (a && a != f &&
- a->selected->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
- {
- menu_frame_select(a, NULL);
- }
+ menu_frame_select(e->frame, NULL);
}
+ case MotionNotify:
+ if ((e = menu_entry_frame_under(ev->xmotion.x_root,
+ ev->xmotion.y_root)))
+ menu_frame_select(e->frame, e);
break;
case KeyPress:
if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
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);
+ menu_entry_frame_execute(f->selected, ev->xkey.state,
+ ev->xkey.time);
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
ObMenuFrame *f;
if ((f = find_active_or_last_menu()) && f->parent)
return FALSE; /* no repeat */
}
+static void focus_delay_dest(gpointer data)
+{
+ g_free(data);
+}
+
+static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
+{
+ const ObFocusDelayData *f1 = d1;
+ return f1->client == d2;
+}
+
static gboolean focus_delay_func(gpointer data)
{
- ObClient *c = data;
+ ObFocusDelayData *d = data;
+ Time old = event_curtime;
- if (focus_client != c) {
- client_focus(c);
- if (config_focus_raise)
- client_raise(c);
+ event_curtime = d->time;
+ if (focus_client != d->client) {
+ if (client_focus(d->client) && config_focus_raise)
+ client_raise(d->client);
}
+ event_curtime = old;
return FALSE; /* no repeat */
}
static void focus_delay_client_dest(ObClient *client, gpointer data)
{
- ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client);
-}
-
-static void event_client_dest(ObClient *client, gpointer data)
-{
- if (client == focus_hilite)
- focus_hilite = NULL;
+ ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
+ client, FALSE);
}
void event_halt_focus_delay()
}
g_slist_free(saved);
}
+
+gboolean event_time_after(Time t1, Time t2)
+{
+ g_assert(t1 != CurrentTime);
+ g_assert(t2 != CurrentTime);
+
+ /*
+ Timestamp values wrap around (after about 49.7 days). The server, given
+ its current time is represented by timestamp T, always interprets
+ timestamps from clients by treating half of the timestamp space as being
+ later in time than T.
+ - http://tronche.com/gui/x/xlib/input/pointer-grabbing.html
+ */
+
+ /* TIME_HALF is half of the number space of a Time type variable */
+#define TIME_HALF (Time)(1 << (sizeof(Time)*8-1))
+
+ if (t2 >= TIME_HALF)
+ /* t2 is in the second half so t1 might wrap around and be smaller than
+ t2 */
+ return t1 >= t2 || t1 < (t2 + TIME_HALF);
+ else
+ /* t2 is in the first half so t1 has to come after it */
+ return t1 >= t2 && t1 < (t2 + TIME_HALF);
+}