feat: configure a persistent global launcher shortcut
This commit is contained in:
@@ -14,6 +14,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
private var locationLabels: [URL: String] = [:]
|
||||
private var discoveryTask: Task<Void, Never>?
|
||||
private var isLaunching = false
|
||||
private var previousApplication: NSRunningApplication?
|
||||
|
||||
init(history: LaunchHistory = LaunchHistory()) {
|
||||
self.history = history
|
||||
@@ -36,6 +37,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
configureContent(in: window)
|
||||
window.delegate = self
|
||||
window.navigateSelection = { [weak self] offset in self?.moveSelection(by: offset) }
|
||||
window.dismiss = { [weak self] in self?.dismiss() }
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@@ -43,6 +45,10 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
}
|
||||
|
||||
func present() {
|
||||
let frontmost = NSWorkspace.shared.frontmostApplication
|
||||
if frontmost?.processIdentifier != ProcessInfo.processInfo.processIdentifier {
|
||||
previousApplication = frontmost
|
||||
}
|
||||
searchField.stringValue = ""
|
||||
updateResults()
|
||||
window?.deminiaturize(nil)
|
||||
@@ -54,9 +60,29 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
refreshApplications()
|
||||
}
|
||||
|
||||
func toggle() {
|
||||
guard !isLaunching, window?.attachedSheet == nil else { return }
|
||||
if window?.isVisible == true, window?.isKeyWindow == true {
|
||||
dismiss()
|
||||
} else {
|
||||
present()
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss(restoringFocus: Bool = true) {
|
||||
guard !restoringFocus || (!isLaunching && window?.attachedSheet == nil) else { return }
|
||||
let previous = previousApplication
|
||||
previousApplication = nil
|
||||
window?.orderOut(nil)
|
||||
if restoringFocus, let previous, !previous.isTerminated {
|
||||
NSApp.yieldActivation(to: previous)
|
||||
previous.activate(from: .current, options: [])
|
||||
}
|
||||
}
|
||||
|
||||
func windowDidResignKey(_ notification: Notification) {
|
||||
guard !isLaunching, window?.attachedSheet == nil else { return }
|
||||
window?.orderOut(nil)
|
||||
dismiss(restoringFocus: false)
|
||||
}
|
||||
|
||||
private func configureContent(in window: NSWindow) {
|
||||
@@ -120,7 +146,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
tableView.target = self
|
||||
tableView.doubleAction = #selector(openSelection)
|
||||
tableView.openSelection = { [weak self] in self?.openSelection() }
|
||||
tableView.dismiss = { [weak self] in self?.window?.orderOut(nil) }
|
||||
tableView.dismiss = { [weak self] in self?.dismiss() }
|
||||
tableView.editSearch = { [weak self] event in
|
||||
guard let self, let window = self.window else { return }
|
||||
window.makeFirstResponder(self.searchField)
|
||||
@@ -295,7 +321,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
case #selector(NSResponder.insertNewline(_:)):
|
||||
openSelection()
|
||||
case #selector(NSResponder.cancelOperation(_:)):
|
||||
window?.orderOut(nil)
|
||||
dismiss()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -397,7 +423,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
|
||||
do {
|
||||
try await AppLauncher.launch(application.url)
|
||||
history.recordLaunch(of: application)
|
||||
window?.orderOut(nil)
|
||||
dismiss(restoringFocus: false)
|
||||
} catch {
|
||||
let alert = NSAlert(error: error)
|
||||
alert.messageText = "Couldn’t open \(application.name)"
|
||||
@@ -445,6 +471,7 @@ private final class LauncherPanel: NSPanel {
|
||||
override var canBecomeKey: Bool { true }
|
||||
override var canBecomeMain: Bool { true }
|
||||
var navigateSelection: ((Int) -> Void)?
|
||||
var dismiss: (() -> Void)?
|
||||
|
||||
override func sendEvent(_ event: NSEvent) {
|
||||
if event.type == .keyDown, attachedSheet == nil,
|
||||
@@ -464,7 +491,7 @@ private final class LauncherPanel: NSPanel {
|
||||
}
|
||||
|
||||
override func performClose(_ sender: Any?) {
|
||||
close()
|
||||
dismiss?()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user