macos: setup sequence for SplitTree

This commit is contained in:
Mitchell Hashimoto
2025-06-03 15:57:01 -07:00
parent 672d276276
commit 33d94521ea
3 changed files with 53 additions and 28 deletions

View File

@@ -350,3 +350,30 @@ extension SplitTree.Node: Equatable {
} }
} }
} }
// MARK: SplitTree Sequences
extension SplitTree.Node {
/// Returns all leaf views in this subtree
func leaves() -> [NSView] {
switch self {
case .leaf(let view):
return [view]
case .split(let split):
return split.left.leaves() + split.right.leaves()
}
}
}
extension SplitTree: Sequence {
func makeIterator() -> [NSView].Iterator {
return root?.leaves().makeIterator() ?? [].makeIterator()
}
}
extension SplitTree.Node: Sequence {
func makeIterator() -> [NSView].Iterator {
return leaves().makeIterator()
}
}

View File

@@ -175,16 +175,16 @@ class BaseTerminalController: NSWindowController,
/// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about /// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about
/// what surface is focused. This must be called whenever a surface OR window changes focus. /// what surface is focused. This must be called whenever a surface OR window changes focus.
func syncFocusToSurfaceTree() { func syncFocusToSurfaceTree() {
guard let tree = self.surfaceTree else { return } for view in surfaceTree2 {
if let surfaceView = view as? Ghostty.SurfaceView {
for leaf in tree {
// Our focus state requires that this window is key and our currently // Our focus state requires that this window is key and our currently
// focused surface is the surface in this leaf. // focused surface is the surface in this view.
let focused: Bool = (window?.isKeyWindow ?? false) && let focused: Bool = (window?.isKeyWindow ?? false) &&
!commandPaletteIsShowing && !commandPaletteIsShowing &&
focusedSurface != nil && focusedSurface != nil &&
leaf.surface == focusedSurface! surfaceView == focusedSurface!
leaf.surface.focusDidChange(focused) surfaceView.focusDidChange(focused)
}
} }
} }
@@ -387,21 +387,19 @@ class BaseTerminalController: NSWindowController,
} }
private func localEventFlagsChanged(_ event: NSEvent) -> NSEvent? { private func localEventFlagsChanged(_ event: NSEvent) -> NSEvent? {
// Go through all our surfaces and notify it that the flags changed. // Also update surfaceTree2
if let surfaceTree { var surfaces2: [Ghostty.SurfaceView] = surfaceTree2.compactMap { $0 as? Ghostty.SurfaceView }
var surfaces: [Ghostty.SurfaceView] = surfaceTree.map { $0.surface }
// If we're the main window receiving key input, then we want to avoid // If we're the main window receiving key input, then we want to avoid
// calling this on our focused surface because that'll trigger a double // calling this on our focused surface because that'll trigger a double
// flagsChanged call. // flagsChanged call.
if NSApp.mainWindow == window { if NSApp.mainWindow == window {
surfaces = surfaces.filter { $0 != focusedSurface } surfaces2 = surfaces2.filter { $0 != focusedSurface }
} }
for surface in surfaces { for surface in surfaces2 {
surface.flagsChanged(with: event) surface.flagsChanged(with: event)
} }
}
return event return event
} }
@@ -675,10 +673,10 @@ class BaseTerminalController: NSWindowController,
} }
func windowDidChangeOcclusionState(_ notification: Notification) { func windowDidChangeOcclusionState(_ notification: Notification) {
guard let surfaceTree = self.surfaceTree else { return }
let visible = self.window?.occlusionState.contains(.visible) ?? false let visible = self.window?.occlusionState.contains(.visible) ?? false
for leaf in surfaceTree { for view in surfaceTree2 {
if let surface = leaf.surface.surface { if let surfaceView = view as? Ghostty.SurfaceView,
let surface = surfaceView.surface {
ghostty_surface_set_occlusion(surface, visible) ghostty_surface_set_occlusion(surface, visible)
} }
} }

View File

@@ -11,7 +11,7 @@ extension Ghostty {
/// "container" which has a recursive top/left SplitNode and bottom/right SplitNode. These /// "container" which has a recursive top/left SplitNode and bottom/right SplitNode. These
/// values can further be split infinitely. /// values can further be split infinitely.
/// ///
enum SplitNode: Equatable, Hashable, Codable, Sequence { enum SplitNode: Equatable, Hashable, Codable {
case leaf(Leaf) case leaf(Leaf)
case split(Container) case split(Container)