mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-19 10:51:01 +03:00
fix(flutter): correct cursor scaling and Linux cursor clipping
Keep Linux/macOS bitmap sizing and painted cursor DPI conversion consistent, and derive hotspots from the actual scaled bitmap. Pad tall Linux native cursor buffers with transparency to preserve the lower half in the hardware cursor plane. Cover bitmap sizing, hotspots, artwork preservation, and painting with focused regression tests.
This commit is contained in:
@@ -1,16 +1,39 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_custom_cursor/cursor_manager.dart'
|
||||
as custom_cursor_manager;
|
||||
import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
import 'package:flutter_hbb/models/model.dart';
|
||||
|
||||
deleteCustomCursor(String key) =>
|
||||
custom_cursor_manager.CursorManager.instance.deleteCursor(key);
|
||||
resetSystemCursor() {}
|
||||
|
||||
double _nativeHotspot(double hotspot, int bitmapSize) {
|
||||
if (!isLinux) return hotspot;
|
||||
// GDK takes integer hotspots inside the bitmap; avoid truncating toward zero.
|
||||
return min(hotspot.round(), bitmapSize - 1).toDouble();
|
||||
}
|
||||
|
||||
Uint8List _padCursorWidth(Uint8List data, int width) {
|
||||
final bitmap = img.decodePng(data);
|
||||
if (bitmap == null) {
|
||||
throw const FormatException('Invalid native cursor PNG');
|
||||
}
|
||||
final padded = img.copyExpandCanvas(bitmap,
|
||||
newWidth: width,
|
||||
newHeight: bitmap.height,
|
||||
position: img.ExpandCanvasPosition.topLeft,
|
||||
toImage: img.Image(width: width, height: bitmap.height, numChannels: 4));
|
||||
return Uint8List.fromList(img.encodePng(padded));
|
||||
}
|
||||
|
||||
MouseCursor buildCursorOfCache(
|
||||
CursorModel cursor, double scale, CursorData? cache) {
|
||||
if (cache == null) {
|
||||
@@ -23,6 +46,12 @@ MouseCursor buildCursorOfCache(
|
||||
if (data == null) {
|
||||
return MouseCursor.defer;
|
||||
}
|
||||
// Pad tall Linux buffers to prevent clipping in the hardware cursor plane.
|
||||
final width = isLinux
|
||||
? max(cache.scaledWidth, cache.scaledHeight)
|
||||
: cache.scaledWidth;
|
||||
final buffer =
|
||||
width == cache.scaledWidth ? data : _padCursorWidth(data, width);
|
||||
debugPrint(
|
||||
"Register custom cursor with key $key (${cache.hotx},${cache.hoty})");
|
||||
// [Safety]
|
||||
@@ -32,11 +61,11 @@ MouseCursor buildCursorOfCache(
|
||||
custom_cursor_manager.CursorManager.instance
|
||||
.registerCursor(custom_cursor_manager.CursorData()
|
||||
..name = key
|
||||
..buffer = data
|
||||
..width = (cache.width * cache.scale).toInt()
|
||||
..height = (cache.height * cache.scale).toInt()
|
||||
..hotX = cache.hotx
|
||||
..hotY = cache.hoty);
|
||||
..buffer = buffer
|
||||
..width = width
|
||||
..height = cache.scaledHeight
|
||||
..hotX = _nativeHotspot(cache.hotx, cache.scaledWidth)
|
||||
..hotY = _nativeHotspot(cache.hoty, cache.scaledHeight));
|
||||
cursor.addKey(key);
|
||||
}
|
||||
return FlutterCustomMemoryImageCursor(key: key);
|
||||
|
||||
Reference in New Issue
Block a user