Settings window is no longer a popover.

This commit is contained in:
2025-05-31 19:14:33 -07:00
parent 727c1ceb09
commit 43e58d8af3
4 changed files with 55 additions and 25 deletions

View File

@@ -6,9 +6,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
let fileManager = FileManager.default let fileManager = FileManager.default
let window = PopoverPanel(viewController: SearchViewController()) let window = PopoverPanel(viewController: SearchViewController())
let settingsWindow =
MenulessWindow(viewController: SettingsViewController())
let aboutWindow = MenulessWindow(viewController: AboutViewController()) let aboutWindow = MenulessWindow(viewController: AboutViewController())
func applicationDidFinishLaunching(_ notification: Notification) { func applicationDidFinishLaunching(_ notification: Notification) {
settingsWindow.title = "Settings"
aboutWindow.level = .statusBar aboutWindow.level = .statusBar
PathManager.shared.updateIndex() PathManager.shared.updateIndex()
@@ -16,8 +19,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
window.delegate = self window.delegate = self
// NOTE: Here we check wether the program was launched by the // NOTE: Here we check wether the program was launched by the
// system (e.g. launch-at-login). If it was not, then display // system (e.g. launch-at-login). If it was not, then display the
// the window. // window.
if let event = NSAppleEventManager.shared().currentAppleEvent, if let event = NSAppleEventManager.shared().currentAppleEvent,
!(event.eventID == kAEOpenApplication && !(event.eventID == kAEOpenApplication &&
event.paramDescriptor(forKeyword: keyAEPropData)? event.paramDescriptor(forKeyword: keyAEPropData)?
@@ -70,8 +73,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
func applicationShouldHandleReopen(_ sender: NSApplication, func applicationShouldHandleReopen(_ sender: NSApplication,
hasVisibleWindows: Bool) -> Bool { hasVisibleWindows: Bool) -> Bool {
if !window.isKeyWindow { if !window.isKeyWindow {
if !settingsWindow.isVisible {
window.makeKeyAndOrderFront(nil) window.makeKeyAndOrderFront(nil)
} }
}
return true return true
} }
@@ -99,8 +104,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
aboutWindow.makeKeyAndOrderFront(nil) aboutWindow.makeKeyAndOrderFront(nil)
} }
// NOTE: This function act like a callback is triggered by DirMonitor public func showSettingsWindow() {
// when file system events occur. settingsWindow.makeKeyAndOrderFront(nil)
}
// NOTE: This function act like a callback and is triggered by
// DirMonitor when file system events occur.
public func fsEventTriggered(_ path: String, _ flags: Int) { public func fsEventTriggered(_ path: String, _ flags: Int) {
if containsFlags(key: kFSEventStreamEventFlagItemCreated, in: flags) || if containsFlags(key: kFSEventStreamEventFlagItemCreated, in: flags) ||
containsFlags(key: kFSEventStreamEventFlagItemRemoved, in: flags) || containsFlags(key: kFSEventStreamEventFlagItemRemoved, in: flags) ||

View File

@@ -13,8 +13,8 @@ final class PathManager {
private var dirMonitor: DirMonitor? private var dirMonitor: DirMonitor?
// NOTE: These are default paths where MacOS's default programs are // NOTE: These are default paths where MacOS's default programs are
// stored. This list should be updated if something changes in // stored. This list should be updated if something changes in newer
// newer MacOS version. // MacOS versions.
static let defaultPaths = [ static let defaultPaths = [
"/Applications", "/Applications",
"/System/Applications", "/System/Applications",
@@ -102,8 +102,8 @@ final class PathManager {
} }
// PERF: Optimize some more. Do not rebuild the entire array, instead // PERF: Optimize some more. Do not rebuild the entire array, instead
// remove or add only needed programs. Thereby, limiting the // remove or add only needed programs. Thereby, limiting the amount of
// amount of allocations. // allocations.
public func rebuildIndex(at path: String) { public func rebuildIndex(at path: String) {
paths[path] = [] paths[path] = []
paths[path] = indexDirs(at: path, deepness: 2) paths[path] = indexDirs(at: path, deepness: 2)
@@ -141,7 +141,7 @@ final class PathManager {
refreshFilesystemWatchers() refreshFilesystemWatchers()
} }
// Touch paths to load them into CPUs cache. // Touch paths to load them into CPU's cache for performance.
public func touchPaths() { public func touchPaths() {
for path in paths { for path in paths {
_ = path _ = path

View File

@@ -9,8 +9,7 @@ fileprivate let windowCornerRadius = 15.0
fileprivate let maxItems = 20 fileprivate let maxItems = 20
class SearchViewController: NSViewController, NSTextFieldDelegate, class SearchViewController: NSViewController, NSTextFieldDelegate,
NSPopoverDelegate, NSTableViewDataSource, NSTableViewDataSource, NSTableViewDelegate
NSTableViewDelegate
{ {
private var keyboardEvents: EventMonitor? private var keyboardEvents: EventMonitor?
@@ -20,13 +19,6 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
private var programsTableViewSelection = 0 private var programsTableViewSelection = 0
private var settingsPopover: NSPopover = {
let popover = NSPopover()
popover.contentViewController = SettingsViewController()
popover.behavior = .transient
return popover
}()
private var shadowView: ShadowView = { private var shadowView: ShadowView = {
let view = ShadowView() let view = ShadowView()
view.translatesAutoresizingMaskIntoConstraints = false view.translatesAutoresizingMaskIntoConstraints = false
@@ -301,7 +293,6 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
return event return event
} }
settingsPopover.delegate = self
searchInput.delegate = self searchInput.delegate = self
tableScrollView.documentView = programsTableView tableScrollView.documentView = programsTableView
@@ -364,8 +355,7 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
@objc @objc
func openSettings() { func openSettings() {
settingsPopover.show(relativeTo: settingsButton.bounds, delegate.showSettingsWindow()
of: settingsButton, preferredEdge: .maxY)
} }
@objc @objc

View File

@@ -2,11 +2,15 @@ import AppKit
import Carbon import Carbon
import ServiceManagement import ServiceManagement
// TODO: Rework the paths table and selection. Right now, it is very
// disfunctional and error-prone.
class SettingsViewController: NSViewController, class SettingsViewController: NSViewController,
NSTextFieldDelegate, KeyDetectorButtonDelegate, NSTextFieldDelegate, KeyDetectorButtonDelegate,
NSTableViewDataSource, NSTableViewDelegate, NSTableViewDataSource, NSTableViewDelegate,
PathsTableCellViewDelegate PathsTableCellViewDelegate
{ {
private var keyboardEvents: EventMonitor?
private var recording = false private var recording = false
// NOTE: This is the default shortcut. If you were to change it, don't // NOTE: This is the default shortcut. If you were to change it, don't
@@ -346,6 +350,20 @@ class SettingsViewController: NSViewController,
launchAtLoginToggle.target = self launchAtLoginToggle.target = self
launchAtLoginToggle.action = #selector(affectLaunchAtLogin(_:)) launchAtLoginToggle.action = #selector(affectLaunchAtLogin(_:))
keyboardEvents = LocalEventMonitor(mask: [.keyDown])
{ [weak self] event in
let key = event.keyCode
let modifiers = event.modifierFlags.rawValue
if modsContains(keys: OSCmd, in: modifiers) &&
key == kVK_ANSI_Q || modsContainsNone(in: modifiers)
{
NSApplication.shared.terminate(self)
}
return event
}
addSubviews() addSubviews()
setConstraints() setConstraints()
} }
@@ -372,11 +390,18 @@ class SettingsViewController: NSViewController,
override func viewDidAppear() { override func viewDidAppear() {
super.viewDidAppear() super.viewDidAppear()
keyboardEvents?.start()
NSApp.setActivationPolicy(.regular)
self.view.window?.center()
} }
override func viewWillDisappear() { override func viewWillDisappear() {
super.viewWillDisappear() super.viewWillDisappear()
keyboardEvents?.stop()
HotKeyManager.shared.registerHotKey(key: keyCode, HotKeyManager.shared.registerHotKey(key: keyCode,
modifiers: modifiers) modifiers: modifiers)
@@ -399,6 +424,12 @@ class SettingsViewController: NSViewController,
PathManager.shared.savePaths() PathManager.shared.savePaths()
} }
override func viewDidDisappear() {
super.viewDidDisappear()
NSApp.setActivationPolicy(.accessory)
}
override func loadView() { override func loadView() {
self.view = NSView() self.view = NSView()
} }
@@ -578,9 +609,9 @@ class SettingsViewController: NSViewController,
makeIfNecessary: false) as? PathsTableCellView makeIfNecessary: false) as? PathsTableCellView
{ {
if isDirectory(text) { if isDirectory(text) {
cell.titleField.textColor = NSColor.green cell.titleField.textColor = NSColor.systemGreen
} else { } else {
cell.titleField.textColor = NSColor.red cell.titleField.textColor = NSColor.systemRed
} }
} }
} }
@@ -599,7 +630,7 @@ class SettingsViewController: NSViewController,
} }
// WARN: // WARN:
// FIX: THere is a bug where the program crashes when adding a new // FIX: There is a bug where the program crashes when adding a new
// path. This happens because the settings popup is closed before // path. This happens because the settings popup is closed before
// displaying the selection modal, as a result the new path item // displaying the selection modal, as a result the new path item
// is cleared (well, b/c it's empty) and the path gets set into // is cleared (well, b/c it's empty) and the path gets set into