make restacking much better, yay
authorDana Jansens <danakj@orodu.net>
Thu, 10 May 2007 00:57:35 +0000 (00:57 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 10 May 2007 00:57:35 +0000 (00:57 +0000)
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. !

openbox/client.c
openbox/client.h
openbox/event.c
openbox/stacking.c
openbox/stacking.h

index 0c4cce1..4c88daf 100644 (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_nonintrusive(CLIENT_AS_WINDOW(self));
+        } else if (self->layer < old && self->transients == NULL) {
             stacking_remove(CLIENT_AS_WINDOW(self));
-            stacking_add(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;
index 30d4051..5a83739 100644 (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
index 566739c..0c594d6 100644 (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:
+                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:
-                /* Apps are so rude. And this is totally disconnected from
-                   activation/focus. Bleh. */
-                /*client_lower(client);*/
+                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 */
index 18747b9..afad8ad 100644 (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;
+}
index 2391f65..70e4b2d 100644 (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