hyprland: click away from a scratchpad to dismiss it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-08-17 09:53:29 +01:00
parent d4b76f2b13
commit a1deb77a04
2 changed files with 37 additions and 5 deletions

View file

@ -187,6 +187,11 @@ 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;
@ -306,6 +311,19 @@ 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)
-- Startup
hl.on("hyprland.start", function()
-- Ensure hyprland-session.target starts even if HM's

View file

@ -2265,11 +2265,18 @@ in
? Qt.vector4d(surfLeftX + chrome.width / 2, (panelTop + panelBottom) / 2,
meltInto / 2 + chrome.width / 2, (panelBottom - panelTop) / 2)
: Qt.vector4d(0, 0, 0, 0)
// Toast sits under the top frame band and melts up into it.
readonly property real toastBot: toastItem.y + 8 + _toastRect.height
// Toast melts into whichever frame band it lands against
// same snap test the panel uses, since the toast now
// follows the clock instead of sitting at the top.
readonly property real toastRawTop: toastItem.y + 8
readonly property real toastRawBot: toastRawTop + _toastRect.height
readonly property real toastTop: toastRawTop <= Theme.frameWidth + snapDist
? meltTop : toastRawTop
readonly property real toastBot: toastRawBot >= bar.height - Theme.frameWidth - snapDist
? meltBot : toastRawBot
property vector4d toast: toastItem.visible && _toastRect.width > 0.5
? Qt.vector4d(surfLeftX + _toastRect.width / 2, (meltTop + toastBot) / 2,
meltInto / 2 + _toastRect.width / 2, (toastBot - meltTop) / 2)
? Qt.vector4d(surfLeftX + _toastRect.width / 2, (toastTop + toastBot) / 2,
meltInto / 2 + _toastRect.width / 2, (toastBot - toastTop) / 2)
: Qt.vector4d(0, 0, 0, 0)
// The launcher is the one surface that stays put: it still
// grows from the bottom frame band at screen centre.
@ -7137,7 +7144,14 @@ in
readonly property bool isPrimary: bar.screen === Quickshell.screens[0]
x: Theme.barWidth
y: Theme.frameWidth + 8
// Hangs off the clock, exactly like the calendar popup
// (same clamp as BarDropdown). Move the clock in the bar
// column and both the popup and the toast follow it.
y: {
const c = clockText.mapToItem(bar.contentItem, 0, clockText.height / 2).y;
return Math.round(Math.max(Theme.frameWidth,
Math.min(bar.height - Theme.frameWidth - height, c - height / 2)));
}
width: _toastRect.width + 4
height: _toastRect.height + 16