diff --git a/src/logic/Application.swift b/src/logic/Application.swift index 2ea59593..1d561f63 100644 --- a/src/logic/Application.swift +++ b/src/logic/Application.swift @@ -19,10 +19,7 @@ class Application: NSObject { var dockLabel: String? var focusedWindow: Window? = nil var alreadyRequestedToQuit = false - - func debugId() -> String { - return "(pid:\(pid) \(bundleIdentifier ?? bundleURL?.absoluteString ?? executableURL?.absoluteString ?? localizedName))" - } + var debugId: String static let notifications = [ kAXApplicationActivatedNotification, @@ -81,8 +78,9 @@ class Application: NSObject { bundleIdentifier = runningApplication.bundleIdentifier bundleURL = runningApplication.bundleURL executableURL = runningApplication.executableURL + debugId = "(pid:\(pid) \(bundleIdentifier ?? bundleURL?.absoluteString ?? executableURL?.absoluteString ?? localizedName))" super.init() - Logger.info { self.debugId() } + Logger.info { self.debugId } observeEventsIfEligible() kvObservers = [ runningApplication.observe(\.isFinishedLaunching, options: [.new]) { [weak self] _, _ in @@ -100,7 +98,7 @@ class Application: NSObject { } deinit { - Logger.info { self.debugId() } + Logger.info { self.debugId } } @@ -118,17 +116,17 @@ class Application: NSObject { private func observeEvents() { guard let axObserver else { return } - AXUIElement.retryAxCallUntilTimeout(context: debugId(), pid: pid, callType: .subscribeToAppNotification) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: debugId, pid: pid, callType: .subscribeToAppNotification) { [weak self] in guard let self, !self.isReallyFinishedLaunching else { return } if try self.axUiElement!.subscribeToNotification(axObserver, Application.notifications.first!) { - Logger.debug { "Subscribed to app: \(self.debugId())" } + Logger.debug { "Subscribed to app: \(self.debugId)" } if !self.isReallyFinishedLaunching { // some apps have `isFinishedLaunching == true` but are actually not finished, and will return .cannotComplete // we consider them ready when the first subscription succeeds // windows opened before that point won't send a notification, so check those windows manually here self.isReallyFinishedLaunching = true for notification in Application.notifications.dropFirst() { - AXUIElement.retryAxCallUntilTimeout(context: self.debugId(), pid: self.pid, callType: .subscribeToAppNotification) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: self.debugId, pid: self.pid, callType: .subscribeToAppNotification) { [weak self] in try self?.axUiElement!.subscribeToNotification(axObserver, notification) } } @@ -142,7 +140,7 @@ class Application: NSObject { } func manuallyUpdateWindows() { - AXUIElement.retryAxCallUntilTimeout(context: debugId(), pid: pid, callType: .updateAppWindows) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: debugId, pid: pid, callType: .updateAppWindows) { [weak self] in guard let self, let axUiElement = self.axUiElement else { return } let axWindows = try axUiElement.allWindows(self.pid) guard !axWindows.isEmpty else { diff --git a/src/logic/Applications.swift b/src/logic/Applications.swift index ae8cb941..dac7c20c 100644 --- a/src/logic/Applications.swift +++ b/src/logic/Applications.swift @@ -47,7 +47,7 @@ class Applications { let zombies = believedAlive.subtracting(confirmedAlive) for window in Windows.list.reversed() { if let wid = window.cgWindowId, zombies.contains(wid) { - Logger.debug { window.debugId() } + Logger.debug { window.debugId } Windows.removeWindows([window], true) } } diff --git a/src/logic/Window.swift b/src/logic/Window.swift index b8e819e0..47678798 100644 --- a/src/logic/Window.swift +++ b/src/logic/Window.swift @@ -11,7 +11,7 @@ class Window { ] private static var globalCreationCounter = Int.zero - var id: String! + var id: String var cgWindowId: CGWindowID? var lastFocusOrder = Int.zero var creationOrder = Int.zero @@ -35,10 +35,7 @@ class Window { var application: Application var axObserver: AXObserver? var rowIndex: Int? - - func debugId() -> String { - return "\(application.debugId()) (wid:\(cgWindowId) title:\(title))" - } + var debugId: String! init(_ axUiElement: AXUIElement, _ application: Application, _ wid: CGWindowID, _ title: String?, _ isFullscreen: Bool?, _ isMinimized: Bool?, _ position: CGPoint?, _ size: CGSize?) { id = "\(wid)" @@ -47,6 +44,7 @@ class Window { cgWindowId = wid self.updateSpacesAndScreen() updateFromAxAttributes(title, size, position, isFullscreen, isMinimized) + debugId = "\(self.application.debugId) (wid:\(cgWindowId) title:\(self.title))" Window.globalCreationCounter += 1 creationOrder = Window.globalCreationCounter application.removeWindowlessAppWindow() @@ -54,7 +52,7 @@ class Window { // It may be responsive now since it has a window; we attempt again application.observeEventsIfEligible() checkIfFocused() - Logger.info { self.debugId() } + Logger.info { self.debugId } observeEvents() } @@ -64,11 +62,12 @@ class Window { title = bestEffortTitle(nil) Window.globalCreationCounter += 1 creationOrder = Window.globalCreationCounter - Logger.debug { self.debugId() } + debugId = "\(application.debugId) (title:\(title))" + Logger.debug { self.debugId } } deinit { - Logger.info { self.debugId() } + Logger.info { self.debugId } } func updateFromAxAttributes(_ title: String?, _ size: CGSize?, _ position: CGPoint?, _ isFullscreen: Bool?, _ isMinimized: Bool?) { @@ -88,12 +87,12 @@ class Window { private func observeEvents() { AXObserverCreate(application.pid, AccessibilityEvents.axObserverCallback, &axObserver) guard let axObserver else { return } - AXUIElement.retryAxCallUntilTimeout(context: debugId(), pid: application.pid, callType: .subscribeToWindowNotification) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: debugId, pid: application.pid, callType: .subscribeToWindowNotification) { [weak self] in guard let self else { return } if try self.axUiElement!.subscribeToNotification(axObserver, Window.notifications.first!) { - Logger.debug { "Subscribed to window: \(self.debugId())" } + Logger.debug { "Subscribed to window: \(self.debugId)" } for notification in Window.notifications.dropFirst() { - AXUIElement.retryAxCallUntilTimeout(context: self.debugId(), pid: self.application.pid, callType: .subscribeToWindowNotification) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: self.debugId, pid: self.application.pid, callType: .subscribeToWindowNotification) { [weak self] in try self?.axUiElement!.subscribeToNotification(axObserver, notification) } } @@ -316,7 +315,7 @@ class Window { /// some apps will not trigger AXApplicationActivated, where we usually update application.focusedWindow /// workaround: we check and possibly do it here private func checkIfFocused() { - AXUIElement.retryAxCallUntilTimeout(context: debugId(), pid: application.pid, callType: .updateWindow) { [weak self] in + AXUIElement.retryAxCallUntilTimeout(context: debugId, pid: application.pid, callType: .updateWindow) { [weak self] in guard let self, let focusedWindow = try self.application.axUiElement?.attributes([kAXFocusedWindowAttribute]).focusedWindow, let window = try (Windows.list.first { $0.isEqualRobust(focusedWindow, (try focusedWindow.cgWindowId())) }) else { return } diff --git a/src/logic/Windows.swift b/src/logic/Windows.swift index dd7693f8..b9c70548 100644 --- a/src/logic/Windows.swift +++ b/src/logic/Windows.swift @@ -10,7 +10,7 @@ class Windows { static func updateIsFullscreenOnCurrentSpace() { let windowsOnCurrentSpace = list.filter { !$0.isWindowlessApp } for window in windowsOnCurrentSpace { - AXUIElement.retryAxCallUntilTimeout(context: window.debugId(), after: .now() + humanPerceptionDelay, callType: .updateWindow) { [weak window] in + AXUIElement.retryAxCallUntilTimeout(context: window.debugId, after: .now() + humanPerceptionDelay, callType: .updateWindow) { [weak window] in guard let window else { return } // we reuse existing code, to update .isFullscreen, as if there was a kAXWindowResizedNotification try AccessibilityEvents.handleEventWindow(kAXWindowResizedNotification, window.cgWindowId!, window.application.pid, window.axUiElement!) diff --git a/src/logic/events/AccessibilityEvents.swift b/src/logic/events/AccessibilityEvents.swift index f67c80a5..5704c1ae 100644 --- a/src/logic/events/AccessibilityEvents.swift +++ b/src/logic/events/AccessibilityEvents.swift @@ -25,7 +25,7 @@ class AccessibilityEvents { let appFocusedWindow = try element.attributes([kAXFocusedWindowAttribute]).focusedWindow DispatchQueue.main.async { guard let app = Applications.findOrCreate(pid) else { return } - Logger.info { "\(type) app:\(app.debugId())" } + Logger.info { "\(type) app:\(app.debugId)" } if type == kAXApplicationActivatedNotification { applicationActivated(app, pid, type, appFocusedWindow) } else if type == kAXApplicationHiddenNotification || type == kAXApplicationShownNotification { @@ -84,7 +84,7 @@ class AccessibilityEvents { let a = try element.attributes([kAXTitleAttribute, kAXSubroleAttribute, kAXRoleAttribute, kAXSizeAttribute, kAXPositionAttribute, kAXFullscreenAttribute, kAXMinimizedAttribute]) DispatchQueue.main.async { guard let app = Applications.findOrCreate(pid) else { return } - Logger.info { "\(type) wid:\(wid) app:\(app.debugId())" } + Logger.info { "\(type) wid:\(wid) app:\(app.debugId)" } if type == kAXUIElementDestroyedNotification { windowDestroyed(element, pid, wid) return @@ -96,7 +96,7 @@ class AccessibilityEvents { } return } - Logger.debug { "\(type) win:\(window.debugId())" } + Logger.debug { "\(type) win:\(window.debugId)" } if type == kAXMainWindowChangedNotification || type == kAXFocusedWindowChangedNotification { focusedWindowChanged(window) } else if type == kAXWindowResizedNotification || type == kAXWindowMovedNotification { diff --git a/src/logic/events/WindowCaptureEvents.swift b/src/logic/events/WindowCaptureEvents.swift index 9f59d6f0..d5f30293 100644 --- a/src/logic/events/WindowCaptureEvents.swift +++ b/src/logic/events/WindowCaptureEvents.swift @@ -62,7 +62,7 @@ class WindowCaptureScreenshots { ActiveWindowCaptures.increment() SCScreenshotManager.captureImage(contentFilter: filter, configuration: config) { cgImage, error in ActiveWindowCaptures.decrement() - guard let cgImage, error == nil else { Logger.error { "\(window.debugId()) \(cgImage == nil) \(error)" }; return } + guard let cgImage, error == nil else { Logger.error { "\(window.debugId) \(cgImage == nil) \(error)" }; return } guard source != .refreshOnlyThumbnailsAfterShowUi || App.app.appIsBeingUsed else { return } DispatchQueue.main.async { guard source != .refreshOnlyThumbnailsAfterShowUi || App.app.appIsBeingUsed else { return } diff --git a/src/ui/App.swift b/src/ui/App.swift index 8f20cfad..a73bcc1d 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -117,7 +117,7 @@ class App: AppCenterApplication { func focusTarget() { guard appIsBeingUsed else { return } // already hidden let selectedWindow = Windows.selectedWindow() - Logger.info { selectedWindow?.debugId() } + Logger.info { selectedWindow?.debugId } focusSelectedWindow(selectedWindow) }