fix some more memory problems
[dana/dcompmgr.git] / render.c
index 1843cc4..7950419 100644 (file)
--- a/render.c
+++ b/render.c
+#include "efence.h"
+
 #include "render.h"
 #include "screen.h"
+#include "window.h"
+#include "display.h"
+#include "list.h"
 #include <stdio.h>
+#include <assert.h>
 #include <stdlib.h>
 #include <xcb/render.h>
 
-#define PLUGIN_NAME "render"
+static int plugin_id;
 
 typedef struct {
     void (*screen_paint)(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);
+
+    xcb_render_query_pict_formats_reply_t *pict_formats;
+    xcb_render_picture_t overlay_picture;
+    xcb_render_picture_t overlay_buffer;
+    xcb_render_picture_t solid_bg;
 } data_t;
 
-static void render_paint_screen(d_screen_t *sc);
+typedef struct {
+    xcb_render_picture_t picture;
+    gboolean waiting_picture;
+    xcb_void_cookie_t    ck_picture;
+} window_data_t;
+
+static void render_screen_paint(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);
+static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd,
+                                  gboolean children);
+static void render_free_picture(d_window_t *w, window_data_t *wd);
+static xcb_render_pictformat_t find_visual_format(data_t *d,
+                                                  xcb_visualid_t visual);
+static xcb_render_picture_t solid_picture(d_screen_t *sc,
+                                          double a, double r,
+                                          double g, double 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);
 
 void
-render_init(d_screen_t *sc)
+render_init(d_screen_t *sc, int id)
 {
+    xcb_render_query_pict_formats_cookie_t ck;
+    xcb_render_pictformat_t format;
+    xcb_pixmap_t px;
+
+    plugin_id = id;
+
     data_t *d = malloc(sizeof(data_t));
     d->screen_paint = sc->screen_paint;
-    screen_add_plugin_data(sc, PLUGIN_NAME, d);
+    d->window_show = sc->window_show;
+    d->window_hide = sc->window_hide;
+    d->window_resize = sc->window_resize;
+    screen_add_plugin_data(sc, plugin_id, d);
+
+    sc->screen_paint = render_screen_paint;
+    sc->window_show = render_window_show;
+    sc->window_hide = render_window_hide;
+    sc->window_resize = render_window_resize;
+
+    ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
+    d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
+                                                          NULL);
+
+    format = find_visual_format(d, sc->super.root_visual);
 
-    sc->screen_paint = render_paint_screen;
+    d->overlay_picture = xcb_generate_id(sc->dpy->conn);
+    xcb_render_create_picture(sc->dpy->conn,
+                              d->overlay_picture, sc->overlay, format,
+                              0, NULL);
+
+    /* make the double buffer */
+    px = xcb_generate_id(sc->dpy->conn);
+    xcb_create_pixmap(sc->dpy->conn, sc->super.root_depth, px,
+                      sc->super.root, sc->super.width_in_pixels,
+                      sc->super.height_in_pixels);
+    d->overlay_buffer = xcb_generate_id(sc->dpy->conn);
+    xcb_render_create_picture(sc->dpy->conn, d->overlay_buffer, px,
+                              format, 0, 0);
+    xcb_free_pixmap(sc->dpy->conn, px);
+
+    d->solid_bg = solid_picture(sc, 1.0, 0.0, 0.0, 0.0);
 }
 
 void
 render_free(d_screen_t *sc)
 {
-    data_t *d = screen_find_plugin_data(sc, PLUGIN_NAME);
+    data_t *d = screen_find_plugin_data(sc, plugin_id);
+    free(d->pict_formats);
+    xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
+    xcb_render_free_picture(sc->dpy->conn, d->overlay_picture);
+    xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer);
     free(d);
+    screen_remove_plugin_data(sc, plugin_id);
+}
+
+void
+render_window_free(d_window_t *w, window_data_t *wd)
+{
+    render_free_picture(w, wd);
+    free(wd);
+}
+
+static void
+render_window_show(d_window_t *w)
+{
+    data_t *d;
+    window_data_t *wd;
+
+    d = screen_find_plugin_data(w->sc, plugin_id);
+
+    /* pass it on */
+    d->window_show(w);
+
+    wd = window_find_plugin_data(w, plugin_id);
+    if (wd)
+        render_window_free(w, wd);
+   
+    wd = malloc(sizeof(window_data_t));
+    wd->picture = XCB_NONE;
+    wd->waiting_picture = FALSE;
+    window_add_plugin_data(w, plugin_id, wd);
+
+    window_ref(w);
+}
+
+static void
+render_window_hide(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);
+    if (wd) {
+        render_window_free(w, wd);
+        window_remove_plugin_data(w, plugin_id);
+    }
+
+    /* pass it on */
+    d->window_hide(w);
+}
+
+static
+xcb_render_picture_t solid_picture(d_screen_t *sc,
+                                   double a, double r,
+                                   double g, double b)
+{
+    xcb_render_picture_t picture;
+    xcb_render_color_t   c;
+
+    picture = xcb_generate_id (sc->dpy->conn);
+
+    c.alpha = a * 0xffff;
+    c.red   = a * r * 0xffff;
+    c.green = a * g * 0xffff;
+    c.blue  = a * b * 0xffff;
+
+    xcb_render_create_solid_fill (sc->dpy->conn, picture, c);
+    return picture;
+}
+
+static xcb_render_pictformat_t
+find_visual_format(data_t *d, xcb_visualid_t visual)
+{
+    xcb_render_pictscreen_iterator_t si;
+    xcb_render_pictdepth_iterator_t di;
+    xcb_render_pictvisual_iterator_t vi;
+
+    if (!visual) return XCB_NONE;
+
+    /* go through all the screens */
+    si = xcb_render_query_pict_formats_screens_iterator(d->pict_formats);
+    for (; si.rem; xcb_render_pictscreen_next(&si)) {
+        di = xcb_render_pictscreen_depths_iterator(si.data);
+        for (; di.rem; xcb_render_pictdepth_next(&di)) {
+            vi = xcb_render_pictdepth_visuals_iterator(di.data);
+            for (; vi.rem; xcb_render_pictvisual_next(&vi)) {
+                if (vi.data->visual == visual)
+                    return vi.data->format;
+            }
+        }
+    }
+    return XCB_NONE;
+}
+
+static xcb_render_picture_t
+render_get_picture(d_window_t *w, window_data_t *wd)
+{
+    if (wd->waiting_picture) {
+        xcb_generic_error_t *err;
+        //printf("** checking create picture 0x%x\n", w->id);
+        err = xcb_request_check(w->sc->dpy->conn, wd->ck_picture);
+        if (err) {
+            wd->picture = XCB_NONE;
+            printf("error creating picture for window 0x%x\n", w->id);
+            free(err);
+        }
+        wd->waiting_picture = FALSE;
+    }
+    //printf("returning picture 0x%x for window 0x%x\n", wd->picture, w->id);
+    return wd->picture;
+}
+
+static void
+render_free_picture(d_window_t *w, window_data_t *wd)
+{
+    xcb_render_picture_t pict;
+
+    pict = render_get_picture(w, wd);
+    if (pict) xcb_render_free_picture(w->sc->dpy->conn, pict);
+    wd->picture = XCB_NONE;
+}
+
+static void
+render_update_picture(d_window_t *w, data_t *d, window_data_t *wd,
+                      gboolean children)
+{
+    xcb_pixmap_t px;
+
+    px = window_get_pixmap(w);
+    //printf("got pixmap 0x%x\n", px);
+    if (px) {
+        xcb_render_pictformat_t format;
+        const uint32_t vals = (children ?
+                               XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS :
+                               XCB_SUBWINDOW_MODE_CLIP_BY_CHILDREN);
+
+        render_free_picture(w, wd);
+
+        wd->picture = xcb_generate_id(w->sc->dpy->conn);
+        format = find_visual_format(d, window_get_visual(w));
+        wd->ck_picture =
+            xcb_render_create_picture_checked(w->sc->dpy->conn,
+                                              wd->picture, px, format,
+                                              XCB_RENDER_CP_SUBWINDOW_MODE,
+                                              &vals);
+        wd->waiting_picture = TRUE;
+    }
 }
 
 static void
-render_paint_screen(d_screen_t *sc)
+render_window_resize(d_window_t *w)
 {
-    data_t *d = screen_find_plugin_data(sc, PLUGIN_NAME);
+    data_t *d;
+    window_data_t *wd;
 
-    printf("-- painting --\n");
+    d = screen_find_plugin_data(w->sc, plugin_id);
+    wd = window_find_plugin_data(w, plugin_id);
+    assert(wd != NULL);
+    render_free_picture(w, wd);
+
+    /* pass it on */
+    d->window_resize(w);
+}
+
+static void
+render_screen_paint(d_screen_t *sc)
+{
+    data_t *d = screen_find_plugin_data(sc, plugin_id);
+    d_list_it_t *it;
+
+    //printf("-- painting --\n");
+    paint_root(sc, d);
+#if 1
+    for (it = list_bottom(sc->stacking); it; it = it->prev) {
+        d_window_t *w = it->data;
+        if (!window_is_input_only(w) && window_is_mapped(w))
+            paint_window(w, d);
+    }
+#endif
+
+    /* copy the double buffer to the overlay window */
+    xcb_render_composite(sc->dpy->conn,
+                         XCB_RENDER_PICT_OP_SRC,
+                         d->overlay_buffer,
+                         XCB_NONE,
+                         d->overlay_picture,
+                         0, 0, 0, 0,
+                         0, 0,
+                         sc->super.width_in_pixels,
+                         sc->super.height_in_pixels);
 
     /* call the function we replaced in the chain */
     d->screen_paint(sc);
 }
+
+static void
+paint_root(d_screen_t *sc, data_t *d)
+{
+    xcb_render_composite(sc->dpy->conn,
+                         XCB_RENDER_PICT_OP_CLEAR,
+                         d->solid_bg,
+                         XCB_NONE,
+                         d->overlay_buffer,
+                         0, 0, 0, 0,
+                         0, 0,
+                         sc->super.width_in_pixels,
+                         sc->super.height_in_pixels);
+}
+
+static void
+paint_window(d_window_t *w, data_t *d)
+{
+    window_data_t *wd;
+    xcb_render_picture_t pict;
+    int x, y, width, height, bwidth;
+
+    wd = window_find_plugin_data(w, plugin_id);
+
+    if (!wd->picture)
+        render_update_picture(w, d, wd, TRUE);
+    pict = render_get_picture(w, wd);
+
+    //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
+    window_get_area(w, &x, &y, &width, &height, &bwidth);
+    xcb_render_composite(w->sc->dpy->conn,
+                         //XCB_RENDER_PICT_OP_SRC,  /* - for solid */
+                         XCB_RENDER_PICT_OP_OVER, /* - for argb */
+                         wd->picture,
+                         XCB_NONE,
+                         d->overlay_buffer,
+                         0, 0, 0, 0,
+                         x, y, width + bwidth*2, height + bwidth *2);
+}