From 5fe03442328eca8b70731da1a8d510aef74a3d1f Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Mar 2016 11:26:04 +0200 Subject: [PATCH 1/4] Fix invalid memory usage in event.c p_dup really only duplicates the given region of memory. It does not append a zero byte. Thus, the string we are using here was not zero-terminated. Fix this by just using lua_pushlstring() so that we do not have to worry about a null terminating the string at all. Signed-off-by: Uli Schlachter --- event.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/event.c b/event.c index 555978bf5..b08ce2f82 100644 --- a/event.c +++ b/event.c @@ -793,7 +793,6 @@ event_handle_randr_output_change_notify(xcb_randr_notify_event_t *ev) if(ev->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) { xcb_randr_output_t output = ev->u.oc.output; uint8_t connection = ev->u.oc.connection; - char *output_name = NULL; const char *connection_str = NULL; xcb_randr_get_output_info_reply_t *info = NULL; lua_State *L = globalconf_get_lua_State(); @@ -806,9 +805,6 @@ event_handle_randr_output_change_notify(xcb_randr_notify_event_t *ev) if(!info) return; - output_name = p_dup((char *)xcb_randr_get_output_info_name(info), - xcb_randr_get_output_info_name_length(info)); - switch(connection) { case XCB_RANDR_CONNECTION_CONNECTED: connection_str = "Connected"; @@ -821,11 +817,10 @@ event_handle_randr_output_change_notify(xcb_randr_notify_event_t *ev) break; } - lua_pushstring(L, output_name); + lua_pushlstring(L, (char *)xcb_randr_get_output_info_name(info), xcb_randr_get_output_info_name_length(info)); lua_pushstring(L, connection_str); signal_object_emit(L, &global_signals, "screen::change", 2); - p_delete(&output_name); p_delete(&info); /* The docs for RRSetOutputPrimary say we get this signal */ From 3117b439a24d48c908a9ea89fe8b7f5165a61b48 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Mar 2016 11:28:02 +0200 Subject: [PATCH 2/4] Cache the wallpaper Instead of querying the wallpaper every time that root.wallpaper() is called, we just remember it in globalconf. Signed-off-by: Uli Schlachter --- awesome.c | 3 ++ globalconf.h | 5 +++ property.c | 1 + root.c | 95 +++++++++++++++++++++++++++++----------------------- 4 files changed, 63 insertions(+), 41 deletions(-) diff --git a/awesome.c b/awesome.c index b16f23950..2c4caa82b 100644 --- a/awesome.c +++ b/awesome.c @@ -694,6 +694,9 @@ main(int argc, char **argv) xcb_ungrab_server(globalconf.connection); xcb_flush(globalconf.connection); + /* get the current wallpaper, from now on we are informed when it changes */ + root_update_wallpaper(); + /* Parse and run configuration file */ if (!luaA_parserc(&xdg, confpath, true)) fatal("couldn't find any rc file"); diff --git a/globalconf.h b/globalconf.h index 8d5791cc6..be4a65354 100644 --- a/globalconf.h +++ b/globalconf.h @@ -171,6 +171,8 @@ typedef struct struct xkb_state *xkb_state; /** The preferred size of client icons for this screen */ uint32_t preferred_icon_size; + /** Cached wallpaper information */ + cairo_surface_t *wallpaper; } awesome_t; extern awesome_t globalconf; @@ -182,5 +184,8 @@ static inline lua_State *globalconf_get_lua_State(void) { return globalconf.L.real_L_dont_use_directly; } +/* Defined in root.c */ +void root_update_wallpaper(void); + #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/property.c b/property.c index d48747c19..faf13b180 100644 --- a/property.c +++ b/property.c @@ -381,6 +381,7 @@ property_handle_xrootpmap_id(uint8_t state, xcb_window_t window) { lua_State *L = globalconf_get_lua_State(); + root_update_wallpaper(); signal_object_emit(L, &global_signals, "wallpaper_changed", 0); return 0; } diff --git a/root.c b/root.c index 8bbe960f6..6b1ab5c5f 100644 --- a/root.c +++ b/root.c @@ -123,6 +123,58 @@ disconnect: return result; } +void +root_update_wallpaper(void) +{ + xcb_get_property_cookie_t prop_c; + xcb_get_property_reply_t *prop_r; + xcb_get_geometry_cookie_t geom_c; + xcb_get_geometry_reply_t *geom_r; + xcb_pixmap_t *rootpix; + + cairo_surface_destroy(globalconf.wallpaper); + globalconf.wallpaper = NULL; + + prop_c = xcb_get_property_unchecked(globalconf.connection, false, + globalconf.screen->root, _XROOTPMAP_ID, XCB_ATOM_PIXMAP, 0, 1); + prop_r = xcb_get_property_reply(globalconf.connection, prop_c, NULL); + + if (!prop_r || !prop_r->value_len) + { + p_delete(&prop_r); + return; + } + + rootpix = xcb_get_property_value(prop_r); + if (!rootpix) + { + p_delete(&prop_r); + return; + } + + geom_c = xcb_get_geometry_unchecked(globalconf.connection, *rootpix); + geom_r = xcb_get_geometry_reply(globalconf.connection, geom_c, NULL); + if (!geom_r) + { + p_delete(&prop_r); + return; + } + + /* Only the default visual makes sense, so just the default depth */ + if (geom_r->depth != draw_visual_depth(globalconf.screen, globalconf.default_visual->visual_id)) + warn("Got a pixmap with depth %d, but the default depth is %d, continuing anyway", + geom_r->depth, draw_visual_depth(globalconf.screen, globalconf.default_visual->visual_id)); + + globalconf.wallpaper = cairo_xcb_surface_create(globalconf.connection, + *rootpix, + globalconf.default_visual, + geom_r->width, + geom_r->height); + + p_delete(&prop_r); + p_delete(&geom_r); +} + static xcb_keycode_t _string_to_key_code(const char *s) { @@ -344,13 +396,6 @@ luaA_root_drawins(lua_State *L) static int luaA_root_wallpaper(lua_State *L) { - xcb_get_property_cookie_t prop_c; - xcb_get_property_reply_t *prop_r; - xcb_get_geometry_cookie_t geom_c; - xcb_get_geometry_reply_t *geom_r; - xcb_pixmap_t *rootpix; - cairo_surface_t *surface; - if(lua_gettop(L) == 1) { cairo_pattern_t *pattern = (cairo_pattern_t *)lua_touserdata(L, -1); @@ -359,43 +404,11 @@ luaA_root_wallpaper(lua_State *L) return 1; } - prop_c = xcb_get_property_unchecked(globalconf.connection, false, - globalconf.screen->root, _XROOTPMAP_ID, XCB_ATOM_PIXMAP, 0, 1); - prop_r = xcb_get_property_reply(globalconf.connection, prop_c, NULL); - - if (!prop_r || !prop_r->value_len) - { - p_delete(&prop_r); + if(globalconf.wallpaper == NULL) return 0; - } - - rootpix = xcb_get_property_value(prop_r); - if (!rootpix) - { - p_delete(&prop_r); - return 0; - } - - geom_c = xcb_get_geometry_unchecked(globalconf.connection, *rootpix); - geom_r = xcb_get_geometry_reply(globalconf.connection, geom_c, NULL); - if (!geom_r) - { - p_delete(&prop_r); - return 0; - } - - /* Only the default visual makes sense, so just the default depth */ - if (geom_r->depth != draw_visual_depth(globalconf.screen, globalconf.default_visual->visual_id)) - warn("Got a pixmap with depth %d, but the default depth is %d, continuing anyway", - geom_r->depth, draw_visual_depth(globalconf.screen, globalconf.default_visual->visual_id)); - - surface = cairo_xcb_surface_create(globalconf.connection, *rootpix, globalconf.default_visual, - geom_r->width, geom_r->height); /* lua has to make sure this surface gets destroyed */ - lua_pushlightuserdata(L, surface); - p_delete(&prop_r); - p_delete(&geom_r); + lua_pushlightuserdata(L, cairo_surface_reference(globalconf.wallpaper)); return 1; } From d9c918c14a75d8ad837037b9616960ed018a47da Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Mar 2016 11:29:28 +0200 Subject: [PATCH 3/4] wibox.drawable: Stop caching the wallpaper The C code now does this for us. Signed-off-by: Uli Schlachter --- lib/wibox/drawable.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/wibox/drawable.lua b/lib/wibox/drawable.lua index 341505e6c..cf6682e2b 100644 --- a/lib/wibox/drawable.lua +++ b/lib/wibox/drawable.lua @@ -24,7 +24,6 @@ local hierarchy = require("wibox.hierarchy") local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) local drawables = setmetatable({}, { __mode = 'k' }) -local wallpaper = nil -- This is awful.screen.getbycoord() which we sadly cannot use from here (cyclic -- dependencies are bad!) @@ -113,9 +112,7 @@ local function do_redraw(self) if not capi.awesome.composite_manager_running then -- This is pseudo-transparency: We draw the wallpaper in the background - if not wallpaper then - wallpaper = surface.load_silently(capi.root.wallpaper(), false) - end + local wallpaper = surface.load_silently(capi.root.wallpaper(), false) if wallpaper then cr.operator = cairo.Operator.SOURCE cr:set_source_surface(wallpaper, -x, -y) @@ -426,7 +423,6 @@ end -- Redraw all drawables when the wallpaper changes capi.awesome.connect_signal("wallpaper_changed", function() - wallpaper = nil for k in pairs(drawables) do k() end From 222f0a133cb73a9e8cf747e1f841b07a581f09df Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Mar 2016 11:36:23 +0200 Subject: [PATCH 4/4] Keep the cairo surface we use for setting the wallpaper This fixes a race where we would keep giving the old wallpaper surface to Lua when a new one was set, because we didn't get the "wallpaper changed"-event yet. Fix this by just keeping the surface we use for setting the wallpaper around. Signed-off-by: Uli Schlachter --- root.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/root.c b/root.c index 6b1ab5c5f..6682d910c 100644 --- a/root.c +++ b/root.c @@ -74,6 +74,7 @@ root_set_wallpaper_pixmap(xcb_connection_t *c, xcb_pixmap_t p) static bool root_set_wallpaper(cairo_pattern_t *pattern) { + lua_State *L = globalconf_get_lua_State(); xcb_connection_t *c = xcb_connect(NULL, NULL); xcb_pixmap_t p = xcb_generate_id(c); /* globalconf.connection should be connected to the same X11 server, so we @@ -107,15 +108,30 @@ root_set_wallpaper(cairo_pattern_t *pattern) cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_destroy(cr); - cairo_surface_finish(surface); - cairo_surface_destroy(surface); + cairo_surface_flush(surface); xcb_aux_sync(globalconf.connection); + /* Change the wallpaper, without sending us a PropertyNotify event */ + xcb_grab_server(globalconf.connection); + xcb_change_window_attributes(globalconf.connection, + globalconf.screen->root, + XCB_CW_EVENT_MASK, + (uint32_t[]) { 0 }); root_set_wallpaper_pixmap(c, p); + xcb_change_window_attributes(globalconf.connection, + globalconf.screen->root, + XCB_CW_EVENT_MASK, + ROOT_WINDOW_EVENT_MASK); + xcb_ungrab_server(globalconf.connection); /* Make sure our pixmap is not destroyed when we disconnect. */ xcb_set_close_down_mode(c, XCB_CLOSE_DOWN_RETAIN_PERMANENT); + /* Tell Lua that the wallpaper changed */ + cairo_surface_destroy(globalconf.wallpaper); + globalconf.wallpaper = surface; + signal_object_emit(L, &global_signals, "wallpaper_changed", 0); + result = true; disconnect: xcb_flush(c);