diff --git a/lib/awful/placement.lua b/lib/awful/placement.lua index 96abc0562..47ee330e2 100644 --- a/lib/awful/placement.lua +++ b/lib/awful/placement.lua @@ -262,16 +262,19 @@ local resize_to_point_map = { } -- Outer position matrix --- 1=best case, 2=fallback local outer_positions = { - left1 = function(r, w, _) return {x=r.x-w , y=r.y }, "down" end, - left2 = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "up" end, - right1 = function(r, _, _) return {x=r.x , y=r.y }, "down" end, - right2 = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "up" end, - top1 = function(r, _, h) return {x=r.x , y=r.y-h }, "right" end, - top2 = function(r, w, h) return {x=r.x-w+r.width, y=r.y-h }, "left" end, - bottom1 = function(r, _, _) return {x=r.x , y=r.y }, "right" end, - bottom2 = function(r, w, _) return {x=r.x-w+r.width, y=r.y }, "left" end, + left_front = function(r, w, _) return {x=r.x-w , y=r.y }, "front" end, + left_back = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "back" end, + left_middle = function(r, w, h) return {x=r.x-w , y=r.y-h/2+r.height/2 }, "middle" end, + right_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end, + right_back = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "back" end, + right_middle = function(r, _, h) return {x=r.x , y=r.y-h/2+r.height/2 }, "middle" end, + top_front = function(r, _, h) return {x=r.x , y=r.y-h }, "front" end, + top_back = function(r, w, h) return {x=r.x-w+r.width , y=r.y-h }, "back" end, + top_middle = function(r, w, h) return {x=r.x-w/2+r.width/2, y=r.y-h }, "middle" end, + bottom_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end, + bottom_back = function(r, w, _) return {x=r.x-w+r.width , y=r.y }, "back" end, + bottom_middle = function(r, w, _) return {x=r.x-w/2+r.width/2, y=r.y }, "middle" end, } --- Add a context to the arguments. @@ -1353,28 +1356,55 @@ end --- Move a drawable to a relative position next to another one. -- +-- This placement function offers two additional settings to align the drawable +-- alongside the parent geometry. The first one, the position, sets the side +-- relative to the parent. The second one, the anchor, set the alignment within +-- the side selected by the `preferred_positions`. Both settings are tables of +-- priorities. The first available slot will be used. If there isn't enough +-- space, then it will fallback to the next until it is possible to fit the +-- drawable. This is meant to avoid going offscreen. +-- -- The `args.preferred_positions` look like this: -- -- {"top", "right", "left", "bottom"} -- +-- The `args.preferred_anchors` are: +-- +-- * "front": The closest to the origin (0,0) +-- * "middle": Centered aligned with the parent +-- * "back": The opposite side compared to `front` +-- -- In that case, if there is room on the top of the geometry, then it will have -- priority, followed by all the others, in order. -- -- @tparam drawable d A wibox or client -- @tparam table args -- @tparam string args.mode The mode --- @tparam string args.preferred_positions The preferred positions (in order) +-- @tparam string|table args.preferred_positions The preferred positions (in order) +-- @tparam string|table args.preferred_anchors The preferred anchor(s) (in order) -- @tparam string args.geometry A geometry inside the other drawable -- @treturn table The new geometry --- @treturn string The choosen position --- @treturn string The choosen direction +-- @treturn string The choosen position ("left", "right", "top" or "bottom") +-- @treturn string The choosen anchor ("front", "middle" or "back") function placement.next_to(d, args) args = add_context(args, "next_to") d = d or capi.client.focus - local preferred_positions = {} + local original_pos, original_anchors = args.preferred_positions, args.preferred_anchors - for k, v in ipairs(args.preferred_positions or {}) do + if type(original_pos) == "string" then + original_pos = {original_pos} + end + + if type(original_anchors) == "string" then + original_anchors = {original_anchors} + end + + local preferred_positions = {} + local preferred_anchors = #(original_anchors or {}) > 0 and + original_anchors or {"front", "back", "middle"} + + for k, v in ipairs(original_pos or {}) do preferred_positions[v] = k end @@ -1406,15 +1436,14 @@ function placement.next_to(d, args) -- and order them by preferred_positions local does_fit = {} for k,v in pairs(regions) do - local geo, dir = outer_positions[k.."1"](v, dgeo.width, dgeo.height) - geo.width, geo.height = dgeo.width, dgeo.height - local fit = fit_in_bounding(v.screen, geo, args) + local geo, dir, fit - -- Try the other compatible geometry - if not fit then - geo, dir = outer_positions[k.."2"](v, dgeo.width, dgeo.height) + -- Try each anchor until one that fits is found + for _, anchor in ipairs(preferred_anchors) do + geo, dir = outer_positions[k.."_"..anchor](v, dgeo.width, dgeo.height) geo.width, geo.height = dgeo.width, dgeo.height fit = fit_in_bounding(v.screen, geo, args) + if fit then break end end does_fit[k] = fit and {geo, dir} or nil