Make NET_ACTIVE messages always treated as from the user. Loosen up focus stealing...
authorDana Jansens <danakj@orodu.net>
Sat, 16 Oct 2010 21:19:24 +0000 (17:19 -0400)
committerDana Jansens <danakj@orodu.net>
Mon, 24 Jan 2011 19:19:23 +0000 (14:19 -0500)
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).

openbox/client.c
openbox/event.c

index 35afb31..35b146e 100644 (file)
@@ -110,6 +110,7 @@ static void client_ping_event(ObClient *self, gboolean dead);
 static void client_prompt_kill(ObClient *self);
 static gboolean client_can_steal_focus(ObClient *self,
                                        gboolean allow_other_desktop,
+                                       gboolean request_from_user,
                                        Time steal_time, Time launch_time);
 
 void client_startup(gboolean reconfig)
@@ -303,6 +304,7 @@ void client_manage(Window window, ObPrompt *prompt)
              try_activate ? "yes" : "no");
     if (try_activate)
         do_activate = client_can_steal_focus(self, settings->focus,
+                                             !!launch_time,
                                              event_time(), launch_time);
     else
         do_activate = FALSE;
@@ -694,6 +696,7 @@ void client_fake_unmanage(ObClient *self)
 
 static gboolean client_can_steal_focus(ObClient *self,
                                        gboolean allow_other_desktop,
+                                       gboolean request_from_user,
                                        Time steal_time,
                                        Time launch_time)
 {
@@ -708,9 +711,10 @@ static gboolean client_can_steal_focus(ObClient *self,
 
     /* This is focus stealing prevention */
     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,
-             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.
@@ -739,33 +743,41 @@ static gboolean client_can_steal_focus(ObClient *self,
             if (event_last_user_time && client_search_focus_group_full(self)) {
                 /* our relative is focused */
                 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 {
+            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 "
+                ob_debug("Unknown launch time, using %u window in inactive "
                          "group", launch_time);
             }
+            else {
+                /* has relatives which are not being used, but the user seems
+                   to want to go there! */
+            launch_time = event_last_user_time;
+            ob_debug("Unknown launch time, using %u - user request",
+                     launch_time);
+            }
         }
         else {
             /* the window is on its own, probably the user knows it is going
                to appear */
             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);
         }
     }
 
     /* if it's on another desktop
-       then if allow_other_desktop is false, we don't want to let it steal
-       focus, unless it was launched after we changed desktops
+       then if allow_other_desktop is true, we don't want to let it steal
+       focus, unless it was launched after we changed desktops and the request
+       came from the user
      */
     if (!(self->desktop == screen_desktop ||
           self->desktop == DESKTOP_ALL) &&
         (!allow_other_desktop ||
-         (screen_desktop_user_time &&
+         (request_from_user && screen_desktop_user_time &&
           !event_time_after(launch_time, screen_desktop_user_time))))
     {
         steal = FALSE;
@@ -787,23 +799,6 @@ static gboolean client_can_steal_focus(ObClient *self,
             ob_debug("Not focusing the window because the user is "
                      "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
            anyway */
         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 "
                      "would get the focus anyway");
         }
-        /* Don't move focus if the window is not visible on the current
-           desktop and none of its relatives are focused */
-        else if (!(self->desktop == screen_desktop ||
-                   self->desktop == DESKTOP_ALL) &&
-                 !relative_focused)
-        {
-            steal = FALSE;
-            ob_debug("Not focusing the window because it is on "
-                     "another desktop and no relatives are focused ");
+        /* For requests that don't come from the user */
+        else if (!request_from_user) {
+            /* If the new window is a transient (and its relatives aren't
+               focused) */
+            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 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 "
                  "time %u (last user interaction time %u)",
                  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;
 }
 
@@ -3961,13 +3978,10 @@ void client_activate(ObClient *self, gboolean desktop,
                      gboolean here, gboolean raise,
                      gboolean unshade, gboolean user)
 {
-    if ((user && (desktop ||
-                  self->desktop == DESKTOP_ALL ||
-                  self->desktop == screen_desktop)) ||
-        client_can_steal_focus(self, desktop, event_time(), CurrentTime))
-    {
+    self = client_focus_target(self);
+
+    if (client_can_steal_focus(self, desktop, user, event_time(), CurrentTime))
         client_present(self, here, raise, unshade);
-    }
     else
         client_hilite(self, TRUE);
 }
index 8a52402..b39660a 100644 (file)
@@ -1443,9 +1443,15 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 ob_debug_type(OB_DEBUG_APP_BUGS,
                               "_NET_ACTIVE_WINDOW message for window %s is "
                               "missing source indication", client->title);
-            client_activate(client, FALSE, FALSE, TRUE, TRUE,
-                            (e->xclient.data.l[0] == 0 ||
-                             e->xclient.data.l[0] == 2));
+            /* TODO(danakj) This should use
+               (e->xclient.data.l[0] == 0 ||
+                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)) {
             ob_debug("net_wm_moveresize for 0x%lx direction %d",
                      client->window, e->xclient.data.l[2]);