mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-18 18:31:02 +03:00
Align painted cursors with Linux texture origins
Use the truncated Linux texture origin while preserving fractional cursor positions and hotspots. Compare painted cursor geometry with the actual video widget in the existing regression tests.
This commit is contained in:
@@ -1469,7 +1469,10 @@ class CursorPaint extends StatelessWidget {
|
|||||||
final ffi = canvas.parent.target!;
|
final ffi = canvas.parent.target!;
|
||||||
final peer = ffi.ffiModel;
|
final peer = ffi.ffiModel;
|
||||||
if (ffi.imageModel.useTextureRender || peer.pi.forceTextureRender) {
|
if (ffi.imageModel.useTextureRender || peer.pi.forceTextureRender) {
|
||||||
return null;
|
// Match Linux's texture origin without rounding the cursor or hotspot.
|
||||||
|
return isLinux
|
||||||
|
? Offset(canvas.x.toInt().toDouble(), canvas.y.toInt().toDouble())
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
var scale = canvas.scale;
|
var scale = canvas.scale;
|
||||||
final displays = peer.pi.getCurDisplays();
|
final displays = peer.pi.getCurDisplays();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'dart:ui' as ui;
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/remote_page.dart';
|
import 'package:flutter_hbb/desktop/pages/remote_page.dart';
|
||||||
|
import 'package:flutter_hbb/models/desktop_render_texture.dart';
|
||||||
import 'package:flutter_hbb/models/model.dart';
|
import 'package:flutter_hbb/models/model.dart';
|
||||||
import 'package:flutter_hbb/utils/image.dart';
|
import 'package:flutter_hbb/utils/image.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@@ -12,7 +13,7 @@ import 'package:provider/provider.dart';
|
|||||||
|
|
||||||
const _hotspot = Offset(4, 9);
|
const _hotspot = Offset(4, 9);
|
||||||
const _remotePosition = Offset(100.25, 80.75);
|
const _remotePosition = Offset(100.25, 80.75);
|
||||||
const _canvasOffset = Offset(15.125, 10.25);
|
const _canvasOffset = Offset(15.125, -10.25);
|
||||||
const _viewport = Size(200, 160);
|
const _viewport = Size(200, 160);
|
||||||
|
|
||||||
class _CursorModel extends ChangeNotifier implements CursorModel {
|
class _CursorModel extends ChangeNotifier implements CursorModel {
|
||||||
@@ -44,11 +45,18 @@ class _Density extends Fake implements CursorData {
|
|||||||
final double pixelRatio;
|
final double pixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ImageModel extends Fake implements ImageModel {
|
class _ImageModel extends ChangeNotifier implements ImageModel {
|
||||||
_ImageModel(this.useTextureRender);
|
_ImageModel(this.useTextureRender);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final bool useTextureRender;
|
final bool useTextureRender;
|
||||||
|
@override
|
||||||
|
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TextureModel extends Fake implements TextureModel {
|
||||||
|
@override
|
||||||
|
RxInt getTextureId(int display) => 0.obs;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Display extends Display {
|
class _Display extends Display {
|
||||||
@@ -64,7 +72,10 @@ class _Display extends Display {
|
|||||||
|
|
||||||
class _Peer extends Fake implements FfiModel {
|
class _Peer extends Fake implements FfiModel {
|
||||||
@override
|
@override
|
||||||
final pi = PeerInfo();
|
final pi = PeerInfo()
|
||||||
|
..displays.add(Display()
|
||||||
|
..width = _viewport.width.toInt()
|
||||||
|
..height = _viewport.height.toInt());
|
||||||
@override
|
@override
|
||||||
bool isPeerLinux = false;
|
bool isPeerLinux = false;
|
||||||
@override
|
@override
|
||||||
@@ -79,6 +90,8 @@ class _FFI extends Fake implements FFI {
|
|||||||
@override
|
@override
|
||||||
final _Peer ffiModel = _Peer();
|
final _Peer ffiModel = _Peer();
|
||||||
@override
|
@override
|
||||||
|
final textureModel = _TextureModel();
|
||||||
|
@override
|
||||||
late CanvasModel canvasModel;
|
late CanvasModel canvasModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,16 +164,29 @@ Future<ImagePainter> _paintCursor(WidgetTester tester, CanvasModel canvas,
|
|||||||
final image = (await tester
|
final image = (await tester
|
||||||
.runAsync(() => createTestImage(width: source.$1, height: source.$2)))!;
|
.runAsync(() => createTestImage(width: source.$1, height: source.$2)))!;
|
||||||
addTearDown(image.dispose);
|
addTearDown(image.dispose);
|
||||||
await tester.pumpWidget(MediaQuery(
|
tester.view.devicePixelRatio = dpr;
|
||||||
|
tester.view.physicalSize = _viewport * dpr;
|
||||||
|
addTearDown(tester.view.reset);
|
||||||
|
await tester.pumpWidget(Directionality(textDirection: TextDirection.ltr,
|
||||||
|
child: MediaQuery(
|
||||||
data: MediaQueryData(devicePixelRatio: dpr),
|
data: MediaQueryData(devicePixelRatio: dpr),
|
||||||
child: MultiProvider(
|
child: MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
ChangeNotifierProvider<ImageModel>.value(value: canvas.parent.target!.imageModel),
|
||||||
ChangeNotifierProvider<CursorModel>(create: (_) => _CursorModel(image, position, density)),
|
ChangeNotifierProvider<CursorModel>(create: (_) => _CursorModel(image, position, density)),
|
||||||
ChangeNotifierProvider<CanvasModel>(create: (_) => canvas),
|
ChangeNotifierProvider<CanvasModel>(create: (_) => canvas),
|
||||||
],
|
],
|
||||||
child: CursorPaint(id: 'cursor-test', zoomCursor: zoom.obs),
|
child: Stack(fit: StackFit.expand, children: [
|
||||||
|
// Measure the video's origin instead of copying its rounding policy.
|
||||||
|
if (canvas.parent.target!.imageModel.useTextureRender &&
|
||||||
|
canvas.scrollStyle == ScrollStyle.scrollauto)
|
||||||
|
ImagePaint(ffi: canvas.parent.target!, id: 'cursor-test',
|
||||||
|
zoomCursor: zoom.obs, cursorOverImage: false.obs,
|
||||||
|
keyboardEnabled: true.obs, remoteCursorMoved: false.obs),
|
||||||
|
CursorPaint(id: 'cursor-test', zoomCursor: zoom.obs),
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
));
|
)));
|
||||||
final painter = tester.widget<CustomPaint>(find.byType(CustomPaint)).painter!
|
final painter = tester.widget<CustomPaint>(find.byType(CustomPaint)).painter!
|
||||||
as ImagePainter;
|
as ImagePainter;
|
||||||
expect(painter.image, same(image));
|
expect(painter.image, same(image));
|
||||||
@@ -191,7 +217,7 @@ void _linuxDisplayTests() {
|
|||||||
: _remotePosition);
|
: _remotePosition);
|
||||||
final pixelScale = 2 / displayScale;
|
final pixelScale = 2 / displayScale;
|
||||||
expect(painter.scale, pixelScale);
|
expect(painter.scale, pixelScale);
|
||||||
final origin = texture ? _canvasOffset
|
final origin = texture ? tester.getTopLeft(find.byType(Texture).first)
|
||||||
: Offset((_canvasOffset.dx / pixelScale).toInt() * pixelScale,
|
: Offset((_canvasOffset.dx / pixelScale).toInt() * pixelScale,
|
||||||
(_canvasOffset.dy / pixelScale).toInt() * pixelScale);
|
(_canvasOffset.dy / pixelScale).toInt() * pixelScale);
|
||||||
final position = allDisplays
|
final position = allDisplays
|
||||||
@@ -228,7 +254,8 @@ void main() {
|
|||||||
tester, _CanvasModel(style, canvasScale, texture),
|
tester, _CanvasModel(style, canvasScale, texture),
|
||||||
dpr: dpr, zoom: zoom, source: source, density: density);
|
dpr: dpr, zoom: zoom, source: source, density: density);
|
||||||
expect(painter.scale, scale);
|
expect(painter.scale, scale);
|
||||||
var imageOrigin = _canvasOffset;
|
var imageOrigin = texture
|
||||||
|
? tester.getTopLeft(find.byType(Texture).first) : _canvasOffset;
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
final background = _Canvas();
|
final background = _Canvas();
|
||||||
ImagePainter(
|
ImagePainter(
|
||||||
|
|||||||
Reference in New Issue
Block a user