paneful 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -58,9 +58,7 @@ func log(_ msg: String) {
|
|
|
58
58
|
var lastOutput = ""
|
|
59
59
|
var currentPid: pid_t = 0
|
|
60
60
|
var currentAppName = ""
|
|
61
|
-
var
|
|
62
|
-
var observedWindow: AXUIElement?
|
|
63
|
-
var fallbackTimer: Timer?
|
|
61
|
+
var pollTimer: Timer?
|
|
64
62
|
|
|
65
63
|
func emit(_ appName: String, _ title: String, source: String) {
|
|
66
64
|
let output = "\\(appName)\\t\\(title)"
|
|
@@ -75,69 +73,18 @@ func emitCurrentTitle(source: String) {
|
|
|
75
73
|
emit(currentAppName, title, source: source)
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if name == (kAXFocusedWindowChangedNotification as String) {
|
|
81
|
-
log("AX: focused window changed")
|
|
82
|
-
observeFocusedWindowTitle()
|
|
83
|
-
emitCurrentTitle(source: "ax-window-change")
|
|
84
|
-
} else if name == (kAXTitleChangedNotification as String) {
|
|
85
|
-
log("AX: title changed")
|
|
86
|
-
emitCurrentTitle(source: "ax-title-change")
|
|
87
|
-
} else {
|
|
88
|
-
emitCurrentTitle(source: "ax-\\(name)")
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
func observeFocusedWindowTitle() {
|
|
93
|
-
guard let obs = axObserver else { return }
|
|
94
|
-
if let old = observedWindow {
|
|
95
|
-
AXObserverRemoveNotification(obs, old, kAXTitleChangedNotification as CFString)
|
|
96
|
-
observedWindow = nil
|
|
97
|
-
}
|
|
98
|
-
let app = AXUIElementCreateApplication(currentPid)
|
|
99
|
-
var winValue: AnyObject?
|
|
100
|
-
guard AXUIElementCopyAttributeValue(app, kAXFocusedWindowAttribute as CFString, &winValue) == .success else { return }
|
|
101
|
-
let window = winValue as! AXUIElement
|
|
102
|
-
AXObserverAddNotification(obs, window, kAXTitleChangedNotification as CFString, nil)
|
|
103
|
-
observedWindow = window
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
func startObserving(pid: pid_t) {
|
|
107
|
-
stopObserving()
|
|
76
|
+
func startPolling(pid: pid_t) {
|
|
77
|
+
stopPolling()
|
|
108
78
|
emitCurrentTitle(source: "editor-activated")
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
guard AXObserverCreate(pid, axCallback, &observer) == .success, let obs = observer else {
|
|
112
|
-
log("AXObserver failed for pid \\(pid), using poll fallback")
|
|
113
|
-
fallbackTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
|
|
114
|
-
emitCurrentTitle(source: "poll")
|
|
115
|
-
}
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let appElement = AXUIElementCreateApplication(pid)
|
|
120
|
-
AXObserverAddNotification(obs, appElement, kAXFocusedWindowChangedNotification as CFString, nil)
|
|
121
|
-
CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(obs), .defaultMode)
|
|
122
|
-
axObserver = obs
|
|
123
|
-
observeFocusedWindowTitle()
|
|
124
|
-
log("AXObserver active for pid \\(pid)")
|
|
125
|
-
|
|
126
|
-
// AX notifications don't fire for Electron apps (Cursor, VS Code, etc.)
|
|
127
|
-
// so this timer is the primary mechanism for those editors
|
|
128
|
-
fallbackTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
|
|
79
|
+
log("polling title for pid \\(pid)")
|
|
80
|
+
pollTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
|
|
129
81
|
emitCurrentTitle(source: "poll")
|
|
130
82
|
}
|
|
131
83
|
}
|
|
132
84
|
|
|
133
|
-
func
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
axObserver = nil
|
|
137
|
-
observedWindow = nil
|
|
138
|
-
}
|
|
139
|
-
fallbackTimer?.invalidate()
|
|
140
|
-
fallbackTimer = nil
|
|
85
|
+
func stopPolling() {
|
|
86
|
+
pollTimer?.invalidate()
|
|
87
|
+
pollTimer = nil
|
|
141
88
|
}
|
|
142
89
|
|
|
143
90
|
let nc = NSWorkspace.shared.notificationCenter
|
|
@@ -148,9 +95,9 @@ nc.addObserver(forName: NSWorkspace.didActivateApplicationNotification, object:
|
|
|
148
95
|
currentAppName = name
|
|
149
96
|
currentPid = app.processIdentifier
|
|
150
97
|
if isEditor(name) {
|
|
151
|
-
|
|
98
|
+
startPolling(pid: currentPid)
|
|
152
99
|
} else {
|
|
153
|
-
|
|
100
|
+
stopPolling()
|
|
154
101
|
emit(name, "", source: "app-switch")
|
|
155
102
|
}
|
|
156
103
|
}
|
|
@@ -160,7 +107,7 @@ if let front = NSWorkspace.shared.frontmostApplication, let name = front.localiz
|
|
|
160
107
|
currentAppName = name
|
|
161
108
|
currentPid = front.processIdentifier
|
|
162
109
|
if isEditor(name) {
|
|
163
|
-
|
|
110
|
+
startPolling(pid: currentPid)
|
|
164
111
|
} else {
|
|
165
112
|
emit(name, "", source: "seed")
|
|
166
113
|
}
|