hyprland: focus scratchpads on toggle without warping the cursor

Replaces the warp_on_toggle_special + click-away approach, which dragged
the pointer around on open and close.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-08-17 11:55:30 +01:00
parent a1deb77a04
commit 4f89af16db

View file

@ -187,11 +187,6 @@ in
follow_mouse = 1;
accel_profile = "flat";
sensitivity = 0;
# An open special workspace otherwise swallows focus for the
# regular workspace underneath. Both scratchpads hold exactly one
# floating window, which is the case this unblocks — and the
# click-away handler below needs that focus change to fire.
special_fallthrough = true;
} // lib.optionalAttrs isMacbook {
touchpad = {
tap_to_click = true;
@ -207,11 +202,6 @@ in
cursor = {
no_warps = true;
# Scratchpads are floated at 80% inset, so opening one leaves the
# cursor over the window underneath and follow_mouse=1 hands focus
# straight back to it. Warp onto the special workspace's window
# instead. 2, not 1: 1 obeys no_warps above and would no-op.
warp_on_toggle_special = 2;
# Force real HW cursor plane (default "auto" can fall back to a
# software cursor on i915 → cursor waits a full repaint = laggy).
no_hardware_cursors = false;
@ -311,18 +301,20 @@ in
if cmd and not shutting_down then hl.exec_cmd(cmd) end
end)
-- Click-away dismiss: focus landing on anything outside the open
-- special workspace slides it back out, so a scratchpad never has
-- to be toggled off by hand. Generic on purpose any special
-- workspace, not just these two.
hl.on("window.active", function(win)
local special = hl.get_active_special_workspace()
if not special then return end
if win and win.workspace and win.workspace.special then return end
-- Workspace name is "special:scratch"; toggle_special wants the
-- bare "scratch" (and "" for the unnamed "special" workspace).
hl.dispatch(hl.dsp.workspace.toggle_special(special.name:match("^special:(.*)$") or ""))
end)
-- Toggling a special workspace leaves keyboard focus wherever the
-- cursor already was, so a scratchpad opened over another window
-- came up unfocused. Focus its window explicitly on the way in.
-- Deliberately not cursor:warp_on_toggle_special that yanks the
-- pointer to the window on open and back again on close.
local function toggle_scratchpad(name, class)
return function()
hl.dispatch(hl.dsp.workspace.toggle_special(name))
-- Only on the opening half of the toggle.
if hl.get_active_special_workspace() then
hl.dispatch(hl.dsp.focus({ window = "class<" .. class .. ">" }))
end
end
end
-- Startup
hl.on("hyprland.start", function()
@ -479,8 +471,8 @@ in
hl.bind(mod .. " + F", hl.dsp.window.fullscreen())
hl.bind(mod .. " + P", hl.dsp.window.pseudo())
hl.bind(mod .. " + S", hl.dsp.layout("togglesplit"))
hl.bind(mod .. " + M", hl.dsp.workspace.toggle_special("music"))
hl.bind(mod .. " + Return", hl.dsp.workspace.toggle_special("scratch"))
hl.bind(mod .. " + M", toggle_scratchpad("music", "dev.fred.spotify"))
hl.bind(mod .. " + Return", toggle_scratchpad("scratch", "dev.fred.scratchpad"))
-- Focus
hl.bind(mod .. " + left", hl.dsp.focus({ direction = "left" }))