Browse Source

Fix Auto Layout conflicts and MainActor isolation warnings.

Replace embedded browser width-collapse with NSStackView visibility toggling, remove deprecated WKProcessPool usage, and hop MainActor-safe for timer/notification callbacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
huzaifahayat12 4 days ago
parent
commit
c661584828

+ 6 - 2
zoom_app/Managers/MeetingRecordingManager.swift

@@ -335,11 +335,15 @@ final class MeetingRecordingManager: NSObject {
             object: nil,
             queue: .main
         ) { [weak self] note in
-            self?.handleZoomDesktopClientTerminated(note)
+            MainActor.assumeIsolated {
+                self?.handleZoomDesktopClientTerminated(note)
+            }
         }
 
         let timer = Timer(timeInterval: Self.automaticStopPollInterval, repeats: true) { [weak self] _ in
-            self?.automaticStopPresenceTimerFired()
+            MainActor.assumeIsolated {
+                self?.automaticStopPresenceTimerFired()
+            }
         }
         RunLoop.main.add(timer, forMode: .common)
         automaticStopTimer = timer

+ 2 - 1
zoom_app/Services/OAuthRedirectListener.swift

@@ -8,7 +8,8 @@ enum OAuthRedirectListenerError: Error {
 }
 
 /// Listens for a single OAuth redirect hit on `http://127.0.0.1:<port><pathPrefix>?...` and returns the full URL.
-final class OAuthRedirectListener {
+/// Opt out of default MainActor isolation — Network.framework callbacks run off the main thread.
+nonisolated final class OAuthRedirectListener: @unchecked Sendable {
     private let port: NWEndpoint.Port
     private let pathPrefix: String
     private var listener: NWListener?

+ 107 - 90
zoom_app/Views/ViewController.swift

@@ -33,8 +33,6 @@ private let embeddedZoomWebViewUserAgent =
 
 /// Shared cookie jar for embedded Zoom meetings and Zoom OAuth so the in-app browser reuses the same Zoom web session.
 private let zoomEmbeddedWebsiteDataStore = WKWebsiteDataStore.default()
-/// Shared renderer process so OAuth cookies are visible to the embedded meeting web client.
-private let zoomEmbeddedWebProcessPool = WKProcessPool()
 
 /// Errors from the main-window embedded OAuth web session (right panel).
 private enum EmbeddedOAuthFlowError: Error {
@@ -454,8 +452,11 @@ class ViewController: NSViewController {
     private weak var homeMainContentColumnView: NSView?
     private weak var embeddedBrowserBackButton: NSButton?
     private weak var embeddedBrowserForwardButton: NSButton?
-    private var embeddedBrowserPanelWidthConstraint: NSLayoutConstraint?
-    private var embeddedBrowserMainColumnCollapsedWidthConstraint: NSLayoutConstraint?
+    private var embeddedBrowserPanelWidthConstraint: NSLayoutConstraint? // unused; panel visibility is stack-driven
+    private var mainColumnVerticalFillConstraints: [NSLayoutConstraint] = []
+    private var webPanelVerticalFillConstraints: [NSLayoutConstraint] = []
+    /// Tracks expanded layout mode (NSStackView hides the inactive column out of Auto Layout).
+    private var isEmbeddedBrowserPanelExpanded = false
     private var oauthSessionContinuation: CheckedContinuation<URL, Error>?
     private var oauthSessionCallbackPrefix: String?
     /// ZAK + display name for the next embedded join; used to re-auth the web client if sign-in or guest join appears.
@@ -889,7 +890,7 @@ class ViewController: NSViewController {
             updatePaywallPanelSize()
             updatePaywallResponsiveLayout()
         }
-        if (embeddedBrowserPanelWidthConstraint?.constant ?? 0) > 0.5 {
+        if isEmbeddedBrowserPanelExpanded {
             updateEmbeddedRightPanelWidthForOpenState()
         }
         if aiCompanionPageRootView?.isHidden == false {
@@ -920,7 +921,9 @@ class ViewController: NSViewController {
             object: window,
             queue: .main
         ) { [weak self] _ in
-            self?.syncBrandPositionForCurrentWindowState(animated: true)
+            MainActor.assumeIsolated {
+                self?.syncBrandPositionForCurrentWindowState(animated: true)
+            }
         }
 
         let exitObserver = center.addObserver(
@@ -928,7 +931,9 @@ class ViewController: NSViewController {
             object: window,
             queue: .main
         ) { [weak self] _ in
-            self?.syncBrandPositionForCurrentWindowState(animated: true)
+            MainActor.assumeIsolated {
+                self?.syncBrandPositionForCurrentWindowState(animated: true)
+            }
         }
 
         windowFullScreenObservers = [enterObserver, exitObserver]
@@ -2600,9 +2605,11 @@ class ViewController: NSViewController {
         embeddedMeetingReachedInCallPage = false
         embeddedMeetingAbsentCallConsecutiveMisses = 0
         let timer = Timer(timeInterval: 1.0, repeats: true) { [weak self] _ in
-            guard let self else { return }
-            let webView = self.embeddedBrowserWebView
-            self.updateEmbeddedMeetingRecordingPresence(for: webView?.url, webViewTitle: webView?.title)
+            MainActor.assumeIsolated {
+                guard let self else { return }
+                let webView = self.embeddedBrowserWebView
+                self.updateEmbeddedMeetingRecordingPresence(for: webView?.url, webViewTitle: webView?.title)
+            }
         }
         RunLoop.main.add(timer, forMode: .common)
         embeddedMeetingRecordingMonitorTimer = timer
@@ -2639,8 +2646,7 @@ class ViewController: NSViewController {
         guard MeetingRecordingManager.shared.isRecording == false else { return }
         pendingZoomMeetingRecording = (normalizedEmbeddedJoinURL(for: sourceURL), meetingDisplayName)
         updateAiCompanionRecordingUI()
-        if embeddedBrowserWebView != nil,
-           (embeddedBrowserPanelWidthConstraint?.constant ?? 0) > 0.5 {
+        if embeddedBrowserWebView != nil, isEmbeddedBrowserPanelExpanded {
             startEmbeddedMeetingRecordingMonitorIfNeeded()
         }
     }
@@ -2689,7 +2695,7 @@ class ViewController: NSViewController {
 
     @MainActor
     private var isEmbeddedBrowserPanelOpen: Bool {
-        (embeddedBrowserPanelWidthConstraint?.constant ?? 0) > 0.5
+        isEmbeddedBrowserPanelExpanded
     }
 
     @MainActor
@@ -2745,24 +2751,28 @@ class ViewController: NSViewController {
         }
     }
 
-    /// Makes the embedded web panel fill the entire right-side content area (to match the reference behavior).
+    /// Expands the embedded web panel to fill the body row via stack arranged-subview hiding.
+    /// Never force `width == 0` — that fights WKWebView/toolbar intrinsic sizes (see console conflict log).
     @MainActor
     private func updateEmbeddedRightPanelWidthForOpenState() {
-        guard let widthConstraint = embeddedBrowserPanelWidthConstraint else { return }
+        if isEmbeddedBrowserPanelExpanded == false {
+            isEmbeddedBrowserPanelExpanded = true
+            NSLayoutConstraint.deactivate(mainColumnVerticalFillConstraints)
+            NSLayoutConstraint.activate(webPanelVerticalFillConstraints)
+            homeMainContentColumnView?.isHidden = true
+            embeddedBrowserPanel?.isHidden = false
+        }
         view.layoutSubtreeIfNeeded()
         view.window?.contentView?.layoutSubtreeIfNeeded()
-        var rowW = homeBodyRowView?.bounds.width ?? 0
-        if rowW < 1 {
-            rowW = view.bounds.width
-        }
-        // Right panel spans from (bodyRow.leading + gap) to bodyRow.trailing when the main column is collapsed (width 0).
-        // Using the full row width here over-constrains by the column gap and nudges the window wider.
-        let available = max(0, rowW - homeEmbeddedBrowserColumnGap)
-        widthConstraint.constant = max(320, floor(available))
+    }
 
-        // Collapse the left main content column while web is visible.
-        homeMainContentColumnView?.isHidden = true
-        embeddedBrowserMainColumnCollapsedWidthConstraint?.isActive = true
+    @MainActor
+    private func restoreEmbeddedBrowserClosedLayout() {
+        isEmbeddedBrowserPanelExpanded = false
+        NSLayoutConstraint.deactivate(webPanelVerticalFillConstraints)
+        NSLayoutConstraint.activate(mainColumnVerticalFillConstraints)
+        embeddedBrowserPanel?.isHidden = true
+        homeMainContentColumnView?.isHidden = false
     }
 
     @MainActor
@@ -2823,9 +2833,7 @@ class ViewController: NSViewController {
         }
         embeddedZoomPendingWebAuth = nil
         embeddedZoomPendingJoinURL = nil
-        embeddedBrowserPanelWidthConstraint?.constant = 0
-        embeddedBrowserMainColumnCollapsedWidthConstraint?.isActive = false
-        homeMainContentColumnView?.isHidden = false
+        restoreEmbeddedBrowserClosedLayout()
         refreshEmbeddedBrowserNavButtons()
         view.window?.contentView?.layoutSubtreeIfNeeded()
     }
@@ -2874,7 +2882,7 @@ class ViewController: NSViewController {
                 self.oauthSessionContinuation = nil
                 self.oauthSessionCallbackPrefix = nil
                 webView.stopLoading()
-                self.embeddedBrowserPanelWidthConstraint?.constant = 0
+                self.restoreEmbeddedBrowserClosedLayout()
                 self.refreshEmbeddedBrowserNavButtons()
                 webView.load(URLRequest(url: URL(string: "about:blank")!))
                 self.view.window?.contentView?.layoutSubtreeIfNeeded()
@@ -6146,12 +6154,14 @@ class ViewController: NSViewController {
         continueButtonWrap.translatesAutoresizingMaskIntoConstraints = false
         continueButtonWrap.addSubview(continueButton)
         planColumn.addArrangedSubview(continueButtonWrap)
+        let continuePreferredWidth = continueButton.widthAnchor.constraint(equalToConstant: 400)
+        continuePreferredWidth.priority = .defaultHigh
         NSLayoutConstraint.activate([
             continueButtonWrap.widthAnchor.constraint(equalTo: planColumn.widthAnchor),
             continueButton.topAnchor.constraint(equalTo: continueButtonWrap.topAnchor),
             continueButton.bottomAnchor.constraint(equalTo: continueButtonWrap.bottomAnchor),
             continueButton.centerXAnchor.constraint(equalTo: continueButtonWrap.centerXAnchor),
-            continueButton.widthAnchor.constraint(equalToConstant: 400),
+            continuePreferredWidth,
             continueButton.widthAnchor.constraint(lessThanOrEqualTo: continueButtonWrap.widthAnchor, constant: -40)
         ])
         planColumn.setCustomSpacing(16, after: continueButtonWrap)
@@ -6225,21 +6235,18 @@ class ViewController: NSViewController {
         planColumn.addArrangedSubview(footerWrap)
         footerWrap.widthAnchor.constraint(equalTo: planColumn.widthAnchor).isActive = true
 
-        // Keep a comfortable top margin, but center the paywall content vertically when there's room.
+        // Keep a comfortable top margin; center when there's room. Avoid dual required-style
+        // bottom anchors (centerY + bottomEq) which fight when content is taller than the panel.
         let contentTopMin = contentStack.topAnchor.constraint(greaterThanOrEqualTo: panel.topAnchor, constant: 84)
         let contentBottomMax = contentStack.bottomAnchor.constraint(lessThanOrEqualTo: panel.bottomAnchor, constant: -18)
         let contentCenterY = contentStack.centerYAnchor.constraint(equalTo: panel.centerYAnchor)
         contentCenterY.priority = .defaultLow
-
-        let contentBottomEq = contentStack.bottomAnchor.constraint(equalTo: panel.bottomAnchor, constant: -18)
-        contentBottomEq.priority = .defaultLow
         NSLayoutConstraint.activate([
             contentStack.leadingAnchor.constraint(equalTo: panel.leadingAnchor, constant: 70),
             contentStack.trailingAnchor.constraint(equalTo: panel.trailingAnchor, constant: -70),
             contentTopMin,
             contentBottomMax,
-            contentCenterY,
-            contentBottomEq
+            contentCenterY
         ])
 
         refreshPaywallStoreUI()
@@ -7207,11 +7214,16 @@ class ViewController: NSViewController {
         let schedulerEmptyLabel = makeLabel("No meetings scheduled for this date.", size: 15, color: secondaryText, weight: .regular, centered: true)
         schedulerEmptyLabel.isHidden = true
 
-        let bodyRow = NSView()
+        let bodyRow = NSStackView()
+        bodyRow.orientation = .horizontal
+        bodyRow.alignment = .top
+        bodyRow.distribution = .fill
+        bodyRow.spacing = homeEmbeddedBrowserColumnGap
         bodyRow.translatesAutoresizingMaskIntoConstraints = false
 
         let mainContentColumn = NSView()
         mainContentColumn.translatesAutoresizingMaskIntoConstraints = false
+        mainContentColumn.setContentHuggingPriority(.defaultLow, for: .horizontal)
         mainContentColumn.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
 
         let rightWebPanel = NSView()
@@ -7222,6 +7234,10 @@ class ViewController: NSViewController {
         rightWebPanel.layer?.backgroundColor = secondaryCardBackground.withAlphaComponent(0.94).cgColor
         rightWebPanel.layer?.borderWidth = 1
         rightWebPanel.layer?.borderColor = palette.inputBorder.cgColor
+        rightWebPanel.setContentHuggingPriority(.defaultLow, for: .horizontal)
+        rightWebPanel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
+        // Closed by default: stack hiding removes this column from Auto Layout (no width==0).
+        rightWebPanel.isHidden = true
 
         let webToolbar = NSView()
         webToolbar.translatesAutoresizingMaskIntoConstraints = false
@@ -7267,7 +7283,6 @@ class ViewController: NSViewController {
 
         let embeddedBrowserConfiguration = WKWebViewConfiguration()
         embeddedBrowserConfiguration.websiteDataStore = zoomEmbeddedWebsiteDataStore
-        embeddedBrowserConfiguration.processPool = zoomEmbeddedWebProcessPool
         embeddedBrowserConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = true
         embeddedBrowserConfiguration.mediaTypesRequiringUserActionForPlayback = []
         let meetingLifecycleController = WKUserContentController()
@@ -7290,16 +7305,12 @@ class ViewController: NSViewController {
         content.addSubview(topBar)
         content.addSubview(topBarDivider)
         content.addSubview(bodyRow)
-        bodyRow.addSubview(mainContentColumn)
-        bodyRow.addSubview(rightWebPanel)
+        bodyRow.addArrangedSubview(mainContentColumn)
+        bodyRow.addArrangedSubview(rightWebPanel)
         rightWebPanel.addSubview(webToolbar)
         webToolbar.addSubview(webToolBarStack)
         rightWebPanel.addSubview(embeddedWK)
 
-        let rightPanelWidthConstraint = rightWebPanel.widthAnchor.constraint(equalToConstant: 0)
-        let mainColumnCollapsedWidthConstraint = mainContentColumn.widthAnchor.constraint(equalToConstant: 0)
-        mainColumnCollapsedWidthConstraint.isActive = false
-
         [brandStack, searchRow, rightTopBarCluster, searchPill, searchField, searchIcon, searchHintLabel].forEach {
             $0.translatesAutoresizingMaskIntoConstraints = false
         }
@@ -7334,14 +7345,23 @@ class ViewController: NSViewController {
         meetingsDocument.addSubview(meetingsStack)
 
         let searchRowCenterX = searchRow.centerXAnchor.constraint(equalTo: topBar.centerXAnchor)
-        searchRowCenterX.priority = .defaultHigh
+        // Prefer centering, but yield when space is tight.
+        searchRowCenterX.priority = .defaultLow
 
         let brandLeading = brandStack.leadingAnchor.constraint(equalTo: shell.leadingAnchor, constant: brandLeadingInset)
         brandLeadingConstraint = brandLeading
 
+        // Prefer 610pt, but allow shrink.
+        let homeMeetingsPanelWidth = panel.widthAnchor.constraint(equalToConstant: 610)
+        homeMeetingsPanelWidth.priority = .defaultHigh
+
+        let searchPillWidth = searchPill.widthAnchor.constraint(equalToConstant: 320)
+        searchPillWidth.priority = .defaultHigh
+
         NSLayoutConstraint.activate([
+            // Brand is a shell overlay only — do not pin it to searchRow (cross-subtree constraints
+            // routinely conflict at launch with the centered search pill + auth cluster).
             brandLeading,
-            brandStack.trailingAnchor.constraint(lessThanOrEqualTo: searchRow.leadingAnchor, constant: -12),
             brandStack.centerYAnchor.constraint(equalTo: chromeHeader.centerYAnchor, constant: -1),
 
             topBar.topAnchor.constraint(equalTo: content.topAnchor),
@@ -7358,16 +7378,6 @@ class ViewController: NSViewController {
             bodyRow.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 8),
             bodyRow.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -8),
 
-            mainContentColumn.leadingAnchor.constraint(equalTo: bodyRow.leadingAnchor),
-            mainContentColumn.topAnchor.constraint(equalTo: bodyRow.topAnchor),
-            mainContentColumn.bottomAnchor.constraint(equalTo: bodyRow.bottomAnchor),
-            mainContentColumn.trailingAnchor.constraint(equalTo: rightWebPanel.leadingAnchor, constant: -homeEmbeddedBrowserColumnGap),
-
-            rightWebPanel.topAnchor.constraint(equalTo: bodyRow.topAnchor),
-            rightWebPanel.bottomAnchor.constraint(equalTo: bodyRow.bottomAnchor),
-            rightWebPanel.trailingAnchor.constraint(equalTo: bodyRow.trailingAnchor),
-            rightPanelWidthConstraint,
-
             webToolbar.leadingAnchor.constraint(equalTo: rightWebPanel.leadingAnchor),
             webToolbar.trailingAnchor.constraint(equalTo: rightWebPanel.trailingAnchor),
             webToolbar.topAnchor.constraint(equalTo: rightWebPanel.topAnchor),
@@ -7385,14 +7395,13 @@ class ViewController: NSViewController {
             searchRowCenterX,
             searchRow.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
             searchRow.leadingAnchor.constraint(greaterThanOrEqualTo: topBar.leadingAnchor, constant: 40),
-            searchRow.leadingAnchor.constraint(greaterThanOrEqualTo: brandStack.trailingAnchor, constant: 16),
             searchRow.trailingAnchor.constraint(lessThanOrEqualTo: rightTopBarCluster.leadingAnchor, constant: -12),
 
             rightTopBarCluster.trailingAnchor.constraint(equalTo: topBar.trailingAnchor, constant: -12),
             rightTopBarCluster.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
 
             searchPill.heightAnchor.constraint(equalToConstant: 32),
-            searchPill.widthAnchor.constraint(equalToConstant: 320),
+            searchPillWidth,
             searchIcon.leadingAnchor.constraint(equalTo: searchPill.leadingAnchor, constant: 12),
             searchIcon.centerYAnchor.constraint(equalTo: searchPill.centerYAnchor),
             searchIcon.widthAnchor.constraint(equalToConstant: 16),
@@ -7418,7 +7427,7 @@ class ViewController: NSViewController {
 
             panel.topAnchor.constraint(equalTo: actions.bottomAnchor, constant: 18),
             panel.centerXAnchor.constraint(equalTo: mainContentColumn.centerXAnchor),
-            panel.widthAnchor.constraint(equalToConstant: 610),
+            homeMeetingsPanelWidth,
             panel.leadingAnchor.constraint(greaterThanOrEqualTo: mainContentColumn.leadingAnchor, constant: 6),
             panel.trailingAnchor.constraint(lessThanOrEqualTo: mainContentColumn.trailingAnchor, constant: -6),
             panel.heightAnchor.constraint(greaterThanOrEqualToConstant: 280),
@@ -7634,8 +7643,16 @@ class ViewController: NSViewController {
         embeddedBrowserPanel = rightWebPanel
         homeBodyRowView = bodyRow
         homeMainContentColumnView = mainContentColumn
-        embeddedBrowserPanelWidthConstraint = rightPanelWidthConstraint
-        embeddedBrowserMainColumnCollapsedWidthConstraint = mainColumnCollapsedWidthConstraint
+        embeddedBrowserPanelWidthConstraint = nil
+        mainColumnVerticalFillConstraints = [
+            mainContentColumn.topAnchor.constraint(equalTo: bodyRow.topAnchor),
+            mainContentColumn.bottomAnchor.constraint(equalTo: bodyRow.bottomAnchor)
+        ]
+        webPanelVerticalFillConstraints = [
+            rightWebPanel.topAnchor.constraint(equalTo: bodyRow.topAnchor),
+            rightWebPanel.bottomAnchor.constraint(equalTo: bodyRow.bottomAnchor)
+        ]
+        NSLayoutConstraint.activate(mainColumnVerticalFillConstraints)
         embeddedBrowserBackButton = browserBack
         embeddedBrowserForwardButton = browserForward
         refreshEmbeddedBrowserNavButtons()
@@ -9214,36 +9231,35 @@ class ViewController: NSViewController {
     private func setupWidgetBridge() {
         let center = NotificationCenter.default
         center.addObserver(forName: .widgetOpenHomePage, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarShowSection(.home)
+            MainActor.assumeIsolated { self?.menuBarShowSection(.home) }
         }
         center.addObserver(forName: .widgetOpenMeetingsPage, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarShowSection(.meetings)
+            MainActor.assumeIsolated { self?.menuBarShowSection(.meetings) }
         }
         center.addObserver(forName: .widgetOpenSchedulerPage, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarShowSection(.scheduler)
+            MainActor.assumeIsolated { self?.menuBarShowSection(.scheduler) }
         }
         center.addObserver(forName: .widgetOpenWidgetsPage, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarShowSection(.widgets)
+            MainActor.assumeIsolated { self?.menuBarShowSection(.widgets) }
         }
         center.addObserver(forName: .widgetOpenSettingsPage, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarShowSection(.settings)
+            MainActor.assumeIsolated { self?.menuBarShowSection(.settings) }
         }
         center.addObserver(forName: .widgetStartNewMeetingRequested, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarTriggerNewMeeting()
+            MainActor.assumeIsolated { self?.menuBarTriggerNewMeeting() }
         }
         center.addObserver(forName: .widgetJoinMeetingRequested, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarTriggerJoinMeeting()
+            MainActor.assumeIsolated { self?.menuBarTriggerJoinMeeting() }
         }
         center.addObserver(forName: .widgetScheduleMeetingRequested, object: nil, queue: .main) { [weak self] _ in
-            self?.menuBarTriggerScheduleMeeting()
+            MainActor.assumeIsolated { self?.menuBarTriggerScheduleMeeting() }
         }
         center.addObserver(forName: .widgetRefreshRequested, object: nil, queue: .main) { [weak self] _ in
-            self?.triggerMeetingsRefresh(force: true)
+            MainActor.assumeIsolated { self?.triggerMeetingsRefresh(force: true) }
         }
         center.addObserver(forName: .widgetOpenMeetingLinkRequested, object: nil, queue: .main) { [weak self] notification in
-            guard let self else { return }
             guard let link = notification.userInfo?["link"] as? String else { return }
-            self.joinZoomMeetingFromLink(link, displayName: nil)
+            MainActor.assumeIsolated { self?.joinZoomMeetingFromLink(link, displayName: nil) }
         }
     }
 
@@ -10152,7 +10168,9 @@ class ViewController: NSViewController {
     private func makeActionTile(title: String, symbol: String, color: NSColor, action: Selector? = nil) -> NSView {
         let root = HoverTileView()
         root.translatesAutoresizingMaskIntoConstraints = false
-        root.widthAnchor.constraint(equalToConstant: 88).isActive = true
+        let tileWidth = root.widthAnchor.constraint(equalToConstant: 88)
+        tileWidth.priority = .defaultHigh
+        tileWidth.isActive = true
         // Give caption text a little more vertical room so descenders (e.g. "g") are never clipped.
         root.heightAnchor.constraint(equalToConstant: 76).isActive = true
 
@@ -10339,20 +10357,24 @@ extension ViewController: WKNavigationDelegate, WKUIDelegate {
 
     func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
         guard webView === embeddedBrowserWebView else { return }
-        updateEmbeddedMeetingRecordingPresence(for: webView.url, webViewTitle: webView.title)
-        applyEmbeddedZoomWebAuthenticationIfNeeded(webView: webView)
-        refreshEmbeddedBrowserNavButtons()
+        Task { @MainActor in
+            self.updateEmbeddedMeetingRecordingPresence(for: webView.url, webViewTitle: webView.title)
+            self.applyEmbeddedZoomWebAuthenticationIfNeeded(webView: webView)
+            self.refreshEmbeddedBrowserNavButtons()
+        }
     }
 
     func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
         guard webView === embeddedBrowserWebView else { return }
-        updateEmbeddedMeetingRecordingPresence(for: webView.url, webViewTitle: webView.title)
-        applyEmbeddedZoomWebAuthenticationIfNeeded(webView: webView)
-        if let pageURL = webView.url, isZoomEmbeddedWebClientInCallURL(pageURL) {
-            embeddedZoomPendingWebAuth = nil
-            embeddedZoomPendingJoinURL = nil
+        Task { @MainActor in
+            self.updateEmbeddedMeetingRecordingPresence(for: webView.url, webViewTitle: webView.title)
+            self.applyEmbeddedZoomWebAuthenticationIfNeeded(webView: webView)
+            if let pageURL = webView.url, self.isZoomEmbeddedWebClientInCallURL(pageURL) {
+                self.embeddedZoomPendingWebAuth = nil
+                self.embeddedZoomPendingJoinURL = nil
+            }
+            self.refreshEmbeddedBrowserNavButtons()
         }
-        refreshEmbeddedBrowserNavButtons()
     }
 
     func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
@@ -10998,8 +11020,7 @@ final class ZoomOAuthService: NSObject {
         if let existing = inAppOAuthWindowController { return existing }
         let controller = InAppOAuthWindowController(
             title: "Zoom Sign-In",
-            websiteDataStore: zoomEmbeddedWebsiteDataStore,
-            processPool: zoomEmbeddedWebProcessPool
+            websiteDataStore: zoomEmbeddedWebsiteDataStore
         )
         inAppOAuthWindowController = controller
         return controller
@@ -11208,14 +11229,10 @@ private final class InAppOAuthWindowController: NSWindowController, WKNavigation
 
     init(
         title: String,
-        websiteDataStore: WKWebsiteDataStore = .nonPersistent(),
-        processPool: WKProcessPool? = nil
+        websiteDataStore: WKWebsiteDataStore
     ) {
         let configuration = WKWebViewConfiguration()
         configuration.websiteDataStore = websiteDataStore
-        if let processPool {
-            configuration.processPool = processPool
-        }
         self.webView = WKWebView(frame: .zero, configuration: configuration)
         let container = OAuthWebViewContainerView(webView: webView)
         let contentSize = NSSize(width: AppWindowMetrics.defaultContentWidth, height: AppWindowMetrics.defaultContentHeight)