diff --git a/awesome.c b/awesome.c index 60aa2dc3..54d1a7c3 100644 --- a/awesome.c +++ b/awesome.c @@ -691,6 +691,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/event.c b/event.c index 555978bf..b08ce2f8 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 */ diff --git a/globalconf.h b/globalconf.h index 8d5791cc..be4a6535 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/lib/wibox/drawable.lua b/lib/wibox/drawable.lua index 341505e6..cf6682e2 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 diff --git a/property.c b/property.c index d48747c1..faf13b18 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 8bbe960f..6682d910 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); @@ -123,6 +139,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 +412,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 +420,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; }