shims: Enforce working on valid screen objects.

Previously it was possible to manipulate deleted screens and that
made debugging harder down the line. By catching this early, it
wont be as nightmarish.
This commit is contained in:
Emmanuel Lepage Vallee 2019-04-27 15:45:56 -04:00
parent ce2dbea510
commit a18348542c
2 changed files with 45 additions and 6 deletions

View File

@ -53,9 +53,14 @@ function mouse.push_history()
mouse.history = {} mouse.history = {}
end end
local forced_screen = nil
return setmetatable(mouse, { return setmetatable(mouse, {
__index = function(self, key) __index = function(self, key)
if key == "screen" then if key == "screen" then
if forced_screen and screen._deleted[forced_screen] then
forced_screen = nil
end
return screen[1] return screen[1]
end end
local h = rawget(mouse,"_i_handler") local h = rawget(mouse,"_i_handler")
@ -63,10 +68,13 @@ return setmetatable(mouse, {
return h(self, key) return h(self, key)
end end
end, end,
__newindex = function(...) __newindex = function(_, k, v)
local h = rawget(mouse,"_ni_handler") local h = rawget(mouse,"_ni_handler")
if h then if k == "screen" then
h(...) -- This will assert if the screen is invalid
forced_screen = v and screen[v] or nil
elseif h then
h(_, k, v)
end end
end, end,
}) })

View File

@ -1,7 +1,7 @@
local gears_obj = require("gears.object") local gears_obj = require("gears.object")
local screen, meta = awesome._shim_fake_class() local screen, meta = awesome._shim_fake_class()
screen._count = 0 screen._count, screen._deleted = 0, {}
local function create_screen(args) local function create_screen(args)
local s = gears_obj() local s = gears_obj()
@ -41,6 +41,8 @@ local function create_screen(args)
end end
return setmetatable(s,{ __index = function(_, key) return setmetatable(s,{ __index = function(_, key)
assert(s.valid)
if key == "geometry" then if key == "geometry" then
return { return {
x = geo.x or 0, x = geo.x or 0,
@ -59,7 +61,7 @@ local function create_screen(args)
return meta.__index(_, key) return meta.__index(_, key)
end end
end, end,
__newindex = function(...) return meta.__newindex(...) end __newindex = function(...) assert(s.valid); return meta.__newindex(...) end
}) })
end end
@ -91,8 +93,36 @@ function screen._get_extents()
return xmax.geometry.x+xmax.geometry.width, ymax.geometry.y+ymax.geometry.height return xmax.geometry.x+xmax.geometry.width, ymax.geometry.y+ymax.geometry.height
end end
-- The way the `screen` module is used to store both number and object is
-- problematic since it can cause invalid screens to be "resurrected".
local function catch_invalid(_, s)
-- The CAPI implementation allows `nil`
if s == nil or type(s) == "string" then return end
assert(screen ~= s, "Some code tried (and failed) to shadow the global `screen`")
-- Valid numbers wont get this far.
assert(type(s) == "table", "Expected a table, but got a "..type(s))
if type(s) == "number" then return end
assert(s.geometry, "The object is not a screen")
assert(s.outputs, "The object is not a screen")
assert((not screen._deleted[s]) or (not s.valid), "The shims are broken")
assert(not screen._deleted[s], "The screen "..tostring(s).."has been deleted")
-- Other errors. If someone place an object in the `screen` module, it wont
-- get this far. So the remaining cases are probably bugs.
assert(false)
end
function screen._clear() function screen._clear()
assert(#screen == screen._count)
for i=1, #screen do for i=1, #screen do
screen._deleted[screen[i]] = true
screen[i].valid = false
screen[screen[i]] = nil screen[screen[i]] = nil
screen[i] = nil screen[i] = nil
end end
@ -144,7 +174,8 @@ function screen.count()
end end
return setmetatable(screen, { return setmetatable(screen, {
__call = iter_scr __call = iter_scr,
__index = catch_invalid
}) })
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80