Skip to content
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Cannot retrieve contributors at this time
--- Key+value based theme library and associated utility modules.
-- @author Damien Leone <>
-- @author Julien Danjou <>
-- @copyright 2008-2009 Damien Leone, Julien Danjou
-- @themelib beautiful
-- Grab environment
local os = os
local pairs = pairs
local type = type
local dofile = dofile
local setmetatable = setmetatable
local lgi = require("lgi")
local Pango = lgi.Pango
local PangoCairo = lgi.PangoCairo
local gears_debug = require("gears.debug")
local Gio = require("lgi").Gio
local protected_call = require("gears.protected_call")
local xresources = require("beautiful.xresources")
local theme_assets = require("beautiful.theme_assets")
local gtk = require("beautiful.gtk")
local beautiful = {
xresources = xresources,
theme_assets = theme_assets,
gtk = gtk,
mt = {}
-- Local data
local theme = {}
local descs = setmetatable({}, { __mode = 'k' })
local fonts = setmetatable({}, { __mode = 'v' })
local active_font
-- luacheck: max comment line length 300
--- Get GTK+3 theme variables from GtkStyleContext
-- @treturn table Key-value table with the following structure:
-- <table class='widget_list' border=1>
-- <tr style='font-weight: bold;'> <th align='center'>Result key</th> <th align='center'>StyleContext key</th> <th align='center'>StyleContext fallback #1</th> <th align='center'>StyleContext fallback #2</th> <th align='center'>GTK Widget fallback</th> </tr>
-- <tr> <td>`font_size`</td> <td></td> <td></td> <td></td> <td>Label font-size</td> </tr>
-- <tr> <td>`font_family`</td> <td></td> <td></td> <td></td> <td>Label font-family</td> </tr>
-- <tr> <td>`bg_color`</td> <td>`theme_bg_color`</td> <td></td> <td></td> <td>Window bg</td> </tr>
-- <tr> <td>`fg_color`</td> <td>`theme_fg_color`</td> <td></td> <td></td> <td>Window fg</td> </tr>
-- <tr> <td>`base_color`</td> <td>`theme_base_color`</td> <td></td> <td></td> <td>Entry bg</td> </tr>
-- <tr> <td>`text_color`</td> <td>`theme_text_color`</td> <td></td> <td></td> <td>Entry fg</td> </tr>
-- <tr> <td>`button_bg_color`</td> <td>`theme_button_bg_color`</td> <td>`theme_bg_color`</td> <td></td> <td>Button bg</td> </tr>
-- <tr> <td>`button_fg_color`</td> <td>`theme_button_fg_color`</td> <td>`theme_fg_color`</td> <td></td> <td>Button fg</td> </tr>
-- <tr> <td>`button_border_color`</td> <td></td> <td></td> <td></td> <td>Button border-color</td> </tr>
-- <tr> <td>`button_border_radius`</td> <td></td> <td></td> <td></td> <td>Button border-radius</td> </tr>
-- <tr> <td>`button_border_width`</td> <td></td> <td></td> <td></td> <td>Button border-top-width</td> </tr>
-- <tr> <td>`selected_bg_color`</td> <td>`theme_selected_bg_color`</td> <td></td> <td></td> <td>ToggleButton bg</td> </tr>
-- <tr> <td>`selected_fg_color`</td> <td>`theme_selected_fg_color`</td> <td></td> <td></td> <td>ToggleButton fg</td> </tr>
-- <tr> <td>`menubar_bg_color`</td> <td>`menubar_bg_color`</td> <td>`theme_bg_color`</td> <td></td> <td>HeaderBar bg</td> </tr>
-- <tr> <td>`menubar_fg_color`</td> <td>`menubar_fg_color`</td> <td>`theme_fg_color`</td> <td></td> <td>HeaderBar fg</td> </tr>
-- <tr> <td>`header_button_bg_color`</td> <td>`header_button_bg_color`</td> <td>`menubar_bg_color`</td> <td>`theme_bg_color`</td> <td>HeaderBar > Button bg</td> </tr>
-- <tr> <td>`header_button_fg_color`</td> <td>`header_button_fg_color`</td> <td>`menubar_fg_color`</td> <td>`theme_fg_color`</td> <td>HeaderBar > Button fg</td> </tr>
-- <tr> <td>`header_button_border_color`</td> <td></td> <td></td> <td></td> <td>HeaderBar > Button border-color</td> </tr>
-- <tr> <td>`error_color`</td> <td>`error_color`</td> <td>`error_bg_color`</td> <td></td> <td>destructive Button bg</td> </tr>
-- <tr> <td>`error_bg_color`</td> <td>`error_bg_color`</td> <td>`error_color`</td> <td></td> <td>destructive Button bg</td> </tr>
-- <tr> <td>`error_fg_color`</td> <td>`error_fg_color`</td> <td>`theme_selected_fg_color`</td> <td></td> <td>destructive Button fg</td> </tr>
-- <tr> <td>`warning_color`</td> <td>`warning_color`</td> <td>`warning_bg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`warning_bg_color`</td> <td>`warning_bg_color`</td> <td>`warning_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`warning_fg_color`</td> <td>`warning_fg_color`</td> <td>`theme_selected_fg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`success_color`</td> <td>`success_color`</td> <td>`success_bg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`success_bg_color`</td> <td>`success_bg_color`</td> <td>`success_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`success_fg_color`</td> <td>`success_fg_color`</td> <td>`theme_selected_fg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`tooltip_bg_color`</td> <td>`theme_tooltip_bg_color`</td> <td>`theme_bg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`tooltip_fg_color`</td> <td>`theme_tooltip_fg_color`</td> <td>`theme_fg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`osd_bg_color`</td> <td>`osd_bg`</td> <td>`theme_tooltip_bg_color`</td> <td>`theme_bg_color`</td> <td></td> </tr>
-- <tr> <td>`osd_fg_color`</td> <td>`osd_fg`</td> <td>`theme_tooltip_fg_color`</td> <td>`theme_fg_color`</td> <td></td> </tr>
-- <tr> <td>`osd_border_color`</td> <td>`osd_borders_color`</td> <td>`osd_fg_color`</td> <td></td> <td></td> </tr>
-- <tr> <td>`wm_bg_color`</td> <td>`wm_bg`</td> <td>`menubar_bg_color`</td> <td>`theme_bg_color`</td> <td>HeaderBar bg</td> </tr>
-- <tr> <td>`wm_border_focused_color`</td> <td>`wm_border_focused`</td> <td>`theme_selected_bg_color`</td> <td></td> <td>ToggleButton bg</td> </tr>
-- <tr> <td>`wm_border_unfocused_color`</td> <td>`wm_border_unfocused`</td> <td>`wm_border`</td> <td>`menubar_bg_color`</td><td>HeaderBar bg</td> </tr>
-- <tr> <td>`wm_title_focused_color`</td> <td>`wm_title_focused`</td> <td>`wm_title`</td> <td>`theme_selected_fg_color`</td> <td>ToggleButton fg</td> </tr>
-- <tr> <td>`wm_title_unfocused_color`</td> <td>`wm_title_unfocused`</td> <td>`wm_unfocused_title`</td> <td>`menubar_fg_color`</td><td>HeaderBar fg</td> </tr>
-- <tr> <td>`wm_icons_focused_color`</td> <td>`wm_icons_focused`</td> <td>`wm_title_focused`</td> <td>`theme_selected_fg_color`</td> <td>ToggleButton fg</td> </tr>
-- <tr> <td>`wm_icons_unfocused_color`</td> <td>`wm_icons_unfocused`</td> <td>`wm_title_unfocused`</td> <td>`menubar_fg_color`</td> <td>HeaderBar fg</td> </tr>
-- </table>
-- @staticfct beautiful.gtk.get_theme_variables
--- The default font.
-- @beautiful beautiful.font
-- @param[opt="sans 8"] string
--- The default background color.
-- The background color can be transparent. If there is a
-- compositing manager such as compton, then it will be
-- real transparency and may include blur (provided by the
-- compositor). When there is no compositor, it will take
-- a picture of the wallpaper and blend it.
-- @beautiful beautiful.bg_normal
-- @param color
--- The default focused element background color.
-- @beautiful beautiful.bg_focus
-- @param color
--- The default urgent element background color.
-- @beautiful beautiful.bg_urgent
-- @param color
--- The default minimized element background color.
-- @beautiful beautiful.bg_minimize
-- @param color
--- The default focused element foreground (text) color.
-- @beautiful beautiful.fg_normal
-- @param color
--- The default focused element foreground (text) color.
-- @beautiful beautiful.fg_focus
-- @param color
--- The default urgent element foreground (text) color.
-- @beautiful beautiful.fg_urgent
-- @param color
--- The default minimized element foreground (text) color.
-- @beautiful beautiful.fg_minimize
-- @param color
--- The wallpaper path.
-- @beautiful beautiful.wallpaper
-- @tparam string|gears.surface wallpaper
--- The icon theme name.
-- It has to be a directory in `/usr/share/icons` or an XDG icon folder.
-- @beautiful beautiful.icon_theme
-- @param string
--- The Awesome icon path.
-- @beautiful beautiful.awesome_icon
-- @tparam string|gears.surface icon
--- The current theme path (if any)
-- @tfield string beautiful.theme_path
-- @param string
--- Load a font from a string or a font description.
-- @see
-- @tparam string|lgi.Pango.FontDescription name Font, which can be a
-- string or a lgi.Pango.FontDescription.
-- @treturn table A table with `name`, `description` and `height`.
local function load_font(name)
name = name or active_font
if name and type(name) ~= "string" then
if descs[name] then
name = descs[name]
name = name:to_string()
if fonts[name] then
return fonts[name]
-- Load new font
local desc = Pango.FontDescription.from_string(name)
local ctx = PangoCairo.font_map_get_default():create_context()
-- Apply default values from the context (e.g. a default font size)
desc:merge(ctx:get_font_description(), false)
-- Calculate font height.
local metrics = ctx:get_metrics(desc, nil)
local height = math.ceil((metrics:get_ascent() + metrics:get_descent()) / Pango.SCALE)
if height == 0 then
height = desc:get_size() / Pango.SCALE
"beautiful.load_font: could not get height for '%s' (likely missing font), using %d.",
name, height))
local font = { name = name, description = desc, height = height }
fonts[name] = font
descs[desc] = name
return font
--- Set an active font
-- @param name The font
local function set_font(name)
active_font = load_font(name).name
--- Get a font description.
-- See
-- @tparam string|lgi.Pango.FontDescription name The name of the font.
-- @treturn lgi.Pango.FontDescription
-- @staticfct beautiful.get_font
function beautiful.get_font(name)
return load_font(name).description
--- Get a new font with merged attributes, based on another one.
-- See
-- @tparam string|Pango.FontDescription name The base font.
-- @tparam string merge Attributes that should be merged, e.g. "bold".
-- @treturn lgi.Pango.FontDescription
-- @staticfct beautiful.get_merged_font
function beautiful.get_merged_font(name, merge)
local font = beautiful.get_font(name)
merge = Pango.FontDescription.from_string(merge)
local merged = font:copy_static()
merged:merge(merge, true)
return beautiful.get_font(merged:to_string())
--- Get the height of a font.
-- @tparam string name Name of the font.
-- @treturn number The font height.
-- @staticfct beautiful.get_font_height
function beautiful.get_font_height(name)
return load_font(name).height
--- Function that initializes the theme settings. Should be run at the
-- beginning of the awesome configuration file (normally rc.lua).
-- Example usages:
-- -- Using a table
-- beautiful.init({font = 'Monospace Bold 10'})
-- -- From a config file
-- beautiful.init("<path>/theme.lua")
-- Example "<path>/theme.lua" (see ``):
-- theme = {}
-- theme.font = 'Monospace Bold 10'
-- return theme
-- Example using the return value:
-- local beautiful = require("beautiful")
-- if not beautiful.init("<path>/theme.lua") then
-- beautiful.init("<path>/.last.theme.lua") -- a known good fallback
-- end
-- @tparam string|table config The theme to load. It can be either the path to
-- the theme file (which should return a table) or directly a table
-- containing all the theme values.
-- @treturn true|nil True if successful, nil in case of error.
-- @staticfct beautiful.init
function beautiful.init(config)
if config then
local state, t_theme = nil, nil
local homedir = os.getenv("HOME")
-- If `config` is the path to a theme file, run this file,
-- otherwise if it is a theme table, save it.
local t_config = type(config)
if t_config == 'string' then
-- Expand the '~' $HOME shortcut
config = config:gsub("^~/", homedir .. "/")
local dir = Gio.File.new_for_path(config):get_parent()
rawset(beautiful, "theme_path", dir and (dir:get_path().."/") or nil)
theme = protected_call(dofile, config)
t_theme = type(theme)
state = t_theme == 'table' and next(theme)
elseif t_config == 'table' then
rawset(beautiful, "theme_path", nil)
theme = config
state = next(theme)
if state then
-- expand '~'
if homedir then
for k, v in pairs(theme) do
if type(v) == "string" then theme[k] = v:gsub("^~/", homedir .. "/") end
if theme.font then set_font(theme.font) end
return true
rawset(beautiful, "theme_path", nil)
theme = {}
local file = t_config == 'string' and (" from: " .. config)
local err = (file and t_theme == 'table' and "got an empty table" .. file)
or (file and t_theme ~= 'table' and "got a " .. t_theme .. file)
or (t_config == 'table' and "got an empty table")
or ("got a " .. t_config)
return gears_debug.print_error("beautiful: error loading theme: " .. err)
return gears_debug.print_error("beautiful: error loading theme: no theme specified")
--- Get the current theme.
-- @treturn table The current theme table.
-- @staticfct beautiful.get
function beautiful.get()
return theme
return theme[k]
function, v)
theme[k] = v
-- Set the default font
set_font("sans 8")
return setmetatable(beautiful,
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80