awful.placement: Extend the compositing feature

It can now keep the different return values and use them in
later chain nodes.

It also add a "virtual" geometry argument so the geometry is applied
only after the last node is executed.

Finally, it fixes using pretend and a composite chain at the same time.
This commit is contained in:
Emmanuel Lepage Vallee 2016-04-21 04:14:09 -04:00
parent be455cb140
commit e6a04a5922
1 changed files with 88 additions and 13 deletions

View File

@ -90,20 +90,89 @@ end
local wrap_client = nil
local function compose(w1, w2)
return wrap_client(function(...)
w1(...)
w2(...)
return --It make no sense to keep a return value
end)
--- Allow multiple placement functions to be daisy chained.
-- This also allow the functions to be aware they are being chained and act
-- upon the previous nodes results to avoid unnecessary processing or deduce
-- extra paramaters/arguments.
local function compose(...)
local queue = {}
local nodes = {...}
-- Allow placement.foo + (var == 42 and placement.bar)
if not nodes[2] then
return nodes[1]
end
-- nodes[1] == self, nodes[2] == other
for _, w in ipairs(nodes) do
-- Build an execution queue
if w.context and w.context == "compose" then
for _, elem in ipairs(w.queue or {}) do
table.insert(queue, elem)
end
else
table.insert(queue, w)
end
end
local ret = wrap_client(function(d, args, ...)
local rets = {}
local last_geo = nil
-- As some functions may have to take into account results from
-- previously execued ones, add the `composition_results` hint.
args = setmetatable({composition_results=rets}, {__index=args})
-- Only apply the geometry once, not once per chain node, to do this,
-- Force the "pretend" argument and restore the original value for
-- the last node.
local pretend_real = args.pretend
args.pretend = true
for k, f in ipairs(queue) do
if k == #queue then
args.pretent = pretend_real
end
local r = {f(d, args, ...)}
last_geo = r[1] or last_geo
args.override_geometry = last_geo
-- Keep the return value, store one per context
if f.context then
-- When 2 composition queue are executed, merge the return values
if f.context == "compose" then
for k2,v in pairs(r) do
rets[k2] = v
end
else
rets[f.context] = r
end
end
end
return last_geo, rets
end, "compose")
ret.queue = queue
return ret
end
wrap_client = function(f)
return setmetatable({is_placement=true}, {
__call = function(_,...) return f(...) end,
__add = compose, -- Composition is usually defined as +
__mul = compose -- Make sense if you think of the functions as matrices
})
wrap_client = function(f, context)
return setmetatable(
{
is_placement= true,
context = context,
},
{
__call = function(_,...) return f(...) end,
__add = compose, -- Composition is usually defined as +
__mul = compose -- Make sense if you think of the functions as matrices
}
)
end
local placement_private = {}
@ -116,7 +185,7 @@ local placement_private = {}
local placement = setmetatable({}, {
__index = placement_private,
__newindex = function(_, k, f)
placement_private[k] = wrap_client(f)
placement_private[k] = wrap_client(f, k)
end
})
@ -226,6 +295,12 @@ local function geometry_common(obj, args, new_geo, ignore_border_width)
obj, (not args.pretend) and new_geo or nil, ignore_border_width
)
-- When using the placement composition along with the "pretend"
-- option, it is necessary to keep a "virtual" geometry.
if args.override_geometry then
dgeo = args.override_geometry
end
-- Apply the margins
if args.margins then
local delta = type(args.margins) == "table" and args.margins or {