stacking has been made more reliable with groups and group transients.

this was a pretty invasive change in client.c though, so it may break things?

it did expose some bugginess in client_calc_layer, which is now better than ever, hopefully there isn't more to be found.
This commit is contained in:
Dana Jansens 2007-03-11 16:58:19 +00:00
parent 1ff3c1dd9d
commit 62a39c4c70
4 changed files with 129 additions and 82 deletions

View file

@ -301,6 +301,8 @@ void client_manage(Window window)
client_get_all(self); client_get_all(self);
client_restore_session_state(self); client_restore_session_state(self);
client_calc_layer(self);
{ {
Time t = sn_app_started(self->startup_id, self->class); Time t = sn_app_started(self->startup_id, self->class);
if (t) self->user_time = t; if (t) self->user_time = t;
@ -461,7 +463,8 @@ void client_manage(Window window)
/* This is focus stealing prevention, if a user_time has been set */ /* This is focus stealing prevention, if a user_time has been set */
ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n", ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
self->window, self->user_time, client_last_user_time); self->window, self->user_time, client_last_user_time);
if (!self->user_time || self->user_time >= client_last_user_time) if (!self->user_time || self->user_time >= client_last_user_time ||
client_search_focus_parent(self) != NULL)
{ {
/* since focus can change the stacking orders, if we focus the /* since focus can change the stacking orders, if we focus the
window then the standard raise it gets is not enough, we need window then the standard raise it gets is not enough, we need
@ -1901,8 +1904,6 @@ static void client_change_state(ObClient *self)
netstate[num++] = prop_atoms.ob_wm_state_undecorated; netstate[num++] = prop_atoms.ob_wm_state_undecorated;
PROP_SETA32(self->window, net_wm_state, atom, netstate, num); PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
client_calc_layer(self);
if (self->frame) if (self->frame)
frame_adjust_state(self->frame); frame_adjust_state(self->frame);
} }
@ -1968,20 +1969,23 @@ static ObStackingLayer calc_layer(ObClient *self)
} }
static void client_calc_layer_recursive(ObClient *self, ObClient *orig, static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
ObStackingLayer l, gboolean raised) ObStackingLayer min, gboolean raised)
{ {
ObStackingLayer old, own; ObStackingLayer old, own;
GSList *it; GSList *it;
old = self->layer; old = self->layer;
own = calc_layer(self); own = calc_layer(self);
self->layer = l > own ? l : own; self->layer = MAX(own, min);
ob_debug("layer for %s: %d\n", self->title, self->layer);
for (it = self->transients; it; it = g_slist_next(it)) for (it = self->transients; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig, client_calc_layer_recursive(it->data, orig,
l, raised ? raised : l != old); self->layer,
raised ? raised : self->layer != old);
if (!raised && l != old) if (!raised && self->layer != old)
if (orig->frame) { /* only restack if the original window is managed */ if (orig->frame) { /* only restack if the original window is managed */
stacking_remove(CLIENT_AS_WINDOW(self)); stacking_remove(CLIENT_AS_WINDOW(self));
stacking_add(CLIENT_AS_WINDOW(self)); stacking_add(CLIENT_AS_WINDOW(self));
@ -1990,17 +1994,16 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
void client_calc_layer(ObClient *self) void client_calc_layer(ObClient *self)
{ {
ObStackingLayer l;
ObClient *orig; ObClient *orig;
GSList *it;
orig = self; orig = self;
/* transients take on the layer of their parents */ /* transients take on the layer of their parents */
self = client_search_top_transient(self); it = client_search_top_transients(self);
l = calc_layer(self); for (; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig, 0, FALSE);
client_calc_layer_recursive(self, orig, l, FALSE);
} }
gboolean client_should_show(ObClient *self) gboolean client_should_show(ObClient *self)
@ -2323,8 +2326,8 @@ void client_fullscreen(ObClient *self, gboolean fs, gboolean savearea)
self->fullscreen == fs) return; /* already done */ self->fullscreen == fs) return; /* already done */
self->fullscreen = fs; self->fullscreen = fs;
client_change_state(self); /* change the state hints on the client, client_change_state(self); /* change the state hints on the client */
and adjust out layer/stacking */ client_calc_layer(self); /* and adjust out layer/stacking */
if (fs) { if (fs) {
if (savearea) if (savearea)
@ -2427,11 +2430,13 @@ static void client_iconify_recursive(ObClient *self,
void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk) void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
{ {
/* move up the transient chain as far as possible first */ GSList *it;
self = client_search_top_transient(self);
client_iconify_recursive(client_search_top_transient(self), /* move up the transient chain as far as possible first */
iconic, curdesk); it = client_search_top_transients(self);
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)
@ -2631,8 +2636,12 @@ void client_set_desktop_recursive(ObClient *self,
void client_set_desktop(ObClient *self, guint target, gboolean donthide) void client_set_desktop(ObClient *self, guint target, gboolean donthide)
{ {
client_set_desktop_recursive(client_search_top_transient(self), GSList *it;
target, donthide);
it = client_search_top_transients(self);
for(; it; it = g_slist_next(it))
client_set_desktop_recursive(it->data, target, donthide);
} }
ObClient *client_search_modal_child(ObClient *self) ObClient *client_search_modal_child(ObClient *self)
@ -2839,16 +2848,14 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
if (demands_attention != self->demands_attention) if (demands_attention != self->demands_attention)
client_hilite(self, demands_attention); client_hilite(self, demands_attention);
client_calc_layer(self);
client_change_state(self); /* change the hint to reflect these changes */ client_change_state(self); /* change the hint to reflect these changes */
} }
ObClient *client_focus_target(ObClient *self) ObClient *client_focus_target(ObClient *self)
{ {
ObClient *child; ObClient *child = NULL;
/* if we have a modal child, then focus it, not us */ child = client_search_modal_child(self);
child = client_search_modal_child(client_search_top_transient(self));
if (child) return child; if (child) return child;
return self; return self;
} }
@ -3224,13 +3231,17 @@ guint client_monitor(ObClient *self)
return most; return most;
} }
ObClient *client_search_top_transient(ObClient *self) GSList *client_search_top_transients(ObClient *self)
{ {
/* move up the transient chain as far as possible */ GSList *ret = NULL;
if (self->transient_for) {
if (self->transient_for != OB_TRAN_GROUP) { /* move up the direct transient chain as far as possible */
return client_search_top_transient(self->transient_for); while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
} else { self = self->transient_for;
if (!self->transient_for)
ret = g_slist_prepend(ret, self);
else {
GSList *it; GSList *it;
g_assert(self->group); g_assert(self->group);
@ -3238,16 +3249,15 @@ ObClient *client_search_top_transient(ObClient *self)
for (it = self->group->members; it; it = g_slist_next(it)) { for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data; ObClient *c = it->data;
/* checking transient_for prevents infinate loops! */ if (!c->transient_for)
if (c != self && !c->transient_for) ret = g_slist_prepend(ret, c);
break;
} }
if (it)
return it->data; if (ret == NULL) /* no group parents */
} ret = g_slist_prepend(ret, self);
} }
return self; return ret;
} }
ObClient *client_search_focus_parent(ObClient *self) ObClient *client_search_focus_parent(ObClient *self)

View file

@ -571,7 +571,11 @@ ObClient *client_search_focus_tree_full(ObClient *self);
*/ */
ObClient *client_search_modal_child(ObClient *self); ObClient *client_search_modal_child(ObClient *self);
ObClient *client_search_top_transient(ObClient *self); /*! 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);
/*! 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

@ -260,11 +260,15 @@ ObClient* focus_fallback_target(ObFocusFallbackType type)
if (!config_focus_follow || config_focus_last) if (!config_focus_follow || config_focus_last)
trans = TRUE; trans = TRUE;
else { else {
if ((target = client_under_pointer()) && if ((target = client_under_pointer())) {
client_search_transient GSList *sit;
(client_search_top_transient(target), old))
{ sit = client_search_top_transients(target);
trans = TRUE; for (; sit; sit = g_slist_next(sit))
if (client_search_transient(sit->data, old)) {
trans = TRUE;
break;
}
} }
} }

View file

@ -158,7 +158,8 @@ static void do_lower(GList *wins)
} }
} }
static GList *pick_windows(ObClient *top, ObClient *selected, gboolean raise) static GList *pick_windows_recur(ObClient *top, ObClient *selected,
gboolean raise)
{ {
GList *ret = NULL; GList *ret = NULL;
GList *it, *next, *prev; GList *it, *next, *prev;
@ -194,21 +195,19 @@ static GList *pick_windows(ObClient *top, ObClient *selected, gboolean raise)
if (!c->modal) { if (!c->modal) {
if (!sel_child) { if (!sel_child) {
trans = g_list_concat(trans, trans = g_list_concat
pick_windows(c, selected, raise)); (trans, pick_windows_recur(c, selected, raise));
} else { } else {
trans_sel = g_list_concat(trans_sel, trans_sel = g_list_concat
pick_windows(c, selected, (trans_sel, pick_windows_recur(c, selected, raise));
raise));
} }
} else { } else {
if (!sel_child) { if (!sel_child) {
modals = g_list_concat(modals, modals = g_list_concat
pick_windows(c, selected, raise)); (modals, pick_windows_recur(c, selected, raise));
} else { } else {
modal_sel = g_list_concat(modal_sel, modal_sel = g_list_concat
pick_windows(c, selected, (modal_sel, pick_windows_recur(c, selected, raise));
raise));
} }
} }
/* if we dont have a prev then start back at the beginning, /* if we dont have a prev then start back at the beginning,
@ -230,8 +229,8 @@ static GList *pick_windows(ObClient *top, ObClient *selected, gboolean raise)
return ret; return ret;
} }
static GList *pick_group_windows(ObClient *top, ObClient *selected, static GList *pick_group_windows_recur(ObClient *top, ObClient *selected,
gboolean raise, gboolean normal) gboolean raise, gboolean normal)
{ {
GList *ret = NULL; GList *ret = NULL;
GList *it, *next, *prev; GList *it, *next, *prev;
@ -262,8 +261,8 @@ static GList *pick_group_windows(ObClient *top, ObClient *selected,
(normal && t == OB_CLIENT_TYPE_NORMAL))) (normal && t == OB_CLIENT_TYPE_NORMAL)))
{ {
ret = g_list_concat(ret, ret = g_list_concat(ret,
pick_windows(sit->data, pick_windows_recur(sit->data,
selected, raise)); selected, raise));
/* if we dont have a prev then start back at the beginning, /* if we dont have a prev then start back at the beginning,
otherwise skip back to the prev's next */ otherwise skip back to the prev's next */
next = prev ? g_list_next(prev) : stacking_list; next = prev ? g_list_next(prev) : stacking_list;
@ -274,18 +273,43 @@ static GList *pick_group_windows(ObClient *top, ObClient *selected,
return ret; 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; GList *wins;
if (WINDOW_IS_CLIENT(window)) { if (WINDOW_IS_CLIENT(window)) {
ObClient *c;
ObClient *selected; ObClient *selected;
selected = WINDOW_AS_CLIENT(window); selected = WINDOW_AS_CLIENT(window);
c = client_search_top_transient(selected); wins = pick_windows(selected, TRUE, group);
wins = pick_windows(c, selected, TRUE);
wins = g_list_concat(wins,
pick_group_windows(c, selected, TRUE, group));
} else { } else {
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);
@ -299,13 +323,9 @@ void stacking_lower(ObWindow *window, gboolean group)
GList *wins; GList *wins;
if (WINDOW_IS_CLIENT(window)) { if (WINDOW_IS_CLIENT(window)) {
ObClient *c;
ObClient *selected; ObClient *selected;
selected = WINDOW_AS_CLIENT(window); selected = WINDOW_AS_CLIENT(window);
c = client_search_top_transient(selected); wins = pick_windows(selected, FALSE, group);
wins = pick_windows(c, selected, FALSE);
wins = g_list_concat(pick_group_windows(c, selected, FALSE, group),
wins);
} else { } else {
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);
@ -341,7 +361,7 @@ void stacking_add_nonintrusive(ObWindow *win)
{ {
ObClient *client; ObClient *client;
ObClient *parent = NULL; ObClient *parent = NULL;
GList *it_before = NULL; GList *it_below = NULL;
if (!WINDOW_IS_CLIENT(win)) { if (!WINDOW_IS_CLIENT(win)) {
stacking_add(win); /* no special rules for others */ stacking_add(win); /* no special rules for others */
@ -373,29 +393,38 @@ void stacking_add_nonintrusive(ObWindow *win)
} }
} }
if (!(it_before = g_list_find(stacking_list, parent))) { if (!(it_below = g_list_find(stacking_list, parent))) {
/* no parent to put above, try find the focused client to go /* no parent to put above, try find the focused client to go
under */ under */
if (focus_client && focus_client->layer == client->layer) { if (focus_client && focus_client->layer == client->layer) {
if ((it_before = g_list_find(stacking_list, focus_client))) if ((it_below = g_list_find(stacking_list, focus_client)))
it_before = it_before->next; it_below = it_below->next;
} }
} }
if (!it_before) { if (!it_below) {
/* out of ideas, just add it normally... */ /* out of ideas, just add it normally... */
stacking_add(win); stacking_add(win);
} else { } else {
GList *it;
/* make sure it's not in the wrong layer though ! */ /* make sure it's not in the wrong layer though ! */
while (it_before && client->layer < ((ObClient*)it_before->data)->layer) for (; it_below; it_below = g_list_next(it_below))
it_before = g_list_next(it_before); {
while (it_before != stacking_list && /* stop when the window is not in a higher layer than the window
client->layer > ((ObClient*)g_list_previous(it_before)->data)->layer) it is going above (it_below) */
it_before = g_list_previous(it_before); if (client->layer >= window_layer(it_below->data))
break;
}
for (; it_below != stacking_list;
it_below = g_list_previous(it_below))
{
/* stop when the window is not in a lower layer than the
window it is going under (it_above) */
GList *it_above = g_list_previous(it_below);
if (client->layer <= window_layer(it_above->data))
break;
}
GList *wins = g_list_append(NULL, win); GList *wins = g_list_append(NULL, win);
do_restack(wins, it_before); do_restack(wins, it_below);
g_list_free(wins); g_list_free(wins);
} }
} }