From ce50d53fd83c3f0cb1b0eef4d538770ea388cc07 Mon Sep 17 00:00:00 2001 From: momenbasel Date: Wed, 12 Aug 2026 09:11:58 +0300 Subject: [PATCH] Add click-outside hide preference New Behavior toggle controls whether the bar hides when it loses key focus. Defaults to on, preserving current behavior. When pinned, the panel drops from .modalPanel to .floating so it stops covering full-screen apps, and the paste target keeps tracking the frontmost app via lastActiveApp. Co-authored-by: alvst Co-authored-by: Cursor --- Sources/Pesty/Settings/Settings.swift | 7 +++++++ Sources/Pesty/Settings/SettingsView.swift | 1 + Sources/Pesty/UI/BarWindowController.swift | 8 ++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Sources/Pesty/Settings/Settings.swift b/Sources/Pesty/Settings/Settings.swift index 6b92366..8a1be6a 100644 --- a/Sources/Pesty/Settings/Settings.swift +++ b/Sources/Pesty/Settings/Settings.swift @@ -60,6 +60,7 @@ final class Settings { static let quickPasteModifier = "quickPasteModifier" static let plainTextModifier = "plainTextModifier" static let launchAtLogin = "launchAtLogin" + static let hideOnClickOutside = "hideOnClickOutside" static let pasteDirectly = "pasteDirectly" static let playSound = "playSound" static let ignoreConcealed = "ignoreConcealed" @@ -111,6 +112,10 @@ final class Settings { d.set(launchAtLogin, forKey: Keys.launchAtLogin); LaunchAtLogin.set(enabled: launchAtLogin) } } + var hideOnClickOutside: Bool { + didSet { guard isLoaded else { return }; d.set(hideOnClickOutside, forKey: Keys.hideOnClickOutside) } + } + var pasteDirectly: Bool { didSet { guard isLoaded else { return }; d.set(pasteDirectly, forKey: Keys.pasteDirectly) } } @@ -167,6 +172,7 @@ final class Settings { Keys.quickPasteModifier: cmdKey, Keys.plainTextModifier: shiftKey, Keys.launchAtLogin: false, + Keys.hideOnClickOutside: true, Keys.pasteDirectly: true, Keys.playSound: false, Keys.ignoreConcealed: true, @@ -183,6 +189,7 @@ final class Settings { quickPasteModifier = d.integer(forKey: Keys.quickPasteModifier) plainTextModifier = d.integer(forKey: Keys.plainTextModifier) launchAtLogin = d.bool(forKey: Keys.launchAtLogin) + hideOnClickOutside = d.bool(forKey: Keys.hideOnClickOutside) pasteDirectly = d.bool(forKey: Keys.pasteDirectly) playSound = d.bool(forKey: Keys.playSound) ignoreConcealed = d.bool(forKey: Keys.ignoreConcealed) diff --git a/Sources/Pesty/Settings/SettingsView.swift b/Sources/Pesty/Settings/SettingsView.swift index 03bed66..ef977b9 100644 --- a/Sources/Pesty/Settings/SettingsView.swift +++ b/Sources/Pesty/Settings/SettingsView.swift @@ -134,6 +134,7 @@ private struct GeneralSettings: View { #endif Toggle("Ignore passwords (concealed clips)", isOn: $settings.ignoreConcealed) Toggle("Play sound on paste", isOn: $settings.playSound) + Toggle("Hide Pesty when clicking outside", isOn: $settings.hideOnClickOutside) Toggle("Launch at login", isOn: $settings.launchAtLogin) Toggle("Show Pesty in the menu bar", isOn: $settings.showMenuBarIcon) VStack(alignment: .leading) { diff --git a/Sources/Pesty/UI/BarWindowController.swift b/Sources/Pesty/UI/BarWindowController.swift index b80c60d..663be06 100644 --- a/Sources/Pesty/UI/BarWindowController.swift +++ b/Sources/Pesty/UI/BarWindowController.swift @@ -143,6 +143,7 @@ final class BarWindowController: NSWindowController, NSWindowDelegate { func show() { guard let panel = window else { return } guard let screen = Self.targetScreen() else { return } + panel.level = Settings.shared.hideOnClickOutside ? .modalPanel : .floating let vf = screen.visibleFrame let height = min(CGFloat(Settings.shared.barHeight), vf.height) let onScreen = NSRect(x: vf.minX, y: vf.minY, width: vf.width, height: height) @@ -174,7 +175,8 @@ final class BarWindowController: NSWindowController, NSWindowDelegate { // The panel can lose key focus while it is still animating up, and // windowDidResignKey ignores that because the bar is not .shown yet. // Catch it here so the bar does not sit on screen unfocused forever. - if panel.isVisible, !panel.isKeyWindow, !AppController.shared.suppressAutoHide { + if Settings.shared.hideOnClickOutside, + panel.isVisible, !panel.isKeyWindow, !AppController.shared.suppressAutoHide { AppController.shared.hideBar() } } @@ -222,7 +224,9 @@ final class BarWindowController: NSWindowController, NSWindowDelegate { } func windowDidResignKey(_ notification: Notification) { - guard phase == .shown, !AppController.shared.suppressAutoHide else { return } + guard Settings.shared.hideOnClickOutside, + phase == .shown, + !AppController.shared.suppressAutoHide else { return } AppController.shared.hideBar() } }