From edab4fd62d23be7695573e2ccd825a1987968958 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Nov 2022 21:34:53 +0800 Subject: [PATCH] fix predefined win forbidden cursor Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 41 +++---- flutter/lib/mobile/pages/remote_page.dart | 8 +- flutter/lib/models/model.dart | 123 ++++++++++++--------- 3 files changed, 88 insertions(+), 84 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 84ea36d78..9e775f86f 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -356,9 +356,8 @@ class _ImagePaintState extends State { } } - MouseCursor _buildCustomCursor(BuildContext context, double scale) { - final cursor = Provider.of(context); - final cache = cursor.cache ?? cursor.defaultCache; + MouseCursor _buildCursorOfCache( + CursorModel cursor, double scale, CursorData? cache) { if (cache == null) { return MouseCursor.defer; } else { @@ -375,26 +374,16 @@ class _ImagePaintState extends State { } } + MouseCursor _buildCustomCursor(BuildContext context, double scale) { + final cursor = Provider.of(context); + final cache = cursor.cache ?? preDefaultCursor.cache; + return _buildCursorOfCache(cursor, scale, cache); + } + MouseCursor _buildDisabledCursor(BuildContext context, double scale) { final cursor = Provider.of(context); - final cache = cursor.cache; - if (cache == null) { - return MouseCursor.defer; - } else { - if (cursor.cachedForbidmemoryCursorData == null) { - cursor.updateForbiddenCursorBuffer(); - } - final key = 'disabled_cursor_key'; - cursor.addKey(key); - return FlutterCustomMemoryImageCursor( - pixbuf: cursor.cachedForbidmemoryCursorData, - key: key, - hotx: 0, - hoty: 0, - imageWidth: 32, - imageHeight: 32, - ); - } + final cache = preForbiddenCursor.cache; + return _buildCursorOfCache(cursor, scale, cache); } Widget _buildCrossScrollbarFromLayout( @@ -521,22 +510,22 @@ class CursorPaint extends StatelessWidget { double hotx = m.hotx; double hoty = m.hoty; if (m.image == null) { - if (m.defaultCache != null) { - hotx = m.defaultImage!.width / 2; - hoty = m.defaultImage!.height / 2; + if (preDefaultCursor.image != null) { + hotx = preDefaultCursor.image!.width / 2; + hoty = preDefaultCursor.image!.height / 2; } } return zoomCursor.isTrue ? CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: m.x - hotx + c.x / c.scale, y: m.y - hoty + c.y / c.scale, scale: c.scale), ) : CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: (m.x - hotx) * c.scale + c.x, y: (m.y - hoty) * c.scale + c.y, scale: 1.0), diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index b48e9960a..b17f0ef54 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -865,14 +865,14 @@ class CursorPaint extends StatelessWidget { double hotx = m.hotx; double hoty = m.hoty; if (m.image == null) { - if (m.defaultCache != null) { - hotx = m.defaultImage!.width / 2; - hoty = m.defaultImage!.height / 2; + if (preDefaultCursor.image != null) { + hotx = preDefaultCursor.image!.width / 2; + hoty = preDefaultCursor.image!.height / 2; } } return CustomPaint( painter: ImagePainter( - image: m.image ?? m.defaultImage, + image: m.image ?? preDefaultCursor.image, x: m.x * s - hotx * s + c.x, y: m.y * s - hoty * s + c.y - adjust, scale: 1), diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 7a08fc671..b7d72f878 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -763,13 +763,78 @@ class CursorData { } } +const _forbiddenCursorPng = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAkZQTFRFAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4GWAwCAAAAAAAA2B4GAAAAMTExAAAAAAAA2B4G2B4G2B4GAAAAmZmZkZGRAQEBAAAA2B4G2B4G2B4G////oKCgAwMDag8D2B4G2B4G2B4Gra2tBgYGbg8D2B4G2B4Gubm5CQkJTwsCVgwC2B4GxcXFDg4OAAAAAAAA2B4G2B4Gz8/PFBQUAAAAAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4GDgIA2NjYGxsbAAAAAAAA2B4GFwMB4eHhIyMjAAAAAAAA2B4G6OjoLCwsAAAAAAAA2B4G2B4G2B4G2B4G2B4GCQEA4ODgv7+/iYmJY2NjAgICAAAA9PT0Ojo6AAAAAAAAAAAA+/v7SkpKhYWFr6+vAAAAAAAA8/PzOTk5ERER9fX1KCgoAAAAgYGBKioqAAAAAAAApqamlpaWAAAAAAAAAAAAAAAAAAAAAAAALi4u/v7+GRkZAAAAAAAAAAAAAAAAAAAAfn5+AAAAAAAAV1dXkJCQAAAAAAAAAQEBAAAAAAAAAAAA7Hz6BAAAAMJ0Uk5TAAIWEwEynNz6//fVkCAatP2fDUHs6cDD8d0mPfT5fiEskiIR584A0gejr3AZ+P4plfALf5ZiTL85a4ziD6697fzN3UYE4v/4TwrNHuT///tdRKZh///+1U/ZBv///yjb///eAVL//50Cocv//6oFBbPvpGZCbfT//7cIhv///8INM///zBEcWYSZmO7//////1P////ts/////8vBv//////gv//R/z///QQz9sevP///2waXhNO/+fc//8mev/5gAe2r90MAAAByUlEQVR4nGNggANGJmYWBpyAlY2dg5OTi5uHF6s0H78AJxRwCAphyguLgKRExcQlQLSkFLq8tAwnp6ycPNABjAqKQKNElVDllVU4OVVhVquJA81Q10BRoAkUUYbJa4Edoo0sr6PLqaePLG/AyWlohKTAmJPTBFnelAFoixmSAnNOTgsUeQZLTk4rJAXWnJw2EHlbiDyDPCenHZICe04HFrh+RydnBgYWPU5uJAWinJwucPNd3dw9GDw5Ob2QFHBzcnrD7ffx9fMPCOTkDEINhmC4+3x8Q0LDwlEDIoKTMzIKKg9SEBIdE8sZh6SAJZ6Tkx0qD1YQkpCYlIwclCng0AXLQxSEpKalZyCryATKZwkhKQjJzsnNQ1KQXwBUUVhUXBJYWgZREFJeUVmFpMKlWg+anmqgCkJq6+obkG1pLEBTENLU3NKKrIKhrb2js8u4G6Kgpze0r3/CRAZMAHbkpJDJU6ZMmTqtFbuC6TNmhsyaMnsOFlmwgrnzpsxfELJwEXZ5Bp/FS3yWLlsesmLlKuwKVk9Ys5Zh3foN0zduwq5g85atDAzbpqSGbN9RhV0FGOzctWH3lD14FOzdt3H/gQw8Cg4u2gQPAwBYDXXdIH+wqAAAAABJRU5ErkJggg=='; +const _defaultCursorPng = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAFmSURBVFiF7dWxSlxREMbx34QFDRowYBchZSxSCWlMCOwD5FGEFHap06UI7KPsAyyEEIQFqxRaCqYTsqCJFsKkuAeRXb17wrqV918dztw55zszc2fo6Oh47MR/e3zO1/iAHWmznHKGQwx9ip/LEbCfazbsoY8j/JLOhcC6sCW9wsjEwJf483AC9nPNc1+lFRwI13d+l3rYFS799rFGxJMqARv2pBXh+72XQ7gWvklPS7TmMl9Ak/M+DqrENvxAv/guKKApuKPWl0/TROK4+LbSqzhuB+OZ3fRSeFPWY+Fkyn56Y29hfgTSpnQ+s98cvorVey66uPlNFxKwZOYLCGfCs5n9NMYVrsp6mvXSoFqpqYFDvMBkStgJJe93dZOwVXxbqUnBENulydSReqUrDhcX0PT2EXarBYS3GNXMhboinBgIl9K71kg0L3+PvyYGdVpruT2MwrF0iotiXfIwus0Dj+OOjo6Of+e7ab74RkpgAAAAAElFTkSuQmCC'; + +final preForbiddenCursor = PredefinedCursor( + png: _forbiddenCursorPng, + id: -2, +); +final preDefaultCursor = PredefinedCursor( + png: _defaultCursorPng, + id: -1, + hotxGetter: (double w) => w / 2, + hotyGetter: (double h) => h / 2, +); + +class PredefinedCursor { + ui.Image? _image; + img2.Image? _image2; + CursorData? _cache; + String png; + int id; + double Function(double)? hotxGetter; + double Function(double)? hotyGetter; + + PredefinedCursor( + {required this.png, required this.id, this.hotxGetter, this.hotyGetter}) { + init(); + } + + ui.Image? get image => _image; + CursorData? get cache => _cache; + + init() { + _image2 = img2.decodePng(base64Decode(png)); + if (_image2 != null) { + () async { + final defaultImg = _image2!; + // This function is called only one time, no need to care about the performance. + Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); + _image = await img.decodeImageFromPixels( + data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); + + double scale = 1.0; + if (Platform.isWindows) { + data = _image2!.getBytes(format: img2.Format.bgra); + } else { + data = Uint8List.fromList(img2.encodePng(_image2!)); + } + + _cache = CursorData( + peerId: '', + id: id, + image: _image2?.clone(), + scale: scale, + data: data, + hotxOrigin: + hotxGetter != null ? hotxGetter!(_image2!.width.toDouble()) : 0, + hotyOrigin: + hotyGetter != null ? hotyGetter!(_image2!.height.toDouble()) : 0, + width: _image2!.width, + height: _image2!.height, + ); + }(); + } + } +} + class CursorModel with ChangeNotifier { ui.Image? _image; - ui.Image? _defaultImage; final _images = >{}; CursorData? _cache; - final _defaultCacheId = -1; - CursorData? _defaultCache; final _cacheMap = {}; final _cacheKeys = {}; double _x = -10000; @@ -785,9 +850,7 @@ class CursorModel with ChangeNotifier { WeakReference parent; ui.Image? get image => _image; - ui.Image? get defaultImage => _defaultImage; CursorData? get cache => _cache; - CursorData? get defaultCache => _getDefaultCache(); double get x => _x - _displayOriginX; double get y => _y - _displayOriginY; @@ -801,50 +864,11 @@ class CursorModel with ChangeNotifier { DateTime.now().difference(_lastPeerMouse).inMilliseconds < kMouseControlTimeoutMSec; - CursorModel(this.parent) { - _getDefaultImage(); - _getDefaultCache(); - } + CursorModel(this.parent); Set get cachedKeys => _cacheKeys; addKey(String key) => _cacheKeys.add(key); - Future _getDefaultImage() async { - if (_defaultImage == null) { - final defaultImg = defaultCursorImage!; - // This function is called only one time, no need to care about the performance. - Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); - _defaultImage = await img.decodeImageFromPixels( - data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); - } - return _defaultImage; - } - - CursorData? _getDefaultCache() { - if (_defaultCache == null) { - Uint8List data; - double scale = 1.0; - if (Platform.isWindows) { - data = defaultCursorImage!.getBytes(format: img2.Format.bgra); - } else { - data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); - } - - _defaultCache = CursorData( - peerId: id, - id: _defaultCacheId, - image: defaultCursorImage?.clone(), - scale: scale, - data: data, - hotxOrigin: defaultCursorImage!.width / 2, - hotyOrigin: defaultCursorImage!.height / 2, - width: defaultCursorImage!.width, - height: defaultCursorImage!.height, - ); - } - return _defaultCache; - } - // remote physical display coordinate Rect getVisibleRect() { final size = MediaQueryData.fromWindow(ui.window).size; @@ -1085,15 +1109,6 @@ class CursorModel with ChangeNotifier { customCursorController.freeCache(k); } } - - Uint8List? cachedForbidmemoryCursorData; - void updateForbiddenCursorBuffer() { - cachedForbidmemoryCursorData ??= base64Decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAkZQTFRFAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4GWAwCAAAAAAAA2B4GAAAAMTExAAAAAAAA2B4G2B4G2B4GAAAAmZmZkZGRAQEBAAAA2B4G2B4G2B4G////oKCgAwMDag8D2B4G2B4G2B4Gra2tBgYGbg8D2B4G2B4Gubm5CQkJTwsCVgwC2B4GxcXFDg4OAAAAAAAA2B4G2B4Gz8/PFBQUAAAAAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4GDgIA2NjYGxsbAAAAAAAA2B4GFwMB4eHhIyMjAAAAAAAA2B4G6OjoLCwsAAAAAAAA2B4G2B4G2B4G2B4G2B4GCQEA4ODgv7+/iYmJY2NjAgICAAAA9PT0Ojo6AAAAAAAAAAAA+/v7SkpKhYWFr6+vAAAAAAAA8/PzOTk5ERER9fX1KCgoAAAAgYGBKioqAAAAAAAApqamlpaWAAAAAAAAAAAAAAAAAAAAAAAALi4u/v7+GRkZAAAAAAAAAAAAAAAAAAAAfn5+AAAAAAAAV1dXkJCQAAAAAAAAAQEBAAAAAAAAAAAA7Hz6BAAAAMJ0Uk5TAAIWEwEynNz6//fVkCAatP2fDUHs6cDD8d0mPfT5fiEskiIR584A0gejr3AZ+P4plfALf5ZiTL85a4ziD6697fzN3UYE4v/4TwrNHuT///tdRKZh///+1U/ZBv///yjb///eAVL//50Cocv//6oFBbPvpGZCbfT//7cIhv///8INM///zBEcWYSZmO7//////1P////ts/////8vBv//////gv//R/z///QQz9sevP///2waXhNO/+fc//8mev/5gAe2r90MAAAByUlEQVR4nGNggANGJmYWBpyAlY2dg5OTi5uHF6s0H78AJxRwCAphyguLgKRExcQlQLSkFLq8tAwnp6ycPNABjAqKQKNElVDllVU4OVVhVquJA81Q10BRoAkUUYbJa4Edoo0sr6PLqaePLG/AyWlohKTAmJPTBFnelAFoixmSAnNOTgsUeQZLTk4rJAXWnJw2EHlbiDyDPCenHZICe04HFrh+RydnBgYWPU5uJAWinJwucPNd3dw9GDw5Ob2QFHBzcnrD7ffx9fMPCOTkDEINhmC4+3x8Q0LDwlEDIoKTMzIKKg9SEBIdE8sZh6SAJZ6Tkx0qD1YQkpCYlIwclCng0AXLQxSEpKalZyCryATKZwkhKQjJzsnNQ1KQXwBUUVhUXBJYWgZREFJeUVmFpMKlWg+anmqgCkJq6+obkG1pLEBTENLU3NKKrIKhrb2js8u4G6Kgpze0r3/CRAZMAHbkpJDJU6ZMmTqtFbuC6TNmhsyaMnsOFlmwgrnzpsxfELJwEXZ5Bp/FS3yWLlsesmLlKuwKVk9Ys5Zh3foN0zduwq5g85atDAzbpqSGbN9RhV0FGOzctWH3lD14FOzdt3H/gQw8Cg4u2gQPAwBYDXXdIH+wqAAAAABJRU5ErkJggg=='); - } - - img2.Image? defaultCursorImage = img2.decodePng(base64Decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAFmSURBVFiF7dWxSlxREMbx34QFDRowYBchZSxSCWlMCOwD5FGEFHap06UI7KPsAyyEEIQFqxRaCqYTsqCJFsKkuAeRXb17wrqV918dztw55zszc2fo6Oh47MR/e3zO1/iAHWmznHKGQwx9ip/LEbCfazbsoY8j/JLOhcC6sCW9wsjEwJf483AC9nPNc1+lFRwI13d+l3rYFS799rFGxJMqARv2pBXh+72XQ7gWvklPS7TmMl9Ak/M+DqrENvxAv/guKKApuKPWl0/TROK4+LbSqzhuB+OZ3fRSeFPWY+Fkyn56Y29hfgTSpnQ+s98cvorVey66uPlNFxKwZOYLCGfCs5n9NMYVrsp6mvXSoFqpqYFDvMBkStgJJe93dZOwVXxbqUnBENulydSReqUrDhcX0PT2EXarBYS3GNXMhboinBgIl9K71kg0L3+PvyYGdVpruT2MwrF0iotiXfIwus0Dj+OOjo6Of+e7ab74RkpgAAAAAElFTkSuQmCC')); } class QualityMonitorData {