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