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