awesome/lib/awful/root.lua

120 lines
3.9 KiB
Lua

---------------------------------------------------------------------------
-- @author Emmanuel Lepage-Vallee <elv1313@gmail.com>
-- @copyright 2018-2019 Emmanuel Lepage-Vallee
-- @module root
---------------------------------------------------------------------------
local capi = { root = root }
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
for _, type_name in ipairs { "button", "key" } do
local prop_name = type_name.."s"
-- The largest amount of wall clock time when loading Awesome 3.4 rc.lua
-- was the awful.util.table.join (now gears.table.join). While the main
-- bottleneck in the newer releases moved into LGI, doing all these `join`
-- slow startup down quite a lot. On top of that, with the ability to add
-- and remove keys and buttons can cause a large overhead of its own. To
-- mitigate that, only set the actual content once per main loop iteration.
--
-- The C code also delay uploading these keys into the X server to prevent
-- too many keyboard map changes from freezing Awesome.
local has_delayed, added, removed = false, {}, {}
local function delay(value)
if value then
table.insert(added, value)
end
if has_delayed then return end
has_delayed = true
gtimer.delayed_call(function()
local new_values = capi.root["_"..prop_name]()
-- In theory, because they are inserted ordered, it is safe to assume
-- the once found, the capi.key/button will be next to each other.
for _, v in ipairs(removed) do
local idx = gtable.hasitem(new_values, v[1])
if idx then
for i=1, #v do
assert(
new_values[idx] == v[i],
"The root private "..type_name.." table is corrupted"
)
table.remove(new_values, idx)
end
end
idx = gtable.hasitem(added, v)
if idx then
table.remove(added, idx)
end
end
local joined = gtable.join(unpack(added))
new_values = gtable.merge(new_values, joined)
capi.root["_"..prop_name](new_values)
has_delayed, added, removed = false, {}, {}
end)
end
capi.root["_append_"..type_name] = function(value)
if not value then return end
local t1 = capi.root._private[prop_name]
-- Simple case
if (not t1) or not next(t1) then
capi.root[prop_name] = {value}
assert(capi.root._private[prop_name])
return
end
delay(value)
end
capi.root["_append_"..prop_name] = function(values)
-- It's pointless to use gears.table.merge, in the background it has the
-- same loop anyway. Also, this isn't done very often.
for _, value in ipairs(values) do
capi.root["_append_"..type_name](value)
end
end
capi.root["_remove_"..type_name] = function(value)
if not capi.root._private[prop_name] then return end
local k = gtable.hasitem(capi.root._private[prop_name], value)
if k then
table.remove(capi.root._private[prop_name], k)
end
-- Because of the legacy API, it is possible the capi.key/buttons will
-- be in the formatted table but not of the awful.key/button one.
assert(value[1])
table.insert(removed, value)
end
capi.root["has_"..type_name] = function(item)
if not item["_is_capi_"..type_name] then
item = item[1]
end
return gtable.hasitem(capi.root["_"..prop_name](), item) ~= nil
end
assert(root[prop_name])
end