c1d181a58fbfa1d340182ee3dd827351e76395a9
[dana/dcompmgr.git] / render.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "display.h"
7 #include "list.h"
8 #include <stdio.h>
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <xcb/render.h>
12
13 static int plugin_id;
14
15 typedef struct {
16     void (*screen_paint)(d_screen_t *sc);
17     void (*screen_root_pixmap_changed)(d_screen_t *sc);
18     void (*window_show)(d_window_t *w);
19     void (*window_hide)(d_window_t *w);
20     void (*window_resize)(d_window_t *w);
21
22     xcb_render_pictformat_t root_format;
23     xcb_render_query_pict_formats_reply_t *pict_formats;
24     xcb_render_picture_t overlay_picture;
25     xcb_render_picture_t overlay_buffer;
26     xcb_render_picture_t root_picture;
27     xcb_render_picture_t solid_bg;
28 } data_t;
29
30 typedef struct {
31     xcb_render_picture_t picture;
32 } window_data_t;
33
34 static void render_paint(d_screen_t *sc);
35 static void render_root_pixmap_changed(d_screen_t *sc);
36 static void paint_root(d_screen_t *sc, data_t *d);
37 static void paint_window(d_window_t *window, data_t *d);
38 static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd);
39 static void render_update_root_picture(d_screen_t *sc, data_t *d);
40 static void render_free_picture(d_window_t *w, window_data_t *wd);
41 static xcb_render_pictformat_t find_visual_format(data_t *d,
42                                                   xcb_visualid_t visual);
43 static xcb_render_picture_t solid_picture(d_screen_t *sc,
44                                           double a, double r,
45                                           double g, double b);
46
47 static void render_window_show(d_window_t *window);
48 static void render_window_hide(d_window_t *window);
49 static void render_window_resize(d_window_t *window);
50
51 void
52 render_init(d_screen_t *sc, int id)
53 {
54     xcb_render_query_pict_formats_cookie_t ck;
55     xcb_pixmap_t px;
56
57     plugin_id = id;
58
59     data_t *d = malloc(sizeof(data_t));
60     d->screen_paint = sc->screen_paint;
61     d->screen_root_pixmap_changed = sc->screen_root_pixmap_changed;
62     d->window_show = sc->window_show;
63     d->window_hide = sc->window_hide;
64     d->window_resize = sc->window_resize;
65     screen_add_plugin_data(sc, plugin_id, d);
66
67     sc->screen_paint = render_paint;
68     sc->screen_root_pixmap_changed = render_root_pixmap_changed;
69     sc->window_show = render_window_show;
70     sc->window_hide = render_window_hide;
71     sc->window_resize = render_window_resize;
72
73     ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
74     d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
75                                                           NULL);
76
77     d->root_format = find_visual_format(d, sc->super.root_visual);
78     d->root_picture = XCB_NONE;
79
80     d->overlay_picture = xcb_generate_id(sc->dpy->conn);
81     xcb_render_create_picture(sc->dpy->conn,
82                               d->overlay_picture, sc->overlay, d->root_format,
83                               0, NULL);
84
85     /* make the double buffer */
86     px = xcb_generate_id(sc->dpy->conn);
87     xcb_create_pixmap(sc->dpy->conn, sc->super.root_depth, px,
88                       sc->super.root, sc->super.width_in_pixels,
89                       sc->super.height_in_pixels);
90     d->overlay_buffer = xcb_generate_id(sc->dpy->conn);
91     xcb_render_create_picture(sc->dpy->conn, d->overlay_buffer, px,
92                               d->root_format, 0, 0);
93     xcb_free_pixmap(sc->dpy->conn, px);
94
95     d->solid_bg = solid_picture(sc, 1.0, 0.0, 0.0, 0.0);
96 }
97
98 void
99 render_free(d_screen_t *sc)
100 {
101     data_t *d = screen_find_plugin_data(sc, plugin_id);
102     free(d->pict_formats);
103     xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
104     if (d->root_picture)
105         xcb_render_free_picture(sc->dpy->conn, d->root_picture);
106     xcb_render_free_picture(sc->dpy->conn, d->overlay_picture);
107     xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer);
108     free(d);
109     screen_remove_plugin_data(sc, plugin_id);
110 }
111
112 void
113 render_window_free(d_window_t *w, window_data_t *wd)
114 {
115     render_free_picture(w, wd);
116     free(wd);
117 }
118
119 static void
120 render_window_show(d_window_t *w)
121 {
122     data_t *d;
123     window_data_t *wd;
124
125     d = screen_find_plugin_data(w->sc, plugin_id);
126
127     /* pass it on */
128     d->window_show(w);
129
130     wd = window_find_plugin_data(w, plugin_id);
131     if (wd)
132         render_window_free(w, wd);
133    
134     wd = malloc(sizeof(window_data_t));
135     wd->picture = XCB_NONE;
136     window_add_plugin_data(w, plugin_id, wd);
137
138     window_ref(w);
139 }
140
141 static void
142 render_window_hide(d_window_t *w)
143 {
144     data_t *d;
145     window_data_t *wd;
146
147     d = screen_find_plugin_data(w->sc, plugin_id);
148     wd = window_find_plugin_data(w, plugin_id);
149     if (wd) {
150         render_window_free(w, wd);
151         window_remove_plugin_data(w, plugin_id);
152     }
153
154     /* pass it on */
155     d->window_hide(w);
156 }
157
158 static xcb_render_picture_t
159 solid_picture(d_screen_t *sc, double a, double r, double g, double b)
160 {
161     xcb_render_picture_t picture;
162     xcb_render_color_t   c;
163
164     picture = xcb_generate_id (sc->dpy->conn);
165
166     c.alpha = a * 0xffff;
167     c.red   = a * r * 0xffff;
168     c.green = a * g * 0xffff;
169     c.blue  = a * b * 0xffff;
170
171     xcb_render_create_solid_fill (sc->dpy->conn, picture, c);
172     return picture;
173 }
174
175 static xcb_render_pictformat_t
176 find_visual_format(data_t *d, xcb_visualid_t visual)
177 {
178     xcb_render_pictscreen_iterator_t si;
179     xcb_render_pictdepth_iterator_t di;
180     xcb_render_pictvisual_iterator_t vi;
181
182     if (!visual) return XCB_NONE;
183
184     /* go through all the screens */
185     si = xcb_render_query_pict_formats_screens_iterator(d->pict_formats);
186     for (; si.rem; xcb_render_pictscreen_next(&si)) {
187         di = xcb_render_pictscreen_depths_iterator(si.data);
188         for (; di.rem; xcb_render_pictdepth_next(&di)) {
189             vi = xcb_render_pictdepth_visuals_iterator(di.data);
190             for (; vi.rem; xcb_render_pictvisual_next(&vi)) {
191                 if (vi.data->visual == visual)
192                     return vi.data->format;
193             }
194         }
195     }
196     return XCB_NONE;
197 }
198
199 static void
200 render_free_picture(d_window_t *w, window_data_t *wd)
201 {
202     /* this might cause an error, oh well */
203     if (wd->picture) {
204         xcb_render_free_picture(w->sc->dpy->conn, wd->picture);
205         wd->picture = XCB_NONE;
206     }
207 }
208
209 static void
210 render_update_root_picture(d_screen_t *sc, data_t *d)
211 {
212     xcb_pixmap_t px;
213
214     px = screen_get_root_pixmap(sc);
215     if (px) {
216         d->root_picture = xcb_generate_id(sc->dpy->conn);
217         xcb_render_create_picture_checked(sc->dpy->conn,
218                                           d->root_picture, px,
219                                           d->root_format, 0, NULL);
220     }
221 }
222
223 static void
224 render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
225 {
226     xcb_pixmap_t px;
227
228     px = window_get_pixmap(w);
229     //printf("got pixmap 0x%x\n", px);
230     if (px) {
231         xcb_render_pictformat_t format;
232         const uint32_t vals = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
233
234         render_free_picture(w, wd);
235
236         wd->picture = xcb_generate_id(w->sc->dpy->conn);
237         format = find_visual_format(d, window_get_visual(w));
238         /* we don't need to check this.  if it fails, we'll just be drawing
239            an invalid picture and creating some X errors but that's no big
240            deal really */
241         xcb_render_create_picture(w->sc->dpy->conn,
242                                   wd->picture, px, format,
243                                   XCB_RENDER_CP_SUBWINDOW_MODE,
244                                   &vals);
245     }
246 }
247
248 static void
249 render_window_resize(d_window_t *w)
250 {
251     data_t *d;
252     window_data_t *wd;
253
254     d = screen_find_plugin_data(w->sc, plugin_id);
255     wd = window_find_plugin_data(w, plugin_id);
256     assert(wd != NULL);
257     render_free_picture(w, wd);
258
259     /* pass it on */
260     d->window_resize(w);
261 }
262
263 static void
264 render_root_pixmap_changed(d_screen_t *sc)
265 {
266     data_t *d;
267
268     d = screen_find_plugin_data(sc, plugin_id);
269     if (d->root_picture) {
270         xcb_render_free_picture(sc->dpy->conn, d->root_picture);
271         d->root_picture = XCB_NONE;
272     }
273
274     /* pass it on */
275     d->screen_root_pixmap_changed(sc);
276 }
277
278 static void
279 render_paint(d_screen_t *sc)
280 {
281     data_t *d = screen_find_plugin_data(sc, plugin_id);
282     d_list_it_t *it;
283
284     //printf("-- painting --\n");
285     paint_root(sc, d);
286 #if 1
287     for (it = list_bottom(sc->stacking); it; it = it->prev) {
288         d_window_t *w = it->data;
289         if (!window_is_input_only(w) && window_is_mapped(w))
290             paint_window(w, d);
291     }
292 #endif
293
294     /* copy the double buffer to the overlay window */
295     xcb_render_composite(sc->dpy->conn,
296                          XCB_RENDER_PICT_OP_SRC,
297                          d->overlay_buffer,
298                          XCB_NONE,
299                          d->overlay_picture,
300                          0, 0, 0, 0,
301                          0, 0,
302                          sc->super.width_in_pixels,
303                          sc->super.height_in_pixels);
304
305     /* call the function we replaced in the chain */
306     d->screen_paint(sc);
307 }
308
309 static void
310 paint_root(d_screen_t *sc, data_t *d)
311 {
312     xcb_render_picture_t src;
313     int op;
314
315     if (!d->root_picture)
316         render_update_root_picture(sc, d);
317
318     if (d->root_picture) {
319         src = d->root_picture;
320         op = XCB_RENDER_PICT_OP_SRC;
321     }
322     else {
323         src = d->solid_bg;
324         op = XCB_RENDER_PICT_OP_CLEAR;
325     }
326     xcb_render_composite(sc->dpy->conn,
327                          op,
328                          src,
329                          XCB_NONE,
330                          d->overlay_buffer,
331                          0, 0, 0, 0,
332                          0, 0,
333                          sc->super.width_in_pixels,
334                          sc->super.height_in_pixels);
335 }
336
337 static void
338 paint_window(d_window_t *w, data_t *d)
339 {
340     window_data_t *wd;
341     int x, y, width, height, bwidth;
342
343     wd = window_find_plugin_data(w, plugin_id);
344
345     if (!wd->picture)
346         render_update_picture(w, d, wd);
347
348     //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
349     if (wd->picture) {
350         window_get_area(w, &x, &y, &width, &height, &bwidth);
351         xcb_render_composite(w->sc->dpy->conn,
352                              //XCB_RENDER_PICT_OP_SRC,  /* - for solid */
353                              XCB_RENDER_PICT_OP_OVER, /* - for argb */
354                              wd->picture,
355                              XCB_NONE,
356                              d->overlay_buffer,
357                              0, 0, 0, 0,
358                              x, y, width + bwidth*2, height + bwidth *2);
359     }
360 }