]> Dogcows Code - chaz/openbox/commitdiff
Rewrite the stacking code. It's a lot faster now, I should think. It's def a more...
authorDana Jansens <danakj@orodu.net>
Mon, 12 Mar 2007 02:24:40 +0000 (02:24 +0000)
committerDana Jansens <danakj@orodu.net>
Mon, 12 Mar 2007 02:24:40 +0000 (02:24 +0000)
On that note, utility and menu and toolbar window types are now treated as group transients in terms of stacking and focus and such.

openbox/client.c
openbox/client.h
openbox/stacking.c

index c59baf96905d7d04036ed6b632b7b98b91ba0b7f..37c7f40b83e3c15e6aefc4673d9fb1ffd63f427e 100644 (file)
@@ -1117,9 +1117,15 @@ void client_update_transient_for(ObClient *self)
                 }
             }
         }
-    } else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
-        self->transient = TRUE;
-        target = OB_TRAN_GROUP;
+    } else if (self->group) {
+        if (self->type == OB_CLIENT_TYPE_DIALOG ||
+            self->type == OB_CLIENT_TYPE_TOOLBAR ||
+            self->type == OB_CLIENT_TYPE_MENU ||
+            self->type == OB_CLIENT_TYPE_UTILITY)
+        {
+            self->transient = TRUE;
+            target = OB_TRAN_GROUP;
+        }
     } else
         self->transient = FALSE;
 
@@ -2024,7 +2030,7 @@ void client_calc_layer(ObClient *self)
     orig = self;
 
     /* transients take on the layer of their parents */
-    it = client_search_top_transients(self);
+    it = client_search_all_top_parents(self);
 
     for (; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig, 0, FALSE);
@@ -2449,21 +2455,18 @@ static void client_iconify_recursive(ObClient *self,
             screen_update_areas();
     }
 
-    /* iconify all transients */
+    /* iconify all direct transients */
     for (it = self->transients; it; it = g_slist_next(it))
-        if (it->data != self) client_iconify_recursive(it->data,
-                                                       iconic, curdesk);
+        if (it->data != self)
+            if (client_is_direct_child(self, it->data))
+                client_iconify_recursive(it->data, iconic, curdesk);
 }
 
 void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
 {
-    GSList *it;
-
     /* move up the transient chain as far as possible first */
-    it = client_search_top_transients(self);
-
-    for (; it; it = g_slist_next(it))
-    client_iconify_recursive(it->data, iconic, curdesk);
+    self = client_search_top_parent(self);
+    client_iconify_recursive(self, iconic, curdesk);
 }
 
 void client_maximize(ObClient *self, gboolean max, gint dir, gboolean savearea)
@@ -2657,18 +2660,23 @@ void client_set_desktop_recursive(ObClient *self,
 
     /* move all transients */
     for (it = self->transients; it; it = g_slist_next(it))
-        if (it->data != self) client_set_desktop_recursive(it->data,
-                                                           target, donthide);
+        if (it->data != self)
+            if (client_is_direct_child(self, it->data))
+                client_set_desktop_recursive(it->data, target, donthide);
 }
 
 void client_set_desktop(ObClient *self, guint target, gboolean donthide)
 {
-    GSList *it;
-
-    it = client_search_top_transients(self);
+    self = client_search_top_parent(self);
+    client_set_desktop_recursive(self, target, donthide);
+}
 
-    for(; it; it = g_slist_next(it))
-        client_set_desktop_recursive(it->data, target, donthide);
+gboolean client_is_direct_child(ObClient *parent, ObClient *child)
+{
+    while (child != parent &&
+           child->transient_for && child->transient_for != OB_TRAN_GROUP)
+        child = child->transient_for;
+    return child == parent;
 }
 
 ObClient *client_search_modal_child(ObClient *self)
@@ -3236,7 +3244,14 @@ guint client_monitor(ObClient *self)
     return screen_find_monitor(&self->frame->area);
 }
 
-GSList *client_search_top_transients(ObClient *self)
+ObClient *client_search_top_parent(ObClient *self)
+{
+    while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
+        self = self->transient_for;
+    return self;
+}
+
+GSList *client_search_all_top_parents(ObClient *self)
 {
     GSList *ret = NULL;
 
index b418964dcedc9c98e1844dcc2f96cfc910b35547..ff460153092eb3067d4d9854afb43b22feebf6a9 100644 (file)
@@ -575,7 +575,15 @@ ObClient *client_search_modal_child(ObClient *self);
   It will only contain more than 1 element if the client is transient for its
   group.
 */
-GSList *client_search_top_transients(ObClient *self);
+GSList *client_search_all_top_parents(ObClient *self);
+
+/*! Returns a window's top level parent. This only counts direct parents,
+  not groups if it is transient for its group.
+*/
+ObClient *client_search_top_parent(ObClient *self);
+
+/*! Is one client a direct child of another (i.e. not through the group.) */
+gboolean client_is_direct_child(ObClient *parent, ObClient *child);
 
 /*! Search for a parent of a client. This only searches up *ONE LEVEL*, and
   returns the searched for parent if it is a parent, or NULL if not. */
index 34064db7d3a9b5df8df5e78fd6d2572726fd88a6..db1606b58417726022d4231c5cfe1f2222d3e767 100644 (file)
@@ -158,180 +158,182 @@ static void do_lower(GList *wins)
     }
 }
 
-static GList *pick_windows_recur(ObClient *top, ObClient *selected,
-                                 gboolean raise)
+static void restack_windows(ObClient *selected, gboolean raise, gboolean group)
 {
-    GList *ret = NULL;
-    GList *it, *next, *prev;
-    GSList *sit;
-    gint i, n;
+    GList *it, *last, *below, *above, *next;
+    GList *wins = NULL;
+
+    GList *group_modals = NULL;
+    GList *group_trans = NULL;
     GList *modals = NULL;
     GList *trans = NULL;
-    GList *modal_sel = NULL; /* the selected guys if modal */
-    GList *trans_sel = NULL; /* the selected guys if not */
-
-    /* remove first so we can't run into ourself */
-    if ((it = g_list_find(stacking_list, top)))
-        stacking_list = g_list_delete_link(stacking_list, it);
-    else
-        return NULL;
 
-    i = 0;
-    n = g_slist_length(top->transients);
-    for (it = stacking_list; i < n && it; it = next) {
-        prev = g_list_previous(it);
-        next = g_list_next(it);
-
-        if ((sit = g_slist_find(top->transients, it->data))) {
-            ObClient *c = sit->data;
-            gboolean sel_child;
-
-            ++i;
+    if (!raise && selected->transient_for) {
+        GSList *top, *top_it;
+        GSList *top_reorder = NULL;
+        
+        /* if it's a transient lowering, lower its parents so that we can lower
+           this window, or it won't move */
+        top = client_search_all_top_parents(selected);
+
+        /* go thru stacking list backwards so we can use g_slist_prepend */
+        for (it = g_list_last(stacking_list); it && top;
+             it = g_list_previous(it))
+            if ((top_it = g_slist_find(top, it->data))) {
+                top_reorder = g_slist_prepend(top_reorder, top_it->data);
+                top = g_slist_delete_link(top, top_it);
+            }
+        g_assert(top == NULL);
 
-            if (c == selected)
-                sel_child = TRUE;
-            else
-                sel_child = client_search_transient(c, selected) != NULL;
+        /* call restack for each of these to lower them */
+        for (top_it = top_reorder; top_it; top_it = g_slist_next(top_it))
+            restack_windows(top_it->data, raise, group);
+        return;
+    }
 
-            if (!c->modal) {
-                if (!sel_child) {
-                    trans = g_list_concat
-                        (trans, pick_windows_recur(c, selected, raise));
-                } else {
-                    trans_sel = g_list_concat
-                        (trans_sel, pick_windows_recur(c, selected, raise));
+    /* remove first so we can't run into ourself */
+    it = g_list_find(stacking_list, selected);
+    g_assert(it);
+    stacking_list = g_list_delete_link(stacking_list, it);
+
+    /* go from the bottom of the stacking list up */
+    for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *ch = it->data;
+
+            /* only move windows in the same stacking layer */
+            if (ch->layer == selected->layer &&
+                client_search_transient(selected, ch))
+            {
+                if (client_is_direct_child(selected, ch)) {
+                    if (ch->modal)
+                        modals = g_list_prepend(modals, ch);
+                    else
+                        trans = g_list_prepend(trans, ch);
                 }
-            } else {
-                if (!sel_child) {
-                    modals = g_list_concat
-                        (modals, pick_windows_recur(c, selected, raise));
-                } else {
-                    modal_sel = g_list_concat
-                        (modal_sel, pick_windows_recur(c, selected, raise));
+                else {
+                    if (ch->modal)
+                        group_modals = g_list_prepend(group_modals, ch);
+                    else
+                        group_trans = g_list_prepend(group_trans, ch);
                 }
+                stacking_list = g_list_delete_link(stacking_list, it);
             }
-            /* if we dont have a prev then start back at the beginning,
-               otherwise skip back to the prev's next */
-            next = prev ? g_list_next(prev) : stacking_list;
         }
     }
 
-    ret = g_list_concat((raise ? modal_sel : modals),
-                        (raise ? modals : modal_sel));
-
-    ret = g_list_concat(ret, (raise ? trans_sel : trans));
-    ret = g_list_concat(ret, (raise ? trans : trans_sel));
+    /* put transients of the selected window right above it */
+    wins = g_list_concat(modals, trans);
+    wins = g_list_append(wins, selected);
 
+    /* if selected window is transient for group then raise it above others */
+    if (selected->transient_for == OB_TRAN_GROUP) {
+        /* if it's modal, raise it above those also */
+        if (selected->modal) {
+            wins = g_list_concat(wins, group_modals);
+            group_modals = NULL;
+        }
+        wins = g_list_concat(wins, group_trans);
+        group_trans = NULL;
+    }
 
-    /* add itself */
-    ret = g_list_append(ret, top);
-
-    return ret;
-}
+    /* find where to put the selected window, start from bottom of list,
+       this is the window below everything we are re-adding to the list */
+    last = NULL;
+    for (it = g_list_last(stacking_list); it; it = g_list_previous(it))
+    {
+        if (window_layer(it->data) < selected->layer)
+            continue;
+        /* if lowering, stop at the beginning of the layer */
+        if (!raise)
+            break;
+        /* if raising, stop at the end of the layer */
+        if (window_layer(it->data) > selected->layer)
+            break;
+
+        last = it;
+    }
 
-static GList *pick_group_windows_recur(ObClient *top, ObClient *selected,
-                                       gboolean raise, gboolean normal)
-{
-    GList *ret = NULL;
-    GList *it, *next, *prev;
-    GSList *sit;
-    gint i, n;
-
-    /* add group members in their stacking order */
-    if (top->group) {
-        i = 0;
-        n = g_slist_length(top->group->members) - 1;
-        for (it = stacking_list; i < n && it; it = next) {
-            prev = g_list_previous(it);
-            next = g_list_next(it);
-
-            if ((sit = g_slist_find(top->group->members, it->data))) {
-                ObClient *c;
-                ObClientType t;
-
-                ++i;
-                c = it->data;
-                t = c->type;
-
-                if ((c->desktop == selected->desktop ||
-                     c->desktop == DESKTOP_ALL) &&
-                    (t == OB_CLIENT_TYPE_TOOLBAR ||
-                     t == OB_CLIENT_TYPE_MENU ||
-                     t == OB_CLIENT_TYPE_UTILITY ||
-                     (normal && t == OB_CLIENT_TYPE_NORMAL)))
-                {
-                    ret = g_list_concat(ret,
-                                        pick_windows_recur(sit->data,
-                                                           selected, raise)); 
-                    /* if we dont have a prev then start back at the beginning,
-                       otherwise skip back to the prev's next */
-                    next = prev ? g_list_next(prev) : stacking_list;
-                }
-            }
+    /* save this position in the stacking list */
+    below = last;
+
+    /* find where to put the group transients, start from the top of list */
+    for (it = stacking_list; it; it = g_list_next(it)) {
+        /* skip past higher layers */
+        if (window_layer(it->data) > selected->layer)
+            continue;
+        /* if we reach the end of the layer (how?) then don't go further */
+        if (window_layer(it->data) < selected->layer)
+            break;
+        /* stop when we reach the first window in the group */
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *c = it->data;
+            if (c->group == selected->group)
+                break;
         }
+        /* if we don't hit any other group members, stop here because this
+           is where we are putting the selected window (and its children) */
+        if (it == below)
+            break;
     }
-    return ret;
-}
 
-static GList *pick_windows(ObClient *selected, gboolean raise, gboolean group)
-{
-    GList *it;
-    GSList *top, *top_it;
-    GSList *top_reorder = NULL;
-    GList *ret = NULL;
-
-    top = client_search_top_transients(selected);
-
-    /* go thru stacking list backwords so we can use g_slist_prepend */
-    for (it = g_list_last(stacking_list); it && top;
-         it = g_list_previous(it))
-        if ((top_it = g_slist_find(top, it->data))) {
-            top_reorder = g_slist_prepend(top_reorder, top_it->data);
-            top = g_slist_delete_link(top, top_it);
-        }
-    g_assert(top == NULL);
+    /* save this position, this is the top of the group of windows between the
+       group transient ones we're restacking and the others up above that we're
+       restacking
 
-    for (top_it = top_reorder; top_it; top_it = g_slist_next(top_it))
-        ret = g_list_concat(ret,
-                            pick_windows_recur(top_it->data, selected, raise));
+       we actually want to save 1 position _above_ that, for for loops to work
+       nicely, so move back one position in the list while saving it
+    */
+    above = it ? g_list_previous(it) : g_list_last(stacking_list);
+
+    /* put the windows inside the gap to the other windows we're stacking
+       into the restacking list, go from the bottom up so that we can use
+       g_list_prepend */
+    if (below) it = g_list_previous(below);
+    else       it = g_list_last(stacking_list);
+    for (; it != above; it = next) {
+        next = g_list_previous(it);
+        wins = g_list_prepend(wins, it->data);
+        stacking_list = g_list_delete_link(stacking_list, it);
+    }
+
+    /* group transients go above the rest of the stuff acquired to now */
+    wins = g_list_concat(group_trans, wins);
+    /* group modals go on the very top */
+    wins = g_list_concat(group_modals, wins);
 
-    for (top_it = top_reorder; top_it; top_it = g_slist_next(top_it))
-        ret = g_list_concat(ret,
-                            pick_group_windows_recur(top_it->data,
-                                                     selected, raise, group));
-    return ret;
+    do_restack(wins, below);
+    g_list_free(wins);
 }
 
 void stacking_raise(ObWindow *window, gboolean group)
 {
-    GList *wins;
-
     if (WINDOW_IS_CLIENT(window)) {
         ObClient *selected;
         selected = WINDOW_AS_CLIENT(window);
-        wins = pick_windows(selected, TRUE, group);
+        restack_windows(selected, TRUE, group);
     } else {
+        GList *wins;
         wins = g_list_append(NULL, window);
         stacking_list = g_list_remove(stacking_list, window);
+        do_raise(wins);
+        g_list_free(wins);
     }
-    do_raise(wins);
-    g_list_free(wins);
 }
 
 void stacking_lower(ObWindow *window, gboolean group)
 {
-    GList *wins;
-
     if (WINDOW_IS_CLIENT(window)) {
         ObClient *selected;
         selected = WINDOW_AS_CLIENT(window);
-        wins = pick_windows(selected, FALSE, group);
+        restack_windows(selected, FALSE, group);
     } else {
+        GList *wins;
         wins = g_list_append(NULL, window);
         stacking_list = g_list_remove(stacking_list, window);
+        do_lower(wins);
+        g_list_free(wins);
     }
-    do_lower(wins);
-    g_list_free(wins);
 }
 
 void stacking_below(ObWindow *window, ObWindow *below)
This page took 0.044699 seconds and 4 git commands to generate.