#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);
}
#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);
}
#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
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;
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) {
break;
}
do_restack(layer[i], it);
- g_list_free(layer[i]);
}
}
}
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;
/* 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;
}
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)
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);
}
}
+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);
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)
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