fix some more memory problems
[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 (*window_show)(d_window_t *w);
18     void (*window_hide)(d_window_t *w);
19     void (*window_resize)(d_window_t *w);
20
21     xcb_render_query_pict_formats_reply_t *pict_formats;
22     xcb_render_picture_t overlay_picture;
23     xcb_render_picture_t overlay_buffer;
24     xcb_render_picture_t solid_bg;
25 } data_t;
26
27 typedef struct {
28     xcb_render_picture_t picture;
29     gboolean waiting_picture;
30     xcb_void_cookie_t    ck_picture;
31 } window_data_t;
32
33 static void render_screen_paint(d_screen_t *sc);
34 static void paint_root(d_screen_t *sc, data_t *d);
35 static void paint_window(d_window_t *window, data_t *d);
36 static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd,
37                                   gboolean children);
38 static void render_free_picture(d_window_t *w, window_data_t *wd);
39 static xcb_render_pictformat_t find_visual_format(data_t *d,
40                                                   xcb_visualid_t visual);
41 static xcb_render_picture_t solid_picture(d_screen_t *sc,
42                                           double a, double r,
43                                           double g, double b);
44
45 static void render_window_show(d_window_t *window);
46 static void render_window_hide(d_window_t *window);
47 static void render_window_resize(d_window_t *window);
48
49 void
50 render_init(d_screen_t *sc, int id)
51 {
52     xcb_render_query_pict_formats_cookie_t ck;
53     xcb_render_pictformat_t format;
54     xcb_pixmap_t px;
55
56     plugin_id = id;
57
58     data_t *d = malloc(sizeof(data_t));
59     d->screen_paint = sc->screen_paint;
60     d->window_show = sc->window_show;
61     d->window_hide = sc->window_hide;
62     d->window_resize = sc->window_resize;
63     screen_add_plugin_data(sc, plugin_id, d);
64
65     sc->screen_paint = render_screen_paint;
66     sc->window_show = render_window_show;
67     sc->window_hide = render_window_hide;
68     sc->window_resize = render_window_resize;
69
70     ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
71     d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
72                                                           NULL);
73
74     format = find_visual_format(d, sc->super.root_visual);
75
76     d->overlay_picture = xcb_generate_id(sc->dpy->conn);
77     xcb_render_create_picture(sc->dpy->conn,
78                               d->overlay_picture, sc->overlay, format,
79                               0, NULL);
80
81     /* make the double buffer */
82     px = xcb_generate_id(sc->dpy->conn);
83     xcb_create_pixmap(sc->dpy->conn, sc->super.root_depth, px,
84                       sc->super.root, sc->super.width_in_pixels,
85                       sc->super.height_in_pixels);
86     d->overlay_buffer = xcb_generate_id(sc->dpy->conn);
87     xcb_render_create_picture(sc->dpy->conn, d->overlay_buffer, px,
88                               format, 0, 0);
89     xcb_free_pixmap(sc->dpy->conn, px);
90
91     d->solid_bg = solid_picture(sc, 1.0, 0.0, 0.0, 0.0);
92 }
93
94 void
95 render_free(d_screen_t *sc)
96 {
97     data_t *d = screen_find_plugin_data(sc, plugin_id);
98     free(d->pict_formats);
99     xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
100     xcb_render_free_picture(sc->dpy->conn, d->overlay_picture);
101     xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer);
102     free(d);
103     screen_remove_plugin_data(sc, plugin_id);
104 }
105
106 void
107 render_window_free(d_window_t *w, window_data_t *wd)
108 {
109     render_free_picture(w, wd);
110     free(wd);
111 }
112
113 static void
114 render_window_show(d_window_t *w)
115 {
116     data_t *d;
117     window_data_t *wd;
118
119     d = screen_find_plugin_data(w->sc, plugin_id);
120
121     /* pass it on */
122     d->window_show(w);
123
124     wd = window_find_plugin_data(w, plugin_id);
125     if (wd)
126         render_window_free(w, wd);
127    
128     wd = malloc(sizeof(window_data_t));
129     wd->picture = XCB_NONE;
130     wd->waiting_picture = FALSE;
131     window_add_plugin_data(w, plugin_id, wd);
132
133     window_ref(w);
134 }
135
136 static void
137 render_window_hide(d_window_t *w)
138 {
139     data_t *d;
140     window_data_t *wd;
141
142     d = screen_find_plugin_data(w->sc, plugin_id);
143     wd = window_find_plugin_data(w, plugin_id);
144     if (wd) {
145         render_window_free(w, wd);
146         window_remove_plugin_data(w, plugin_id);
147     }
148
149     /* pass it on */
150     d->window_hide(w);
151 }
152
153 static
154 xcb_render_picture_t solid_picture(d_screen_t *sc,
155                                    double a, double r,
156                                    double g, double b)
157 {
158     xcb_render_picture_t picture;
159     xcb_render_color_t   c;
160
161     picture = xcb_generate_id (sc->dpy->conn);
162
163     c.alpha = a * 0xffff;
164     c.red   = a * r * 0xffff;
165     c.green = a * g * 0xffff;
166     c.blue  = a * b * 0xffff;
167
168     xcb_render_create_solid_fill (sc->dpy->conn, picture, c);
169     return picture;
170 }
171
172 static xcb_render_pictformat_t
173 find_visual_format(data_t *d, xcb_visualid_t visual)
174 {
175     xcb_render_pictscreen_iterator_t si;
176     xcb_render_pictdepth_iterator_t di;
177     xcb_render_pictvisual_iterator_t vi;
178
179     if (!visual) return XCB_NONE;
180
181     /* go through all the screens */
182     si = xcb_render_query_pict_formats_screens_iterator(d->pict_formats);
183     for (; si.rem; xcb_render_pictscreen_next(&si)) {
184         di = xcb_render_pictscreen_depths_iterator(si.data);
185         for (; di.rem; xcb_render_pictdepth_next(&di)) {
186             vi = xcb_render_pictdepth_visuals_iterator(di.data);
187             for (; vi.rem; xcb_render_pictvisual_next(&vi)) {
188                 if (vi.data->visual == visual)
189                     return vi.data->format;
190             }
191         }
192     }
193     return XCB_NONE;
194 }
195
196 static xcb_render_picture_t
197 render_get_picture(d_window_t *w, window_data_t *wd)
198 {
199     if (wd->waiting_picture) {
200         xcb_generic_error_t *err;
201         //printf("** checking create picture 0x%x\n", w->id);
202         err = xcb_request_check(w->sc->dpy->conn, wd->ck_picture);
203         if (err) {
204             wd->picture = XCB_NONE;
205             printf("error creating picture for window 0x%x\n", w->id);
206             free(err);
207         }
208         wd->waiting_picture = FALSE;
209     }
210     //printf("returning picture 0x%x for window 0x%x\n", wd->picture, w->id);
211     return wd->picture;
212 }
213
214 static void
215 render_free_picture(d_window_t *w, window_data_t *wd)
216 {
217     xcb_render_picture_t pict;
218
219     pict = render_get_picture(w, wd);
220     if (pict) xcb_render_free_picture(w->sc->dpy->conn, pict);
221     wd->picture = XCB_NONE;
222 }
223
224 static void
225 render_update_picture(d_window_t *w, data_t *d, window_data_t *wd,
226                       gboolean children)
227 {
228     xcb_pixmap_t px;
229
230     px = window_get_pixmap(w);
231     //printf("got pixmap 0x%x\n", px);
232     if (px) {
233         xcb_render_pictformat_t format;
234         const uint32_t vals = (children ?
235                                XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS :
236                                XCB_SUBWINDOW_MODE_CLIP_BY_CHILDREN);
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         wd->ck_picture =
243             xcb_render_create_picture_checked(w->sc->dpy->conn,
244                                               wd->picture, px, format,
245                                               XCB_RENDER_CP_SUBWINDOW_MODE,
246                                               &vals);
247         wd->waiting_picture = TRUE;
248     }
249 }
250
251 static void
252 render_window_resize(d_window_t *w)
253 {
254     data_t *d;
255     window_data_t *wd;
256
257     d = screen_find_plugin_data(w->sc, plugin_id);
258     wd = window_find_plugin_data(w, plugin_id);
259     assert(wd != NULL);
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 }