Merge branch 'backport' into work
[mikachu/openbox.git] / openbox / client.c
index e9443d4..5686a93 100644 (file)
@@ -108,7 +108,6 @@ static void client_call_notifies(ObClient *self, GSList *list);
 static void client_ping_event(ObClient *self, gboolean dead);
 static void client_prompt_kill(ObClient *self);
 
-
 void client_startup(gboolean reconfig)
 {
     if ((client_default_icon = RrImageCacheFind(ob_rr_icons,
@@ -203,6 +202,7 @@ void client_manage(Window window, ObPrompt *prompt)
     gboolean transient = FALSE;
     Rect place, *monitor;
     Time launch_time, map_time;
+    gint user_time;
 
     ob_debug("Managing window: 0x%lx", window);
 
@@ -233,6 +233,7 @@ void client_manage(Window window, ObPrompt *prompt)
 
     ob_debug("Window type: %d", self->type);
     ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
+    ob_debug("Window name: %s class: %s", self->name, self->class);
 
     /* now we have all of the window's information so we can set this up.
        do this before creating the frame, so it can tell that we are still
@@ -264,6 +265,9 @@ void client_manage(Window window, ObPrompt *prompt)
     /* tell startup notification that this app started */
     launch_time = sn_app_started(self->startup_id, self->class, self->name);
 
+    if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time))
+        user_time = map_time;
+
     /* do this after we have a frame.. it uses the frame to help determine the
        WM_STATE to apply. */
     client_change_state(self);
@@ -280,6 +284,8 @@ void client_manage(Window window, ObPrompt *prompt)
         /* this means focus=true for window is same as config_focus_new=true */
         ((config_focus_new || (settings && settings->focus == 1)) ||
          client_search_focus_tree_full(self)) &&
+        /* NET_WM_USER_TIME 0 when mapping means don't focus */
+        (user_time != 0) &&
         /* this checks for focus=false for the window */
         (!settings || settings->focus != 0) &&
         focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE))
@@ -414,12 +420,14 @@ void client_manage(Window window, ObPrompt *prompt)
                   activate ? "yes" : "no");
     if (activate) {
         gboolean raise = FALSE;
-        gboolean relative_focused = FALSE;
+        gboolean relative_focused;
+        gboolean parent_focused;
 
+        parent_focused = (focus_client != NULL &&
+                          client_search_focus_parent(self));
         relative_focused = (focus_client != NULL &&
-                            client_search_focus_tree_full(self) != NULL &&
-                            client_search_focus_group_full(self) != NULL);
-
+                            (client_search_focus_tree_full(self) != NULL ||
+                             client_search_focus_group_full(self) != NULL));
 
         /* This is focus stealing prevention */
         ob_debug_type(OB_DEBUG_FOCUS,
@@ -427,6 +435,12 @@ void client_manage(Window window, ObPrompt *prompt)
                       "launched at %u (last user interaction time %u)",
                       self->window, map_time, launch_time,
                       event_last_user_time);
+        ob_debug_type(OB_DEBUG_FOCUS,
+                      "Current focus_client: %s",
+                      (focus_client ? focus_client->title : "(none)"));
+        ob_debug_type(OB_DEBUG_FOCUS,
+                      "parent focuesed: %d  relative focused: %d",
+                      parent_focused, relative_focused);
 
         if (menu_frame_visible || moveresize_in_progress) {
             activate = FALSE;
@@ -454,7 +468,8 @@ void client_manage(Window window, ObPrompt *prompt)
         else if (focus_client) {
             /* If the user is working in another window right now, then don't
                steal focus */
-            if (event_last_user_time && launch_time &&
+            if (!parent_focused &&
+                event_last_user_time && launch_time &&
                 event_time_after(event_last_user_time, launch_time) &&
                 event_last_user_time != launch_time &&
                 event_time_after(event_last_user_time,
@@ -463,7 +478,8 @@ void client_manage(Window window, ObPrompt *prompt)
                 activate = FALSE;
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Not focusing the window because the user is "
-                              "working in another window");
+                              "working in another window that is not "
+                              "its parent");
             }
             /* If the new window is a transient (and its relatives aren't
                focused) */
@@ -573,7 +589,6 @@ void client_manage(Window window, ObPrompt *prompt)
     hooks_queue(OB_HOOK_WIN_NEW, self);
 }
 
-
 ObClient *client_fake_manage(Window window)
 {
     ObClient *self;
@@ -1300,7 +1315,6 @@ static void client_update_transient_tree(ObClient *self,
       transient windows as their children.
       * * */
 
-
     /* No change has occured */
     if (oldgroup == newgroup &&
         oldgtran == newgtran &&
@@ -2116,7 +2130,6 @@ void client_update_icons(ObClient *self)
                                        (gint*)&w, (gint*)&h, &data);
                 obt_display_ignore_errors(FALSE);
 
-
                 if (xicon) {
                     if (w > 0 && h > 0) {
                         /* is this icon in the cache yet? */
@@ -2613,7 +2626,6 @@ gboolean client_enter_focusable(ObClient *self)
             self->type != OB_CLIENT_TYPE_DESKTOP);
 }
 
-
 static void client_apply_startup_state(ObClient *self,
                                        gint x, gint y, gint w, gint h)
 {
@@ -2923,7 +2935,6 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
     g_assert(*h > 0);
 }
 
-
 void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
                       gboolean user, gboolean final, gboolean force_reply)
 {
@@ -3958,6 +3969,21 @@ ObClient *client_search_focus_parent(ObClient *self)
     return NULL;
 }
 
+ObClient *client_search_focus_parent_full(ObClient *self)
+{
+    GSList *it;
+    ObClient *ret = NULL;
+
+    for (it = self->parents; it; it = g_slist_next(it)) {
+        if (client_focused(it->data))
+            ret = it->data;
+        else
+            ret = client_search_focus_parent_full(it->data);
+        if (ret) break;
+    }
+    return ret;
+}
+
 ObClient *client_search_parent(ObClient *self, ObClient *search)
 {
     GSList *it;