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:

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 be awful.wallpaper{}. This is a Lua shortcut syntax equivalent to awful.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 or surface 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 wallpaper image and add bars colored with the bg color on the sides.

Constraints:

Default value : false
Valid values : true or false.

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 or false.

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 and honor_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 or inner_vertical.

inner_horizontal:

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

inner_vertical:

Take the smallest y value, the largest y+height, the smallest x and the smallest x+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 and height 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 and false 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:

  • bg The background color.
  • bg The background color.
  • bg The background color.
🔗 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:

generated by LDoc 1.5.0