Forgot to init restack sibling to NULL
[mikachu/openbox.git] / openbox / stacking.c
index cb710e5..166d382 100644 (file)
 #include "window.h"
 #include "event.h"
 #include "debug.h"
+#include "dock.h"
 #include "obt/prop.h"
 
 GList  *stacking_list = NULL;
+GList  *stacking_list_tail = NULL;
 /*! When true, stacking changes will not be reflected on the screen.  This is
   to freeze the on-screen stacking order while a window is being temporarily
   raised during focus cycling */
@@ -403,6 +405,7 @@ void stacking_raise(ObWindow *window)
         do_raise(wins);
         g_list_free(wins);
     }
+    stacking_list_tail = g_list_last(stacking_list);
 }
 
 void stacking_lower(ObWindow *window)
@@ -418,6 +421,21 @@ void stacking_lower(ObWindow *window)
         do_lower(wins);
         g_list_free(wins);
     }
+    stacking_list_tail = g_list_last(stacking_list);
+}
+
+void stacking_above(ObWindow *window, ObWindow *above)
+{
+    GList *wins, *before;
+
+    if (window_layer(window) != window_layer(above))
+        return;
+
+    wins = g_list_append(NULL, window);
+    stacking_list = g_list_remove(stacking_list, window);
+    before = g_list_previous(g_list_find(stacking_list, above));
+    do_restack(wins, before);
+    g_list_free(wins);
 }
 
 void stacking_below(ObWindow *window, ObWindow *below)
@@ -432,15 +450,20 @@ void stacking_below(ObWindow *window, ObWindow *below)
     before = g_list_next(g_list_find(stacking_list, below));
     do_restack(wins, before);
     g_list_free(wins);
+    stacking_list_tail = g_list_last(stacking_list);
 }
 
 void stacking_add(ObWindow *win)
 {
     g_assert(screen_support_win != None); /* make sure I dont break this in the
                                              future */
+    /* don't add windows that are being unmanaged ! */
+    if (WINDOW_IS_CLIENT(win)) g_assert(WINDOW_AS_CLIENT(win)->managed);
 
     stacking_list = g_list_append(stacking_list, win);
+
     stacking_raise(win);
+    /* stacking_list_tail set by stacking_raise() */
 }
 
 static GList *find_highest_relative(ObClient *client)
@@ -498,6 +521,9 @@ void stacking_add_nonintrusive(ObWindow *win)
 
     client = WINDOW_AS_CLIENT(win);
 
+    /* don't add windows that are being unmanaged ! */
+    g_assert(client->managed);
+
     /* insert above its highest parent (or its highest child !) */
     it_below = find_highest_relative(client);
 
@@ -550,26 +576,27 @@ void stacking_add_nonintrusive(ObWindow *win)
     wins = g_list_append(NULL, win);
     do_restack(wins, it_below);
     g_list_free(wins);
+    stacking_list_tail = g_list_last(stacking_list);
 }
 
-/*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
-  tries against all other clients.
-*/
-static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
+ObWindow *stacking_occluded(ObClient *client, ObWindow *sibling_win)
 {
     GList *it;
-    gboolean occluded = FALSE;
-    gboolean found = FALSE;
+    ObWindow *occluded = NULL;
+    ObClient *sibling = NULL;
+
+    if (sibling_win && WINDOW_IS_CLIENT(sibling_win))
+        sibling = WINDOW_AS_CLIENT(sibling_win);
 
     /* no need for any looping in this case */
     if (sibling && client->layer != sibling->layer)
-        return occluded;
+        return NULL;
 
-    for (it = stacking_list; it;
-         it = (found ? g_list_previous(it) :g_list_next(it)))
+    for (it = g_list_previous(g_list_find(stacking_list, client)); it;
+         it = g_list_previous(it))
         if (WINDOW_IS_CLIENT(it->data)) {
             ObClient *c = it->data;
-            if (found && !c->iconic &&
+            if (!c->iconic &&
                 (c->desktop == DESKTOP_ALL || client->desktop == DESKTOP_ALL ||
                  c->desktop == client->desktop) &&
                 !client_search_transient(client, c))
@@ -578,41 +605,54 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
                 {
                     if (sibling != NULL) {
                         if (c == sibling) {
-                            occluded = TRUE;
+                            occluded = sibling_win;
                             break;
                         }
                     }
                     else if (c->layer == client->layer) {
-                        occluded = TRUE;
+                        occluded = CLIENT_AS_WINDOW(c);
                         break;
                     }
                     else if (c->layer > client->layer)
                         break; /* we past its layer */
                 }
             }
-            else if (c == client)
-                found = TRUE;
+        }
+        else if (WINDOW_IS_DOCK(it->data)) {
+            ObDock *dock = it->data;
+            if (RECT_INTERSECTS_RECT(dock->area, client->frame->area))
+            {
+                if (sibling_win != NULL) {
+                    if (DOCK_AS_WINDOW(dock) == sibling_win) {
+                        occluded = sibling_win;
+                        break;
+                    }
+                }
+                else
+                    occluded = DOCK_AS_WINDOW(dock);
+            }
         }
     return occluded;
 }
 
-/*! Returns TRUE if client occludes the sibling. If sibling is NULL it tries
-  against all other clients.
-*/
-static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
+ObWindow *stacking_occludes(ObClient *client, ObWindow *sibling_win)
 {
     GList *it;
-    gboolean occludes = FALSE;
-    gboolean found = FALSE;
+    ObWindow *occludes = NULL;
+    ObClient *sibling = NULL;
+
+    if (sibling_win && WINDOW_IS_CLIENT(sibling_win))
+        sibling = WINDOW_AS_CLIENT(sibling_win);
 
     /* no need for any looping in this case */
     if (sibling && client->layer != sibling->layer)
-        return occludes;
+        return NULL;
 
-    for (it = stacking_list; it; it = g_list_next(it))
+    for (it = g_list_next(g_list_find(stacking_list, client));
+         it; it = g_list_next(it))
         if (WINDOW_IS_CLIENT(it->data)) {
             ObClient *c = it->data;
-            if (found && !c->iconic &&
+            if (!c->iconic &&
                 (c->desktop == DESKTOP_ALL || client->desktop == DESKTOP_ALL ||
                  c->desktop == client->desktop) &&
                 !client_search_transient(c, client))
@@ -621,29 +661,46 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
                 {
                     if (sibling != NULL) {
                         if (c == sibling) {
-                            occludes = TRUE;
+                            occludes = sibling_win;
                             break;
                         }
                     }
                     else if (c->layer == client->layer) {
-                        occludes = TRUE;
+                        occludes = CLIENT_AS_WINDOW(c);
                         break;
                     }
                     else if (c->layer < client->layer)
                         break; /* we past its layer */
                 }
             }
-            else if (c == client)
-                found = TRUE;
+        }
+        else if (WINDOW_IS_DOCK(it->data)) {
+            ObDock *dock = it->data;
+            if (RECT_INTERSECTS_RECT(dock->area, client->frame->area))
+            {
+                if (sibling_win != NULL) {
+                    if (DOCK_AS_WINDOW(dock) == sibling_win) {
+                        occludes = sibling_win;
+                        break;
+                    }
+                }
+                else
+                    occludes = DOCK_AS_WINDOW(dock);
+            }
         }
     return occludes;
 }
 
-gboolean stacking_restack_request(ObClient *client, ObClient *sibling,
+gboolean stacking_restack_request(ObClient *client, ObWindow *sibling_win,
                                   gint detail)
 {
     gboolean ret = FALSE;
 
+    ObClient *sibling = NULL;
+
+    if (sibling_win && WINDOW_IS_CLIENT(sibling_win))
+        sibling = WINDOW_AS_CLIENT(sibling_win);
+
     if (sibling && ((client->desktop != sibling->desktop &&
                      client->desktop != DESKTOP_ALL &&
                      sibling->desktop != DESKTOP_ALL) ||
@@ -667,7 +724,7 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling,
                  client->title, sibling ? sibling->title : "(all)");
         /* if this client occludes sibling (or anything if NULL), then
            lower it to the bottom */
-        if (stacking_occludes(client, sibling)) {
+        if (stacking_occludes(client, sibling_win)) {
             stacking_lower(CLIENT_AS_WINDOW(client));
             ret = TRUE;
         }
@@ -681,7 +738,7 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling,
     case TopIf:
         ob_debug("Restack request TopIf for client %s sibling %s",
                  client->title, sibling ? sibling->title : "(all)");
-        if (stacking_occluded(client, sibling)) {
+        if (stacking_occluded(client, sibling_win)) {
             stacking_raise(CLIENT_AS_WINDOW(client));
             ret = TRUE;
         }
@@ -689,11 +746,11 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling,
     case Opposite:
         ob_debug("Restack request Opposite for client %s sibling %s",
                  client->title, sibling ? sibling->title : "(all)");
-        if (stacking_occluded(client, sibling)) {
+        if (stacking_occluded(client, sibling_win)) {
             stacking_raise(CLIENT_AS_WINDOW(client));
             ret = TRUE;
         }
-        else if (stacking_occludes(client, sibling)) {
+        else if (stacking_occludes(client, sibling_win)) {
             stacking_lower(CLIENT_AS_WINDOW(client));
             ret = TRUE;
         }