From 62a39c4c70b0ed8e153b0cccac853cc6fded99ba Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sun, 11 Mar 2007 16:58:19 +0000 Subject: [PATCH] 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. --- openbox/client.c | 84 ++++++++++++++++++++---------------- openbox/client.h | 6 ++- openbox/focus.c | 14 +++--- openbox/stacking.c | 105 +++++++++++++++++++++++++++++---------------- 4 files changed, 128 insertions(+), 81 deletions(-) diff --git a/openbox/client.c b/openbox/client.c index c32a4635..5bc79847 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -301,6 +301,8 @@ void client_manage(Window window) client_get_all(self); client_restore_session_state(self); + client_calc_layer(self); + { Time t = sn_app_started(self->startup_id, self->class); 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 */ 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); - 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 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; PROP_SETA32(self->window, net_wm_state, atom, netstate, num); - client_calc_layer(self); - if (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, - ObStackingLayer l, gboolean raised) + ObStackingLayer min, gboolean raised) { ObStackingLayer old, own; GSList *it; old = self->layer; 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)) 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 */ stacking_remove(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) { - ObStackingLayer l; ObClient *orig; + GSList *it; orig = self; /* transients take on the layer of their parents */ - self = client_search_top_transient(self); - - l = calc_layer(self); + it = client_search_top_transients(self); - client_calc_layer_recursive(self, orig, l, FALSE); + for (; it; it = g_slist_next(it)) + client_calc_layer_recursive(it->data, orig, 0, FALSE); } 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; - client_change_state(self); /* change the state hints on the client, - and adjust out layer/stacking */ + client_change_state(self); /* change the state hints on the client */ + client_calc_layer(self); /* and adjust out layer/stacking */ if (fs) { if (savearea) @@ -2427,11 +2430,13 @@ static void client_iconify_recursive(ObClient *self, void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk) { + GSList *it; + /* move up the transient chain as far as possible first */ - self = client_search_top_transient(self); + it = client_search_top_transients(self); - client_iconify_recursive(client_search_top_transient(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) @@ -2631,8 +2636,12 @@ void client_set_desktop_recursive(ObClient *self, void client_set_desktop(ObClient *self, guint target, gboolean donthide) { - client_set_desktop_recursive(client_search_top_transient(self), - target, donthide); + GSList *it; + + 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) @@ -2839,16 +2848,14 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) if (demands_attention != self->demands_attention) client_hilite(self, demands_attention); - client_calc_layer(self); client_change_state(self); /* change the hint to reflect these changes */ } ObClient *client_focus_target(ObClient *self) { - ObClient *child; - - /* if we have a modal child, then focus it, not us */ - child = client_search_modal_child(client_search_top_transient(self)); + ObClient *child = NULL; + + child = client_search_modal_child(self); if (child) return child; return self; } @@ -3224,13 +3231,17 @@ guint client_monitor(ObClient *self) 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 */ - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - return client_search_top_transient(self->transient_for); - } else { + GSList *ret = NULL; + + /* move up the direct transient chain as far as possible */ + while (self->transient_for && self->transient_for != OB_TRAN_GROUP) + self = self->transient_for; + + if (!self->transient_for) + ret = g_slist_prepend(ret, self); + else { GSList *it; 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)) { ObClient *c = it->data; - /* checking transient_for prevents infinate loops! */ - if (c != self && !c->transient_for) - break; + if (!c->transient_for) + ret = g_slist_prepend(ret, c); } - 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) diff --git a/openbox/client.h b/openbox/client.h index 043a6def..b418964d 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -571,7 +571,11 @@ ObClient *client_search_focus_tree_full(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 returns the searched for parent if it is a parent, or NULL if not. */ diff --git a/openbox/focus.c b/openbox/focus.c index 2d6804bc..73cb6f52 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -260,11 +260,15 @@ ObClient* focus_fallback_target(ObFocusFallbackType type) if (!config_focus_follow || config_focus_last) trans = TRUE; else { - if ((target = client_under_pointer()) && - client_search_transient - (client_search_top_transient(target), old)) - { - trans = TRUE; + if ((target = client_under_pointer())) { + GSList *sit; + + sit = client_search_top_transients(target); + for (; sit; sit = g_slist_next(sit)) + if (client_search_transient(sit->data, old)) { + trans = TRUE; + break; + } } } diff --git a/openbox/stacking.c b/openbox/stacking.c index ff5a943b..34064db7 100644 --- a/openbox/stacking.c +++ b/openbox/stacking.c @@ -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 *it, *next, *prev; @@ -194,21 +195,19 @@ static GList *pick_windows(ObClient *top, ObClient *selected, gboolean raise) if (!c->modal) { if (!sel_child) { - trans = g_list_concat(trans, - pick_windows(c, selected, raise)); + trans = g_list_concat + (trans, pick_windows_recur(c, selected, raise)); } else { - trans_sel = g_list_concat(trans_sel, - pick_windows(c, selected, - raise)); + trans_sel = g_list_concat + (trans_sel, pick_windows_recur(c, selected, raise)); } } else { if (!sel_child) { - modals = g_list_concat(modals, - pick_windows(c, selected, raise)); + modals = g_list_concat + (modals, pick_windows_recur(c, selected, raise)); } else { - modal_sel = g_list_concat(modal_sel, - pick_windows(c, selected, - raise)); + 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, @@ -230,8 +229,8 @@ static GList *pick_windows(ObClient *top, ObClient *selected, gboolean raise) return ret; } -static GList *pick_group_windows(ObClient *top, ObClient *selected, - gboolean raise, gboolean normal) +static GList *pick_group_windows_recur(ObClient *top, ObClient *selected, + gboolean raise, gboolean normal) { GList *ret = NULL; GList *it, *next, *prev; @@ -262,8 +261,8 @@ static GList *pick_group_windows(ObClient *top, ObClient *selected, (normal && t == OB_CLIENT_TYPE_NORMAL))) { ret = g_list_concat(ret, - pick_windows(sit->data, - selected, raise)); + 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; @@ -274,18 +273,43 @@ static GList *pick_group_windows(ObClient *top, ObClient *selected, 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) { GList *wins; if (WINDOW_IS_CLIENT(window)) { - ObClient *c; ObClient *selected; selected = WINDOW_AS_CLIENT(window); - c = client_search_top_transient(selected); - wins = pick_windows(c, selected, TRUE); - wins = g_list_concat(wins, - pick_group_windows(c, selected, TRUE, group)); + wins = pick_windows(selected, TRUE, group); } else { wins = g_list_append(NULL, window); stacking_list = g_list_remove(stacking_list, window); @@ -299,13 +323,9 @@ void stacking_lower(ObWindow *window, gboolean group) GList *wins; if (WINDOW_IS_CLIENT(window)) { - ObClient *c; ObClient *selected; selected = WINDOW_AS_CLIENT(window); - c = client_search_top_transient(selected); - wins = pick_windows(c, selected, FALSE); - wins = g_list_concat(pick_group_windows(c, selected, FALSE, group), - wins); + wins = pick_windows(selected, FALSE, group); } else { wins = g_list_append(NULL, window); stacking_list = g_list_remove(stacking_list, window); @@ -341,7 +361,7 @@ void stacking_add_nonintrusive(ObWindow *win) { ObClient *client; ObClient *parent = NULL; - GList *it_before = NULL; + GList *it_below = NULL; if (!WINDOW_IS_CLIENT(win)) { 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 under */ if (focus_client && focus_client->layer == client->layer) { - if ((it_before = g_list_find(stacking_list, focus_client))) - it_before = it_before->next; + if ((it_below = g_list_find(stacking_list, focus_client))) + it_below = it_below->next; } } - if (!it_before) { + if (!it_below) { /* out of ideas, just add it normally... */ stacking_add(win); } else { - GList *it; - /* make sure it's not in the wrong layer though ! */ - while (it_before && client->layer < ((ObClient*)it_before->data)->layer) - it_before = g_list_next(it_before); - while (it_before != stacking_list && - client->layer > ((ObClient*)g_list_previous(it_before)->data)->layer) - it_before = g_list_previous(it_before); + for (; it_below; it_below = g_list_next(it_below)) + { + /* stop when the window is not in a higher layer than the window + it is going above (it_below) */ + 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); - do_restack(wins, it_before); + do_restack(wins, it_below); g_list_free(wins); } } -- 2.39.2