From 983001613a46b760c15dd48aa64a87b020fda615 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Wed, 20 Feb 2013 14:09:19 +0100 Subject: [PATCH] Drawable: Improve signal behavior When property::surface is emitted, the drawable didn't know its geometry yet, which had weird side effects. Fix this by changing the C API a little. The function drawable_set_surface() now no longer allows a NULL surface as its argument. The required changes for the titlebar code also means that we no longer throw away the double-buffering surface when a client is moved. Signed-off-by: Uli Schlachter --- objects/client.c | 43 ++++++++++++++++++++++++------------------- objects/drawable.c | 33 ++++++++++++++++++--------------- objects/drawable.h | 3 ++- objects/drawin.c | 7 +++---- 4 files changed, 47 insertions(+), 39 deletions(-) diff --git a/objects/client.c b/objects/client.c index 4f912d89..d7ec17f5 100644 --- a/objects/client.c +++ b/objects/client.c @@ -668,33 +668,38 @@ client_resize_do(client_t *c, area_t geometry, bool force_notice) luaA_object_push(globalconf.L, c); drawable_t *drawable = titlebar_get_drawable(globalconf.L, c, -1, bar); - - /* Get rid of the old state */ luaA_object_push_item(globalconf.L, -1, drawable); - drawable_set_surface(drawable, -1, NULL); - if (c->titlebar[bar].pixmap != XCB_NONE) - xcb_free_pixmap(globalconf.connection, c->titlebar[bar].pixmap); - c->titlebar[bar].pixmap = XCB_NONE; - /* And get us some new state */ area_t area = titlebar_get_area(c, bar); - if (c->titlebar[bar].size != 0 && !hide_titlebars) - { - c->titlebar[bar].pixmap = xcb_generate_id(globalconf.connection); - xcb_create_pixmap(globalconf.connection, globalconf.default_depth, c->titlebar[bar].pixmap, - globalconf.screen->root, area.width, area.height); - cairo_surface_t *surface = cairo_xcb_surface_create(globalconf.connection, - c->titlebar[bar].pixmap, globalconf.visual, - area.width, area.height); - drawable_set_surface(drawable, -1, surface); - } /* Convert to global coordinates */ area.x += geometry.x; area.y += geometry.y; if (hide_titlebars) area.width = area.height = 0; - drawable_set_geometry(drawable, -1, area); + + if (old_geometry.width != geometry.width || old_geometry.height != geometry.height || + drawable->geometry.width == 0 || drawable->geometry.height == 0) { + /* Get rid of the old state */ + drawable_unset_surface(drawable); + if (c->titlebar[bar].pixmap != XCB_NONE) + xcb_free_pixmap(globalconf.connection, c->titlebar[bar].pixmap); + c->titlebar[bar].pixmap = XCB_NONE; + + /* And get us some new state */ + if (c->titlebar[bar].size != 0 && !hide_titlebars) + { + c->titlebar[bar].pixmap = xcb_generate_id(globalconf.connection); + xcb_create_pixmap(globalconf.connection, globalconf.default_depth, c->titlebar[bar].pixmap, + globalconf.screen->root, area.width, area.height); + cairo_surface_t *surface = cairo_xcb_surface_create(globalconf.connection, + c->titlebar[bar].pixmap, globalconf.visual, + area.width, area.height); + drawable_set_surface(drawable, -1, surface, area); + } else + drawable_set_geometry(drawable, -1, area); + } else + drawable_set_geometry(drawable, -1, area); /* Pop the client and the drawable */ lua_pop(globalconf.L, 2); @@ -1028,7 +1033,7 @@ client_unmanage(client_t *c, bool window_valid) luaA_object_push_item(globalconf.L, -1, c->titlebar[bar].drawable); /* Make the drawable unusable */ - drawable_set_surface(c->titlebar[bar].drawable, -1, NULL); + drawable_unset_surface(c->titlebar[bar].drawable); if (c->titlebar[bar].pixmap != XCB_NONE) xcb_free_pixmap(globalconf.connection, c->titlebar[bar].pixmap); diff --git a/objects/drawable.c b/objects/drawable.c index 6366f387..84a032e7 100644 --- a/objects/drawable.c +++ b/objects/drawable.c @@ -48,24 +48,27 @@ drawable_wipe(drawable_t *d) } void -drawable_set_surface(drawable_t *d, int didx, cairo_surface_t *surface) +drawable_unset_surface(drawable_t *d) { - if (d->surface) { - cairo_surface_finish(d->surface); - cairo_surface_destroy(d->surface); - } + if (!d->surface) + return; + cairo_surface_finish(d->surface); + cairo_surface_destroy(d->surface); + d->surface = NULL; +} +void +drawable_set_surface(drawable_t *d, int didx, cairo_surface_t *surface, area_t geom) +{ + drawable_unset_surface(d); d->surface = cairo_surface_reference(surface); - - if (d->surface) - { - /* Make sure the surface doesn't contain garbage by filling it with black */ - cairo_t *cr = cairo_create(surface); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_destroy(cr); - luaA_object_emit_signal(globalconf.L, didx, "property::surface", 0); - } + /* Make sure the surface doesn't contain garbage by filling it with black */ + cairo_t *cr = cairo_create(surface); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + cairo_destroy(cr); + drawable_set_geometry(d, didx, geom); + luaA_object_emit_signal(globalconf.L, didx, "property::surface", 0); } void diff --git a/objects/drawable.h b/objects/drawable.h index 722bd3a3..732fe7e7 100644 --- a/objects/drawable.h +++ b/objects/drawable.h @@ -43,7 +43,8 @@ struct drawable_t }; drawable_t *drawable_allocator(lua_State *, drawable_refresh_callback *, void *); -void drawable_set_surface(drawable_t *, int, cairo_surface_t *); +void drawable_unset_surface(drawable_t *); +void drawable_set_surface(drawable_t *, int, cairo_surface_t *, area_t); void drawable_set_geometry(drawable_t *, int, area_t); void drawable_class_setup(lua_State *); diff --git a/objects/drawin.c b/objects/drawin.c index f290c372..54e1a333 100644 --- a/objects/drawin.c +++ b/objects/drawin.c @@ -62,7 +62,7 @@ drawin_wipe(drawin_t *w) /* The drawin must already be unmapped, else it * couldn't be garbage collected -> no unmap needed */ p_delete(&w->cursor); - cairo_surface_finish(w->drawable->surface); + drawable_unset_surface(w->drawable); if(w->window) { /* Activate BMA */ @@ -98,7 +98,7 @@ drawin_update_drawing(drawin_t *w, int widx) return; /* Clean up old stuff */ luaA_object_push_item(globalconf.L, widx, w->drawable); - drawable_set_surface(w->drawable, -1, NULL); + drawable_unset_surface(w->drawable); if(w->pixmap) xcb_free_pixmap(globalconf.connection, w->pixmap); @@ -111,8 +111,7 @@ drawin_update_drawing(drawin_t *w, int widx) cairo_surface_t *surface = cairo_xcb_surface_create(globalconf.connection, w->pixmap, globalconf.visual, w->geometry.width, w->geometry.height); - drawable_set_surface(w->drawable, -1, surface); - drawable_set_geometry(w->drawable, -1, w->geometry); + drawable_set_surface(w->drawable, -1, surface, w->geometry); lua_pop(globalconf.L, 1); }