From aed571eb4881c63327a6aa347630aba5e2c427f1 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 8 May 2016 17:48:40 +0200 Subject: [PATCH] gears.wallpaper: Handle concurrent screen changes The code in gears.wallpaper currently sets a wallpaper in a deferred fashion. Only a while after it is told to do something does it actually do the wallpaper change. This is to incorporate many wallpaper changes right after another. These changes happens during startup where the wallpaper for each screen is set one after another. However, since we no longer restart on RandR changes, the screen configuration could change while we have a pending wallpaper. In this case, part of the wallpaper could be "chopped off", because the surface that we draw the wallpaper to is too small. This commit makes gears.wallpaper track the size of the pending wallpaper and create a new surface if the already-pending one is too small. Signed-off-by: Uli Schlachter --- lib/gears/wallpaper.lua | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/gears/wallpaper.lua b/lib/gears/wallpaper.lua index fe6609ae2..540df805d 100644 --- a/lib/gears/wallpaper.lua +++ b/lib/gears/wallpaper.lua @@ -18,7 +18,7 @@ local function root_geometry() return { x = 0, y = 0, width = width, height = height } end --- A cairo surface that we still want to set as the wallpaper +-- Information about a pending wallpaper change, see prepare_context() local pending_wallpaper = nil --- Prepare the needed state for setting a wallpaper. @@ -29,35 +29,49 @@ local pending_wallpaper = nil -- @return[1] The available geometry (table with entries width and height) -- @return[1] A cairo context that the wallpaper should be drawn to function wallpaper.prepare_context(s) + local root_width, root_height = root.size() local geom = s and screen[s].geometry or root_geometry() - local cr + local source, target, cr if not pending_wallpaper then -- Prepare a pending wallpaper - local wp = surface(root.wallpaper()) - - pending_wallpaper = wp:create_similar(cairo.Content.COLOR, root.size()) - - -- Copy the old wallpaper to the new one - cr = cairo.Context(pending_wallpaper) - cr:save() - cr.operator = cairo.Operator.SOURCE - cr:set_source_surface(wp, 0, 0) - cr:paint() - cr:restore() + source = surface(root.wallpaper()) + target = source:create_similar(cairo.Content.COLOR, root_width, root_height) -- Set the wallpaper (delayed) timer.delayed_call(function() local paper = pending_wallpaper pending_wallpaper = nil - wallpaper.set(paper) - paper:finish() + wallpaper.set(paper.surface) + paper.surface:finish() end) + elseif root_width > pending_wallpaper.width or root_height > pending_wallpaper.height then + -- The root window was resized while a wallpaper is pending + source = pending_wallpaper.surface + target = source:create_similar(cairo.Content.COLOR, root_width, root_height) else -- Draw to the already-pending wallpaper - cr = cairo.Context(pending_wallpaper) + source = nil + target = pending_wallpaper.surface end + cr = cairo.Context(target) + + if source then + -- Copy the old wallpaper to the new one + cr:save() + cr.operator = cairo.Operator.SOURCE + cr:set_source_surface(source, 0, 0) + cr:paint() + cr:restore() + end + + pending_wallpaper = { + surface = target, + width = root_width, + height = root_height + } + -- Only draw to the selected area cr:translate(geom.x, geom.y) cr:rectangle(0, 0, geom.width, geom.height)