From 5414eaf7026125a3a4e92b1e232f8656f4057531 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 24 Sep 2026 10:56:27 +0800 Subject: [PATCH] cursor: look a native cursor up by the raster asked for The key ended in the raster made last. A shape switched away from keeps no pixels, so its raster stays where it was, and going back to a raster it was shown at before looked up the wrong key: A at 1.0, A at 0.5, then B, then A at 1.0 again missed the 32x32 cursor that was still there, fetched A from the core, and showed B meanwhile. With native cursors kept for every raster, the key now ends in the raster asked for; with pixels, that is the raster made, as before. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab --- flutter/lib/models/model.dart | 7 +++++-- flutter/test/cursor_replay_test.dart | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a64e101a7..d28392430 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -2930,7 +2930,8 @@ class CursorData { final targetHeight = (height * scale).ceil(); if ((_rasterWidth != targetWidth || _rasterHeight != targetHeight) && !hasPixels) { - // No native cursor at this size yet; buildCursorOfCache asks for the pixels. + // Nothing to make this raster from; buildCursorOfCache asks for the pixels unless its + // native cursor was made before. data = null; return scale; } @@ -3004,7 +3005,9 @@ class CursorData { String updateGetKey(double scale) { scale = _checkUpdateScale(scale); - return '${peerId}_${id}_${_doubleToInt(width * scale)}_${_doubleToInt(height * scale)}_${rasterWidth}_$rasterHeight'; + // The raster asked for, not the one made last: a shape without pixels keeps the native + // cursors of every raster it was shown at. + return '${peerId}_${id}_${_doubleToInt(width * scale)}_${_doubleToInt(height * scale)}_${(width * scale).ceil()}_${(height * scale).ceil()}'; } } diff --git a/flutter/test/cursor_replay_test.dart b/flutter/test/cursor_replay_test.dart index c579bcfbe..4560aacdc 100644 --- a/flutter/test/cursor_replay_test.dart +++ b/flutter/test/cursor_replay_test.dart @@ -155,6 +155,27 @@ void main() { expect(registered.length, 100); }); + test('a raster made before is found again after the shape was switched away from', + () async { + final cursor = ffi.cursorModel; + await _feed(ffi, 'A', size: 32); + buildCursorOfCache(cursor, 1.0, cursor.cache); + await _settle(); + final first = registered.single; + buildCursorOfCache(cursor, 0.5, cursor.cache); + await _settle(); + await _feed(ffi, 'B'); + buildCursorOfCache(cursor, 1.0, cursor.cache); + await _settle(); + final count = registered.length; + + _select(ffi, 'A'); // its pixels went; its cursors at both rasters stay + expect(_key(buildCursorOfCache(cursor, 1.0, cursor.cache)), first); + await _settle(); + expect(ffi.cursor.fetched, isEmpty); + expect(registered.length, count); + }); + test('a new raster of a shape without pixels keeps the cursor shown before', () async { final cursor = ffi.cursorModel;