Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public import AppKit
public final class ChildPageFocus {
/// The page this window gave focus to (blurred when focus leaves it), held weakly.
public weak var page: AnyObject?
/// A grant is running (``focus(_:)``).
private var granting = false
private let keys: any KeyWindowSwitching
/// Gives (true) or takes (false) a page's focus; giving a Chromium page focus makes its window key.
private let setFocus: (AnyObject, Bool) -> Void
Expand All @@ -50,6 +52,8 @@ public final class ChildPageFocus {
guard page !== next else { return }
blurPage()
page = next
granting = true
defer { granting = false }
setFocus(next, true)
}

Expand Down Expand Up @@ -81,13 +85,16 @@ public final class ChildPageFocus {

/// `window` takes the keys back from another key window that `shouldReclaim` accepts.
///
/// No change when `window` is key already or no window is key (an inactive app).
/// No change when `window` is key already, no window is key (an inactive app), or inside the grant
/// of a page that still has focus: its page window took the keys from that grant (AppKit's
/// didBecomeKey), and taking them back would leave the page focused with no keys. Once the page
/// blurred (focus moved on inside the grant), the keys come back.
///
/// - Parameters:
/// - window: The cmux window.
/// - shouldReclaim: Whether `window` takes the keys from this key window.
public func reclaim(into window: NSWindow, when shouldReclaim: (NSWindow) -> Bool) {
guard !keys.isKey(window), let key = keys.keyWindow, key !== window, shouldReclaim(key) else { return }
guard !(granting && page != nil), !keys.isKey(window), let key = keys.keyWindow, key !== window, shouldReclaim(key) else { return }
keys.makeKey(window)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ struct ChildPageFocusKeyChangeTests {
#expect(world.focusCalls.count == 1)
}

/// Focus leaves the page inside its grant (the model moved on to a terminal): the page blurs and
/// the cmux window takes the keys back, grant or not.
@Test func reclaimInsideTheGrantAfterThePageBlurredTakesTheKeysBack() {
let world = World()
world.duringGrant = { [weak world] in
guard let world else { return }
world.focus.blurPage()
world.reclaim()
}
world.focus.focus(world.b)
#expect(world.keys.changes == ["pageB", "cmux"], "the keys stayed on the blurred page: \(world.keys.changes)")
#expect(world.focus.page == nil)
}

@Test func reclaimMakesNoKeyChangeWhenTheCmuxWindowIsKey() {
let world = World()
world.keys.makeKey(world.cmux)
Expand Down
Loading