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.

Usage example

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:

Usage example

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:

Usage example

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:

Usage example

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:

Usage example

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:

Usage example

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:

Usage example

awful.wallpaper {
    screen = s,
    bg     = {
        type  = "linear" ,
        from  = { 0, 0  },
        to    = { 0, 240 },
        stops = {
            { 0, "#0000ff" },
            { 1, "#ff0000" }
        }
     }
}

Usage example

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.

Usage example

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:

Usage example

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):

Usage example

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:

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)

Object properties

widget wibox.widget
The wallpaper widget.

When set, instead of using the image_path or surface 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).

Usage example

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.

Usage example

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 the widget.

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 wallpaper image and add bars colored with the bg color on the sides.

Usage example

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

Usage example output:

Uncovered area: 0   0   30  196
Uncovered area: 0   0   320 14
Uncovered area: 310 0   10  196

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 and height 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.

Usage example

inner:

Take the largest area or either inner_horizontal or inner_vertical.

Usage example

inner_horizontal:

Take the smallest x value, the largest x+width, the smallest y and the smallest y+height.

Usage example

inner_vertical:

Take the smallest y value, the largest y+height, the smallest x and the smallest x+width.

Usage example

Custom function:

It is also possible to define a custom function.

Usage example

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:

Usage example

After:

Usage example

Also note that adding a non-continuous screen might not work well, but will not automatically add the screens in between:

Usage example

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:

Usage example

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:

Usage example

awful.wallpaper {
    screen = screen[1],
    bg     = "#00ffff",
}

Parameters:

  • screen screen The screen to remove.

See also:

Theme variables

beautiful.wallpaper_bg gears.color
The default wallpaper background color.

See also:

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:

generated by LDoc 1.4.6 Last updated 2030-01-01 00:00:00