diff --git a/settings/hyprland.nix b/settings/hyprland.nix index 6a93dc4..0857ddb 100644 --- a/settings/hyprland.nix +++ b/settings/hyprland.nix @@ -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 diff --git a/settings/quickshell.nix b/settings/quickshell.nix index 29dbea4..0e80bee 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -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