Skip to content

Commit

Permalink
Further attempts to fix space moving focus loss (#1591)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianyh committed Jan 25, 2024
1 parent 725502b commit 4cff96b
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class BinarySpacePartitioningLayout<Window: WindowType>: StatefulLayout<Window>

windowNode.windowID = otherWindowID
otherWindowNode.windowID = windowID
case .applicationDeactivate, .applicationActivate, .spaceChange, .layoutChange, .unknown:
case .applicationDeactivate, .applicationActivate, .spaceChange, .layoutChange, .tabChange, .none, .unknown:
break
}
}
Expand Down
4 changes: 4 additions & 0 deletions Amethyst/Layout/Layouts/CustomLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,12 @@ class CustomLayout<Window: WindowType>: StatefulLayout<Window> {
jsChange["change"] = "space_change"
case .layoutChange:
jsChange["change"] = "layout_change"
case .tabChange:
jsChange["change"] = "tab_change"
case .unknown:
jsChange["change"] = "unknown"
case .none:
jsChange["change"] = "none"
}

return jsChange
Expand Down
2 changes: 1 addition & 1 deletion Amethyst/Managers/ScreenManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ final class ScreenManager<Delegate: ScreenManagerDelegate>: NSObject, Codable {
if lastFocusedWindow == window {
lastFocusedWindow = nil
}
case .windowSwap, .applicationActivate, .applicationDeactivate, .spaceChange, .layoutChange, .unknown:
case .windowSwap, .applicationActivate, .applicationDeactivate, .spaceChange, .layoutChange, .tabChange, .none, .unknown:
break
}

Expand Down
25 changes: 21 additions & 4 deletions Amethyst/Managers/WindowManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ final class WindowManager<Application: ApplicationType>: NSObject, Codable {
guard let focusedWindow = Window.currentlyFocused(), let screen = focusedWindow.screen() else {
return
}
markScreen(screen, forReflowWithChange: .unknown)
markScreen(screen, forReflowWithChange: .applicationActivate)
// doMouseFollowsFocus(focusedWindow: focusedWindow)
}

Expand Down Expand Up @@ -374,11 +374,12 @@ extension WindowManager {
for runningApplication in NSWorkspace.shared.runningApplications {
add(runningApplication: runningApplication)
}
markAllScreensForReflow(withChange: .unknown)
markAllScreensForReflow(withChange: .none)
}

private func add(window: Window, retries: Int = 5) {
guard !windows.isWindowTracked(window) else {
log.warning("skipping window")
return
}

Expand Down Expand Up @@ -467,7 +468,7 @@ extension WindowManager {
add(window: window)
executeTransition(.switchWindows(existingWindow, window))
windows.regenerateActiveIDCache()
markScreen(screen, forReflowWithChange: .unknown)
markScreen(screen, forReflowWithChange: .tabChange)

return
}
Expand Down Expand Up @@ -730,6 +731,22 @@ extension WindowManager: WindowTransitionTarget {
guard let targetScreen = CGSpacesInfo<Window>.screenForSpace(space: targetSpace) else {
return
}
if window.isFocused() {
if activeWindows(on: screen).count == 1,
let finder = NSWorkspace.shared.runningApplications.first(where: { $0.bundleIdentifier == "com.apple.finder" }) {
var psn = ProcessSerialNumber()
let status = GetProcessForPID(finder.processIdentifier, &psn)
if status != noErr {
log.error(status)
}
let cgStatus = _SLPSSetFrontProcessWithOptions(&psn, 0, kCPSNoWindows)
if cgStatus != .success {
log.error(cgStatus.rawValue)
}
} else {
focusTransitionCoordinator.moveFocusClockwise()
}
}
markScreen(screen, forReflowWithChange: .remove(window: window))
window.move(toSpace: targetSpace.id)
if targetScreen.screenID() != screen.screenID() {
Expand All @@ -739,10 +756,10 @@ extension WindowManager: WindowTransitionTarget {
window.setFrame(newFrame, withThreshold: CGSize(width: 25, height: 25))
}
}
markScreen(targetScreen, forReflowWithChange: .add(window: window))
if UserConfiguration.shared.followWindowsThrownBetweenSpaces() {
window.focus()
}
markScreen(targetScreen, forReflowWithChange: .add(window: window))
case .resetFocus:
if let screen = screens.screenManagers.first?.screen {
executeTransition(.focusScreen(screen))
Expand Down
2 changes: 2 additions & 0 deletions Amethyst/Model/Change.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ enum Change<Window: WindowType> {
case applicationDeactivate
case spaceChange
case layoutChange
case tabChange
case none
case unknown
}
6 changes: 5 additions & 1 deletion Amethyst/Model/Window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ func _SLPSSetFrontProcessWithOptions(_ psn: inout ProcessSerialNumber, _ wid: UI
@_silgen_name("SLPSPostEventRecordTo") @discardableResult
func SLPSPostEventRecordTo(_ psn: inout ProcessSerialNumber, _ bytes: inout UInt8) -> CGError

@_silgen_name("SLSMoveWindowsToManagedSpace")
func SLSMoveWindowsToManagedSpace(_ cid: Int32, _ window_ids: CFArray, _ sid: Int)

let kCPSUserGenerated: UInt32 = 0x200
let kCPSNoWindows: UInt32 = 0x400
// swiftlint:enable identifier_name

/// Generic protocol for objects acting as windows in the system.
Expand Down Expand Up @@ -363,6 +367,6 @@ extension AXWindow: WindowType {
}

func move(toSpace spaceID: CGSSpaceID) {
CGSMoveWindowsToManagedSpace(CGSMainConnectionID(), [cgID()] as CFArray, spaceID)
SLSMoveWindowsToManagedSpace(CGSMainConnectionID(), [cgID()] as CFArray, spaceID)
}
}

0 comments on commit 4cff96b

Please sign in to comment.