Skip to content

Commit 2855b1b

Browse files
committed
refactor: cache more runningapplication properties for perf
1 parent 2a616e2 commit 2855b1b

File tree

8 files changed

+114
-108
lines changed

8 files changed

+114
-108
lines changed

src/api-wrappers/AXUIElement.swift

Lines changed: 71 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ extension AXUIElement {
7676
return nil
7777
}
7878

79-
static func isActualWindow(_ runningApp: NSRunningApplication, _ wid: CGWindowID, _ level: CGWindowLevel, _ title: String?, _ subrole: String?, _ role: String?, _ size: CGSize?) -> Bool {
79+
static func isActualWindow(_ app: Application, _ wid: CGWindowID, _ level: CGWindowLevel, _ title: String?, _ subrole: String?, _ role: String?, _ size: CGSize?) -> Bool {
8080
// Some non-windows have title: nil (e.g. some OS elements)
8181
// Some non-windows have subrole: nil (e.g. some OS elements), "AXUnknown" (e.g. Bartender), "AXSystemDialog" (e.g. Intellij tooltips)
8282
// Minimized windows or windows of a hidden app have subrole "AXDialog"
@@ -87,157 +87,157 @@ extension AXUIElement {
8787
// Sonoma introduced a bug: a caps-lock indicator shows as a small window. We try to hide it by filtering out tiny windows
8888
&& size != nil && (size!.width > 100 || size!.height > 100) && (
8989
(
90-
books(runningApp) ||
91-
keynote(runningApp) ||
92-
preview(runningApp, subrole) ||
93-
iina(runningApp) ||
94-
openFlStudio(runningApp, title) ||
95-
crossoverWindow(runningApp, role, subrole, level) ||
96-
isAlwaysOnTopScrcpy(runningApp, level, role, subrole)
90+
books(app) ||
91+
keynote(app) ||
92+
preview(app, subrole) ||
93+
iina(app) ||
94+
openFlStudio(app, title) ||
95+
crossoverWindow(app, role, subrole, level) ||
96+
isAlwaysOnTopScrcpy(app, level, role, subrole)
9797
) || (
9898
// CGWindowLevel == .normalWindow helps filter out iStats Pro and other top-level pop-overs, and floating windows
9999
level == CGWindow.normalLevel && (
100100
[kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole) ||
101-
openBoard(runningApp) ||
102-
adobeAudition(runningApp, subrole) ||
103-
adobeAfterEffects(runningApp, subrole) ||
104-
steam(runningApp, title, role) ||
105-
worldOfWarcraft(runningApp, role) ||
106-
battleNetBootstrapper(runningApp, role) ||
107-
firefox(runningApp, role, size) ||
108-
vlcFullscreenVideo(runningApp, role) ||
109-
sanGuoShaAirWD(runningApp) ||
110-
dvdFab(runningApp) ||
111-
drBetotte(runningApp) ||
112-
androidEmulator(runningApp, title) ||
113-
autocad(runningApp, subrole)
101+
openBoard(app) ||
102+
adobeAudition(app, subrole) ||
103+
adobeAfterEffects(app, subrole) ||
104+
steam(app, title, role) ||
105+
worldOfWarcraft(app, role) ||
106+
battleNetBootstrapper(app, role) ||
107+
firefox(app, role, size) ||
108+
vlcFullscreenVideo(app, role) ||
109+
sanGuoShaAirWD(app) ||
110+
dvdFab(app) ||
111+
drBetotte(app) ||
112+
androidEmulator(app, title) ||
113+
autocad(app, subrole)
114114
) && (
115-
mustHaveIfJetbrainApp(runningApp, title, subrole, size!) &&
116-
mustHaveIfSteam(runningApp, title, role) &&
117-
mustHaveIfColorSlurp(runningApp, subrole)
115+
mustHaveIfJetbrainApp(app, title, subrole, size!) &&
116+
mustHaveIfSteam(app, title, role) &&
117+
mustHaveIfColorSlurp(app, subrole)
118118
)
119119
)
120120
)
121121
}
122122

123-
private static func mustHaveIfJetbrainApp(_ runningApp: NSRunningApplication, _ title: String?, _ subrole: String?, _ size: NSSize) -> Bool {
123+
private static func mustHaveIfJetbrainApp(_ app: Application, _ title: String?, _ subrole: String?, _ size: NSSize) -> Bool {
124124
// jetbrain apps sometimes generate non-windows that pass all checks in isActualWindow
125125
// they have no title, so we can filter them out based on that
126126
// we also hide windows too small
127-
return runningApp.bundleIdentifier?.range(of: "^com\\.(jetbrains\\.|google\\.android\\.studio).*?$", options: .regularExpression) == nil || (
127+
return app.bundleIdentifier?.range(of: "^com\\.(jetbrains\\.|google\\.android\\.studio).*?$", options: .regularExpression) == nil || (
128128
(subrole == kAXStandardWindowSubrole || (title != nil && title != "")) &&
129129
size.width > 100 && size.height > 100
130130
)
131131
}
132132

133-
private static func mustHaveIfColorSlurp(_ runningApp: NSRunningApplication, _ subrole: String?) -> Bool {
134-
return runningApp.bundleIdentifier != "com.IdeaPunch.ColorSlurp" || subrole == kAXStandardWindowSubrole
133+
private static func mustHaveIfColorSlurp(_ app: Application, _ subrole: String?) -> Bool {
134+
return app.bundleIdentifier != "com.IdeaPunch.ColorSlurp" || subrole == kAXStandardWindowSubrole
135135
}
136136

137-
private static func iina(_ runningApp: NSRunningApplication) -> Bool {
137+
private static func iina(_ app: Application) -> Bool {
138138
// IINA.app can have videos float (level == 2 instead of 0)
139139
// there is also complex animations during which we may or may not consider the window not a window
140-
return runningApp.bundleIdentifier == "com.colliderli.iina"
140+
return app.bundleIdentifier == "com.colliderli.iina"
141141
}
142142

143-
private static func keynote(_ runningApp: NSRunningApplication) -> Bool {
143+
private static func keynote(_ app: Application) -> Bool {
144144
// apple Keynote has a fake fullscreen window when in presentation mode
145145
// it covers the screen with a AXUnknown window instead of using standard fullscreen mode
146-
return runningApp.bundleIdentifier == "com.apple.iWork.Keynote"
146+
return app.bundleIdentifier == "com.apple.iWork.Keynote"
147147
}
148148

149-
private static func preview(_ runningApp: NSRunningApplication, _ subrole: String?) -> Bool {
149+
private static func preview(_ app: Application, _ subrole: String?) -> Bool {
150150
// when opening multiple documents at once with apple Preview,
151151
// one of the window will have level == 1 for some reason
152-
return runningApp.bundleIdentifier == "com.apple.Preview" && [kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole)
152+
return app.bundleIdentifier == "com.apple.Preview" && [kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole)
153153
}
154154

155-
private static func openFlStudio(_ runningApp: NSRunningApplication, _ title: String?) -> Bool {
155+
private static func openFlStudio(_ app: Application, _ title: String?) -> Bool {
156156
// OpenBoard is a ported app which doesn't use standard macOS windows
157-
return runningApp.bundleIdentifier == "com.image-line.flstudio" && (title != nil && title != "")
157+
return app.bundleIdentifier == "com.image-line.flstudio" && (title != nil && title != "")
158158
}
159159

160-
private static func openBoard(_ runningApp: NSRunningApplication) -> Bool {
160+
private static func openBoard(_ app: Application) -> Bool {
161161
// OpenBoard is a ported app which doesn't use standard macOS windows
162-
return runningApp.bundleIdentifier == "org.oe-f.OpenBoard"
162+
return app.bundleIdentifier == "org.oe-f.OpenBoard"
163163
}
164164

165-
private static func adobeAudition(_ runningApp: NSRunningApplication, _ subrole: String?) -> Bool {
166-
return runningApp.bundleIdentifier == "com.adobe.Audition" && subrole == kAXFloatingWindowSubrole
165+
private static func adobeAudition(_ app: Application, _ subrole: String?) -> Bool {
166+
return app.bundleIdentifier == "com.adobe.Audition" && subrole == kAXFloatingWindowSubrole
167167
}
168168

169-
private static func adobeAfterEffects(_ runningApp: NSRunningApplication, _ subrole: String?) -> Bool {
170-
return runningApp.bundleIdentifier == "com.adobe.AfterEffects" && subrole == kAXFloatingWindowSubrole
169+
private static func adobeAfterEffects(_ app: Application, _ subrole: String?) -> Bool {
170+
return app.bundleIdentifier == "com.adobe.AfterEffects" && subrole == kAXFloatingWindowSubrole
171171
}
172172

173-
private static func books(_ runningApp: NSRunningApplication) -> Bool {
173+
private static func books(_ app: Application) -> Bool {
174174
// Books.app has animations on window creation. This means windows are originally created with subrole == AXUnknown or isOnNormalLevel == false
175-
return runningApp.bundleIdentifier == "com.apple.iBooksX"
175+
return app.bundleIdentifier == "com.apple.iBooksX"
176176
}
177177

178-
private static func worldOfWarcraft(_ runningApp: NSRunningApplication, _ role: String?) -> Bool {
179-
return runningApp.bundleIdentifier == "com.blizzard.worldofwarcraft" && role == kAXWindowRole
178+
private static func worldOfWarcraft(_ app: Application, _ role: String?) -> Bool {
179+
return app.bundleIdentifier == "com.blizzard.worldofwarcraft" && role == kAXWindowRole
180180
}
181181

182-
private static func battleNetBootstrapper(_ runningApp: NSRunningApplication, _ role: String?) -> Bool {
182+
private static func battleNetBootstrapper(_ app: Application, _ role: String?) -> Bool {
183183
// Battlenet bootstrapper windows have subrole == AXUnknown
184-
return runningApp.bundleIdentifier == "net.battle.bootstrapper" && role == kAXWindowRole
184+
return app.bundleIdentifier == "net.battle.bootstrapper" && role == kAXWindowRole
185185
}
186186

187-
private static func drBetotte(_ runningApp: NSRunningApplication) -> Bool {
188-
return runningApp.bundleIdentifier == "com.ssworks.drbetotte"
187+
private static func drBetotte(_ app: Application) -> Bool {
188+
return app.bundleIdentifier == "com.ssworks.drbetotte"
189189
}
190190

191-
private static func dvdFab(_ runningApp: NSRunningApplication) -> Bool {
192-
return runningApp.bundleIdentifier == "com.goland.dvdfab.macos"
191+
private static func dvdFab(_ app: Application) -> Bool {
192+
return app.bundleIdentifier == "com.goland.dvdfab.macos"
193193
}
194194

195-
private static func sanGuoShaAirWD(_ runningApp: NSRunningApplication) -> Bool {
196-
return runningApp.bundleIdentifier == "SanGuoShaAirWD"
195+
private static func sanGuoShaAirWD(_ app: Application) -> Bool {
196+
return app.bundleIdentifier == "SanGuoShaAirWD"
197197
}
198198

199-
private static func steam(_ runningApp: NSRunningApplication, _ title: String?, _ role: String?) -> Bool {
199+
private static func steam(_ app: Application, _ title: String?, _ role: String?) -> Bool {
200200
// All Steam windows have subrole == AXUnknown
201201
// some dropdown menus are not desirable; they have title == "", or sometimes role == nil when switching between menus quickly
202-
return runningApp.bundleIdentifier == "com.valvesoftware.steam" && (title != nil && title != "" && role != nil)
202+
return app.bundleIdentifier == "com.valvesoftware.steam" && (title != nil && title != "" && role != nil)
203203
}
204204

205-
private static func mustHaveIfSteam(_ runningApp: NSRunningApplication, _ title: String?, _ role: String?) -> Bool {
205+
private static func mustHaveIfSteam(_ app: Application, _ title: String?, _ role: String?) -> Bool {
206206
// All Steam windows have subrole == AXUnknown
207207
// some dropdown menus are not desirable; they have title == "", or sometimes role == nil when switching between menus quickly
208-
return runningApp.bundleIdentifier != "com.valvesoftware.steam" || (title != nil && title != "" && role != nil)
208+
return app.bundleIdentifier != "com.valvesoftware.steam" || (title != nil && title != "" && role != nil)
209209
}
210210

211-
private static func firefox(_ runningApp: NSRunningApplication, _ role: String?, _ size: CGSize?) -> Bool {
211+
private static func firefox(_ app: Application, _ role: String?, _ size: CGSize?) -> Bool {
212212
// Firefox fullscreen video have subrole == AXUnknown if fullscreen'ed when the base window is not fullscreen
213213
// Firefox tooltips are implemented as windows with subrole == AXUnknown
214-
return (runningApp.bundleIdentifier?.hasPrefix("org.mozilla.firefox") ?? false) && role == kAXWindowRole && size?.height != nil && size!.height > 400
214+
return (app.bundleIdentifier?.hasPrefix("org.mozilla.firefox") ?? false) && role == kAXWindowRole && size?.height != nil && size!.height > 400
215215
}
216216

217-
private static func vlcFullscreenVideo(_ runningApp: NSRunningApplication, _ role: String?) -> Bool {
217+
private static func vlcFullscreenVideo(_ app: Application, _ role: String?) -> Bool {
218218
// VLC fullscreen video have subrole == AXUnknown if fullscreen'ed
219-
return (runningApp.bundleIdentifier?.hasPrefix("org.videolan.vlc") ?? false) && role == kAXWindowRole
219+
return (app.bundleIdentifier?.hasPrefix("org.videolan.vlc") ?? false) && role == kAXWindowRole
220220
}
221221

222-
private static func androidEmulator(_ runningApp: NSRunningApplication, _ title: String?) -> Bool {
222+
private static func androidEmulator(_ app: Application, _ title: String?) -> Bool {
223223
// android emulator small vertical menu is a "window" with empty title; we exclude it
224-
return title != "" && Applications.isAndroidEmulator(runningApp)
224+
return title != "" && Applications.isAndroidEmulator(app.bundleIdentifier, app.pid)
225225
}
226226

227-
private static func crossoverWindow(_ runningApp: NSRunningApplication, _ role: String?, _ subrole: String?, _ level: CGWindowLevel) -> Bool {
228-
return runningApp.bundleIdentifier == nil && role == kAXWindowRole && subrole == kAXUnknownSubrole && level == CGWindow.normalLevel
229-
&& (runningApp.localizedName == "wine64-preloader" || runningApp.executableURL?.absoluteString.contains("/winetemp-") ?? false)
227+
private static func crossoverWindow(_ app: Application, _ role: String?, _ subrole: String?, _ level: CGWindowLevel) -> Bool {
228+
return app.bundleIdentifier == nil && role == kAXWindowRole && subrole == kAXUnknownSubrole && level == CGWindow.normalLevel
229+
&& (app.localizedName == "wine64-preloader" || app.executableURL?.absoluteString.contains("/winetemp-") ?? false)
230230
}
231231

232-
private static func isAlwaysOnTopScrcpy(_ runningApp: NSRunningApplication, _ level: CGWindowLevel, _ role: String?, _ subrole: String?) -> Bool {
232+
private static func isAlwaysOnTopScrcpy(_ app: Application, _ level: CGWindowLevel, _ role: String?, _ subrole: String?) -> Bool {
233233
// scrcpy presents as a floating window when "Always on top" is enabled, so it doesn't get picked up normally.
234234
// It also doesn't have a bundle ID, so we need to match using the localized name, which should always be the same.
235-
return runningApp.localizedName == "scrcpy" && level == CGWindow.floatingWindow && role == kAXWindowRole && subrole == kAXStandardWindowSubrole
235+
return app.localizedName == "scrcpy" && level == CGWindow.floatingWindow && role == kAXWindowRole && subrole == kAXStandardWindowSubrole
236236
}
237237

238-
private static func autocad(_ runningApp: NSRunningApplication, _ subrole: String?) -> Bool {
238+
private static func autocad(_ app: Application, _ subrole: String?) -> Bool {
239239
// AutoCAD uses the undocumented "AXDocumentWindow" subrole
240-
return (runningApp.bundleIdentifier?.hasPrefix("com.autodesk.AutoCAD") ?? false) && subrole == kAXDocumentWindowSubrole
240+
return (app.bundleIdentifier?.hasPrefix("com.autodesk.AutoCAD") ?? false) && subrole == kAXDocumentWindowSubrole
241241
}
242242

243243
func position() throws -> CGPoint? {

src/logic/Application.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,28 @@ class Application: NSObject {
99
var axObserver: AXObserver?
1010
var isReallyFinishedLaunching = false
1111
var localizedName: String?
12+
var bundleIdentifier: String?
1213
var bundleURL: URL?
13-
var isHidden: Bool!
14-
var hasBeenActiveOnce: Bool!
14+
var executableURL: URL?
15+
var pid: pid_t
16+
var isHidden: Bool
17+
var hasBeenActiveOnce: Bool
1518
var icon: NSImage?
1619
var dockLabel: String?
17-
var pid: pid_t!
1820
var focusedWindow: Window? = nil
1921
var alreadyRequestedToQuit = false
2022

2123
init(_ runningApplication: NSRunningApplication) {
2224
self.runningApplication = runningApplication
2325
pid = runningApplication.processIdentifier
24-
super.init()
2526
isHidden = runningApplication.isHidden
2627
hasBeenActiveOnce = runningApplication.isActive
2728
icon = runningApplication.icon
2829
localizedName = runningApplication.localizedName
30+
bundleIdentifier = runningApplication.bundleIdentifier
2931
bundleURL = runningApplication.bundleURL
32+
executableURL = runningApplication.executableURL
33+
super.init()
3034
observeEventsIfEligible()
3135
kvObservers = [
3236
runningApplication.observe(\.isFinishedLaunching, options: [.new]) { [weak self] _, _ in
@@ -44,7 +48,7 @@ class Application: NSObject {
4448
}
4549

4650
deinit {
47-
Logger.debug("Deinit app", runningApplication.bundleIdentifier ?? runningApplication.bundleURL ?? "nil")
51+
Logger.debug("Deinit app", bundleIdentifier ?? bundleURL ?? "nil")
4852
}
4953

5054
func removeWindowslessAppWindow() {
@@ -58,7 +62,7 @@ class Application: NSObject {
5862
if runningApplication.activationPolicy != .prohibited && axUiElement == nil {
5963
axUiElement = AXUIElementCreateApplication(pid)
6064
AXObserverCreate(pid, axObserverCallback, &axObserver)
61-
Logger.debug("Adding app", pid ?? "nil", runningApplication.bundleIdentifier ?? "nil")
65+
Logger.debug("Adding app", pid, bundleIdentifier ?? "nil")
6266
observeEvents()
6367
}
6468
}
@@ -77,7 +81,7 @@ class Application: NSObject {
7781
let role = try axWindow.role()
7882
let size = try axWindow.size()
7983
let level = try wid.level()
80-
if AXUIElement.isActualWindow(self.runningApplication, wid, level, title, subrole, role, size) {
84+
if AXUIElement.isActualWindow(self, wid, level, title, subrole, role, size) {
8185
let isFullscreen = try axWindow.isFullscreen()
8286
let isMinimized = try axWindow.isMinimized()
8387
let position = try axWindow.position()
@@ -139,7 +143,7 @@ class Application: NSObject {
139143
}
140144

141145
func canBeQuit() -> Bool {
142-
return runningApplication.bundleIdentifier != "com.apple.finder" || Preferences.finderShowsQuitMenuItem
146+
return bundleIdentifier != "com.apple.finder" || Preferences.finderShowsQuitMenuItem
143147
}
144148

145149
func quit() {

0 commit comments

Comments
 (0)