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