From 84dbaa06aaba4d10f0acf04506db9e5bc6aaa954 Mon Sep 17 00:00:00 2001 From: Louis Pontoise Date: Tue, 27 Oct 2020 21:26:33 +0900 Subject: [PATCH] feat: don't show glitchy windows from non-native apps (closes #562) See #456 --- src/api-wrappers/AXUIElement.swift | 35 ++++++++++++---------- src/logic/Application.swift | 3 +- src/logic/events/AccessibilityEvents.swift | 6 ++-- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/api-wrappers/AXUIElement.swift b/src/api-wrappers/AXUIElement.swift index ccd5ee19e..17a1d308b 100644 --- a/src/api-wrappers/AXUIElement.swift +++ b/src/api-wrappers/AXUIElement.swift @@ -73,7 +73,7 @@ extension AXUIElement { return nil } - func isActualWindow(_ runningApp: NSRunningApplication, _ wid: CGWindowID, _ isOnNormalLevel: Bool, _ title: String?, _ subrole: String?, _ role: String?) -> Bool { + func isActualWindow(_ runningApp: NSRunningApplication, _ wid: CGWindowID, _ isOnNormalLevel: Bool, _ 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" @@ -81,20 +81,21 @@ extension AXUIElement { // Some non-windows have cgWindowId == 0 (e.g. windows of apps starting at login with the checkbox "Hidden" checked) return wid != 0 && - (books(runningApp) || keynote(runningApp)) || ( - // CGWindowLevel == .normalWindow helps filter out iStats Pro and other top-level pop-overs, and floating windows - isOnNormalLevel && - ([kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole) || - openBoard(runningApp) || - adobeAudition(runningApp, subrole) || - steam(runningApp, title, role) || - worldOfWarcraft(runningApp, role) || - battleNetBootstrapper(runningApp, role) || - firefoxFullscreenVideo(runningApp, role) || - androidEmulator(runningApp, title) || - sanGuoShaAirWD(runningApp) || - dvdFab(runningApp) || - drBetotte(runningApp))) + size != nil && size!.width > 100 && size!.height > 100 && + (books(runningApp) || keynote(runningApp) || ( + // CGWindowLevel == .normalWindow helps filter out iStats Pro and other top-level pop-overs, and floating windows + isOnNormalLevel && + ([kAXStandardWindowSubrole, kAXDialogSubrole].contains(subrole) || + openBoard(runningApp) || + adobeAudition(runningApp, subrole) || + steam(runningApp, title, role) || + worldOfWarcraft(runningApp, role) || + battleNetBootstrapper(runningApp, role) || + firefoxFullscreenVideo(runningApp, role) || + androidEmulator(runningApp, title) || + sanGuoShaAirWD(runningApp) || + dvdFab(runningApp) || + drBetotte(runningApp)))) } private func keynote(_ runningApp: NSRunningApplication) -> Bool { @@ -163,6 +164,10 @@ extension AXUIElement { return try value(kAXPositionAttribute, CGPoint.zero, .cgPoint) } + func size() throws -> CGSize? { + return try value(kAXSizeAttribute, CGSize.zero, .cgSize) + } + func title() throws -> String? { return try attribute(kAXTitleAttribute, String.self) } diff --git a/src/logic/Application.swift b/src/logic/Application.swift index 152dd2012..828fd0c09 100644 --- a/src/logic/Application.swift +++ b/src/logic/Application.swift @@ -83,8 +83,9 @@ class Application: NSObject { let title = try $0.title() let subrole = try $0.subrole() let role = try $0.role() + let size = try $0.size() let isOnNormalLevel = $0.isOnNormalLevel(wid) - if $0.isActualWindow(self.runningApplication, wid, isOnNormalLevel, title, subrole, role) { + if $0.isActualWindow(self.runningApplication, wid, isOnNormalLevel, title, subrole, role, size) { return ($0, wid, title, try $0.isFullscreen(), try $0.isMinimized(), try $0.position()) } } diff --git a/src/logic/events/AccessibilityEvents.swift b/src/logic/events/AccessibilityEvents.swift index 3b9ac6ff6..2f3c6009b 100644 --- a/src/logic/events/AccessibilityEvents.swift +++ b/src/logic/events/AccessibilityEvents.swift @@ -85,10 +85,11 @@ fileprivate func windowCreated(_ element: AXUIElement, _ pid: pid_t) throws { let isMinimized = try element.isMinimized() let isOnNormalLevel = element.isOnNormalLevel(wid) let position = try element.position() + let size = try element.size() DispatchQueue.main.async { if (Windows.list.firstIndex { $0.isEqualRobust(element, wid) }) == nil, let runningApp = NSRunningApplication(processIdentifier: pid), - element.isActualWindow(runningApp, wid, isOnNormalLevel, axTitle, subrole, role), + element.isActualWindow(runningApp, wid, isOnNormalLevel, axTitle, subrole, role, size), let app = (Applications.list.first { $0.pid == pid }) { let window = Window(element, app, wid, axTitle, isFullscreen, isMinimized, position) Windows.appendAndUpdateFocus(window) @@ -112,10 +113,11 @@ fileprivate func focusedWindowChanged(_ element: AXUIElement, _ pid: pid_t) thro let isMinimized = try element.isMinimized() let isOnNormalLevel = element.isOnNormalLevel(wid) let position = try element.position() + let size = try element.size() DispatchQueue.main.async { if let windows = Windows.updateLastFocus(element, wid) { App.app.refreshOpenUi(windows) - } else if element.isActualWindow(runningApp, wid, isOnNormalLevel, axTitle, subrole, role), + } else if element.isActualWindow(runningApp, wid, isOnNormalLevel, axTitle, subrole, role, size), let app = (Applications.list.first { $0.pid == pid }) { let window = Window(element, app, wid, axTitle, isFullscreen, isMinimized, position) Windows.appendAndUpdateFocus(window)