more wip
authorDana Jansens <danakj@orodu.net>
Mon, 21 Dec 2009 23:34:47 +0000 (18:34 -0500)
committerDana Jansens <danakj@orodu.net>
Tue, 22 Dec 2009 16:44:52 +0000 (11:44 -0500)
openbox/stacking.c
openbox/stacking.h

index 5a4675eb04c5fb8f0c0914d907e76d3bf2ccd622..a93ad6adb4c2ea508449742599bf6dc7052d8e30 100644 (file)
@@ -220,10 +220,72 @@ static void do_lower(GList *wins)
     }
 }
 
-static GList* get_restack_order(ObClient *selected, gboolean raise)
+/*! Returns a position in the stacking_list, which is the first window
+  from the top down that is in a layer <= the query layer, or NULL if there
+  are no such windows.
+*/
+GList* find_top_of_layer(ObStackingLayer layer)
+{
+    GList *top;
+
+    *top = NULL;
+    /* start from the bottom of the list and go up */
+    for (it = g_list_last(stacking_list); it; it = g_list_previous(it))
+    {
+        if (window_layer(it->data) > layer)
+            break;
+        *top = it;
+    }
+    return top;
+}
+
+static void find_parents_r(ObClient *client, GHashTable *t)
+{
+    GSList *sit;
+    for (sit = client->parents; sit; sit = g_slist_next(sit)) {
+        g_hash_table_insert(t, sit->data, sit->data);
+        find_parents_r(sit->data, t);
+    }
+}
+
+static GList* get_parents(ObClient *client)
+{
+    GHashTable *parents;
+    GList *it, *next, *ret;
+
+    if (!client->parents) return NULL;
+
+    /* collect all the parents */
+
+    parents = g_hash_table_new(g_direct_hash, g_direct_equal);
+    find_parents_r(client, parents);
+
+    /* go through the stacking list and find all the parents, and put them
+       into a list in order */
+    ret = NULL;
+    for (it = g_list_last(stacking_list); it; it = next) {
+        next = g_list_previous(it);
+        if (g_hash_table_lookup(parents, it->data)) {
+            ret = g_list_prepend(ret, it->data);
+            stacking_list = g_list_delete_link(stacking_list, it);
+        }
+    }
+
+    g_hash_table_destroy(parents);
+    return ret;
+}
+
+/*! reorders the windows from the stacking_list, removing them and placing
+  them into some lists.
+  @direct A list of windows directly related to the @selected window, and
+          will contain @selected, ordered from top to bottom.
+  @group_trans A list of windows indirectly related to the @selected window,
+          which should be placed above @direct, ordered from top to bottom.
+*/
+static GList* get_restack_order(ObClient *selected, gboolean raise,
+                                GList **direct, GList **grouped)
 {
     GList *it, *last, *below, *above, *next;
-    GList *wins = NULL;
     ObClient *bottom = NULL;
 
     GList *group_helpers = NULL;
@@ -287,152 +349,112 @@ static GList* get_restack_order(ObClient *selected, gboolean raise)
     }
 
     /* put modals above other direct transients */
-    wins = g_list_concat(modals, trans);
+    *direct = g_list_concat(modals, trans);
 
     /* put helpers below direct transients */
-    wins = g_list_concat(wins, group_helpers);
+    *direct = g_list_concat(*direct, group_helpers);
 
     /* put the selected window right below these children */
-    wins = g_list_append(wins, selected);
+    *direct = g_list_append(*direct, selected);
 
     /* if selected window is transient for group then raise it above others */
     if (selected->transient_for_group) {
         /* if it's modal, raise it above those also */
         if (selected->modal) {
-            wins = g_list_concat(wins, group_modals);
+            *direct = g_list_concat(*direct, group_modals);
             group_modals = NULL;
         }
-        wins = g_list_concat(wins, group_trans);
+        *direct = g_list_concat(*direct, group_trans);
         group_trans = NULL;
     }
 
-    /* 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) {
-            last = it;
-            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;
-    }
-
-    /* save this position in the stacking list */
-    below = last;
+    /* if not raising, the selected window can't go below its parents, so
+       put them all in the direct list below it */
+    if (!raise)
+        *direct = g_list_concat(*direct, get_parents(selected));
 
-    /* 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;
-    }
+    /* modal group transients go above other group transients */
+    *grouped = g_list_concat(group_modals, group_trans);
+}
 
-    /* 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
+static GList* get_app_windows(ObClient *selected)
+{
+    GList *it, *next, *app;
 
-       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) {
+    app = NULL;
+    for (it = g_list_last(stacking_list); it; 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);
 
-    return wins;
+        if (WINDOW_IS_CLIENT(it->data) &&
+            client_is_in_application(WINDOW_AS_CLIENT(it->data)))
+        {
+            stacking_list = g_list_remove_link(stacking_list, it);
+            app = g_list_concat(it, app);
+        }
+    }
+    return app;
 }
 
 static void restack_windows(ObClient *selected, gboolean raise, gboolean app)
 {
-    GList *wins;
+    GList *wins, *direct, *app_trans, *parents;
     GList *app_members = NULL;
 
+    GList *it, *next, *direct_below, *group_trans_below, *between;
+
     /* get the restacking order for the selected window and its relatives */
-    wins = get_restack_order(selected, raise);
-
-    /* if we're lowering the window, then the parents will not be included
-       in the above list.  find all the parents and put them below the windows
-       we have so far */
-    if (!raise && selected->parents) {
-        GSList *parents_copy, *sit;
-        GSList *reorder = NULL;
-
-        parents_copy = g_slist_copy(selected->parents);
-
-        /* go thru stacking list backwards so we can use g_slist_prepend */
-        for (it = g_list_last(stacking_list); it && parents_copy;
-             it = g_list_previous(it))
-            if ((sit = g_slist_find(parents_copy, it->data))) {
-                reorder = g_slist_prepend(reorder, sit->data);
-                parents_copy = g_slist_delete_link(parents_copy, sit);
-            }
-        g_assert(parents_copy == NULL);
+    get_restack_order(selected, raise, &direct, &app_trans);
 
-        for (sit = reorder; sit; sit = g_slist_next(sit))
-            wins = g_list_concat(wins, get_restack_order(sit->data, FALSE);
-    }
+    /* stick the selected window and all its direct-relations above this
+       spot */
+    direct_below = find_top_of_layer(raise ?
+                                     selected->layer : selected->layer - 1);
 
+    /* WHERE DO THE APP WINDOWS GO EXACTLY???  AND THE GROUP TRANSIENTS?
 
-    /* collect all other windows in the application in all stacking layers,
-       while preserving their relative stacking order */
-    if (app) {
+    THE BETWEEN WINDOWS ARE BETWEEN WHICH GROUPS OF WINDOWS ? */
 
-        /* go thru stacking list backwards so we can use g_list_prepend */
-        for (it = g_list_last(stacking_list); it; it = next) {
-            next = g_list_previous(it);
+    if (app) {
+        app_members = get_app_windows(selected);
+        app_below = direct_below;
+    }
+    else {
+        app_members = NULL;
+        app_below = direct_below;
+
+        if (selected->group) {
+            /* find the highest member of @selected's group */
+            it = app_below;
+            for (it = g_list_previous(it); it; it = g_list_previous(it))
+                if (window_layer(it->data) > selected->layer)
+                    break;
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *c = WINDOW_AS_CLIENT(it->data);
-                /* find windows in the same application */
-                if ((c->desktop == selected->desktop ||
-                    c->desktop == DESKTOP_ALL ||
-                    (selected->desktop == DESKTOP_ALL &&
-                     c->desktop == screen_destkop))
-                    client_is_in_application(c, selected) &&
-                    window_layer(w) == selected->layer)
-                {
-                    app_members = g_list_prepend(app_members, w);
-                    stacking_list = g_list_delete_link(stacking_list, it);
-                }
+                if (c->group == selected->group)
+                    app_below = it;
             }
         }
     }
 
-    do_restack(wins, below);
+    /* stick the application transients directly above the other left-over
+       application windows */
+    app_members = g_list_concat(app_trans, app_members);
 
+    /* grab all the stuff between app_below and direct_below */
+    between = NULL;
+    for (it = direct_below; it && it != app_below; it = next) {
+        next = g_list_previous(it);
+        stacking_list = g_list_remove_link(stacking_list, it);
+        between = g_list_concat(it, between);
+    }
+
+    /* stick them all together and restack */
+    if (raise)
+        /* app_members, between, direct, below */
+        do_restack(g_list_concat(app_members, g_list_concat(between, direct)),
+                   below);
+    else
+        do_restack(g_list_concat(
 }
 
 void stacking_raise_app(ObClient *client)
index 10482744f315a3c1eaba751e55dd371213f69bb9..b67d528ddccfb1ea757f0fa50fed6615db3adef4 100644 (file)
@@ -29,12 +29,12 @@ struct _ObClient;
 /*! The possible stacking layers a client window can be a part of */
 typedef enum {
     OB_STACKING_LAYER_INVALID,
-    OB_STACKING_LAYER_DESKTOP,          /*!< 0 - desktop windows */
-    OB_STACKING_LAYER_BELOW,            /*!< 1 - normal windows w/ below */
-    OB_STACKING_LAYER_NORMAL,           /*!< 2 - normal windows */
-    OB_STACKING_LAYER_ABOVE,            /*!< 3 - normal windows w/ above */
-    OB_STACKING_LAYER_FULLSCREEN,       /*!< 4 - fullscreeen windows */
-    OB_STACKING_LAYER_INTERNAL,         /*!< 5 - openbox windows/menus */
+    OB_STACKING_LAYER_DESKTOP,          /*!< 1 - desktop windows */
+    OB_STACKING_LAYER_BELOW,            /*!< 2 - normal windows w/ below */
+    OB_STACKING_LAYER_NORMAL,           /*!< 3 - normal windows */
+    OB_STACKING_LAYER_ABOVE,            /*!< 4 - normal windows w/ above */
+    OB_STACKING_LAYER_FULLSCREEN,       /*!< 5 - fullscreeen windows */
+    OB_STACKING_LAYER_INTERNAL,         /*!< 6 - openbox windows/menus */
     OB_NUM_STACKING_LAYERS
 } ObStackingLayer;