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.
This commit is contained in:
Dana Jansens 2007-03-12 02:24:40 +00:00
parent bf247215bb
commit d33f44cd86
3 changed files with 190 additions and 165 deletions

View file

@ -1117,9 +1117,15 @@ void client_update_transient_for(ObClient *self)
} }
} }
} }
} else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) { } else if (self->group) {
self->transient = TRUE; if (self->type == OB_CLIENT_TYPE_DIALOG ||
target = OB_TRAN_GROUP; 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 } else
self->transient = FALSE; self->transient = FALSE;
@ -2024,7 +2030,7 @@ void client_calc_layer(ObClient *self)
orig = self; orig = self;
/* transients take on the layer of their parents */ /* 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)) for (; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig, 0, FALSE); client_calc_layer_recursive(it->data, orig, 0, FALSE);
@ -2449,21 +2455,18 @@ static void client_iconify_recursive(ObClient *self,
screen_update_areas(); screen_update_areas();
} }
/* iconify all transients */ /* iconify all direct transients */
for (it = self->transients; it; it = g_slist_next(it)) for (it = self->transients; it; it = g_slist_next(it))
if (it->data != self) client_iconify_recursive(it->data, if (it->data != self)
iconic, curdesk); if (client_is_direct_child(self, it->data))
client_iconify_recursive(it->data, iconic, curdesk);
} }
void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk) void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
{ {
GSList *it;
/* move up the transient chain as far as possible first */ /* move up the transient chain as far as possible first */
it = client_search_top_transients(self); self = client_search_top_parent(self);
client_iconify_recursive(self, iconic, curdesk);
for (; it; it = g_slist_next(it))
client_iconify_recursive(it->data, iconic, curdesk);
} }
void client_maximize(ObClient *self, gboolean max, gint dir, gboolean savearea) void client_maximize(ObClient *self, gboolean max, gint dir, gboolean savearea)
@ -2657,18 +2660,23 @@ void client_set_desktop_recursive(ObClient *self,
/* move all transients */ /* move all transients */
for (it = self->transients; it; it = g_slist_next(it)) for (it = self->transients; it; it = g_slist_next(it))
if (it->data != self) client_set_desktop_recursive(it->data, if (it->data != self)
target, donthide); 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) 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); gboolean client_is_direct_child(ObClient *parent, ObClient *child)
{
for(; it; it = g_slist_next(it)) while (child != parent &&
client_set_desktop_recursive(it->data, target, donthide); child->transient_for && child->transient_for != OB_TRAN_GROUP)
child = child->transient_for;
return child == parent;
} }
ObClient *client_search_modal_child(ObClient *self) ObClient *client_search_modal_child(ObClient *self)
@ -3236,7 +3244,14 @@ guint client_monitor(ObClient *self)
return screen_find_monitor(&self->frame->area); 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; GSList *ret = NULL;

View file

@ -575,7 +575,15 @@ ObClient *client_search_modal_child(ObClient *self);
It will only contain more than 1 element if the client is transient for its It will only contain more than 1 element if the client is transient for its
group. 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 /*! 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. */ returns the searched for parent if it is a parent, or NULL if not. */

View file

@ -158,180 +158,182 @@ static void do_lower(GList *wins)
} }
} }
static GList *pick_windows_recur(ObClient *top, ObClient *selected, static void restack_windows(ObClient *selected, gboolean raise, gboolean group)
gboolean raise)
{ {
GList *ret = NULL; GList *it, *last, *below, *above, *next;
GList *it, *next, *prev; GList *wins = NULL;
GSList *sit;
gint i, n; GList *group_modals = NULL;
GList *group_trans = NULL;
GList *modals = NULL; GList *modals = NULL;
GList *trans = NULL; GList *trans = NULL;
GList *modal_sel = NULL; /* the selected guys if modal */
GList *trans_sel = NULL; /* the selected guys if not */ 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);
/* 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);
/* 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;
}
/* remove first so we can't run into ourself */ /* remove first so we can't run into ourself */
if ((it = g_list_find(stacking_list, top))) it = g_list_find(stacking_list, selected);
g_assert(it);
stacking_list = g_list_delete_link(stacking_list, it);
/* 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;
/* 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 (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);
}
}
}
/* put transients of the selected window right above it */
wins = g_list_concat(modals, trans);
wins = g_list_append(wins, selected);
/* 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;
}
/* 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;
last = it;
}
/* save this position in the stacking list */
below = last;
/* 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;
}
/* 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
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) {
next = g_list_previous(it);
wins = g_list_prepend(wins, it->data);
stacking_list = g_list_delete_link(stacking_list, it); stacking_list = g_list_delete_link(stacking_list, it);
else
return NULL;
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);
if ((sit = g_slist_find(top->transients, it->data))) {
ObClient *c = sit->data;
gboolean sel_child;
++i;
if (c == selected)
sel_child = TRUE;
else
sel_child = client_search_transient(c, selected) != NULL;
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));
}
} 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));
}
}
/* 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), /* group transients go above the rest of the stuff acquired to now */
(raise ? modals : modal_sel)); wins = g_list_concat(group_trans, wins);
/* group modals go on the very top */
wins = g_list_concat(group_modals, wins);
ret = g_list_concat(ret, (raise ? trans_sel : trans)); do_restack(wins, below);
ret = g_list_concat(ret, (raise ? trans : trans_sel)); g_list_free(wins);
/* 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);
if ((sit = g_slist_find(top->group->members, it->data))) {
ObClient *c;
ObClientType t;
++i;
c = it->data;
t = c->type;
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;
}
}
}
}
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;
top = client_search_top_transients(selected);
/* 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);
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));
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;
} }
void stacking_raise(ObWindow *window, gboolean group) void stacking_raise(ObWindow *window, gboolean group)
{ {
GList *wins;
if (WINDOW_IS_CLIENT(window)) { if (WINDOW_IS_CLIENT(window)) {
ObClient *selected; ObClient *selected;
selected = WINDOW_AS_CLIENT(window); selected = WINDOW_AS_CLIENT(window);
wins = pick_windows(selected, TRUE, group); restack_windows(selected, TRUE, group);
} else { } else {
GList *wins;
wins = g_list_append(NULL, window); wins = g_list_append(NULL, window);
stacking_list = g_list_remove(stacking_list, 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) void stacking_lower(ObWindow *window, gboolean group)
{ {
GList *wins;
if (WINDOW_IS_CLIENT(window)) { if (WINDOW_IS_CLIENT(window)) {
ObClient *selected; ObClient *selected;
selected = WINDOW_AS_CLIENT(window); selected = WINDOW_AS_CLIENT(window);
wins = pick_windows(selected, FALSE, group); restack_windows(selected, FALSE, group);
} else { } else {
GList *wins;
wins = g_list_append(NULL, window); wins = g_list_append(NULL, window);
stacking_list = g_list_remove(stacking_list, 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) void stacking_below(ObWindow *window, ObWindow *below)