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