all repos — openbox @ 0ce14a727968736e57fb3fabba3794b46903875f

openbox fork - make it a bit more like ryudo

fix a focus race condition in two ways:

1. when focusing a window, ignore any enter events up until the serial of the X event causing the focus, not up until the last thing sent to the server.  if we get 2 enters very quickly, then we don't want to ignore the second one just because we are focusing the first window.
2. there is a race if you check (focus_client != d->client) in the delay_focus_func, because the current focused window might change by the time this focus_client would take effect, so don't check that.
Dana Jansens danakj@orodu.net
commit

0ce14a727968736e57fb3fabba3794b46903875f

parent

b447f16f6080e1a92c3ea6a5848609a7a96ea3ce

1 files changed, 31 insertions(+), 14 deletions(-)

jump to
M openbox/event.copenbox/event.c

@@ -91,6 +91,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e);

static void event_handle_client(ObClient *c, XEvent *e); static void event_handle_user_input(ObClient *client, XEvent *e); static gboolean is_enter_focus_event_ignored(XEvent *e); +static void event_ignore_enter_range(gulong start, gulong end); static void focus_delay_dest(gpointer data); static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);

@@ -99,6 +100,8 @@ static void focus_delay_client_dest(ObClient *client, gpointer data);

Time event_curtime = CurrentTime; Time event_last_user_time = CurrentTime; +/*! The serial of the current X event */ +gulong event_curserial; static gboolean focus_left_screen = FALSE; /*! A list of ObSerialRanges which are to be ignored for mouse enter events */

@@ -243,6 +246,7 @@ if (t && event_last_user_time && event_time_after(event_last_user_time, t))

event_last_user_time = CurrentTime; event_curtime = t; + event_curserial = 0; } static void event_hack_mods(XEvent *e)

@@ -479,6 +483,7 @@ }

} event_set_curtime(e); + event_curserial = e->xany.serial; event_hack_mods(e); if (event_ignore(e, client)) { if (ed)

@@ -1010,18 +1015,23 @@ e->xcrossing.detail == NotifyInferior ||

is_enter_focus_event_ignored(e)) { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx IGNORED\n", + "%sNotify mode %d detail %d serial %lu on %lx " + "IGNORED\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + e->xcrossing.detail, + e->xcrossing.serial, + client?client->window:0); } else { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx, " + "%sNotify mode %d detail %d serial %lu on %lx, " "focusing window\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, (client?client->window:0)); + e->xcrossing.detail, + e->xcrossing.serial, + (client?client->window:0)); if (config_focus_follow) event_enter_client(client); }

@@ -1864,10 +1874,8 @@ /* don't move focus and kill the menu or the move/resize */

if (menu_frame_visible || moveresize_in_progress) return FALSE; event_curtime = d->time; - if (focus_client != d->client) { - if (client_focus(d->client) && config_focus_raise) - stacking_raise(CLIENT_AS_WINDOW(d->client)); - } + if (client_focus(d->client) && config_focus_raise) + stacking_raise(CLIENT_AS_WINDOW(d->client)); event_curtime = old; return FALSE; /* no repeat */ }

@@ -1878,33 +1886,42 @@ ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,

client, FALSE); } -void event_halt_focus_delay(void) +void event_halt_focus_delay(gulong serial) { - /* ignore all enter events up till now */ - event_end_ignore_all_enters(1); + /* ignore all enter events up till the event which caused this to occur */ + if (event_curserial) event_ignore_enter_range(1, event_curserial); ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); } gulong event_start_ignore_all_enters(void) { + /* increment the serial so we don't ignore events we weren't meant to */ XSync(ob_display, FALSE); return LastKnownRequestProcessed(ob_display); } -void event_end_ignore_all_enters(gulong start) +static void event_ignore_enter_range(gulong start, gulong end) { ObSerialRange *r; g_assert(start != 0); - XSync(ob_display, FALSE); + g_assert(end != 0); r = g_new(ObSerialRange, 1); r->start = start; - r->end = LastKnownRequestProcessed(ob_display); + r->end = end; ignore_serials = g_slist_prepend(ignore_serials, r); + + ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu\n", + r->start, r->end); /* increment the serial so we don't ignore events we weren't meant to */ XSync(ob_display, FALSE); +} + +void event_end_ignore_all_enters(gulong start) +{ + event_ignore_enter_range(start, LastKnownRequestProcessed(ob_display)); } static gboolean is_enter_focus_event_ignored(XEvent *e)