Merge branch 'backport' into work
[mikachu/openbox.git] / openbox / client.c
index 38dc7c1..50a0dbe 100644 (file)
@@ -33,7 +33,6 @@
 #include "focus.h"
 #include "stacking.h"
 #include "openbox.h"
-#include "hooks.h"
 #include "group.h"
 #include "config.h"
 #include "menuframe.h"
@@ -80,7 +79,6 @@ static void client_get_area(ObClient *self);
 static void client_get_desktop(ObClient *self);
 static void client_get_state(ObClient *self);
 static void client_get_shaped(ObClient *self);
-static void client_get_mwm_hints(ObClient *self);
 static void client_get_colormap(ObClient *self);
 static void client_set_desktop_recursive(ObClient *self,
                                          guint target,
@@ -107,6 +105,8 @@ static GSList *client_search_all_top_parents_internal(ObClient *self,
 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);
+static gboolean client_can_steal_focus(ObClient *self, Time steal_time,
+                                       Time launch_time);
 
 void client_startup(gboolean reconfig)
 {
@@ -420,121 +420,14 @@ void client_manage(Window window, ObPrompt *prompt)
     ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
                   activate ? "yes" : "no");
     if (activate) {
-        gboolean raise = 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));
-
-        /* This is focus stealing prevention */
-        ob_debug_type(OB_DEBUG_FOCUS,
-                      "Want to focus new window 0x%x at time %u "
-                      "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 focused: %d  relative focused: %d",
-                      parent_focused, relative_focused);
-
-        if (menu_frame_visible || moveresize_in_progress) {
-            activate = FALSE;
-            raise = TRUE;
-            ob_debug_type(OB_DEBUG_FOCUS,
-                          "Not focusing the window because the user is inside "
-                          "an Openbox menu or is move/resizing a window and "
-                          "we don't want to interrupt them");
-        }
-
-        /* if it's on another desktop */
-        else if (!(self->desktop == screen_desktop ||
-                   self->desktop == DESKTOP_ALL) &&
-                 /* the timestamp is from before you changed desktops */
-                 launch_time && screen_desktop_user_time &&
-                 !event_time_after(launch_time, screen_desktop_user_time))
-        {
-            activate = FALSE;
-            raise = TRUE;
-            ob_debug_type(OB_DEBUG_FOCUS,
-                          "Not focusing the window because its on another "
-                          "desktop");
-        }
-        /* If something is focused... */
-        else if (focus_client) {
-            /* If the user is working in another window right now, then don't
-               steal focus */
-            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,
-                                 map_time - OB_EVENT_USER_TIME_DELAY))
-            {
-                activate = FALSE;
-                ob_debug_type(OB_DEBUG_FOCUS,
-                              "Not focusing the window because the user is "
-                              "working in another window that is not "
-                              "its parent");
-            }
-            /* If the new window is a transient (and its relatives aren't
-               focused) */
-            else if (client_has_parent(self) && !relative_focused) {
-                activate = FALSE;
-                ob_debug_type(OB_DEBUG_FOCUS,
-                              "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))
-            {
-                activate = FALSE;
-                ob_debug_type(OB_DEBUG_FOCUS,
-                              "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) {
-                activate = FALSE;
-                raise = TRUE;
-                ob_debug_type(OB_DEBUG_FOCUS,
-                              "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)
-            {
-                activate = FALSE;
-                raise = TRUE;
-                ob_debug_type(OB_DEBUG_FOCUS,
-                              "Not focusing the window because it is on "
-                              "another desktop and no relatives are focused ");
-            }
-        }
+        activate = client_can_steal_focus(self, map_time, launch_time);
 
         if (!activate) {
-            ob_debug_type(OB_DEBUG_FOCUS,
-                          "Focus stealing prevention activated for %s at "
-                          "time %u (last user interaction time %u)",
-                          self->title, map_time, event_last_user_time);
-            /* if the client isn't focused, then hilite it so the user
-               knows it is there */
-            client_hilite(self, TRUE);
-            /* we may want to raise it even tho we're not activating it */
-            if (raise && !client_restore_session_stacking(self))
-                stacking_raise(CLIENT_AS_WINDOW(self));
+            /* if the client isn't stealing focus, then hilite it so the user
+               knows it is there, but don't do this if we're restoring from a
+               session */
+            if (!client_restore_session_stacking(self))
+                client_hilite(self, TRUE);
         }
     }
     else {
@@ -586,8 +479,6 @@ void client_manage(Window window, ObPrompt *prompt)
 
     ob_debug("Managed window 0x%lx plate 0x%x (%s)",
              window, self->frame->window, self->class);
-
-    hooks_queue(OB_HOOK_WIN_NEW, self);
 }
 
 ObClient *client_fake_manage(Window window)
@@ -662,9 +553,6 @@ void client_unmanage(ObClient *self)
     if (!self->prompt)
         XChangeSaveSet(obt_display, self->window, SetModeDelete);
 
-    /* this can't be queued to run later */
-    hooks_run(OB_HOOK_WIN_CLOSE, self);
-
     /* update the focus lists */
     focus_order_remove(self);
     if (client_focused(self)) {
@@ -788,6 +676,105 @@ void client_fake_unmanage(ObClient *self)
     g_free(self);
 }
 
+static gboolean client_can_steal_focus(ObClient *self, Time steal_time,
+                                       Time launch_time)
+{
+    gboolean steal;
+    gboolean relative_focused;
+    gboolean parent_focused;
+
+    steal = TRUE;
+
+    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));
+
+    /* This is focus stealing prevention */
+    ob_debug_type(OB_DEBUG_FOCUS,
+                  "Want to focus new window 0x%x at time %u "
+                  "launched at %u (last user interaction time %u)",
+                  self->window, steal_time, launch_time,
+                  event_last_user_time);
+
+    /* if it's on another desktop */
+    if (!(self->desktop == screen_desktop ||
+          self->desktop == DESKTOP_ALL) &&
+        /* the timestamp is from before you changed desktops */
+        launch_time && screen_desktop_user_time &&
+        !event_time_after(launch_time, screen_desktop_user_time))
+    {
+        steal = FALSE;
+        ob_debug_type(OB_DEBUG_FOCUS,
+                      "Not focusing the window because its on another "
+                      "desktop\n");
+    }
+    /* If something is focused... */
+    else if (focus_client) {
+        /* If the user is working in another window right now, then don't
+           steal focus */
+        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,
+                             steal_time - OB_EVENT_USER_TIME_DELAY))
+        {
+            steal = FALSE;
+            ob_debug_type(OB_DEBUG_FOCUS,
+                          "Not focusing the window because the user is "
+                          "working in another window that is not "
+                          "its parent");
+        }
+        /* 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_type(OB_DEBUG_FOCUS,
+                          "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_type(OB_DEBUG_FOCUS,
+                          "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) {
+            steal = FALSE;
+            ob_debug_type(OB_DEBUG_FOCUS,
+                          "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_type(OB_DEBUG_FOCUS,
+                          "Not focusing the window because it is on "
+                          "another desktop and no relatives are focused ");
+        }
+    }
+
+    if (!steal)
+        ob_debug_type(OB_DEBUG_FOCUS,
+                      "Focus stealing prevention activated for %s at "
+                      "time %u (last user interaction time %u)",
+                      self->title, steal_time, event_last_user_time);
+    return steal;
+}
+
 /*! Returns a new structure containing the per-app settings for this client.
   The returned structure needs to be freed with g_free. */
 static ObAppSettings *client_get_settings_state(ObClient *self)
@@ -1409,7 +1396,7 @@ static void client_update_transient_tree(ObClient *self,
     }
 }
 
-static void client_get_mwm_hints(ObClient *self)
+void client_get_mwm_hints(ObClient *self)
 {
     guint num;
     guint32 *hints;
@@ -1759,7 +1746,8 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
     /* finally, the user can have requested no decorations, which overrides
        everything (but doesnt give it a border if it doesnt have one) */
     if (self->undecorated)
-        self->decorations = 0;
+        self->decorations &= (config_theme_keepborder ?
+                              OB_FRAME_DECOR_BORDER : 0);
 
     /* if we don't have a titlebar, then we cannot shade! */
     if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
@@ -2379,7 +2367,7 @@ ObClient *client_search_focus_tree_full(ObClient *self)
 
         for (it = self->parents; it; it = g_slist_next(it)) {
             ObClient *c = it->data;
-            if ((c = client_search_focus_tree_full(it->data))) return c;
+            if ((c = client_search_focus_tree_full(c))) return c;
         }
 
         return NULL;
@@ -2547,8 +2535,6 @@ gboolean client_show(ObClient *self)
            desktop!
         */
         client_change_wm_state(self);
-
-        hooks_queue(OB_HOOK_WIN_VISIBLE, self);
     }
     return show;
 }
@@ -2558,10 +2544,6 @@ gboolean client_hide(ObClient *self)
     gboolean hide = FALSE;
 
     if (!client_should_show(self)) {
-        if (self == focus_client) {
-            event_cancel_all_key_grabs();
-        }
-
         /* We don't need to ignore enter events here.
            The window can hide/iconify in 3 different ways:
            1 - through an x message. in this case we ignore all enter events
@@ -2587,8 +2569,6 @@ gboolean client_hide(ObClient *self)
            desktop!
         */
         client_change_wm_state(self);
-
-        hooks_queue(OB_HOOK_WIN_INVISIBLE, self);
     }
     return hide;
 }
@@ -3182,9 +3162,6 @@ static void client_iconify_recursive(ObClient *self,
             frame_begin_iconify_animation(self->frame, iconic);
         /* do this after starting the animation so it doesn't flash */
         client_showhide(self);
-
-        hooks_queue((iconic ? OB_HOOK_WIN_ICONIC : OB_HOOK_WIN_UNICONIC),
-                    self);
     }
 
     /* iconify all direct transients, and deiconify all transients
@@ -3272,8 +3249,6 @@ void client_maximize(ObClient *self, gboolean max, gint dir)
 
     client_setup_decor_and_functions(self, FALSE);
     client_move_resize(self, x, y, w, h);
-
-    hooks_queue((max ? OB_HOOK_WIN_MAX : OB_HOOK_WIN_UNMAX), self);
 }
 
 void client_shade(ObClient *self, gboolean shade)
@@ -3287,8 +3262,6 @@ void client_shade(ObClient *self, gboolean shade)
     client_change_wm_state(self); /* the window is being hidden/shown */
     /* resize the frame to just the titlebar */
     frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
-
-    hooks_queue((shade ? OB_HOOK_WIN_SHADE : OB_HOOK_WIN_UNSHADE), self);
 }
 
 static void client_ping_event(ObClient *self, gboolean dead)
@@ -3460,8 +3433,18 @@ void client_hilite(ObClient *self, gboolean hilite)
     /* don't allow focused windows to hilite */
     self->demands_attention = hilite && !client_focused(self);
     if (self->frame != NULL) { /* if we're mapping, just set the state */
-        if (self->demands_attention)
+        if (self->demands_attention) {
             frame_flash_start(self->frame);
+
+            /* if the window is on another desktop then raise it and make it
+               the most recently used window */
+            if (self->desktop != screen_desktop &&
+                self->desktop != DESKTOP_ALL)
+            {
+                stacking_raise(CLIENT_AS_WINDOW(self));
+                focus_order_to_top(self);
+            }
+        }
         else
             frame_flash_stop(self->frame);
         client_change_state(self);
@@ -3500,9 +3483,6 @@ static void client_set_desktop_recursive(ObClient *self,
             /* the new desktop's geometry may be different, so we may need to
                resize, for example if we are maximized */
             client_reconfigure(self, FALSE);
-
-        if (old != self->desktop)
-            hooks_queue(OB_HOOK_WIN_DESK_CHANGE, self);
     }
 
     /* move all transients */
@@ -3640,6 +3620,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 value = self->demands_attention;
             else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
                 value = undecorated;
+            else
+                g_assert_not_reached();
             action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) :
                              OBT_PROP_ATOM(NET_WM_STATE_ADD);
         }
@@ -3777,8 +3759,6 @@ gboolean client_focus(ObClient *self)
        go moving on us */
     event_halt_focus_delay();
 
-    event_cancel_all_key_grabs();
-
     obt_display_ignore_errors(TRUE);
 
     if (self->can_focus) {
@@ -3837,12 +3817,16 @@ static void client_present(ObClient *self, gboolean here, gboolean raise,
 }
 
 /* this function exists to map to the net_active_window message in the ewmh */
-void client_activate(ObClient *self, gboolean here, gboolean raise,
+void client_activate(ObClient *self, gboolean desktop, gboolean raise,
                      gboolean unshade, gboolean user)
 {
-    if (user || (self->desktop == DESKTOP_ALL ||
-                 self->desktop == screen_desktop))
-        client_present(self, here, raise, unshade);
+    if ((user && (desktop ||
+                  self->desktop == DESKTOP_ALL ||
+                  self->desktop == screen_desktop)) ||
+        client_can_steal_focus(self, event_curtime, CurrentTime))
+    {
+        client_present(self, FALSE, raise, unshade);
+    }
     else
         client_hilite(self, TRUE);
 }
@@ -3927,9 +3911,6 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
         self->undecorated = undecorated;
         client_setup_decor_and_functions(self, TRUE);
         client_change_state(self); /* reflect this in the state hints */
-
-        hooks_queue((undecorated ?
-                     OB_HOOK_WIN_UNDECORATED : OB_HOOK_WIN_DECORATED), self);
     }
 }