Skip to main content

kiln.placement

kiln.placement places floating clients: each helper is a function f(c, s?) that computes a position against the screen's workarea and writes c.float in one assignment (one property::float, one re-declare). s defaults to the client's screen.

kiln.placement.centered(c)

There are no placement objects and no apply pass: helpers compose by being called in order, so "centered, then nudged on screen" is two calls, not an operator.

The box being placed is c.float if set, otherwise the client's committed size, falling back to 400x300 for a client that has not committed one yet. The area placed against is screen.workarea (what is left after bars and exclusive zones), falling back to the whole output before the first solve.

The helpers

The 11 position combinators put the box at a fixed fraction of the workarea per axis; an axis a helper does not name is left where it is.

HelperHorizontalVertical
centeredcentercenter
center_horizontalcenterunchanged
center_verticalunchangedcenter
leftleft edgecenter
rightright edgecenter
topcentertop edge
bottomcenterbottom edge
top_leftleft edgetop edge
top_rightright edgetop edge
bottom_leftleft edgebottom edge
bottom_rightright edgebottom edge

The three constraint helpers:

HelperBehavior
no_offscreenClamp the box into the workarea. A box larger than the area pins to the near edge rather than pushing its top-left off screen.
no_overlapPlace the box clear of every other visible float on the screen: try the workarea origin, then the right and bottom edge of each occupied float, and take the first spot that fits inside the workarea and overlaps nothing (touching edges do not count as overlap). With no free slot it degrades to no_offscreen.
under_mouseCenter the box on the pointer's last known position, then apply no_offscreen. Before any pointer motion exists (a launcher summoned by key, say) it falls back to centered.

All three return the client, like the combinators, and compose the same way:

kiln.placement.under_mouse(c)      -- already includes no_offscreen
kiln.placement.top_right(c)
kiln.placement.no_overlap(c) -- find a clear slot instead

In a rule

A rule's on(c) callback takes a placement helper directly, since a helper is already a function(c):

kiln.rule { match_any = { app = { "pinentry" } },
props = { floating = true },
on = kiln.placement.centered }

kiln.rule { match = { app = "mpv" },
props = { floating = true },
on = function(c)
kiln.placement.bottom_right(c)
kiln.placement.no_offscreen(c)
end }
note

Rules fire at map, before the client has committed a size, so a placement at rule time places the box the client asked for (or the fallback), not the size it may end up drawing at. And screen.workarea reflects the last layout solve: inside a screen's own declare it is authoritative, but calling a helper from a keybinding on a multi-monitor setup can read a screen that did not solve last, which falls back to the whole output and loses the bar inset.

See also