From 7194743a3016a81a95923c9a560a8dd1a9c79a84 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 10 Sep 2026 14:08:42 +0800 Subject: [PATCH] fix(flutter): shrink the unzoomed remote cursor by DPR on macOS and Linux With "Zoom cursor" off in Adaptive or Custom view, the remote cursor bitmap was registered at scale 1.0. NSCursor and GdkCursor treat the bitmap size as logical pixels, so on a HiDPI controller the cursor was drawn DPR times larger than in Original view (which already passes 1/DPR) and than on Windows (whose cursor path is in physical pixels). A HiDPI remote such as KDE Wayland sends a 48-64 px bitmap, which then showed up 3-4x too big on a Retina Mac. Scale the bitmap by 1/DPR in that case, and scale the Flutter-painted cursor used while the peer moves the mouse the same way so its size does not jump. The new branch is an identity at DPR 1 and the Windows paths are untouched. Fixes https://github.com/rustdesk/rustdesk/discussions/15363 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01K8HSHTEHo27mDcJXVyVfSP --- flutter/lib/desktop/pages/remote_page.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 3e98418b1..5e392d99f 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -1117,6 +1117,12 @@ class _ImagePaintState extends State { } else { if (zoomCursor.value || isViewOriginal()) { cursorScale = s; + } else { + // NSCursor and GdkCursor treat the bitmap size as logical + // pixels, so an unzoomed cursor must be shrunk by the DPR to + // keep 1 remote px == 1 physical px, the size Original view + // already renders it at. + cursorScale = 1.0 / c.devicePixelRatio; } } return cursorScale; @@ -1412,6 +1418,12 @@ class CursorPaint extends StatelessWidget { x = m.x - hotx + cx / c.scale; y = m.y - hoty + cy / c.scale; scale = c.scale; + } else if (!isWindows) { + // Keep the painted cursor the same physical size as the native one + // built by getCursorScale() above. + scale = 1.0 / c.devicePixelRatio; + x = (m.x * c.scale + cx) / scale - hotx; + y = (m.y * c.scale + cy) / scale - hoty; } return CustomPaint(