2012-07-29 16:39:03 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
-- @author Uli Schlachter
|
|
|
|
-- @copyright 2012 Uli Schlachter
|
|
|
|
-- @release @AWESOME_VERSION@
|
2014-05-19 15:15:39 +02:00
|
|
|
-- @module gears.wallpaper
|
2012-07-29 16:39:03 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
local cairo = require("lgi").cairo
|
|
|
|
local color = require("gears.color")
|
|
|
|
local surface = require("gears.surface")
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
local timer = require("gears.timer")
|
2012-07-29 16:39:03 +02:00
|
|
|
|
|
|
|
local wallpaper = { mt = {} }
|
|
|
|
|
|
|
|
-- The size of the root window
|
2016-03-26 18:37:55 +01:00
|
|
|
local root_geom = { x = 0, y = 0, width = 0, height = 0 }
|
2016-04-05 06:01:31 +02:00
|
|
|
|
|
|
|
-- Gears should not depend on awful or C-API, this should be fixed eventually
|
|
|
|
require("awful.screen").connect_for_each_screen(function(s)
|
2016-03-26 18:37:55 +01:00
|
|
|
local g = s.geometry
|
|
|
|
root_geom.width = math.max(root_geom.width, g.x + g.width)
|
|
|
|
root_geom.height = math.max(root_geom.height, g.y + g.height)
|
|
|
|
end)
|
2012-07-29 16:39:03 +02:00
|
|
|
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
-- A cairo surface that we still want to set as the wallpaper
|
|
|
|
local pending_wallpaper = nil
|
|
|
|
|
|
|
|
--- Prepare the needed state for setting a wallpaper.
|
|
|
|
-- This function returns a cairo context through which a wallpaper can be drawn.
|
|
|
|
-- The context is only valid for a short time and should not be saved in a
|
|
|
|
-- global variable.
|
2012-07-29 16:39:03 +02:00
|
|
|
-- @param s The screen to set the wallpaper on or nil for all screens
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
-- @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)
|
2012-07-29 16:39:03 +02:00
|
|
|
local geom = s and screen[s].geometry or root_geom
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
local cr
|
|
|
|
|
|
|
|
if not pending_wallpaper then
|
|
|
|
-- Prepare a pending wallpaper
|
|
|
|
local wp = surface(root.wallpaper())
|
|
|
|
|
|
|
|
pending_wallpaper = wp:create_similar(cairo.Content.COLOR, root_geom.width, root_geom.height)
|
|
|
|
|
|
|
|
-- 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()
|
|
|
|
|
|
|
|
-- Set the wallpaper (delayed)
|
|
|
|
timer.delayed_call(function()
|
2016-02-07 13:29:46 +01:00
|
|
|
local paper = pending_wallpaper
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
pending_wallpaper = nil
|
2016-02-07 13:29:46 +01:00
|
|
|
wallpaper.set(paper)
|
2016-02-28 17:24:24 +01:00
|
|
|
paper:finish()
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
end)
|
|
|
|
else
|
|
|
|
-- Draw to the already-pending wallpaper
|
|
|
|
cr = cairo.Context(pending_wallpaper)
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Only draw to the selected area
|
|
|
|
cr:translate(geom.x, geom.y)
|
|
|
|
cr:rectangle(0, 0, geom.width, geom.height)
|
|
|
|
cr:clip()
|
|
|
|
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
return geom, cr
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Set the current wallpaper.
|
|
|
|
-- @param pattern The wallpaper that should be set. This can be a cairo surface,
|
2014-05-19 15:15:39 +02:00
|
|
|
-- a description for gears.color or a cairo pattern.
|
2012-07-29 16:39:03 +02:00
|
|
|
function wallpaper.set(pattern)
|
|
|
|
if cairo.Surface:is_type_of(pattern) then
|
|
|
|
pattern = cairo.Pattern.create_for_surface(pattern)
|
|
|
|
end
|
|
|
|
if type(pattern) == "string" or type(pattern) == "table" then
|
|
|
|
pattern = color(pattern)
|
|
|
|
end
|
|
|
|
if not cairo.Pattern:is_type_of(pattern) then
|
|
|
|
error("wallpaper.set() called with an invalid argument")
|
|
|
|
end
|
|
|
|
root.wallpaper(pattern._native)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Set a centered wallpaper.
|
|
|
|
-- @param surf The wallpaper to center. Either a cairo surface or a file name.
|
|
|
|
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
|
2014-05-19 15:15:39 +02:00
|
|
|
-- all screens are set.
|
2012-07-29 16:39:03 +02:00
|
|
|
-- @param background The background color that should be used. Gets handled via
|
2014-05-19 15:15:39 +02:00
|
|
|
-- gears.color. The default is black.
|
2012-07-29 16:39:03 +02:00
|
|
|
function wallpaper.centered(surf, s, background)
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
local geom, cr = wallpaper.prepare_context(s)
|
2016-02-28 17:24:24 +01:00
|
|
|
surf = surface.load_uncached(surf)
|
2016-02-07 13:29:46 +01:00
|
|
|
background = color(background)
|
2012-07-29 16:39:03 +02:00
|
|
|
|
|
|
|
-- Fill the area with the background
|
|
|
|
cr.operator = cairo.Operator.SOURCE
|
|
|
|
cr.source = background
|
|
|
|
cr:paint()
|
|
|
|
|
|
|
|
-- Now center the surface
|
2014-03-16 03:00:23 +01:00
|
|
|
local w, h = surface.get_size(surf)
|
2012-07-29 16:39:03 +02:00
|
|
|
cr:translate((geom.width - w) / 2, (geom.height - h) / 2)
|
|
|
|
cr:rectangle(0, 0, w, h)
|
|
|
|
cr:clip()
|
|
|
|
cr:set_source_surface(surf, 0, 0)
|
|
|
|
cr:paint()
|
2016-02-28 17:24:24 +01:00
|
|
|
surf:finish()
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Set a tiled wallpaper.
|
|
|
|
-- @param surf The wallpaper to tile. Either a cairo surface or a file name.
|
|
|
|
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
|
2014-05-19 15:15:39 +02:00
|
|
|
-- all screens are set.
|
2012-07-29 16:39:03 +02:00
|
|
|
-- @param offset This can be set to a table with entries x and y.
|
|
|
|
function wallpaper.tiled(surf, s, offset)
|
2016-02-07 13:29:46 +01:00
|
|
|
local _, cr = wallpaper.prepare_context(s)
|
2012-07-29 16:39:03 +02:00
|
|
|
|
|
|
|
if offset then
|
|
|
|
cr:translate(offset.x, offset.y)
|
|
|
|
end
|
|
|
|
|
2016-02-28 17:24:24 +01:00
|
|
|
surf = surface.load_uncached(surf)
|
|
|
|
local pattern = cairo.Pattern.create_for_surface(surf)
|
2012-07-29 16:39:03 +02:00
|
|
|
pattern.extend = cairo.Extend.REPEAT
|
|
|
|
cr.source = pattern
|
|
|
|
cr.operator = cairo.Operator.SOURCE
|
|
|
|
cr:paint()
|
2016-02-28 17:24:24 +01:00
|
|
|
surf:finish()
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Set a maximized wallpaper.
|
|
|
|
-- @param surf The wallpaper to set. Either a cairo surface or a file name.
|
|
|
|
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
|
2014-05-19 15:15:39 +02:00
|
|
|
-- all screens are set.
|
2012-07-29 16:39:03 +02:00
|
|
|
-- @param ignore_aspect If this is true, the image's aspect ratio is ignored.
|
2014-05-19 15:15:39 +02:00
|
|
|
-- The default is to honor the aspect ratio.
|
2012-07-29 16:39:03 +02:00
|
|
|
-- @param offset This can be set to a table with entries x and y.
|
|
|
|
function wallpaper.maximized(surf, s, ignore_aspect, offset)
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
local geom, cr = wallpaper.prepare_context(s)
|
2016-02-28 17:24:24 +01:00
|
|
|
surf = surface.load_uncached(surf)
|
2014-03-16 03:00:23 +01:00
|
|
|
local w, h = surface.get_size(surf)
|
2012-07-29 16:39:03 +02:00
|
|
|
local aspect_w = geom.width / w
|
|
|
|
local aspect_h = geom.height / h
|
|
|
|
|
|
|
|
if not ignore_aspect then
|
|
|
|
aspect_h = math.max(aspect_w, aspect_h)
|
|
|
|
aspect_w = math.max(aspect_w, aspect_h)
|
|
|
|
end
|
|
|
|
cr:scale(aspect_w, aspect_h)
|
|
|
|
|
|
|
|
if offset then
|
|
|
|
cr:translate(offset.x, offset.y)
|
2014-06-08 20:18:09 +02:00
|
|
|
elseif not ignore_aspect then
|
2014-08-24 11:54:12 +02:00
|
|
|
local scaled_width = geom.width / aspect_w
|
|
|
|
local scaled_height = geom.height / aspect_h
|
|
|
|
cr:translate((scaled_width - w) / 2, (scaled_height - h) / 2)
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
cr:set_source_surface(surf, 0, 0)
|
|
|
|
cr.operator = cairo.Operator.SOURCE
|
|
|
|
cr:paint()
|
2016-02-28 17:24:24 +01:00
|
|
|
surf:finish()
|
2012-07-29 16:39:03 +02:00
|
|
|
end
|
|
|
|
|
2013-01-10 13:58:40 +01:00
|
|
|
--- Set a fitting wallpaper.
|
|
|
|
-- @param surf The wallpaper to set. Either a cairo surface or a file name.
|
|
|
|
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
|
2014-05-19 15:15:39 +02:00
|
|
|
-- all screens are set.
|
2013-01-10 13:58:40 +01:00
|
|
|
-- @param background The background color that should be used. Gets handled via
|
2014-05-19 15:15:39 +02:00
|
|
|
-- gears.color. The default is black.
|
2013-01-10 13:58:40 +01:00
|
|
|
function wallpaper.fit(surf, s, background)
|
Set the wallpaper more intelligently
Usually users want a wallpaper on all their screens. With the current code, this
resulted in a loop of upload-wallpaper, {download-wallpaper, add-new-part,
upload-wallpaper}*.
Fix this by being more intelligent: Instead of setting the wallpaper
immediately, this now uses gears.timer.delayed_call() to set the wallpaper. All
following modifications which come in before the delayed call runs will still be
part of the current update. This should mean that during startup, there is just
a single upload of a wallpaper.
(The above is what happens if there is no wallpaper yet. If there is already
one, we use :create_similar() and thus should only upload the part of the
wallpaper that changed, but this doesn't really make a difference.)
As a side-effect, the new code no longer draws to the old wallpaper to modify
it, but always creates a copy of it. This means that:
Fixes https://github.com/awesomeWM/awesome/issues/288.
Closes https://github.com/awesomeWM/awesome/pull/530.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-10-14 16:28:17 +02:00
|
|
|
local geom, cr = wallpaper.prepare_context(s)
|
2016-02-28 17:24:24 +01:00
|
|
|
surf = surface.load_uncached(surf)
|
2016-02-07 13:29:46 +01:00
|
|
|
background = color(background)
|
2013-01-10 13:58:40 +01:00
|
|
|
|
|
|
|
-- Fill the area with the background
|
|
|
|
cr.operator = cairo.Operator.SOURCE
|
|
|
|
cr.source = background
|
|
|
|
cr:paint()
|
|
|
|
|
|
|
|
-- Now fit the surface
|
2014-03-16 03:00:23 +01:00
|
|
|
local w, h = surface.get_size(surf)
|
2013-01-10 13:58:40 +01:00
|
|
|
local scale = geom.width / w
|
|
|
|
if h * scale > geom.height then
|
|
|
|
scale = geom.height / h
|
|
|
|
end
|
|
|
|
cr:translate((geom.width - (w * scale)) / 2, (geom.height - (h * scale)) / 2)
|
|
|
|
cr:rectangle(0, 0, w * scale, h * scale)
|
|
|
|
cr:clip()
|
|
|
|
cr:scale(scale, scale)
|
|
|
|
cr:set_source_surface(surf, 0, 0)
|
|
|
|
cr:paint()
|
2016-02-28 17:24:24 +01:00
|
|
|
surf:finish()
|
2013-01-10 13:58:40 +01:00
|
|
|
end
|
|
|
|
|
2012-07-29 16:39:03 +02:00
|
|
|
return wallpaper
|
|
|
|
|
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|