wip
authorDana Jansens <danakj@orodu.net>
Thu, 17 Dec 2009 19:00:56 +0000 (14:00 -0500)
committerDana Jansens <danakj@orodu.net>
Tue, 22 Dec 2009 16:44:52 +0000 (11:44 -0500)
openbox/actions/lower.c
openbox/actions/raise.c
openbox/client.c
openbox/client.h
openbox/stacking.c
openbox/stacking.h

index 80ca6b8bcf9fc22c2d229e9f1b2cddb4c299769e..ad936aaba6b3614908efb0392b2b528f5ff59421 100644 (file)
@@ -2,21 +2,41 @@
 #include "openbox/stacking.h"
 #include "openbox/window.h"
 
+typedef struct {
+    gboolean app;
+} Options;
+
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_lower_startup(void)
 {
-    actions_register("Lower",
-                     NULL, NULL,
-                     run_func);
+    actions_register("Lower", setup_func, NULL, run_func);
+}
+
+static gpointer setup_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o;
+
+    o = g_new0(Options, 1);
+
+    if ((n = obt_parse_find_node(node, "app")))
+        o->app = obt_parse_node_bool(n);
+    return o;
 }
 
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
+    Options *o = options;
+
     if (data->client) {
         actions_client_move(data, TRUE);
-        stacking_lower(CLIENT_AS_WINDOW(data->client));
+        if (o->app)
+            stacking_lower_app(data->client);
+        else
+            stacking_lower(CLIENT_AS_WINDOW(data->client));
         actions_client_move(data, FALSE);
     }
 
index f6ac1452a43120cef1b12e41368985eb6fbe1ef3..cb789408558d4575bf3402c05789e0e1f132bf4a 100644 (file)
@@ -2,19 +2,41 @@
 #include "openbox/stacking.h"
 #include "openbox/window.h"
 
+typedef struct {
+    gboolean app;
+} Options;
+
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_raise_startup(void)
 {
-    actions_register("Raise", NULL, NULL, run_func);
+    actions_register("Raise", setup_func, NULL, run_func);
+}
+
+static gpointer setup_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o;
+
+    o = g_new0(Options, 1);
+
+    if ((n = obt_parse_find_node(node, "app")))
+        o->app = obt_parse_node_bool(n);
+    return o;
 }
 
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
+    Options *o = options;
+
     if (data->client) {
         actions_client_move(data, TRUE);
-        stacking_raise(CLIENT_AS_WINDOW(data->client));
+        if (o->app)
+            stacking_raise_app(data->client);
+        else
+            stacking_raise(CLIENT_AS_WINDOW(data->client));
         actions_client_move(data, FALSE);
     }
 
index 4d8f4e77ae014e374fc53c31ce3dadcb3bd55b46..a87851b09f0c2b4ed010f93a3c751f65da96caec 100644 (file)
@@ -3512,6 +3512,12 @@ void client_set_desktop(ObClient *self, guint target,
     client_set_desktop_recursive(self, target, donthide, dontraise);
 }
 
+gboolean client_is_in_application(ObClient *self, ObClient *search)
+{
+    /* XXX FIXME make this better */
+    return self->group == search->group;
+}
+
 gboolean client_is_direct_child(ObClient *parent, ObClient *child)
 {
     while (child != parent && (child = client_direct_parent(child)));
index a361e3670be8e821add501efc00e2e415f4dc24b..781341c275397c9ad6fb32238a86b8f3d8911cfd 100644 (file)
@@ -706,6 +706,10 @@ ObClient *client_direct_parent(ObClient *self);
 */
 ObClient *client_search_top_direct_parent(ObClient *self);
 
+/*! Are the two clients windows belonging to the same application.
+  This checks group members, their children/parents, etc. */
+gboolean client_is_in_application(ObClient *self, ObClient *search);
+
 /*! Is one client a direct child of another (i.e. not through the group.)
   This checks more than one level, so there may be another direct child in
   between */
index cb710e5e0f8940a4be76fba10058be00623b4028..5a4675eb04c5fb8f0c0914d907e76d3bf2ccd622 100644 (file)
@@ -28,6 +28,7 @@
 #include "debug.h"
 #include "obt/prop.h"
 
+/*! The list of all windows in their stacking order, from top to bottom */
 GList  *stacking_list = NULL;
 /*! When true, stacking changes will not be reflected on the screen.  This is
   to freeze the on-screen stacking order while a window is being temporarily
@@ -61,9 +62,10 @@ void stacking_set_list(void)
     g_free(windows);
 }
 
+/* steals the elements of the wins list, so don't free them */
 static void do_restack(GList *wins, GList *before)
 {
-    GList *it;
+    GList *it, *after;
     Window *win;
     gint i;
 
@@ -94,9 +96,16 @@ static void do_restack(GList *wins, GList *before)
         win[i] = window_top(it->data);
         g_assert(win[i] != None); /* better not call stacking shit before
                                      setting your top level window value */
-        stacking_list = g_list_insert_before(stacking_list, before, it->data);
     }
 
+    /* wins are inserted before @before and after @after
+       stacking_list = after..wins..before */
+    if (before == stacking_list)
+        after = NULL;
+    else
+        after = stacking_list;
+    stacking_list = g_list_concat(g_list_concat(after, wins), before);
+
 #ifdef DEBUG
     /* some debug checking of the stacking list's order */
     for (it = stacking_list; ; it = next) {
@@ -181,7 +190,6 @@ static void do_raise(GList *wins)
                     break;
             }
             do_restack(layer[i], it);
-            g_list_free(layer[i]);
         }
     }
 }
@@ -208,15 +216,15 @@ static void do_lower(GList *wins)
                     break;
             }
             do_restack(layer[i], it);
-            g_list_free(layer[i]);
         }
     }
 }
 
-static void restack_windows(ObClient *selected, gboolean raise)
+static GList* get_restack_order(ObClient *selected, gboolean raise)
 {
     GList *it, *last, *below, *above, *next;
     GList *wins = NULL;
+    ObClient *bottom = NULL;
 
     GList *group_helpers = NULL;
     GList *group_modals = NULL;
@@ -365,10 +373,20 @@ static void restack_windows(ObClient *selected, gboolean raise)
     /* group modals go on the very top */
     wins = g_list_concat(group_modals, wins);
 
-    do_restack(wins, below);
-    g_list_free(wins);
+    return wins;
+}
+
+static void restack_windows(ObClient *selected, gboolean raise, gboolean app)
+{
+    GList *wins;
+    GList *app_members = NULL;
+
+    /* get the restacking order for the selected window and its relatives */
+    wins = get_restack_order(selected, raise);
 
-    /* lower our parents after us, so they go below us */
+    /* 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;
@@ -384,10 +402,42 @@ static void restack_windows(ObClient *selected, gboolean raise)
             }
         g_assert(parents_copy == NULL);
 
-        /* call restack for each of these to lower them */
         for (sit = reorder; sit; sit = g_slist_next(sit))
-            restack_windows(sit->data, raise);
+            wins = g_list_concat(wins, get_restack_order(sit->data, FALSE);
     }
+
+
+    /* collect all other windows in the application in all stacking layers,
+       while preserving their relative stacking order */
+    if (app) {
+
+        /* 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 (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);
+                }
+            }
+        }
+    }
+
+    do_restack(wins, below);
+
+}
+
+void stacking_raise_app(ObClient *client)
+{
+    restack_windows(client, TRUE, TRUE);
 }
 
 void stacking_raise(ObWindow *window)
@@ -395,7 +445,7 @@ void stacking_raise(ObWindow *window)
     if (WINDOW_IS_CLIENT(window)) {
         ObClient *selected;
         selected = WINDOW_AS_CLIENT(window);
-        restack_windows(selected, TRUE);
+        restack_windows(selected, TRUE, FALSE);
     } else {
         GList *wins;
         wins = g_list_append(NULL, window);
@@ -405,12 +455,17 @@ void stacking_raise(ObWindow *window)
     }
 }
 
+void stacking_lower_app(struct _ObClient *client)
+{
+    restack_windows(client, FALSE, TRUE);
+}
+
 void stacking_lower(ObWindow *window)
 {
     if (WINDOW_IS_CLIENT(window)) {
         ObClient *selected;
         selected = WINDOW_AS_CLIENT(window);
-        restack_windows(selected, FALSE);
+        restack_windows(selected, FALSE, FALSE);
     } else {
         GList *wins;
         wins = g_list_append(NULL, window);
@@ -431,7 +486,6 @@ void stacking_below(ObWindow *window, ObWindow *below)
     stacking_list = g_list_remove(stacking_list, window);
     before = g_list_next(g_list_find(stacking_list, below));
     do_restack(wins, before);
-    g_list_free(wins);
 }
 
 void stacking_add(ObWindow *win)
@@ -549,7 +603,6 @@ void stacking_add_nonintrusive(ObWindow *win)
 
     wins = g_list_append(NULL, win);
     do_restack(wins, it_below);
-    g_list_free(wins);
 }
 
 /*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
index 773f65887677881766be2b51f5d50d2cc8bdc829..10482744f315a3c1eaba751e55dd371213f69bb9 100644 (file)
@@ -52,6 +52,11 @@ void stacking_add_nonintrusive(struct _ObWindow *win);
 /*! Raises a window above all others in its stacking layer */
 void stacking_raise(struct _ObWindow *window);
 
+/*! Raises a window above all others in its stacking layer, and raises all
+  other windows belonging to the same application with it (to the best of
+  our abilities) */
+void stacking_raise_app(struct _ObClient *client);
+
 /*! Temporarily raises a window above all others */
 void stacking_temp_raise(struct _ObWindow *window);
 
@@ -61,6 +66,11 @@ void stacking_restore(void);
 /*! Lowers a window below all others in its stacking layer */
 void stacking_lower(struct _ObWindow *window);
 
+/*! Lowers a window below all others in its stacking layer, and lowers all
+  other windows belonging tot he same application with it (to the best of
+  our abilities) */
+void stacking_lower_app(struct _ObClient *client);
+
 /*! Moves a window below another if its in the same layer.
   This function does not enforce stacking rules IRT transients n such, and so
   it should really ONLY be used to restore stacking orders from saved sessions