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