]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
all my changes while i was offline.
[chaz/openbox] / openbox / client.c
index 2fcbd003b481f72e48628557247a33ea67051e34..2cd92125ff8dfc7159564d417a4f910eb97ee657 100644 (file)
@@ -1,4 +1,5 @@
 #include "client.h"
+#include "startup.h"
 #include "screen.h"
 #include "moveresize.h"
 #include "prop.h"
@@ -26,9 +27,6 @@
 GList      *client_list      = NULL;
 GHashTable *client_map       = NULL;
 
-static Window *client_startup_stack_order = NULL;
-static guint  client_startup_stack_size = 0;
-
 static void client_get_all(Client *self);
 static void client_toggle_border(Client *self, gboolean show);
 static void client_get_area(Client *self);
@@ -40,10 +38,7 @@ static void client_get_gravity(Client *self);
 static void client_showhide(Client *self);
 static void client_change_allowed_actions(Client *self);
 static void client_change_state(Client *self);
-static void client_move_onscreen(Client *self);
-static Client *search_focus_tree(Client *node, Client *skip);
 static void client_apply_startup_state(Client *self);
-static Client *search_modal_tree(Client *node, Client *skip);
 
 static guint map_hash(Window *w) { return *w; }
 static gboolean map_key_comp(Window *w1, Window *w2) { return *w1 == *w2; }
@@ -53,11 +48,6 @@ void client_startup()
     client_map = g_hash_table_new((GHashFunc)map_hash,
                                  (GEqualFunc)map_key_comp);
 
-    /* save the stacking order on startup! */
-    PROP_GETA32(ob_root, net_client_list_stacking, window,
-                (guint32**)&client_startup_stack_order,
-                &client_startup_stack_size);
-
     client_set_list();
 }
 
@@ -89,12 +79,44 @@ void client_set_list()
     stacking_set_list();
 }
 
+/*
+void client_foreach_transient(Client *self, ClientForeachFunc func, void *data)
+{
+    GSList *it;
+
+    for (it = self->transients; it; it = it->next) {
+        if (!func(it->data, data)) return;
+        client_foreach_transient(it->data, func, data);
+    }
+}
+
+void client_foreach_ancestor(Client *self, ClientForeachFunc func, void *data)
+{
+    if (self->transient_for) {
+        if (self->transient_for != TRAN_GROUP) {
+            if (!func(self->transient_for, data)) return;
+            client_foreach_ancestor(self->transient_for, func, data);
+        } else {
+            GSList *it;
+
+            for (it = self->group->members; it; it = it->next)
+                if (it->data != self &&
+                    ((Client*)it->data)->transient_for != TRAN_GROUP) {
+                    if (!func(it->data, data)) return;
+                    client_foreach_ancestor(it->data, func, data);
+                }
+        }
+    }
+}
+*/
+
 void client_manage_all()
 {
     unsigned int i, j, nchild;
     Window w, *children;
     XWMHints *wmhints;
     XWindowAttributes attrib;
+    Client *active;
 
     XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild);
 
@@ -130,19 +152,22 @@ void client_manage_all()
        why with stacking_lower? Why, because then windows who aren't in the
        stacking list are on the top where you can see them instead of buried
        at the bottom! */
-    for (i = client_startup_stack_size; i > 0; --i) {
+    for (i = startup_stack_size; i > 0; --i) {
         Client *c;
 
-        w = client_startup_stack_order[i-1];
+        w = startup_stack_order[i-1];
         c = g_hash_table_lookup(client_map, &w);
         if (c) stacking_lower(c);
     }
-    g_free(client_startup_stack_order);
-    client_startup_stack_order = NULL;
-    client_startup_stack_size = 0;
+    g_free(startup_stack_order);
+    startup_stack_order = NULL;
+    startup_stack_size = 0;
 
-    if (config_focus_new)
-        focus_fallback(Fallback_NoFocus);
+    if (config_focus_new) {
+        active = g_hash_table_lookup(client_map, &startup_active);
+        if (!(active && client_focus(active)))
+            focus_fallback(Fallback_NoFocus);
+    }
 }
 
 void client_manage(Window window)
@@ -152,7 +177,6 @@ void client_manage(Window window)
     XWindowAttributes attrib;
     XSetWindowAttributes attrib_set;
 /*    XWMHints *wmhint; */
-    guint i;
 
     grab_server(TRUE);
 
@@ -222,13 +246,7 @@ void client_manage(Window window)
     g_hash_table_insert(client_map, &self->window, self);
 
     /* update the focus lists */
-    if (self->desktop == DESKTOP_ALL) {
-        for (i = 0; i < screen_num_desktops; ++i)
-            focus_order[i] = g_list_insert(focus_order[i], self, 1);
-    } else {
-        i = self->desktop;
-        focus_order[i] = g_list_insert(focus_order[i], self, 1);
-    }
+    focus_order_add_new(self);
 
     stacking_raise(self);
 
@@ -276,7 +294,7 @@ void client_manage(Window window)
                 (!parent && (!self->group ||
                              !self->group->members->next)))))) ||
             (parent && (client_focused(parent) ||
-                        search_focus_tree(parent, parent)))) {
+                        client_search_focus_tree(parent)))) {
             client_focus(self);
         }
     }
@@ -300,7 +318,6 @@ void client_unmanage_all()
 
 void client_unmanage(Client *self)
 {
-    guint i;
     int j;
     GSList *it;
 
@@ -322,13 +339,7 @@ void client_unmanage(Client *self)
     g_hash_table_remove(client_map, &self->window);
 
     /* update the focus lists */
-    if (self->desktop == DESKTOP_ALL) {
-        for (i = 0; i < screen_num_desktops; ++i)
-            focus_order[i] = g_list_remove(focus_order[i], self);
-    } else {
-        i = self->desktop;
-        focus_order[i] = g_list_remove(focus_order[i], self);
-    }
+    focus_order_remove(self);
 
     /* once the client is out of the list, update the struts to remove it's
        influence */
@@ -416,7 +427,7 @@ void client_unmanage(Client *self)
     client_set_list();
 }
 
-static void client_move_onscreen(Client *self)
+void client_move_onscreen(Client *self)
 {
     Rect *a;
     int x = self->frame->area.x, y = self->frame->area.y;
@@ -432,7 +443,7 @@ static void client_move_onscreen(Client *self)
         y = a->y;
 
     frame_frame_gravity(self->frame, &x, &y); /* get where the client
-                                              should be */
+                                                 should be */
     client_configure(self , Corner_TopLeft, x, y,
                      self->area.width, self->area.height,
                      TRUE, TRUE);
@@ -513,6 +524,7 @@ static void client_get_all(Client *self)
     /* defaults */
     self->frame = NULL;
     self->title = self->icon_title = NULL;
+    self->title_count = 1;
     self->name = self->class = self->role = NULL;
     self->wmstate = NormalState;
     self->transient = FALSE;
@@ -546,7 +558,6 @@ static void client_get_all(Client *self)
     client_setup_decor_and_functions(self);
   
     client_update_title(self);
-    client_update_icon_title(self);
     client_update_class(self);
     client_update_strut(self);
     client_update_icons(self);
@@ -799,10 +810,6 @@ void client_get_type(Client *self)
        else
            self->type = Type_Normal;
     }
-
-    /* this makes sure that these windows appear on all desktops */
-    if (self->type == Type_Desktop)
-       self->desktop = DESKTOP_ALL;
 }
 
 void client_update_protocols(Client *self)
@@ -1008,11 +1015,19 @@ void client_setup_decor_and_functions(Client *self)
     client_change_allowed_actions(self);
 
     if (self->frame) {
+        /* this makes sure that these windows appear on all desktops */
+        if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL)
+            client_set_desktop(self, DESKTOP_ALL, FALSE);
+
        /* change the decors on the frame, and with more/less decorations,
            we may also need to be repositioned */
        frame_adjust_area(self->frame, TRUE, TRUE);
        /* with new decor, the window's maximized size may change */
        client_remaximize(self);
+    } else {
+        /* this makes sure that these windows appear on all desktops */
+        if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL)
+            self->desktop = DESKTOP_ALL;
     }
 }
 
@@ -1021,7 +1036,9 @@ static void client_change_allowed_actions(Client *self)
     guint32 actions[9];
     int num = 0;
 
-    actions[num++] = prop_atoms.net_wm_action_change_desktop;
+    /* desktop windows are kept on all desktops */
+    if (self->type != Type_Desktop)
+        actions[num++] = prop_atoms.net_wm_action_change_desktop;
 
     if (self->functions & Func_Shade)
        actions[num++] = prop_atoms.net_wm_action_shade;
@@ -1171,6 +1188,9 @@ void client_update_wmhints(Client *self)
 
 void client_update_title(Client *self)
 {
+    GList *it;
+    guint32 nums;
+    guint i;
     char *data = NULL;
 
     g_free(self->title);
@@ -1182,6 +1202,29 @@ void client_update_title(Client *self)
            data = g_strdup("Unnamed Window");
 
     /* look for duplicates and append a number */
+    nums = 0;
+    for (it = client_list; it; it = it->next)
+        if (it->data != self) {
+            Client *c = it->data;
+            if (0 == strncmp(c->title, data, strlen(data)))
+                nums |= 1 << c->title_count;
+        }
+    /* find first free number */
+    for (i = 1; i <= 32; ++i)
+        if (!(nums & (1 << i))) {
+            if (self->title_count == 1 || i == 1)
+                self->title_count = i;
+            break;
+        }
+    /* dont display the number for the first window */
+    if (self->title_count > 1) {
+        char *vdata, *ndata;
+        ndata = g_strdup_printf(" - [%u]", self->title_count);
+        vdata = g_strconcat(data, ndata, NULL);
+        g_free(ndata);
+        g_free(data);
+        data = vdata;
+    }
 
     PROP_SETS(self->window, net_wm_visible_name, data);
 
@@ -1189,12 +1232,9 @@ void client_update_title(Client *self)
 
     if (self->frame)
        frame_adjust_title(self->frame);
-}
-
-void client_update_icon_title(Client *self)
-{
-    char *data = NULL;
 
+    /* update the icon title */
+    data = NULL;
     g_free(self->icon_title);
      
     /* try netwm */
@@ -1203,6 +1243,16 @@ void client_update_icon_title(Client *self)
        if (!PROP_GETS(self->window, wm_icon_name, locale, &data))
             data = g_strdup("Unnamed Window");
 
+    /* append the title count, dont display the number for the first window */
+    if (self->title_count > 1) {
+        char *vdata, *ndata;
+        ndata = g_strdup_printf(" - [%u]", self->title_count);
+        vdata = g_strconcat(data, ndata, NULL);
+        g_free(ndata);
+        g_free(data);
+        data = vdata;
+    }
+
     PROP_SETS(self->window, net_wm_visible_icon_name, data);
 
     self->icon_title = data;
@@ -1359,40 +1409,85 @@ static void client_change_state(Client *self)
        frame_adjust_state(self->frame);
 }
 
-static Client *search_focus_tree(Client *node, Client *skip)
+Client *client_search_focus_tree(Client *self)
 {
     GSList *it;
     Client *ret;
 
-    for (it = node->transients; it != NULL; it = it->next) {
-       Client *c = it->data;
-       if (c == skip) continue; /* circular? */
-       if ((ret = search_focus_tree(c, skip))) return ret;
-       if (client_focused(c)) return c;
+    for (it = self->transients; it != NULL; it = it->next) {
+       if (client_focused(it->data)) return it->data;
+       if ((ret = client_search_focus_tree(it->data))) return ret;
     }
     return NULL;
 }
 
-static void calc_recursive(Client *self, StackLayer l, gboolean raised)
+Client *client_search_focus_tree_full(Client *self)
+{
+    if (self->transient_for) {
+        if (self->transient_for != TRAN_GROUP) {
+            return client_search_focus_tree_full(self->transient_for);
+        } else {
+            GSList *it;
+        
+            for (it = self->group->members; it; it = it->next)
+                if (((Client*)it->data)->transient_for != TRAN_GROUP) {
+                    Client *c;
+                    if ((c = client_search_focus_tree_full(it->data)))
+                        return c;
+                }
+            return NULL;
+        }
+    } else {
+        /* this function checks the whole tree, the client_search_focus_tree
+           does not, so we need to check this window */
+        if (client_focused(self))
+            return self;
+        return client_search_focus_tree(self);
+    }
+}
+
+static StackLayer calc_layer(Client *self)
+{
+    StackLayer l;
+
+    if (self->iconic) l = Layer_Icon;
+    else if (self->fullscreen) l = Layer_Fullscreen;
+    else if (self->type == Type_Desktop) l = Layer_Desktop;
+    else if (self->type == Type_Dock) {
+        if (!self->below) l = Layer_Top;
+        else l = Layer_Normal;
+    }
+    else if (self->above) l = Layer_Above;
+    else if (self->below) l = Layer_Below;
+    else l = Layer_Normal;
+
+    return l;
+}
+
+static void calc_recursive(Client *self, Client *orig, StackLayer l,
+                           gboolean raised)
 {
-    StackLayer old;
+    StackLayer old, own;
     GSList *it;
 
     old = self->layer;
-    self->layer = l;
+    own = calc_layer(self);
+    self->layer = l > own ? l : own;
 
     for (it = self->transients; it; it = it->next)
-        calc_recursive(it->data, l, raised ? raised : l != old);
+        calc_recursive(it->data, orig, l, raised ? raised : l != old);
 
     if (!raised && l != old)
-       if (self->frame)
+       if (orig->frame) /* only restack if the original window is managed */
            stacking_raise(self);
 }
 
 void client_calc_layer(Client *self)
 {
     StackLayer l;
-    gboolean f;
+    Client *orig;
+
+    orig = self;
 
     /* transients take on the layer of their parents */
     if (self->transient_for) {
@@ -1410,27 +1505,9 @@ void client_calc_layer(Client *self)
         }
     }
 
-    /* is us or one of our transients focused? */
-    if (client_focused(self))
-        f = TRUE;
-    else if (search_focus_tree(self, self))
-        f = TRUE;
-    else
-        f = FALSE;
+    l = calc_layer(self);
 
-    if (self->iconic) l = Layer_Icon;
-    /* fullscreen windows are only in the fullscreen layer while focused */
-    else if (self->fullscreen && f) l = Layer_Fullscreen;
-    else if (self->type == Type_Desktop) l = Layer_Desktop;
-    else if (self->type == Type_Dock) {
-        if (!self->below) l = Layer_Top;
-        else l = Layer_Normal;
-    }
-    else if (self->above) l = Layer_Above;
-    else if (self->below) l = Layer_Below;
-    else l = Layer_Normal;
-
-    calc_recursive(self, l, FALSE);
+    calc_recursive(self, orig, l, FALSE);
 }
 
 gboolean client_should_show(Client *self)
@@ -1711,31 +1788,30 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
 {
     GSList *it;
 
-    /* move up the transient chain as far as possible first if deiconifying */
-    if (!iconic)
-        while (self->transient_for) {
-            if (self->transient_for != TRAN_GROUP) {
-                if (self->transient_for->iconic == iconic)
-                    break;
-                self = self->transient_for;
-            } else {
-                GSList *it;
-
-                /* the check for TRAN_GROUP is to prevent an infinate loop with
-                   2 transients of the same group at the head of the group's
-                   members list */
-                for (it = self->group->members; it; it = it->next) {
-                    Client *c = it->data;
+    /* move up the transient chain as far as possible first */
+    if (self->transient_for) {
+        if (self->transient_for != TRAN_GROUP) {
+            if (self->transient_for->iconic != iconic) {
+                client_iconify(self->transient_for, iconic, curdesk);
+                return;
+            }
+        } else {
+            GSList *it;
 
-                    if (c != self && c->transient_for->iconic != iconic &&
-                        c->transient_for != TRAN_GROUP) {
-                        self = it->data;
-                        break;
-                    }
+            /* the check for TRAN_GROUP is to prevent an infinate loop with
+               2 transients of the same group at the head of the group's
+               members list */
+            for (it = self->group->members; it; it = it->next) {
+                Client *c = it->data;
+                if (c != self && c->iconic != iconic &&
+                    c->transient_for != TRAN_GROUP) {
+                    client_iconify(it->data, iconic, curdesk);
+                    break;
                 }
-                if (it == NULL) break;
             }
+            if (it != NULL) return;
         }
+    }
 
     if (self->iconic == iconic) return; /* nothing to do */
 
@@ -1750,11 +1826,19 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
        /* we unmap the client itself so that we can get MapRequest events,
           and because the ICCCM tells us to! */
        XUnmapWindow(ob_display, self->window);
+
+        /* update the focus lists.. iconic windows go to the bottom of the
+         list, put the new iconic window at the 'top of the bottom'. */
+        focus_order_to_top(self);
     } else {
        if (curdesk)
            client_set_desktop(self, screen_desktop, FALSE);
        self->wmstate = self->shaded ? IconicState : NormalState;
        XMapWindow(ob_display, self->window);
+
+        /* this puts it after the current focused window */
+        focus_order_remove(self);
+        focus_order_add_new(self);
     }
     client_change_state(self);
     client_showhide(self);
@@ -1918,7 +2002,7 @@ void client_kill(Client *self)
 
 void client_set_desktop(Client *self, guint target, gboolean donthide)
 {
-    guint old, i;
+    guint old;
 
     if (target == self->desktop) return;
   
@@ -1926,6 +2010,9 @@ void client_set_desktop(Client *self, guint target, gboolean donthide)
 
     g_assert(target < screen_num_desktops || target == DESKTOP_ALL);
 
+    /* remove from the old desktop(s) */
+    focus_order_remove(self);
+
     old = self->desktop;
     self->desktop = target;
     PROP_SET32(self->window, net_wm_desktop, cardinal, target);
@@ -1939,48 +2026,28 @@ void client_set_desktop(Client *self, guint target, gboolean donthide)
         stacking_raise(self);
     screen_update_struts();
 
-    /* update the focus lists */
-    if (old == DESKTOP_ALL) {
-        for (i = 0; i < screen_num_desktops; ++i)
-            focus_order[i] = g_list_remove(focus_order[i], self);
-    } else
-        focus_order[old] = g_list_remove(focus_order[old], self);
-    if (target == DESKTOP_ALL) {
-        for (i = 0; i < screen_num_desktops; ++i) {
-            if (config_focus_new)
-                focus_order[i] = g_list_prepend(focus_order[i], self);
-            else
-                focus_order[i] = g_list_append(focus_order[i], self);
-        }
-    } else {
-        if (config_focus_new)
-            focus_order[target] = g_list_prepend(focus_order[target], self);
-        else
-            focus_order[target] = g_list_append(focus_order[target], self);
-    }
+    /* add to the new desktop(s) */
+    if (config_focus_new)
+        focus_order_to_top(self);
+    else
+        focus_order_to_bottom(self);
 
     dispatch_client(Event_Client_Desktop, self, target, old);
 }
 
-static Client *search_modal_tree(Client *node, Client *skip)
+Client *client_search_modal_child(Client *self)
 {
     GSList *it;
     Client *ret;
   
-    for (it = node->transients; it != NULL; it = it->next) {
+    for (it = self->transients; it != NULL; it = it->next) {
        Client *c = it->data;
-       if (c == skip) continue; /* circular? */
-       if ((ret = search_modal_tree(c, skip))) return ret;
+       if ((ret = client_search_modal_child(c))) return ret;
        if (c->modal) return c;
     }
     return NULL;
 }
 
-Client *client_find_modal_child(Client *self)
-{
-    return search_modal_tree(self, self);
-}
-
 gboolean client_validate(Client *self)
 {
     XEvent e; 
@@ -2139,43 +2206,28 @@ Client *client_focus_target(Client *self)
     Client *child;
      
     /* if we have a modal child, then focus it, not us */
-    child = client_find_modal_child(self);
+    child = client_search_modal_child(self);
     if (child) return child;
     return self;
 }
 
-gboolean client_focusable(Client *self)
-{
-    /* won't try focus if the client doesn't want it, or if the window isn't
-       visible on the screen */
-    return self->frame->visible &&
-        (self->can_focus || self->focus_notify);
-}
-
 gboolean client_focus(Client *self)
 {
     XEvent ev;
-    guint i;
 
     /* choose the correct target */
     self = client_focus_target(self);
 
     if (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop) {
         /* update the focus lists */
-        if (self->desktop == DESKTOP_ALL) {
-            for (i = 0; i < screen_num_desktops; ++i) {
-                focus_order[i] = g_list_remove(focus_order[i], self);
-                focus_order[i] = g_list_prepend(focus_order[i], self);
-            }
-        } else {
-            i = self->desktop;
-            focus_order[i] = g_list_remove(focus_order[i], self);
-            focus_order[i] = g_list_prepend(focus_order[i], self);
-        }
+        focus_order_to_top(self);
         return FALSE;
     }
 
-    if (!client_focusable(self))
+    if (!((self->can_focus || self->focus_notify) &&
+          (self->desktop == screen_desktop ||
+           self->desktop == DESKTOP_ALL) &&
+          !self->iconic))
        return FALSE;
 
     /* do a check to see if the window has already been unmapped or destroyed
This page took 0.035672 seconds and 4 git commands to generate.