fix some more memory problems
[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         mapped;
25     gboolean         input_only;
26     xcb_visualid_t   visual;
27     xcb_pixmap_t     pixmap;
28
29     double           opacity;
30
31     gboolean         zombie;
32
33     d_list_t        *plugin_data;
34
35     xcb_damage_damage_t damage;
36
37     gboolean waiting_attr;
38     xcb_get_window_attributes_cookie_t ck_get_attr;
39     gboolean waiting_geom;
40     xcb_get_geometry_cookie_t          ck_get_geom;
41     gboolean waiting_pixmap;
42     xcb_void_cookie_t                  ck_get_pixmap;
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->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->waiting_pixmap = FALSE;
70
71     w->plugin_data = list_new();
72
73     //printf("new window 0x%x\n", w->id);
74
75     return (d_window_t*)w;
76 }
77
78 void
79 window_ref(d_window_t *pubw)
80 {
81     d_window_priv_t *w = (d_window_priv_t*)pubw;
82
83     ++w->ref;
84 }
85
86 void
87 window_unref(d_window_t *pubw)
88 {
89     d_window_priv_t *w = (d_window_priv_t*)pubw;
90
91     if (w && --w->ref == 0) {
92         xcb_pixmap_t p;
93
94         screen_stacking_remove(w->sc, (d_window_t*)w);
95
96         if ((p = window_get_pixmap(pubw))) {
97             xcb_free_pixmap(w->sc->dpy->conn, p);
98             w->pixmap = XCB_NONE;
99         }
100
101         list_unref(w->plugin_data);
102         free(w);
103     }
104 }
105
106 static void
107 window_update_pixmap(d_window_priv_t *w)
108 {
109     xcb_pixmap_t p;
110
111     if (window_is_zombie((d_window_t*)w)) return;
112
113     /* XXX can we save it for until we get the new pixmap? */
114     if ((p = window_get_pixmap((d_window_t*)w))) {
115         xcb_free_pixmap(w->sc->dpy->conn, p);
116         w->pixmap = XCB_NONE;
117     }
118
119     //printf("updating pixmap for 0x%x\n", w->id);
120
121     w->pixmap = xcb_generate_id(w->sc->dpy->conn);
122     w->ck_get_pixmap = 
123         xcb_composite_name_window_pixmap_checked(w->sc->dpy->conn,
124                                                  w->id, w->pixmap);
125     w->waiting_pixmap = TRUE;
126     xcb_flush(w->sc->dpy->conn);
127 }
128
129 void
130 window_show(d_window_t *pubw)
131 {
132     d_window_priv_t *w = (d_window_priv_t*)pubw;
133
134     window_is_mapped(pubw); /* kill any ongoing request */
135     assert(!w->mapped);
136
137     //printf("show window 0x%x\n", w->id);
138
139     window_update_pixmap(w);
140     w->mapped = TRUE;
141 }
142
143 void
144 window_hide(d_window_t *pubw)
145 {
146     d_window_priv_t *w = (d_window_priv_t*)pubw;
147
148     window_is_mapped(pubw); /* kill any ongoing request */
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->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->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     if (w->waiting_attr)
268         window_get_attributes_reply(w);
269     return w->mapped;
270 }
271
272 xcb_pixmap_t
273 window_get_pixmap(d_window_t *pubw)
274 {
275     d_window_priv_t *w = (d_window_priv_t*)pubw;
276
277     if (w->waiting_pixmap) {
278         xcb_generic_error_t *err;
279         //printf("** checking get pixmap 0x%x\n", w->id);
280         err = xcb_request_check(w->sc->dpy->conn, w->ck_get_pixmap);
281         if (err) {
282             w->pixmap = XCB_NONE;
283             printf("error getting named pixmap for window 0x%x\n", w->id);
284             free(err);
285         }
286         w->waiting_pixmap = FALSE;
287     }
288     //printf("returning pixmap 0x%x for window 0x%x\n", w->pixmap, w->id);
289     return w->pixmap;
290 }
291
292 xcb_visualid_t
293 window_get_visual(d_window_t *pubw)
294 {
295     d_window_priv_t *w = (d_window_priv_t*)pubw;
296     if (w->waiting_attr)
297         window_get_attributes_reply(w);
298     return w->visual;
299 }
300
301 void
302 window_configure(d_window_t *pubw, int x, int y, int width, int height,
303                  int border_width)
304 {
305     d_window_priv_t *w = (d_window_priv_t*)pubw;
306
307     /* this overrides any reply from our get_geometry call */
308     if (w->waiting_geom)
309         w->waiting_geom = FALSE;
310     w->x = x;
311     w->y = y;
312     w->w = width;
313     w->h = height;
314     w->bw = border_width;
315 }
316
317 void
318 window_move(d_window_t *w)
319 {
320     (void)w;
321 }
322
323 void
324 window_resize(d_window_t *w)
325 {
326     window_update_pixmap((d_window_priv_t*)w);
327 }
328
329 void
330 window_add_plugin_data(d_window_t *pubw, int id, void *data)
331 {
332     d_window_priv_t *w = (d_window_priv_t*)pubw;
333     plugin_data_add(w->plugin_data, id, data);
334 }
335
336 void*
337 window_find_plugin_data(d_window_t *pubw, int id)
338 {
339     d_window_priv_t *w = (d_window_priv_t*)pubw;
340     return plugin_data_find(w->plugin_data, id);
341 }
342
343 void
344 window_remove_plugin_data(d_window_t *pubw, int id)
345 {
346     d_window_priv_t *w = (d_window_priv_t*)pubw;
347     plugin_data_remove(w->plugin_data, id);
348 }
349
350 void
351 window_create_damage(d_window_t *pubw)
352 {
353     d_window_priv_t *w = (d_window_priv_t*)pubw;
354
355     if (!window_is_input_only(pubw)) {
356         assert(w->damage == XCB_NONE);
357         w->damage = xcb_generate_id(w->sc->dpy->conn);
358         //printf("creating damage 0x%x\n", w->damage);
359         xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
360                           XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
361     }
362 }
363
364 void window_destroy_damage(d_window_t *pubw)
365 {
366     d_window_priv_t *w = (d_window_priv_t*)pubw;
367
368     if (w->damage) {
369         //printf("destroying damage 0x%x\n", w->damage);
370         xcb_damage_destroy(w->sc->dpy->conn, w->damage);
371         w->damage = XCB_NONE;
372     }
373 }