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, }, }
To maintain the image's aspect ratio while filling the screen, the image can be cropped using gears.surface:
awful.wallpaper { screen = s, widget = { image = gears.surface.crop_surface { surface = gears.surface.load_uncached(beautiful.wallpaper), ratio = s.geometry.width/s.geometry.height, }, 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", halign = "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 to 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 <[email protected]>
(Full contributors list available on our github project)
Constructors
awful.wallpaper {[args]} | Create a wallpaper. |
Object properties
widget | widget or nil | 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 | color | The background color. | |
fg | 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 | 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) -> boolean | Remove a screen. |
Theme variables
beautiful.wallpaper_bg | 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:
Note: This constructors uses named parameters calling convention. It means you call it with{}
and omit the parantheses. For example, calling this will all default argument would beawful.wallpaper{}
. This is a Lua shortcut syntax equivalent toawful.wallpaper({})
.args
is only a placeholder name for the "lone table argument" used in named parameters calls.Name Type(s) Description args table widget Optional wibox.widget The wallpaper widget. dpi Optional number The wallpaper DPI (dots per inch). screen Optional screen The wallpaper screen. screens Optional 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, ...}
)bg Optional gears.color The background color. fg Optional gears.color The foreground color. uncovered_areas_color Optional gears.color The color for the uncovered areas. honor_workarea Optional boolean Honor the workarea. honor_padding Optional boolean Honor the screen padding. uncovered_areas Optional table Returns the list of screen(s) area which won't be covered by the wallpaper. panning_area Optional function or string Defines where the wallpaper is placed when there is multiple screens.
Object properties
- 🔗 widget widget or nil
-
The wallpaper widget.
When set, instead of using the
image_path
orsurface
properties, the wallpaper will be defined as a normal wibox widget tree.Constraints:
Default value : nil
See also:
wibox.widget.imagebox A widget to display an image. module wibox.container.tile Replicate the content of the widget over and over. module - 🔗 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).
Constraints:
Default value : self.screen.dpi
Unit : pixel_per_inch Negative allowed : false See also:
screen A physical or virtual screen object. module screen.dpi The number of pixels per inch of the screen. (screen) object properties 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", halign = "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.
Constraints:
Default value : Obtained from the constructor. Type description: screen : A valid screen object such as retured by awful.screen.focused()
or mouse.screen.integer : A screen global id. Avoid using this since they are unsorted. string : The "primary"
value is also valid.See also:
screens A list of screen for this wallpaper. object properties add_screen Add another screen (enable panning). object methods remove_screen Remove a screen. object methods - 🔗 screens table
-
A list of screen for this wallpaper.
Constraints:
Default value : {self.screen}
Table content : A list of screen objects. See also:
screen A physical or virtual screen object. module add_screen Add another screen (enable panning). object methods remove_screen Remove a screen. object methods detach Detach the wallpaper from all screens. object methods 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", halign = "center", widget = wibox.widget.textbox, }, widget = wibox.layout.stack } } Some large wallpaper are made to span multiple screens.
- 🔗 bg color · 1 theme variable
-
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 the widget.As usual with colors in
AwesomeWM
, it can also be a gradient or a pattern.Constraints:
Default value : beautiful.wallpaper_bg
Type description: string : An hexadecimal color code, such as "#ff0000"
for red.string : A color name, such as "red"
.table : A gradient table. cairo.pattern : Any valid Cairo pattern. cairo.pattern : A texture build from an image by gears.color.create_png_pattern See also:
gears.color This module simplifies the creation of cairo pattern objects. module
Click to display more Consumed theme variables:
Theme variable Usage beautiful.wallpaper_bg beautiful.wallpaper_bg - 🔗 fg 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.Constraints:
Default value : beautiful.wallpaper_fg
Type description: string : An hexadecimal color code, such as "#ff0000"
for red.string : A color name, such as "red"
.table : A gradient table. cairo.pattern : Any valid Cairo pattern. cairo.pattern : A texture build from an image by gears.color.create_png_pattern See also:
gears.color This module simplifies the creation of cairo pattern objects. module
Click to display more Consumed theme variables:
Theme variable Usage beautiful.wallpaper_fg - 🔗 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.Constraints:
Default value : false
Valid values : true
orfalse
.See also:
honor_padding Honor the screen padding. object properties uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper. object properties - 🔗 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:
Uncovered area: 0 0 30 196 Uncovered area: 0 0 320 14 Uncovered area: 310 0 10 196
Constraints:
Default value : false
Valid values : true
orfalse
.See also:
honor_workarea Honor the workarea. object properties uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper. object properties 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.
Constraints:
Default value : This depends on the honor_workarea
andhonor_padding
values.Table content: : A list of area tables with the following keys: x
(number)y
(number)width
(number)height
(number)See also:
honor_workarea Honor the workarea. object properties honor_padding Honor the screen padding. object properties uncovered_areas_color The color for the uncovered areas. object properties - 🔗 uncovered_areas_color 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.
Constraints:
Default value : "transparent"
Type description: string : An hexadecimal color code, such as "#ff0000"
for red.string : A color name, such as "red"
.table : A gradient table. cairo.pattern : Any valid Cairo pattern. cairo.pattern : A texture build from an image by gears.color.create_png_pattern See also:
uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper. object properties - 🔗 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
Constraints:
Default value : "outer"
Type description: string : A panning algorithm function: : Custom panning function. Function prototype: Parameters: wallpaper (awful.wallpaper) : The wallpaper object. Return (A) : table with x
,y
,width
andheight
keys,Valid values: "outer"
"inner"
"inner_horizontal"
"inner_vertical"
See also:
uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper. object properties
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:
Name Type(s) Description screen screen The screen object. See also:
remove_screen Remove a screen. object methods - 🔗 :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:
remove_screen Remove a screen. object methods add_screen Add another screen (enable panning). object methods - 🔗 :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) -> boolean
-
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:
Name Type(s) Description screen screen The screen to remove. Returns:
-
boolean
true
if the screen was removed andfalse
if the screen wasn't found.See also:
detach Detach the wallpaper from all screens. object methods add_screen Add another screen (enable panning). object methods screens A list of screen for this wallpaper. object properties
Theme variables
- 🔗 beautiful.wallpaper_bg color · 1 theme variable
-
The default wallpaper background color.
See also:
bg The background color. object properties
Click to display more Consumed theme variables:
Theme variable Usage beautiful.wallpaper_fg Used by:
- 🔗 beautiful.wallpaper_fg gears.color
-
The default wallpaper foreground color.
This is useful when using widgets or text in the wallpaper. A wallpaper created from a single image wont use this.
See also:
bg The background color. object properties
Click to display more Used by:
- fg The foreground color.
- fg The foreground color.
- beautiful.wallpaper_bg The default wallpaper background color.