make the render code use the window's opacity
[dana/dcompmgr.git] / render.c
index 267f81a..795d824 100644 (file)
--- a/render.c
+++ b/render.c
@@ -14,10 +14,11 @@ static int plugin_id;
 
 typedef struct {
     void (*screen_paint)(d_screen_t *sc);
-    void (*screen_root_pixmap_changed)(d_screen_t *sc);
+    void (*screen_root_pixmap_change)(d_screen_t *sc);
     void (*window_show)(d_window_t *w);
     void (*window_hide)(d_window_t *w);
     void (*window_resize)(d_window_t *w);
+    void (*window_opacity_change)(d_window_t *w);
 
     xcb_render_pictformat_t root_format;
     xcb_render_pictformat_t argb32_format;
@@ -31,7 +32,7 @@ typedef struct {
     xcb_xfixes_region_t paint_region;
     xcb_xfixes_region_t shadow_region;
 
-    double shadowalpha;
+    uint16_t shadowalpha;
     int xshadowoff;
     int yshadowoff;
 } data_t;
@@ -43,11 +44,15 @@ typedef struct {
 } window_data_t;
 
 static void render_paint(d_screen_t *sc);
-static void render_root_pixmap_changed(d_screen_t *sc);
+static void render_root_pixmap_change(d_screen_t *sc);
 static void paint_root(d_screen_t *sc, data_t *d);
 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
-                         gboolean opaque);
-static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd);
+                         gboolean opaque, int x, int y, int width,
+                         int height, int bwidth);
+static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
+                         int x, int y, int width, int height, int bwidth);
+static void render_update_shadow_picture(d_window_t *w, data_t *d,
+                                         window_data_t *wd);
 static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd);
 static void render_update_root_picture(d_screen_t *sc, data_t *d);
 static void render_free_picture(d_window_t *w, window_data_t *wd);
@@ -55,12 +60,13 @@ static xcb_render_pictformat_t find_visual_format(data_t *d,
                                                   xcb_visualid_t visual);
 static xcb_render_pictformat_t find_argb32_format(data_t *d);
 static xcb_render_picture_t solid_picture(data_t *d, d_screen_t *sc,
-                                          double a, double r,
-                                          double g, double b);
+                                          uint16_t a, uint16_t r,
+                                          uint16_t g, uint16_t b);
 
 static void render_window_show(d_window_t *window);
 static void render_window_hide(d_window_t *window);
 static void render_window_resize(d_window_t *window);
+static void render_window_opacity_change(d_window_t *w);
 
 void
 render_init(d_screen_t *sc, int id)
@@ -73,17 +79,19 @@ render_init(d_screen_t *sc, int id)
 
     data_t *d = malloc(sizeof(data_t));
     d->screen_paint = sc->screen_paint;
-    d->screen_root_pixmap_changed = sc->screen_root_pixmap_changed;
+    d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
     d->window_show = sc->window_show;
     d->window_hide = sc->window_hide;
     d->window_resize = sc->window_resize;
+    d->window_opacity_change = sc->window_opacity_change;
     screen_add_plugin_data(sc, plugin_id, d);
 
     sc->screen_paint = render_paint;
-    sc->screen_root_pixmap_changed = render_root_pixmap_changed;
+    sc->screen_root_pixmap_change = render_root_pixmap_change;
     sc->window_show = render_window_show;
     sc->window_hide = render_window_hide;
     sc->window_resize = render_window_resize;
+    sc->window_opacity_change = render_window_opacity_change;
 
     ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
     d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
@@ -108,7 +116,7 @@ render_init(d_screen_t *sc, int id)
                               d->root_format, 0, 0);
     xcb_free_pixmap(sc->dpy->conn, px);
 
-    d->solid_bg = solid_picture(d, sc, 1.0, 0.0, 0.0, 0.0);
+    d->solid_bg = solid_picture(d, sc, 0xffff, 0x6060, 02020, 0x3030);
 
     d->all_region = xcb_generate_id(sc->dpy->conn);
     d->paint_region = xcb_generate_id(sc->dpy->conn);
@@ -120,7 +128,7 @@ render_init(d_screen_t *sc, int id)
     xcb_xfixes_create_region(sc->dpy->conn, d->paint_region, 1, &rect);
     xcb_xfixes_create_region(sc->dpy->conn, d->shadow_region, 1, &rect);
 
-    d->shadowalpha = 0.2;
+    d->shadowalpha = 0x3333; /* 20% */
     d->xshadowoff = 2;
     d->yshadowoff = 2;
 }
@@ -171,14 +179,14 @@ render_window_show(d_window_t *w)
    
     wd = malloc(sizeof(window_data_t));
     wd->picture = XCB_NONE;
-    wd->shadow_picture = solid_picture(d, w->sc, d->shadowalpha,
-                                       0.0, 0.0, 0.0);
 
     wd->paint_clip = xcb_generate_id(w->sc->dpy->conn);
     rect.x = rect.y = 0;
     rect.width = rect.height = 1;
     xcb_xfixes_create_region(w->sc->dpy->conn, wd->paint_clip, 1, &rect);
 
+    render_update_shadow_picture(w, d, wd);
+
     window_add_plugin_data(w, plugin_id, wd);
 
     window_ref(w);
@@ -203,8 +211,8 @@ render_window_hide(d_window_t *w)
 }
 
 static xcb_render_picture_t
-solid_picture(data_t *d, d_screen_t *sc,
-              double a, double r, double g, double b)
+solid_picture(data_t *d, d_screen_t *sc, uint16_t a, uint16_t r,
+              uint16_t g, uint16_t b)
 {
     xcb_pixmap_t pixmap;
     xcb_render_picture_t picture;
@@ -219,10 +227,10 @@ solid_picture(data_t *d, d_screen_t *sc,
     xcb_render_create_picture(sc->dpy->conn, picture, pixmap, d->argb32_format,
                               XCB_RENDER_CP_REPEAT, &vals);
 
-    c.alpha = a * 0xffff;
-    c.red = r * 0xffff;
-    c.green = g * 0xffff;
-    c.blue = b * 0xffff;
+    c.alpha = a;
+    c.red   = r;
+    c.green = g;
+    c.blue  = b;
 
     xcb_render_fill_rectangles(sc->dpy->conn, XCB_RENDER_PICT_OP_SRC,
                                picture, c, 1, &rect);
@@ -291,6 +299,17 @@ render_free_picture(d_window_t *w, window_data_t *wd)
 }
 
 static void
+render_update_shadow_picture(d_window_t *w, data_t *d, window_data_t *wd)
+{
+    if (wd->shadow_picture)
+        xcb_render_free_picture(w->sc->dpy->conn, wd->shadow_picture);
+    wd->shadow_picture = solid_picture(d, w->sc,
+                                       d->shadowalpha *
+                                       window_get_opacity(w) / 0xffff,
+                                       0, 0, 0);
+}
+
+static void
 render_update_root_picture(d_screen_t *sc, data_t *d)
 {
     xcb_pixmap_t px;
@@ -298,9 +317,9 @@ render_update_root_picture(d_screen_t *sc, data_t *d)
     px = screen_get_root_pixmap(sc);
     if (px) {
         d->root_picture = xcb_generate_id(sc->dpy->conn);
-        xcb_render_create_picture_checked(sc->dpy->conn,
-                                          d->root_picture, px,
-                                          d->root_format, 0, NULL);
+        xcb_render_create_picture(sc->dpy->conn,
+                                  d->root_picture, px,
+                                  d->root_format, 0, NULL);
     }
 }
 
@@ -346,7 +365,23 @@ render_window_resize(d_window_t *w)
 }
 
 static void
-render_root_pixmap_changed(d_screen_t *sc)
+render_window_opacity_change(d_window_t *w)
+{
+    data_t *d;
+    window_data_t *wd;
+
+    d = screen_find_plugin_data(w->sc, plugin_id);
+    wd = window_find_plugin_data(w, plugin_id);
+
+    /* pass it on */
+    d->window_opacity_change(w);
+
+    assert(wd != NULL);
+    render_update_shadow_picture(w, d, wd);
+}
+
+static void
+render_root_pixmap_change(d_screen_t *sc)
 {
     data_t *d;
 
@@ -357,7 +392,7 @@ render_root_pixmap_changed(d_screen_t *sc)
     }
 
     /* pass it on */
-    d->screen_root_pixmap_changed(sc);
+    d->screen_root_pixmap_change(sc);
 }
 
 static void
@@ -371,16 +406,23 @@ render_paint(d_screen_t *sc)
     //printf("-- painting --\n");
     for (it = list_top(sc->stacking); it; it = it->next) {
         d_window_t *w = it->data;
+        int x, y, width, height, bwidth;
 
-        if (!window_is_input_only(w) && window_is_mapped(w)) {
-            gboolean opaque = !window_is_argb(w);
+        window_get_area(w, &x, &y, &width, &height, &bwidth);
+
+        if (!window_is_input_only(w) && window_is_mapped(w) &&
+            x < sc->super.width_in_pixels &&
+            y < sc->super.height_in_pixels &&
+            x + width > 0 && y + height > 0)
+        {
+            gboolean opaque = !(window_is_argb(w) ||
+                                window_get_opacity(w) < 0xffff);
             window_data_t *wd;
 
             wd = window_find_plugin_data(w, plugin_id);
 
             if (opaque) {
-
-                paint_window(w, d, wd, opaque);
+                paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
 
                 /* remove this window from the paint region, as nothing is
                    above it, so nothing should draw to this space again */
@@ -409,10 +451,19 @@ render_paint(d_screen_t *sc)
 
     for (it = list_bottom(sc->stacking); it; it = it->prev) {
         d_window_t *w = it->data;
+        int x, y, width, height, bwidth;
 
-        if (!window_is_input_only(w) && window_is_mapped(w)) {
+        window_get_area(w, &x, &y, &width, &height, &bwidth);
+
+        if (!window_is_input_only(w) && window_is_mapped(w) &&
+            x < sc->super.width_in_pixels &&
+            y < sc->super.height_in_pixels &&
+            (x + width > 0 || x + width + d->xshadowoff > 0) &&
+            (y + height > 0 || y + height + d->yshadowoff > 0))
+        {
             window_data_t *wd;
-            gboolean opaque = !window_is_argb(w);
+            gboolean opaque = !(window_is_argb(w) ||
+                                window_get_opacity(w) < 0xffff);
 
             wd = window_find_plugin_data(w, plugin_id);
 
@@ -428,7 +479,7 @@ render_paint(d_screen_t *sc)
                                                d->overlay_buffer,
                                                d->shadow_region,
                                                0, 0);
-            paint_shadow(w, d, wd);
+            paint_shadow(w, d, wd, x, y, width, height, bwidth);
 
             if (!opaque) {
                 /* use the clip region of the highest opaque window seen so
@@ -438,7 +489,7 @@ render_paint(d_screen_t *sc)
                                                    d->overlay_buffer,
                                                    wd->paint_clip,
                                                    0, 0);
-                paint_window(w, d, wd, opaque);
+                paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
             }
         }
     }
@@ -480,6 +531,7 @@ paint_root(d_screen_t *sc, data_t *d)
         src = d->solid_bg;
         op = XCB_RENDER_PICT_OP_CLEAR;
     }
+
     xcb_render_composite(sc->dpy->conn,
                          op,
                          src,
@@ -492,24 +544,30 @@ paint_root(d_screen_t *sc, data_t *d)
 }
 
 static void
-paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque)
+paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
+             int x, int y, int width, int height, int bwidth)
 {
+    xcb_render_picture_t alphamap;
+
     if (!wd->picture)
         render_update_picture(w, d, wd);
 
     //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
     if (wd->picture) {
-        int x, y, width, height, bwidth;
         int op;
 
-        window_get_area(w, &x, &y, &width, &height, &bwidth);
         op = !opaque ?
             XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC;
 
+        if (opaque)
+            alphamap = XCB_NONE;
+        else
+            alphamap = solid_picture(d, w->sc, window_get_opacity(w), 0, 0, 0);
+
         xcb_render_composite(w->sc->dpy->conn,
                              op,
                              wd->picture,
-                             XCB_NONE,
+                             alphamap,
                              d->overlay_buffer,
                              0, 0, 0, 0,
                              x, y, width + bwidth*2, height + bwidth *2);
@@ -517,11 +575,9 @@ paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque)
 }
 
 static void
-paint_shadow(d_window_t *w, data_t *d, window_data_t *wd)
+paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
+             int x, int y, int width, int height, int bwidth)
 {
-    int x, y, width, height, bwidth;
-
-    window_get_area(w, &x, &y, &width, &height, &bwidth);
     xcb_render_composite(w->sc->dpy->conn,
                          XCB_RENDER_PICT_OP_OVER,
                          wd->shadow_picture,