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

View File

@ -1,7 +1,7 @@
local gears_obj = require("gears.object")
local screen, meta = awesome._shim_fake_class()
screen._count = 0
screen._count, screen._deleted = 0, {}
local function create_screen(args)
local s = gears_obj()
@ -41,6 +41,8 @@ local function create_screen(args)
end
return setmetatable(s,{ __index = function(_, key)
assert(s.valid)
if key == "geometry" then
return {
x = geo.x or 0,
@ -59,7 +61,7 @@ local function create_screen(args)
return meta.__index(_, key)
end
end,
__newindex = function(...) return meta.__newindex(...) end
__newindex = function(...) assert(s.valid); return meta.__newindex(...) end
})
end
@ -91,8 +93,36 @@ function screen._get_extents()
return xmax.geometry.x+xmax.geometry.width, ymax.geometry.y+ymax.geometry.height
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()
assert(#screen == screen._count)
for i=1, #screen do
screen._deleted[screen[i]] = true
screen[i].valid = false
screen[screen[i]] = nil
screen[i] = nil
end
@ -144,7 +174,8 @@ function screen.count()
end
return setmetatable(screen, {
__call = iter_scr
__call = iter_scr,
__index = catch_invalid
})
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80