make sure that when a window is shown it stops being a zombie
[dana/dcompmgr.git] / window.c
index cecae41..0662acf 100644 (file)
--- a/window.c
+++ b/window.c
@@ -11,6 +11,8 @@
 #include <xcb/composite.h>
 #include <xcb/damage.h>
 
+#define TOPLEVEL_WINDOW_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE)
+
 typedef struct {
     /* public stuff */
     xcb_window_t     id;
@@ -18,6 +20,7 @@ typedef struct {
 
     /* private stuff */
     int              ref;
+    int              zombieref;
 
     /* queried things, don't read them directly from the struct */
     int                 x, y, w, h, bw;
@@ -32,7 +35,10 @@ typedef struct {
        queries should go to this window */
     xcb_window_t        client;
 
-    double              opacity;
+    /* opacity is from 0xffff to 0, these 2 are combined to give the final
+       result */
+    uint16_t            opacity;      /* this one is set by plugins/settings */
+    uint16_t            user_opacity; /* this one is set by the user */
 
     gboolean            mapped;
     gboolean            zombie;
@@ -45,6 +51,8 @@ typedef struct {
     xcb_get_window_attributes_cookie_t ck_get_attr;
     gboolean waiting_geom;
     xcb_get_geometry_cookie_t          ck_get_geom;
+    gboolean waiting_opac;
+    xcb_get_property_cookie_t          ck_get_opac;
 } d_window_priv_t;
 
 static void window_get_attributes_reply(d_window_priv_t *w);
@@ -61,6 +69,7 @@ window_new(xcb_window_t id, struct d_screen *sc)
     w = malloc(sizeof(d_window_priv_t));
     w->id = id;
     w->ref = 1;
+    w->zombieref = 0;
     w->sc = sc;
     w->zombie = FALSE;
     w->mapped = FALSE;
@@ -68,6 +77,8 @@ window_new(xcb_window_t id, struct d_screen *sc)
     w->damage = XCB_NONE;
     w->region = XCB_NONE;
     w->type = DC_WINDOW_TYPE_INVALID;
+    w->opacity = 0xffff;
+    w->user_opacity = 0xffff;
 
     screen_stacking_add(sc, (d_window_t*)w);
 
@@ -100,17 +111,9 @@ window_unref(d_window_t *pubw)
     if (w && --w->ref == 0) {
         screen_stacking_remove(w->sc, (d_window_t*)w);
 
-        if (w->region) {
-            xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
-            w->region = XCB_NONE;
-        }
-
-        if (w->pixmap) {
-            /* this may cause an error if the pixmap was never valid, but
-               that's fine */
-            xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
-            w->pixmap = XCB_NONE;
-        }
+        assert(w->zombieref == 0);
+        while (w->zombieref)
+            window_zombie_unref(pubw);
 
         list_unref(w->plugin_data);
         free(w);
@@ -125,6 +128,18 @@ window_get_pixmap(d_window_t *pubw)
     return w->pixmap;
 }
 
+void
+window_update_user_opacity(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    w->ck_get_opac =
+        xcb_get_property(w->sc->dpy->conn, FALSE, w->id,
+                         w->sc->dpy->a.net_wm_window_opacity,
+                         w->sc->dpy->a.cardinal, 0, 1);
+    w->waiting_opac = TRUE;
+}
+
 static void
 window_update_region(d_window_priv_t *w)
 {
@@ -173,6 +188,7 @@ void
 window_show(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
+    unsigned int mask;
 
     assert(!w->mapped);
 
@@ -182,24 +198,41 @@ window_show(d_window_t *pubw)
     if (w->sc->dpy->shape.present)
         xcb_shape_select_input(w->sc->dpy->conn, w->id, TRUE);
 
+    mask = TOPLEVEL_WINDOW_EVENT_MASK;
+    xcb_change_window_attributes(w->sc->dpy->conn, w->id,
+                                 XCB_CW_EVENT_MASK, &mask);
+
+    assert(w->zombieref == 0);
+
     window_update_pixmap(w);
     window_update_region(w);
+    window_update_user_opacity(pubw);
     window_update_type(w);
     w->mapped = TRUE;
+
+    /* hold one reference for ourselves */
+    window_zombie_ref(pubw);
 }
 
 void
 window_hide(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
+    unsigned int mask;
 
     assert(w->mapped);
 
     //printf("hide window 0x%x\n", w->id);
     if (w->sc->dpy->shape.present)
         xcb_shape_select_input(w->sc->dpy->conn, w->id, FALSE);
+    mask = 0;
+    xcb_change_window_attributes(w->sc->dpy->conn, w->id,
+                                 XCB_CW_EVENT_MASK, &mask);
 
     w->mapped = FALSE;
+
+    /* try to free zombie things */
+    window_zombie_unref(pubw);
 }
 
 void
@@ -220,6 +253,16 @@ window_become_zombie(d_window_t *pubw)
     w->zombie = TRUE;
 }
 
+void
+window_zombie_dead(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    if (!w->zombie) return;
+
+    w->zombie = FALSE;
+}
+
 gboolean
 window_is_zombie(d_window_t *pubw)
 {
@@ -389,6 +432,11 @@ window_reshape(d_window_t *w)
     window_update_region((d_window_priv_t*)w);
 }
 
+void window_opacity_change(d_window_t *w)
+{
+    (void)w;
+}
+
 void
 window_add_plugin_data(d_window_t *pubw, int id, void *data)
 {
@@ -550,8 +598,7 @@ window_update_type(d_window_priv_t *w)
         w->type = DC_WINDOW_TYPE_NORMAL;
         w->client = w->id;
     }
-
-    printf("window 0x%x type %d\n", w->id, w->type);
+    //printf("window 0x%x type %d\n", w->id, w->type);
 }
 
 d_window_type_t
@@ -562,3 +609,77 @@ window_get_type(d_window_t *pubw)
     return w->type;
 }
 
+uint16_t
+window_get_opacity(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    unsigned long long l;
+
+    if (w->waiting_opac) {
+        xcb_get_property_reply_t *rep;
+
+        w->user_opacity = 0xffff;
+        rep = xcb_get_property_reply(w->sc->dpy->conn, w->ck_get_opac, NULL);
+        if (rep) {
+            if (rep->type == w->sc->dpy->a.cardinal && rep->length >= 1) {
+                l = ((uint32_t*)xcb_get_property_value(rep))[0];
+                l = 0xffff * l / 0xffffffff;
+                w->user_opacity = l;
+            }
+            free(rep);
+        }
+        w->waiting_opac = FALSE;
+    }
+
+    l = w->opacity;
+    l = l * w->user_opacity / 0xffff;
+    return l;
+}
+
+void
+window_set_opacity(d_window_t *pubw, uint16_t o)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    w->opacity = o;
+    if (w->mapped || w->zombie) {
+        w->sc->window_opacity_change(pubw);
+        screen_refresh(w->sc);
+    }
+    //printf("mapped %d opacity 0x%x\n", w->mapped, w->opacity);
+}
+
+void
+window_zombie_ref(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    ++w->zombieref;
+}
+
+void
+window_zombie_unref(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    if (--w->zombieref == 0) {
+        w->zombie = FALSE;
+
+        if (w->region) {
+            xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
+            w->region = XCB_NONE;
+        }
+
+        if (w->pixmap) {
+            /* this may cause an error if the pixmap was never valid, but
+               that's fine */
+            xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
+            w->pixmap = XCB_NONE;
+        }
+
+        w->sc->window_zombie_dead(pubw);
+
+        /* reset the opacity */
+        w->opacity = 0xffff;
+    }
+}