Module: awful.wallpaper
Allows to use the wibox widget system to draw the wallpaper.
Rather than simply having a function to set an image
(stretched, centered or tiled) like most wallpaper tools, this module
leverage the full widget system to draw the wallpaper. Note that the result
is not interactive. If you want an interactive wallpaper, better use
a wibox object with the below
property set to true
and maximized
using awful.placement.maximized
.
It is possible to create an awful.wallpaper object from any places, but
it is recommanded to do it from the request::wallpaper
signal handler.
That signal is called everytime something which could affect the wallpaper
rendering changes, such as new screens.
Single image
This is the default rc.lua wallpaper format. It fills the whole screen and stretches the image while keeping the aspect ratio.
awful.wallpaper { screen = s, widget = { { image = beautiful.wallpaper, resize = true, widget = wibox.widget.imagebox, }, valign = "center", halign = "center", tiled = false, widget = wibox.container.tile, } }
If the image aspect ratio doesn't match, the bg property can be used to fill the empty area:
awful.wallpaper { screen = s, bg = "#0000ff", widget = { { image = beautiful.wallpaper, resize = true, widget = wibox.widget.imagebox, }, valign = "center", halign = "center", tiled = false, widget = wibox.container.tile, } }
It is also possible to stretch the image:
awful.wallpaper { screen = s, widget = { horizontal_fit_policy = "fit", vertical_fit_policy = "fit", image = beautiful.wallpaper, widget = wibox.widget.imagebox, }, }
Finally, it is also possible to use simpler "branding" in a corner using awful.placement:
awful.wallpaper { screen = s, bg = "#000000", widget = { { { image = beautiful.awesome_icon, resize = false, point = awful.placement.bottom_right, widget = wibox.widget.imagebox, }, widget = wibox.layout.manual, }, margins = 5, widget = wibox.container.margin } }
Tiled
This example tiles an image:
awful.wallpaper { screen = s, bg = "#0000ff", widget = { { image = beautiful.awesome_icon, resize = false, widget = wibox.widget.imagebox, }, horizontal_spacing = 5, vertical_spacing = 5, valign = "top", halign = "left", tiled = true, widget = wibox.container.tile, } }
This one tiles a shape using the wibox.widget.separator widget:
awful.wallpaper { screen = s, bg = "#0000ff", widget = { { shape = gears.shape.star, forced_width = 30, forced_height = 30, widget = wibox.widget.separator, }, horizontal_spacing = 5, vertical_spacing = 5, vertical_crop = true, horizontal_crop = true, valign = "center", halign = "center", tiled = true, widget = wibox.container.tile, } }
See the wibox.container.tile for more advanced tiling configuration options.
Solid colors and gradients
Solid colors can be set using the bg property mentionned above. It is also possible to set gradients:
awful.wallpaper { screen = s, bg = { type = "linear" , from = { 0, 0 }, to = { 0, 240 }, stops = { { 0, "#0000ff" }, { 1, "#ff0000" } } } }
awful.wallpaper { screen = s, bg = { type = "radial", from = { 160, 98, 20 }, to = { 160, 98, 120 }, stops = { { 0 , "#ff0000" }, { 0.5, "#00ff00" }, { 1 , "#0000ff" }, } } }
Widgets
It is possible to create a wallpaper using any widgets. However, keep in mind that the wallpaper surface is not interactive, so some widgets like the sliders will render, but will not behave correctly. Also, it is not recommanded to update the wallpaper too often. This is very slow.
local function binary() local ret = {} for _=1, 15 do for _=1, 57 do table.insert(ret, math.random() > 0.5 and 1 or 0) end table.insert(ret, "\n") end return table.concat(ret) end awful.wallpaper { bg = "#000000", fg = "#55ff5577", widget = wibox.widget { { { markup = "<tt><b>[SYSTEM FAILURE]</b></tt>", valign = "center", align = "center", widget = wibox.widget.textbox }, fg = "#00ff00", widget = wibox.container.background }, { wrap = "word", text = binary(), widget = wibox.widget.textbox, }, widget = wibox.layout.stack }, }
Cairo graphics API
AwesomeWM widgets are backed by Cairo. So it is always possible to get access to the Cairo context directly to do some vector art:
awful.wallpaper { screen = s, widget = wibox.widget { fit = function(_, width, height) return width, height end, draw = function(_, _, cr, width, height) cr:set_source(gears.color { type = 'linear', from = { 0, 0 }, to = { 0, height }, stops = { { 0 , '#030d27' }, { 0.75, '#3a183f' }, { 0.75, '#000000' }, { 1 , '#222222' } } }) cr:paint() -- Clip the first 33% of the screen cr:rectangle(0,0, width, height/3) -- Clip-out some increasingly large sections of add the sun "bars" for i=0, 6 do cr:rectangle(0, height*.28 + i*(height*.055 + i/2), width, height*.055) end cr:clip() -- Draw the sun cr:set_source(gears.color { type = 'linear' , from = { 0, 0 }, to = { 0, height }, stops = { { 0, '#f0d64f' }, { 1, '#e484c6' } } }) cr:arc(width/2, height/2, height*.35, 0, math.pi*2) cr:fill() -- Draw the grid local lines = width/8 cr:reset_clip() cr:set_line_width(0.5) cr:set_source(gears.color("#8922a3")) for i=1, lines do cr:move_to((-width) + i* math.sin(i * (math.pi/(lines*2)))*30, height) cr:line_to(width/4 + i*((width/2)/lines), height*0.75 + 2) cr:stroke() end for i=1, 5 do cr:move_to(0, height*0.75 + i*10 + i*2) cr:line_to(width, height*0.75 + i*10 + i*2) cr:stroke() end end, } }
SVG vector images
SVG are supported if librsvg
is installed. Please note that librsvg
doesn't implement all filters you might find in the latest version of
your web browser. It is possible some advanced SVG will not look exactly
as they do in a web browser or even Inkscape. However, for most images,
it should look identical.
Our SVG support goes beyond simple rendering. It is possible to set a custom CSS stylesheet (see wibox.widget.imagebox.stylesheet):
local image = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'.. '<svg width="190" height="60">'.. '<rect x="10" y="10" width="50" height="50" />'.. '<rect x="70" y="10" width="50" height="50" class="my_class" />'.. '<rect x="130" y="10" width="50" height="50" id="my_id" />'.. '</svg>' local stylesheet = "" .. "rect { fill: #ffff00; } ".. ".my_class { fill: #00ff00; } ".. "#my_id { fill: #0000ff; }" awful.wallpaper { widget = wibox.widget { stylesheet = stylesheet, image = image, widget = wibox.widget.imagebox } }
Note that in the example above, it is raw SVG code, but it is also possible
to use a file path. If you have a .svgz
, you need to uncompress it first
using gunzip
or a software like Inkscape.
Multiple screen
The default rc.lua creates a new wallpaper everytime request::wallpaper
is emitted. This is well suited for having a single wallpaper per screen.
It is also much simpler to implement slideshows and add/remove screens.
However, it isn't wall suited for wallpaper rendered across multiple screens.
For this case, it is better to capture the return value of awful.wallpaper {}
as a global variable. Then manually call add_screen and remove_screen when
needed. A shortcut can be to do:
local global_wallpaper = awful.wallpaper { -- [...] your content } screen.connect_signal("request::wallpaper", function() -- screen is the global screen module. It is also a list of all screens. global_wallpaper.screens = screen end)
Slideshow
Slideshows (changing the wallpaper after a few minutes) can be implemented directly using a timer and callback, but it is more elegant to simply request a new wallpaper, then get a random image from within the request handler. This way, corner cases such as adding and removing screens are handled:
-- The "request::wallpaper" section is already in the default
-- rc.lua, replace it with this.
screen.connect_signal("request::wallpaper", function(s)
awful.wallpaper {
screen = s,
bg = "#0000ff",
widget = {
{
image = gears.filesystem.get_random_file_from_dir(
"path/to/dir",
{".jpg", ".png", ".svg"},
true
),
resize = true,
widget = wibox.widget.imagebox,
},
valign = "center",
halign = "center",
tiled = false,
widget = wibox.container.tile,
}
}
end)
-- **Somewhere else** in the code, **not** in the request::wallpaper
handler.
gears.timer {
timeout = 1800,
autostart = true,
callback = function()
for s in screen do
s:emit_signal("request::wallpaper")
end
end,
}
Info:
- Copyright: 2019 Emmanuel Lepage Vallee
-
Originally authored by: Emmanuel Lepage Vallee <elv1313@gmail.com>
(Full contributors list available on our github project)
Constructors
awful.wallpaper {[args]} | Create a wallpaper. |
Object properties
widget | wibox.widget | The wallpaper widget. | |
dpi | number | The wallpaper DPI (dots per inch). | |
screen | screen | The wallpaper screen. | |
screens | table | A list of screen for this wallpaper. | |
bg | gears.color | The background color. | |
fg | gears.color | The foreground color. | |
honor_workarea | boolean | Honor the workarea. | |
honor_padding | boolean | Honor the screen padding. | |
uncovered_areas | table | Returns the list of screen(s) area which won't be covered by the wallpaper. | |
uncovered_areas_color | gears.color | The color for the uncovered areas. | |
panning_area | function or string | Defines where the wallpaper is placed when there is multiple screens. |
Object methods
:add_screen (screen) | Add another screen (enable panning). | |
:detach () | Detach the wallpaper from all screens. | |
:repaint () | Repaint the wallpaper. | |
:remove_screen (screen) | Remove a screen. |
Theme variables
beautiful.wallpaper_bg | gears.color | The default wallpaper background color. | |
beautiful.wallpaper_fg | gears.color | The default wallpaper foreground color. |
Constructors
- awful.wallpaper {[args]}
-
Create a wallpaper.
Note that all parameters are not required. Please refer to the module description and examples to understand parameters usages.
Parameters:
- args
- widget wibox.widget The wallpaper widget. (optional)
- dpi number The wallpaper DPI (dots per inch). (optional)
- screen screen The wallpaper screen. (optional)
- screens
table
A list of screen for this wallpaper.
Use this parameter as a remplacement for
args.screen
to manage multiscreen wallpaper. (Note: the expected table should be an array-like table{screen1, screen2, ...}
) (optional) - bg gears.color The background color. (optional)
- fg gears.color The foreground color. (optional)
- uncovered_areas_color gears.color The color for the uncovered areas. (optional)
- honor_workarea boolean Honor the workarea. (optional)
- honor_padding boolean Honor the screen padding. (optional)
- uncovered_areas table Returns the list of screen(s) area which won't be covered by the wallpaper. (optional)
- panning_area function or string Defines where the wallpaper is placed when there is multiple screens. (optional)
- args
Object properties
- widget wibox.widget
-
The wallpaper widget.
When set, instead of using the
image_path
orsurface
properties, the wallpaper will be defined as a normal wibox widget tree.See also:
- dpi number
-
The wallpaper DPI (dots per inch).
Each screen has a DPI. This value will be used by default, but sometime it is useful to override the screen DPI and use a custom one. This makes possible, for example, to draw the widgets bigger than they would otherwise be.
If not DPI is defined, it will use the smallest DPI from any of the screen.
In this example, there is 3 screens with DPI of 100, 200 and 300. As you can see, only the text size is affected. Many widgetds are DPI aware, but not all of them. This is either because DPI isn't relevant to them or simply because it isn't supported (like wibox.widget.graph).
See also:
Usage:
for s in screen do local dpi = s.index * 100 awful.wallpaper { screen = s, dpi = dpi, widget = wibox.widget { text = "DPI: " .. dpi, valign = "center", align = "center", widget = wibox.widget.textbox, } end
- screen screen
-
The wallpaper screen.
Note that there can only be one wallpaper per screen. If there is more, one will be chosen and all other ignored.
See also:
- screens table
-
A list of screen for this wallpaper.
See also:
Usage:
-- There is 3 screens. This will add the wallpaper to the last 2. awful.wallpaper { screens = { screen[2], screen[3], }, bg = "#222222", widget = wibox.widget { { fit = function(_, width, height) return width, height end, draw = function(_, _, cr, width, height) cr:set_source(gears.color("#0000ff")) cr:line_to(width, height) cr:line_to(width, 0) cr:line_to(0, 0) cr:close_path() cr:fill() cr:set_source(gears.color("#ff00ff")) cr:move_to(0, 0) cr:line_to(0, height) cr:line_to(width, height) cr:close_path() cr:fill() end, widget = wibox.widget.base.make_widget() }, { text = "Center", valign = "center", align = "center", widget = wibox.widget.textbox, }, widget = wibox.layout.stack } } e large wallpaper are made to span multiple screens.
- bg gears.color
-
The background color.
It will be used as the "fill" color if the
image
doesn't take all the screen space. It will also be the default background for thewidget.
As usual with colors in AwesomeWM`, it can also be a gradient or a pattern.
See also:
- fg gears.color
-
The foreground color.
This will be used by the widget (if any).
As usual with colors in
AwesomeWM
, it can also be a gradient or a pattern.See also:
- honor_workarea boolean
-
Honor the workarea.
When set to
true
, the wallpaper will only fill the workarea space instead of the entire screen. This means it wont be drawn below the awful.wibar or docked clients. This is useful when using opaque bars. Note that it can cause aspect ratio issues for the wallpaperimage
and add bars colored with the bg color on the sides.See also:
- honor_padding boolean
-
Honor the screen padding.
When set, this will look at the screen.padding property to restrict the area where the wallpaper is rendered.
Usage example output:
See also:
Usage:
-- Add some padding to the first screen. screen[1].padding = { left = 30, right = 10, } local wall = awful.wallpaper { screen = screen[1], honor_workarea = true, honor_padding = true, bg = "#222222", uncovered_areas_color = "#ff0000", widget = wibox.widget { fit = function(_, width, height) return width, height end, draw = function(_, _, cr, width, height) local radius = math.min(width, height)/2 cr:arc(width/2, height/2, radius, 0, 2 * math.pi) cr:set_source(gears.color { type = "radial", from = { width/2, radius, 20 }, to = { width/2, radius, 120 }, stops = { { 0, "#0000ff" }, { 1, "#ff0000" }, { 1, "#000000" }, } }) cr:fill() end, widget = wibox.widget.base.make_widget() } } -- Areas due to the padding and the wibar (workarea). for _, area in ipairs(wall.uncovered_areas) do print("Uncovered area:", area.x, area.y, area.width, area.height) end
- uncovered_areas table
-
Returns the list of screen(s) area which won't be covered by the wallpaper.
When honor_workarea, honor_padding or panning are used, some section of the screen won't have a wallpaper. This returns a list of areas tables. Each table has a
x
,y
,width
andheight
key.See also:
- uncovered_areas_color gears.color
-
The color for the uncovered areas.
Some application rely on the wallpaper for "fake" transparency. Even if an area is hidden under a wibar (or other clients), its background can still become visible. If you use such application and change your screen geometry often enough, it is possible some areas would become filled with the remains of previous wallpapers. This property allows to clean those areas with a solid color or a gradient.
See also:
- panning_area function or string
-
Defines where the wallpaper is placed when there is multiple screens.
When there is more than 1 screen, it is possible they don't have the same resolution, position or orientation. Panning the wallpaper over them may look better if a continuous rectangle is used rather than creating a virtual rectangle around all screens.
The default algorithms are:
outer: (default)
Draw an imaginary rectangle around all screens.
inner:
Take the largest area or either
inner_horizontal
orinner_vertical
.inner_horizontal:
Take the smallest
x
value, the largestx+width
, the smallesty
and the smallesty+height
.inner_vertical:
Take the smallest
y
value, the largesty+height
, the smallestx
and the smallestx+width
.Custom function:
It is also possible to define a custom function.
Usage example output:
Usage example:
local function custom_panning_area(wallpaper) return { x = wallpaper.screens[1].geometry.x + 50, y = wallpaper.screens[2].geometry.y + 50, width = 96, height = 96, } end -- Areas due to the padding and the wibar (workarea). for k, wall in ipairs(walls) do for _, area in ipairs(wall.uncovered_areas) do print("Uncovered wallpaper #".. k .." area:", area.x, area.y, area.width, area.height) end end
See also:
Object methods
- :add_screen (screen)
-
Add another screen (enable panning).
Before:
After:
Also note that adding a non-continuous screen might not work well, but will not automatically add the screens in between:
Parameters:
- screen screen The screen object.
See also:
- :detach ()
-
Detach the wallpaper from all screens.
Adding a new wallpaper to a screen will automatically detach the older one. However there is some case when it is useful to call this manually. For example, when adding a new panned wallpaper, it is possible that 2 wallpaper will have an overlap.
See also:
- :repaint ()
-
Repaint the wallpaper.
By default, even if the widget changes, the wallpaper will NOT be automatically repainted. Repainting the native X11 wallpaper is slow and it would be too easy to accidentally cause a performance problem. If you really need to repaint the wallpaper, call this method.
- :remove_screen (screen)
-
Remove a screen.
Calling this will remove a screen, but will not repaint its area. In this example, the wallpaper was spanning all 3 screens and the first screen was removed:
wall:remove_screen(screen[1])
As you can see, the content of screen 1 still looks like it is part of the 3 screen wallpaper. The only use case for calling this method is if you use a 3rd party tools to change the wallpaper.
If you wish to simply remove a screen and not have leftover content, it is simpler to just create a new wallpaper for that screen:
awful.wallpaper { screen = screen[1], bg = "#00ffff", }
Parameters:
- screen screen The screen to remove.
See also: