macOS: fix surface focus/render state after dragging in to to another window/tab (#12338)
Fixes 2 bugs 1. After dragging a non-focused surface from window A to window B **quickly without making B the key window**, the focused surface in window A is not receiving `keyDown` events. https://github.com/user-attachments/assets/a8861c0a-9300-470d-bf7e-0f32a9ab2cd1 2. #12343 After dragging a surface from tab A to tab B within the same window, the dragged surface is not rendering input correctly. > The reason the thread is stuck is because the surface's occlusion state is set to invisible after target tab's activate while dragging, since the dragged surface is still in previous tree before dropping, and after dropping the occlusion state of this surface is not updated to visible, which causing the surface is accepting input but not rendering. https://github.com/user-attachments/assets/d67f5dba-8609-4f67-a956-921982faf796pull/12779/head
commit
3e3705b932
|
|
@ -292,6 +292,7 @@ class BaseTerminalController: NSWindowController,
|
|||
if to.isEmpty {
|
||||
focusedSurface = nil
|
||||
}
|
||||
syncSurfaceTreeOcclusionState()
|
||||
}
|
||||
|
||||
/// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about
|
||||
|
|
@ -470,8 +471,12 @@ class BaseTerminalController: NSWindowController,
|
|||
|
||||
replaceSurfaceTree(
|
||||
surfaceTree.removing(node),
|
||||
moveFocusTo: nextFocus,
|
||||
moveFocusFrom: focusedSurface,
|
||||
// When a non-focused surface is removed and this window stays as the key window,
|
||||
// we should refocus the `focusedSurface` to make sure the window's firstResponder remains as it is.
|
||||
//
|
||||
// This is a weird workaround, since `resignFirstResponder` wasn't called on `focusedSurface` after drag,
|
||||
// but the first responder became the window itself.
|
||||
moveFocusTo: nextFocus ?? focusedSurface,
|
||||
undoAction: "Close Terminal"
|
||||
)
|
||||
}
|
||||
|
|
@ -1277,10 +1282,15 @@ class BaseTerminalController: NSWindowController,
|
|||
}
|
||||
|
||||
func windowDidChangeOcclusionState(_ notification: Notification) {
|
||||
syncSurfaceTreeOcclusionState()
|
||||
}
|
||||
|
||||
private func syncSurfaceTreeOcclusionState() {
|
||||
let visible = self.window?.occlusionState.contains(.visible) ?? false
|
||||
for view in surfaceTree {
|
||||
if let surface = view.surface {
|
||||
if let surface = view.surface, view.isWindowVisible != visible {
|
||||
ghostty_surface_set_occlusion(surface, visible)
|
||||
view.isWindowVisible = visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@ extension Ghostty {
|
|||
// Whether the cursor is currently visible (not hidden by typing, etc.)
|
||||
@Published private(set) var cursorVisible: Bool = true
|
||||
|
||||
/// Whether the belonging window is visible
|
||||
///
|
||||
/// We track this to restore surface occlusion state
|
||||
/// after this surface is dragged to another window
|
||||
var isWindowVisible = false
|
||||
|
||||
/// The configuration derived from the Ghostty config so we don't need to rely on references.
|
||||
@Published private(set) var derivedConfig: DerivedConfig
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue