Merge pull request #3343 from Elv13/awful_wallpaper

Rewrite the wallpaper API
This commit is contained in:
Emmanuel Lepage Vallée 2021-10-02 13:38:21 -07:00 committed by GitHub
commit 2bca64b89c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 3146 additions and 245 deletions

View File

@ -77,7 +77,7 @@ mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
-- }}}
-- {{{ Tag
-- {{{ Tag layout
-- @DOC_LAYOUT@
-- Table of layouts to cover with awful.layout.inc, order matters.
tag.connect_signal("request::default_layouts", function()
@ -99,6 +99,27 @@ tag.connect_signal("request::default_layouts", function()
end)
-- }}}
-- {{{ Wallpaper
-- @DOC_WALLPAPER@
screen.connect_signal("request::wallpaper", function(s)
awful.wallpaper {
screen = s,
widget = {
{
image = beautiful.wallpaper,
upscale = true,
downscale = true,
widget = wibox.widget.imagebox,
},
valign = "center",
halign = "center",
tiled = false,
widget = wibox.container.tile,
}
}
end)
-- }}}
-- {{{ Wibar
-- Keyboard map indicator and switcher
@ -107,19 +128,6 @@ mykeyboardlayout = awful.widget.keyboardlayout()
-- Create a textclock widget
mytextclock = wibox.widget.textclock()
-- @DOC_WALLPAPER@
screen.connect_signal("request::wallpaper", function(s)
-- Wallpaper
if beautiful.wallpaper then
local wallpaper = beautiful.wallpaper
-- If wallpaper is a function, call it with the screen
if type(wallpaper) == "function" then
wallpaper = wallpaper(s)
end
gears.wallpaper.maximized(wallpaper, s, true)
end
end)
-- @DOC_FOR_EACH_SCREEN@
screen.connect_signal("request::desktop_decoration", function(s)
-- Each screen has its own tag table.

View File

@ -124,6 +124,10 @@ to an object such as the mouse.
The `naughty.layout.box` allows to provide custom widgets to use within the
notifications.
The `awful.wallpaper` provides a non-intereactive "backgroud" for one or more
`screen`. While it uses normal widget, it will not automatically be repainted
if they change. It will also not provide any mouse events.
Finally, the `awful.titlebar`, while not technically a real `wibox`, acts
exactly the same way and allows to attach widgets on each side of clients.

View File

@ -72,6 +72,17 @@ variables such as `bg_normal`. To get a list of all official variables, see
the [appearance guide](../documentation/06-appearance.md.html).
]]
sections.DOC_WALLPAPER = [[
The AwesomeWM wallpaper module, `awful.wallpaper` support both per-screen wallpaper
and wallpaper across multiple screens. In the default configuration, the `"request::wallpaper"` signal
is emitted everytime a screen is added, moved, resized or when the bars
(`awful.wibar`) are moved.
This is will suited for single-screen wallpapers. If you wish to use multi-screen wallpaper,
it is better to create a global wallpaper object and edit it when the screen change. See
the `add_screen`/`remove_screens` methods and the `screens` property of `awful.wallpaper` for
examples.
]]
sections.DOC_DEFAULT_APPLICATIONS = [[
 

View File

@ -38,7 +38,8 @@
# local use_li = ldoc.use_li
# local display_name = ldoc.display_name
# local iter = ldoc.modules.iter
# local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end
# local function un_cmake(s) return s:gsub("&#59", ";"):gsub("&#34", '"') end
# local function M(txt,item) return ldoc.markup(txt and un_cmake(txt) or nil,item,ldoc.plain) end
# local nowrap = ldoc.wrap and '' or 'nowrap'
# local html_space = function(s) return s:gsub(" ", "%%20") end
# local no_underscores = function(s) return s:gsub("_", " ") end
@ -189,7 +190,7 @@
<h3>Usage:</h3>
<ul>
# for usage in iter(module.usage) do
$(li)<pre class="example">$(ldoc.escape(usage))</pre>$(il)
$(li)<pre class="example">$(ldoc.escape(un_cmake(usage)))</pre>$(il)
# end -- for
</ul>
# end -- if usage
@ -331,7 +332,7 @@
# end
# if kitem.usage then
<h3>Usage:</h3>
<pre class="example">$(ldoc.prettify(kitem.usage[1]))</pre>
<pre class="example">$(ldoc.prettify(un_cmake(kitem.usage[1])))</pre>
# end
# end
# if not kind:match("^ldoc_skip") then
@ -450,7 +451,7 @@
<h3>Usage:</h3>
<ul>
# for usage in iter(item.usage) do
$(li)<pre class="example">$(ldoc.prettify(usage))</pre>$(il)
$(li)<pre class="example">$(ldoc.prettify(un_cmake(usage)))</pre>$(il)
# end -- for
</ul>
# end -- if usage

View File

@ -58,6 +58,28 @@ do
assert(root.object == root_object)
end
--- The old wallpaper only took native surfaces.
--
-- This was a problem for the test backend. The new function takes both
-- native surfaces and LGI-ified Cairo surfaces.
function root.wallpaper(pattern)
if not pattern then return root._wallpaper() end
-- Checking for type will either potentially `error()` or always
-- return `userdata`. This check will error() when the surface is
-- already native.
local err = pcall(function() return pattern._native end)
-- The presence of `root._write_string` means the test backend is
-- used. Avoid passing the native surface.
if err and not root._write_string then
return root._wallpaper(pattern._native)
else
return root._wallpaper(pattern)
end
end
-- root.bottons() used to be a capi function. However this proved confusing
-- as rc.lua used `awful.button` and `root.buttons()` used capi.button. There
-- was a little documented hack to "flatten" awful.button into a pair of

View File

@ -35,6 +35,7 @@ local ret = {
tooltip = require("awful.tooltip");
permissions = require("awful.permissions");
titlebar = require("awful.titlebar");
wallpaper = require("awful.wallpaper");
rules = require("awful.rules");
popup = require("awful.popup");
spawn = require("awful.spawn");

862
lib/awful/wallpaper.lua Normal file
View File

@ -0,0 +1,862 @@
---------------------------------------------------------------------------
--- 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.
--
--@DOC_awful_wallpaper_mazimized1_EXAMPLE@
--
-- If the image aspect ratio doesn't match, the `bg` property can be used to
-- fill the empty area:
--
--@DOC_awful_wallpaper_mazimized2_EXAMPLE@
--
-- It is also possible to stretch the image:
--
--@DOC_awful_wallpaper_mazimized3_EXAMPLE@
--
-- Finally, it is also possible to use simpler "branding" in a corner using
-- `awful.placement`:
--
--@DOC_awful_wallpaper_corner1_EXAMPLE@
--
-- Tiled
-- =====
--
-- This example tiles an image:
--
--@DOC_awful_wallpaper_tiled1_EXAMPLE@
--
-- This one tiles a shape using the `wibox.widget.separator` widget:
--
--@DOC_awful_wallpaper_tiled2_EXAMPLE@
--
-- 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:
--
--@DOC_awful_wallpaper_gradient1_EXAMPLE@
--
--@DOC_awful_wallpaper_gradient2_EXAMPLE@
--
-- 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.
--
--@DOC_awful_wallpaper_widget2_EXAMPLE@
--
-- 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:
--
--@DOC_awful_wallpaper_widget1_EXAMPLE@
--
--
-- 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`):
--
--@DOC_awful_wallpaper_svg_EXAMPLE@
--
-- 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:
--
-- @DOC_text_awful_wallpaper_multi_screen_EXAMPLE@
--
-- 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:
--
--@DOC_awful_wallpaper_slideshow1_EXAMPLE@
--
-- @author Emmanuel Lepage Vallee &lt;elv1313@gmail.com&gt;
-- @copyright 2019 Emmanuel Lepage Vallee
-- @popupmod awful.wallpaper
---------------------------------------------------------------------------
require("awful._compat")
local gtable = require( "gears.table" )
local gobject = require( "gears.object" )
local gcolor = require( "gears.color" )
local gtimer = require( "gears.timer" )
local surface = require( "gears.surface" )
local base = require( "wibox.widget.base" )
local background = require( "wibox.container.background")
local beautiful = require( "beautiful" )
local cairo = require( "lgi" ).cairo
local draw = require( "wibox.widget" ).draw_to_cairo_context
local grect = require( "gears.geometry" ).rectangle
local capi = { screen = screen, root = root }
local module = {}
local function get_screen(s)
return s and capi.screen[s]
end
-- Screen as key, wallpaper as values.
local pending_repaint = setmetatable({}, {__mode = 'k'})
local backgrounds = setmetatable({}, {__mode = 'k'})
local panning_modes = {}
-- Get a list of all screen areas.
local function get_rectangles(screens, honor_workarea, honor_padding)
local ret = {}
for _, s in ipairs(screens) do
table.insert(ret, s:get_bounding_geometry {
honor_padding = honor_padding,
honor_workarea = honor_workarea
})
end
return ret
end
-- Outer perimeter of all rectangles.
function panning_modes.outer(self)
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
local p1, p2 = {x = math.huge, y = math.huge}, {x = 0, y = 0}
for _, rect in ipairs(rectangles) do
p1.x, p1.y = math.min(p1.x, rect.x), math.min(p1.y, rect.y)
p2.x, p2.y = math.max(p2.x, rect.x + rect.width), math.max(p2.y, rect.y + rect.height)
end
-- Never try to paint this, it would freeze the system.
assert(p1.x ~= math.huge and p1.y ~= math.huge, "Setting wallpaper failed"..#self.screens)
return {
x = p1.x,
y = p1.y,
width = p2.x - p1.x,
height = p2.y - p1.y,
}
end
-- Horizontal inner perimeter of all rectangles.
function panning_modes.inner_horizontal(self)
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
local p1, p2 = {x = math.huge, y = 0}, {x = 0, y = math.huge}
for _, rect in ipairs(rectangles) do
p1.x, p1.y = math.min(p1.x, rect.x), math.max(p1.y, rect.y)
p2.x, p2.y = math.max(p2.x, rect.x + rect.width), math.min(p2.y, rect.y + rect.height)
end
-- Never try to paint this, it would freeze the system.
assert(p1.x ~= math.huge and p2.y ~= math.huge, "Setting wallpaper failed")
return {
x = p1.x,
y = p1.y,
width = p2.x - p1.x,
height = p2.y - p1.y,
}
end
-- Vertical inner perimeter of all rectangles.
function panning_modes.inner_vertical(self)
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
local p1, p2 = {x = 0, y = math.huge}, {x = math.huge, y = 0}
for _, rect in ipairs(rectangles) do
p1.x, p1.y = math.max(p1.x, rect.x), math.min(p1.y, rect.y)
p2.x, p2.y = math.min(p2.x, rect.x + rect.width), math.max(p2.y, rect.y + rect.height)
end
-- Never try to paint this, it would freeze the system.
assert(p1.y ~= math.huge and p2.a ~= math.huge, "Setting wallpaper failed")
return {
x = p1.x,
y = p1.y,
width = p2.x - p1.x,
height = p2.y - p1.y,
}
end
-- Best or vertical and horizontal "inner" modes.
function panning_modes.inner(self)
local vert = panning_modes.inner_vertical(self)
local hori = panning_modes.inner_horizontal(self)
if vert.width <= 0 or vert.height <= 0 then return hori end
if hori.width <= 0 or hori.height <= 0 then return vert end
if vert.width * vert.height > hori.width * hori.height then
return vert
else
return hori
end
end
local function paint()
if not next(pending_repaint) then return end
local root_width, root_height = capi.root.size()
-- Get the current wallpaper content.
local source = surface(root.wallpaper())
local target, cr
-- It's possible that a wallpaper for 1 screen is set using another tool, so make
-- sure we copy the current content.
if source then
target = source:create_similar(cairo.Content.COLOR, root_width, root_height)
cr = cairo.Context(target)
-- Copy the old wallpaper to the new one
cr:save()
cr.operator = cairo.Operator.SOURCE
cr:set_source_surface(source, 0, 0)
for s in screen do
cr:rectangle(
s.geometry.x,
s.geometry.y,
s.geometry.width,
s.geometry.height
)
end
cr:clip()
cr:paint()
cr:restore()
else
target = cairo.ImageSurface(cairo.Format.RGB32, root_width, root_height)
cr = cairo.Context(target)
end
local walls = {}
for _, wall in pairs(backgrounds) do
walls[wall] = true
end
-- Not supposed to happen, but there is enough API surface for
-- it to be a side effect of some signals. Calling the panning
-- mode callback with zero screen is not supported.
if not next(walls) then
return
end
for wall in pairs(walls) do
local geo = type(wall._private.panning_area) == "function" and
wall._private.panning_area(wall) or
panning_modes[wall._private.panning_area](wall)
-- If false, this panning area isn't well suited for the screen geometry.
if geo.width > 0 or geo.height > 0 then
local uncovered_areas = grect.area_remove(get_rectangles(wall.screens, false, false), geo)
cr:save()
-- Prevent overwrite then there is multiple non-continuous screens.
for _, s in ipairs(wall.screens) do
cr:rectangle(
s.geometry.x,
s.geometry.y,
s.geometry.width,
s.geometry.height
)
end
cr:clip()
-- The older surface might contain garbage, optionally clean it.
if wall.uncovered_areas_color then
cr:set_source(gcolor(wall.uncovered_areas_color))
for _, area in ipairs(uncovered_areas) do
cr:rectangle(area.x, area.y, area.width, area.height)
cr:fill()
end
end
if not wall._private.container then
wall._private.container = background()
wall._private.container.bg = wall._private.bg or beautiful.wallpaper_bg or "#000000"
wall._private.container.fg = wall._private.fg or beautiful.wallpaper_fg or "#ffffff"
wall._private.container.widget = wall.widget
end
local a_context = {
dpi = wall._private.context.dpi
}
-- Pick the lowest DPI.
if not a_context.dpi then
a_context.dpi = math.huge
for _, s in ipairs(wall.screens) do
a_context.dpi = math.min(
s.dpi and s.dpi or s.preferred_dpi, a_context.dpi
)
end
end
-- Fallback.
if not a_context.dpi then
a_context.dpi = 96
end
cr:translate(geo.x, geo.y)
draw(wall._private.container, cr, geo.width, geo.height, a_context)
cr:restore()
end
end
-- Set the wallpaper.
local pattern = cairo.Pattern.create_for_surface(target)
capi.root.wallpaper(pattern)
-- Limit some potential GC induced increase in memory usage.
-- But really, is someone is trying to apply wallpaper changes more
-- often than the GC is executed, they are doing it wrong.
target:finish()
end
local mutex = false
-- Uploading the surface to X11 is *very* resource intensive. Given the updates
-- will often happen in batch (like startup), make sure to only do one "real"
-- update.
local function update()
if mutex then return end
mutex = true
gtimer.delayed_call(function()
-- Remove the mutex first in case `paint()` raises an exception.
mutex = false
paint()
end)
end
capi.screen.connect_signal("removed", function(s)
if not backgrounds[s] then return end
backgrounds[s]:remove_screen(s)
update()
end)
capi.screen.connect_signal("property::geometry", function(s)
if not backgrounds[s] then return end
backgrounds[s]:repaint()
end)
--- 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.
--
-- @property widget
-- @tparam wibox.widget widget
-- @see wibox.widget.imagebox
-- @see wibox.container.tile
--- 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`).
--
-- @DOC_awful_wallpaper_dpi1_EXAMPLE@
--
-- @property dpi
-- @tparam[opt=screen.dpi] number dpi
-- @see screen
-- @see screen.dpi
--- 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.
--
-- @property screen
-- @tparam screen screen
-- @see screens
-- @see add_screen
-- @see remove_screen
--- A list of screen for this wallpaper.
--
--@DOC_awful_wallpaper_screens1_EXAMPLE@
--
-- Some large wallpaper are made to span multiple screens.
-- @property screens
-- @tparam table screens
-- @see screen
-- @see add_screen
-- @see remove_screen
-- @see detach
--- 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.
--
-- @property bg
-- @tparam gears.color bg
-- @see 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.
--
-- @property fg
-- @tparam gears.color fg
-- @see gears.color
--- The default wallpaper background color.
-- @beautiful beautiful.wallpaper_bg
-- @tparam gears.color wallpaper_bg
-- @see bg
--- 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.
--
-- @beautiful beautiful.wallpaper_fg
-- @tparam gears.color wallpaper_fg
-- @see bg
--- 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.
--
--@DOC_awful_wallpaper_workarea1_EXAMPLE@
--
-- @property honor_workarea
-- @tparam[opt=false] boolean honor_workarea
-- @see honor_padding
-- @see uncovered_areas
--- Honor the screen padding.
--
-- When set, this will look at the `screen.padding` property to restrict the
-- area where the wallpaper is rendered.
--
-- @DOC_awful_wallpaper_padding1_EXAMPLE@
--
-- @property honor_padding
-- @tparam boolean honor_padding
-- @see honor_workarea
-- @see uncovered_areas
--- 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.
--
-- @property uncovered_areas
-- @tparam table uncovered_areas
-- @see honor_workarea
-- @see honor_padding
-- @see uncovered_areas_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.
--
-- @property uncovered_areas_color
-- @tparam gears.color uncovered_areas_color
-- @see uncovered_areas
--- 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.
--
-- @DOC_awful_wallpaper_panning_outer_EXAMPLE@
--
-- **inner:**
--
-- Take the largest area or either `inner_horizontal` or `inner_vertical`.
--
-- @DOC_awful_wallpaper_panning_inner_EXAMPLE@
--
-- **inner_horizontal:**
--
-- Take the smallest `x` value, the largest `x+width`, the smallest `y`
-- and the smallest `y+height`.
--
-- @DOC_awful_wallpaper_panning_inner_horizontal_EXAMPLE@
--
-- **inner_vertical:**
--
-- Take the smallest `y` value, the largest `y+height`, the smallest `x`
-- and the smallest `x+width`.
--
-- @DOC_awful_wallpaper_panning_inner_vertical_EXAMPLE@
--
-- **Custom function:**
--
-- It is also possible to define a custom function.
--
-- @DOC_awful_wallpaper_panning_custom_EXAMPLE@
--
-- @property panning_area
-- @tparam function|string panning_area
-- @see uncovered_areas
function module:set_panning_area(value)
value = value or "outer"
assert(type(value) == "function" or panning_modes[value], "Invalid panning mode: "..tostring(value))
self._private.panning_area = value
self:repaint()
self:emit_signal("property::panning_area", value)
end
function module:set_widget(w)
self._private.widget = base.make_widget_from_value(w)
if self._private.container then
self._private.container.widget = self._private.widget
end
self:repaint()
end
function module:get_widget()
return self._private.widget
end
function module:set_dpi(dpi)
self._private.context.dpi = dpi
self:repaint()
end
function module:get_dpi()
return self._private.context.dpi
end
function module:set_screen(s)
if not s then return end
self:_clear()
self:add_screen(s)
end
for _, prop in ipairs {"bg", "fg"} do
module["set_"..prop] = function(self, color)
if self._private.container then
self._private.container[prop] = color
end
self._private[prop] = color
self:repaint()
end
end
function module:get_uncovered_areas()
local geo = type(self._private.panning_area) == "function" and
self._private.panning_area(self) or
panning_modes[self._private.panning_area](self)
return grect.area_remove(get_rectangles(self.screens, false, false), geo)
end
function module:set_screens(screens)
local to_rem = {}
-- All screens.
-- The copy is needed because it's a metatable, `ipairs` doesn't work
-- correctly in all Lua versions.
if screens == capi.screen then
screens = {}
for s in capi.screen do
table.insert(screens, s)
end
end
for _, s in ipairs(screens) do
to_rem[get_screen(s)] = true
end
for _, s in ipairs(self.screens) do
to_rem[get_screen(s)] = nil
end
for _, s in ipairs(screens) do
s = get_screen(s)
self:add_screen(s)
to_rem[s] = nil
end
for s, remove in pairs(to_rem) do
if remove then
self:remove_screen(s)
end
end
end
function module:get_screens()
return self._private.screens
end
--- Add another screen (enable panning).
--
-- **Before:**
--
--@DOC_awful_wallpaper_add_screen1_EXAMPLE@
--
-- **After:**
--
--@DOC_awful_wallpaper_add_screen2_EXAMPLE@
--
-- Also note that adding a non-continuous screen might not work well,
-- but will not automatically add the screens in between:
--
--@DOC_awful_wallpaper_add_screen3_EXAMPLE@
--
-- @method add_screen
-- @tparam screen screen The screen object.
-- @see remove_screen
function module:add_screen(s)
s = get_screen(s)
for _, s2 in ipairs(self._private.screens) do
if s == s2 then return end
end
table.insert(self._private.screens, s)
if backgrounds[s] and backgrounds[s] ~= self then
backgrounds[s]:remove_screen(s)
end
backgrounds[s] = self
self:repaint()
end
--- 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.
--
-- @method detach
-- @see remove_screen
-- @see add_screen
function module:detach()
local screens = gtable.clone(self.screens)
for _, s in ipairs(screens) do
self:remove_screen(s)
end
end
function module:_clear()
self._private.screens = setmetatable({}, {__mode = "v"})
update()
end
--- 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.
--
-- @method repaint
function module:repaint()
for _, s in ipairs(self._private.screens) do
pending_repaint[s] = true
end
update()
end
--- 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:
--
-- @DOC_awful_wallpaper_remove_screen1_EXAMPLE@
--
-- 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:
--
-- @DOC_awful_wallpaper_remove_screen2_EXAMPLE@
--
-- @method remove_screen
-- @tparam screen screen The screen to remove.
-- @see detach
-- @see add_screen
-- @see screens
function module:remove_screen(s)
s = get_screen(s)
for k, s2 in ipairs(self._private.screens) do
if s == s2 then
table.remove(self._private.screens, k)
end
end
backgrounds[s] = nil
self:repaint()
end
--- Create a wallpaper.
--
-- Note that all parameters are not required. Please refer to the
-- module description and examples to understand parameters usages.
--
-- @constructorfct awful.wallpaper
-- @tparam table args
-- @tparam[opt] wibox.widget args.widget The wallpaper widget.
-- @tparam[opt] number args.dpi The wallpaper DPI (dots per inch).
-- @tparam[opt] screen args.screen The wallpaper screen.
-- @tparam[opt] table args.screens 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, ...}`)
-- @tparam[opt] gears.color args.bg The background color.
-- @tparam[opt] gears.color args.fg The foreground color.
-- @tparam[opt] gears.color args.uncovered_areas_color The color for the uncovered areas.
-- @tparam[opt] boolean args.honor_workarea Honor the workarea.
-- @tparam[opt] boolean args.honor_padding Honor the screen padding.
-- @tparam[opt] table args.uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper.
-- @tparam[opt] function|string args.panning_area Defines where the wallpaper is placed when there is multiple screens.
local function new(_, args)
args = args or {}
local ret = gobject {
enable_auto_signals = true,
enable_properties = true,
}
rawset(ret, "_private", {})
ret._private.context = {}
ret._private.panning_area = "outer"
gtable.crush(ret, module, true)
ret:_clear()
-- Set the screen or screens first to avoid a race condition
-- with the other setters.
local args_screen, args_screens = args.screen, args.screens
if args_screen then
ret.screen = args_screen
elseif args_screens then
ret.screens = args_screens
end
-- Avoid crushing `screen` and `screens` twice.
args.screen, args.screens = nil, nil
gtable.crush(ret, args, false)
args.screen, args.screens = args_screen, args_screens
return ret
end
return setmetatable(module, {__call = new})

View File

@ -172,28 +172,39 @@ end
-- @tparam string path The directory to search.
-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }`
-- If ommited, all files are considered.
-- @tparam[opt=false] boolean absolute_path Return the absolute path instead of the filename.
-- @treturn string|nil A randomly selected filename from the specified path (with
-- a specified extension if required) or nil if no suitable file is found.
-- a specified extension if required) or nil if no suitable file is found. If `absolute_path`
-- is set, then a path is returned instead of a file name.
-- @staticfct gears.filesystem.get_random_file_from_dir
function filesystem.get_random_file_from_dir(path, exts)
function filesystem.get_random_file_from_dir(path, exts, absolute_path)
local files, valid_exts = {}, {}
-- Transforms { "jpg", ... } into { [jpg] = #, ... }
if exts then for i, j in ipairs(exts) do valid_exts[j:lower()] = i end end
if exts then for i, j in ipairs(exts) do valid_exts[j:lower():gsub("^[.]", "")] = i end end
-- Build a table of files from the path with the required extensions
local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0)
-- This will happen when the directory doesn't exist.
if not file_list then return nil end
for file in function() return file_list:next_file() end do
if file:get_file_type() == "REGULAR" then
local file_name = file:get_display_name()
if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then
table.insert(files, file_name)
end
end
end
if #files == 0 then return nil end
-- Return a randomly selected filename from the file table
return #files > 0 and files[math.random(#files)] or nil
local file = files[math.random(#files)]
return absolute_path and (path:gsub("[/]*$", "") .. "/" .. file) or file
end
return filesystem

View File

@ -1,22 +1,7 @@
---------------------------------------------------------------------------
-- Functions for setting the wallpaper.
--
-- There are two levels of functionality provided by this module:
--
-- The low-level functionality consists of two functions.
-- @{set} an already-prepared wallpaper on all screens and @{prepare_context}
-- prepares things to draw a new wallpaper.
--
-- The low-level API can for example be used to set solid red as a wallpaper
-- (see @{gears.color} for details on the supported syntax):
--
-- gears.wallpaper.set("#ff0000")
--
-- Ontop of these low-level functions, the remaining functions implement more
-- useful functionality. For example, given a screen object `s`, an image can be
-- set as the wallpaper as follows:
--
-- gears.wallpaper.maximized("path/to/image.png", s)
-- This module is deprecated, please use `awful.wallpaper`.
--
-- @author Uli Schlachter
-- @copyright 2012 Uli Schlachter
@ -51,8 +36,10 @@ end
-- @param s The screen to set the wallpaper on or nil for all screens
-- @return[1] The available geometry (table with entries width and height)
-- @return[1] A cairo context that the wallpaper should be drawn to.
-- @staticfct gears.wallpaper.prepare_context
-- @deprecated gears.wallpaper.prepare_context
function wallpaper.prepare_context(s)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
s = get_screen(s)
local root_width, root_height = root.size()
@ -110,8 +97,10 @@ end
-- @param pattern The wallpaper that should be set. This can be a cairo surface,
-- a description for gears.color or a cairo pattern.
-- @see gears.color
-- @staticfct gears.wallpaper.set
-- @deprecated gears.wallpaper.set
function wallpaper.set(pattern)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
if cairo.Surface:is_type_of(pattern) then
pattern = cairo.Pattern.create_for_surface(pattern)
end
@ -121,7 +110,7 @@ function wallpaper.set(pattern)
if not cairo.Pattern:is_type_of(pattern) then
error("wallpaper.set() called with an invalid argument")
end
root.wallpaper(pattern._native)
root.wallpaper(pattern)
end
--- Set a centered wallpaper.
@ -132,8 +121,10 @@ end
-- gears.color. The default is black.
-- @param scale The scale factor for the wallpaper. Default is 1 (original size).
-- @see gears.color
-- @staticfct gears.wallpaper.centered
-- @deprecated gears.wallpaper.centered
function wallpaper.centered(surf, s, background, scale)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
local geom, cr = wallpaper.prepare_context(s)
local original_surf = surf
surf = surface.load_uncached(surf)
@ -172,8 +163,10 @@ end
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
-- all screens are set.
-- @param offset This can be set to a table with entries x and y.
-- @staticfct gears.wallpaper.tiled
-- @deprecated gears.wallpaper.tiled
function wallpaper.tiled(surf, s, offset)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
local _, cr = wallpaper.prepare_context(s)
if offset then
@ -202,8 +195,10 @@ end
-- @param ignore_aspect If this is true, the image's aspect ratio is ignored.
-- The default is to honor the aspect ratio.
-- @param offset This can be set to a table with entries x and y.
-- @staticfct gears.wallpaper.maximized
-- @deprecated gears.wallpaper.maximized
function wallpaper.maximized(surf, s, ignore_aspect, offset)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
local geom, cr = wallpaper.prepare_context(s)
local original_surf = surf
surf = surface.load_uncached(surf)
@ -243,8 +238,10 @@ end
-- @param background The background color that should be used. Gets handled via
-- gears.color. The default is black.
-- @see gears.color
-- @staticfct gears.wallpaper.fit
-- @deprecated gears.wallpaper.fit
function wallpaper.fit(surf, s, background)
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
local geom, cr = wallpaper.prepare_context(s)
local original_surf = surf
surf = surface.load_uncached(surf)

View File

@ -31,6 +31,7 @@ function module:draw(context, cr, width, height)
if not self._private.surface then
self._private.surface = cairo.ImageSurface(cairo.Format.ARGB32, w+hspace, h+vspace)
self._private.cr = cairo.Context(self._private.surface)
self._private.cr:set_source(cr:get_source())
self._private.pattern = cairo.Pattern.create_for_surface(self._private.surface)
self._private.pattern.extend = cairo.Extend.REPEAT
self._private.cr:translate(math.ceil(hspace), math.ceil(vspace))

View File

@ -48,28 +48,128 @@ end
local imagebox = { mt = {} }
local rsvg_handle_cache = setmetatable({}, { __mode = 'v' })
local rsvg_handle_cache = setmetatable({}, { __mode = 'k' })
---Load rsvg handle form image file
---@tparam string file Path to svg file.
---@return Rsvg handle
-- @tparam string file Path to svg file.
-- @return Rsvg handle
-- @treturn table A table where cached data can be stored.
local function load_rsvg_handle(file)
if not Rsvg then return end
local cache = rsvg_handle_cache[file]
local cache = (rsvg_handle_cache[file] or {})["handle"]
if cache then
return cache
return cache, rsvg_handle_cache[file]
end
local handle, err
if file:match("<[?]?xml") or file:match("<svg") then
handle, err = Rsvg.Handle.new_from_data(file)
else
handle, err = Rsvg.Handle.new_from_file(file)
end
local handle, err = Rsvg.Handle.new_from_file(file)
if not err then
rsvg_handle_cache[file] = handle
return handle
rsvg_handle_cache[file] = rsvg_handle_cache[file] or {}
rsvg_handle_cache[file]["handle"] = handle
return handle, rsvg_handle_cache[file]
end
end
---Apply cairo surface for given imagebox widget
local function set_surface(ib, surf)
local is_surf_valid = surf.width > 0 and surf.height > 0
if not is_surf_valid then return false end
ib._private.default = { width = surf.width, height = surf.height }
ib._private.handle = nil
ib._private.image = surf
return true
end
---Apply RsvgHandle for given imagebox widget
local function set_handle(ib, handle, cache)
local dim = handle:get_dimensions()
local is_handle_valid = dim.width > 0 and dim.height > 0
if not is_handle_valid then return false end
ib._private.default = { width = dim.width, height = dim.height }
ib._private.handle = handle
ib._private.cache = cache
ib._private.image = nil
return true
end
---Try to load some image object from file then apply it to imagebox.
---@tparam table ib Imagebox
---@tparam string file Image file name
---@tparam function image_loader Function to load image object from file
---@tparam function image_setter Function to set image object to imagebox
---@treturn boolean True if image was successfully applied
local function load_and_apply(ib, file, image_loader, image_setter)
local image_applied
local object, cache = image_loader(file)
if object then
image_applied = image_setter(ib, object, cache)
end
return image_applied
end
---Update the cached size depending on the stylesheet and dpi.
--
-- It's necessary because a single RSVG handle can be used by
-- many imageboxes. So DPI and Stylesheet need to be set each time.
local function update_dpi(self, ctx)
if not self._private.handle then return end
local dpi = self._private.auto_dpi and
ctx.dpi or
self._private.dpi or
nil
local need_dpi = dpi and
self._private.last_dpi ~= dpi
local need_style = self._private.handle.set_stylesheet and
self._private.stylesheet
local old_size = self._private.default and self._private.default.width
if dpi and dpi ~= self._private.cache.dpi then
if type(dpi) == "table" then
self._private.handle:set_dpi_x_y(dpi.x, dpi.y)
else
self._private.handle:set_dpi(dpi)
end
end
if need_style and self._private.cache.stylesheet ~= self._private.stylesheet then
self._private.handle:set_stylesheet(self._private.stylesheet)
end
-- Reload the size.
if need_dpi or (need_style and self._private.stylesheet ~= self._private.last_stylesheet) then
set_handle(self, self._private.handle, self._private.cache)
end
self._private.last_dpi = dpi
self._private.cache.dpi = dpi
self._private.last_stylesheet = self._private.stylesheet
self._private.cache.stylesheet = self._private.stylesheet
-- This can happen in the constructor when `dpi` is set after `image`.
if old_size and old_size ~= self._private.default.width then
self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed")
end
end
-- Draw an imagebox with the given cairo context in the given geometry.
function imagebox:draw(_, cr, width, height)
function imagebox:draw(ctx, cr, width, height)
if width == 0 or height == 0 or not self._private.default then return end
-- For valign = "top" and halign = "left"
@ -78,9 +178,11 @@ function imagebox:draw(_, cr, width, height)
y = 0,
}
update_dpi(self, ctx)
local w, h = self._private.default.width, self._private.default.height
if not self._private.resize_forbidden then
if self._private.resize then
-- That's for the "fit" policy.
local aspects = {
w = width / w,
@ -93,10 +195,14 @@ function imagebox:draw(_, cr, width, height)
}
for _, aspect in ipairs {"w", "h"} do
if policy[aspect] == "auto" then
aspects[aspect] = math.min(width / w, height / h)
if self._private.upscale == false and (w < width and h < height) then
aspects[aspect] = 1
elseif self._private.downscale == false and (w >= width and h >= height) then
aspects[aspect] = 1
elseif policy[aspect] == "none" then
aspects[aspect] = 1
elseif policy[aspect] == "auto" then
aspects[aspect] = math.min(width / w, height / h)
end
end
@ -165,11 +271,22 @@ function imagebox:draw(_, cr, width, height)
end
-- Fit the imagebox into the given geometry
function imagebox:fit(_, width, height)
function imagebox:fit(ctx, width, height)
if not self._private.default then return 0, 0 end
update_dpi(self, ctx)
local w, h = self._private.default.width, self._private.default.height
if not self._private.resize_forbidden or w > width or h > height then
if w <= width and h <= height and self._private.upscale == false then
return w, h
end
if (w < width or h < height) and self._private.downscale == false then
return w, h
end
if self._private.resize or w > width or h > height then
local aspect = math.min(width / w, height / h)
return w * aspect, h * aspect
end
@ -177,44 +294,6 @@ function imagebox:fit(_, width, height)
return w, h
end
---Apply cairo surface for given imagebox widget
local function set_surface(ib, surf)
local is_surd_valid = surf.width > 0 and surf.height > 0
if not is_surd_valid then return end
ib._private.default = { width = surf.width, height = surf.height }
ib._private.handle = nil
ib._private.image = surf
return true
end
---Apply RsvgHandle for given imagebox widget
local function set_handle(ib, handle)
local dim = handle:get_dimensions()
local is_handle_valid = dim.width > 0 and dim.height > 0
if not is_handle_valid then return end
ib._private.default = { width = dim.width, height = dim.height }
ib._private.handle = handle
ib._private.image = nil
return true
end
---Try to load some image object from file then apply it to imagebox.
---@tparam table ib Imagebox
---@tparam string file Image file name
---@tparam function image_loader Function to load image object from file
---@tparam function image_setter Function to set image object to imagebox
---@treturn boolean True if image was successfully applied
local function load_and_apply(ib, file, image_loader, image_setter)
local image_applied
local object = image_loader(file)
if object then
image_applied = image_setter(ib, object)
end
return image_applied
end
--- The image rendered by the `imagebox`.
--
-- It can can be any of the following:
@ -242,7 +321,10 @@ end
function imagebox:set_image(image)
local setup_succeed
if type(image) == "userdata" then
-- Keep the original to prevent the cache from being GCed.
self._private.original_image = image
if type(image) == "userdata" and not (Rsvg and Rsvg.Handle:is_type_of(image)) then
-- This function is not documented to handle userdata objects, but
-- historically it did, and it did by just assuming they refer to a
-- cairo surface.
@ -259,7 +341,8 @@ function imagebox:set_image(image)
end
elseif Rsvg and Rsvg.Handle:is_type_of(image) then
-- try to apply given rsvg handle
setup_succeed = set_handle(self, image)
rsvg_handle_cache[image] = rsvg_handle_cache[image] or {}
setup_succeed = set_handle(self, image, rsvg_handle_cache[image])
elseif cairo.Surface:is_type_of(image) then
-- try to apply given cairo surface
setup_succeed = set_surface(self, image)
@ -311,23 +394,126 @@ function imagebox:set_clip_shape(clip_shape, ...)
end
--- Should the image be resized to fit into the available space?
--
-- Note that `upscale` and `downscale` can affect the value of `resize`.
-- If conflicting values are passed to the constructor, then the result
-- is undefined.
--
-- @DOC_wibox_widget_imagebox_resize_EXAMPLE@
-- @property resize
-- @propemits true false
-- @tparam boolean resize
--- Should the image be resized to fit into the available space?
-- @tparam boolean allowed If `false`, the image will be clipped, else it will
-- be resized to fit into the available space.
-- @method set_resize
-- @hidden
--- Allow the image to be upscaled (made bigger).
--
-- Note that `upscale` and `downscale` can affect the value of `resize`.
-- If conflicting values are passed to the constructor, then the result
-- is undefined.
--
-- @DOC_wibox_widget_imagebox_upscale_EXAMPLE@
-- @property upscale
-- @tparam boolean upscale
-- @see downscale
-- @see resize
--- Allow the image to be downscaled (made smaller).
--
-- Note that `upscale` and `downscale` can affect the value of `resize`.
-- If conflicting values are passed to the constructor, then the result
-- is undefined.
--
-- @DOC_wibox_widget_imagebox_downscale_EXAMPLE@
-- @property downscale
-- @tparam boolean downscale
-- @see upscale
-- @see resize
--- Set the SVG CSS stylesheet.
--
-- If the image is an SVG (vector graphics), this property allows to set
-- a CSS stylesheet. It can be used to set colors and much more.
--
-- Note that this property is a string, not a path. If the stylesheet is
-- stored on disk, read the content first.
--
--@DOC_wibox_widget_imagebox_stylesheet_EXAMPLE@
--
-- @property stylesheet
-- @tparam string stylesheet
-- @propemits true false
--- Set the SVG DPI (dot per inch).
--
-- Force a specific DPI when rendering the `.svg`. For other file formats,
-- this does nothing.
--
-- It can either be a number of a table containing the `x` and `y` keys.
--
-- Please note that DPI and `resize` can "fight" each other and end up
-- making the image smaller instead of bigger.
--
--@DOC_wibox_widget_imagebox_dpi_EXAMPLE@
--
-- @property dpi
-- @tparam number|table dpi
-- @propemits true false
-- @see auto_dpi
--- Use the object DPI when rendering the SVG.
--
-- By default, the SVG are interpreted as-is. When this property is set,
-- the screen DPI will be passed to the SVG renderer. Depending on which
-- tool was used to create the `.svg`, this may do nothing at all. However,
-- for example, if the `.svg` uses `<text>` elements and doesn't have an
-- hardcoded stylesheet, the result will differ.
--
-- @property auto_dpi
-- @tparam[opt=false] boolean auto_dpi
-- @propemits true false
-- @see dpi
for _, prop in ipairs {"stylesheet", "dpi", "auto_dpi"} do
imagebox["set_" .. prop] = function(self, value)
-- It will be set in :fit and :draw. The handle is shared
-- by multiple imagebox, so it cannot be set just once.
self._private[prop] = value
self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed")
self:emit_signal("property::" .. prop)
end
end
function imagebox:set_resize(allowed)
self._private.resize_forbidden = not allowed
self._private.resize = allowed
if allowed then
self._private.downscale = true
self._private.upscale = true
self:emit_signal("property::downscale", allowed)
self:emit_signal("property::upscale", allowed)
end
self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed")
self:emit_signal("property::resize", allowed)
end
for _, prop in ipairs {"downscale", "upscale" } do
imagebox["set_" .. prop] = function(self, allowed)
self._private[prop] = allowed
if self._private.resize ~= (self._private.upscale or self._private.downscale) then
self._private.resize = self._private.upscale or self._private.downscale
self:emit_signal("property::resize", self._private.resize)
end
self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed")
self:emit_signal("property::"..prop, allowed)
end
end
--- Set the horizontal fit policy.
--
-- Valid values are:
@ -506,12 +692,14 @@ local function new(image, resize_allowed, clip_shape, ...)
local ret = base.make_widget(nil, nil, {enable_properties = true})
gtable.crush(ret, imagebox, true)
ret._private.resize = true
if image then
ret:set_image(image)
end
if resize_allowed ~= nil then
ret:set_resize(resize_allowed)
ret.resize = resize_allowed
end
ret._private.clip_shape = clip_shape

7
root.c
View File

@ -481,6 +481,11 @@ luaA_root_wallpaper(lua_State *L)
{
if(lua_gettop(L) == 1)
{
/* Avoid `error()s` down the line. If this happens during
* initialization, AwesomeWM can be stuck in an infinite loop */
if(lua_isnil(L, -1))
return 0;
cairo_pattern_t *pattern = (cairo_pattern_t *)lua_touserdata(L, -1);
lua_pushboolean(L, root_set_wallpaper(pattern));
/* Don't return the wallpaper, it's too easy to get memleaks */
@ -602,7 +607,7 @@ const struct luaL_Reg awesome_root_methods[] =
{ "cursor", luaA_root_cursor },
{ "fake_input", luaA_root_fake_input },
{ "drawins", luaA_root_drawins },
{ "wallpaper", luaA_root_wallpaper },
{ "_wallpaper", luaA_root_wallpaper },
{ "size", luaA_root_size },
{ "size_mm", luaA_root_size_mm },
{ "tags", luaA_root_tags },

View File

@ -115,22 +115,40 @@ describe("gears.filesystem", function()
assert.is_true(test_b == "a.png"
or test_b == "b.jpg")
-- Any file found (selected extensions)
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"})
assert.is_true(test_c == "a.png"
or test_c == "b.jpg")
-- Test absolute paths.
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"}, true)
assert.is_true(test_d == root .. "filesystem_tests/a.png"
or test_d == root .. "filesystem_tests/b.jpg")
-- Make sure the paths are generated correctly.
assert.is_nil(test_d:match("//"))
-- "." in filename test cases with extensions
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"})
assert.is_true(test_c == "filename.ext"
or test_c == ".filename.ext"
or test_c == "file.name.ext"
or test_c == ".file.name.ext")
local test_e = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"})
assert.is_true(test_e == "filename.ext"
or test_e == ".filename.ext"
or test_e == "file.name.ext"
or test_e == ".file.name.ext")
-- "." in filename test cases with no extensions
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""})
assert.is_true(test_d == "filename"
or test_d == "filename."
or test_d == "filename.ext."
or test_d == ".filename"
or test_d == ".filename."
or test_d == "file.name.ext."
or test_d == ".file.name.ext.")
local test_f = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""})
assert.is_true(test_f == "filename"
or test_f == "filename."
or test_f == "filename.ext."
or test_f == ".filename"
or test_f == ".filename."
or test_f == "file.name.ext."
or test_f == ".file.name.ext.")
-- Test invalid directories.
local test_g = gfs.get_random_file_from_dir(root .. "filesystem_tests/fake_dir")
assert.is_nil(test_g)
end
end)
end)

View File

@ -85,7 +85,9 @@ function(escape_string variable content escaped_content line_prefix)
if(variable MATCHES "--DOC_HIDE_ALL")
return()
endif()
string(REGEX REPLACE "\n" ";" var_lines "${variable}")
string(REGEX REPLACE ";" "&#59" var_lines "${variable}")
string(REGEX REPLACE "\n" ";" var_lines "${var_lines}")
set(tmp_output ${content})
set(section OFF)
@ -101,7 +103,7 @@ function(escape_string variable content escaped_content line_prefix)
# Pick lines that are not specified to be hidden
if((NOT LINE MATCHES "^.*--DOC_[A-Z]+") AND (NOT section))
set(tmp_output ${tmp_output}\n${DOC_LINE_PREFIX}${line_prefix}${LINE})
set(tmp_output "${tmp_output}\n${DOC_LINE_PREFIX}${line_prefix}${LINE}")
endif()
# If we found a start marker previously, look for an end marker.
@ -256,6 +258,12 @@ function(run_test test_path namespace escaped_content)
"\n${expected_output}"
"${TEST_DOC_CONTENT}" TEST_DOC_CONTENT " "
)
# Add a <br/> to prevent markdown from merging the usage and output
# into a single block.
if(tmp_content MATCHES "--DOC_NO_USAGE")
set(TEST_DOC_CONTENT "${TEST_DOC_CONTENT}\n${DOC_LINE_PREFIX} **Usage example:**")
endif()
else()
escape_string(
"\n${expected_output}"
@ -347,7 +355,7 @@ foreach(file ${test_files})
# variable during the pre-processing.
# While at it, replace \" created by CMake by ',
# &quot; wont work in <code>.
string(REPLACE "\"" "'" ${TEST_NAME} ${ESCAPED_CODE_EXAMPLE})
string(REPLACE "\"" "&#34" ${TEST_NAME} ${ESCAPED_CODE_EXAMPLE})
endif()
endforeach()

View File

@ -8,6 +8,7 @@ local gears = require("gears")
local naughty = require("naughty")
local wibox = require("wibox")
local beautiful = require("beautiful") --DOC_HIDE
local assets = require("beautiful.theme_assets")
local look = require("_default_look")
screen[1]._resize {width = 640, height = 480}
@ -17,6 +18,78 @@ screen[1]._resize {width = 640, height = 480}
local c = client.gen_fake {hide_first=true}
-- Don't use `awful.wallpaper` to avoid rasterizing the background.
local wallpaper = wibox {
below = true,
shape = gears.shape.octogon,
visible = true,
bg = "#00000000",
}
awful.placement.maximize(wallpaper)
wallpaper.widget = wibox.widget {
fit = function(_, _, width, height)
return width, height
end,
draw = function(_, _, cr, width, height)
cr:translate(width - 80, 60)
assets.gen_awesome_name(
cr, height - 40, "#ffffff", beautiful.bg_normal, beautiful.bg_normal
)
end,
widget = wibox.widget.base.make_widget()
}
local p = awful.popup {
widget = wibox.widget {
{ text = "Item", widget = wibox.widget.textbox },
{
{
text = "Selected",
widget = wibox.widget.textbox
},
bg = beautiful.bg_highlight,
widget = wibox.container.background
},
{ text = "Item", widget = wibox.widget.textbox },
forced_width = 100,
widget = wibox.layout.fixed.vertical
},
border_color = beautiful.border_color,
border_width = 1,
x = 50,
y = 200,
}
p:_apply_size_now()
require("gears.timer").run_delayed_calls_now()
p._drawable._do_redraw()
require("gears.timer").delayed_call(function()
-- Get the 4th textbox
local list = p:find_widgets(30, 40)
mouse.coords {x= 120, y=225}
mouse.push_history()
local textboxinstance = list[#list]
local p2 = awful.popup {
widget = wibox.widget {
text = "Submenu",
forced_height = 20,
forced_width = 70,
widget = wibox.widget.textbox
},
border_color = beautiful.border_color,
preferred_positions = "right",
border_width = 1,
}
p2:move_next_to(textboxinstance, "right")
end)
c:geometry {
x = 50,
y = 350,
@ -97,6 +170,7 @@ wibox {
width = 50,
height = 50,
shape = gears.shape.octogon,
visible = true,
color = "#0000ff",
x = 570,
y = 410,
@ -188,13 +262,17 @@ create_info("awful.tooltip", 30, 130, 100, 30)
create_info("awful.popup", 450, 240, 100, 30)
create_info("naughty.layout.box", 255, 110, 130, 30)
create_info("Standard `wibox`", 420, 420, 130, 30)
create_info("awful.wallpaper", 420, 330, 110, 30)
create_info("awful.menu", 60, 270, 80, 30)
create_line(150, 10, 150, 55)
create_line(75, 100, 75, 135)
create_line(545, 432, 575, 432)
create_line(500, 165, 500, 245)
create_line(390, 250, 450, 250)
create_line(380, 250, 450, 250)
create_line(190, 365, 255, 365)
create_line(320, 60, 320, 110)
create_line(525, 345, 570, 345)
create_line(100, 240, 100, 270)
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -58,11 +58,23 @@ if not rawget(screen, "no_outline") then
end
end
-- Draw the wallpaper (if any).
if root._wallpaper_pattern then
cr:set_source_rgb(1,0,0)
cr:set_line_width(2)
cr:rectangle(0, 0, root.size())
cr:stroke()
cr:set_source(root._wallpaper_pattern)
cr:rectangle(0, 0, root.size())
cr:fill()
cr:paint()
end
cr:set_line_width(beautiful.border_width/2)
cr:set_source(color(beautiful.border_color))
local rect = {x1 = 0 ,y1 = 0 , x2 = 0 , y2 = 0}
-- Get the region with wiboxes

View File

@ -0,0 +1,48 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
awful.wallpaper {
screen = screen[1],
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
}
}
require("gears.timer").run_delayed_calls_now()

View File

@ -0,0 +1,50 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
local wall = awful.wallpaper {
screen = screen[1],
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
}
}
wall:add_screen(screen[2])
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,51 @@
--DOC_GEN_IMAGE
--DOC_HIDE_ALL
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
local wall = awful.wallpaper {
screen = screen[1],
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
}
}
wall:add_screen(screen[3])
require("gears.timer").run_delayed_calls_now()

View File

@ -0,0 +1,30 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { --DOC_HIDE
wallpaper = require("awful.wallpaper"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
} --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
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
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,57 @@
--DOC_GEN_IMAGE
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
--DOC_HIDE_END
for s in screen do
local dpi = s.index * 100
--DOC_NEWLINE
awful.wallpaper {
screen = s,
dpi = dpi,
widget = wibox.widget {
--DOC_HIDE_START
{
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()
},
{
--DOC_HIDE_END
text = "DPI: " .. dpi,
valign = "center",
align = "center",
widget = wibox.widget.textbox,
}, --DOC_HIDE
widget = wibox.layout.stack --DOC_HIDE
} --DOC_HIDE
}
end
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,21 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
awful.wallpaper {
screen = s,
bg = {
type = "linear" ,
from = { 0, 0 },
to = { 0, 240 },
stops = {
{ 0, "#0000ff" },
{ 1, "#ff0000" }
}
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,22 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
awful.wallpaper {
screen = s,
bg = {
type = "radial",
from = { 160, 98, 20 },
to = { 160, 98, 120 },
stops = {
{ 0 , "#ff0000" },
{ 0.5, "#00ff00" },
{ 1 , "#0000ff" },
}
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,24 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
local s = screen[1] --DOC_HIDE
awful.wallpaper {
screen = s,
widget = {
{
image = beautiful.wallpaper,
resize = true,
widget = wibox.widget.imagebox,
},
valign = "center",
halign = "center",
tiled = false,
widget = wibox.container.tile,
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,26 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
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,
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,20 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
awful.wallpaper {
screen = s,
widget = {
horizontal_fit_policy = "fit",
vertical_fit_policy = "fit",
image = beautiful.wallpaper,
widget = wibox.widget.imagebox,
},
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,58 @@
--DOC_GEN_IMAGE --DOC_GEN_OUTPUT
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 320, height = 196}
require("_default_look")
--DOC_HIDE_END
-- Add some padding to the first screen.
screen[1].padding = {
left = 30,
right = 10,
}
--DOC_NEWLINE
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()
}
}
--DOC_HIDE_START
require("gears.timer").run_delayed_calls_now()
--DOC_HIDE_END
--DOC_NEWLINE
-- 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

View File

@ -0,0 +1,3 @@
Uncovered area: 0 0 30 196
Uncovered area: 0 0 320 14
Uncovered area: 310 0 10 196

View File

@ -0,0 +1,86 @@
--DOC_GEN_IMAGE --DOC_GEN_OUTPUT --DOC_NO_USAGE
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 97, width = 96, height = 160}
screen._add_screen {x = 97, y = 129, width = 160, height = 96}
screen._add_screen {x = 258, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 0,width = 160, height = 96}
screen._add_screen {x = 402, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 258,width = 160, height = 96}
require("_default_look")
local walls = {}
--DOC_HIDE_END
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
--DOC_HIDE_START
for i=0, 1 do
walls[i+1] = awful.wallpaper {
screens = {
screen[i*3 + 1],
screen[i*3 + 2],
screen[i*3 + 3],
},
bg = "#222222",
panning_area = custom_panning_area,
uncovered_areas_color = "#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
}
}
end
require("gears.timer").run_delayed_calls_now()
--DOC_HIDE_END
--DOC_NEWLINE
-- 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

View File

@ -0,0 +1,60 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL --DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 97, width = 96, height = 160}
screen._add_screen {x = 97, y = 129, width = 160, height = 96}
screen._add_screen {x = 258, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 0,width = 160, height = 96}
screen._add_screen {x = 402, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 258,width = 160, height = 96}
require("_default_look")
for i=0, 1 do
awful.wallpaper {
screens = {
screen[i*3 + 1],
screen[i*3 + 2],
screen[i*3 + 3],
},
bg = "#222222",
panning_area = "inner",
uncovered_areas_color = "#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
}
}
end
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,60 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL --DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 97, width = 96, height = 160}
screen._add_screen {x = 97, y = 129, width = 160, height = 96}
screen._add_screen {x = 258, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 0,width = 160, height = 96}
screen._add_screen {x = 402, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 258,width = 160, height = 96}
require("_default_look")
for i=0, 1 do
awful.wallpaper {
screens = {
screen[i*3 + 1],
screen[i*3 + 2],
screen[i*3 + 3],
},
bg = "#222222",
panning_area = "inner_horizontal",
uncovered_areas_color = "#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
}
}
end
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,60 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL --DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 97, width = 96, height = 160}
screen._add_screen {x = 97, y = 129, width = 160, height = 96}
screen._add_screen {x = 258, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 0,width = 160, height = 96}
screen._add_screen {x = 402, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 258,width = 160, height = 96}
require("_default_look")
for i=0, 1 do
awful.wallpaper {
screens = {
screen[i*3 + 1],
screen[i*3 + 2],
screen[i*3 + 3],
},
bg = "#222222",
panning_area = "inner_vertical",
uncovered_areas_color = "#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
}
}
end
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,58 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL --DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 97, width = 96, height = 160}
screen._add_screen {x = 97, y = 129, width = 160, height = 96}
screen._add_screen {x = 258, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 0,width = 160, height = 96}
screen._add_screen {x = 402, y = 97,width = 96, height = 160}
screen._add_screen {x = 370, y = 258,width = 160, height = 96}
require("_default_look")
for i=0, 1 do
awful.wallpaper {
screens = {
screen[i*3 + 1],
screen[i*3 + 2],
screen[i*3 + 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
}
}
end
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,53 @@
--DOC_GEN_IMAGE --DOC_NO_USAGE
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
-- There is 3 screens. This will add the wallpaper to the last 2.
local wall = awful.wallpaper {
screens = screen,
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
}
}
require("gears.timer").run_delayed_calls_now()
--DOC_HIDE_END
wall:remove_screen(screen[1])
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,58 @@
--DOC_GEN_IMAGE --DOC_NO_USAGE
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
-- There is 3 screens. This will add the wallpaper to the last 2.
awful.wallpaper {
screens = screen,
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
}
}
require("gears.timer").run_delayed_calls_now()
--DOC_HIDE_END
awful.wallpaper {
screen = screen[1],
bg = "#00ffff",
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,54 @@
--DOC_GEN_IMAGE
--DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 160, height = 96}
screen._add_screen {x = 161, y = 0, width = 160, height = 96}
screen._add_screen {x = 322, y = 0, width = 160, height = 96}
require("_default_look")
--DOC_HIDE_END
-- 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
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,45 @@
--DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local gears = {timer = require("gears.timer"), filesystem = require("gears.filesystem")}--DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
-- 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)
--DOC_NEWLINE
-- **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,
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,36 @@
--DOC_GEN_IMAGE --DOC_NO_USAGE --DOC_HIDE_START
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
screen[1]._resize {x = 0, y = 0, width = 320, height = 196}
--DOC_HIDE_END
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>'
--DOC_NEWLINE
local stylesheet = "" ..
"rect { fill: #ffff00; } "..
".my_class { fill: #00ff00; } "..
"#my_id { fill: #0000ff; }"
--DOC_NEWLINE
awful.wallpaper {
screen = screen[1], --DOC_HIDE
widget = wibox.widget {
forced_height = 60, --DOC_HIDE
forced_width = 190, --DOC_HIDE
stylesheet = stylesheet,
image = image,
widget = wibox.widget.imagebox
}
}
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,27 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
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,
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,30 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local gears = { shape = require("gears.shape") } --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
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,
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,82 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local gears = {color = require("gears.color") } --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
local s = screen[1] --DOC_HIDE
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)
--DOC_NEWLINE
-- 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()
--DOC_NEWLINE
-- 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()
--DOC_NEWLINE
-- Draw the grid
local lines = width/8
cr:reset_clip()
cr:set_line_width(0.5)
cr:set_source(gears.color("#8922a3"))
--DOC_NEWLINE
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
--DOC_NEWLINE
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,
}
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,48 @@
--DOC_NO_USAGE --DOC_GEN_IMAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
math.randomseed(1) --DOC_HIDE
screen[1]._resize {x = 0, y = 0, width = 320, height = 196} --DOC_HIDE
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
--DOC_NEWLINE
awful.wallpaper {
screen = screen[1], --DOC_HIDE
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
},
}
require("gears.timer").run_delayed_calls_now() --DOC_HIDE

View File

@ -0,0 +1,56 @@
--DOC_GEN_IMAGE --DOC_HIDE_ALL
local awful = { wallpaper = require("awful.wallpaper") }
local wibox = require("wibox")
local gears = {color = require("gears.color") }
screen._track_workarea = true
screen[1]._resize {x = 0, y = 0, width = 320, height = 196}
screen._add_screen {x = 330, y = 0, width = 320, height = 196}
require("_default_look")
screen.connect_signal("request::wallpaper", function(s)
awful.wallpaper {
screen = s,
honor_workarea = s.index == 2,
bg = "#222222",
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()
},
{
text = "honor_workarea = " .. (s.index == 2 and "true" or "false"),
valign = "center",
align = "center",
widget = wibox.widget.textbox,
},
widget = wibox.layout.stack
}
}
end)
require("gears.timer").run_delayed_calls_now()
for s in screen do
s:emit_signal("request::wallpaper", s)
end
require("gears.timer").run_delayed_calls_now()

View File

@ -3,87 +3,98 @@ local wibox = require("wibox")
local beautiful = require("beautiful")
require("_date")
-- Create the same number of tags as the default config
awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.layouts[1])
local mykeyboardlayout = awful.widget.keyboardlayout()
local mytextclock = wibox.widget.textclock()
local mylayoutbox = awful.widget.layoutbox(screen[1])
local mytaglist = awful.widget.taglist(screen[1], awful.widget.taglist.filter.all, {})
local mytasklist = awful.widget.tasklist(screen[1], awful.widget.tasklist.filter.currenttags, {})
local mypromptbox = wibox.widget.textbox("")
local ret = nil
local wb = awful.wibar { position = "top" }
wb:setup {
layout = wibox.layout.align.horizontal,
{
layout = wibox.layout.fixed.horizontal,
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
mytaglist,
mypromptbox,
},
mytasklist,
{
layout = wibox.layout.fixed.horizontal,
mykeyboardlayout,
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
mytextclock,
mylayoutbox,
},
}
for i = 1, screen.count() do
local s = screen[i]
-- Create the same number of tags as the default config
awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])
local mykeyboardlayout = awful.widget.keyboardlayout()
local mytextclock = wibox.widget.textclock()
local mylayoutbox = awful.widget.layoutbox(s)
local mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, {})
local mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, {})
local mypromptbox = wibox.widget.textbox("")
client.connect_signal("request::titlebars", function(c)
local top_titlebar = awful.titlebar(c, {
height = 20,
bg_normal = beautiful.bg_normal,
})
top_titlebar : setup {
{ -- Left
awful.titlebar.widget.iconwidget(c),
layout = wibox.layout.fixed.horizontal
},
{ -- Middle
{ -- Title
align = "center",
widget = awful.titlebar.widget.titlewidget(c)
},
layout = wibox.layout.flex.horizontal
},
{ -- Right
awful.titlebar.widget.floatingbutton (c),
awful.titlebar.widget.maximizedbutton(c),
awful.titlebar.widget.stickybutton (c),
awful.titlebar.widget.ontopbutton (c),
awful.titlebar.widget.closebutton (c),
layout = wibox.layout.fixed.horizontal()
},
layout = wibox.layout.align.horizontal
local wb = awful.wibar {
position = "top",
screen = s
}
end)
wb:setup {
layout = wibox.layout.align.horizontal,
{
layout = wibox.layout.fixed.horizontal,
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
mytaglist,
mypromptbox,
},
mytasklist,
{
layout = wibox.layout.fixed.horizontal,
mykeyboardlayout,
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
{
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox,
},
mytextclock,
mylayoutbox,
},
}
client.connect_signal("request::titlebars", function(c)
local top_titlebar = awful.titlebar(c, {
height = 20,
bg_normal = beautiful.bg_normal,
})
top_titlebar : setup {
{ -- Left
awful.titlebar.widget.iconwidget(c),
layout = wibox.layout.fixed.horizontal
},
{ -- Middle
{ -- Title
align = "center",
widget = awful.titlebar.widget.titlewidget(c)
},
layout = wibox.layout.flex.horizontal
},
{ -- Right
awful.titlebar.widget.floatingbutton (c),
awful.titlebar.widget.maximizedbutton(c),
awful.titlebar.widget.stickybutton (c),
awful.titlebar.widget.ontopbutton (c),
awful.titlebar.widget.closebutton (c),
layout = wibox.layout.fixed.horizontal()
},
layout = wibox.layout.align.horizontal
}
end)
ret = ret or {
mykeyboardlayout = mykeyboardlayout,
mytextclock = mytextclock ,
mylayoutbox = mylayoutbox ,
mytaglist = mytaglist ,
mytasklist = mytasklist ,
mywibox = wb ,
mypromptbox = mypromptbox ,
}
end
require("gears.timer").run_delayed_calls_now()
return {
mykeyboardlayout = mykeyboardlayout,
mytextclock = mytextclock ,
mylayoutbox = mylayoutbox ,
mytaglist = mytaglist ,
mytasklist = mytasklist ,
mywibox = wb ,
mypromptbox = mypromptbox ,
}
return ret

View File

@ -118,6 +118,10 @@ awesome._modifiers = {
},
}
function awesome._get_key_name(key)
return key
end
awesome._active_modifiers = {}
return awesome

View File

@ -1,6 +1,8 @@
local root = {_tags={}}
local gtable = require("gears.table")
local cairo = require( "lgi" ).cairo
function root:tags()
return root._tags
@ -169,6 +171,24 @@ function root._write_string(string, c)
end
end
function root._wallpaper(pattern)
if not pattern then return root._wallpaper_surface end
-- Make a copy because `:finish()` is called by `root.wallpaper` to avoid
-- a memory leak in the "real" backend.
local target = cairo.ImageSurface(cairo.Format.RGB32, root.size())
local cr = cairo.Context(target)
cr:set_source(pattern)
cr:rectangle(0, 0, root.size())
cr:fill()
root._wallpaper_pattern = cairo.Pattern.create_for_surface(target)
root._wallpaper_surface = target
return target
end
function root.set_newindex_miss_handler(h)
rawset(root, "_ni_handler", h)

View File

@ -0,0 +1,13 @@
--DOC_NO_USAGE
local awful = { wallpaper = require("awful.wallpaper") } --DOC_HIDE
local global_wallpaper = awful.wallpaper {
-- [...] your content
}
--DOC_NEWLINE
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)

View File

@ -0,0 +1,54 @@
--DOC_HIDE_ALL
--DOC_GEN_IMAGE
local parent = ...
local wibox = require( "wibox" )
local beautiful = require( "beautiful" )
local function cell_centered_widget(widget)
return wibox.widget {
widget,
valign = 'center',
halign = 'center',
content_fill_vertical = false,
content_fill_horizontal = false,
widget = wibox.container.place
}
end
local function build_ib(size, resize)
return cell_centered_widget(wibox.widget {
{
downscale = resize,
upscale = true,
forced_height = size,
forced_width = size,
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox
},
forced_width = size + 2,
forced_height = size + 2,
color = beautiful.border_color,
margins = 1,
widget = wibox.container.margin
})
end
local l = wibox.widget {
homogeneous = false,
spacing = 5,
layout = wibox.layout.grid,
}
parent:add(l)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('downscale = true')), 1, 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('downscale = false')), 2, 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('imagebox size')), 3, 1)
for i,size in ipairs({16, 32, 64}) do
l:add_widget_at(build_ib(size, true), 1, i + 1)
l:add_widget_at(build_ib(size, false), 2, i + 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox(size..'x'..size)), 3, i + 1)
end
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,48 @@
--DOC_GEN_IMAGE --DOC_HIDE
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local l = wibox.layout { --DOC_HIDE
forced_width = 360, --DOC_HIDE
spacing = 5, --DOC_HIDE
layout = wibox.layout.flex.vertical --DOC_HIDE
} --DOC_HIDE
local image = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'..
'<svg width="2in" height="1in">'..
'<rect height="0.1in" width="0.1in" style="fill:red;" />'..
'<text x="10" y="32" width="150" style="font-size: 0.1in;">Hello world!</text>'..
'</svg>'
--DOC_NEWLINE
for _, dpi in ipairs {100, 200, 300} do
local row = wibox.layout { --DOC_HIDE
spacing = 5, --DOC_HIDE
layout = wibox.layout.fixed.horizontal --DOC_HIDE
} --DOC_HIDE
row:add(wibox.widget { --DOC_HIDE
markup = "<b>dpi = "..dpi.."</b>", --DOC_HIDE
forced_width = 80, --DOC_HIDE
widget = wibox.widget.textbox --DOC_HIDE
}) --DOC_HIDE
local w = wibox.widget {
image = image,
dpi = dpi,
resize = false,
forced_height = 70,
forced_width = 150,
widget = wibox.widget.imagebox
}
row:add(w) --DOC_HIDE
l:add(row) --DOC_HIDE
end
parent:add(l) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,31 @@
--DOC_GEN_IMAGE --DOC_HIDE
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
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>'
--DOC_NEWLINE
local stylesheet = "" ..
"rect { fill: #ffff00; } "..
".my_class { fill: #00ff00; } "..
"#my_id { fill: #0000ff; }"
--DOC_NEWLINE
local w = wibox.widget {
forced_height = 60, --DOC_HIDE
forced_width = 190, --DOC_HIDE
stylesheet = stylesheet,
image = image,
widget = wibox.widget.imagebox
}
parent:add(w) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,54 @@
--DOC_HIDE_ALL
--DOC_GEN_IMAGE
local parent = ...
local wibox = require( "wibox" )
local beautiful = require( "beautiful" )
local function cell_centered_widget(widget)
return wibox.widget {
widget,
valign = 'center',
halign = 'center',
content_fill_vertical = false,
content_fill_horizontal = false,
widget = wibox.container.place
}
end
local function build_ib(size, resize)
return cell_centered_widget(wibox.widget {
{
upscale = resize,
downscale = true,
forced_height = size,
forced_width = size,
image = beautiful.awesome_icon,
widget = wibox.widget.imagebox
},
forced_width = size + 2,
forced_height = size + 2,
color = beautiful.border_color,
margins = 1,
widget = wibox.container.margin
})
end
local l = wibox.widget {
homogeneous = false,
spacing = 5,
layout = wibox.layout.grid,
}
parent:add(l)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('upscale = true')), 1, 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('upscale = false')), 2, 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox('imagebox size')), 3, 1)
for i,size in ipairs({16, 32, 64}) do
l:add_widget_at(build_ib(size, true), 1, i + 1)
l:add_widget_at(build_ib(size, false), 2, i + 1)
l:add_widget_at(cell_centered_widget(wibox.widget.textbox(size..'x'..size)), 3, i + 1)
end
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -68,7 +68,10 @@ local function add_client(args)
local c = data.c
if not c then
c = client.get()[1]
assert(c.name == name)
assert(c.name == name,
"Expected "..name.." got "..c.name.." there is "
..#client.get().." clients"
)
data.c = c
end
local test = args.test or default_test

View File

@ -5,6 +5,13 @@ local wp = require("gears.wallpaper")
local color = require("gears.color")
local cairo = require( "lgi" ).cairo
local surface = require("gears.surface")
local awall = require("awful.wallpaper")
local beautiful = require("beautiful")
local wibox = require("wibox")
local gdebug = require("gears.debug")
-- This test suite is for a deprecated module.
gdebug.deprecate = function() end
local steps = {}
@ -54,85 +61,236 @@ table.insert(steps, function()
end)
table.insert(steps, function()
wp.fit(img, screen[1], "#00ff00")
wp.fit(img, screen[1], "#00ff00")
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.centered(img, nil, nil)
wp.centered(img, screen[1], nil)
wp.centered(img, nil, nil)
wp.centered(img, screen[1], nil)
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.centered(img, screen[1], "#00ff00")
wp.centered(img, screen[1], "#00ff00")
return true
return true
end)
table.insert(steps, function()
wp.maximized(img, nil, nil, nil)
wp.maximized(img, nil, nil, nil)
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.maximized(img, screen[1], nil, nil)
wp.maximized(img, screen[1], nil, nil)
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.maximized(img, screen[1], false, nil)
wp.maximized(img, screen[1], true, nil)
wp.maximized(img, screen[1], false, nil)
wp.maximized(img, screen[1], true, nil)
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.maximized(img, screen[1], false, {x=10, y= 10})
wp.maximized(img, screen[1], true, {x=10, y= 10})
wp.maximized(img, screen[1], false, {x=10, y= 10})
wp.maximized(img, screen[1], true, {x=10, y= 10})
return true
return true
end)
table.insert(steps, function()
wp.tiled(img, nil, nil)
wp.tiled(img, screen[1], nil)
wp.tiled(img, nil, nil)
wp.tiled(img, screen[1], nil)
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
-- There is a delayed call for the last call, let it be processed before
-- adding more
return true
end)
table.insert(steps, function()
wp.tiled(img, screen[1], {x=10, y= 10})
wp.tiled(img, screen[1], {x=10, y= 10})
return true
return true
end)
table.insert(steps, function()
for _, c in ipairs(colors) do
wp.set(c)
end
for _, c in ipairs(colors) do
wp.set(c)
end
return true
return true
end)
-- Make sure passing `nil` doesn't crash Awesome.
table.insert(steps, function()
root._wallpaper(nil)
root.wallpaper(nil)
return true
end)
local walls = setmetatable({}, {__mode = "v"})
-- Test awful.wallpaper garbage collection.
table.insert(steps, function()
walls["first"] = awall {
screen = screen[1],
widget = {
{
image = beautiful.wallpaper,
upscale = true,
downscale = true,
widget = wibox.widget.imagebox,
},
valign = "center",
halign = "center",
tiled = false,
widget = wibox.container.tile,
}
}
collectgarbage("collect")
return true
end)
table.insert(steps, function(count)
if count < 3 then
collectgarbage("collect")
return
end
assert(walls["first"])
walls["second"] = awall {
screen = screen[1],
widget = {
{
image = beautiful.wallpaper,
upscale = true,
downscale = true,
widget = wibox.widget.imagebox,
},
valign = "center",
halign = "center",
tiled = false,
widget = wibox.container.tile,
}
}
return true
end)
local repaint_called, paint_width, paint_height = false, nil, nil
-- Test setting "after the fact"
table.insert(steps, function(count)
if count < 3 then
collectgarbage("collect")
return
end
assert(walls["second"])
assert(not walls["first"])
local real_repaint = walls["second"].repaint
walls["second"].repaint = function(self)
repaint_called = true
real_repaint(self)
end
walls["second"].widget = wibox.widget {
fit = function(_, w, h)
return w, h
end,
draw = function(self, ctx, cr2, width, height)
cr2:set_source_rgba(1, 0, 0, 0.5)
cr2:rectangle(0, 0, width/2, height/2)
cr2:fill()
paint_width, paint_height = width, height
assert((not self.dpi) and ctx.dpi)
end
}
walls["second"].bg = "#0000ff"
walls["second"].fg = "#00ff00"
assert(repaint_called)
-- This needs to happen after this event loop to avoid
-- painting the wallpaper many time in a row.
assert(not paint_width)
return true
end)
table.insert(steps, function()
assert(walls["second"])
assert(paint_width == screen[1].geometry.width)
assert(paint_height == screen[1].geometry.height)
repaint_called = false
paint_width, paint_height = nil, nil
-- Disable new wallpaper creation to prevent request::wallpaper from
-- replacing the wall.
local constructor = getmetatable(awall).__call
setmetatable(awall, {__call = function() end})
screen[1]:fake_resize(
10, 10, math.floor(screen[1].geometry.width/2), math.floor(screen[1].geometry.height/2)
)
assert(paint_height ~= screen[1].geometry.height)
assert(repaint_called)
setmetatable(awall, {__call = constructor})
return true
end)
table.insert(steps, function(count)
if count == 1 then return end
print(paint_width, paint_height, screen[1].geometry.width, screen[1].geometry.height)
assert(paint_width == screen[1].geometry.width)
assert(paint_height == screen[1].geometry.height)
walls["second"].dpi = 123
assert(walls["second"].dpi == 123)
walls["second"]:detach()
return true
end)
table.insert(steps, function(count)
if count < 3 then
collectgarbage("collect")
return
end
assert(not walls["second"])
return true
end)
runner.run_steps(steps)

View File

@ -8,6 +8,7 @@ local xresources = require("beautiful.xresources")
local rnotification = require("ruled.notification")
local dpi = xresources.apply_dpi
local xrdb = xresources.get_current_theme()
local gdebug = require("gears.debug")
local gfs = require("gears.filesystem")
local themes_path = gfs.get_themes_dir()
@ -126,10 +127,40 @@ local wallpaper_alt_fg = xrdb.color12
if not is_dark_bg then
wallpaper_bg, wallpaper_fg = wallpaper_fg, wallpaper_bg
end
theme.wallpaper = function(s)
return theme_assets.wallpaper(wallpaper_bg, wallpaper_fg, wallpaper_alt_fg, s)
local rsvg = pcall(function() return require("lgi").Rsvg end)
if rsvg then
local handle = require("lgi").Rsvg.Handle.new_from_file(
themes_path.."xresources/wallpaper.svg"
)
if handle then
handle:set_stylesheet([[
.normal {
fill: ]]..wallpaper_fg..[[;
}
.background {
fill: ]]..wallpaper_bg..[[;
stroke: ]]..wallpaper_bg..[[;
}
.logo {
fill: ]]..wallpaper_alt_fg..[[;
}
]])
theme.wallpaper = handle
end
else
gdebug.print_warning("Could not load the wallpaper: librsvg is not installed.")
end
if not theme.wallpaper then
theme.wallpaper = themes_path.."xresources/wallpaper.svg"
end
theme.wallpaper_bg = wallpaper_bg
-- Set different colors for urgent notifications.
rnotification.connect_signal('request::rules', function()
rnotification.append_rule {

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1280pt" height="720pt" viewBox="0 0 1280 720" version="1.1">
<rect x="0" y="0" width="1280" height="720" style="stroke:none;" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843137%,47.843137%,70.196078%);fill-opacity:1;" d="M 1152 72 L 1224 72 L 1224 144 L 1152 144 Z M 1152 72 " class="logo"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 0 24 L 48 24 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 156 L 1224 156 L 1224 228 L 1152 228 Z M 1152 156 " class="normal"/>
<path style="fill:none !important;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 48 L 48 48 L 48 72 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 84 L 24 132 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 48 84 L 48 132 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 240 L 1224 240 L 1224 312 L 1152 312 Z M 1152 240 " class="normal"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 192 L 72 192 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 216 L 72 216 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 324 L 1224 324 L 1224 396 L 1152 396 Z M 1152 324 " class="normal"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 276 L 72 276 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 0 300 L 48 300 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 408 L 1224 408 L 1224 480 L 1152 480 Z M 1152 408 " class="normal"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 36 360 L 36 384 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 492 L 1224 492 L 1224 564 L 1152 564 Z M 1152 492 " class="normal"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 444 L 24 492 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 48 444 L 48 492 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style=" stroke:none;fill-rule:nonzero;" d="M 1152 576 L 1224 576 L 1224 648 L 1152 648 Z M 1152 576 " class="normal"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 528 L 72 528 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
<path style="fill:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;" d="M 24 552 L 72 552 " transform="matrix(1,0,0,1,1152,72)" class="background"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB