hyprland: match scratchpads by dedicated ghostty class, not title

This commit is contained in:
rope 2026-08-16 19:18:32 +01:00
parent e5566fc412
commit f82a6430ea

View file

@ -263,17 +263,25 @@ in
hl.layer_rule({ match = { namespace = "quickshell-bar" }, blur = true, ignore_alpha = 0.3 })
hl.layer_rule({ match = { namespace = "quickshell-osd" }, blur = true, ignore_alpha = 0.3 })
-- Scratchpad respawn: both special-workspace terminals are meant to
-- exist for the whole session, so SUPER+Q on them reads as "reset
-- this thing", not "close it". Relaunch on close.
-- Both special-workspace terminals get their own --class, which does
-- two things ghostty's --title cannot. First, gtk-single-instance
-- means a second `ghostty` hands its request to the running instance
-- and exits; forwarded requests keep -e but DROP --title, so the
-- window ends up named by the shell and no title rule matches it.
-- A distinct class forces a separate instance. Second, the class is
-- fixed at surface creation, so the shell's own title escapes can't
-- desync the window rules or the respawn below.
--
-- Respawn: these are meant to exist for the whole session, so SUPER+Q
-- on them reads as "reset this thing", not "close it".
local scratchpads = {
["scratchpad"] = "ghostty --title=scratchpad",
["spotify-player"] = "ghostty --title=spotify-player -e spotify_player",
["dev.fred.scratchpad"] = "ghostty --class=dev.fred.scratchpad --title=scratchpad",
["dev.fred.spotify"] = "ghostty --class=dev.fred.spotify --title=spotify-player -e spotify_player",
}
local shutting_down = false
hl.on("hyprland.shutdown", function() shutting_down = true end)
hl.on("window.close", function(win)
local cmd = scratchpads[win.title]
local cmd = scratchpads[win.class]
if cmd and not shutting_down then hl.exec_cmd(cmd) end
end)
@ -295,11 +303,11 @@ in
-- Warms spotify-player's Spotify Connect device while you're
-- doing something else; the window rule above swallows it onto
-- special:music silently, so it never steals focus.
hl.exec_cmd("ghostty --title=spotify-player -e spotify_player")
hl.exec_cmd(scratchpads["dev.fred.spotify"])
-- Scratchpad terminal, same trick: parked on special:scratch at
-- login so SUPER+Return is always an instant toggle and the shell
-- keeps its history/cwd between peeks.
hl.exec_cmd("ghostty --title=scratchpad")
hl.exec_cmd(scratchpads["dev.fred.scratchpad"])
-- swayosd removed; volume/brightness OSD handled by quickshell
${lib.optionalString isMacbook ''hl.exec_cmd("hypridle")''}
end)
@ -343,38 +351,38 @@ in
-- Spotify's backend, and that cost is per *process*, so relaunching
-- a terminal for it means waiting every time. Parking one instance
-- here pays it once at login; SUPER+M slides it in and out.
-- Matched on title, not class: gtk-single-instance means every
-- ghostty window is the same app-id, and --title is authoritative
-- (ghostty ignores the program's own title escapes once it is set).
-- Matched on the dedicated --class set above, not on title: a shell
-- prompt rewrites its window title, and forwarded single-instance
-- launches never carry --title in the first place.
hl.window_rule({
match = { title = "^spotify-player$" },
match = { class = "^dev.fred.spotify$" },
workspace = "special:music silent",
})
-- Inset it rather than filling the screen, so the workspace
-- underneath still frames it. Floating is what makes a percentage
-- size stick: a tiled window is sized by the layout, which would
-- just expand it back to the full area. Matched on title for the
-- just expand it back to the full area. Matched on class for the
-- same reason as above, and because matching on the special
-- workspace would depend on the assignment rule running first.
hl.window_rule({
name = "spotify-player-inset",
match = { title = "^spotify-player$" },
match = { class = "^dev.fred.spotify$" },
float = true,
size = "80% 80%",
center = true,
})
-- Scratchpad terminal same title-match + float-to-inset pattern as
-- Scratchpad terminal same class-match + float-to-inset pattern as
-- spotify-player above.
hl.window_rule({
match = { title = "^scratchpad$" },
match = { class = "^dev.fred.scratchpad$" },
workspace = "special:scratch silent",
})
hl.window_rule({
name = "scratchpad-inset",
match = { title = "^scratchpad$" },
match = { class = "^dev.fred.scratchpad$" },
float = true,
size = "80% 80%",
center = true,