+#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>
-void render_paint_screen(struct d_screen *sc)
+static int plugin_id;
+
+typedef struct {
+ void (*screen_paint)(d_screen_t *sc);
+ void (*screen_root_pixmap_changed)(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_pictformat_t root_format;
+ 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 root_picture;
+ xcb_render_picture_t solid_bg;
+} data_t;
+
+typedef struct {
+ xcb_render_picture_t picture;
+} window_data_t;
+
+static void render_paint(d_screen_t *sc);
+static void render_root_pixmap_changed(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);
+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);
+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, int id)
+{
+ xcb_render_query_pict_formats_cookie_t ck;
+ xcb_pixmap_t px;
+
+ plugin_id = 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->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_paint;
+ sc->screen_root_pixmap_changed = render_root_pixmap_changed;
+ 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);
+
+ d->root_format = find_visual_format(d, sc->super.root_visual);
+ d->root_picture = XCB_NONE;
+
+ d->overlay_picture = xcb_generate_id(sc->dpy->conn);
+ xcb_render_create_picture(sc->dpy->conn,
+ d->overlay_picture, sc->overlay, d->root_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,
+ d->root_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)
{
- (void)sc;
- printf("painting\n");
+ data_t *d = screen_find_plugin_data(sc, plugin_id);
+ free(d->pict_formats);
+ xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
+ if (d->root_picture)
+ xcb_render_free_picture(sc->dpy->conn, d->root_picture);
+ 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;
+ 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 void
+render_free_picture(d_window_t *w, window_data_t *wd)
+{
+ /* this might cause an error, oh well */
+ if (wd->picture) {
+ xcb_render_free_picture(w->sc->dpy->conn, wd->picture);
+ wd->picture = XCB_NONE;
+ }
+}
+
+static void
+render_update_root_picture(d_screen_t *sc, data_t *d)
+{
+ xcb_pixmap_t px;
+
+ 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);
+ }
+}
+
+static void
+render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
+{
+ 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 = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
+
+ render_free_picture(w, wd);
+
+ wd->picture = xcb_generate_id(w->sc->dpy->conn);
+ format = find_visual_format(d, window_get_visual(w));
+ /* we don't need to check this. if it fails, we'll just be drawing
+ an invalid picture and creating some X errors but that's no big
+ deal really */
+ xcb_render_create_picture(w->sc->dpy->conn,
+ wd->picture, px, format,
+ XCB_RENDER_CP_SUBWINDOW_MODE,
+ &vals);
+ }
+}
+
+static void
+render_window_resize(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);
+ assert(wd != NULL);
+ render_free_picture(w, wd);
+
+ /* pass it on */
+ d->window_resize(w);
+}
+
+static void
+render_root_pixmap_changed(d_screen_t *sc)
+{
+ data_t *d;
+
+ d = screen_find_plugin_data(sc, plugin_id);
+ if (d->root_picture) {
+ xcb_render_free_picture(sc->dpy->conn, d->root_picture);
+ d->root_picture = XCB_NONE;
+ }
+
+ /* pass it on */
+ d->screen_root_pixmap_changed(sc);
+}
+
+static void
+render_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_picture_t src;
+ int op;
+
+ if (!d->root_picture)
+ render_update_root_picture(sc, d);
+
+ if (d->root_picture) {
+ src = d->root_picture;
+ op = XCB_RENDER_PICT_OP_SRC;
+ }
+ else {
+ src = d->solid_bg;
+ op = XCB_RENDER_PICT_OP_CLEAR;
+ }
+ xcb_render_composite(sc->dpy->conn,
+ op,
+ src,
+ 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;
+
+ wd = window_find_plugin_data(w, plugin_id);
+
+ 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 = (window_is_argb(w) ?
+ XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
+ xcb_render_composite(w->sc->dpy->conn,
+ op,
+ wd->picture,
+ XCB_NONE,
+ d->overlay_buffer,
+ 0, 0, 0, 0,
+ x, y, width + bwidth*2, height + bwidth *2);
+ }
}