#include <xcb/composite.h>
#include <xcb/damage.h>
+#define TOPLEVEL_WINDOW_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE)
+
typedef struct {
/* public stuff */
xcb_window_t id;
/* private stuff */
int ref;
+ int zombieref;
/* queried things, don't read them directly from the struct */
int x, y, w, h, bw;
gboolean attr_mapped;
gboolean input_only;
- gboolean argb;
+ uint8_t depth;
xcb_visualid_t visual;
xcb_pixmap_t pixmap;
xcb_xfixes_region_t region;
queries should go to this window */
xcb_window_t client;
- double opacity;
+ /* opacity is from 0xffff to 0, these 2 are combined to give the final
+ result */
+ uint16_t opacity; /* this one is set by plugins/settings */
+ uint16_t user_opacity; /* this one is set by the user */
gboolean mapped;
gboolean zombie;
xcb_get_window_attributes_cookie_t ck_get_attr;
gboolean waiting_geom;
xcb_get_geometry_cookie_t ck_get_geom;
+ gboolean waiting_opac;
+ xcb_get_property_cookie_t ck_get_opac;
} d_window_priv_t;
static void window_get_attributes_reply(d_window_priv_t *w);
w = malloc(sizeof(d_window_priv_t));
w->id = id;
w->ref = 1;
+ w->zombieref = 0;
w->sc = sc;
w->zombie = FALSE;
w->mapped = FALSE;
w->damage = XCB_NONE;
w->region = XCB_NONE;
w->type = DC_WINDOW_TYPE_INVALID;
+ w->opacity = 0xffff;
+ w->user_opacity = 0xffff;
screen_stacking_add(sc, (d_window_t*)w);
if (w && --w->ref == 0) {
screen_stacking_remove(w->sc, (d_window_t*)w);
- if (w->region) {
- xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
- w->region = XCB_NONE;
- }
-
- if (w->pixmap) {
- /* this may cause an error if the pixmap was never valid, but
- that's fine */
- xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
- w->pixmap = XCB_NONE;
- }
+ assert(w->zombieref == 0);
+ while (w->zombieref)
+ window_zombie_unref(pubw);
list_unref(w->plugin_data);
free(w);
return w->pixmap;
}
+void
+window_update_user_opacity(d_window_t *pubw)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+ w->ck_get_opac =
+ xcb_get_property(w->sc->dpy->conn, FALSE, w->id,
+ w->sc->dpy->a.net_wm_window_opacity,
+ w->sc->dpy->a.cardinal, 0, 1);
+ w->waiting_opac = TRUE;
+}
+
static void
window_update_region(d_window_priv_t *w)
{
window_show(d_window_t *pubw)
{
d_window_priv_t *w = (d_window_priv_t*)pubw;
+ unsigned int mask;
assert(!w->mapped);
if (w->sc->dpy->shape.present)
xcb_shape_select_input(w->sc->dpy->conn, w->id, TRUE);
+ mask = TOPLEVEL_WINDOW_EVENT_MASK;
+ xcb_change_window_attributes(w->sc->dpy->conn, w->id,
+ XCB_CW_EVENT_MASK, &mask);
+
+ assert(w->zombieref == 0);
+
window_update_pixmap(w);
window_update_region(w);
+ window_update_user_opacity(pubw);
window_update_type(w);
w->mapped = TRUE;
+
+ /* hold one reference for ourselves */
+ window_zombie_ref(pubw);
}
void
window_hide(d_window_t *pubw)
{
d_window_priv_t *w = (d_window_priv_t*)pubw;
+ unsigned int mask;
assert(w->mapped);
//printf("hide window 0x%x\n", w->id);
if (w->sc->dpy->shape.present)
xcb_shape_select_input(w->sc->dpy->conn, w->id, FALSE);
+ mask = 0;
+ xcb_change_window_attributes(w->sc->dpy->conn, w->id,
+ XCB_CW_EVENT_MASK, &mask);
w->mapped = FALSE;
+
+ /* try to free zombie things */
+ window_zombie_unref(pubw);
}
void
w->zombie = TRUE;
}
+void
+window_zombie_dead(d_window_t *pubw)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+ if (!w->zombie) return;
+
+ w->zombie = FALSE;
+}
+
gboolean
window_is_zombie(d_window_t *pubw)
{
w->w = rep->width;
w->h = rep->height;
w->bw = rep->border_width;
- w->argb = rep->depth == 32;
+ w->depth = rep->depth;
free(rep);
}
else {
w->x = w->y = -1;
w->w = w->h = 1;
w->bw = 0;
- w->argb = FALSE;
+ w->depth = 0;
}
if (err) {
printf("error getting geometry for window 0x%x\n", w->id);
gboolean
window_is_argb(d_window_t *pubw)
{
+ uint8_t depth = window_get_depth(pubw);
+ return depth == 32;
+}
+
+uint8_t
+window_get_depth(d_window_t *pubw)
+{
d_window_priv_t *w = (d_window_priv_t*)pubw;
if (w->waiting_geom)
window_get_geometry_reply(w);
- return w->argb;
+ return w->depth;
}
xcb_visualid_t
window_update_region((d_window_priv_t*)w);
}
+void window_opacity_change(d_window_t *w)
+{
+ screen_refresh(w->sc);
+}
+
void
window_add_plugin_data(d_window_t *pubw, int id, void *data)
{
w->type = DC_WINDOW_TYPE_NORMAL;
w->client = w->id;
}
-
- printf("window 0x%x type %d\n", w->id, w->type);
+ //printf("window 0x%x type %d\n", w->id, w->type);
}
d_window_type_t
return w->type;
}
+uint16_t
+window_get_opacity(d_window_t *pubw)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+ unsigned long long l;
+
+ if (w->waiting_opac) {
+ xcb_get_property_reply_t *rep;
+
+ w->user_opacity = 0xffff;
+ rep = xcb_get_property_reply(w->sc->dpy->conn, w->ck_get_opac, NULL);
+ if (rep) {
+ if (rep->type == w->sc->dpy->a.cardinal && rep->length >= 1) {
+ l = ((uint32_t*)xcb_get_property_value(rep))[0];
+ l = 0xffff * l / 0xffffffff;
+ w->user_opacity = l;
+ }
+ free(rep);
+ }
+ w->waiting_opac = FALSE;
+ }
+
+ l = w->opacity;
+ l = l * w->user_opacity / 0xffff;
+ return l;
+}
+
+void
+window_set_opacity(d_window_t *pubw, uint16_t o)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+ w->opacity = o;
+ if (w->mapped || w->zombie)
+ w->sc->window_opacity_change(pubw);
+ //printf("mapped %d opacity 0x%x\n", w->mapped, w->opacity);
+}
+
+void
+window_zombie_ref(d_window_t *pubw)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+ ++w->zombieref;
+}
+
+void
+window_zombie_unref(d_window_t *pubw)
+{
+ d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+ if (--w->zombieref == 0) {
+ w->sc->window_zombie_dead(pubw);
+
+ w->zombie = FALSE;
+
+ if (w->region) {
+ xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
+ w->region = XCB_NONE;
+ }
+
+ if (w->pixmap) {
+ /* this may cause an error if the pixmap was never valid, but
+ that's fine */
+ xcb_free_pixmap(w->sc->dpy->conn, w->pixmap);
+ w->pixmap = XCB_NONE;
+ }
+
+ /* reset the opacity */
+ w->opacity = 0xffff;
+ }
+}
+
+void
+window_damage(d_window_t *w)
+{
+ (void)w;
+}
+
+void
+window_restack(d_window_t *w, d_window_t *above)
+{
+ screen_stacking_move_above(w->sc, w, above);
+}