From c1bed4f53bd4bfa0490bf1f5dbd4bfa6ee966127 Mon Sep 17 00:00:00 2001 From: Trey T Date: Fri, 17 Apr 2026 14:21:33 -0500 Subject: [PATCH] FramebufferUIView: disable CALayer implicit animations on frame updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every time Mac repainted a region we set imageLayer.contents to a new CGImage. CALayer's default action for .contents is a 0.25s crossfade, so big repaints (like after a click — cursor + button + window-focus) looked like a pulse. Tap seemed "flickery"; actually the whole view was doing quarter-second crossfades constantly, most just weren't big enough to notice until a chunky repaint hit. Override imageLayer.actions with NSNull for contents/contentsRect/frame/ transform so blits are instantaneous, and wrap apply() in a CATransaction.setDisableActions(true) for safety. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Sources/VNCUI/Session/FramebufferUIView.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Packages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift b/Packages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift index bfa0afc..d0ef7f0 100644 --- a/Packages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift +++ b/Packages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift @@ -86,6 +86,17 @@ final class FramebufferUIView: UIView, imageLayer.magnificationFilter = .nearest imageLayer.minificationFilter = .linear imageLayer.contentsGravity = .resize + // Kill CALayer's implicit animations — we want every framebuffer + // update to be an instantaneous blit, not a 0.25s crossfade. + imageLayer.actions = [ + "contents": NSNull(), + "contentsRect": NSNull(), + "position": NSNull(), + "bounds": NSNull(), + "frame": NSNull(), + "transform": NSNull(), + "backgroundColor": NSNull() + ] layer.addSublayer(imageLayer) configureGestureRecognizers() @@ -161,8 +172,11 @@ final class FramebufferUIView: UIView, } func apply(image: CGImage?, framebufferSize: CGSize) { + CATransaction.begin() + CATransaction.setDisableActions(true) imageLayer.contents = image applyLayerFrame() + CATransaction.commit() } private func applyLayerFrame() {