Count only tiled windows and refit when apps move or float
A floating window on the console is not laid out by the gaps, so it no longer stretches the panel to full width. Moving an app onto or off the scratchpad and toggling floating now refit too, via window.move_to_workspace and window.update_rules; both were measured on Hyprland 0.56.2 to carry the settled count. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UyVoFTM98Tduoxg7qZax7
This commit is contained in:
1 parent
a59afb9659
commit
d377569edb
2 files changed
+68
-13
No files matched your search
@@ -63,10 +63,17 @@ local function cover(side, bottom)
|
||||
end
|
||||
|
||||
-- One window reads as a console and gets the panel. A second app has turned the
|
||||
-- scratchpad into a workspace, and a workspace wants the whole width.
|
||||
-- scratchpad into a workspace, and a workspace wants the whole width. Only tiled
|
||||
-- windows count: the gaps are what size the panel, and a floating window on top
|
||||
-- of the console is not laid out by them.
|
||||
local function alone()
|
||||
local ws = hl.get_workspace(SCRATCHPAD)
|
||||
return not ws or ws.windows <= 1
|
||||
local tiled = 0
|
||||
for _, window in ipairs(hl.get_workspace_windows(SCRATCHPAD)) do
|
||||
if not window.floating then
|
||||
tiled = tiled + 1
|
||||
end
|
||||
end
|
||||
return tiled <= 1
|
||||
end
|
||||
|
||||
-- Sizing the console with a window rule would freeze it at whatever the screen
|
||||
@@ -158,11 +165,14 @@ hl.on("workspace.move_to_monitor", function(ws, mon)
|
||||
end
|
||||
end)
|
||||
|
||||
-- The panel is only centered while the console holds one window, so the count
|
||||
-- has to be rechecked as apps come and go. These are the two events that run
|
||||
-- after the workspace's count has already moved: window.close and
|
||||
-- window.move_to_workspace still count the window on its way out, and refitting
|
||||
-- from those would read one too many and leave the console full width.
|
||||
-- The panel is only centered while the console holds one tiled window, so the
|
||||
-- count has to be rechecked as apps come and go: opened and closed, moved on or
|
||||
-- off (Super+Alt+S, Super+Shift+1), and floated or tiled (Super+T, Super+O).
|
||||
-- window.close is left out, since it still counts the window on its way out and
|
||||
-- window.destroy follows it anyway. Measured on Hyprland 0.56.2, a move is
|
||||
-- trailed by several window.update_rules, as is a float toggle, and the last of
|
||||
-- those always reads the settled count; the earlier ones refit to what the rule
|
||||
-- already is, which cover() skips.
|
||||
--
|
||||
-- Only while it is on screen, though. A hidden console is refitted on its way in
|
||||
-- by workspace.special_active, and every window opened anywhere on the desktop
|
||||
@@ -176,6 +186,8 @@ end
|
||||
|
||||
hl.on("window.open", recount)
|
||||
hl.on("window.destroy", recount)
|
||||
hl.on("window.move_to_workspace", recount)
|
||||
hl.on("window.update_rules", recount)
|
||||
|
||||
-- The direction names the edge the offset is measured from, not where the
|
||||
-- workspace goes: "slide top" drops it down into view, and "slide bottom"
|
||||
|
||||
@@ -22,6 +22,14 @@ hl = {
|
||||
on = function(event, callback) handlers[event] = callback end,
|
||||
get_active_monitor = function() return monitor end,
|
||||
get_workspace = function() return workspace end,
|
||||
-- workspace.windows is the tiled count here and workspace.floats the floating
|
||||
-- one, so the fixtures can say which kind of window is on the console.
|
||||
get_workspace_windows = function()
|
||||
local list = {}
|
||||
for _ = 1, workspace and workspace.windows or 0 do table.insert(list, { floating = false }) end
|
||||
for _ = 1, workspace and workspace.floats or 0 do table.insert(list, { floating = true }) end
|
||||
return list
|
||||
end,
|
||||
exec_scheduled_prop_refresh_immediately = function() end,
|
||||
}
|
||||
|
||||
@@ -226,11 +234,46 @@ handlers["monitor.layout_changed"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 420 and right == 420 and bottom == 540, "a scratchpad that does not exist yet is sized as a console")
|
||||
|
||||
-- window.close and window.move_to_workspace both run while the workspace still
|
||||
-- counts the window that is leaving, so a refit from either reads one too many
|
||||
-- and strands the console at full width. window.open and window.destroy are the
|
||||
-- two that run after the count has already moved, and are the only ones hooked.
|
||||
-- Back to a console on screen for the move and float checks.
|
||||
workspace = { name = "special:scratchpad", visible = true, monitor = acer, windows = 1 }
|
||||
monitor = acer
|
||||
handlers["monitor.layout_changed"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 435 and right == 435, "a single tiled window is a console")
|
||||
|
||||
-- A floating window on top of the console is not laid out by the gaps, so it
|
||||
-- must not stretch the panel out from under the agent.
|
||||
workspace.floats = 1
|
||||
handlers["window.open"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 435 and right == 435, "a floating window on the console keeps the panel")
|
||||
|
||||
-- Tiling that float (Super+T) makes it a second app, and floating it again
|
||||
-- gives the panel back. Both arrive as window.update_rules.
|
||||
workspace.floats, workspace.windows = 0, 2
|
||||
handlers["window.update_rules"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 0 and right == 0, "tiling a float on the console restores the full width")
|
||||
|
||||
workspace.floats, workspace.windows = 1, 1
|
||||
handlers["window.update_rules"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 435 and right == 435, "floating it again recenters the panel")
|
||||
|
||||
-- Sending an app onto the scratchpad (Super+Alt+S) or off it (Super+Shift+1)
|
||||
-- does not open or destroy anything, so the move itself has to refit.
|
||||
workspace.floats, workspace.windows = 0, 2
|
||||
handlers["window.move_to_workspace"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 0 and right == 0, "moving a second app onto the console restores the full width")
|
||||
|
||||
workspace.windows = 1
|
||||
handlers["window.move_to_workspace"]()
|
||||
top, right, bottom, left = gaps()
|
||||
assert(left == 435 and right == 435, "moving it back off recenters the panel")
|
||||
|
||||
-- window.close still counts the window on its way out, and window.destroy
|
||||
-- follows it with the settled count, so only destroy is hooked.
|
||||
assert(handlers["window.close"] == nil, "window.close counts the window on its way out")
|
||||
assert(handlers["window.move_to_workspace"] == nil, "window.move_to_workspace does too")
|
||||
LUA
|
||||
pass "the console is a centered panel until a second app joins it"
|
||||
Reference in new issue
Block a user