forked from nikitabobko/AeroSpace
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGlobalObserver.swift
More file actions
74 lines (70 loc) · 3.88 KB
/
GlobalObserver.swift
File metadata and controls
74 lines (70 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import AppKit
import Common
class GlobalObserver {
private static func onNotif(_ notification: Notification) {
check(Thread.isMainThread)
// Third line of defence against lock screen window. See: closedWindowsCache
// Second and third lines of defence are technically needed only to avoid potential flickering
if (notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication)?.bundleIdentifier == lockScreenAppBundleId {
return
}
let notifName = notification.name.rawValue
MainActor.assumeIsolated {
scheduleRefreshAndLayout(.globalObserver(notifName), screenIsDefinitelyUnlocked: false)
}
}
private static func onHideApp(_ notification: Notification) {
check(Thread.isMainThread)
let notifName = notification.name.rawValue
MainActor.assumeIsolated {
refreshSession(.globalObserver(notifName), screenIsDefinitelyUnlocked: false) {
if TrayMenuModel.shared.isEnabled && config.automaticallyUnhideMacosHiddenApps {
if let w = prevFocus?.windowOrNil,
w.macAppUnsafe.nsApp.isHidden,
// "Hide others" (cmd-alt-h) -> don't force focus
// "Hide app" (cmd-h) -> force focus
MacApp.allAppsMap.values.filter({ $0.nsApp.isHidden }).count == 1
{
// Force focus
_ = w.focusWindow()
_ = w.nativeFocus()
}
for app in MacApp.allAppsMap.values {
app.nsApp.unhide()
}
}
}
}
}
@MainActor
static func initObserver() {
let nc = NSWorkspace.shared.notificationCenter
nc.addObserver(forName: NSWorkspace.didLaunchApplicationNotification, object: nil, queue: .main, using: onNotif)
nc.addObserver(forName: NSWorkspace.didActivateApplicationNotification, object: nil, queue: .main, using: onNotif)
nc.addObserver(forName: NSWorkspace.didHideApplicationNotification, object: nil, queue: .main, using: onHideApp)
nc.addObserver(forName: NSWorkspace.didUnhideApplicationNotification, object: nil, queue: .main, using: onNotif)
nc.addObserver(forName: NSWorkspace.didDeactivateApplicationNotification, object: nil, queue: .main, using: onNotif)
nc.addObserver(forName: NSWorkspace.activeSpaceDidChangeNotification, object: nil, queue: .main, using: onNotif)
nc.addObserver(forName: NSWorkspace.didTerminateApplicationNotification, object: nil, queue: .main, using: onNotif)
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseUp) { _ in
// todo reduce number of refreshSession in the callback
// resetManipulatedWithMouseIfPossible might call its own refreshSession
// The end of the callback calls refreshSession
resetClosedWindowsCache()
resetManipulatedWithMouseIfPossible()
let mouseLocation = mouseLocation
let clickedMonitor = mouseLocation.monitorApproximation
switch () {
// Detect clicks on desktop of different monitors
case _ where clickedMonitor.activeWorkspace != focus.workspace:
_ = refreshSession(.globalObserverLeftMouseUp, screenIsDefinitelyUnlocked: true) {
clickedMonitor.activeWorkspace.focusWorkspace()
}
// Detect close button clicks for unfocused windows. Yes, kAXUIElementDestroyedNotification is that unreliable
// And trigger new window detection that could be delayed due to mouseDown event
default:
scheduleRefreshAndLayout(.globalObserverLeftMouseUp, screenIsDefinitelyUnlocked: true)
}
}
}
}