11 #include <xcb/composite.h>
12 #include <xcb/damage.h>
22 /* queried things, don't read them directly from the struct */
27 xcb_visualid_t visual;
29 xcb_xfixes_region_t region;
31 /* the window id where we got the window type from. further property
32 queries should go to this window */
35 /* opacity is from 0xffff to 0 */
41 d_list_t *plugin_data;
43 xcb_damage_damage_t damage;
45 gboolean waiting_attr;
46 xcb_get_window_attributes_cookie_t ck_get_attr;
47 gboolean waiting_geom;
48 xcb_get_geometry_cookie_t ck_get_geom;
51 static void window_get_attributes_reply(d_window_priv_t *w);
52 static void window_get_geometry_reply(d_window_priv_t *w);
53 static void window_update_pixmap(d_window_priv_t *w);
54 static void window_update_region(d_window_priv_t *w);
55 static void window_update_type(d_window_priv_t *w);
58 window_new(xcb_window_t id, struct d_screen *sc)
62 w = malloc(sizeof(d_window_priv_t));
71 w->type = DC_WINDOW_TYPE_INVALID;
74 screen_stacking_add(sc, (d_window_t*)w);
76 w->ck_get_attr = xcb_get_window_attributes(sc->dpy->conn, id);
77 w->waiting_attr = TRUE;
79 w->ck_get_geom = xcb_get_geometry(sc->dpy->conn, id);
80 w->waiting_geom = TRUE;
82 w->plugin_data = list_new();
84 //printf("new window 0x%x\n", w->id);
86 return (d_window_t*)w;
90 window_ref(d_window_t *pubw)
92 d_window_priv_t *w = (d_window_priv_t*)pubw;
98 window_unref(d_window_t *pubw)
100 d_window_priv_t *w = (d_window_priv_t*)pubw;
102 if (w && --w->ref == 0) {
103 screen_stacking_remove(w->sc, (d_window_t*)w);
106 xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
107 w->region = XCB_NONE;
111 /* this may cause an error if the pixmap was never valid, but
113 xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
114 w->pixmap = XCB_NONE;
117 list_unref(w->plugin_data);
123 window_get_pixmap(d_window_t *pubw)
125 d_window_priv_t *w = (d_window_priv_t*)pubw;
131 window_update_region(d_window_priv_t *w)
133 int x, y, wi, hei, bw;
135 if (window_is_zombie((d_window_t*)w)) return;
138 xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
139 w->region = XCB_NONE;
142 w->region = xcb_generate_id(w->sc->dpy->conn);
143 xcb_xfixes_create_region_from_window(w->sc->dpy->conn, w->region,
144 w->id, XCB_SHAPE_SK_BOUNDING);
145 window_get_area((d_window_t*)w, &x, &y, &wi, &hei, &bw);
146 xcb_xfixes_translate_region(w->sc->dpy->conn, w->region, x+bw, y+bw);
150 window_update_pixmap(d_window_priv_t *w)
152 if (window_is_zombie((d_window_t*)w)) return;
154 /* the pixmap may not be valid even though it is non-zero, but
155 we can free it anyways and let it fail. we don't need to wait
156 for a response from the server */
158 xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
159 w->pixmap = XCB_NONE;
162 //printf("updating pixmap for 0x%x\n", w->id);
164 /* we don't check the result of this call, because it seems that sometimes
165 the X server just doesn't reply. if we check it, we end up hanging
166 sometimes waiting for the reply */
167 w->pixmap = xcb_generate_id(w->sc->dpy->conn);
168 xcb_composite_name_window_pixmap(w->sc->dpy->conn, w->id, w->pixmap);
169 //printf("requested pixmap sequence %u\n", w->ck_get_pixmap.sequence);
171 xcb_flush(w->sc->dpy->conn);
175 window_show(d_window_t *pubw)
177 d_window_priv_t *w = (d_window_priv_t*)pubw;
181 //printf("show window 0x%x\n", w->id);
183 /* make sure this is before we update the window's region */
184 if (w->sc->dpy->shape.present)
185 xcb_shape_select_input(w->sc->dpy->conn, w->id, TRUE);
187 window_update_pixmap(w);
188 window_update_region(w);
189 window_update_type(w);
194 window_hide(d_window_t *pubw)
196 d_window_priv_t *w = (d_window_priv_t*)pubw;
200 //printf("hide window 0x%x\n", w->id);
201 if (w->sc->dpy->shape.present)
202 xcb_shape_select_input(w->sc->dpy->conn, w->id, FALSE);
208 window_fake_unmapped(d_window_t *pubw)
210 d_window_priv_t *w = (d_window_priv_t*)pubw;
216 window_become_zombie(d_window_t *pubw)
218 d_window_priv_t *w = (d_window_priv_t*)pubw;
220 if (w->zombie) return;
226 window_is_zombie(d_window_t *pubw)
228 d_window_priv_t *w = (d_window_priv_t*)pubw;
233 window_is_input_only(d_window_t *pubw)
235 d_window_priv_t *w = (d_window_priv_t*)pubw;
237 window_get_attributes_reply(w);
238 return w->input_only;
242 window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
245 d_window_priv_t *w = (d_window_priv_t*)pubw;
247 window_get_geometry_reply(w);
252 *border_width = w->bw;
256 window_get_attributes_reply(d_window_priv_t *w)
258 xcb_get_window_attributes_reply_t *rep;
259 xcb_generic_error_t *err = NULL;
261 rep = xcb_get_window_attributes_reply(w->sc->dpy->conn,
266 w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
267 w->attr_mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
268 w->visual = rep->visual;
269 //printf("0x%x attributes mapped %d\n", w->id, w->mapped);
273 w->input_only = TRUE;
274 w->attr_mapped = FALSE;
275 w->visual = XCB_NONE;
278 printf("error getting attributes for window 0x%x\n", w->id);
281 w->waiting_attr = FALSE;
285 window_get_geometry_reply(d_window_priv_t *w)
287 xcb_get_geometry_reply_t *rep;
288 xcb_generic_error_t *err = NULL;
290 rep = xcb_get_geometry_reply(w->sc->dpy->conn,
299 w->bw = rep->border_width;
300 w->argb = rep->depth == 32;
310 printf("error getting geometry for window 0x%x\n", w->id);
313 w->waiting_geom = FALSE;
317 window_is_mapped(d_window_t *pubw)
319 d_window_priv_t *w = (d_window_priv_t*)pubw;
324 window_is_attr_mapped(d_window_t *pubw)
326 d_window_priv_t *w = (d_window_priv_t*)pubw;
328 window_get_attributes_reply(w);
329 return w->attr_mapped;
333 window_is_argb(d_window_t *pubw)
335 d_window_priv_t *w = (d_window_priv_t*)pubw;
337 window_get_geometry_reply(w);
342 window_get_visual(d_window_t *pubw)
344 d_window_priv_t *w = (d_window_priv_t*)pubw;
346 window_get_attributes_reply(w);
351 window_get_region(d_window_t *pubw)
353 d_window_priv_t *w = (d_window_priv_t*)pubw;
359 window_configure(d_window_t *pubw, int x, int y, int width, int height,
362 d_window_priv_t *w = (d_window_priv_t*)pubw;
364 /* this overrides any reply from our get_geometry call */
366 w->waiting_geom = FALSE;
371 w->bw = border_width;
375 window_move(d_window_t *pubw)
377 //d_window_priv_t *w = (d_window_priv_t*)pubw;
378 window_update_region((d_window_priv_t*)pubw);
382 window_resize(d_window_t *w)
384 window_update_pixmap((d_window_priv_t*)w);
385 window_update_region((d_window_priv_t*)w);
389 window_reshape(d_window_t *w)
391 window_update_region((d_window_priv_t*)w);
394 void window_opacity_change(d_window_t *w)
400 window_add_plugin_data(d_window_t *pubw, int id, void *data)
402 d_window_priv_t *w = (d_window_priv_t*)pubw;
403 plugin_data_add(w->plugin_data, id, data);
407 window_find_plugin_data(d_window_t *pubw, int id)
409 d_window_priv_t *w = (d_window_priv_t*)pubw;
410 return plugin_data_find(w->plugin_data, id);
414 window_remove_plugin_data(d_window_t *pubw, int id)
416 d_window_priv_t *w = (d_window_priv_t*)pubw;
417 plugin_data_remove(w->plugin_data, id);
421 window_create_damage(d_window_t *pubw)
423 d_window_priv_t *w = (d_window_priv_t*)pubw;
425 if (!window_is_input_only(pubw)) {
426 assert(w->damage == XCB_NONE);
427 w->damage = xcb_generate_id(w->sc->dpy->conn);
428 //printf("creating damage 0x%x\n", w->damage);
429 xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
430 XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
435 window_destroy_damage(d_window_t *pubw)
437 d_window_priv_t *w = (d_window_priv_t*)pubw;
440 //printf("destroying damage 0x%x\n", w->damage);
441 xcb_damage_destroy(w->sc->dpy->conn, w->damage);
442 w->damage = XCB_NONE;
447 type_request(d_display_t *dpy, d_window_priv_t *w, xcb_window_t *id, int nid)
449 xcb_get_property_cookie_t *cks;
452 cks = malloc(sizeof(xcb_get_property_cookie_t) * nid * 2);
453 for (i = 0; i < nid; ++i) {
455 xcb_get_property_unchecked(dpy->conn, FALSE, id[i],
456 dpy->a.net_wm_window_type,
459 xcb_get_property_unchecked(dpy->conn, FALSE, id[i],
460 dpy->a.wm_transient_for,
461 dpy->a.window, 0, 1);
464 for (i = 0; i < nid; ++i) {
465 xcb_get_property_reply_t *rep;
466 d_window_type_t type = DC_WINDOW_TYPE_INVALID;
468 rep = xcb_get_property_reply(dpy->conn, cks[i*2+0], NULL);
470 if (!w->type && rep->type == dpy->a.atom && rep->length >= 1) {
471 xcb_atom_t *a = (xcb_atom_t*)(xcb_get_property_value(rep));
473 for (j = 0; j < rep->length; ++j) {
474 if (a[j] == dpy->a.net_wm_window_type_normal) {
475 type = DC_WINDOW_TYPE_NORMAL; break;
477 if (a[j] == dpy->a.net_wm_window_type_desktop) {
478 type = DC_WINDOW_TYPE_DESKTOP; break;
480 if (a[j] == dpy->a.net_wm_window_type_dock) {
481 type = DC_WINDOW_TYPE_DOCK; break;
483 if (a[j] == dpy->a.net_wm_window_type_dialog) {
484 type = DC_WINDOW_TYPE_DIALOG; break;
486 if (a[j] == dpy->a.net_wm_window_type_toolbar) {
487 type = DC_WINDOW_TYPE_TOOLBAR; break;
489 if (a[j] == dpy->a.net_wm_window_type_menu) {
490 type = DC_WINDOW_TYPE_MENU; break;
492 if (a[j] == dpy->a.net_wm_window_type_utility) {
493 type = DC_WINDOW_TYPE_UTILITY; break;
495 if (a[j] == dpy->a.net_wm_window_type_splash) {
496 type = DC_WINDOW_TYPE_SPLASH; break;
498 if (a[j] == dpy->a.net_wm_window_type_dropdown_menu) {
499 type = DC_WINDOW_TYPE_DROPDOWN_MENU; break;
501 if (a[j] == dpy->a.net_wm_window_type_popup_menu) {
502 type = DC_WINDOW_TYPE_POPUP_MENU; break;
504 if (a[j] == dpy->a.net_wm_window_type_tooltip) {
505 type = DC_WINDOW_TYPE_TOOLTIP; break;
507 if (a[j] == dpy->a.net_wm_window_type_notification) {
508 type = DC_WINDOW_TYPE_NOTIFICATION; break;
510 if (a[j] == dpy->a.net_wm_window_type_combo) {
511 type = DC_WINDOW_TYPE_COMBO; break;
513 if (a[j] == dpy->a.net_wm_window_type_dnd) {
514 type = DC_WINDOW_TYPE_DND; break;
520 rep = xcb_get_property_reply(dpy->conn, cks[i*2+1], NULL);
522 if (!w->type && rep->type == dpy->a.window && rep->length == 1)
523 type = DC_WINDOW_TYPE_DIALOG;
527 /* also save the window id that we got the type/transient hint from */
528 if (!w->type && type) {
535 for (i = 0; i < nid && !w->type; ++i) {
536 xcb_query_tree_cookie_t ck;
537 xcb_query_tree_reply_t *rep;
539 ck = xcb_query_tree(dpy->conn, id[i]);
540 rep = xcb_query_tree_reply(dpy->conn, ck, NULL);
542 int num = xcb_query_tree_children_length(rep);
543 xcb_window_t *ch = xcb_query_tree_children(rep);
545 type_request(dpy, w, ch, num);
552 window_update_type(d_window_priv_t *w)
554 w->type = DC_WINDOW_TYPE_INVALID;
555 type_request(w->sc->dpy, w, &w->id, 1);
557 w->type = DC_WINDOW_TYPE_NORMAL;
561 printf("window 0x%x type %d\n", w->id, w->type);
565 window_get_type(d_window_t *pubw)
567 d_window_priv_t *w = (d_window_priv_t*)pubw;
573 window_get_opacity(d_window_t *pubw)
575 d_window_priv_t *w = (d_window_priv_t*)pubw;
581 window_set_opacity(d_window_t *pubw, uint16_t o)
583 d_window_priv_t *w = (d_window_priv_t*)pubw;
587 w->sc->window_opacity_change(pubw);