Skip to content

Fix browser panel resize flicker during split drag - #2513

Merged
austinywang merged 1 commit into
mainfrom
issue-2503-browser-panel-resize-flicker
Apr 2, 2026
Merged

austinywang merged 1 commit into
mainfrom
issue-2503-browser-panel-resize-flicker

Conversation

@austinywang

@austinywang austinywang commented Apr 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Skip redundant portal-wide geometry sync when an interactive split divider drag is already in progress, since browser host anchors already emit coalesced geometry callbacks
  • Adds isInteractiveSplitDividerDrag check to prevent double WebKit refresh that caused visible flicker in browser panes

Closes #2503

Test plan

  • Open a browser panel alongside a terminal split
  • Drag the split divider back and forth — browser pane should resize smoothly without flicker
  • Verify DevTools split views still work correctly (internal NSSplitView bypass unchanged)
  • Confirm no regressions in browser portal sync when not dragging

🤖 Generated with Claude Code


Summary by cubic

Fixes browser pane flicker during split resize by skipping redundant portal-wide geometry sync while a divider drag is in progress. This prevents double WebKit refresh and makes resizing smooth.

  • Bug Fixes
    • Skip portal-wide geometry sync during interactive split divider drags to avoid duplicate WebKit refresh.
    • Add isInteractiveSplitDividerDrag helper that detects recent left-mouse drag events on the same window.

Written for commit 2dbb8c2. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Improved window split pane resize behavior during interactive dragging. The application now correctly suppresses external geometry synchronization when a split divider is actively being dragged, preventing unwanted geometry updates that could interfere with the resize operation.

@vercel

vercel Bot commented Apr 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 1, 2026 9:48pm

@coderabbitai

coderabbitai Bot commented Apr 1, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9ef941f9-07f6-4a5a-928c-5ab7cba3e388

📥 Commits

Reviewing files that changed from the base of the PR and between e9b2090 and 2dbb8c2.

📒 Files selected for processing (1)
  • Sources/BrowserWindowPortal.swift

📝 Walkthrough

Walkthrough

This PR modifies the WindowBrowserPortal class to suppress external-geometry synchronization during interactive split-divider dragging by detecting active left-mouse drag events using system uptime and event timestamp comparisons.

Changes

Cohort / File(s) Summary
Split-Divider Drag Suppression
Sources/BrowserWindowPortal.swift
Added isInteractiveSplitDividerDrag(in:) helper that detects active left-mouse drag/down by checking NSEvent.pressedMouseButtons, current event, and timestamp delta (< 0.1s). Updated shouldTreatSplitResizeAsExternalGeometry to return false immediately for portal host descendants and suppress sync during interactive drags via the new helper.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 A split so smooth, no flicker in sight,
When dragging dividers with all of my might,
The portal stays calm while I resize with care,
No more dancing panels—just geometry so fair! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: fixing browser panel resize flicker during split drag operations.
Description check ✅ Passed The description includes summary of changes and reasoning, but the testing section is incomplete with unchecked items and missing video demonstration for UI behavior changes.
Linked Issues check ✅ Passed The PR directly addresses issue #2503 by implementing the isInteractiveSplitDividerDrag check to prevent double WebKit refresh and eliminate flickering during split resize.
Out of Scope Changes check ✅ Passed All changes are narrowly scoped to fix the browser panel flicker issue; the modifications target only the shouldTreatSplitResizeAsExternalGeometry function and add a focused helper method.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-2503-browser-panel-resize-flicker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes visible flicker in browser panes during split-divider drags by skipping the redundant portal-wide geometry sync when an interactive drag is already in progress. The change is small and well-targeted: shouldTreatSplitResizeAsExternalGeometry now returns false while a left-mouse drag is detected in the window, relying on browser host anchor coalesced callbacks to handle geometry updates instead of double-firing WebKit refreshes.

  • The existing DevTools NSSplitView bypass is preserved and correctly refactored to an early-return guard.
  • The new isInteractiveSplitDividerDrag helper correctly degrades gracefully: if NSApp.currentEvent is nil, stale, or belongs to a different window, the function returns false and the full sync proceeds as before.
  • Two P2 style/clarity findings: the helper's name implies split-divider specificity but it actually detects any left-mouse drag in the window (a broader heuristic), and the 0.1-second staleness threshold is an unexplained magic constant.

Confidence Score: 5/5

  • Safe to merge — all findings are P2 style/clarity concerns that do not affect correctness on any current code path.
  • The logic is sound: the end-of-drag case is handled correctly (mouse-button release immediately clears the guard), the DevTools bypass is preserved, and the graceful-degradation path (nil/stale/wrong-window event) ensures the sync still fires when the heuristic cannot confirm an active drag. Both remaining findings are naming and style concerns.
  • No files require special attention.

Important Files Changed

Filename Overview
Sources/BrowserWindowPortal.swift Adds isInteractiveSplitDividerDrag heuristic to skip redundant portal-wide geometry sync during split-divider drags; logic is sound with minor naming clarity and magic-constant style concerns.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["NSSplitView.didResizeSubviewsNotification fires"] --> B{"splitView.window === window?"}
    B -- No --> Z["return false\n(ignore)"]
    B -- Yes --> C{"splitView.isDescendant\nof hostView?"}
    C -- Yes --> Z2["return false\n(DevTools internal resize — ignore)"]
    C -- No --> D{"isInteractiveSplitDividerDrag\nin window?"}
    D -- "pressedMouseButtons bit 0 == 0\nor no currentEvent\nor event stale > 0.1s\nor event.window ≠ window\nor event type not drag/down" --> E["return true\n→ scheduleExternalGeometrySynchronize()"]
    D -- "Left button held + recent drag event\nin same window" --> F["return false\n(suppress — browser host anchor\nalready handling geometry)"]
Loading

Reviews (1): Last reviewed commit: "Avoid duplicate browser portal sync duri..." | Re-trigger Greptile

Comment on lines +2122 to +2133
private static func isInteractiveSplitDividerDrag(in window: NSWindow) -> Bool {
guard (NSEvent.pressedMouseButtons & 1) != 0 else { return false }
guard let event = NSApp.currentEvent else { return false }
let now = ProcessInfo.processInfo.systemUptime
guard (now - event.timestamp) < 0.1 else { return false }
guard event.window === window else { return false }
switch event.type {
case .leftMouseDown, .leftMouseDragged:
return true
default:
return false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 isInteractiveSplitDividerDrag is broader than its name implies

The function name suggests it specifically detects a split-divider drag, but the implementation detects any left-mouse drag (.leftMouseDown / .leftMouseDragged) occurring in window. There is no check that the drag event originated on an NSSplitView divider hit-test region.

In practice this means: if the user is performing a non-divider left-button drag in the same window — for example, selecting text in a terminal pane, dragging a tab, or drawing a selection rectangle — and a NSSplitView.didResizeSubviewsNotification fires concurrently (e.g., from a programmatic split-position change), shouldTreatSplitResizeAsExternalGeometry will return false and the external-geometry sync will be silently skipped. The portal would then be stale until the next unrelated trigger fires the sync.

The risk is low in the current codebase since programmatic split resizes during unrelated drags are uncommon, but the name and intent are misleading. Consider either (a) narrowing the check to events whose locationInWindow falls within any NSSplitView divider rect in the window, or (b) renaming the function and adding a comment that it is intentionally a broader "left-mouse-drag" heuristic.

guard (NSEvent.pressedMouseButtons & 1) != 0 else { return false }
guard let event = NSApp.currentEvent else { return false }
let now = ProcessInfo.processInfo.systemUptime
guard (now - event.timestamp) < 0.1 else { return false }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Magic constant 0.1 should be a named constant

The staleness threshold 0.1 (seconds) is an unexplained magic number. Extracting it into a named constant makes the intent clear and makes future tuning easier.

Suggested change
guard (now - event.timestamp) < 0.1 else { return false }
let eventStalenessThreshold = 0.1 // seconds; events older than this are not treated as current drag activity
guard (now - event.timestamp) < eventStalenessThreshold else { return false }

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/BrowserWindowPortal.swift">

<violation number="1" location="Sources/BrowserWindowPortal.swift:2129">
P2: This branch classifies any left-button drag in the window as a split-divider drag. Narrow the detection to actual `NSSplitView` divider interaction (e.g., divider hit-testing), otherwise external geometry sync can be skipped during unrelated drags and leave portal geometry stale until a later trigger.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

guard (now - event.timestamp) < 0.1 else { return false }
guard event.window === window else { return false }
switch event.type {
case .leftMouseDown, .leftMouseDragged:

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This branch classifies any left-button drag in the window as a split-divider drag. Narrow the detection to actual NSSplitView divider interaction (e.g., divider hit-testing), otherwise external geometry sync can be skipped during unrelated drags and leave portal geometry stale until a later trigger.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/BrowserWindowPortal.swift, line 2129:

<comment>This branch classifies any left-button drag in the window as a split-divider drag. Narrow the detection to actual `NSSplitView` divider interaction (e.g., divider hit-testing), otherwise external geometry sync can be skipped during unrelated drags and leave portal geometry stale until a later trigger.</comment>

<file context>
@@ -2111,7 +2111,26 @@ final class WindowBrowserPortal: NSObject {
+        guard (now - event.timestamp) < 0.1 else { return false }
+        guard event.window === window else { return false }
+        switch event.type {
+        case .leftMouseDown, .leftMouseDragged:
+            return true
+        default:
</file context>
Fix with Cubic

@austinywang
austinywang merged commit 6f4c12c into main Apr 2, 2026
22 checks passed
@austinywang austinywang mentioned this pull request Apr 6, 2026
3 tasks

This branch was successfully deployed

1 active deployment
Preview — 2dbb8c29 Deployed Apr 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser panel flickering during panel resize

1 participant