all repos — openbox @ d33f44cd86c1474a2c84376509691869aca7bd9f

openbox fork - make it a bit more like ryudo

Rewrite the stacking code. It's a lot faster now, I should think. It's def a more clever algorithm. It deals with group transients much better.

On that note, utility and menu and toolbar window types are now treated as group transients in terms of stacking and focus and such.
Dana Jansens danakj@orodu.net
commit

d33f44cd86c1474a2c84376509691869aca7bd9f

parent

bf247215bb015dbb4dfa39c38bf020aa815cd306

3 files changed, 172 insertions(+), 147 deletions(-)

jump to
M openbox/client.copenbox/client.c

@@ -1117,9 +1117,15 @@ target = OB_TRAN_GROUP;

} } } - } 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 @@

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 @@ if (STRUT_EXISTS(self->strut))

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 @@ }

/* 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; + self = client_search_top_parent(self); + client_set_desktop_recursive(self, target, donthide); +} - it = client_search_top_transients(self); - - 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 @@ {

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;
M openbox/client.hopenbox/client.h

@@ -575,7 +575,15 @@ /*! Returns a list of top-level windows which this is a transient for.

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. */
M openbox/stacking.copenbox/stacking.c

@@ -158,180 +158,182 @@ }

} } -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; + 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); - 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); + /* 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 ((sit = g_slist_find(top->transients, it->data))) { - ObClient *c = sit->data; - gboolean sel_child; + /* 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; + } - ++i; + /* 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); - if (c == selected) - sel_child = TRUE; - else - sel_child = client_search_transient(c, selected) != NULL; + /* 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; - 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)); + /* 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)); + /* put transients of the selected window right above it */ + wins = g_list_concat(modals, trans); + wins = g_list_append(wins, selected); - ret = g_list_concat(ret, (raise ? trans_sel : trans)); - ret = g_list_concat(ret, (raise ? trans : trans_sel)); - + /* 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; -} - -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); + /* 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; - if ((sit = g_slist_find(top->group->members, it->data))) { - ObClient *c; - ObClientType t; + last = it; + } - ++i; - c = it->data; - t = c->type; + /* save this position in the stacking list */ + below = last; - 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; - } - } + /* 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; + /* 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 - top = client_search_top_transients(selected); + 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); - /* 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); + /* 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); + } - 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)); + /* 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)