From fef8ef91cba02d3161ffbd59241970e46bbb060f Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 26 Aug 2008 16:03:28 +0200 Subject: [PATCH] awful: add no_overlap and no_offscreen placement Signed-off-by: Julien Danjou --- lib/awful.lua.in | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/lib/awful.lua.in b/lib/awful.lua.in index e77e0076..afd22ad1 100644 --- a/lib/awful.lua.in +++ b/lib/awful.lua.in @@ -1606,6 +1606,149 @@ function widget.button(args) return w end +--- Check if an area intersect another area. +-- @param a The area. +-- @param b The other area. +-- @return True if they intersect, false otherwise. +local function area_intersect_area(a, b) + return (b.x < a.x + a.width + and b.x + b.width > a.x + and b.y < a.y + a.height + and b.y + b.height > a.y) +end + +--- Get the intersect area between a and b. +-- @param a The area. +-- @param b The other area. +-- @return The intersect area. +local function area_intersect_area_get(a, b) + local g = {} + g.x = math.max(a.x, b.x) + g.y = math.max(a.y, b.y) + g.width = math.min(a.x + a.width, b.x + b.width) - g.x + g.height = math.min(a.y + a.height, b.y + b.height) - g.y + return g +end + +--- Remove an area from a list, splitting the space between several area that +-- can overlap. +-- @param areas Table of areas. +-- @param elem Area to remove. +-- @return The new area list. +local function area_remove(areas, elem) + local newareas = areas + for i, r in ipairs(areas) do + -- Check if the 'elem' intersect + if area_intersect_area(r, elem) then + -- It does? remove it + table.remove(areas, i) + local inter = area_intersect_area_get(r, elem) + + if inter.x > r.x then + table.insert(newareas, { + x = r.x, + y = r.y, + width = inter.x - r.x, + height = r.height + }) + end + + if inter.y > r.y then + table.insert(newareas, { + x = r.x, + y = r.y, + width = r.width, + height = inter.y - r.y + }) + end + + if inter.x + inter.width < r.x + r.width then + table.insert(newareas, { + x = inter.x + inter.width, + y = r.y, + width = (r.x + r.width) - (inter.x + inter.width), + height = r.height + }) + end + + if inter.y + inter.height < r.y + r.height then + table.insert(newareas, { + x = r.x, + y = inter.y + inter.height, + width = r.width, + height = (r.y + r.height) - (inter.y + inter.height) + }) + end + end + end + + return newareas +end + +--- Place the client without it being outside the screen. +-- @param c The client. +function placement.no_offscreen(c) + local geometry = c:fullcoords() + local screen_geometry = capi.screen[c.screen].workarea + + if geometry.x + geometry.width > screen_geometry.x + screen_geometry.width then + geometry.x = screen_geometry.x + screen_geometry.width - geometry.width + elseif geometry.x < screen_geometry.x then + geometry.x = screen_geometry.x + end + + if geometry.y + geometry.height > screen_geometry.y + screen_geometry.height then + geometry.y = screen_geometry.y + screen_geometry.height - geometry.height + elseif geometry.y < screen_geometry.y then + geometry.y = screen_geometry.y + end + + c:fullcoords(geometry) +end + +--- Place the client where there's place available with minimum overlap. +-- @param c The client. +function placement.no_overlap(c) + local cls = capi.client.visible_get(c.screen) + local layout = layout.get() + local areas = { capi.screen[c.screen].workarea } + local coords = c:coords() + local fullcoords = c:fullcoords() + for i, cl in pairs(cls) do + if cl ~= c and (cl.floating or layout == "floating") then + areas = area_remove(areas, cl:fullcoords()) + end + end + + -- Look for available space + local found = false + local new = { x = coords.x, y = coords.y, width = 0, height = 0 } + for i, r in ipairs(areas) do + if r.width >= fullcoords.width + and r.height >= fullcoords.height + and r.width * r.height > new.width * new.height then + found = true + new = r + end + end + + -- We did not foudn an area with enough space for our size: + -- just take the biggest available one and go in + if not found then + for i, r in ipairs(areas) do + if r.width * r.height > new.width * new.height then + new = r + end + end + end + + -- Restore height and width + new.width = coords.width + new.height = coords.height + + c:coords(new) +end + --- Place the client under the mouse. -- @param c The client. function placement.under_mouse(c)