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