0

it's a question about switching wallpapers on Awesome Windows Manager.

I would like to switch my wallpapers smoothly with a fade transition effect. At present, I use the gears.wallpaper API to change my wallpapers randomly, here is the part of the codes https://p.ume.ink/t/cbbM .

Can anyone give me a little advice? I would not like to use external tools.

Bekcpear
  • 1
  • 1

2 Answers2

1

A way, yes, of course, but not a pretty one.

You can use the LGI Cairo along with Cairo composition operators to pre-render each frame (let say, one per event loop over 5 seconds before changing the wallpaper to avoid latency). Then use the gears.wallpaper API to set each frame along with a gears.timer set at either 30hz or 60hz.

While not that much work, it definitely isn't simple.

1

Some completely untested code that might or might not work that hopefully provides some more details to Emmanuel's suggestion:

local surface = require("gears.surface")
local cairo = require("lgi").cairo
local timer = require("gears.timer")

-- "Mix" two surface based on a factor between 0 and 1
local function mix_surfaces(first, second, factor)
    local result = surface.duplicate_surface(first)
    local cr = cairo.Context(result)
    cr:set_source_surface(second, 0, 0)
    cr:paint_with_alpha(factor)
    return result
end

-- Get the current wallpaper and do a fade 'steps' times with 'interval'
-- seconds between steps. At each step, the wallpapers are mixed and the
-- result is given to 'callback'. If no wallpaper is set, the callback
-- function is directly called with the new wallpaper.
local function fade_to_wallpaper(new_wp, steps, interval, callback)
    new_wp = surface(new_wp)
    local old_wp = surface(root.wallpaper())
    if not old_wp then
        callback(new_wp)
        return
    end
    -- Setting a new wallpaper invalidates any surface returned
    -- by root.wallpaper(), so create a copy.
    old_wp = surface.duplicate_surface(old_wp)
    local steps_done = 0
    timer.start_new(interval, function()
        steps_done = steps_done + 1
        local mix = mix_surface(old_wp, new_wp, steps_done / steps)
        callback(mix)
        mix:finish()
        return steps_done <= steps
    end)
end

-- Example how to use:
-- Fade to the given file for 4 seconds with 30 "frames per second".
fade_to_wallpaper("path/to/file.png", 120, 1/30, function(surf)
    gears.wallpaper.maximized(surf)
end)

Note that this does not "pre-render" the frames, as suggested by Emmanuel. However, the actual mixing is done on a surface which was created via create_similar() from a create_similar() from the old wallpaper. As such, this is not a cairo image surface, but a cairo XCB surface and the mixing is done on the X11 server and not in awesome. That might or might not help to speed things up...

Uli Schlachter
  • 9,337
  • 1
  • 23
  • 39