From 1922648283e86a7df2deaaffea49c61130947047 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 17 Dec 2009 14:00:56 -0500 Subject: [PATCH] wip --- openbox/actions/lower.c | 28 ++++++++++++-- openbox/actions/raise.c | 26 ++++++++++++- openbox/client.c | 6 +++ openbox/client.h | 4 ++ openbox/stacking.c | 81 ++++++++++++++++++++++++++++++++++------- openbox/stacking.h | 10 +++++ 6 files changed, 135 insertions(+), 20 deletions(-) diff --git a/openbox/actions/lower.c b/openbox/actions/lower.c index 80ca6b8b..ad936aab 100644 --- a/openbox/actions/lower.c +++ b/openbox/actions/lower.c @@ -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); } diff --git a/openbox/actions/raise.c b/openbox/actions/raise.c index f6ac1452..cb789408 100644 --- a/openbox/actions/raise.c +++ b/openbox/actions/raise.c @@ -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); } diff --git a/openbox/client.c b/openbox/client.c index 4d8f4e77..a87851b0 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -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))); diff --git a/openbox/client.h b/openbox/client.h index a361e367..781341c2 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -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 */ diff --git a/openbox/stacking.c b/openbox/stacking.c index cb710e5e..5a4675eb 100644 --- a/openbox/stacking.c +++ b/openbox/stacking.c @@ -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 diff --git a/openbox/stacking.h b/openbox/stacking.h index 773f6588..10482744 100644 --- a/openbox/stacking.h +++ b/openbox/stacking.h @@ -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 -- 2.34.1