f4a97a95dbf3975e6a0349f8979d97424b586e29
[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
136     //printf("show window 0x%x\n", w->id);
137
138     window_update_pixmap(w);
139     w->mapped = TRUE;
140 }
141
142 void
143 window_hide(d_window_t *pubw)
144 {
145     d_window_priv_t *w = (d_window_priv_t*)pubw;
146
147     window_is_mapped(pubw); /* kill any ongoing request */
148
149     //printf("hide window 0x%x\n", w->id);
150
151     w->mapped = FALSE;
152 }
153
154 void
155 window_become_zombie(d_window_t *pubw)
156 {
157     d_window_priv_t *w = (d_window_priv_t*)pubw;
158
159     if (w->zombie) return;
160
161     w->zombie = TRUE;
162 }
163
164 gboolean
165 window_is_zombie(d_window_t *pubw)
166 {
167     d_window_priv_t *w = (d_window_priv_t*)pubw;
168     return w->zombie;
169 }
170
171 gboolean
172 window_is_input_only(d_window_t *pubw)
173 {
174     d_window_priv_t *w = (d_window_priv_t*)pubw;
175     if (w->waiting_attr)
176         window_get_attributes_reply(w);
177     return w->input_only;
178 }
179
180 void
181 window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
182                 int *border_width)
183 {
184     d_window_priv_t *w = (d_window_priv_t*)pubw;
185     if (w->waiting_geom)
186         window_get_geometry_reply(w);
187     *x = w->x;
188     *y = w->y;
189     *width = w->w;
190     *height = w->h;
191     *border_width = w->bw;
192 }
193
194 static void
195 window_get_attributes_reply(d_window_priv_t *w)
196 {
197     xcb_get_window_attributes_reply_t *rep;
198     xcb_generic_error_t *err = NULL;
199
200     rep = xcb_get_window_attributes_reply(w->sc->dpy->conn,
201                                           w->ck_get_attr,
202                                           &err);
203
204     if (rep) {
205         w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
206         w->mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
207         w->visual = rep->visual;
208         free(rep);
209     }
210     else {
211         w->input_only = TRUE;
212         w->mapped = FALSE;
213         w->visual = XCB_NONE;
214     }
215     if (err) {
216         printf("error getting attributes for window 0x%x\n", w->id);
217         free(err);
218     }
219     w->waiting_attr = 0;
220 }
221
222 static void
223 window_get_geometry_reply(d_window_priv_t *w)
224 {
225     xcb_get_geometry_reply_t *rep;
226     xcb_generic_error_t *err = NULL;
227
228     rep = xcb_get_geometry_reply(w->sc->dpy->conn,
229                                  w->ck_get_geom,
230                                  &err);
231
232     if (rep) {
233         w->x = rep->x;
234         w->y = rep->y;
235         w->w = rep->width;
236         w->h = rep->height;
237         w->bw = rep->border_width;
238         free(rep);
239     }
240     else {
241         w->x = w->y = -1;
242         w->w = w->h = 1;
243         w->bw = 0;
244     }
245     if (err) {
246         printf("error getting geometry for window 0x%x\n", w->id);
247         free(err);
248     }
249     w->waiting_geom = 0;
250 }
251
252 gboolean
253 window_is_mapped(d_window_t *pubw)
254 {
255     d_window_priv_t *w = (d_window_priv_t*)pubw;
256     if (w->waiting_attr)
257         window_get_attributes_reply(w);
258     return w->mapped;
259 }
260
261 xcb_pixmap_t
262 window_get_pixmap(d_window_t *pubw)
263 {
264     d_window_priv_t *w = (d_window_priv_t*)pubw;
265
266     if (w->waiting_pixmap) {
267         xcb_generic_error_t *err;
268         //printf("** checking get pixmap 0x%x\n", w->id);
269         err = xcb_request_check(w->sc->dpy->conn, w->ck_get_pixmap);
270         if (err) {
271             w->pixmap = XCB_NONE;
272             printf("error getting named pixmap for window 0x%x\n", w->id);
273             free(err);
274         }
275         w->waiting_pixmap = FALSE;
276     }
277     //printf("returning pixmap 0x%x for window 0x%x\n", w->pixmap, w->id);
278     return w->pixmap;
279 }
280
281 xcb_visualid_t
282 window_get_visual(d_window_t *pubw)
283 {
284     d_window_priv_t *w = (d_window_priv_t*)pubw;
285     if (w->waiting_attr)
286         window_get_attributes_reply(w);
287     return w->visual;
288 }
289
290 void
291 window_configure(d_window_t *pubw, int x, int y, int width, int height,
292                  int border_width)
293 {
294     d_window_priv_t *w = (d_window_priv_t*)pubw;
295
296     /* this overrides any reply from our get_geometry call */
297     if (w->waiting_geom)
298         w->waiting_geom = FALSE;
299     w->x = x;
300     w->y = y;
301     w->w = width;
302     w->h = height;
303     w->bw = border_width;
304 }
305
306 void
307 window_move(d_window_t *w)
308 {
309     (void)w;
310 }
311
312 void
313 window_resize(d_window_t *w)
314 {
315     window_update_pixmap((d_window_priv_t*)w);
316 }
317
318 void
319 window_add_plugin_data(d_window_t *pubw, int id, void *data)
320 {
321     d_window_priv_t *w = (d_window_priv_t*)pubw;
322     plugin_data_add(w->plugin_data, id, data);
323 }
324
325 void*
326 window_find_plugin_data(d_window_t *pubw, int id)
327 {
328     d_window_priv_t *w = (d_window_priv_t*)pubw;
329     return plugin_data_find(w->plugin_data, id);
330 }
331
332 void
333 window_remove_plugin_data(d_window_t *pubw, int id)
334 {
335     d_window_priv_t *w = (d_window_priv_t*)pubw;
336     plugin_data_remove(w->plugin_data, id);
337 }
338
339 void
340 window_create_damage(d_window_t *pubw)
341 {
342     d_window_priv_t *w = (d_window_priv_t*)pubw;
343
344     if (!window_is_input_only(pubw)) {
345         assert(w->damage == XCB_NONE);
346         w->damage = xcb_generate_id(w->sc->dpy->conn);
347         //printf("creating damage 0x%x\n", w->damage);
348         xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
349                           XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
350     }
351 }
352
353 void window_destroy_damage(d_window_t *pubw)
354 {
355     d_window_priv_t *w = (d_window_priv_t*)pubw;
356
357     if (w->damage) {
358         //printf("destroying damage 0x%x\n", w->damage);
359         xcb_damage_destroy(w->sc->dpy->conn, w->damage);
360         w->damage = XCB_NONE;
361     }
362 }