local gears_obj = require("gears.object") local gears_tab = require("gears.table") local grect = require("gears.geometry").rectangle local screen, meta = awesome._shim_fake_class() screen._count, screen._deleted = 0, {} local function get_drawin_screen(s, d) return grect.area_intersect_area (s.geometry, { x = d:geometry().x, y = d:geometry().y, width = 1, height = 1 }) end local function compute_workarea(s) local struts = {top=0,bottom=0,left=0,right=0} for _, c in ipairs(drawin.get()) do if get_drawin_screen(s, c) then for k,v in pairs(struts) do struts[k] = v + (c:struts()[k] or 0) end end end for _, c in ipairs(client.get()) do if c.screen == s then for k,v in pairs(struts) do struts[k] = v + (c:struts()[k] or 0) end 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() awesome._forward_class(s, screen) s._private = {} s.valid = true -- Deprecated. s.data = s._private -- Copy the geo in case the args are mutated local geo = { x = args.x , y = args.y , width = args.width , height = args.height, } function s._resize(args2) 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 geo.height = args2.height or geo.height s:emit_signal("property::geometry", old) end 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 return setmetatable(s,{ __index = function(_, key) 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 = {} function screen._add_screen(args) local s = create_screen(args) table.insert(screens, s) -- Skip the metatable or it will have side effects rawset(s, "index", #screens) 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 screen do if not xmax or v.geometry.x+v.geometry.width > xmax.geometry.x+xmax.geometry.width then xmax = v end if not ymax or v.geometry.y+v.geometry.height > ymax.geometry.y+ymax.geometry.height then ymax = v end end 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 screens = {} if mouse then mouse.screen = nil end screen._count = 0 end function screen._setup_grid(w, h, rows, args) args = args or {} screen._clear() for i, row in ipairs(rows) do for j=1, row do args.x = (j-1)*w + (j-1)*screen._grid_horizontal_margin args.y = (i-1)*h + (i-1)*screen._grid_vertical_margin args.width = w args.height = h screen._add_screen(args) end end end local function iter_scr(_, _, s) if not s then assert(screen[1]) return screen[1], 1 end local i = s.index if i < #screen then return screen[i+1], i+1 end end function screen._viewports() 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 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, __index = catch_invalid }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80