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.
This commit is contained in:
Dana Jansens 2008-01-11 14:40:58 -05:00
parent b447f16f60
commit 0ce14a7279

View file

@ -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 @@ static void event_set_curtime(XEvent *e)
event_last_user_time = CurrentTime;
event_curtime = t;
event_curserial = 0;
}
static void event_hack_mods(XEvent *e)
@ -479,6 +483,7 @@ static void event_process(const XEvent *ec, gpointer data)
}
event_set_curtime(e);
event_curserial = e->xany.serial;
event_hack_mods(e);
if (event_ignore(e, client)) {
if (ed)
@ -1010,18 +1015,23 @@ static void event_handle_client(ObClient *client, XEvent *e)
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 @@ static gboolean focus_delay_func(gpointer data)
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,35 +1886,44 @@ static void focus_delay_client_dest(ObClient *client, gpointer data)
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)
{
GSList *it, *next;