Make NET_ACTIVE messages always treated as from the user. Loosen up focus stealing for user-requested focusing.

Seems panels such as xfce's and gnome's still treat their activation requests
  as being from an application when a user has requested it.

Make the focus stealing code more lenient for user-requested focusings
  (_NET_ACTIVE).  But treat new windows as not user-requested unless they
  gave a launch time.

When activating a window, if another window would be the one to actually get
  focused, then activate that instead (avoid clicking a window in the panel and
  nothing happens).
This commit is contained in:
Dana Jansens 2010-10-16 17:19:24 -04:00
parent d291a9c7aa
commit 385967b552
2 changed files with 66 additions and 46 deletions

View file

@ -110,6 +110,7 @@ static void client_ping_event(ObClient *self, gboolean dead);
static void client_prompt_kill(ObClient *self); static void client_prompt_kill(ObClient *self);
static gboolean client_can_steal_focus(ObClient *self, static gboolean client_can_steal_focus(ObClient *self,
gboolean allow_other_desktop, gboolean allow_other_desktop,
gboolean request_from_user,
Time steal_time, Time launch_time); Time steal_time, Time launch_time);
void client_startup(gboolean reconfig) void client_startup(gboolean reconfig)
@ -303,6 +304,7 @@ void client_manage(Window window, ObPrompt *prompt)
try_activate ? "yes" : "no"); try_activate ? "yes" : "no");
if (try_activate) if (try_activate)
do_activate = client_can_steal_focus(self, settings->focus, do_activate = client_can_steal_focus(self, settings->focus,
!!launch_time,
event_time(), launch_time); event_time(), launch_time);
else else
do_activate = FALSE; do_activate = FALSE;
@ -694,6 +696,7 @@ void client_fake_unmanage(ObClient *self)
static gboolean client_can_steal_focus(ObClient *self, static gboolean client_can_steal_focus(ObClient *self,
gboolean allow_other_desktop, gboolean allow_other_desktop,
gboolean request_from_user,
Time steal_time, Time steal_time,
Time launch_time) Time launch_time)
{ {
@ -708,9 +711,10 @@ static gboolean client_can_steal_focus(ObClient *self,
/* This is focus stealing prevention */ /* This is focus stealing prevention */
ob_debug("Want to focus window 0x%x at time %u " ob_debug("Want to focus window 0x%x at time %u "
"launched at %u (last user interaction time %u)", "launched at %u (last user interaction time %u) "
"request from %s",
self->window, steal_time, launch_time, self->window, steal_time, launch_time,
event_last_user_time); event_last_user_time, (request_from_user ? "user" : "other"));
/* /*
if no launch time is provided for an application, make one up. if no launch time is provided for an application, make one up.
@ -739,33 +743,41 @@ static gboolean client_can_steal_focus(ObClient *self,
if (event_last_user_time && client_search_focus_group_full(self)) { if (event_last_user_time && client_search_focus_group_full(self)) {
/* our relative is focused */ /* our relative is focused */
launch_time = event_last_user_time; launch_time = event_last_user_time;
ob_debug("Unknown launch time, using %u window in active " ob_debug("Unknown launch time, using %u - window in active "
"group", launch_time);
}
else if (!request_from_user) {
/* has relatives which are not being used. suspicious */
launch_time = event_time() - OB_EVENT_USER_TIME_DELAY;
ob_debug("Unknown launch time, using %u - window in inactive "
"group", launch_time); "group", launch_time);
} }
else { else {
/* has relatives which are not being used. suspicious */ /* has relatives which are not being used, but the user seems
launch_time = event_time() - OB_EVENT_USER_TIME_DELAY; to want to go there! */
ob_debug("Unknown launch time, using %u window in inactive " launch_time = event_last_user_time;
"group", launch_time); ob_debug("Unknown launch time, using %u - user request",
launch_time);
} }
} }
else { else {
/* the window is on its own, probably the user knows it is going /* the window is on its own, probably the user knows it is going
to appear */ to appear */
launch_time = event_last_user_time; launch_time = event_last_user_time;
ob_debug("Unknown launch time, using %u for solo window", ob_debug("Unknown launch time, using %u - independent window",
launch_time); launch_time);
} }
} }
/* if it's on another desktop /* if it's on another desktop
then if allow_other_desktop is false, we don't want to let it steal then if allow_other_desktop is true, we don't want to let it steal
focus, unless it was launched after we changed desktops focus, unless it was launched after we changed desktops and the request
came from the user
*/ */
if (!(self->desktop == screen_desktop || if (!(self->desktop == screen_desktop ||
self->desktop == DESKTOP_ALL) && self->desktop == DESKTOP_ALL) &&
(!allow_other_desktop || (!allow_other_desktop ||
(screen_desktop_user_time && (request_from_user && screen_desktop_user_time &&
!event_time_after(launch_time, screen_desktop_user_time)))) !event_time_after(launch_time, screen_desktop_user_time))))
{ {
steal = FALSE; steal = FALSE;
@ -787,23 +799,6 @@ static gboolean client_can_steal_focus(ObClient *self,
ob_debug("Not focusing the window because the user is " ob_debug("Not focusing the window because the user is "
"working in another window that is not its relative"); "working in another window that is not its relative");
} }
/* If the new window is a transient (and its relatives aren't
focused) */
else if (client_has_parent(self) && !relative_focused) {
steal = FALSE;
ob_debug("Not focusing the window because it is a "
"transient, and its relatives aren't focused");
}
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
else if (!(focus_client->can_focus ||
focus_client->focus_notify))
{
steal = FALSE;
ob_debug("Not focusing the window because a globally "
"active client has focus");
}
/* Don't move focus if it's not going to go to this window /* Don't move focus if it's not going to go to this window
anyway */ anyway */
else if (client_focus_target(self) != self) { else if (client_focus_target(self) != self) {
@ -811,15 +806,33 @@ static gboolean client_can_steal_focus(ObClient *self,
ob_debug("Not focusing the window because another window " ob_debug("Not focusing the window because another window "
"would get the focus anyway"); "would get the focus anyway");
} }
/* Don't move focus if the window is not visible on the current /* For requests that don't come from the user */
desktop and none of its relatives are focused */ else if (!request_from_user) {
else if (!(self->desktop == screen_desktop || /* If the new window is a transient (and its relatives aren't
self->desktop == DESKTOP_ALL) && focused) */
!relative_focused) if (client_has_parent(self) && !relative_focused) {
{ steal = FALSE;
steal = FALSE; ob_debug("Not focusing the window because it is a "
ob_debug("Not focusing the window because it is on " "transient, and its relatives aren't focused");
"another desktop and no relatives are focused "); }
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
else if (!(focus_client->can_focus || focus_client->focus_notify))
{
steal = FALSE;
ob_debug("Not focusing the window because a globally "
"active client has focus");
}
/* Don't move focus if the window is not visible on the current
desktop and none of its relatives are focused */
else if (!screen_compare_desktops(self->desktop, screen_desktop) &&
!relative_focused)
{
steal = FALSE;
ob_debug("Not focusing the window because it is on "
"another desktop and no relatives are focused ");
}
} }
} }
@ -827,6 +840,10 @@ static gboolean client_can_steal_focus(ObClient *self,
ob_debug("Focus stealing prevention activated for %s at " ob_debug("Focus stealing prevention activated for %s at "
"time %u (last user interaction time %u)", "time %u (last user interaction time %u)",
self->title, steal_time, event_last_user_time); self->title, steal_time, event_last_user_time);
else
ob_debug("Allowing focus stealing for %s at time %u (last user "
"interaction time %u)",
self->title, steal_time, event_last_user_time);
return steal; return steal;
} }
@ -3961,13 +3978,10 @@ void client_activate(ObClient *self, gboolean desktop,
gboolean here, gboolean raise, gboolean here, gboolean raise,
gboolean unshade, gboolean user) gboolean unshade, gboolean user)
{ {
if ((user && (desktop || self = client_focus_target(self);
self->desktop == DESKTOP_ALL ||
self->desktop == screen_desktop)) || if (client_can_steal_focus(self, desktop, user, event_time(), CurrentTime))
client_can_steal_focus(self, desktop, event_time(), CurrentTime))
{
client_present(self, here, raise, unshade); client_present(self, here, raise, unshade);
}
else else
client_hilite(self, TRUE); client_hilite(self, TRUE);
} }

View file

@ -1443,9 +1443,15 @@ static void event_handle_client(ObClient *client, XEvent *e)
ob_debug_type(OB_DEBUG_APP_BUGS, ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is " "_NET_ACTIVE_WINDOW message for window %s is "
"missing source indication", client->title); "missing source indication", client->title);
client_activate(client, FALSE, FALSE, TRUE, TRUE, /* TODO(danakj) This should use
(e->xclient.data.l[0] == 0 || (e->xclient.data.l[0] == 0 ||
e->xclient.data.l[0] == 2)); e->xclient.data.l[0] == 2)
to determine if a user requested the activation, however GTK+
applications seem unable to make this distinction ever
(including panels such as xfce4-panel and gnome-panel).
So we are left just assuming all activations are from the user.
*/
client_activate(client, FALSE, FALSE, TRUE, TRUE, TRUE);
} else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) { } else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) {
ob_debug("net_wm_moveresize for 0x%lx direction %d", ob_debug("net_wm_moveresize for 0x%lx direction %d",
client->window, e->xclient.data.l[2]); client->window, e->xclient.data.l[2]);