Merge pull request #2759 from Elv13/improve_shims

Improve the shims
This commit is contained in:
Emmanuel Lepage Vallée 2019-08-25 15:12:45 -04:00 committed by GitHub
commit d0fcf9b369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 336 additions and 56 deletions

View File

@ -35,8 +35,8 @@ local function draw_mouse(x, y)
end
-- Print an outline for the screens
if not screen.no_outline then
for _, s in ipairs(screen) do
if not rawget(screen, "no_outline") then
for s in screen do
cr:save()
-- Draw the screen outline
cr:set_source(color("#00000044"))

View File

@ -75,6 +75,10 @@ function awesome.pixbuf_to_surface(_, path)
return awesome.load_image(path)
end
function awesome.xrdb_get_value()
return nil
end
-- Always show deprecated messages
awesome.version = "v9999"

View File

@ -22,6 +22,45 @@ local function titlebar_meta(c)
end
end
local properties = {}
-- Emit the request::geometry signal to make immobilized and awful.ewmh work.
for _, prop in ipairs {
"maximized", "maximized_horizontal", "maximized_vertical", "fullscreen" } do
properties["get_"..prop] = function(self)
return self.data[prop] or false
end
properties["set_"..prop] = function(self, value)
self.data[prop] = value or false
if value then
self:emit_signal("request::geometry", prop, nil)
end
self:emit_signal("property::"..prop, value)
end
end
function properties.get_screen(self)
return self.data.screen or screen[1]
end
function properties.set_screen(self, s)
s = screen[s]
self.data.screen = s
if self.x < s.geometry.x or self.x > s.geometry.x+s.geometry.width then
self:geometry { x = s.geometry.x }
end
if self.y < s.geometry.y or self.y > s.geometry.y+s.geometry.height then
self:geometry { y = s.geometry.y }
end
self:emit_signal("property::screen")
end
-- Create fake clients to move around
function client.gen_fake(args)
local ret = gears_obj()
@ -34,6 +73,7 @@ function client.gen_fake(args)
ret.border_width = 1
ret.icon_sizes = {{16,16}}
ret.name = "Example Client"
ret.data._struts = { top = 0, right = 0, left = 0, bottom = 0 }
-- This is a hack because there's a `:is_transient_for(c2)` method
-- and a `transient_for` property. It will cause a stack overflow
@ -49,6 +89,7 @@ function client.gen_fake(args)
-- Tests should always set a geometry, but just in case
for _, v in ipairs{"x","y","width","height"} do
ret[v] = ret[v] or 1
assert((not args[v]) or ret[v] == args[v])
end
-- Emulate capi.client.geometry
@ -89,6 +130,10 @@ function client.gen_fake(args)
return nil
end
function ret:set_xproperty(prop, value)
ret[prop] = value
end
function ret:get_icon(_)
return require("beautiful").awesome_icon
end
@ -101,6 +146,32 @@ function client.gen_fake(args)
--TODO
end
function ret:apply_size_hints(w, h)
return w or ret.width, h or ret.height
end
function ret:kill()
local old_tags = ret:tags() or {}
for k, c in ipairs(clients) do
if c == ret then
ret:emit_signal("unmanaged", c)
ret.valid = false
table.remove(clients, k)
break
end
end
ret._tags = {}
for _, t in ipairs(old_tags) do
ret:emit_signal("untagged", t)
t:emit_signal("property::tags")
end
assert(not ret.valid)
end
titlebar_meta(ret)
function ret:tags(new) --FIXME
@ -121,14 +192,55 @@ function client.gen_fake(args)
return {}
end
function ret:struts(new)
for k, v in pairs(new or {}) do
ret.data._struts[k] = v
end
return ret.data._struts
end
function ret:struts(new)
for k, v in pairs(new or {}) do
ret.data._struts[k] = v
end
return ret.data._struts
end
-- Set a dummy one for now since set_screen will corrupt it.
ret._old_geo = {}
-- Set the screen attributes.
local s = args.screen
-- Pick the screen from the geometry.
if not s then
for s2 in screen do
local geo = s2.geometry
if geo.x >= ret.x and geo.y >= ret.y and ret.x < geo.x+geo.width
and ret.y < geo.y+geo.height then
s = s2
end
end
end
-- This will happen if the screen coords are not {0,0} and the client had
-- an unspecified position.
s = s or screen[1]
properties.set_screen(ret, s)
-- Set the geometry *again* because the screen possibly overwrote it.
for _, v in ipairs{"x","y","width","height"} do
ret[v] = args[v] or ret[v]
end
-- Record the geometry
ret._old_geo = {}
push_geometry(ret)
ret._old_geo[1]._hide = args.hide_first
-- Set the attributes
ret.screen = args.screen or screen[1]
-- Good enough for the geometry and border
ret.drawin = ret
ret.drawable = ret
@ -138,10 +250,6 @@ function client.gen_fake(args)
ret.below = false
ret.above = false
ret.sticky = false
ret.maximized = false
ret.fullscreen = false
ret.maximized_vertical = false
ret.maximized_horizontal = false
-- Add to the client list
table.insert(clients, ret)
@ -149,8 +257,21 @@ function client.gen_fake(args)
client.focus = ret
setmetatable(ret, {
__index = function(...) return meta.__index(...) end,
__newindex = function(...) return meta.__newindex(...) end
__index = function(self, key)
if properties["get_"..key] then
return properties["get_"..key](self)
end
return meta.__index(self, key)
end,
__newindex = function(self, key, value)
if properties["set_"..key] then
return properties["set_"..key](self, value)
end
return meta.__newindex(self, key, value)
end
})
client.emit_signal("manage", ret)

View File

@ -35,11 +35,20 @@ local function new_drawin(_, args)
ret.data.drawable.surface = cairo.ImageSurface(cairo.Format.ARGB32, 0, 0)
ret.data.drawable.geometry = ret.geometry
ret.data.drawable.refresh = function() end
ret.data._struts = { top = 0, right = 0, left = 0, bottom = 0 }
for _, k in pairs{ "buttons", "struts", "get_xproperty", "set_xproperty" } do
for _, k in pairs{ "buttons", "get_xproperty", "set_xproperty" } do
ret[k] = function() end
end
function ret:struts(new)
for k, v in pairs(new or {}) do
ret.data._struts[k] = v
end
return ret.data._struts
end
local md = setmetatable(ret, {
__index = function(...) return meta.__index(...) end,
__newindex = function(...) return meta.__newindex(...) end

View File

@ -53,20 +53,42 @@ function mouse.push_history()
mouse.history = {}
end
local forced_screen = nil
return setmetatable(mouse, {
__index = function(self, key)
if key == "screen" then
return screen[1]
if forced_screen and screen._deleted[forced_screen] then
forced_screen = nil
end
for s in screen do
if coords.x > s.geometry.x and coords.x < s.geometry.x +s.geometry.width
and coords.y > s.geometry.y and coords.y < s.geometry.y +s.geometry.height then
return s
end
end
-- Using capi.mouse.screen is *not* supported when there is zero
-- screen. Nearly all the code uses `mouse.screen` as its ultimate
-- fallback. Having no screens is tolerated during early
-- initialization and that's it.
return screen.count() > 0 and screen[1] or assert(
false, "Calling `mouse.screen` without screens isn't supported"
)
end
local h = rawget(mouse,"_i_handler")
if h then
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

@ -8,12 +8,22 @@ function root:tags()
return root._tags
end
function root:size() --TODO use the screens
return 0, 0
function root.size()
local geo = {x1 = math.huge, y1 = math.huge, x2 = 0, y2 = 0}
for s in screen do
geo.x1 = math.min( geo.x1, s.geometry.x )
geo.y1 = math.min( geo.y1, s.geometry.y )
geo.x2 = math.max( geo.x2, s.geometry.x+s.geometry.width )
geo.y2 = math.max( geo.y2, s.geometry.y+s.geometry.height )
end
return math.max(0, geo.x2-geo.x1), math.max(0, geo.y2 - geo.y1)
end
function root:size_mm()
return 0, 0
function root.size_mm()
local w, h = root.size()
return (w/96)*25.4, (h/96)*25.4
end
function root.cursor() end

View File

@ -1,7 +1,31 @@
local gears_obj = require("gears.object")
local gears_tab = require("gears.table")
local screen, meta = awesome._shim_fake_class()
screen._count = 0
screen._count, screen._deleted = 0, {}
local function compute_workarea(s)
local struts = {top=0,bottom=0,left=0,right=0}
for _, c in ipairs(drawin.get()) do
for k,v in pairs(struts) do
struts[k] = v + (c:struts()[k] or 0)
end
end
for _, c in ipairs(client.get()) do
for k,v in pairs(struts) do
struts[k] = v + (c:struts()[k] or 0)
end
end
return {
x = s.geometry.x + struts.left,
y = s.geometry.y + struts.top ,
width = s.geometry.width - struts.left - struts.right ,
height = s.geometry.height - struts.top - struts.bottom,
}
end
local function create_screen(args)
local s = gears_obj()
@ -19,7 +43,7 @@ local function create_screen(args)
}
function s._resize(args2)
local old = s.geometry
local old = gears_tab.clone(s.geometry)
geo.x = args2.x or geo.x
geo.y = args2.y or geo.y
geo.width = args2.width or geo.width
@ -27,39 +51,71 @@ local function create_screen(args)
s:emit_signal("property::geometry", old)
end
s.outputs = { ["LVDS1"] = {
mm_width = 0,
mm_height = 0,
function s.fake_resize(self, x, y, width, height)
self._resize {
x=x,y=y,width=width,height=height
}
end
function s:fake_remove()
local i = s.index
table.remove(screen, i)
screen._deleted[s] = true
s:emit_signal("removed")
screen[screen[i]] = nil
s.valid = false
end
function s:swap(other_s)
local s1geo = gears_tab.clone(s.geometry)
local s2geo = gears_tab.clone(other_s.geometry)
s:fake_resize(
s2geo.x, s2geo.y, s2geo.width, s2geo.height
)
other_s:fake_resize(
s1geo.x, s1geo.y, s1geo.width, s1geo.height
)
s:emit_signal("swapped",other_s)
other_s:emit_signal("swapped",s)
end
s.outputs = { LVDS1 ={
name = "LVDS1",
mm_width = (geo.width /96)*25.4,
mm_height = (geo.height/96)*25.4,
}}
local wa = args.workarea_sides or 10
-- This will happen if `clear()` is called
if mouse and not mouse.screen then
mouse.screen = s
end
return setmetatable(s,{ __index = function(_, key)
if key == "geometry" then
return {
x = geo.x or 0,
y = geo.y or 0,
width = geo.width ,
height = geo.height,
}
elseif key == "workarea" then
return {
x = (geo.x or 0) + wa ,
y = (geo.y or 0) + wa ,
width = geo.width - 2*wa,
height = geo.height - 2*wa,
}
else
return meta.__index(_, key)
end
end,
__newindex = function(...) return meta.__newindex(...) end
})
assert(s.valid)
if key == "geometry" then
return {
x = geo.x or 0,
y = geo.y or 0,
width = geo.width ,
height = geo.height,
}
elseif key == "workarea" then
if screen._track_workarea then
return compute_workarea(s)
else
return {
x = (geo.x or 0) + wa ,
y = (geo.y or 0) + wa ,
width = geo.width - 2*wa,
height = geo.height - 2*wa,
}
end
else
return meta.__index(_, key)
end
end,
__newindex = function(...) assert(s.valid); return meta.__newindex(...) end
})
end
local screens = {}
@ -74,11 +130,13 @@ function screen._add_screen(args)
screen[#screen+1] = s
screen[s] = s
screen._count = screen._count + 1
return s
end
function screen._get_extents()
local xmax, ymax
for _, v in ipairs(screen) do
for v in screen do
if not xmax or v.geometry.x+v.geometry.width > xmax.geometry.x+xmax.geometry.width then
xmax = v
end
@ -90,8 +148,47 @@ 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 then return end
-- Try to get the screens by output name.
if type(s) == "string" then
for s2 in screen do
for out in pairs(s2.outputs or {}) do
if out == s then
return s2
end
end
end
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
@ -126,11 +223,21 @@ local function iter_scr(_, _, s)
local i = s.index
if i + 1 < #screen then
if i < #screen then
return screen[i+1], i+1
end
end
function screen._areas()
return {}
end
function screen.fake_add(x,y,width,height)
return screen._add_screen {
x=x,y=y,width=width,height=height
}
end
screen._add_screen {width=320, height=240}
screen._grid_vertical_margin = 10
@ -138,12 +245,15 @@ screen._grid_horizontal_margin = 10
screen.primary = screen[1]
screen._track_workarea = false
function screen.count()
return 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

View File

@ -16,15 +16,19 @@ local function new_tag(_, args)
awesome._forward_class(ret, tag)
ret.data = {}
ret.name = args.name or "test"
ret.name = tostring(args.name) or "test"
ret.activated = true
ret.selected = not has_selected_tag(args.screen)
function ret:clients(_) --TODO handle new
local list = {}
for _, c in ipairs(client.get()) do
if c.screen == (ret.screen or screen[1]) then
table.insert(list, c)
if #c:tags() > 0 then
for _, t in ipairs(c:tags()) do
if t == ret then
table.insert(list, c)
end
end
end
end