Fix stacking of unmanaged windows and managing windows on restart.
authorDana Jansens <danakj@orodu.net>
Sat, 26 Jun 2010 00:01:03 +0000 (02:01 +0200)
committerDana Jansens <danakj@orodu.net>
Sat, 26 Jun 2010 23:37:57 +0000 (01:37 +0200)
keep inputonly windows in the stacking order
create hashtables in stacking.[ch] to find windows in the stacking lists by
 their window id
make the screen support window be an obwindow since it is a child of root
 and so windows can stack relative to it.
allow unmanaged windows to change their stacking order and track the changes
 for display
on restart manage unmapped windows as "unmanaged" as well as override-redirect
 windows (the code paths here changed a fair bit, allowing fewer repetitive
 XGetWindowAttributes calls)
adds a ObStackingIter data structure and functions in stacking.[ch] that allow
 you to iterate through all the windows (managed and unmanaged) together in
 the order they should appear on screen.

13 files changed:
openbox/client.c
openbox/composite.c
openbox/dock.c
openbox/event.c
openbox/openbox.c
openbox/popup.c
openbox/screen.c
openbox/stacking.c
openbox/stacking.h
openbox/unmanaged.c
openbox/unmanaged.h
openbox/window.c
openbox/window.h

index 37e326f2c17dccd30cd1bf717ab2d1f0a77b95dc..374ab99c71ab7eaac52e648db701469375160c69 100644 (file)
@@ -78,7 +78,7 @@ static void client_get_all(ObClient *self, gboolean real);
 static void client_get_startup_id(ObClient *self);
 static void client_get_session_ids(ObClient *self);
 static void client_save_app_rule_values(ObClient *self);
-static void client_get_area(ObClient *self);
+static gboolean client_get_area(ObClient *self);
 static void client_get_desktop(ObClient *self);
 static void client_get_state(ObClient *self);
 static void client_get_shaped(ObClient *self);
@@ -211,14 +211,6 @@ void client_manage(Window window, ObPrompt *prompt)
 
     ob_debug("Managing window: 0x%lx", window);
 
-    /* choose the events we want to receive on the CLIENT window
-       (ObPrompt windows can request events too) */
-    attrib_set.event_mask = CLIENT_EVENTMASK |
-        (prompt ? prompt->event_mask : 0);
-    attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
-    XChangeWindowAttributes(obt_display, window,
-                            CWEventMask|CWDontPropagate, &attrib_set);
-
     /* create the ObClient struct, and populate it from the hints on the
        window */
     self = window_new(OB_WINDOW_CLASS_CLIENT, ObClient);
@@ -231,6 +223,21 @@ void client_manage(Window window, ObPrompt *prompt)
     self->gravity = NorthWestGravity;
     self->desktop = screen_num_desktops; /* always an invalid value */
 
+    /* this is needed for the frame to set itself up */
+    if (!client_get_area(self)) {
+        ob_debug("Failed to manage window %lx, could not get area", window);
+        window_free(CLIENT_AS_WINDOW(self));
+        return;
+    }
+
+    /* choose the events we want to receive on the CLIENT window
+       (ObPrompt windows can request events too) */
+    attrib_set.event_mask = CLIENT_EVENTMASK |
+        (prompt ? prompt->event_mask : 0);
+    attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
+    XChangeWindowAttributes(obt_display, window,
+                            CWEventMask|CWDontPropagate, &attrib_set);
+
     /* get all the stuff off the window */
     client_get_all(self, TRUE);
 
@@ -530,6 +537,13 @@ ObClient *client_fake_manage(Window window)
     self = window_new(OB_WINDOW_CLASS_CLIENT, ObClient);
     self->window = window;
 
+    /* this is needed for the frame to set itself up */
+    if (!client_get_area(self)) {
+        ob_debug("Failed to manage window %lx, could not get area", window);
+        window_free(CLIENT_AS_WINDOW(self));
+        return NULL;
+    }
+
     client_get_all(self, FALSE);
     /* per-app settings override stuff, and return the settings for other
        uses too. this returns a shallow copy that needs to be freed */
@@ -615,7 +629,7 @@ void client_unmanage(ObClient *self)
     self->kill_prompt = NULL;
 
     client_list = g_list_remove(client_list, self);
-    stacking_remove(self);
+    stacking_remove(CLIENT_AS_WINDOW(self));
     window_remove(self->window);
 
     /* once the client is out of the list, update the struts to remove its
@@ -1122,9 +1136,6 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
 
 static void client_get_all(ObClient *self, gboolean real)
 {
-    /* this is needed for the frame to set itself up */
-    client_get_area(self);
-
     /* these things can change the decor and functions of the window */
 
     client_get_mwm_hints(self);
@@ -1193,13 +1204,12 @@ static void client_get_startup_id(ObClient *self)
                           NET_STARTUP_ID, utf8, &self->startup_id);
 }
 
-static void client_get_area(ObClient *self)
+static gboolean client_get_area(ObClient *self)
 {
     XWindowAttributes wattrib;
-    Status ret;
 
-    ret = XGetWindowAttributes(obt_display, self->window, &wattrib);
-    g_assert(ret != BadWindow);
+    if (!XGetWindowAttributes(obt_display, self->window, &wattrib))
+        return FALSE;
 
     RECT_SET(self->area, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
     POINT_SET(self->root_pos, wattrib.x, wattrib.y);
@@ -1207,6 +1217,7 @@ static void client_get_area(ObClient *self)
 
     ob_debug("client area: %d,%d  %dx%d  bw %d", wattrib.x, wattrib.y,
              wattrib.width, wattrib.height, wattrib.border_width);
+    return TRUE;
 }
 
 static void client_get_desktop(ObClient *self)
index 6161b5a25c7c0badb5d77e03bc8c711326bd26ac..25a6b282d075085ead88dbca1374dbb90bc60b64 100644 (file)
@@ -60,13 +60,13 @@ static void composite_window_redir(struct _ObWindow *w);
 /*! Turn composite redirection off for a window */
 static void composite_window_unredir(struct _ObWindow *w);
 
-static GLXContext composite_ctx = NULL;
+static GLXContext          composite_ctx = NULL;
 static ObCompositeFBConfig pixmap_config[MAX_DEPTH + 1]; /* depth is index */
-static gboolean composite_enabled = FALSE;
-static guint composite_idle_source = 0;
-static gboolean need_redraw = FALSE;
-static gboolean animating = FALSE;
-static Window composite_support_win = None;
+static gboolean            composite_enabled = FALSE;
+static guint               composite_idle_source = 0;
+static gboolean            need_redraw = FALSE;
+static gboolean            animating = FALSE;
+static Window              composite_support_win = None;
 #ifdef DEBUG
 static gboolean composite_started = FALSE;
 #endif
@@ -169,7 +169,7 @@ static gboolean composite_annex(void)
     g_assert(composite_support_win == None);
 
     attrib.override_redirect = TRUE;
-    composite_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
+    composite_support_win = XCreateWindow(obt_display, screen_support_win,
                                           -100, -100, 1, 1, 0,
                                           CopyFromParent, InputOnly,
                                           CopyFromParent,
@@ -181,14 +181,22 @@ static gboolean composite_annex(void)
     g_free(astr);
 
     cm_owner = XGetSelectionOwner(obt_display, composite_cm_atom);
-    if (cm_owner != None) return FALSE;
+    if (cm_owner != None) {
+        XDestroyWindow(obt_display, composite_support_win);
+        composite_support_win = None;
+        return FALSE;
+    }
 
     timestamp = event_time();
     XSetSelectionOwner(obt_display, composite_cm_atom, composite_support_win,
                        timestamp);
 
     cm_owner = XGetSelectionOwner(obt_display, composite_cm_atom);
-    if (cm_owner != composite_support_win) return FALSE;
+    if (cm_owner != composite_support_win) {
+        XDestroyWindow(obt_display, composite_support_win);
+        composite_support_win = None;
+        return FALSE;
+    }
 
     /* Send client message indicating that we are now the CM */
     obt_prop_message(ob_screen, obt_root(ob_screen), OBT_PROP_ATOM(MANAGER),
@@ -440,9 +448,9 @@ void composite_resize(void)
 static gboolean composite(gpointer data)
 {
     struct timeval start, end, dif;
-    GList *it;
     ObWindow *win;
     ObClient *client;
+    ObStackingIter *it;
 
     if (!composite_enabled) {
         composite_idle_source = 0;
@@ -457,14 +465,10 @@ static gboolean composite(gpointer data)
 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-/* XXX for (it = stacking_list_last; it; it = g_list_previous(it)) { */
-    for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
+    it = stacking_iter_tail();
+    for (; (win = stacking_iter_win(it)); stacking_iter_prev(it)) {
         gint d, x, y, w, h;
 
-        win = it->data;
-        if (win->type == OB_WINDOW_CLASS_PROMPT)
-            continue;
-
         if (!win->mapped || !win->is_redir)
             continue;
 
@@ -644,6 +648,7 @@ static gboolean composite(gpointer data)
         if (obt_display_error_occured)
             g_assert(0 && "ERROR RELEASING GLX PIXMAP");
     }
+    stacking_iter_free(it);
 
     glXSwapBuffers(obt_display, composite_overlay);
     glFinish();
index 18fe0058c496da33ffeaabd14e4009757634409c..1781b505b31403e16c480aab7e2da83ef38535b4 100644 (file)
@@ -142,7 +142,7 @@ void dock_shutdown(gboolean reconfig)
     XDestroyWindow(obt_display, dock->frame);
     RrAppearanceFree(dock->a_frame);
     window_remove(dock->frame);
-    stacking_remove(dock);
+    stacking_remove(DOCK_AS_WINDOW(dock));
     window_free(DOCK_AS_WINDOW(dock));
     dock = NULL;
 }
index 190113f598777820d51899782558d4dc83c0fd43..b9ed709c7311580a4185ea9029b3445afa7fbdc5 100644 (file)
@@ -85,7 +85,7 @@ typedef struct
 static void event_process(const XEvent *e, gpointer data);
 static void event_handle_root(XEvent *e);
 static gboolean event_handle_menu_input(XEvent *e);
-static gboolean event_handle_window(ObWindow *w, XEvent *e);
+static void event_handle_window(ObWindow *w, XEvent *e);
 static void event_handle_menu(ObMenuFrame *frame, XEvent *e);
 static gboolean event_handle_prompt(ObPrompt *p, XEvent *e);
 static void event_handle_dock(ObDock *s, XEvent *e);
@@ -521,6 +521,8 @@ static void event_process(const XEvent *ec, gpointer data)
 
     /* deal with it in the kernel */
 
+    if (obwin) event_handle_window(obwin, e);
+
     if (e->type == FocusIn) {
         print_focusevent(e);
         if (!wanted_focusevent(e, FALSE)) {
@@ -656,8 +658,6 @@ static void event_process(const XEvent *ec, gpointer data)
     {
         obwin = UNMANAGED_AS_WINDOW(unmanaged_new(e->xreparent.window));
     }
-    else if (obwin && event_handle_window(obwin, e))
-        /* handled it ! */;
     else if (client)
         event_handle_client(client, e);
     else if (um)
@@ -1756,12 +1756,12 @@ static void event_handle_dock(ObDock *s, XEvent *e)
     }
 }
 
-static gboolean event_handle_window(ObWindow *wi, XEvent *e)
+static void event_handle_window(ObWindow *wi, XEvent *e)
 {
-    gboolean used = FALSE, pixchange = FALSE;
+    gboolean pixchange = FALSE;
     gboolean same_window;
 
-    if (wi->type == OB_WINDOW_CLASS_PROMPT) return used;
+    if (wi->type == OB_WINDOW_CLASS_PROMPT) return;
 
     switch (e->type) {
     case ConfigureNotify:
@@ -1807,7 +1807,6 @@ static gboolean event_handle_window(ObWindow *wi, XEvent *e)
                 h = xe->height;
             }
             RECT_SET(wi->area, x, y, w, h);
-            used = TRUE;
         }
 
         /* set the top window's area/border */
@@ -1815,8 +1814,8 @@ static gboolean event_handle_window(ObWindow *wi, XEvent *e)
             XConfigureEvent const *xe = &e->xconfigure;
             RECT_SET(wi->toparea, xe->x, xe->y, xe->width, xe->height);
             wi->topborder = xe->border_width;
-            used = TRUE;
         }
+
         break;
 
     case MapNotify:
@@ -1824,14 +1823,12 @@ static gboolean event_handle_window(ObWindow *wi, XEvent *e)
         if (e->xmap.window == window_redir(wi)) {
             wi->mapped = TRUE;
             pixchange = TRUE;
-            used = TRUE;
         }
         break;
     case UnmapNotify:
         composite_dirty();
         if (e->xunmap.window == window_top(wi)) {
             wi->mapped = FALSE;
-            used = TRUE;
         }
         break;
     default:
@@ -1844,7 +1841,6 @@ static gboolean event_handle_window(ObWindow *wi, XEvent *e)
             composite_dirty();
             if (s->window == window_redir(wi) && s->kind == ShapeBounding) {
                 window_adjust_redir_shape(wi);
-                used = FALSE; /* let other people get this event also */
             }
         }
 #endif
@@ -1853,13 +1849,11 @@ static gboolean event_handle_window(ObWindow *wi, XEvent *e)
         {
             XDamageNotifyEvent *ev = (XDamageNotifyEvent *)e;
             composite_dirty();
-            used = TRUE;
         }
 #endif
     }
     if (pixchange)
         composite_window_invalid(wi);
-    return used;
 }
 
 static void event_handle_unmanaged(ObUnmanaged *um, XEvent *e)
@@ -1905,6 +1899,9 @@ static void event_handle_unmanaged(ObUnmanaged *um, XEvent *e)
                          e->xconfigurerequest.value_mask, &xwc);
         obt_display_ignore_errors(FALSE);
         break;
+    case ConfigureNotify:
+        /* XXX check if above changed */
+        stacking_unmanaged_above_notify(um, e->xconfigure.above);
     }
 }
 
index dd152386d78c3e4e964d9cd55ac8d37cb57e53af..7605db629e7ce27f07feb082e9209c7873990559 100644 (file)
@@ -35,6 +35,7 @@
 #include "frame.h"
 #include "framerender.h"
 #include "keyboard.h"
+#include "stacking.h"
 #include "mouse.h"
 #include "menuframe.h"
 #include "grab.h"
@@ -303,6 +304,7 @@ gint main(gint argc, gchar **argv)
             /* focus_backup is used for stacking, so this needs to come before
                anything that calls stacking_add */
             sn_startup(reconfigure);
+            stacking_startup(reconfigure);
             window_startup(reconfigure);
             composite_startup(reconfigure);
             focus_startup(reconfigure);
@@ -413,6 +415,7 @@ gint main(gint argc, gchar **argv)
             focus_shutdown(reconfigure);
             composite_shutdown(reconfigure);
             window_shutdown(reconfigure);
+            stacking_shutdown(reconfigure);
             sn_shutdown(reconfigure);
             event_shutdown(reconfigure);
             config_shutdown();
index cef6ab0790f35dcd49b4daa3beb7cbdea3eb7c72..ff647fe505467b9a863a42e4dcd701a24586b1a2 100644 (file)
@@ -84,7 +84,7 @@ void popup_free(ObPopup *self)
         RrAppearanceFree(self->a_bg);
         RrAppearanceFree(self->a_text);
         window_remove(self->bg);
-        stacking_remove(self);
+        stacking_remove(INTERNAL_AS_WINDOW(self));
         window_free(INTERNAL_AS_WINDOW(self));
     }
 }
index 8dbc4c01efe2612f558d80153dc168a56d527bee..8326a72e410a41a81fa6802066cd142a734b88b0 100644 (file)
@@ -70,6 +70,7 @@ Window          screen_support_win;
 Time            screen_desktop_user_time = CurrentTime;
 Atom            screen_wm_sn_atom = None;
 
+static ObInternalWindow *screen_support_obwin;
 static Size     screen_physical_size;
 static guint    screen_old_desktop;
 static gboolean screen_desktop_timeout = TRUE;
@@ -170,14 +171,15 @@ gboolean screen_annex(void)
     pid_t pid;
     gint i, num_support;
     gulong *supported;
+    const Rect r = {-100, -100, 1, 1};
+    const gint b = 0;
 
     /* create the netwm support window */
     attrib.override_redirect = TRUE;
     attrib.event_mask = PropertyChangeMask;
     screen_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
-                                       -100, -100, 1, 1, 0,
-                                       CopyFromParent, InputOnly,
-                                       CopyFromParent,
+                                       r.x, r.y, r.width, r.height, b, 0,
+                                       InputOnly, CopyFromParent,
                                        CWEventMask | CWOverrideRedirect,
                                        &attrib);
     XMapWindow(obt_display, screen_support_win);
@@ -199,6 +201,10 @@ gboolean screen_annex(void)
         return FALSE;
     }
 
+    screen_support_obwin = window_internal_new(screen_support_win, &r, b, 0);
+    screen_support_obwin->layer = OB_STACKING_LAYER_TOPMOST;
+    stacking_set_topmost(INTERNAL_AS_WINDOW(screen_support_obwin));
+
     screen_set_root_cursor();
 
     /* set the OPENBOX_PID hint */
@@ -477,6 +483,8 @@ void screen_shutdown(gboolean reconfig)
     OBT_PROP_ERASE(obt_root(ob_screen), NET_SHOWING_DESKTOP);
 
     XDestroyWindow(obt_display, screen_support_win);
+    stacking_remove(INTERNAL_AS_WINDOW(screen_support_obwin));
+    window_free(INTERNAL_AS_WINDOW(screen_support_obwin));
 
     g_strfreev(screen_desktop_names);
     screen_desktop_names = NULL;
index 7c8f216edcce0ac616449a8dbcc156248107c5dd..8b478f23b98e94b79354e8525694c853c5dbb871 100644 (file)
 #include "frame.h"
 #include "window.h"
 #include "event.h"
+#include "unmanaged.h"
 #include "debug.h"
 #include "obt/prop.h"
 
+/*! A node holding an unmanaged window for the secondary list stacking_ulist */
+typedef struct _ObUNode {
+    ObUnmanaged *um;
+    /*! Points to the node in stacking_list which is the highest window in
+      the list below this window */
+    GList *belowme;
+} ObUNode;
+
+/* A list of managed ObWindow*s in stacking order from highest to lowest */
 GList  *stacking_list = NULL;
-GList  *stacking_list_tail = NULL;
+/*! A list of unmanaged windows in OBUNode objects in stacking order from
+  highest to lowest */
+GList  *stacking_ulist = NULL;
+
+static GHashTable *stacking_map = NULL;
+static GHashTable *stacking_umap = 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 */
 static gboolean pause_changes = FALSE;
 
+static void list_split(GList **l1, GList **l2)
+{
+    if (*l1 == *l2) *l2 = NULL;
+    else if (*l2) {
+        if ((*l2)->prev) (*l2)->prev->next = NULL;
+        (*l2)->prev = NULL;
+    }
+}
+
+static GList* list_insert_link_before(GList *list, GList *before, GList *link)
+{
+    /* split the list at 'before' */
+    if (before) {
+        if (before->prev) before->prev->next = NULL;
+        before->prev = NULL;
+        /* and stick it at the front of the 'before' list */
+        link = g_list_concat(link, before);
+        /* if before is the whole list, then we have replaced the list */
+        if (before == list) list = NULL;
+    }
+    /* append the node and the rest of the list back onto the original list */
+    return g_list_concat(list, link);
+}
+
+void stacking_startup(gboolean reconfig)
+{
+    if (reconfig) return;
+    stacking_map = g_hash_table_new(g_int_hash, g_int_equal);
+    stacking_umap = g_hash_table_new(g_int_hash, g_int_equal);
+}
+
+void stacking_shutdown(gboolean reconfig)
+{
+    if (reconfig) return;
+    g_hash_table_destroy(stacking_map);
+    stacking_map = NULL;
+    g_hash_table_destroy(stacking_umap);
+    stacking_umap = NULL;
+}
+
+void stacking_set_topmost(ObWindow *win)
+{
+    g_assert(win && stacking_list == NULL);
+    g_assert(WINDOW_IS_INTERNAL(win));
+    g_assert(window_layer(win) == OB_STACKING_LAYER_TOPMOST);
+    stacking_list = g_list_prepend(stacking_list, win);
+}
+
 void stacking_set_list(void)
 {
     Window *windows = NULL;
@@ -74,11 +137,9 @@ static void do_restack(GList *wins, GList *before)
     g_assert(wins);
     /* pls only restack stuff in the same layer at a time */
     for (it = wins; it; it = next) {
-        while (it && window_layer(it->data) == OB_STACKING_LAYER_ALL)
-            it = g_list_next(it);
         next = g_list_next(it);
-        while (next && window_layer(next->data) == OB_STACKING_LAYER_ALL)
-            next = g_list_next(next);
+        /* and there should be no unmanaged windows in the stacking_list */
+        g_assert(!WINDOW_IS_UNMANAGED(it->data));
         if (!next) break;
         g_assert (window_layer(it->data) == window_layer(next->data));
     }
@@ -88,28 +149,27 @@ static void do_restack(GList *wins, GList *before)
 
     win = g_new(Window, g_list_length(wins) + 1);
 
-    if (before == stacking_list)
-        win[0] = screen_support_win;
-    else if (!before)
+    g_assert(before != stacking_list);
+
+    if (!before)
         win[0] = window_top(g_list_last(stacking_list)->data);
     else
         win[0] = window_top(g_list_previous(before)->data);
 
     for (i = 1, it = wins; it; ++i, it = g_list_next(it)) {
         win[i] = window_top(it->data);
-        g_assert(win[i] != None); /* better not call stacking shit before
-                                     setting your top level window value */
-        stacking_list = g_list_insert_before(stacking_list, before, it->data);
+        /* don't call stacking shit before setting your top level window */
+        g_assert(win[i] != None);
     }
 
+    list_split(&stacking_list, &before);
+    stacking_list = g_list_concat(stacking_list, g_list_concat(wins, before));
+
 #ifdef DEBUG
     /* some debug checking of the stacking list's order */
     for (it = stacking_list; ; it = next) {
-        while (it && window_layer(it->data) == OB_STACKING_LAYER_ALL)
-            it = g_list_next(it);
         next = g_list_next(it);
-        while (next && window_layer(next->data) == OB_STACKING_LAYER_ALL)
-            next = g_list_next(next);
+        g_assert(window_layer(it->data) != OB_STACKING_LAYER_INVALID);
         if (!next) break;
         g_assert(window_layer(it->data) >= window_layer(next->data));
     }
@@ -157,8 +217,7 @@ void stacking_restore(void)
     gulong start;
 
     win = g_new(Window, g_list_length(stacking_list) + 1);
-    win[0] = screen_support_win;
-    for (i = 1, it = stacking_list; it; ++i, it = g_list_next(it))
+    for (i = 0, it = stacking_list; it; ++i, it = g_list_next(it))
         win[i] = window_top(it->data);
     start = event_start_ignore_all_enters();
     XRestackWindows(obt_display, win, i);
@@ -170,15 +229,16 @@ void stacking_restore(void)
 
 static void do_raise(GList *wins)
 {
-    GList *it;
+    GList *it, *next;
     GList *layer[OB_NUM_STACKING_LAYERS] = {NULL};
     gint i;
 
-    for (it = wins; it; it = g_list_next(it)) {
-        ObStackingLayer l;
+    for (it = wins; it; it = next) {
+        const ObStackingLayer l = window_layer(it->data);
 
-        l = window_layer(it->data);
-        layer[l] = g_list_append(layer[l], it->data);
+        next = g_list_next(it);
+        wins = g_list_remove_link(wins, it); /* remove it from wins */
+        layer[l] = g_list_concat(layer[l], it); /* stick it in the layer */
     }
 
     it = stacking_list;
@@ -190,22 +250,22 @@ static void do_raise(GList *wins)
                     break;
             }
             do_restack(layer[i], it);
-            g_list_free(layer[i]);
         }
     }
 }
 
 static void do_lower(GList *wins)
 {
-    GList *it;
+    GList *it, *next;
     GList *layer[OB_NUM_STACKING_LAYERS] = {NULL};
     gint i;
 
-    for (it = wins; it; it = g_list_next(it)) {
-        ObStackingLayer l;
+    for (it = wins; it; it = next) {
+        const ObStackingLayer l = window_layer(it->data);
 
-        l = window_layer(it->data);
-        layer[l] = g_list_append(layer[l], it->data);
+        next = g_list_next(it);
+        wins = g_list_remove_link(wins, it); /* remove it from wins */
+        layer[l] = g_list_concat(layer[l], it); /* stick it in the layer */
     }
 
     it = stacking_list;
@@ -217,14 +277,13 @@ static void do_lower(GList *wins)
                     break;
             }
             do_restack(layer[i], it);
-            g_list_free(layer[i]);
         }
     }
 }
 
 static void restack_windows(ObClient *selected, gboolean raise)
 {
-    GList *it, *last, *below, *above, *next;
+    GList *it, *last, *below, *above, *next, *selit;
     GList *wins = NULL;
 
     GList *group_helpers = NULL;
@@ -243,9 +302,9 @@ static void restack_windows(ObClient *selected, gboolean raise)
     }
 
     /* remove first so we can't run into ourself */
-    it = g_list_find(stacking_list, selected);
-    g_assert(it);
-    stacking_list = g_list_delete_link(stacking_list, it);
+    selit = g_list_find(stacking_list, selected);
+    g_assert(selit);
+    stacking_list = g_list_remove_link(stacking_list, selit);
 
     /* go from the bottom of the stacking list up. don't move any other windows
        when lowering, we call this for each window independently */
@@ -255,6 +314,7 @@ static void restack_windows(ObClient *selected, gboolean raise)
 
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *ch = it->data;
+                GList **addto = NULL;
 
                 /* only move windows in the same stacking layer */
                 if (ch->layer == selected->layer &&
@@ -264,24 +324,28 @@ static void restack_windows(ObClient *selected, gboolean raise)
                 {
                     if (client_is_direct_child(selected, ch)) {
                         if (ch->modal)
-                            modals = g_list_prepend(modals, ch);
+                            addto = &modals;
                         else
-                            trans = g_list_prepend(trans, ch);
+                            addto = &trans;
                     }
                     else if (client_helper(ch)) {
                         if (selected->transient) {
                             /* helpers do not stay above transient windows */
                             continue;
                         }
-                        group_helpers = g_list_prepend(group_helpers, ch);
+                        addto = &group_helpers;
                     }
                     else {
                         if (ch->modal)
-                            group_modals = g_list_prepend(group_modals, ch);
+                            addto = &group_modals;
                         else
-                            group_trans = g_list_prepend(group_trans, ch);
+                            addto = &group_trans;
                     }
-                    stacking_list = g_list_delete_link(stacking_list, it);
+                    g_assert(addto != NULL);
+                    /* move it from the stacking list onto the front of the
+                       list pointed at by addto */
+                    stacking_list = g_list_remove_link(stacking_list, it);
+                    *addto = g_list_concat(it, *addto);
                 }
             }
         }
@@ -294,7 +358,7 @@ static void restack_windows(ObClient *selected, gboolean raise)
     wins = g_list_concat(wins, group_helpers);
 
     /* put the selected window right below these children */
-    wins = g_list_append(wins, selected);
+    wins = g_list_concat(wins, selit);
 
     /* if selected window is transient for group then raise it above others */
     if (selected->transient_for_group) {
@@ -375,7 +439,6 @@ static void restack_windows(ObClient *selected, gboolean raise)
     wins = g_list_concat(group_modals, wins);
 
     do_restack(wins, below);
-    g_list_free(wins);
 
     /* lower our parents after us, so they go below us */
     if (!raise && selected->parents) {
@@ -406,13 +469,10 @@ void stacking_raise(ObWindow *window)
         selected = WINDOW_AS_CLIENT(window);
         restack_windows(selected, TRUE);
     } else {
-        GList *wins;
-        wins = g_list_append(NULL, window);
-        stacking_list = g_list_remove(stacking_list, window);
-        do_raise(wins);
-        g_list_free(wins);
+        GList *selit = g_list_find(stacking_list, window);
+        stacking_list = g_list_remove_link(stacking_list, selit);
+        do_raise(selit);
     }
-    stacking_list_tail = g_list_last(stacking_list);
 }
 
 void stacking_lower(ObWindow *window)
@@ -422,43 +482,65 @@ void stacking_lower(ObWindow *window)
         selected = WINDOW_AS_CLIENT(window);
         restack_windows(selected, FALSE);
     } else {
-        GList *wins;
-        wins = g_list_append(NULL, window);
-        stacking_list = g_list_remove(stacking_list, window);
-        do_lower(wins);
-        g_list_free(wins);
+        GList *selit = g_list_find(stacking_list, window);
+        stacking_list = g_list_remove_link(stacking_list, selit);
+        do_lower(selit);
     }
-    stacking_list_tail = g_list_last(stacking_list);
 }
 
 void stacking_below(ObWindow *window, ObWindow *below)
 {
-    GList *wins, *before;
+    GList *selit, *before;
 
     if (window_layer(window) != window_layer(below))
         return;
 
-    wins = g_list_append(NULL, window);
-    stacking_list = g_list_remove(stacking_list, window);
+    selit = g_list_find(stacking_list, window);
+    stacking_list = g_list_remove_link(stacking_list, selit);
     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);
+    do_restack(selit, before);
 }
 
 void stacking_add(ObWindow *win)
 {
-    g_assert(screen_support_win != None); /* make sure I dont break this in the
-                                             future */
+    /* the topmost window should already be present */
+    g_assert(stacking_list != NULL);
+
     /* don't add windows that are being unmanaged ! */
     if (WINDOW_IS_CLIENT(win)) g_assert(WINDOW_AS_CLIENT(win)->managed);
 
-    if (WINDOW_IS_UNMANAGED(win))
-        stacking_list = g_list_prepend(stacking_list, win);
+    if (WINDOW_IS_UNMANAGED(win)) {
+        ObUNode *n = g_slice_new(ObUNode);
+        n->um = WINDOW_AS_UNMANAGED(win);
+        n->belowme = stacking_list;
+        stacking_ulist = g_list_prepend(stacking_ulist, n);
+        g_hash_table_insert(stacking_umap, &window_top(win), stacking_ulist);
+    }
     else {
-        stacking_list = g_list_append(stacking_list, win);
+        GList *newit = g_list_append(NULL, win);
+        stacking_list = g_list_concat(stacking_list, newit);
         stacking_raise(win);
-        /* stacking_list_tail set by stacking_raise() */
+        g_hash_table_insert(stacking_map, &window_top(win), newit);
+    }
+}
+
+void stacking_remove(ObWindow *win)
+{
+    if (WINDOW_IS_UNMANAGED(win)) {
+        GList *it;
+        for (it = stacking_ulist; it; it = g_list_next(it)) {
+            ObUNode *n = it->data;
+            if (n->um == WINDOW_AS_UNMANAGED(win)) {
+                stacking_ulist = g_list_delete_link(stacking_ulist, it);
+                g_slice_free(ObUNode, n);
+                break;
+            }
+        }
+        g_hash_table_remove(stacking_umap, &window_top(win));
+    }
+    else {
+        stacking_list = g_list_remove(stacking_list, win);
+        g_hash_table_remove(stacking_map, &window_top(win));
     }
 }
 
@@ -508,7 +590,7 @@ void stacking_add_nonintrusive(ObWindow *win)
     ObClient *client;
     GList *it_below = NULL; /* this client will be below us */
     GList *it_above;
-    GList *wins;
+    GList *newit;
 
     if (!WINDOW_IS_CLIENT(win)) {
         stacking_add(win); /* no special rules for others */
@@ -569,10 +651,9 @@ void stacking_add_nonintrusive(ObWindow *win)
             break;
     }
 
-    wins = g_list_append(NULL, win);
-    do_restack(wins, it_below);
-    g_list_free(wins);
-    stacking_list_tail = g_list_last(stacking_list);
+    newit = g_list_append(NULL, win);
+    do_restack(newit, it_below);
+    g_hash_table_insert(stacking_map, &window_top(win), newit);
 }
 
 /*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
@@ -724,3 +805,161 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling,
     }
     return ret;
 }
+
+void stacking_unmanaged_above_notify(ObUnmanaged *win, Window above)
+{
+    GList *aboveit, *winit, *uit, *mit;
+    ObUNode *un, *an;
+
+    g_assert(WINDOW_IS_UNMANAGED(win));
+
+    winit = g_hash_table_lookup(stacking_umap, &window_top(win));
+
+    if (!above) {
+        /* at the very bottom of the stacking order */
+        stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+        stacking_ulist = list_insert_link_before(stacking_ulist, NULL, winit);
+        un = winit->data;
+        un->belowme = NULL;
+    }
+    else if ((aboveit = g_hash_table_lookup(stacking_map, &above))) {
+        /* directly above a managed window, so put it at the bottom of
+           any siblings which are also above it */
+
+        stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+        un = winit->data;
+        un->belowme = aboveit;
+
+        /* go through the managed windows in the stacking list from top to
+           bottom.
+           follow along in the list of unmanaged windows, until we come to the
+           managed window @winit is now above.  then keep moving through the
+           unmanaged windows until we find something above a different
+           managed window, and insert @winit into the unmanaged list before it.
+        */
+        mit = stacking_list;
+        uit = stacking_ulist;
+        for (; mit; mit = g_list_next(mit)) {
+            /* skip thru the unmanged windows above 'mit' */
+            while (uit && ((ObUNode*)uit->data)->belowme == mit)
+                uit = g_list_next(uit);
+            if (mit == aboveit) {
+                /* @win is above 'mit', so stick it in the unmanaged list
+                   before 'uit' (the first window above something lower in the
+                   managed stacking list */
+                stacking_ulist = list_insert_link_before(stacking_ulist,
+                                                         uit, winit);
+                break; /* done */
+            }
+        }
+    }
+    else if ((aboveit = g_hash_table_lookup(stacking_umap, &above))) {
+        /* directly above another unmanaged window, put it in that position
+           in the stacking_ulist */
+
+        stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+        stacking_ulist = list_insert_link_before(stacking_ulist,
+                                                 aboveit, winit);
+        /* we share the same neighbour in stacking_list */
+        un = winit->data;
+        an = aboveit->data;
+        un->belowme = an->belowme;
+    }
+}
+
+struct _ObStackingIter {
+    GList *mit, *uit, *mitprev, *uitprev;
+};
+
+ObStackingIter* stacking_iter_head(void)
+{
+    ObStackingIter *it = g_slice_new(ObStackingIter);
+    it->mit = stacking_list;
+    it->mitprev = NULL;
+    it->uit = stacking_ulist;
+    it->uitprev = NULL;
+    return it;
+}
+
+ObStackingIter* stacking_iter_tail(void)
+{
+    ObStackingIter *it = g_slice_new(ObStackingIter);
+    it->uit = g_list_last(stacking_ulist);
+    if (it->uit && ((ObUNode*)it->uit->data)->belowme == NULL) {
+        /* it is below all managed windows */
+        it->uitprev = g_list_previous(it->uit);
+        it->mit = NULL;
+        it->mitprev = g_list_last(stacking_list);
+    }
+    else {
+        /* it is above some managed window */
+        it->uitprev = it->uit;
+        it->uit = NULL;
+        it->mit = g_list_last(stacking_list);
+        it->mitprev = it->mit ? g_list_previous(it->mit) : NULL;
+    }
+    return it;
+}
+
+/*! Returns 1 if it->mit is the current, and 2 if it->uit is. */
+static gint stacking_iter_current(ObStackingIter *it)
+{
+    if (!it->uit)
+        return 1;
+    else {
+        ObUNode *un = it->uit->data;
+        if (un->belowme == it->mit) return 2;
+        else return 1;
+    }
+}
+
+void stacking_iter_next(ObStackingIter *it)
+{
+    g_assert(it->mit || it->uit); /* went past the end of the list */
+
+    if (!it->uit) it->mit = g_list_next(it->mit);
+    else {
+        gint at = stacking_iter_current(it);
+        if (at == 1) {
+            it->mitprev = it->mit;
+            it->mit = g_list_next(it->mit);
+        }
+        else {
+            it->uitprev = it->uit;
+            it->uit = g_list_next(it->uit);
+        }
+    }
+}
+
+void stacking_iter_prev(ObStackingIter *it)
+{
+    g_assert(it->mit || it->uit); /* went past the end of the list */
+
+    /* if the prev unmanged points at the managed, it should be the
+       previous position */
+    if (it->uitprev && ((ObUNode*)it->uitprev->data)->belowme == it->mit) {
+        it->uit = it->uitprev;
+        it->uitprev = g_list_previous(it->uitprev);
+    }
+    else {
+        it->mit = it->mitprev;
+        if (it->mitprev) it->mitprev = g_list_previous(it->mitprev);
+        if (!it->mit) it->uit = NULL;
+    }
+}
+
+ObWindow* stacking_iter_win(ObStackingIter *it)
+{
+    gint at;
+
+    if (!it->mit && !it->uit) return NULL;
+
+    at = stacking_iter_current(it);
+    if (at == 1) return it->mit->data; /* list of ObWindow */
+    else return UNMANAGED_AS_WINDOW(((ObUNode*)it->uit->data)->um);
+}
+
+void stacking_iter_free(ObStackingIter *it)
+{
+    g_slice_free(ObStackingIter, it);
+}
index be247f346eaac303a9be8902fe29961c21777107..1577d944a9119514fbe159c115f12f6c642de04a 100644 (file)
 
 struct _ObWindow;
 struct _ObClient;
+struct _ObUnmanaged;
+
+typedef struct _ObStackingIter ObStackingIter;
 
 /*! The possible stacking layers a client window can be a part of */
 typedef enum {
     OB_STACKING_LAYER_INVALID,
-    OB_STACKING_LAYER_DESKTOP,          /*!< 0 - desktop windows */
-    OB_STACKING_LAYER_BELOW,            /*!< 1 - normal windows w/ below */
-    OB_STACKING_LAYER_NORMAL,           /*!< 2 - normal windows */
-    OB_STACKING_LAYER_ABOVE,            /*!< 3 - normal windows w/ above */
-    OB_STACKING_LAYER_FULLSCREEN,       /*!< 4 - fullscreeen windows */
-    OB_STACKING_LAYER_INTERNAL,         /*!< 5 - openbox windows/menus */
+    OB_STACKING_LAYER_DESKTOP,          /*!< 1 - desktop windows */
+    OB_STACKING_LAYER_BELOW,            /*!< 2 - normal windows w/ below */
+    OB_STACKING_LAYER_NORMAL,           /*!< 3 - normal windows */
+    OB_STACKING_LAYER_ABOVE,            /*!< 4 - normal windows w/ above */
+    OB_STACKING_LAYER_FULLSCREEN,       /*!< 5 - fullscreeen windows */
+    OB_STACKING_LAYER_INTERNAL,         /*!< 6 - openbox windows/menus */
+    OB_STACKING_LAYER_TOPMOST,          /*!< 7 - topmost window */
     OB_NUM_STACKING_LAYERS,
-    OB_STACKING_LAYER_ALL = 0xffffffff  /*!< 0xffffffff - unmamnaged windows */
 } ObStackingLayer;
 
-/* list of ObWindow*s in stacking order from highest to lowest */
 extern GList *stacking_list;
 /* list of ObWindow*s in stacking order from lowest to highest */
 extern GList *stacking_list_tail;
 
+void stacking_startup(gboolean reconfig);
+void stacking_shutdown(gboolean reconfig);
+
+void stacking_set_topmost(struct _ObWindow *win);
+
 /*! Sets the window stacking list on the root window from the
   stacking_list */
 void stacking_set_list(void);
 
 void stacking_add(struct _ObWindow *win);
 void stacking_add_nonintrusive(struct _ObWindow *win);
-#define stacking_remove(win) stacking_list = g_list_remove(stacking_list, win);
+void stacking_remove(struct _ObWindow *win);
 
 /*! Raises a window above all others in its stacking layer */
 void stacking_raise(struct _ObWindow *window);
@@ -83,4 +90,13 @@ gboolean stacking_restack_request(struct _ObClient *client,
                                   struct _ObClient *sibling,
                                   gint detail);
 
+void stacking_unmanaged_above_notify(struct _ObUnmanaged *win, Window above);
+
+ObStackingIter* stacking_iter_head(void);
+ObStackingIter* stacking_iter_tail(void);
+void stacking_iter_next(ObStackingIter *it);
+void stacking_iter_prev(ObStackingIter *it);
+struct _ObWindow* stacking_iter_win(ObStackingIter *it);
+void stacking_iter_free(ObStackingIter *it);
+
 #endif
index 8675fc8196637c9e751f0efc268d0128fa0c43a5..a50be3c36720239bb28d7bf00c933888d9ad4dce 100644 (file)
@@ -28,6 +28,7 @@ struct _ObUnmanaged {
     ObStackingLayer layer;
     gint depth;
     guint32 alpha;
+    gboolean output;
 };
 
 static GSList *unmanaged_list = NULL;
@@ -41,28 +42,29 @@ ObUnmanaged* unmanaged_new(Window w)
     if (w == composite_overlay)
         return NULL;
     if (!XGetWindowAttributes(obt_display, w, &at))
-        return NULL;        
-    if (at.class == InputOnly)
         return NULL;
 
     self = window_new(OB_WINDOW_CLASS_UNMANAGED, ObUnmanaged);
     self->window = w;
-    self->layer = OB_STACKING_LAYER_ALL;
+    self->layer = OB_STACKING_LAYER_INVALID;
     self->depth = at.depth;
     self->alpha = 0xffffffff;
+    self->output = at.class != InputOnly;
+
+    self->super.mapped = at.map_state != IsUnmapped;
 
     XSelectInput(obt_display, self->window, PropertyChangeMask);
 #ifdef SHAPE
     XShapeSelectInput(obt_display, self->window, ShapeNotifyMask);
 #endif
 
-    unmanaged_update_opacity(self);
+    if (self->output) unmanaged_update_opacity(self);
 
     RECT_SET(r, at.x, at.y, at.width, at.height);
     window_set_top_area(UNMANAGED_AS_WINDOW(self), &r, at.border_width);
     window_set_abstract(UNMANAGED_AS_WINDOW(self),
                         &self->window,
-                        &self->window,
+                        (self->output ? &self->window : NULL),
                         &self->layer,
                         &self->depth,
                         &self->alpha);
index 33a0fd2ee61794cea740cd171d7219fe0399a099..97771d775ed262c0105af1fe8192384ba007f07a 100644 (file)
@@ -31,5 +31,6 @@ void unmanaged_destroy(ObUnmanaged *self);
 void unmanaged_destroy_all(void);
 
 void unmanaged_update_opacity(ObUnmanaged *self);
+gboolean unmanaged_output(ObUnmanaged *self);
 
 #endif
index db82e3f2ed96a33ae15ad9bbc72d857aa66aad79..b9f58310e878307d977e819389af2ddcefddf59d 100644 (file)
@@ -85,7 +85,7 @@ void window_set_abstract(ObWindow *self,
 
 #ifdef SHAPE
 #ifdef USE_COMPOSITING
-    {
+    if (window_redir(self)) {
         gint foo;
         guint ufoo;
         gint s;
@@ -98,7 +98,8 @@ void window_set_abstract(ObWindow *self,
 #endif
 #endif
 
-    composite_window_setup(self);
+    if (window_redir(self))
+        composite_window_setup(self);
 }
 
 void window_set_top_area(ObWindow *self, const Rect *r, gint border)
@@ -116,7 +117,8 @@ void window_set_top_area(ObWindow *self, const Rect *r, gint border)
 
 void window_cleanup(ObWindow *self)
 {
-    composite_window_cleanup(self);
+    if (window_redir(self))
+        composite_window_cleanup(self);
 }
 
 void window_free(ObWindow *self)
@@ -180,11 +182,11 @@ ObInternalWindow* window_internal_new(Window window, const Rect *area,
     self->depth = depth;
     window_set_top_area(INTERNAL_AS_WINDOW(self), area, border);
     window_set_abstract(INTERNAL_AS_WINDOW(self),
-                        &self->window, /* top-most window */
-                        &self->window, /* composite redir window */
-                        &self->layer,  /* stacking layer */
-                        &self->depth,  /* window depth */
-                        NULL);         /* opacity */
+                        &self->window,                  /* top-most window */
+                        (depth ? &self->window : NULL), /* comp redir window */
+                        &self->layer,                   /* stacking layer */
+                        &self->depth,                   /* window depth */
+                        NULL);                          /* opacity */
     return self;
 }
 
@@ -221,75 +223,44 @@ void window_manage_all(void)
     for (i = 0; i < nchild; ++i) {
         if (children[i] == None) continue;
         if (window_find(children[i])) continue; /* skip our own windows */
-        if (XGetWindowAttributes(obt_display, children[i], &attrib)) {
-            if (attrib.map_state == IsUnmapped)
-                unmanaged_new(children[i]);
-            else
-                window_manage(children[i]);
-        }
+        if (!XGetWindowAttributes(obt_display, children[i], &attrib)) continue;
+        if (attrib.map_state == IsUnmapped || attrib.override_redirect)
+            unmanaged_new(children[i]);
+        else
+            window_manage(children[i]);
     }
 
     if (children) XFree(children);
 }
 
-static gboolean check_unmap(XEvent *e, gpointer data)
-{
-    const Window win = *(Window*)data;
-    return ((e->type == DestroyNotify && e->xdestroywindow.window == win) ||
-            (e->type == UnmapNotify && e->xunmap.window == win));
-}
-
 void window_manage(Window win)
 {
-    XWindowAttributes attrib;
-    gboolean no_manage = FALSE;
     gboolean is_dockapp = FALSE;
     Window icon_win = None;
+    XWMHints *wmhints;
 
-    grab_server(TRUE);
-
-    /* check if it has already been unmapped by the time we started
-       mapping. the grab does a sync so we don't have to here */
-    if (xqueue_exists_local(check_unmap, &win)) {
-        ob_debug("Trying to manage unmapped window. Aborting that.");
-        no_manage = TRUE;
-    }
-    else if (!XGetWindowAttributes(obt_display, win, &attrib))
-        no_manage = TRUE;
-    else {
-        XWMHints *wmhints;
-
-        /* is the window a docking app */
-        is_dockapp = FALSE;
-        if ((wmhints = XGetWMHints(obt_display, win))) {
-            if ((wmhints->flags & StateHint) &&
-                wmhints->initial_state == WithdrawnState)
-            {
-                if (wmhints->flags & IconWindowHint)
-                    icon_win = wmhints->icon_window;
-                is_dockapp = TRUE;
-            }
-            XFree(wmhints);
+    /* is the window a docking app */
+    is_dockapp = FALSE;
+    if ((wmhints = XGetWMHints(obt_display, win))) {
+        if ((wmhints->flags & StateHint) &&
+            wmhints->initial_state == WithdrawnState)
+        {
+            if (wmhints->flags & IconWindowHint)
+                icon_win = wmhints->icon_window;
+            is_dockapp = TRUE;
         }
+        XFree(wmhints);
     }
 
-    if (!no_manage) {
-        if (attrib.override_redirect) {
-            ob_debug("not managing override redirect window 0x%x", win);
-            grab_server(FALSE);
-        }
-        else if (is_dockapp) {
-            if (!icon_win)
-                icon_win = win;
-            dock_manage(icon_win, win);
-        }
-        else
-            client_manage(win, NULL);
-    }
-    else {
-        grab_server(FALSE);
-        ob_debug("FAILED to manage window 0x%x", win);
+    grab_server(TRUE);
+
+    if (is_dockapp) {
+        if (!icon_win)
+            icon_win = win;
+        dock_manage(icon_win, win);
     }
+    else
+        client_manage(win, NULL);
 }
 
 void window_unmanage_all(void)
index 5ab014430f4b02c5863e579dcb225a7257253fc0..1e2883337552bc6726b45be918b51ec02be4236a 100644 (file)
@@ -144,7 +144,7 @@ typedef void (*ObWindowForeachFunc)(ObWindow *w);
 void      window_foreach(ObWindowForeachFunc func);
 
 #define window_top(w) (*((ObWindow*)w)->top)
-#define window_redir(w) (*((ObWindow*)w)->redir)
+#define window_redir(w) (((ObWindow*)w)->redir ? *((ObWindow*)w)->redir : None)
 #define window_layer(w) (*((ObWindow*)w)->layer)
 #define window_area(w) (*((ObWindow*)w)->area)
 #define window_depth(w) (*((ObWindow*)w)->depth)