diff --git a/README.md b/README.md index 01f671e..cf47f01 100644 --- a/README.md +++ b/README.md @@ -68,14 +68,29 @@ Use `local layout = machi.layout.create(args)` to instantiate the layout with an - `persistent`: whether to keep a history of the command for the layout. The default is `true`. - `default_cmd`: the command to use if there is no persistent history for this layout. - `editor`: the editor used for the layout. The default is `machi.default_editor` (or `machi.editor.default_editor`). - - `new_placement_cb`: a callback `function(c, instance, areas)` that fits new client `c` into the areas. + - `new_placement_cb`: a callback `function(c, instance, areas, geometry)` that fits new client `c` into the areas. Returns whether the new client is in draft mode. This is a new and experimental feature. - XXX have a subsection for this. Either `name` or `name_func` must be set - others are optional. The function is compatible with the previous `machi.layout.create(name, editor, default_cmd)` calls. +For `new_placement_cb` the arguments are: + - `c`: the new client to be placed. + - `instance`: a layout and tag depedent table with the following fields available: + - `cmd`: the current layout command. + - `client_data`: a mapping from previously managed clients to their layout related settings and assigned areas. + Drafting windows are located using `.lu` and `.rd` fields, otherwise located uisng `.area` field; Drafting override is in `.draft` field. + Note that it may contains some clients that are no longer in the layout. You can filter using `screen.tiled_clients`. + - `tag_data`: a mapping from area ids to their fake tag data. This is for nested layouts. + - `areas`: the current array of areas produced by `instance.cmd`. Each area is a table with the following fields available: + - `id`: self index of the array. + - `x`, `y`, `width`, `height`: area geometry. + - `layout`: the string used to index the nested layout, if any. + - `geometry`: the output geometry of the client. + +The callback places the new client by changing its geometry, and returns its draft perference for further area fitting. + ## The layout editor and commands ### Starting editor in lua diff --git a/layout.lua b/layout.lua index 672f700..6b2e2a6 100644 --- a/layout.lua +++ b/layout.lua @@ -219,11 +219,21 @@ function module.create(args_or_name, editor, default_cmd) end end + -- Make new clients appear in the end. + local j = 0 + for i = 1, #cls do + if cd[cls[i]] ~= nil then + j = j + 1 + cls[j], cls[i] = cls[i], cls[j] + end + end + for i, c in ipairs(cls) do if c.floating or c.immobilized then log(DEBUG, "Ignore client " .. tostring(c)) else cd[c] = cd[c] or {} + p.geometries[c] = {} local in_draft = cd[c].draft if cd[c].draft ~= nil then @@ -233,21 +243,26 @@ function module.create(args_or_name, editor, default_cmd) elseif cd[c].area then in_draft = false elseif new_placement_cb then - in_draft = new_placement_cb(c, instance, areas) + in_draft = new_placement_cb(c, instance, areas, p.geometries[c]) else in_draft = nil end + local skip = false + local cx = p.geometries[c].x or c.x + local cy = p.geometries[c].y or c.y + local cw = p.geometries[c].w or c.width + local ch = p.geometries[c].h or c.height if in_draft ~= false then if cd[c].lu ~= nil and cd[c].rd ~= nil and cd[c].lu <= #areas and cd[c].rd <= #areas and not areas[cd[c].lu].inhabitable and not areas[cd[c].rd].inhabitable then - if areas[cd[c].lu].x == c.x and - areas[cd[c].lu].y == c.y and - areas[cd[c].rd].x + areas[cd[c].rd].width - c.border_width * 2 == c.x + c.width and - areas[cd[c].rd].y + areas[cd[c].rd].height - c.border_width * 2 == c.y + c.height + if areas[cd[c].lu].x == cx and + areas[cd[c].lu].y == cy and + areas[cd[c].rd].x + areas[cd[c].rd].width - c.border_width * 2 == cx + cw and + areas[cd[c].rd].y + areas[cd[c].rd].height - c.border_width * 2 == cy + ch then skip = true end @@ -259,14 +274,13 @@ function module.create(args_or_name, editor, default_cmd) log(DEBUG, "Compute areas for " .. (c.name or (""))) lu = find_lu(c, areas) if lu ~= nil then - c.x = areas[lu].x - c.y = areas[lu].y + cx = areas[lu].x + cy = areas[lu].y rd = find_rd(c, areas, lu) end end if lu ~= nil and rd ~= nil then - p.geometries[c] = {} if lu == rd and cd[c].lu == nil then cd[c].area = lu place_client_in_area(c, lu) @@ -282,16 +296,15 @@ function module.create(args_or_name, editor, default_cmd) cd[c].area < #areas and not areas[cd[c].area].inhabitable and areas[cd[c].area].layout == nil and - areas[cd[c].area].x == c.x and - areas[cd[c].area].y == c.y and - areas[cd[c].area].width - c.border_width * 2 == c.width and - areas[cd[c].area].height - c.border_width * 2 == c.height + areas[cd[c].area].x == cx and + areas[cd[c].area].y == cy and + areas[cd[c].area].width - c.border_width * 2 == cw and + areas[cd[c].area].height - c.border_width * 2 == ch then else log(DEBUG, "Compute areas for " .. (c.name or (""))) local area = find_area(c, areas) cd[c].area, cd[c].lu, cd[c].rd = area, nil, nil - p.geometries[c] = {} place_client_in_area(c, area) end end