summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDana Jansens <danakj@orodu.net>2008-01-11 14:40:58 -0500
committerDana Jansens <danakj@orodu.net>2008-01-11 14:40:58 -0500
commit0ce14a727968736e57fb3fabba3794b46903875f (patch)
tree47919ce820037090a407995f227348cd6e079a5b
parentb447f16f6080e1a92c3ea6a5848609a7a96ea3ce (diff)
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.
-rw-r--r--openbox/event.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/openbox/event.c b/openbox/event.c
index e3214a7a..03229117 100644
--- a/openbox/event.c
+++ b/openbox/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 @@ 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;