Skip to content

Fix AppKit live resize redraw timing#4588

Draft
yay wants to merge 1 commit into
rust-windowing:masterfrom
yay:steady/macos-live-resize
Draft

Fix AppKit live resize redraw timing#4588
yay wants to merge 1 commit into
rust-windowing:masterfrom
yay:steady/macos-live-resize

Conversation

@yay
Copy link
Copy Markdown

@yay yay commented Jun 5, 2026

This fixes macOS live-resize behavior for layer-backed winit views.

While investigating resize artifacts in a downstream app, I found that AppKit can update and ask a layer-backed content view to display during live resize through paths that winit was not fully using for surface resize/redraw timing.

The main issue is that during live resize, especially when resizing from the top or left edge, the view backing size and redraw timing need to stay synchronized with AppKit's resize/display callbacks. Otherwise surface users can render with stale size information or miss redraw opportunities during the event-tracking run loop.

This PR changes the AppKit view path to:

  • set NSViewLayerContentsRedrawDuringViewResize for the content view
  • handle setFrameSize: by updating the surface size and requesting redraw during live resize
  • handle viewDidChangeBackingProperties for backing-scale/backing-size changes
  • handle displayLayer: as a redraw signal during live resize
  • report surface size from convertRectToBacking(bounds) instead of deriving it from the window/frame size

The main issue is that during live resize, especially when resizing from the top or left edge, the view backing size and redraw timing need to stay synchronized with AppKit's resize/display callbacks. Otherwise surface users can render with stale size information or miss redraw opportunities during the event-tracking run loop. In practice this shows up as visible wobble/jitter and stale or stretched frames while the window edge is being dragged.

I also looked at other AppKit/Metal applications with smooth live resize behavior while narrowing this down.

Validation

I used a small winit + CAMetalLayer demo that:

  • renders an animated high-contrast grid
  • paints only from WindowEvent::RedrawRequested
  • does not use an external AppKit timer
  • does not use CAMetalLayer.presentsWithTransaction

I recorded the same demo before and after the fix:

Before (notice the ghosting):

before-the-fix.mp4

After:

after-the-fix.mp4

In the before video, live resize shows stale/stretched frames. In the after video, resizing from all four edges stays synchronized and smooth.

I also validated the same change against winit 0.30.13, since that is the version used by the downstream app where I first reproduced the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant