feat(ribbon): animate windows through a proxy overlay

Merged
QE
2d ago
+3305-66

Why

Ribbon and workspace motion moved real windows with many Accessibility writes. Slow apps applied them late, so motion stuttered and windows passed visibly in front of others. This change draws window pictures on an overlay and moves them with a spring like Niri's. Each real window gets one Accessibility write.

What changed

  • RibbonProxyRenderer presents a full-screen overlay with window pictures and the wallpaper. It hides the overlay when the native windows reach their targets.
  • Captures use the WindowServer window capture, including parked windows, the wallpaper, and the Overview previews. ScreenCaptureKit is only a fallback, so the menu bar recording indicator stays off.
  • Drag previews, stacking previews, and borders follow the overlay.

Scope

  • Covers horizontal ribbon motion, workspace switches, and window drags on every monitor.
  • The Overview keeps its CPU-drawn renderer. A follow-up PR moves it to layers.

Tradeoffs

  • One write at the start of motion instead of per-frame writes. Real windows can arrive later than the overlay, so the landing waits up to 0.9 s and covers late windows.
  • The WindowServer capture is a private, read-only, optional symbol. Missing symbols fall back to ScreenCaptureKit.

Blast Radius

Every animated motion goes through the overlay. Navigation, focus, and parking do not depend on capture. When the overlay cannot draw a motion, for example before the wallpaper is captured, the windows move at once. Without Screen Recording, or with several displays, motion uses the previous native path.

Verification

  • python3 script/verify.py local passes.
  • python3 script/verify.py full passes 42 of 45 desktop tests. The same 3 tests (two Carbon hotkey tests and one pointer test) also fail in the full suite on main, and pass when run alone on both branches.

[!NOTE]

Animate windows through a ribbon proxy overlay

  • Adds a new RibbonProxyRenderer that captures window pictures, learns per-window settle offsets, and presents animated proxy overlays for window motion instead of moving native windows. The native window jumps instantly while the proxy handles the visual animation.
  • Applies proxies to lifecycle, command, workspace, focus, and mouse-reorder motions on single-monitor setups, driven by the new window_proxies animation setting (default true).
  • Adds proxy drag-carry and drop-preview flows: tiled windows are carried by the overlay during mouse gestures, and releasing a previewed drop applies it directly without a second settlement pass.
  • Learns per-window width rounding (up to the 16-point tiledWidthRoundingLimit) so layouts request narrower, centered frames instead of widening columns for small app-side overshoots.
  • Classifies non-modal AXSystemDialog/AXSystemFloatingWindow windows as app-drawn popups and leaves them unmanaged; focus-follows-mouse ignores pointer motion while such a popup has native focus.
  • Prefers WindowServer capture for Overview previews and falls back to ScreenCaptureKit only for missed requests; overview surface captures skip unchanged requests.
  • Behavioral Change: proxy mode moves window visuals off the native windows for listed sources, daemon defers desktop sync while proxies move, border overlays are pooled (up to four spares) and hidden panels become transparent one-point surfaces, and pointer hit testing no longer treats proxy surface windows as blocking.

Macroscope summarized 9235d33.