awesome/tests/test-struts.lua

622 lines
16 KiB
Lua

local placement = require("awful.placement")
local wibox = require("wibox")
local wibar = require("awful.wibar")
local test_client = require("_client")
local steps = {}
local parent, small
local twibar, bwibar, lwibar, rwibar
-- Remove the original wibar.
screen.primary.mywibox:remove()
screen.primary.mywibox = nil
for _=1, 3 do
collectgarbage("collect")
end
-- Track garbage collection.
local wibars = setmetatable({}, {__mode="v"})
-- Pretty print issues
local function print_expected()
local wa, sa = mouse.screen.workarea, mouse.screen.geometry
local ret = table.concat{
"\nSCREEN: ", sa.x, " ", sa.y," ", sa.width, " ", sa.height
}
ret = table.concat{ret,
"\nWORKAREA: ", wa.x, " ", wa.y," ", wa.width, " ", wa.height
}
ret = table.concat{ret,
"\nSTRUTS: l:",
wa.x, " t:",
wa.y," r:",
sa.width - wa.width - wa.x, " b:",
sa.height - wa.height - wa.y
}
for k, w in ipairs {lwibar, rwibar, twibar, bwibar} do
ret = table.concat{
ret , "\n " , k, ": ", w.position, " [",
w.width, ", ",
w.height ,
"]"
}
end
return ret
end
-- All wibars on top and bottom are full width and all on left and right
-- must honor the workarea height
local function validate_wibar_geometry()
for _, w in ipairs {lwibar, rwibar, twibar, bwibar} do
assert(w and w.position and w.screen)
if w.visible then
if w.position == "top" or w.position == "bottom" then
assert(w.width == w.screen.geometry.width, print_expected())
else
assert(w.height == w.screen.workarea.height, print_expected())
end
end
end
end
-- Replace the original wibar.
table.insert(steps, function()
twibar = wibar {position = "top", bg = "#ff0000"}
return true
end)
-- Test the struts without using wibars
table.insert(steps, function()
if screen[1].workarea.y == 0 then return end
local sgeo = screen.primary.geometry
-- Manually place at the bottom right
local w = wibox{
height = 50,
width = 50,
y = sgeo.y + sgeo.height - 50,
x = sgeo.x + sgeo.width - 50,
visible = true,
}
w:struts {
left = 0,
top = 0,
bottom = 50,
right = 50,
}
local wa = screen.primary.workarea
assert(wa.x == 0 )
assert(wa.y == twibar.height )
assert(wa.width == sgeo.width - 50 )
assert(wa.height == sgeo.height - 50 - twibar.height)
w:struts {
left = 0,
top = 0,
bottom = 0,
right = 0,
}
w.visible = false
wa = screen.primary.workarea
assert(wa.x == 0 )
assert(wa.y == twibar.height )
assert(wa.width == sgeo.width )
assert(wa.height == sgeo.height - twibar.height)
return true
end)
-- Test "attach" for wibox/client to wibox
table.insert(steps, function()
parent = wibox {
visible = true,
width = 500,
height = 500,
}
placement.centered(parent)
small = wibox {
bg = "#ff0000",
height = 24,
ontop = true,
visible = true,
}
-- Add an attached function
placement.top_left(small, {parent = parent})
placement.maximize_horizontally(small, {parent = parent, attach = true})
return true
end)
table.insert(steps, function()
assert(parent:geometry().width == 500)
assert(parent:geometry().height == 500)
assert(parent:geometry().y == small:geometry().y)
assert(parent:geometry().x == small:geometry().x)
assert(parent:geometry().width == small:geometry().width )
assert(small:geometry().height == 24)
-- Now, move the parent and see of the attached one is correctly updated
placement.stretch_left(parent)
return true
end)
table.insert(steps, function()
assert(parent:geometry().y == small:geometry().y)
assert(parent:geometry().x == small:geometry().x)
assert(parent:geometry().width == small:geometry().width )
assert(small:geometry().height == 24)
-- Hide (and hopefully GC) the old "small"
small.visible = false
-- Do the same, but with placement compositing
small = wibox {
bg = "#ff0000",
height = 50,
width = 50,
ontop = true,
visible = true,
}
local p = placement.bottom_right + placement.scale
p(small, {parent=parent, attach=true, direction="left", to_percent=0.5})
return true
end)
local function check_ratio()
assert(
(
parent:geometry().y
+ parent:geometry().height
- small :geometry().height
) == small:geometry().y
)
assert(math.abs(parent:geometry().x + math.ceil(parent:geometry().width/2) - small:geometry().x) <= 1)
assert(math.abs(math.ceil(parent:geometry().width/2) - small:geometry().width) <= 1)
assert(small:geometry().height == 50)
end
table.insert(steps, function()
check_ratio()
-- Now, do some more transformation on the parent and make sure the "small"
-- wibox follow.
placement.scale (parent, {direction="left", to_percent=0.2})
placement.scale (parent, {direction="up" , to_percent=0.2})
placement.bottom (parent )
placement.top_right(parent )
placement.centered (parent )
return true
end)
-- Do the same checks to see if everything has followed as expected
table.insert(steps, function()
check_ratio()
-- Now, test if the wibar has updated the workarea.
placement.maximize(parent, {honor_workarea = true})
return true
end)
table.insert(steps, function()
local wa = screen.primary.workarea
local sgeo = screen.primary.geometry
local wgeo = twibar:geometry()
assert(wa.width == sgeo.width )
assert(wa.x == sgeo.x )
assert(wa.y == sgeo.y + wgeo.height )
-- assert(wa.height == sgeo.height - wgeo.height)
-- assert(wgeo.height == sgeo.height - wa.height )
assert(parent.y == wa.y )
assert(parent.x == wa.x )
assert(parent.width == wa.width )
assert(parent.height == wa.height )
-- Add more wibars
bwibar = wibar {position = "bottom", bg = "#00ff00"}
lwibar = wibar {position = "left" , bg = "#0000ff"}
rwibar = wibar {position = "right" , bg = "#ff00ff"}
table.insert(wibars, bwibar)
table.insert(wibars, lwibar)
table.insert(wibars, rwibar)
validate_wibar_geometry()
return true
end)
-- Make sure the maximized client has the right size and position
local function check_maximize()
local pgeo = parent:geometry()
local margins = {left=0, right=0, top=0, bottom=0}
for _, w in ipairs {twibar, lwibar, rwibar, bwibar} do
if w.visible then
local pos = w.position
local w_or_h = (pos == "left" or pos == "right") and "width" or "height"
margins[pos] = margins[pos] + w[w_or_h]
end
end
local sgeo = parent.screen.geometry
sgeo.x = sgeo.x + margins.left
sgeo.y = sgeo.y + margins.top
sgeo.width = sgeo.width - margins.left - margins.right
sgeo.height = sgeo.height - margins.top - margins.bottom
local wa = parent.screen.workarea
for k, v in pairs(wa) do
assert(sgeo[k] == v)
end
assert(sgeo.width == pgeo.width + 2*parent.border_width)
assert(sgeo.height == pgeo.height + 2*parent.border_width)
assert(sgeo.x == pgeo.x )
assert(sgeo.y == pgeo.y )
end
table.insert(steps, function()
-- Attach the parent wibox to it is updated along the workarea
placement.maximize(parent, {honor_workarea = true, attach = true})
-- Make the wibox more visible
parent.border_color = "#ffff00"
parent.border_width = 10
parent.ontop = true
-- parent.visible = false
local wa = screen.primary.workarea
local sgeo = screen.primary.geometry
assert(lwibar.width == rwibar.width )
assert(lwibar.height == rwibar.height )
assert(twibar.x == bwibar.x )
assert(twibar.width == bwibar.width )
-- Check the left wibar size and position
assert(lwibar.x == wa.x - lwibar.width )
assert(lwibar.height == wa.height )
-- Check the right wibar size and position
assert(rwibar.x == wa.x + wa.width )
assert(rwibar.height == wa.height )
-- Check the bottom wibar size and position
assert(bwibar.width == sgeo.width )
assert(bwibar.x == 0 )
return true
end)
table.insert(steps, function()
check_maximize()
-- There should be a detach callback
assert(lwibar.detach_callback)
-- Begin to move wibars around
lwibar.position = "top"
assert(lwibar.position == "top")
assert(lwibar.y == twibar.height)
validate_wibar_geometry()
return true
end)
table.insert(steps, function()
check_maximize()
bwibar.position = "right"
bwibar.ontop = true
rwibar.ontop = true
assert(bwibar.position == "right")
validate_wibar_geometry()
return true
end)
table.insert(steps, function()
check_maximize()
rwibar.position = "top"
validate_wibar_geometry()
return true
end)
table.insert(steps, function()
check_maximize()
bwibar.position = "top"
validate_wibar_geometry()
return true
end)
table.insert(steps, function()
check_maximize()
for _, w in ipairs {twibar, lwibar, rwibar, bwibar} do
w.position = "right"
validate_wibar_geometry()
end
return true
end)
-- Test visibility
table.insert(steps, function()
check_maximize()
twibar.visible = false
rwibar.visible = false
return true
end)
table.insert(steps, function()
check_maximize()
twibar.visible = true
return true
end)
table.insert(steps, function()
check_maximize()
return true
end)
-- Now test again with a real client
local c
table.insert(steps, function()
-- I'm lazy, so get rid of all the wiboxes that have struts
parent.visible = false
small.visible = false
bwibar.visible = false
lwibar.visible = false
rwibar.visible = false
twibar.visible = false
-- Spawn a client to test things with
assert(#client.get() == 0)
test_client()
return true
end)
-- Given a geometry and a workarea, test that the given struts are applied
local function test_workarea(geo, wa, left, right, top, bottom)
-- Get the line number from where we were called (helps debugging)
local line = debug.getinfo(2).currentline
assert(geo.x + left == wa.x,
string.format("%d + %d == %d called from line %d", geo.x, left, wa.x, line))
assert(geo.y + top == wa.y,
string.format("%d + %d == %d called from line %d", geo.y, top, wa.y, line))
assert(geo.width - left - right == wa.width,
string.format("%d - %d - %d == %d called from line %d", geo.width, left, right, wa.width, line))
assert(geo.height - top - bottom == wa.height,
string.format("%d - %d - %d == %d called from line %d", geo.height, top, bottom, wa.height, line))
end
table.insert(steps, function()
if #client.get() ~= 1 then
return
end
c = client.get()[1]
assert(c)
assert(c:isvisible())
-- Test some simple struts
c:struts { left = 50 }
test_workarea(c.screen.geometry, c.screen.workarea, 50, 0, 0, 0)
validate_wibar_geometry()
-- A tag switch should make the client no longer apply
screen.primary.tags[2]:view_only()
test_workarea(c.screen.geometry, c.screen.workarea, 0, 0, 0, 0)
validate_wibar_geometry()
-- But sticky clients always 'count'
c.sticky = true
test_workarea(c.screen.geometry, c.screen.workarea, 50, 0, 0, 0)
validate_wibar_geometry()
c.sticky = false
test_workarea(c.screen.geometry, c.screen.workarea, 0, 0, 0, 0)
validate_wibar_geometry()
-- And switch back to the right tag
c.first_tag:view_only()
test_workarea(c.screen.geometry, c.screen.workarea, 50, 0, 0, 0)
validate_wibar_geometry()
-- What if we move the client to another tag?
c:tags{ screen.primary.tags[2] }
test_workarea(c.screen.geometry, c.screen.workarea, 0, 0, 0, 0)
validate_wibar_geometry()
-- Move it back to the selected tag
c:tags{ screen.primary.tags[1] }
test_workarea(c.screen.geometry, c.screen.workarea, 50, 0, 0, 0)
validate_wibar_geometry()
return true
end)
local s
table.insert(steps, function()
c = client.get()[1]
assert(c)
s = c.screen
c:kill()
bwibar:remove()
lwibar:remove()
rwibar:remove()
twibar:remove()
for _, w in ipairs(wibars) do
assert(not w.visible)
end
-- Make sure the placement doesn't hold a reference.
bwibar, lwibar, rwibar, twibar = nil, nil, nil, nil
return true
end)
table.insert(steps, function()
for _=1, 3 do
collectgarbage("collect")
end
if next(wibars) then
for _, w in ipairs(wibars) do
assert(not w.visible)
end
return
end
return true
end)
table.insert(steps, function()
if client.get()[1] then
return
end
test_workarea(s.geometry, s.workarea, 0, 0, 0, 0)
validate_wibar_geometry()
local wdg = {
layout = wibox.layout.align.vertical,
wibox.widget.textbox("BEGIN"),
nil,
wibox.widget.textbox("END")
}
local wdg2 = {
layout = wibox.layout.align.horizontal,
wibox.widget.textbox("BEGIN"),
nil,
wibox.widget.textbox("END")
}
lwibar = wibar{position = "top", screen = s, height = 15,
visible = true, bg = "#660066"}
lwibar:setup(wdg2)
table.insert(wibars, lwibar)
rwibar = wibar{position = "top", screen = s, height = 15,
visible = true, bg = "#660000"}
rwibar:setup(wdg2)
table.insert(wibars, rwibar)
bwibar = wibar{position = "left", screen = s, ontop = true, width = 64,
visible = true, bg = "#006600"}
bwibar:setup(wdg)
table.insert(wibars, bwibar)
twibar = wibar{position = "bottom", screen = s,
height = 15, bg = "#666600"}
twibar:setup(wdg2)
table.insert(wibars, twibar)
test_workarea(s.geometry, s.workarea, 64, 0, 30, 15)
validate_wibar_geometry()
bwibar:remove()
test_workarea(s.geometry, s.workarea, 0, 0, 30, 15)
validate_wibar_geometry()
lwibar:remove()
test_workarea(s.geometry, s.workarea, 0, 0, 15, 15)
validate_wibar_geometry()
rwibar:remove()
test_workarea(s.geometry, s.workarea, 0, 0, 0, 15)
validate_wibar_geometry()
twibar:remove()
test_workarea(s.geometry, s.workarea, 0, 0, 0, 0)
validate_wibar_geometry()
return true
end)
-- Test resizing wibars.
table.insert(steps, function()
-- Make sure the placement doesn't hold a reference.
bwibar, lwibar, rwibar, twibar = nil, nil, nil, nil
for _=1, 3 do
collectgarbage("collect")
end
assert(not next(wibars))
twibar = wibar{position = "top", screen = s, height = 15,
visible = true, bg = "#660066"}
assert(twibar.height == 15)
twibar.height = 64
assert(twibar.height == 64)
twibar:geometry { height = 128 }
assert(twibar.height == 128)
local old_width = twibar.width
twibar.width = 42
assert(twibar.width == old_width)
return true
end)
require("_runner").run_steps(steps)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80