blend argb windows, but just blit non-argb windows which is faster
[dana/dcompmgr.git] / window.c
index 9c7847e..794a1e4 100644 (file)
--- a/window.c
+++ b/window.c
@@ -1,9 +1,15 @@
+#include "efence.h"
+
 #include "window.h"
 #include "screen.h"
+#include "plugin.h"
+#include "list.h"
 #include "display.h"
 #include <stdlib.h>
+#include <assert.h>
 #include <stdio.h>
 #include <xcb/composite.h>
+#include <xcb/damage.h>
 
 typedef struct {
     /* public stuff */
@@ -14,19 +20,26 @@ typedef struct {
     int              ref;
 
     /* queried things, don't read them directly from the struct */
-    int              x, y, w, h;
-    gboolean         mapped;
+    int              x, y, w, h, bw;
+    gboolean         attr_mapped;
     gboolean         input_only;
+    gboolean         argb;
+    xcb_visualid_t   visual;
+    xcb_pixmap_t     pixmap;
 
+    double           opacity;
+
+    gboolean         mapped;
     gboolean         zombie;
 
-    int              opacity;
+    d_list_t        *plugin_data;
 
-    xcb_pixmap_t     pixmap;
+    xcb_damage_damage_t damage;
 
+    gboolean waiting_attr;
     xcb_get_window_attributes_cookie_t ck_get_attr;
+    gboolean waiting_geom;
     xcb_get_geometry_cookie_t          ck_get_geom;
-    xcb_void_cookie_t                  ck_get_pixmap;
 } d_window_priv_t;
 
 static void window_get_attributes_reply(d_window_priv_t *w);
@@ -42,15 +55,19 @@ window_new(xcb_window_t id, struct d_screen *sc)
     w->ref = 1;
     w->sc = sc;
     w->zombie = FALSE;
-    w->opacity = WINDOW_OPACITY_MAX;
+    w->mapped = FALSE;
     w->pixmap = XCB_NONE;
+    w->damage = XCB_NONE;
 
     screen_stacking_add(sc, (d_window_t*)w);
 
     w->ck_get_attr = xcb_get_window_attributes(sc->dpy->conn, id);
+    w->waiting_attr = TRUE;
+
     w->ck_get_geom = xcb_get_geometry(sc->dpy->conn, id);
+    w->waiting_geom = TRUE;
 
-    w->ck_get_pixmap.sequence = 0;
+    w->plugin_data = list_new();
 
     //printf("new window 0x%x\n", w->id);
 
@@ -71,51 +88,83 @@ window_unref(d_window_t *pubw)
     d_window_priv_t *w = (d_window_priv_t*)pubw;
 
     if (w && --w->ref == 0) {
-        xcb_pixmap_t p;
-
         screen_stacking_remove(w->sc, (d_window_t*)w);
 
-        if ((p = window_get_pixmap(pubw))) {
-            xcb_free_pixmap(w->sc->dpy->conn, p);
+        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;
         }
 
+        list_unref(w->plugin_data);
         free(w);
     }
 }
 
-void
-window_show(d_window_t *pubw)
+xcb_pixmap_t
+window_get_pixmap(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
-    xcb_pixmap_t p;
 
-    if (window_is_mapped(pubw)) return;
+    return w->pixmap;
+}
+
 
-    printf("show window 0x%x\n", w->id);
+static void
+window_update_pixmap(d_window_priv_t *w)
+{
+    if (window_is_zombie((d_window_t*)w)) return;
 
-    /* XXX can we save it for until we get the new pixmap? */
-    if ((p = window_get_pixmap(pubw))) {
-        xcb_free_pixmap(w->sc->dpy->conn, p);
+    /* the pixmap may not be valid even though it is non-zero, but
+       we can free it anyways and let it fail.  we don't need to wait
+       for a response from the server */
+    if (w->pixmap) {
+        xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
         w->pixmap = XCB_NONE;
     }
 
-    w->mapped = TRUE;
+    //printf("updating pixmap for 0x%x\n", w->id);
+
+    /* we don't check the result of this call, because it seems that sometimes
+       the X server just doesn't reply.  if we check it, we end up hanging
+       sometimes waiting for the reply */
     w->pixmap = xcb_generate_id(w->sc->dpy->conn);
-    w->ck_get_pixmap = 
-        xcb_composite_name_window_pixmap_checked(w->sc->dpy->conn,
-                                                 w->id, w->pixmap);
+    xcb_composite_name_window_pixmap(w->sc->dpy->conn, w->id, w->pixmap);
+    //printf("requested pixmap sequence %u\n", w->ck_get_pixmap.sequence);
+    //fflush(stdout);
     xcb_flush(w->sc->dpy->conn);
 }
 
 void
+window_show(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    assert(!w->mapped);
+
+    //printf("show window 0x%x\n", w->id);
+
+    window_update_pixmap(w);
+    w->mapped = TRUE;
+}
+
+void
 window_hide(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
 
-    if (!window_is_mapped(pubw)) return;
+    assert(w->mapped);
 
-    printf("hide window 0x%x\n", w->id);
+    //printf("hide window 0x%x\n", w->id);
+
+    w->mapped = FALSE;
+}
+
+void
+window_fake_unmapped(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
 
     w->mapped = FALSE;
 }
@@ -141,21 +190,23 @@ gboolean
 window_is_input_only(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
-    if (w->ck_get_attr.sequence)
+    if (w->waiting_attr)
         window_get_attributes_reply(w);
     return w->input_only;
 }
 
 void
-window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height)
+window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
+                int *border_width)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
-    if (w->ck_get_geom.sequence)
+    if (w->waiting_geom)
         window_get_geometry_reply(w);
     *x = w->x;
     *y = w->y;
     *width = w->w;
     *height = w->h;
+    *border_width = w->bw;
 }
 
 static void
@@ -170,18 +221,21 @@ window_get_attributes_reply(d_window_priv_t *w)
 
     if (rep) {
         w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
-        w->mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
+        w->attr_mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
+        w->visual = rep->visual;
+        //printf("0x%x attributes mapped %d\n", w->id, w->mapped);
         free(rep);
     }
     else {
         w->input_only = TRUE;
-        w->mapped = FALSE;
+        w->attr_mapped = FALSE;
+        w->visual = XCB_NONE;
     }
     if (err) {
         printf("error getting attributes for window 0x%x\n", w->id);
         free(err);
     }
-    w->ck_get_attr.sequence = 0;
+    w->waiting_attr = FALSE;
 }
 
 static void
@@ -197,47 +251,57 @@ window_get_geometry_reply(d_window_priv_t *w)
     if (rep) {
         w->x = rep->x;
         w->y = rep->y;
-        w->w = rep->width + rep->border_width * 2;
-        w->h = rep->height + rep->border_width * 2;
+        w->w = rep->width;
+        w->h = rep->height;
+        w->bw = rep->border_width;
+        w->argb = rep->depth == 32;
         free(rep);
     }
     else {
         w->x = w->y = -1;
         w->w = w->h = 1;
+        w->bw = 0;
+        w->argb = FALSE;
     }
     if (err) {
         printf("error getting geometry for window 0x%x\n", w->id);
         free(err);
     }
-    w->ck_get_geom.sequence = 0;
+    w->waiting_geom = FALSE;
 }
 
 gboolean
 window_is_mapped(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
-    if (w->ck_get_attr.sequence)
-        window_get_attributes_reply(w);
     return w->mapped;
 }
 
-xcb_pixmap_t
-window_get_pixmap(d_window_t *pubw)
+gboolean
+window_is_attr_mapped(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
+    if (w->waiting_attr)
+        window_get_attributes_reply(w);
+    return w->attr_mapped;
+}
 
-    if (w->ck_get_pixmap.sequence) {
-        xcb_generic_error_t *err;
-        //printf("** checking get pixmap 0x%x\n", w->id);
-        err = xcb_request_check(w->sc->dpy->conn, w->ck_get_pixmap);
-        if (err) {
-            printf("error getting named pixmap for window 0x%x\n", w->id);
-            free(err);
-        }
-        w->pixmap = XCB_NONE;
-    }
-    //printf("returning pixmap 0x%x for window 0x%x\n", w->pixmap, w->id);
-    return w->pixmap;
+gboolean
+window_is_argb(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    if (w->waiting_geom)
+        window_get_geometry_reply(w);
+    return w->argb;
+}
+
+xcb_visualid_t
+window_get_visual(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    if (w->waiting_attr)
+        window_get_attributes_reply(w);
+    return w->visual;
 }
 
 void
@@ -247,10 +311,69 @@ window_configure(d_window_t *pubw, int x, int y, int width, int height,
     d_window_priv_t *w = (d_window_priv_t*)pubw;
 
     /* this overrides any reply from our get_geometry call */
-    if (w->ck_get_geom.sequence)
-        w->ck_get_geom.sequence = 0;
+    if (w->waiting_geom)
+        w->waiting_geom = FALSE;
     w->x = x;
     w->y = y;
-    w->w = width + border_width * 2;
-    w->h = height + border_width * 2;
+    w->w = width;
+    w->h = height;
+    w->bw = border_width;
+}
+
+void
+window_move(d_window_t *w)
+{
+    (void)w;
+}
+
+void
+window_resize(d_window_t *w)
+{
+    window_update_pixmap((d_window_priv_t*)w);
+}
+
+void
+window_add_plugin_data(d_window_t *pubw, int id, void *data)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    plugin_data_add(w->plugin_data, id, data);
+}
+
+void*
+window_find_plugin_data(d_window_t *pubw, int id)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    return plugin_data_find(w->plugin_data, id);
+}
+
+void
+window_remove_plugin_data(d_window_t *pubw, int id)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+    plugin_data_remove(w->plugin_data, id);
+}
+
+void
+window_create_damage(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    if (!window_is_input_only(pubw)) {
+        assert(w->damage == XCB_NONE);
+        w->damage = xcb_generate_id(w->sc->dpy->conn);
+        //printf("creating damage 0x%x\n", w->damage);
+        xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
+                          XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
+    }
+}
+
+void window_destroy_damage(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    if (w->damage) {
+        //printf("destroying damage 0x%x\n", w->damage);
+        xcb_damage_destroy(w->sc->dpy->conn, w->damage);
+        w->damage = XCB_NONE;
+    }
 }