Skip to content

Commit

Permalink
refactor: cache more runningapplication properties for perf
Browse files Browse the repository at this point in the history
  • Loading branch information
lwouis committed Jan 5, 2025
1 parent 2a616e2 commit 2855b1b
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 108 deletions.
142 changes: 71 additions & 71 deletions src/api-wrappers/AXUIElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extension AXUIElement {
return nil
}

static func isActualWindow(_ runningApp: NSRunningApplication, _ wid: CGWindowID, _ level: CGWindowLevel, _ title: String?, _ subrole: String?, _ role: String?, _ size: CGSize?) -> Bool {
static func isActualWindow(_ app: Application, _ wid: CGWindowID, _ level: CGWindowLevel, _ title: String?, _ subrole: String?, _ role: String?, _ size: CGSize?) -> Bool {
// Some non-windows have title: nil (e.g. some OS elements)
// Some non-windows have subrole: nil (e.g. some OS elements), "AXUnknown" (e.g. Bartender), "AXSystemDialog" (e.g. Intellij tooltips)
// Minimized windows or windows of a hidden app have subrole "AXDialog"
Expand All @@ -87,157 +87,157 @@ extension AXUIElement {
// Sonoma introduced a bug: a caps-lock indicator shows as a small window. We try to hide it by filtering out tiny windows
&& size != nil && (size!.width > 100 || size!.height > 100) && (
(
books(runningApp) ||
keynote(runningApp) ||
preview(runningApp, subrole) ||
iina(runningApp) ||
openFlStudio(runningApp, title) ||
crossoverWindow(runningApp, role, subrole, level) ||
isAlwaysOnTopScrcpy(runningApp, level, role, subrole)
books(app) ||
keynote(app) ||
preview(app, subrole) ||
iina(app) ||
openFlStudio(app, title) ||
crossoverWindow(app, role, subrole, level) ||
isAlwaysOnTopScrcpy(app, level, role, subrole)
) || (
// CGWindowLevel == .normalWindow helps filter out iStats Pro and other top-level pop-overs, and floating windows
level == CGWindow.normalLevel && (
[kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole) ||
openBoard(runningApp) ||
adobeAudition(runningApp, subrole) ||
adobeAfterEffects(runningApp, subrole) ||
steam(runningApp, title, role) ||
worldOfWarcraft(runningApp, role) ||
battleNetBootstrapper(runningApp, role) ||
firefox(runningApp, role, size) ||
vlcFullscreenVideo(runningApp, role) ||
sanGuoShaAirWD(runningApp) ||
dvdFab(runningApp) ||
drBetotte(runningApp) ||
androidEmulator(runningApp, title) ||
autocad(runningApp, subrole)
openBoard(app) ||
adobeAudition(app, subrole) ||
adobeAfterEffects(app, subrole) ||
steam(app, title, role) ||
worldOfWarcraft(app, role) ||
battleNetBootstrapper(app, role) ||
firefox(app, role, size) ||
vlcFullscreenVideo(app, role) ||
sanGuoShaAirWD(app) ||
dvdFab(app) ||
drBetotte(app) ||
androidEmulator(app, title) ||
autocad(app, subrole)
) && (
mustHaveIfJetbrainApp(runningApp, title, subrole, size!) &&
mustHaveIfSteam(runningApp, title, role) &&
mustHaveIfColorSlurp(runningApp, subrole)
mustHaveIfJetbrainApp(app, title, subrole, size!) &&
mustHaveIfSteam(app, title, role) &&
mustHaveIfColorSlurp(app, subrole)
)
)
)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

func position() throws -> CGPoint? {
Expand Down
20 changes: 12 additions & 8 deletions src/logic/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@ class Application: NSObject {
var axObserver: AXObserver?
var isReallyFinishedLaunching = false
var localizedName: String?
var bundleIdentifier: String?
var bundleURL: URL?
var isHidden: Bool!
var hasBeenActiveOnce: Bool!
var executableURL: URL?
var pid: pid_t
var isHidden: Bool
var hasBeenActiveOnce: Bool
var icon: NSImage?
var dockLabel: String?
var pid: pid_t!
var focusedWindow: Window? = nil
var alreadyRequestedToQuit = false

init(_ runningApplication: NSRunningApplication) {
self.runningApplication = runningApplication
pid = runningApplication.processIdentifier
super.init()
isHidden = runningApplication.isHidden
hasBeenActiveOnce = runningApplication.isActive
icon = runningApplication.icon
localizedName = runningApplication.localizedName
bundleIdentifier = runningApplication.bundleIdentifier
bundleURL = runningApplication.bundleURL
executableURL = runningApplication.executableURL
super.init()
observeEventsIfEligible()
kvObservers = [
runningApplication.observe(\.isFinishedLaunching, options: [.new]) { [weak self] _, _ in
Expand All @@ -44,7 +48,7 @@ class Application: NSObject {
}

deinit {
Logger.debug("Deinit app", runningApplication.bundleIdentifier ?? runningApplication.bundleURL ?? "nil")
Logger.debug("Deinit app", bundleIdentifier ?? bundleURL ?? "nil")
}

func removeWindowslessAppWindow() {
Expand All @@ -58,7 +62,7 @@ class Application: NSObject {
if runningApplication.activationPolicy != .prohibited && axUiElement == nil {
axUiElement = AXUIElementCreateApplication(pid)
AXObserverCreate(pid, axObserverCallback, &axObserver)
Logger.debug("Adding app", pid ?? "nil", runningApplication.bundleIdentifier ?? "nil")
Logger.debug("Adding app", pid, bundleIdentifier ?? "nil")
observeEvents()
}
}
Expand All @@ -77,7 +81,7 @@ class Application: NSObject {
let role = try axWindow.role()
let size = try axWindow.size()
let level = try wid.level()
if AXUIElement.isActualWindow(self.runningApplication, wid, level, title, subrole, role, size) {
if AXUIElement.isActualWindow(self, wid, level, title, subrole, role, size) {
let isFullscreen = try axWindow.isFullscreen()
let isMinimized = try axWindow.isMinimized()
let position = try axWindow.position()
Expand Down Expand Up @@ -139,7 +143,7 @@ class Application: NSObject {
}

func canBeQuit() -> Bool {
return runningApplication.bundleIdentifier != "com.apple.finder" || Preferences.finderShowsQuitMenuItem
return bundleIdentifier != "com.apple.finder" || Preferences.finderShowsQuitMenuItem
}

func quit() {
Expand Down
Loading

0 comments on commit 2855b1b

Please sign in to comment.