Skip to content

Commit

Permalink
fix: show windows of apps launched hidden (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
lwouis committed Feb 23, 2021
1 parent 4003df4 commit eb5d019
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/logic/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Application: NSObject {
var axObserver: AXObserver?
var isReallyFinishedLaunching = false
var isHidden: Bool!
var hasBeenActiveOnce: Bool!
var icon: NSImage?
var dockLabel: String?
var pid: pid_t { runningApplication.processIdentifier }
Expand Down Expand Up @@ -39,6 +40,7 @@ class Application: NSObject {
self.runningApplication = runningApplication
super.init()
isHidden = runningApplication.isHidden
hasBeenActiveOnce = runningApplication.isActive
icon = runningApplication.icon
addAndObserveWindows()
kvObservers = [
Expand Down
59 changes: 37 additions & 22 deletions src/logic/events/AccessibilityEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ fileprivate func handleEvent(_ type: String, _ element: AXUIElement) throws {
debugPrint("Accessibility event", type, type != kAXFocusedUIElementChangedNotification ? (try element.title() ?? "nil") : "nil")
// events are handled concurrently, thus we check that the app is still running
if let pid = try element.pid(),
try (!(type == kAXWindowCreatedNotification && pid == ProcessInfo.processInfo.processIdentifier && element.subrole() == kAXUnknownSubrole)) {
try (!(pid == ProcessInfo.processInfo.processIdentifier && element.subrole() == kAXUnknownSubrole)) {
switch type {
case kAXApplicationActivatedNotification: try applicationActivated(element)
case kAXApplicationActivatedNotification: try applicationActivated(element, pid)
case kAXApplicationHiddenNotification,
kAXApplicationShownNotification: try applicationHiddenOrShown(element, pid, type)
case kAXWindowCreatedNotification: try windowCreated(element, pid)
Expand Down Expand Up @@ -54,10 +54,13 @@ fileprivate func updateTabs(_ pid: pid_t, _ currentWindows: [AXUIElement]?) -> [
return windows
}

fileprivate func applicationActivated(_ element: AXUIElement) throws {
fileprivate func applicationActivated(_ element: AXUIElement, _ pid: pid_t) throws {
if let appFocusedWindow = try element.focusedWindow(),
let wid = try appFocusedWindow.cgWindowId() {
DispatchQueue.main.async {
if let app = (Applications.list.first { $0.pid == pid }), !app.hasBeenActiveOnce {
app.hasBeenActiveOnce = true
}
// ensure alt-tab window remains key, so local shortcuts work
if App.app.appIsBeingUsed { App.app.thumbnailsPanel.makeKeyAndOrderFront(nil) }
if let window = Windows.updateLastFocus(appFocusedWindow, wid) {
Expand Down Expand Up @@ -107,26 +110,38 @@ fileprivate func windowCreated(_ element: AXUIElement, _ pid: pid_t) throws {

fileprivate func focusedWindowChanged(_ element: AXUIElement, _ pid: pid_t) throws {
if let wid = try element.cgWindowId(),
let runningApp = NSRunningApplication(processIdentifier: pid),
// photoshop will focus a window *after* you focus another app
let runningApp = NSRunningApplication(processIdentifier: pid) {
// photoshop will focus a window *after* you focus another app
// we check that a focused window happens within an active app
runningApp.isActive {
let axTitle = try element.title()
let subrole = try element.subrole()
let role = try element.role()
let isFullscreen = try element.isFullscreen()
let isMinimized = try element.isMinimized()
let level = try wid.level()
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, level, axTitle, subrole, role, size),
let app = (Applications.list.first { $0.pid == pid }) {
let window = Window(element, app, wid, axTitle, isFullscreen, isMinimized, position, size)
Windows.appendAndUpdateFocus(window)
App.app.refreshOpenUi([window])
if runningApp.isActive {
let axTitle = try element.title()
let subrole = try element.subrole()
let role = try element.role()
let isFullscreen = try element.isFullscreen()
let isMinimized = try element.isMinimized()
let level = try wid.level()
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, level, axTitle, subrole, role, size),
let app = (Applications.list.first { $0.pid == pid }) {
let window = Window(element, app, wid, axTitle, isFullscreen, isMinimized, position, size)
Windows.appendAndUpdateFocus(window)
App.app.refreshOpenUi([window])
}
}
} else {
DispatchQueue.main.async {
if let app = (Applications.list.first { $0.pid == pid }) {
// work-around for apps started "hidden" like in Login Items with the "Hide" checkbox, or with `open -j`
// these apps report isHidden=false, don't generate windowCreated events initially, and have a delay before their windows are created
// our only recourse is to manually check their windows once they emit
if (!app.hasBeenActiveOnce) {
app.observeNewWindows()
}
}
}
}
}
Expand Down

0 comments on commit eb5d019

Please sign in to comment.