diff --git a/Sources/BrowserWindowPortal.swift b/Sources/BrowserWindowPortal.swift index 92ba0fe0..ac1048cf 100644 --- a/Sources/BrowserWindowPortal.swift +++ b/Sources/BrowserWindowPortal.swift @@ -2786,9 +2786,11 @@ final class WindowBrowserPortal: NSObject { } return } + let previousTransientRecoveryReason = entry.transientRecoveryReason func hideContainerView(reason: String) { containerView.setPaneTopChromeHeight(0) containerView.setSearchOverlay(nil) + containerView.setPaneDropContext(nil) containerView.setDropZoneOverlay(zone: nil) if !containerView.isHidden, webView.superview === containerView { webView.browserPortalNotifyHidden(reason: reason) @@ -2819,6 +2821,7 @@ final class WindowBrowserPortal: NSObject { "reason=\(reason) frame=\(browserPortalDebugFrame(containerView.frame))" ) #endif + containerView.setPaneDropContext(nil) containerView.setDropZoneOverlay(zone: nil) return true } @@ -2962,6 +2965,8 @@ final class WindowBrowserPortal: NSObject { "reason=hostBoundsNotReady frame=\(browserPortalDebugFrame(containerView.frame))" ) #endif + containerView.setPaneDropContext(nil) + containerView.setDropZoneOverlay(zone: nil) return } } else { @@ -3024,6 +3029,9 @@ final class WindowBrowserPortal: NSObject { shouldHide && entry.visibleInUI && !containerView.isHidden + let recoveredFromTransientGeometry = + previousTransientRecoveryReason != nil && + transientRecoveryReason == nil #if DEBUG let frameWasClamped = hasFiniteFrame && !Self.rectApproximatelyEqual(frameInHost, targetFrame) if frameWasClamped { @@ -3152,10 +3160,16 @@ final class WindowBrowserPortal: NSObject { } containerView.setPaneTopChromeHeight(shouldHide ? 0 : entry.paneTopChromeHeight) containerView.setSearchOverlay(shouldHide ? nil : entry.searchOverlay) + containerView.setPaneDropContext(containerView.isHidden ? nil : entry.paneDropContext) containerView.setDropZoneOverlay(zone: containerView.isHidden ? nil : entry.dropZone) if revealedForDisplay { refreshReasons.append("reveal") } + if recoveredFromTransientGeometry { + // Drag/reparent churn can recover to the same visible frame we preserved. + // Force a redraw so WebKit doesn't keep stale tiles until a later resize/focus. + refreshReasons.append("transientRecovery") + } if forcePresentationRefresh { refreshReasons.append("anchor") } diff --git a/Sources/Workspace.swift b/Sources/Workspace.swift index 3f9e25ff..ed48b3a0 100644 --- a/Sources/Workspace.swift +++ b/Sources/Workspace.swift @@ -4896,6 +4896,21 @@ extension Workspace: BonsplitDelegate { "originalKinds=[\(paneKindSummary(originalPane))] newKinds=[\(paneKindSummary(newPane))]" ) #endif + let rearmBrowserPortalHostReplacement: (PaneID, String) -> Void = { paneId, reason in + for tab in controller.tabs(inPane: paneId) { + guard let panelId = self.panelIdFromSurfaceId(tab.id), + let browserPanel = self.browserPanel(for: panelId) else { + continue + } + browserPanel.preparePortalHostReplacementForNextDistinctClaim( + inPane: paneId, + reason: reason + ) + } + } + rearmBrowserPortalHostReplacement(originalPane, "workspace.didSplit.original") + rearmBrowserPortalHostReplacement(newPane, "workspace.didSplit.new") + // Only auto-create a terminal if the split came from bonsplit UI. // Programmatic splits via newTerminalSplit() set isProgrammaticSplit and handle their own panels. guard !isProgrammaticSplit else {