Keep browser webviews alive during drag reparenting
This commit is contained in:
parent
a40c5af4b5
commit
52bd8cf16a
2 changed files with 39 additions and 16 deletions
|
|
@ -2390,7 +2390,28 @@ final class WindowBrowserPortal: NSObject {
|
|||
reason: reason
|
||||
)
|
||||
}
|
||||
func preserveVisibleDuringTransientDetach(reason: String) -> Bool {
|
||||
guard entry.visibleInUI, !containerView.isHidden else { return false }
|
||||
let didScheduleTransientRecovery = scheduleTransientRecoveryRetryIfNeeded(
|
||||
forWebViewId: webViewId,
|
||||
entry: &entry,
|
||||
webView: webView,
|
||||
reason: reason
|
||||
)
|
||||
guard didScheduleTransientRecovery else { return false }
|
||||
#if DEBUG
|
||||
dlog(
|
||||
"browser.portal.hidden.deferKeep web=\(browserPortalDebugToken(webView)) " +
|
||||
"reason=\(reason) frame=\(browserPortalDebugFrame(containerView.frame))"
|
||||
)
|
||||
#endif
|
||||
containerView.setDropZoneOverlay(zone: nil)
|
||||
return true
|
||||
}
|
||||
guard let anchorView = entry.anchorView, let window else {
|
||||
if preserveVisibleDuringTransientDetach(reason: "missingAnchorOrWindow") {
|
||||
return
|
||||
}
|
||||
if scheduleTransientDetachRecovery(reason: "missingAnchorOrWindow") {
|
||||
hideContainerView(reason: "missingAnchorOrWindow")
|
||||
return
|
||||
|
|
@ -2415,21 +2436,15 @@ final class WindowBrowserPortal: NSObject {
|
|||
anchorView.window == nil &&
|
||||
anchorView.superview != nil
|
||||
if isOffWindowReparent {
|
||||
let didScheduleTransientRecovery = scheduleTransientRecoveryRetryIfNeeded(
|
||||
forWebViewId: webViewId,
|
||||
entry: &entry,
|
||||
webView: webView,
|
||||
reason: "anchorWindowMismatch"
|
||||
)
|
||||
#if DEBUG
|
||||
if didScheduleTransientRecovery && !containerView.isHidden {
|
||||
dlog(
|
||||
"browser.portal.hidden.deferKeep web=\(browserPortalDebugToken(webView)) " +
|
||||
"reason=anchorWindowMismatch.offWindow frame=\(browserPortalDebugFrame(containerView.frame))"
|
||||
)
|
||||
if preserveVisibleDuringTransientDetach(reason: "anchorWindowMismatch.offWindow") {
|
||||
return
|
||||
}
|
||||
#endif
|
||||
containerView.setDropZoneOverlay(zone: nil)
|
||||
if scheduleTransientDetachRecovery(reason: "anchorWindowMismatch") {
|
||||
hideContainerView(reason: "anchorWindowMismatch")
|
||||
return
|
||||
}
|
||||
}
|
||||
if preserveVisibleDuringTransientDetach(reason: "anchorWindowMismatch") {
|
||||
return
|
||||
}
|
||||
if scheduleTransientDetachRecovery(reason: "anchorWindowMismatch") {
|
||||
|
|
|
|||
|
|
@ -4264,6 +4264,11 @@ struct WebViewRepresentable: NSViewRepresentable {
|
|||
}
|
||||
|
||||
private static func installPortalAnchorView(_ anchorView: NSView, in host: NSView) {
|
||||
// SwiftUI can keep transient replacement hosts alive off-window during split
|
||||
// reparenting. Never let those hosts steal the shared portal anchor, or the
|
||||
// portal will bind against an anchor with no real window and WKWebView will
|
||||
// fall into a hidden/unrendered state.
|
||||
guard host.window != nil else { return }
|
||||
if anchorView.superview !== host {
|
||||
anchorView.removeFromSuperview()
|
||||
anchorView.frame = host.bounds
|
||||
|
|
@ -4288,13 +4293,15 @@ struct WebViewRepresentable: NSViewRepresentable {
|
|||
let paneDropContext = shouldAttachWebView ? currentPaneDropContext() : nil
|
||||
let activeSearchOverlay = shouldAttachWebView ? searchOverlay : nil
|
||||
let portalAnchorView = panel.portalAnchorView
|
||||
Self.installPortalAnchorView(portalAnchorView, in: host)
|
||||
if host.window != nil {
|
||||
Self.installPortalAnchorView(portalAnchorView, in: host)
|
||||
}
|
||||
|
||||
host.onDidMoveToWindow = { [weak host, weak webView, weak coordinator, weak portalAnchorView] in
|
||||
guard let host, let webView, let coordinator, let portalAnchorView else { return }
|
||||
guard coordinator.attachGeneration == generation else { return }
|
||||
Self.installPortalAnchorView(portalAnchorView, in: host)
|
||||
guard host.window != nil else { return }
|
||||
Self.installPortalAnchorView(portalAnchorView, in: host)
|
||||
BrowserWindowPortalRegistry.bind(
|
||||
webView: webView,
|
||||
to: portalAnchorView,
|
||||
|
|
@ -4314,6 +4321,7 @@ struct WebViewRepresentable: NSViewRepresentable {
|
|||
guard let host, let webView, let coordinator, let portalAnchorView else { return }
|
||||
guard coordinator.attachGeneration == generation else { return }
|
||||
guard coordinator.lastPortalHostId == ObjectIdentifier(host) else { return }
|
||||
guard host.window != nil else { return }
|
||||
Self.installPortalAnchorView(portalAnchorView, in: host)
|
||||
if host.window != nil,
|
||||
!BrowserWindowPortalRegistry.isWebView(webView, boundTo: portalAnchorView) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue