11 #include <xcb/composite.h>
12 #include <xcb/damage.h>
14 #define TOPLEVEL_WINDOW_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE)
24 /* queried things, don't read them directly from the struct */
29 xcb_visualid_t visual;
31 xcb_xfixes_region_t region;
33 /* the window id where we got the window type from. further property
34 queries should go to this window */
37 /* opacity is from 0xffff to 0, these 2 are combined to give the final
39 uint16_t opacity; /* this one is set by plugins/settings */
40 uint16_t user_opacity; /* this one is set by the user */
45 d_list_t *plugin_data;
47 xcb_damage_damage_t damage;
49 gboolean waiting_attr;
50 xcb_get_window_attributes_cookie_t ck_get_attr;
51 gboolean waiting_geom;
52 xcb_get_geometry_cookie_t ck_get_geom;
53 gboolean waiting_opac;
54 xcb_get_property_cookie_t ck_get_opac;
57 static void window_get_attributes_reply(d_window_priv_t *w);
58 static void window_get_geometry_reply(d_window_priv_t *w);
59 static void window_update_pixmap(d_window_priv_t *w);
60 static void window_update_region(d_window_priv_t *w);
61 static void window_update_type(d_window_priv_t *w);
64 window_new(xcb_window_t id, struct d_screen *sc)
68 w = malloc(sizeof(d_window_priv_t));
77 w->type = DC_WINDOW_TYPE_INVALID;
79 w->user_opacity = 0xffff;
81 screen_stacking_add(sc, (d_window_t*)w);
83 w->ck_get_attr = xcb_get_window_attributes(sc->dpy->conn, id);
84 w->waiting_attr = TRUE;
86 w->ck_get_geom = xcb_get_geometry(sc->dpy->conn, id);
87 w->waiting_geom = TRUE;
89 w->plugin_data = list_new();
91 //printf("new window 0x%x\n", w->id);
93 return (d_window_t*)w;
97 window_ref(d_window_t *pubw)
99 d_window_priv_t *w = (d_window_priv_t*)pubw;
105 window_unref(d_window_t *pubw)
107 d_window_priv_t *w = (d_window_priv_t*)pubw;
109 if (w && --w->ref == 0) {
110 screen_stacking_remove(w->sc, (d_window_t*)w);
113 xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
114 w->region = XCB_NONE;
118 /* this may cause an error if the pixmap was never valid, but
120 xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
121 w->pixmap = XCB_NONE;
124 list_unref(w->plugin_data);
130 window_get_pixmap(d_window_t *pubw)
132 d_window_priv_t *w = (d_window_priv_t*)pubw;
138 window_update_user_opacity(d_window_t *pubw)
140 d_window_priv_t *w = (d_window_priv_t*)pubw;
143 xcb_get_property(w->sc->dpy->conn, FALSE, w->id,
144 w->sc->dpy->a.net_wm_window_opacity,
145 w->sc->dpy->a.cardinal, 0, 1);
146 w->waiting_opac = TRUE;
150 window_update_region(d_window_priv_t *w)
152 int x, y, wi, hei, bw;
154 if (window_is_zombie((d_window_t*)w)) return;
157 xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
158 w->region = XCB_NONE;
161 w->region = xcb_generate_id(w->sc->dpy->conn);
162 xcb_xfixes_create_region_from_window(w->sc->dpy->conn, w->region,
163 w->id, XCB_SHAPE_SK_BOUNDING);
164 window_get_area((d_window_t*)w, &x, &y, &wi, &hei, &bw);
165 xcb_xfixes_translate_region(w->sc->dpy->conn, w->region, x+bw, y+bw);
169 window_update_pixmap(d_window_priv_t *w)
171 if (window_is_zombie((d_window_t*)w)) return;
173 /* the pixmap may not be valid even though it is non-zero, but
174 we can free it anyways and let it fail. we don't need to wait
175 for a response from the server */
177 xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
178 w->pixmap = XCB_NONE;
181 //printf("updating pixmap for 0x%x\n", w->id);
183 /* we don't check the result of this call, because it seems that sometimes
184 the X server just doesn't reply. if we check it, we end up hanging
185 sometimes waiting for the reply */
186 w->pixmap = xcb_generate_id(w->sc->dpy->conn);
187 xcb_composite_name_window_pixmap(w->sc->dpy->conn, w->id, w->pixmap);
188 //printf("requested pixmap sequence %u\n", w->ck_get_pixmap.sequence);
190 xcb_flush(w->sc->dpy->conn);
194 window_show(d_window_t *pubw)
196 d_window_priv_t *w = (d_window_priv_t*)pubw;
201 //printf("show window 0x%x\n", w->id);
203 /* make sure this is before we update the window's region */
204 if (w->sc->dpy->shape.present)
205 xcb_shape_select_input(w->sc->dpy->conn, w->id, TRUE);
207 mask = TOPLEVEL_WINDOW_EVENT_MASK;
208 xcb_change_window_attributes(w->sc->dpy->conn, w->id,
209 XCB_CW_EVENT_MASK, &mask);
211 window_update_pixmap(w);
212 window_update_region(w);
213 window_update_user_opacity(pubw);
214 window_update_type(w);
219 window_hide(d_window_t *pubw)
221 d_window_priv_t *w = (d_window_priv_t*)pubw;
226 //printf("hide window 0x%x\n", w->id);
227 if (w->sc->dpy->shape.present)
228 xcb_shape_select_input(w->sc->dpy->conn, w->id, FALSE);
230 xcb_change_window_attributes(w->sc->dpy->conn, w->id,
231 XCB_CW_EVENT_MASK, &mask);
237 window_fake_unmapped(d_window_t *pubw)
239 d_window_priv_t *w = (d_window_priv_t*)pubw;
245 window_become_zombie(d_window_t *pubw)
247 d_window_priv_t *w = (d_window_priv_t*)pubw;
249 if (w->zombie) return;
255 window_is_zombie(d_window_t *pubw)
257 d_window_priv_t *w = (d_window_priv_t*)pubw;
262 window_is_input_only(d_window_t *pubw)
264 d_window_priv_t *w = (d_window_priv_t*)pubw;
266 window_get_attributes_reply(w);
267 return w->input_only;
271 window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
274 d_window_priv_t *w = (d_window_priv_t*)pubw;
276 window_get_geometry_reply(w);
281 *border_width = w->bw;
285 window_get_attributes_reply(d_window_priv_t *w)
287 xcb_get_window_attributes_reply_t *rep;
288 xcb_generic_error_t *err = NULL;
290 rep = xcb_get_window_attributes_reply(w->sc->dpy->conn,
295 w->input_only = rep->_class == XCB_WINDOW_CLASS_INPUT_ONLY;
296 w->attr_mapped = rep->map_state != XCB_MAP_STATE_UNMAPPED;
297 w->visual = rep->visual;
298 //printf("0x%x attributes mapped %d\n", w->id, w->mapped);
302 w->input_only = TRUE;
303 w->attr_mapped = FALSE;
304 w->visual = XCB_NONE;
307 printf("error getting attributes for window 0x%x\n", w->id);
310 w->waiting_attr = FALSE;
314 window_get_geometry_reply(d_window_priv_t *w)
316 xcb_get_geometry_reply_t *rep;
317 xcb_generic_error_t *err = NULL;
319 rep = xcb_get_geometry_reply(w->sc->dpy->conn,
328 w->bw = rep->border_width;
329 w->argb = rep->depth == 32;
339 printf("error getting geometry for window 0x%x\n", w->id);
342 w->waiting_geom = FALSE;
346 window_is_mapped(d_window_t *pubw)
348 d_window_priv_t *w = (d_window_priv_t*)pubw;
353 window_is_attr_mapped(d_window_t *pubw)
355 d_window_priv_t *w = (d_window_priv_t*)pubw;
357 window_get_attributes_reply(w);
358 return w->attr_mapped;
362 window_is_argb(d_window_t *pubw)
364 d_window_priv_t *w = (d_window_priv_t*)pubw;
366 window_get_geometry_reply(w);
371 window_get_visual(d_window_t *pubw)
373 d_window_priv_t *w = (d_window_priv_t*)pubw;
375 window_get_attributes_reply(w);
380 window_get_region(d_window_t *pubw)
382 d_window_priv_t *w = (d_window_priv_t*)pubw;
388 window_configure(d_window_t *pubw, int x, int y, int width, int height,
391 d_window_priv_t *w = (d_window_priv_t*)pubw;
393 /* this overrides any reply from our get_geometry call */
395 w->waiting_geom = FALSE;
400 w->bw = border_width;
404 window_move(d_window_t *pubw)
406 //d_window_priv_t *w = (d_window_priv_t*)pubw;
407 window_update_region((d_window_priv_t*)pubw);
411 window_resize(d_window_t *w)
413 window_update_pixmap((d_window_priv_t*)w);
414 window_update_region((d_window_priv_t*)w);
418 window_reshape(d_window_t *w)
420 window_update_region((d_window_priv_t*)w);
423 void window_opacity_change(d_window_t *w)
429 window_add_plugin_data(d_window_t *pubw, int id, void *data)
431 d_window_priv_t *w = (d_window_priv_t*)pubw;
432 plugin_data_add(w->plugin_data, id, data);
436 window_find_plugin_data(d_window_t *pubw, int id)
438 d_window_priv_t *w = (d_window_priv_t*)pubw;
439 return plugin_data_find(w->plugin_data, id);
443 window_remove_plugin_data(d_window_t *pubw, int id)
445 d_window_priv_t *w = (d_window_priv_t*)pubw;
446 plugin_data_remove(w->plugin_data, id);
450 window_create_damage(d_window_t *pubw)
452 d_window_priv_t *w = (d_window_priv_t*)pubw;
454 if (!window_is_input_only(pubw)) {
455 assert(w->damage == XCB_NONE);
456 w->damage = xcb_generate_id(w->sc->dpy->conn);
457 //printf("creating damage 0x%x\n", w->damage);
458 xcb_damage_create(w->sc->dpy->conn, w->damage, w->id,
459 XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
464 window_destroy_damage(d_window_t *pubw)
466 d_window_priv_t *w = (d_window_priv_t*)pubw;
469 //printf("destroying damage 0x%x\n", w->damage);
470 xcb_damage_destroy(w->sc->dpy->conn, w->damage);
471 w->damage = XCB_NONE;
476 type_request(d_display_t *dpy, d_window_priv_t *w, xcb_window_t *id, int nid)
478 xcb_get_property_cookie_t *cks;
481 cks = malloc(sizeof(xcb_get_property_cookie_t) * nid * 2);
482 for (i = 0; i < nid; ++i) {
484 xcb_get_property_unchecked(dpy->conn, FALSE, id[i],
485 dpy->a.net_wm_window_type,
488 xcb_get_property_unchecked(dpy->conn, FALSE, id[i],
489 dpy->a.wm_transient_for,
490 dpy->a.window, 0, 1);
493 for (i = 0; i < nid; ++i) {
494 xcb_get_property_reply_t *rep;
495 d_window_type_t type = DC_WINDOW_TYPE_INVALID;
497 rep = xcb_get_property_reply(dpy->conn, cks[i*2+0], NULL);
499 if (!w->type && rep->type == dpy->a.atom && rep->length >= 1) {
500 xcb_atom_t *a = (xcb_atom_t*)(xcb_get_property_value(rep));
502 for (j = 0; j < rep->length; ++j) {
503 if (a[j] == dpy->a.net_wm_window_type_normal) {
504 type = DC_WINDOW_TYPE_NORMAL; break;
506 if (a[j] == dpy->a.net_wm_window_type_desktop) {
507 type = DC_WINDOW_TYPE_DESKTOP; break;
509 if (a[j] == dpy->a.net_wm_window_type_dock) {
510 type = DC_WINDOW_TYPE_DOCK; break;
512 if (a[j] == dpy->a.net_wm_window_type_dialog) {
513 type = DC_WINDOW_TYPE_DIALOG; break;
515 if (a[j] == dpy->a.net_wm_window_type_toolbar) {
516 type = DC_WINDOW_TYPE_TOOLBAR; break;
518 if (a[j] == dpy->a.net_wm_window_type_menu) {
519 type = DC_WINDOW_TYPE_MENU; break;
521 if (a[j] == dpy->a.net_wm_window_type_utility) {
522 type = DC_WINDOW_TYPE_UTILITY; break;
524 if (a[j] == dpy->a.net_wm_window_type_splash) {
525 type = DC_WINDOW_TYPE_SPLASH; break;
527 if (a[j] == dpy->a.net_wm_window_type_dropdown_menu) {
528 type = DC_WINDOW_TYPE_DROPDOWN_MENU; break;
530 if (a[j] == dpy->a.net_wm_window_type_popup_menu) {
531 type = DC_WINDOW_TYPE_POPUP_MENU; break;
533 if (a[j] == dpy->a.net_wm_window_type_tooltip) {
534 type = DC_WINDOW_TYPE_TOOLTIP; break;
536 if (a[j] == dpy->a.net_wm_window_type_notification) {
537 type = DC_WINDOW_TYPE_NOTIFICATION; break;
539 if (a[j] == dpy->a.net_wm_window_type_combo) {
540 type = DC_WINDOW_TYPE_COMBO; break;
542 if (a[j] == dpy->a.net_wm_window_type_dnd) {
543 type = DC_WINDOW_TYPE_DND; break;
549 rep = xcb_get_property_reply(dpy->conn, cks[i*2+1], NULL);
551 if (!w->type && rep->type == dpy->a.window && rep->length == 1)
552 type = DC_WINDOW_TYPE_DIALOG;
556 /* also save the window id that we got the type/transient hint from */
557 if (!w->type && type) {
564 for (i = 0; i < nid && !w->type; ++i) {
565 xcb_query_tree_cookie_t ck;
566 xcb_query_tree_reply_t *rep;
568 ck = xcb_query_tree(dpy->conn, id[i]);
569 rep = xcb_query_tree_reply(dpy->conn, ck, NULL);
571 int num = xcb_query_tree_children_length(rep);
572 xcb_window_t *ch = xcb_query_tree_children(rep);
574 type_request(dpy, w, ch, num);
581 window_update_type(d_window_priv_t *w)
583 w->type = DC_WINDOW_TYPE_INVALID;
584 type_request(w->sc->dpy, w, &w->id, 1);
586 w->type = DC_WINDOW_TYPE_NORMAL;
590 printf("window 0x%x type %d\n", w->id, w->type);
594 window_get_type(d_window_t *pubw)
596 d_window_priv_t *w = (d_window_priv_t*)pubw;
602 window_get_opacity(d_window_t *pubw)
604 d_window_priv_t *w = (d_window_priv_t*)pubw;
605 unsigned long long l;
607 if (w->waiting_opac) {
608 xcb_get_property_reply_t *rep;
610 w->user_opacity = 0xffff;
611 rep = xcb_get_property_reply(w->sc->dpy->conn, w->ck_get_opac, NULL);
613 if (rep->type == w->sc->dpy->a.cardinal && rep->length >= 1) {
614 l = ((uint32_t*)xcb_get_property_value(rep))[0];
615 l = 0xffff * l / 0xffffffff;
620 w->waiting_opac = FALSE;
624 l = l * w->user_opacity / 0xffff;
629 window_set_opacity(d_window_t *pubw, uint16_t o)
631 d_window_priv_t *w = (d_window_priv_t*)pubw;
635 w->sc->window_opacity_change(pubw);