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