make restacking much better, yay

no more cludge using actions to raise windows. when a window changes layer it
uses add_nonintrusive now so it won't cover the focused window. this way
fullscreen windows when they drop down, don't cover up the new focus target.

fix add_nonintrusive so that if the window is focused it gets added to the top

add back support for ConfigureRequest restacking, this time properly though,
using all the detail and sibling modes. but when windows use this to raise they
are using some old business and we're going to assume they actually want to
activate instead. this means firefox works nicely. yay.

ubuntu's firefox has been made to just stop raising entirely though. !
This commit is contained in:
Dana Jansens 2007-05-10 00:57:35 +00:00
parent 6412fba7fd
commit 9830440643
5 changed files with 114 additions and 60 deletions

View file

@ -451,7 +451,7 @@ void client_manage(Window window)
raised to the top. Legacy begets legacy I guess?
*/
if (!client_restore_session_stacking(self))
client_raise(self);
stacking_raise(CLIENT_AS_WINDOW(self));
}
/* this has to happen before we try focus the window, but we want it to
@ -2344,13 +2344,25 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
for (it = self->transients; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig,
self->layer,
raised ? raised : self->layer != old);
raised ? raised : self->layer > old);
if (!raised && self->layer != old)
if (orig->frame) { /* only restack if the original window is managed */
/* restack. but only if the original window is managed.
raised is used so that only the bottom-most window in the stacking
order is raised, the others will automatically come with it.
also only the highest windows in the stacking order (no transients)
are lowered, cuz the rest come for free
*/
if (!raised && orig->frame) {
if (self->layer > old) {
stacking_remove(CLIENT_AS_WINDOW(self));
stacking_add(CLIENT_AS_WINDOW(self));
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
} else if (self->layer < old && self->transients == NULL) {
stacking_remove(CLIENT_AS_WINDOW(self));
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
}
}
}
void client_calc_layer(ObClient *self)
@ -3077,7 +3089,7 @@ void client_set_desktop_recursive(ObClient *self,
client_showhide(self);
/* raise if it was not already on the desktop */
if (old != DESKTOP_ALL)
client_raise(self);
stacking_raise(CLIENT_AS_WINDOW(self));
if (STRUT_EXISTS(self->strut))
screen_update_areas();
}
@ -3302,7 +3314,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
self->modal = modal;
/* when a window changes modality, then its stacking order with its
transients needs to change */
client_raise(self);
stacking_raise(CLIENT_AS_WINDOW(self));
}
if (iconic != self->iconic)
client_iconify(self, iconic, FALSE);
@ -3444,17 +3456,10 @@ static void client_present(ObClient *self, gboolean here, gboolean raise)
return;
if (self->shaded)
client_shade(self, FALSE);
if (raise)
stacking_raise(CLIENT_AS_WINDOW(self));
client_focus(self);
if (raise) {
/* we do this as an action here. this is rather important. this is
because we want the results from the focus change to take place
BEFORE we go about raising the window. when a fullscreen window
loses focus, we need this or else the raise wont be able to raise
above the to-lose-focus fullscreen window. */
client_raise(self);
}
}
void client_activate(ObClient *self, gboolean here, gboolean user)
@ -3510,16 +3515,6 @@ void client_bring_helper_windows(ObClient *self)
client_bring_helper_windows_recursive(self, self->desktop);
}
void client_raise(ObClient *self)
{
action_run_string("Raise", self, CurrentTime);
}
void client_lower(ObClient *self)
{
action_run_string("Lower", self, CurrentTime);
}
gboolean client_focused(ObClient *self)
{
return self == focus_client;

View file

@ -550,26 +550,6 @@ void client_bring_helper_windows(ObClient *self);
/*! Calculates the stacking layer for the client window */
void client_calc_layer(ObClient *self);
/*! Raises the client to the top of its stacking layer
Normally actions call to the client_* functions to make stuff go, but this
one is an exception. It just fires off an action, which will be queued.
This is because stacking order rules can be changed by focus state, and so
any time focus changes you have to wait for it to complete before you can
properly restart windows. As such, this only queues an action for later
execution, once the focus change has gone through.
*/
void client_raise(ObClient *self);
/*! Lowers the client to the bottom of its stacking layer
Normally actions call to the client_* functions to make stuff go, but this
one is an exception. It just fires off an action, which will be queued.
This is because stacking order rules can be changed by focus state, and so
any time focus changes you have to wait for it to complete before you can
properly restart windows. As such, this only queues an action for later
execution, once the focus change has gone through.
*/
void client_lower(ObClient *self);
/*! Updates the window's transient status, and any parents of it */
void client_update_transient_for(ObClient *self);
/*! Update the protocols that the window supports and adjusts things if they

View file

@ -1019,20 +1019,55 @@ static void event_handle_client(ObClient *client, XEvent *e)
}
if (e->xconfigurerequest.value_mask & CWStackMode) {
ObClient *sibling = NULL;
/* get the sibling */
if (e->xconfigurerequest.value_mask & CWSibling) {
ObWindow *win;
win = g_hash_table_lookup(window_map,
&e->xconfigurerequest.above);
if (WINDOW_IS_CLIENT(win))
sibling = WINDOW_AS_CLIENT(win);
}
switch (e->xconfigurerequest.detail) {
case Below:
case BottomIf:
/* Apps are so rude. And this is totally disconnected from
activation/focus. Bleh. */
/*client_lower(client);*/
ob_debug("ConfigureRequest Below for client %s sibling %s\n",
client->title, sibling ? sibling->title : "(all)");
/* just lower it */
stacking_lower(CLIENT_AS_WINDOW(client));
break;
case BottomIf:
ob_debug("ConfigureRequest BottomIf for client %s sibling "
"%s\n",
client->title, sibling ? sibling->title : "(all)");
/* if this client occludes sibling (or anything if NULL), then
lower it to the bottom */
if (stacking_occluded(sibling, client))
stacking_lower(CLIENT_AS_WINDOW(client));
break;
case Above:
ob_debug("ConfigureRequest Above for client %s sibling %s\n",
client->title, sibling ? sibling->title : "(all)");
/* activate it rather than just focus it */
client_activate(client, FALSE, FALSE);
break;
case TopIf:
ob_debug("ConfigureRequest TopIf for client %s sibling %s\n",
client->title, sibling ? sibling->title : "(all)");
if (stacking_occluded(client, sibling))
/* activate it rather than just focus it */
client_activate(client, FALSE, FALSE);
case Opposite:
ob_debug("ConfigureRequest Opposite for client %s sibling "
"%s\n",
client->title, sibling ? sibling->title : "(all)");
if (stacking_occluded(client, sibling))
/* activate it rather than just focus it */
client_activate(client, FALSE, FALSE);
else if (stacking_occluded(sibling, client))
stacking_lower(CLIENT_AS_WINDOW(client));
default:
/* Apps are so rude. And this is totally disconnected from
activation/focus. Bleh. */
/*client_raise(client);*/
break;
}
}
@ -1601,7 +1636,7 @@ static gboolean focus_delay_func(gpointer data)
event_curtime = d->time;
if (focus_client != d->client) {
if (client_focus(d->client) && config_focus_raise)
client_raise(d->client);
stacking_raise(CLIENT_AS_WINDOW(d->client));
}
event_curtime = old;
return FALSE; /* no repeat */

View file

@ -416,7 +416,7 @@ void stacking_add_nonintrusive(ObWindow *win)
/* insert above its highest parent (or its highest child !) */
it_below = find_highest_relative(client);
if (!it_below) {
if (!it_below && client != focus_client) {
/* nothing to put it directly above, so try find the focused client to
put it underneath it */
if (focus_client && focus_client->layer == client->layer) {
@ -425,10 +425,16 @@ void stacking_add_nonintrusive(ObWindow *win)
}
}
if (!it_below) {
/* there is no window to put this directly above, so put it at the
bottom */
stacking_list = g_list_prepend(stacking_list, win);
stacking_lower(win);
if (client == focus_client) {
/* it's focused so put it at the top */
stacking_list = g_list_append(stacking_list, win);
stacking_raise(win);
} else {
/* there is no window to put this directly above, so put it at the
bottom */
stacking_list = g_list_prepend(stacking_list, win);
stacking_lower(win);
}
} else {
/* make sure it's not in the wrong layer though ! */
for (; it_below; it_below = g_list_next(it_below))
@ -453,3 +459,36 @@ void stacking_add_nonintrusive(ObWindow *win)
g_list_free(wins);
}
}
gboolean stacking_occluded(ObClient *client, ObClient *sibling)
{
GList *it;
gboolean obscured = FALSE;
gboolean found = FALSE;
/* no need for any looping in this case */
if (sibling && client->layer != sibling->layer)
return obscured;
for (it = stacking_list; it; it = g_list_next(it))
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = it->data;
if (found) {
if (sibling != NULL) {
if (c == sibling) {
obscured = TRUE;
break;
}
}
else if (c->layer == client->layer) {
obscured = TRUE;
break;
}
else if (c->layer > client->layer)
break; /* we past its layer */
}
else if (c == client)
found = TRUE;
}
return obscured;
}

View file

@ -59,4 +59,9 @@ void stacking_lower(ObWindow *window);
*/
void stacking_below(ObWindow *window, ObWindow *below);
/*! Returns TRUE if client is occluded by sibling. If sibling is NULL it tries
against all other clients. Otherwise, it returns FALSE.
*/
gboolean stacking_occluded(struct _ObClient *client,struct _ObClient *sibling);
#endif