Skip to content

Commit

Permalink
fix: apps could steal key focus from alt-tab main window (#719 #916)
Browse files Browse the repository at this point in the history
(closes #719, closes #916)
  • Loading branch information
lwouis committed Apr 17, 2021
1 parent 682cd1e commit 6be72f3
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/logic/SystemPermissions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class SystemPermissions {
startupBlock()
} else {
permissionsWindow = PermissionsWindow()
permissionsWindow.show()
App.app.showSecondaryWindow(permissionsWindow)
observePermissionsPreStartup(startupBlock)
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/logic/Window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,12 @@ class Window {
isOnAllSpaces = true
}
}

func isOnScreen(_ screen: NSScreen) -> Bool {
if let screenUuid = screen.uuid(), let screenSpaces = Spaces.screenSpacesMap[screenUuid] {
return screenSpaces.contains { $0 == spaceId }
}
return true
}
}

23 changes: 1 addition & 22 deletions src/logic/Windows.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,30 +181,9 @@ class Windows {
!(!(Preferences.showMinimizedWindows[App.app.shortcutIndex] != .hide) && window.isMinimized) &&
!(Preferences.spacesToShow[App.app.shortcutIndex] == .active && window.spaceId != Spaces.currentSpaceId) &&
!(Preferences.spacesToShow[App.app.shortcutIndex] == .visible && !Spaces.visibleSpaces.contains(window.spaceId)) &&
!(Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab && !isOnScreen(window, screen)) &&
!(Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab && !window.isOnScreen(screen)) &&
(Preferences.showTabsAsWindows || !window.isTabbed))
}

static func isOnScreen(_ window: Window, _ screen: NSScreen) -> Bool {
if let screenUuid = screen.uuid(), let screenSpaces = Spaces.screenSpacesMap[screenUuid] {
return screenSpaces.contains { $0 == window.spaceId }
}
return true
}

static func checkIfShortcutsShouldBeDisabled(_ activeWindow: Window) {
let shortcutsShouldBeDisabled = (!Preferences.disableShortcutsBlacklistOnlyFullscreen || activeWindow.isFullscreen) &&
(Preferences.disableShortcutsBlacklist.first { blacklistedId in
if let id = activeWindow.application.runningApplication.bundleIdentifier {
return id.hasPrefix(blacklistedId)
}
return false
} != nil)
KeyboardEvents.toggleGlobalShortcuts(shortcutsShouldBeDisabled)
if shortcutsShouldBeDisabled && App.app.appIsBeingUsed {
App.app.hideUi()
}
}
}

func sortByBooleanAttribute(_ b1: Bool, _ b2: Bool) -> Bool? {
Expand Down
20 changes: 9 additions & 11 deletions src/logic/events/AccessibilityEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,16 @@ fileprivate func focusedUiElementChanged(_ pid: pid_t) 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 {
let appFocusedWindow = try element.focusedWindow()
let wid = try appFocusedWindow?.cgWindowId()
DispatchQueue.main.async {
if let app = (Applications.list.first { $0.pid == pid }) {
if !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) {
Windows.checkIfShortcutsShouldBeDisabled(window.first!)
App.app.refreshOpenUi(window)
}
let window = (appFocusedWindow != nil && wid != nil) ? Windows.updateLastFocus(appFocusedWindow!, wid!)?.first : nil
App.app.checkIfShortcutsShouldBeDisabled(window, app.runningApplication)
App.app.refreshOpenUi(window != nil ? [window!] : nil)
}
}
}
Expand Down Expand Up @@ -187,7 +185,7 @@ fileprivate func windowResized(_ element: AXUIElement) throws {
if let window = (Windows.list.first { $0.isEqualRobust(element, wid) }) {
if window.isFullscreen != isFullscreen {
window.isFullscreen = isFullscreen
Windows.checkIfShortcutsShouldBeDisabled(window)
App.app.checkIfShortcutsShouldBeDisabled(window, nil)
}
App.app.refreshOpenUi([window])
}
Expand Down
15 changes: 15 additions & 0 deletions src/ui/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,19 @@ class App: AppCenterApplication, NSApplicationDelegate {
Applications.refreshBadges()
KeyRepeatTimer.toggleRepeatingKeyNextWindow()
}

func checkIfShortcutsShouldBeDisabled(_ activeWindow: Window?, _ activeApp: NSRunningApplication?) {
let app = activeWindow?.application.runningApplication ?? activeApp
let shortcutsShouldBeDisabled = (!Preferences.disableShortcutsBlacklistOnlyFullscreen || (activeWindow?.isFullscreen ?? false)) &&
(Preferences.disableShortcutsBlacklist.first { blacklistedId in
if let id = app?.bundleIdentifier {
return id.hasPrefix(blacklistedId)
}
return false
} != nil)
KeyboardEvents.toggleGlobalShortcuts(shortcutsShouldBeDisabled)
if shortcutsShouldBeDisabled && App.app.appIsBeingUsed {
App.app.hideUi()
}
}
}
13 changes: 12 additions & 1 deletion src/ui/main-window/ThumbnailsPanel.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Cocoa

class ThumbnailsPanel: NSPanel {
class ThumbnailsPanel: NSPanel, NSWindowDelegate {
var thumbnailsView = ThumbnailsView()
override var canBecomeKey: Bool { true }

convenience init() {
self.init(contentRect: .zero, styleMask: .nonactivatingPanel, backing: .buffered, defer: false)
delegate = self
isFloatingPanel = true
updateFadeOutAnimation()
hidesOnDeactivate = false
Expand All @@ -24,6 +25,16 @@ class ThumbnailsPanel: NSPanel {
setAccessibilitySubrole(.unknown)
}

func windowDidResignKey(_ notification: Notification) {
// other windows can steal key focus from alt-tab; we make sure that if it's active, if keeps key focus
// dispatching to the main queue is necessary to introduce a delay in scheduling the makeKey; otherwise it is ignored
DispatchQueue.main.async {
if App.app.appIsBeingUsed {
App.app.thumbnailsPanel.makeKeyAndOrderFront(nil)
}
}
}

func updateFadeOutAnimation() {
animationBehavior = Preferences.fadeOutAnimation ? .utilityWindow : .none
}
Expand Down
6 changes: 0 additions & 6 deletions src/ui/permission-window/PermissionsWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ class PermissionsWindow: NSWindow, NSWindowDelegate {
setupView()
}

func show() {
center()
App.shared.activate(ignoringOtherApps: true)
makeKeyAndOrderFront(nil)
}

func windowShouldClose(_ sender: NSWindow) -> Bool {
debugPrint("Before using this app, you need to give permission in System Preferences > Security & Privacy > Privacy > Accessibility.",
"Please authorize and re-launch.",
Expand Down

0 comments on commit 6be72f3

Please sign in to comment.