make the select always prefer X events over the timeouts for painting. also don't...
[dana/dcompmgr.git] / window.c
1 #include "window.h"
2 #include "screen.h"
3 #include "display.h"
4 #include <stdlib.h>
5 #include <assert.h>
6 #include <stdio.h>
7 #include <xcb/composite.h>
8 #include <xcb/damage.h>
9
10 typedef struct {
11     /* public stuff */
12     xcb_window_t     id;
13     struct d_screen *sc;
14
15     /* private stuff */
16     int              ref;
17
18     /* queried things, don't read them directly from the struct */
19     int              x, y, w, h, bw;
20     gboolean         mapped;
21     gboolean         input_only;
22     xcb_visualid_t   visual;
23     xcb_pixmap_t     pixmap;
24
25     gboolean         zombie;
26
27     GHashTable      *plugin_data;
28
29     xcb_damage_damage_t damage;
30
31     xcb_get_window_attributes_cookie_t ck_get_attr;
32     xcb_get_geometry_cookie_t          ck_get_geom;
33     xcb_void_cookie_t                  ck_get_pixmap;
34 } d_window_priv_t;
35
36 static void window_get_attributes_reply(d_window_priv_t *w);
37 static void window_get_geometry_reply(d_window_priv_t *w);
38
39 d_window_t*
40 window_new(xcb_window_t id, struct d_screen *sc)
41 {
42     d_window_priv_t *w;
43
44     w = malloc(sizeof(d_window_priv_t));
45     w->id = id;
46     w->ref = 1;
47     w->sc = sc;
48     w->zombie = FALSE;
49     w->pixmap = XCB_NONE;
50     w->damage = XCB_NONE;
51
52     screen_stacking_add(sc, (d_window_t*)w);
53
54     w->ck_get_attr = xcb_get_window_attributes(sc->dpy->conn, id);
55     w->ck_get_geom = xcb_get_geometry(sc->dpy->conn, id);
56
57     w->ck_get_pixmap.sequence = 0;
58
59     w->plugin_data = g_hash_table_new_full((GHashFunc)g_str_hash,
60                                            (GEqualFunc)g_str_equal,
61                                            g_free, NULL);
62
63     //printf("new window 0x%x\n", w->id);
64
65     return (d_window_t*)w;
66 }
67
68 void
69 window_ref(d_window_t *pubw)
70 {
71     d_window_priv_t *w = (d_window_priv_t*)pubw;
72
73     ++w->ref;
74 }
75
76 void
77 window_unref(d_window_t *pubw)
78 {
79     d_window_priv_t *w = (d_window_priv_t*)pubw;
80
81     if (w && --w->ref == 0) {
82         xcb_pixmap_t p;
83
84         screen_stacking_remove(w->sc, (d_window_t*)w);
85
86         if ((p = window_get_pixmap(pubw))) {
87             xcb_free_pixmap(w->sc->dpy->conn, p);
88             w->pixmap = XCB_NONE;
89         }
90
91         g_hash_table_unref(w->plugin_data);
92         free(w);
93     }
94 }
95
96 static void
97 window_update_pixmap(d_window_priv_t *w)
98 {
99     xcb_pixmap_t p;
100
101     /* XXX can we save it for until we get the new pixmap? */
102     if ((p = window_get_pixmap((d_window_t*)w))) {
103         xcb_free_pixmap(w->sc->dpy->conn, p);
104         w->pixmap = XCB_NONE;
105     }
106
107     //printf("updating pixmap for 0x%x\n", w->id);
108
109     w->pixmap = xcb_generate_id(w->sc->dpy->conn);
110     w->ck_get_pixmap = 
111         xcb_composite_name_window_pixmap_checked(w->sc->dpy->conn,
112                                                  w->id, w->pixmap);
113     xcb_flush(w->sc->dpy->conn);
114 }
115
116 void
117 window_show(d_window_t *pubw)
118 {
119     d_window_priv_t *w = (d_window_priv_t*)pubw;
120
121     window_is_mapped(pubw); /* kill any ongoing request */
122
123     //printf("show window 0x%x\n", w->id);
124
125     window_update_pixmap(w);
126     w->mapped = TRUE;
127 }
128
129 void
130 window_hide(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("hide window 0x%x\n", w->id);
137
138     w->mapped = FALSE;
139 }
140
141 void
142 window_become_zombie(d_window_t *pubw)
143 {
144     d_window_priv_t *w = (d_window_priv_t*)pubw;
145
146     if (w->zombie) return;
147
148     w->zombie = TRUE;
149 }
150
151 gboolean
152 window_is_zombie(d_window_t *pubw)
153 {
154     d_window_priv_t *w = (d_window_priv_t*)pubw;
155     return w->zombie;
156 }
157
158 gboolean
159 window_is_input_only(d_window_t *pubw)
160 {
161     d_window_priv_t *w = (d_window_priv_t*)pubw;
162     if (w->ck_get_attr.sequence)
163         window_get_attributes_reply(w);
164     return w->input_only;
165 }
166
167 void
168 window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
169                 int *border_width)
170 {
171     d_window_priv_t *w = (d_window_priv_t*)pubw;
172     if (w->ck_get_geom.sequence)
173         window_get_geometry_reply(w);
174     *x = w->x;
175     *y = w->y;
176     *width = w->w;
177     *height = w->h;
178     *border_width = w->bw;
179 }
180
181 static void
182 window_get_attributes_reply(d_window_priv_t *w)
183 {
184     xcb_get_window_attributes_reply_t *rep;
185     xcb_generic_error_t *err = NULL;
186
187     rep = xcb_get_window_attributes_reply(w->sc->dpy->conn,
188                                           w->ck_get_attr,
189                                           &err);
190
191     if (rep) {
192         w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
193         w->mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
194         w->visual = rep->visual;
195         free(rep);
196     }
197     else {
198         w->input_only = TRUE;
199         w->mapped = FALSE;
200         w->visual = XCB_NONE;
201     }
202     if (err) {
203         printf("error getting attributes for window 0x%x\n", w->id);
204         free(err);
205     }
206     w->ck_get_attr.sequence = 0;
207 }
208
209 static void
210 window_get_geometry_reply(d_window_priv_t *w)
211 {
212     xcb_get_geometry_reply_t *rep;
213     xcb_generic_error_t *err = NULL;
214
215     rep = xcb_get_geometry_reply(w->sc->dpy->conn,
216                                  w->ck_get_geom,
217                                  &err);
218
219     if (rep) {
220         w->x = rep->x;
221         w->y = rep->y;
222         w->w = rep->width;
223         w->h = rep->height;
224         w->bw = rep->border_width;
225         free(rep);
226     }
227     else {
228         w->x = w->y = -1;
229         w->w = w->h = 1;
230         w->bw = 0;
231     }
232     if (err) {
233         printf("error getting geometry for window 0x%x\n", w->id);
234         free(err);
235     }
236     w->ck_get_geom.sequence = 0;
237 }
238
239 gboolean
240 window_is_mapped(d_window_t *pubw)
241 {
242     d_window_priv_t *w = (d_window_priv_t*)pubw;
243     if (w->ck_get_attr.sequence)
244         window_get_attributes_reply(w);
245     return w->mapped;
246 }
247
248 xcb_pixmap_t
249 window_get_pixmap(d_window_t *pubw)
250 {
251     d_window_priv_t *w = (d_window_priv_t*)pubw;
252
253     if (w->ck_get_pixmap.sequence) {
254         xcb_generic_error_t *err;
255         //printf("** checking get pixmap 0x%x\n", w->id);
256         err = xcb_request_check(w->sc->dpy->conn, w->ck_get_pixmap);
257         if (err) {
258             w->pixmap = XCB_NONE;
259             printf("error getting named pixmap for window 0x%x\n", w->id);
260             free(err);
261         }
262         w->ck_get_pixmap.sequence = 0;
263     }
264     //printf("returning pixmap 0x%x for window 0x%x\n", w->pixmap, w->id);
265     return w->pixmap;
266 }
267
268 xcb_visualid_t
269 window_get_visual(d_window_t *pubw)
270 {
271     d_window_priv_t *w = (d_window_priv_t*)pubw;
272     if (w->ck_get_attr.sequence)
273         window_get_attributes_reply(w);
274     return w->visual;
275 }
276
277 void
278 window_configure(d_window_t *pubw, int x, int y, int width, int height,
279                  int border_width)
280 {
281     d_window_priv_t *w = (d_window_priv_t*)pubw;
282
283     /* this overrides any reply from our get_geometry call */
284     if (w->ck_get_geom.sequence)
285         w->ck_get_geom.sequence = 0;
286     w->x = x;
287     w->y = y;
288     w->w = width;
289     w->h = height;
290     w->bw = border_width;
291 }
292
293 void
294 window_reconfigure(d_window_t *w)
295 {
296     window_update_pixmap((d_window_priv_t*)w);
297 }
298
299 void
300 window_add_plugin_data(d_window_t *pubw, const char *key, void *data)
301 {
302     d_window_priv_t *w = (d_window_priv_t*)pubw;
303     char *skey = g_strdup(key);
304     g_hash_table_replace(w->plugin_data, skey, data);
305 }
306
307 void*
308 window_find_plugin_data(d_window_t *pubw, const char *key)
309 {
310     d_window_priv_t *w = (d_window_priv_t*)pubw;
311     return g_hash_table_lookup(w->plugin_data, key);
312 }
313
314 void
315 window_remove_plugin_data(d_window_t *pubw, const char *key)
316 {
317     d_window_priv_t *w = (d_window_priv_t*)pubw;
318     g_hash_table_remove(w->plugin_data, key);
319 }
320
321 void
322 window_create_damage(d_window_t *pubw)
323 {
324     d_window_priv_t *w = (d_window_priv_t*)pubw;
325
326     if (!window_is_input_only(pubw)) {
327         assert(w->damage == XCB_NONE);
328         w->damage = xcb_generate_id(w->sc->dpy->conn);
329         xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
330                           XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
331     }
332 }
333
334 void window_destroy_damage(d_window_t *pubw)
335 {
336     d_window_priv_t *w = (d_window_priv_t*)pubw;
337
338     if (w->damage) {
339         xcb_damage_destroy(w->sc->dpy->conn, w->damage);
340         w->damage = XCB_NONE;
341     }
342 }