blend argb windows, but just blit non-argb windows which is faster
[dana/dcompmgr.git] / window.c
1 #include "efence.h"
2
3 #include "window.h"
4 #include "screen.h"
5 #include "plugin.h"
6 #include "list.h"
7 #include "display.h"
8 #include <stdlib.h>
9 #include <assert.h>
10 #include <stdio.h>
11 #include <xcb/composite.h>
12 #include <xcb/damage.h>
13
14 typedef struct {
15     /* public stuff */
16     xcb_window_t     id;
17     struct d_screen *sc;
18
19     /* private stuff */
20     int              ref;
21
22     /* queried things, don't read them directly from the struct */
23     int              x, y, w, h, bw;
24     gboolean         attr_mapped;
25     gboolean         input_only;
26     gboolean         argb;
27     xcb_visualid_t   visual;
28     xcb_pixmap_t     pixmap;
29
30     double           opacity;
31
32     gboolean         mapped;
33     gboolean         zombie;
34
35     d_list_t        *plugin_data;
36
37     xcb_damage_damage_t damage;
38
39     gboolean waiting_attr;
40     xcb_get_window_attributes_cookie_t ck_get_attr;
41     gboolean waiting_geom;
42     xcb_get_geometry_cookie_t          ck_get_geom;
43 } d_window_priv_t;
44
45 static void window_get_attributes_reply(d_window_priv_t *w);
46 static void window_get_geometry_reply(d_window_priv_t *w);
47
48 d_window_t*
49 window_new(xcb_window_t id, struct d_screen *sc)
50 {
51     d_window_priv_t *w;
52
53     w = malloc(sizeof(d_window_priv_t));
54     w->id = id;
55     w->ref = 1;
56     w->sc = sc;
57     w->zombie = FALSE;
58     w->mapped = FALSE;
59     w->pixmap = XCB_NONE;
60     w->damage = XCB_NONE;
61
62     screen_stacking_add(sc, (d_window_t*)w);
63
64     w->ck_get_attr = xcb_get_window_attributes(sc->dpy->conn, id);
65     w->waiting_attr = TRUE;
66
67     w->ck_get_geom = xcb_get_geometry(sc->dpy->conn, id);
68     w->waiting_geom = TRUE;
69
70     w->plugin_data = list_new();
71
72     //printf("new window 0x%x\n", w->id);
73
74     return (d_window_t*)w;
75 }
76
77 void
78 window_ref(d_window_t *pubw)
79 {
80     d_window_priv_t *w = (d_window_priv_t*)pubw;
81
82     ++w->ref;
83 }
84
85 void
86 window_unref(d_window_t *pubw)
87 {
88     d_window_priv_t *w = (d_window_priv_t*)pubw;
89
90     if (w && --w->ref == 0) {
91         screen_stacking_remove(w->sc, (d_window_t*)w);
92
93         if (w->pixmap) {
94             /* this may cause an error if the pixmap was never valid, but
95                that's fine */
96             xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
97             w->pixmap = XCB_NONE;
98         }
99
100         list_unref(w->plugin_data);
101         free(w);
102     }
103 }
104
105 xcb_pixmap_t
106 window_get_pixmap(d_window_t *pubw)
107 {
108     d_window_priv_t *w = (d_window_priv_t*)pubw;
109
110     return w->pixmap;
111 }
112
113
114 static void
115 window_update_pixmap(d_window_priv_t *w)
116 {
117     if (window_is_zombie((d_window_t*)w)) return;
118
119     /* the pixmap may not be valid even though it is non-zero, but
120        we can free it anyways and let it fail.  we don't need to wait
121        for a response from the server */
122     if (w->pixmap) {
123         xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
124         w->pixmap = XCB_NONE;
125     }
126
127     //printf("updating pixmap for 0x%x\n", w->id);
128
129     /* we don't check the result of this call, because it seems that sometimes
130        the X server just doesn't reply.  if we check it, we end up hanging
131        sometimes waiting for the reply */
132     w->pixmap = xcb_generate_id(w->sc->dpy->conn);
133     xcb_composite_name_window_pixmap(w->sc->dpy->conn, w->id, w->pixmap);
134     //printf("requested pixmap sequence %u\n", w->ck_get_pixmap.sequence);
135     //fflush(stdout);
136     xcb_flush(w->sc->dpy->conn);
137 }
138
139 void
140 window_show(d_window_t *pubw)
141 {
142     d_window_priv_t *w = (d_window_priv_t*)pubw;
143
144     assert(!w->mapped);
145
146     //printf("show window 0x%x\n", w->id);
147
148     window_update_pixmap(w);
149     w->mapped = TRUE;
150 }
151
152 void
153 window_hide(d_window_t *pubw)
154 {
155     d_window_priv_t *w = (d_window_priv_t*)pubw;
156
157     assert(w->mapped);
158
159     //printf("hide window 0x%x\n", w->id);
160
161     w->mapped = FALSE;
162 }
163
164 void
165 window_fake_unmapped(d_window_t *pubw)
166 {
167     d_window_priv_t *w = (d_window_priv_t*)pubw;
168
169     w->mapped = FALSE;
170 }
171
172 void
173 window_become_zombie(d_window_t *pubw)
174 {
175     d_window_priv_t *w = (d_window_priv_t*)pubw;
176
177     if (w->zombie) return;
178
179     w->zombie = TRUE;
180 }
181
182 gboolean
183 window_is_zombie(d_window_t *pubw)
184 {
185     d_window_priv_t *w = (d_window_priv_t*)pubw;
186     return w->zombie;
187 }
188
189 gboolean
190 window_is_input_only(d_window_t *pubw)
191 {
192     d_window_priv_t *w = (d_window_priv_t*)pubw;
193     if (w->waiting_attr)
194         window_get_attributes_reply(w);
195     return w->input_only;
196 }
197
198 void
199 window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
200                 int *border_width)
201 {
202     d_window_priv_t *w = (d_window_priv_t*)pubw;
203     if (w->waiting_geom)
204         window_get_geometry_reply(w);
205     *x = w->x;
206     *y = w->y;
207     *width = w->w;
208     *height = w->h;
209     *border_width = w->bw;
210 }
211
212 static void
213 window_get_attributes_reply(d_window_priv_t *w)
214 {
215     xcb_get_window_attributes_reply_t *rep;
216     xcb_generic_error_t *err = NULL;
217
218     rep = xcb_get_window_attributes_reply(w->sc->dpy->conn,
219                                           w->ck_get_attr,
220                                           &err);
221
222     if (rep) {
223         w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
224         w->attr_mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
225         w->visual = rep->visual;
226         //printf("0x%x attributes mapped %d\n", w->id, w->mapped);
227         free(rep);
228     }
229     else {
230         w->input_only = TRUE;
231         w->attr_mapped = FALSE;
232         w->visual = XCB_NONE;
233     }
234     if (err) {
235         printf("error getting attributes for window 0x%x\n", w->id);
236         free(err);
237     }
238     w->waiting_attr = FALSE;
239 }
240
241 static void
242 window_get_geometry_reply(d_window_priv_t *w)
243 {
244     xcb_get_geometry_reply_t *rep;
245     xcb_generic_error_t *err = NULL;
246
247     rep = xcb_get_geometry_reply(w->sc->dpy->conn,
248                                  w->ck_get_geom,
249                                  &err);
250
251     if (rep) {
252         w->x = rep->x;
253         w->y = rep->y;
254         w->w = rep->width;
255         w->h = rep->height;
256         w->bw = rep->border_width;
257         w->argb = rep->depth == 32;
258         free(rep);
259     }
260     else {
261         w->x = w->y = -1;
262         w->w = w->h = 1;
263         w->bw = 0;
264         w->argb = FALSE;
265     }
266     if (err) {
267         printf("error getting geometry for window 0x%x\n", w->id);
268         free(err);
269     }
270     w->waiting_geom = FALSE;
271 }
272
273 gboolean
274 window_is_mapped(d_window_t *pubw)
275 {
276     d_window_priv_t *w = (d_window_priv_t*)pubw;
277     return w->mapped;
278 }
279
280 gboolean
281 window_is_attr_mapped(d_window_t *pubw)
282 {
283     d_window_priv_t *w = (d_window_priv_t*)pubw;
284     if (w->waiting_attr)
285         window_get_attributes_reply(w);
286     return w->attr_mapped;
287 }
288
289 gboolean
290 window_is_argb(d_window_t *pubw)
291 {
292     d_window_priv_t *w = (d_window_priv_t*)pubw;
293     if (w->waiting_geom)
294         window_get_geometry_reply(w);
295     return w->argb;
296 }
297
298 xcb_visualid_t
299 window_get_visual(d_window_t *pubw)
300 {
301     d_window_priv_t *w = (d_window_priv_t*)pubw;
302     if (w->waiting_attr)
303         window_get_attributes_reply(w);
304     return w->visual;
305 }
306
307 void
308 window_configure(d_window_t *pubw, int x, int y, int width, int height,
309                  int border_width)
310 {
311     d_window_priv_t *w = (d_window_priv_t*)pubw;
312
313     /* this overrides any reply from our get_geometry call */
314     if (w->waiting_geom)
315         w->waiting_geom = FALSE;
316     w->x = x;
317     w->y = y;
318     w->w = width;
319     w->h = height;
320     w->bw = border_width;
321 }
322
323 void
324 window_move(d_window_t *w)
325 {
326     (void)w;
327 }
328
329 void
330 window_resize(d_window_t *w)
331 {
332     window_update_pixmap((d_window_priv_t*)w);
333 }
334
335 void
336 window_add_plugin_data(d_window_t *pubw, int id, void *data)
337 {
338     d_window_priv_t *w = (d_window_priv_t*)pubw;
339     plugin_data_add(w->plugin_data, id, data);
340 }
341
342 void*
343 window_find_plugin_data(d_window_t *pubw, int id)
344 {
345     d_window_priv_t *w = (d_window_priv_t*)pubw;
346     return plugin_data_find(w->plugin_data, id);
347 }
348
349 void
350 window_remove_plugin_data(d_window_t *pubw, int id)
351 {
352     d_window_priv_t *w = (d_window_priv_t*)pubw;
353     plugin_data_remove(w->plugin_data, id);
354 }
355
356 void
357 window_create_damage(d_window_t *pubw)
358 {
359     d_window_priv_t *w = (d_window_priv_t*)pubw;
360
361     if (!window_is_input_only(pubw)) {
362         assert(w->damage == XCB_NONE);
363         w->damage = xcb_generate_id(w->sc->dpy->conn);
364         //printf("creating damage 0x%x\n", w->damage);
365         xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
366                           XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
367     }
368 }
369
370 void window_destroy_damage(d_window_t *pubw)
371 {
372     d_window_priv_t *w = (d_window_priv_t*)pubw;
373
374     if (w->damage) {
375         //printf("destroying damage 0x%x\n", w->damage);
376         xcb_damage_destroy(w->sc->dpy->conn, w->damage);
377         w->damage = XCB_NONE;
378     }
379 }