From 4d2036512a76c2021b37a3e35901589299ace2eb Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 27 Jul 2023 20:45:29 +0800 Subject: [PATCH 1/8] add minimize button on fullscreen toolbar Signed-off-by: dignow --- flutter/lib/common.dart | 7 +++ .../lib/desktop/widgets/remote_toolbar.dart | 43 ++++++++++++++++++- flutter/lib/models/state_model.dart | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index b069fcee1..9f6bc01f2 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1389,6 +1389,13 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { isMaximized = await wc.isMaximized(); break; } + if (Platform.isWindows) { + const kMinOffset = -10000; + if (position.dx < kMinOffset || position.dy < kMinOffset) { + debugPrint("Invalid position: $position, ignore saving position"); + return; + } + } final pos = LastWindowPosition( sz.width, sz.height, position.dx, position.dy, isMaximized); diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 8c2f6a0b0..ec96d271e 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -360,6 +360,9 @@ class _RemoteToolbarState extends State { triggerAutoHide() => _debouncerHide.value = _debouncerHide.value + 1; + void _minimize() async => + await WindowController.fromWindowId(windowId).minimize(); + @override initState() { super.initState(); @@ -467,6 +470,12 @@ class _RemoteToolbarState extends State { toolbarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi)); } toolbarItems.add(_RecordMenu(ffi: widget.ffi)); + if (!isWebDesktop) { + toolbarItems.add(_MinimizeMenu( + state: widget.state, + onPressed: _minimize, + )); + } toolbarItems.add(_CloseMenu(id: widget.id, ffi: widget.ffi)); return Column( mainAxisSize: MainAxisSize.min, @@ -549,6 +558,30 @@ class _PinMenu extends StatelessWidget { } } +class _MinimizeMenu extends StatelessWidget { + final ToolbarState state; + final Function() onPressed; + bool get isFullscreen => stateGlobal.fullscreen; + const _MinimizeMenu({ + Key? key, + required this.state, + required this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Offstage( + offstage: !isFullscreen, + child: _IconMenuButton( + assetName: 'assets/minimize_black_24dp.svg', + tooltip: 'Minimize', + onPressed: onPressed, + color: _ToolbarTheme.blueColor, + hoverColor: _ToolbarTheme.hoverBlueColor, + )); + } +} + class _FullscreenMenu extends StatelessWidget { final ToolbarState state; final Function(bool) setFullscreen; @@ -1597,11 +1630,11 @@ class _IconMenuButtonState extends State<_IconMenuButton> { final icon = widget.icon ?? SvgPicture.asset( widget.assetName!, - color: Colors.white, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), width: _ToolbarTheme.buttonSize, height: _ToolbarTheme.buttonSize, ); - final button = SizedBox( + var button = SizedBox( width: _ToolbarTheme.buttonSize, height: _ToolbarTheme.buttonSize, child: MenuItemButton( @@ -1625,6 +1658,12 @@ class _IconMenuButtonState extends State<_IconMenuButton> { ).marginSymmetric( horizontal: widget.hMargin ?? _ToolbarTheme.buttonHMargin, vertical: widget.vMargin ?? _ToolbarTheme.buttonVMargin); + if (widget.tooltip != null) { + button = Tooltip( + message: widget.tooltip!, + child: button, + ); + } if (widget.topLevel) { return MenuBar(children: [button]); } else { diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index f7b4f8cc2..94f9cc234 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -65,7 +65,7 @@ class StateGlobal { ? kMaximizeEdgeSize : kWindowEdgeSize; print( - "fullscreen: ${fullscreen}, resizeEdgeSize: ${_resizeEdgeSize.value}"); + "fullscreen: $fullscreen, resizeEdgeSize: ${_resizeEdgeSize.value}"); _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; WindowController.fromWindowId(windowId) .setFullscreen(_fullscreen) From 9321a4f486b3e3160786738de051c7c9d0c7f8e0 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 27 Jul 2023 22:19:38 +0800 Subject: [PATCH 2/8] refact fullscreen and minimize button Signed-off-by: dignow --- flutter/lib/common.dart | 6 +- .../lib/desktop/pages/remote_tab_page.dart | 3 +- .../lib/desktop/widgets/remote_toolbar.dart | 136 ++++++++---------- 3 files changed, 62 insertions(+), 83 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 9f6bc01f2..bb4c60c37 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1391,7 +1391,11 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { } if (Platform.isWindows) { const kMinOffset = -10000; - if (position.dx < kMinOffset || position.dy < kMinOffset) { + const kMaxOffset = 10000; + if (position.dx < kMinOffset || + position.dy < kMinOffset || + position.dx > kMaxOffset || + position.dy > kMaxOffset) { debugPrint("Invalid position: $position, ignore saving position"); return; } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 9ee04f8b1..1c4c27c48 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -4,7 +4,6 @@ import 'dart:ui' as ui; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/consts.dart'; @@ -172,7 +171,7 @@ class _ConnectionTabPageState extends State { connectionType.secure.value == ConnectionType.strSecure; bool direct = connectionType.direct.value == ConnectionType.strDirect; - var msgConn; + String msgConn; if (secure && direct) { msgConn = translate("Direct and encrypted connection"); } else if (secure && !direct) { diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index ec96d271e..ab74dab59 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:ui' as ui; import 'dart:async'; import 'dart:io'; @@ -432,6 +431,8 @@ class _RemoteToolbarState extends State { dragging: _dragging, fractionX: _fractionX, show: show, + setFullscreen: _setFullscreen, + setMinimize: _minimize, ), ), ), @@ -443,8 +444,6 @@ class _RemoteToolbarState extends State { final List toolbarItems = []; if (!isWebDesktop) { toolbarItems.add(_PinMenu(state: widget.state)); - toolbarItems.add( - _FullscreenMenu(state: widget.state, setFullscreen: _setFullscreen)); toolbarItems.add(_MobileActionMenu(ffi: widget.ffi)); } @@ -470,12 +469,6 @@ class _RemoteToolbarState extends State { toolbarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi)); } toolbarItems.add(_RecordMenu(ffi: widget.ffi)); - if (!isWebDesktop) { - toolbarItems.add(_MinimizeMenu( - state: widget.state, - onPressed: _minimize, - )); - } toolbarItems.add(_CloseMenu(id: widget.id, ffi: widget.ffi)); return Column( mainAxisSize: MainAxisSize.min, @@ -558,51 +551,6 @@ class _PinMenu extends StatelessWidget { } } -class _MinimizeMenu extends StatelessWidget { - final ToolbarState state; - final Function() onPressed; - bool get isFullscreen => stateGlobal.fullscreen; - const _MinimizeMenu({ - Key? key, - required this.state, - required this.onPressed, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Offstage( - offstage: !isFullscreen, - child: _IconMenuButton( - assetName: 'assets/minimize_black_24dp.svg', - tooltip: 'Minimize', - onPressed: onPressed, - color: _ToolbarTheme.blueColor, - hoverColor: _ToolbarTheme.hoverBlueColor, - )); - } -} - -class _FullscreenMenu extends StatelessWidget { - final ToolbarState state; - final Function(bool) setFullscreen; - bool get isFullscreen => stateGlobal.fullscreen; - const _FullscreenMenu( - {Key? key, required this.state, required this.setFullscreen}) - : super(key: key); - - @override - Widget build(BuildContext context) { - return _IconMenuButton( - assetName: - isFullscreen ? "assets/fullscreen_exit.svg" : "assets/fullscreen.svg", - tooltip: isFullscreen ? 'Exit Fullscreen' : 'Fullscreen', - onPressed: () => setFullscreen(!isFullscreen), - color: _ToolbarTheme.blueColor, - hoverColor: _ToolbarTheme.hoverBlueColor, - ); - } -} - class _MobileActionMenu extends StatelessWidget { final FFI ffi; const _MobileActionMenu({Key? key, required this.ffi}) : super(key: key); @@ -647,7 +595,7 @@ class _MonitorMenu extends StatelessWidget { children: [ SvgPicture.asset( "assets/screen.svg", - color: Colors.white, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), ), Obx(() { RxInt display = CurrentDisplayState.find(id); @@ -683,7 +631,7 @@ class _MonitorMenu extends StatelessWidget { children: [ SvgPicture.asset( "assets/screen.svg", - color: Colors.white, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), ), Text( (i + 1).toString(), @@ -754,7 +702,7 @@ class ScreenAdjustor { bool get isFullscreen => stateGlobal.fullscreen; int get windowId => stateGlobal.windowId; - adjustWindow() { + adjustWindow(BuildContext context) { return futureBuilder( future: isWindowCanBeAdjusted(), hasData: (data) { @@ -764,7 +712,7 @@ class ScreenAdjustor { children: [ MenuButton( child: Text(translate('Adjust Window')), - onPressed: doAdjustWindow, + onPressed: () => doAdjustWindow(context), ffi: ffi), Divider(), ], @@ -772,20 +720,19 @@ class ScreenAdjustor { }); } - doAdjustWindow() async { + doAdjustWindow(BuildContext context) async { await updateScreen(); if (_screen != null) { cbExitFullscreen(); double scale = _screen!.scaleFactor; final wndRect = await WindowController.fromWindowId(windowId).getFrame(); - final mediaSize = MediaQueryData.fromWindow(ui.window).size; + final mediaSize = MediaQueryData.fromView(View.of(context)).size; // On windows, wndRect is equal to GetWindowRect and mediaSize is equal to GetClientRect. // https://stackoverflow.com/a/7561083 double magicWidth = wndRect.right - wndRect.left - mediaSize.width * scale; double magicHeight = wndRect.bottom - wndRect.top - mediaSize.height * scale; - final canvasModel = ffi.canvasModel; final width = (canvasModel.getDisplayWidth() * canvasModel.scale + CanvasModel.leftToEdge + @@ -928,7 +875,7 @@ class _DisplayMenuState extends State<_DisplayMenu> { color: _ToolbarTheme.blueColor, hoverColor: _ToolbarTheme.hoverBlueColor, menuChildren: [ - _screenAdjustor.adjustWindow(), + _screenAdjustor.adjustWindow(context), viewStyle(), scrollStyle(), imageQuality(), @@ -1115,9 +1062,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { return _SubmenuButton( ffi: widget.ffi, menuChildren: [ - _OriginalResolutionMenuButton(showOriginalBtn), - _FitLocalResolutionMenuButton(showFitLocalBtn), - _customResolutionMenuButton(isVirtualDisplay), + _OriginalResolutionMenuButton(context, showOriginalBtn), + _FitLocalResolutionMenuButton(context, showFitLocalBtn), + _customResolutionMenuButton(context, isVirtualDisplay), _menuDivider(showOriginalBtn, showFitLocalBtn, isVirtualDisplay), ] + _supportedResolutionMenuButtons(), @@ -1158,7 +1105,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { } } - _onChanged(String? value) async { + _onChanged(BuildContext context, String? value) async { stateGlobal.setLastResolutionGroupValue( widget.id, pi.currentDisplay, value); if (value == null) return; @@ -1178,12 +1125,12 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { if (w != null && h != null) { if (w != display.width || h != display.height) { - await _changeResolution(w, h); + await _changeResolution(context, w, h); } } } - _changeResolution(int w, int h) async { + _changeResolution(BuildContext context, int w, int h) async { await bind.sessionChangeResolution( sessionId: ffi.sessionId, display: pi.currentDisplay, @@ -1194,18 +1141,19 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { final display = ffiModel.display; if (w == display.width && h == display.height) { if (await widget.screenAdjustor.isWindowCanBeAdjusted()) { - widget.screenAdjustor.doAdjustWindow(); + widget.screenAdjustor.doAdjustWindow(context); } } }); } - Widget _OriginalResolutionMenuButton(bool showOriginalBtn) { + Widget _OriginalResolutionMenuButton( + BuildContext context, bool showOriginalBtn) { return Offstage( offstage: !showOriginalBtn, child: MenuButton( - onPressed: () => - _changeResolution(display.originalWidth, display.originalHeight), + onPressed: () => _changeResolution( + context, display.originalWidth, display.originalHeight), ffi: widget.ffi, child: Text( '${translate('resolution_original_tip')} ${display.originalWidth}x${display.originalHeight}'), @@ -1213,14 +1161,15 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { ); } - Widget _FitLocalResolutionMenuButton(bool showFitLocalBtn) { + Widget _FitLocalResolutionMenuButton( + BuildContext context, bool showFitLocalBtn) { return Offstage( offstage: !showFitLocalBtn, child: MenuButton( onPressed: () { final resolution = _getBestFitResolution(); if (resolution != null) { - _changeResolution(resolution.width, resolution.height); + _changeResolution(context, resolution.width, resolution.height); } }, ffi: widget.ffi, @@ -1230,13 +1179,13 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { ); } - Widget _customResolutionMenuButton(isVirtualDisplay) { + Widget _customResolutionMenuButton(BuildContext context, isVirtualDisplay) { return Offstage( offstage: !isVirtualDisplay, child: RdoMenuButton( value: _kCustomResolutionValue, groupValue: _groupValue, - onChanged: _onChanged, + onChanged: (String? value) => _onChanged(context, value), ffi: widget.ffi, child: Row( children: [ @@ -1277,7 +1226,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { .map((e) => RdoMenuButton( value: '${e.width}x${e.height}', groupValue: _groupValue, - onChanged: _onChanged, + onChanged: (String? value) => _onChanged(context, value), ffi: widget.ffi, child: Text('${e.width}x${e.height}'))) .toList(); @@ -1707,7 +1656,7 @@ class _IconSubmenuButtonState extends State<_IconSubmenuButton> { final icon = widget.icon ?? SvgPicture.asset( widget.svg!, - color: Colors.white, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), width: _ToolbarTheme.buttonSize, height: _ToolbarTheme.buttonSize, ); @@ -1856,12 +1805,18 @@ class _DraggableShowHide extends StatefulWidget { final RxDouble fractionX; final RxBool dragging; final RxBool show; + + final Function(bool) setFullscreen; + final Function() setMinimize; + const _DraggableShowHide({ Key? key, required this.sessionId, required this.fractionX, required this.dragging, required this.show, + required this.setFullscreen, + required this.setMinimize, }) : super(key: key); @override @@ -1915,7 +1870,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { widget.dragging.value = true; }), onDragEnd: (details) { - final mediaSize = MediaQueryData.fromWindow(ui.window).size; + final mediaSize = MediaQueryData.fromView(View.of(context)).size; widget.fractionX.value += (details.offset.dx - position.dx) / (mediaSize.width - size.width); if (widget.fractionX.value < left) { @@ -1940,10 +1895,31 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { minimumSize: MaterialStateProperty.all(const Size(0, 0)), padding: MaterialStateProperty.all(EdgeInsets.zero), ); + final isFullscreen = stateGlobal.fullscreen; final child = Row( mainAxisSize: MainAxisSize.min, children: [ _buildDraggable(context), + TextButton( + onPressed: () { + widget.setFullscreen(!isFullscreen); + setState(() {}); + }, + child: Icon( + isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen, + size: 20, + ), + ), + Offstage( + offstage: !isFullscreen, + child: TextButton( + onPressed: () => widget.setMinimize(), + child: Icon( + Icons.minimize, + size: 20, + ), + ), + ), TextButton( onPressed: () => setState(() { widget.show.value = !widget.show.value; @@ -2032,7 +2008,7 @@ class _MultiMonitorMenu extends StatelessWidget { children: [ SvgPicture.asset( "assets/screen.svg", - color: Colors.white, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), ), Obx( () => Text( From ac743ca2fe77c3cb05bf4ea7dc7878cf67b04d43 Mon Sep 17 00:00:00 2001 From: dignow Date: Sun, 30 Jul 2023 16:42:39 +0800 Subject: [PATCH 3/8] check IsClipboardFormatAvailable(CF_HDROP) on clipboard update Signed-off-by: dignow --- libs/clipboard/src/lib.rs | 49 +++++++++++++++++-------- libs/clipboard/src/windows/wf_cliprdr.c | 27 ++++++-------- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 84179621d..ea659b550 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -181,32 +181,37 @@ pub fn server_clip_file( ClipboardFile::MonitorReady => { log::debug!("server_monitor_ready called"); ret = server_monitor_ready(context, conn_id); - log::debug!("server_monitor_ready called, return {}", ret); + log::debug!("server_monitor_ready called, conn_id {}, return {}", conn_id, ret); } ClipboardFile::FormatList { format_list } => { - log::debug!("server_format_list called"); + log::debug!("server_format_list called, conn_id {}, format_list: {:?}", conn_id, &format_list); ret = server_format_list(context, conn_id, format_list); - log::debug!("server_format_list called, return {}", ret); + log::debug!("server_format_list called, conn_id {}, return {}", conn_id, ret); } ClipboardFile::FormatListResponse { msg_flags } => { - log::debug!("format_list_response called"); + log::debug!("server_format_list_response called"); ret = server_format_list_response(context, conn_id, msg_flags); - log::debug!("server_format_list_response called, return {}", ret); + log::debug!("server_format_list_response called, conn_id {}, msg_flags {}, return {}", conn_id, msg_flags, ret); } ClipboardFile::FormatDataRequest { requested_format_id, } => { - log::debug!("format_data_request called"); + log::debug!("server_format_data_request called"); ret = server_format_data_request(context, conn_id, requested_format_id); - log::debug!("server_format_data_request called, return {}", ret); + log::debug!("server_format_data_request called, conn_id {}, requested_format_id {}, return {}", conn_id, requested_format_id, ret); } ClipboardFile::FormatDataResponse { msg_flags, format_data, } => { - log::debug!("format_data_response called"); + log::debug!("server_format_data_response called"); ret = server_format_data_response(context, conn_id, msg_flags, format_data); - log::debug!("server_format_data_response called, return {}", ret); + log::debug!( + "server_format_data_response called, conn_id {}, msg_flags: {}, return {}", + conn_id, + msg_flags, + ret + ); } ClipboardFile::FileContentsRequest { stream_id, @@ -218,7 +223,7 @@ pub fn server_clip_file( have_clip_data_id, clip_data_id, } => { - log::debug!("file_contents_request called"); + log::debug!("server_file_contents_request called"); ret = server_file_contents_request( context, conn_id, @@ -231,14 +236,24 @@ pub fn server_clip_file( have_clip_data_id, clip_data_id, ); - log::debug!("server_file_contents_request called, return {}", ret); + log::debug!("server_file_contents_request called, conn_id {}, stream_id: {}, list_index {}, dw_flags {}, n_position_low {}, n_position_high {}, cb_requested {}, have_clip_data_id {}, clip_data_id {}, return {}", conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ret + ); } ClipboardFile::FileContentsResponse { msg_flags, stream_id, requested_data, } => { - log::debug!("file_contents_response called"); + log::debug!("server_file_contents_response called"); ret = server_file_contents_response( context, conn_id, @@ -246,7 +261,12 @@ pub fn server_clip_file( stream_id, requested_data, ); - log::debug!("server_file_contents_response called, return {}", ret); + log::debug!("server_file_contents_response called, conn_id {}, msg_flags {}, stream_id {}, return {}", + conn_id, + msg_flags, + stream_id, + ret + ); } } ret @@ -578,8 +598,6 @@ extern "C" fn client_format_data_request( _context: *mut CliprdrClientContext, format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST, ) -> UINT { - log::debug!("client_format_data_request called"); - let conn_id; let requested_format_id; unsafe { @@ -589,6 +607,7 @@ extern "C" fn client_format_data_request( let data = ClipboardFile::FormatDataRequest { requested_format_id, }; + log::debug!("client_format_data_request called, conn_id: {}, requested_format_id: {}", conn_id, requested_format_id); // no need to handle result here send_data(conn_id, data); diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 801fa71f3..6d5a2e7b9 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -1367,6 +1367,11 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) if (!clipboard) return ERROR_INTERNAL_ERROR; + if (!IsClipboardFormatAvailable(CF_HDROP)) + { + return ERROR_SUCCESS; + } + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); /* Ignore if other app is holding clipboard */ @@ -1392,21 +1397,11 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) } index = 0; - - if (IsClipboardFormatAvailable(CF_HDROP)) - { - UINT fsid = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); - UINT fcid = RegisterClipboardFormat(CFSTR_FILECONTENTS); - - formats[index++].formatId = fsid; - formats[index++].formatId = fcid; - } - else - { - while (formatId = EnumClipboardFormats(formatId) && index < numFormats) - formats[index++].formatId = formatId; - } - + // IsClipboardFormatAvailable(CF_HDROP) is checked above + UINT fsid = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); + UINT fcid = RegisterClipboardFormat(CFSTR_FILECONTENTS); + formats[index++].formatId = fsid; + formats[index++].formatId = fcid; numFormats = index; if (!CloseClipboard()) @@ -2215,6 +2210,7 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext *context, for (i = 0; i < formatList->numFormats; i++) { + printf("REMOVE ME ========================== idx: %d, format id: %d\n", i, formatList->formats[i].formatId); format = &(formatList->formats[i]); mapping = &(clipboard->format_mappings[i]); mapping->remote_format_id = format->formatId; @@ -2594,6 +2590,7 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context, { // BOOL emptyRes = wf_do_empty_cliprdr((wfClipboard *)context->custom); // (void)emptyRes; + printf("REMOVE ME ================================= msg flags: %d\n", formatDataResponse->msgFlags); rc = E_FAIL; break; } From 549dc057132dd48de95584403e5c4acdb28e58cd Mon Sep 17 00:00:00 2001 From: dignow Date: Sun, 30 Jul 2023 17:16:25 +0800 Subject: [PATCH 4/8] add debug log Signed-off-by: dignow --- libs/clipboard/src/lib.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index ea659b550..2cec93237 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -535,8 +535,6 @@ extern "C" fn client_format_list( _context: *mut CliprdrClientContext, clip_format_list: *const CLIPRDR_FORMAT_LIST, ) -> UINT { - log::debug!("client_format_list called"); - let conn_id; let mut format_list: Vec<(i32, String)> = Vec::new(); unsafe { @@ -561,6 +559,8 @@ extern "C" fn client_format_list( } conn_id = (*clip_format_list).connID as i32; } + log::debug!("client_format_list called, client id: {}, format_list: {:?}", conn_id, &format_list); + let data = ClipboardFile::FormatList { format_list }; // no need to handle result here if conn_id == 0 { @@ -580,14 +580,13 @@ extern "C" fn client_format_list_response( _context: *mut CliprdrClientContext, format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE, ) -> UINT { - log::debug!("client_format_list_response called"); - let conn_id; let msg_flags; unsafe { conn_id = (*format_list_response).connID as i32; msg_flags = (*format_list_response).msgFlags as i32; } + log::debug!("client_format_list_response called, client id: {}, msg_flags: {}", conn_id, msg_flags); let data = ClipboardFile::FormatListResponse { msg_flags }; send_data(conn_id, data); @@ -618,8 +617,6 @@ extern "C" fn client_format_data_response( _context: *mut CliprdrClientContext, format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE, ) -> UINT { - log::debug!("cconn_idlient_format_data_response called"); - let conn_id; let msg_flags; let format_data; @@ -636,6 +633,7 @@ extern "C" fn client_format_data_response( .to_vec(); } } + log::debug!("client_format_data_response called, client id: {}, msg_flags: {}", conn_id, msg_flags); let data = ClipboardFile::FormatDataResponse { msg_flags, format_data, @@ -649,8 +647,6 @@ extern "C" fn client_file_contents_request( _context: *mut CliprdrClientContext, file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST, ) -> UINT { - log::debug!("client_file_contents_request called"); - // TODO: support huge file? // if (!cliprdr->hasHugeFileSupport) // { @@ -692,6 +688,8 @@ extern "C" fn client_file_contents_request( have_clip_data_id, clip_data_id, }; + log::debug!("client_file_contents_request called, data: {:?}", &data); + send_data(conn_id, data); 0 @@ -701,8 +699,6 @@ extern "C" fn client_file_contents_response( _context: *mut CliprdrClientContext, file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE, ) -> UINT { - log::debug!("client_file_contents_response called"); - let conn_id; let msg_flags; let stream_id; @@ -726,6 +722,7 @@ extern "C" fn client_file_contents_response( stream_id, requested_data, }; + log::debug!("client_file_contents_response called, conn_id: {}, msg_flags: {}, stream_id: {}", conn_id, msg_flags, stream_id); send_data(conn_id, data); 0 From 50c737694f739539b6af3f7e2ba353127d2f247b Mon Sep 17 00:00:00 2001 From: dignow Date: Sun, 30 Jul 2023 17:25:35 +0800 Subject: [PATCH 5/8] remove debug log Signed-off-by: dignow --- libs/clipboard/src/lib.rs | 3 --- libs/clipboard/src/windows/wf_cliprdr.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 2cec93237..7a5941029 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -560,7 +560,6 @@ extern "C" fn client_format_list( conn_id = (*clip_format_list).connID as i32; } log::debug!("client_format_list called, client id: {}, format_list: {:?}", conn_id, &format_list); - let data = ClipboardFile::FormatList { format_list }; // no need to handle result here if conn_id == 0 { @@ -677,7 +676,6 @@ extern "C" fn client_file_contents_request( have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; clip_data_id = (*file_contents_request).clipDataId as i32; } - let data = ClipboardFile::FileContentsRequest { stream_id, list_index, @@ -689,7 +687,6 @@ extern "C" fn client_file_contents_request( clip_data_id, }; log::debug!("client_file_contents_request called, data: {:?}", &data); - send_data(conn_id, data); 0 diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 6d5a2e7b9..c8f2038a1 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -2210,7 +2210,6 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext *context, for (i = 0; i < formatList->numFormats; i++) { - printf("REMOVE ME ========================== idx: %d, format id: %d\n", i, formatList->formats[i].formatId); format = &(formatList->formats[i]); mapping = &(clipboard->format_mappings[i]); mapping->remote_format_id = format->formatId; @@ -2590,7 +2589,6 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context, { // BOOL emptyRes = wf_do_empty_cliprdr((wfClipboard *)context->custom); // (void)emptyRes; - printf("REMOVE ME ================================= msg flags: %d\n", formatDataResponse->msgFlags); rc = E_FAIL; break; } From a4600dd8a85e4b2dbe9e4b02bc9cba8c7848ee87 Mon Sep 17 00:00:00 2001 From: dignow Date: Sun, 30 Jul 2023 19:12:51 +0800 Subject: [PATCH 6/8] refact, minimize on fullscreen Signed-off-by: dignow --- .../lib/desktop/widgets/remote_toolbar.dart | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index ab74dab59..dcf78b27b 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1896,6 +1896,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { padding: MaterialStateProperty.all(EdgeInsets.zero), ); final isFullscreen = stateGlobal.fullscreen; + const double iconSize = 20; final child = Row( mainAxisSize: MainAxisSize.min, children: [ @@ -1905,18 +1906,24 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { widget.setFullscreen(!isFullscreen); setState(() {}); }, - child: Icon( - isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen, - size: 20, + child: Tooltip( + message: translate(isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'), + child: Icon( + isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen, + size: iconSize, + ), ), ), Offstage( offstage: !isFullscreen, child: TextButton( onPressed: () => widget.setMinimize(), - child: Icon( - Icons.minimize, - size: 20, + child: Tooltip( + message: translate('Minimize'), + child: Icon( + Icons.remove, + size: iconSize, + ), ), ), ), @@ -1924,9 +1931,13 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { onPressed: () => setState(() { widget.show.value = !widget.show.value; }), - child: Obx((() => Icon( - widget.show.isTrue ? Icons.expand_less : Icons.expand_more, - size: 20, + child: Obx((() => Tooltip( + message: translate( + widget.show.isTrue ? 'Hide Toolbar' : 'Show Toolbar'), + child: Icon( + widget.show.isTrue ? Icons.expand_less : Icons.expand_more, + size: iconSize, + ), ))), ), ], @@ -2008,7 +2019,8 @@ class _MultiMonitorMenu extends StatelessWidget { children: [ SvgPicture.asset( "assets/screen.svg", - colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + colorFilter: + ColorFilter.mode(Colors.white, BlendMode.srcIn), ), Obx( () => Text( From 086c48cea9a78d057cb991ad89c86d0de81c50ba Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Mon, 31 Jul 2023 08:44:54 +0200 Subject: [PATCH 7/8] Update nl.rs --- src/lang/nl.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 92bd7fd1f..7c6d7ba05 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -1,4 +1,4 @@ -lazy_static::lazy_static! { +vicelazy_static::lazy_static! { pub static ref T: std::collections::HashMap<&'static str, &'static str> = [ ("Status", "Status"), @@ -518,11 +518,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Exit", "Verlaten"), ("Open", "Open"), ("logout_tip", "Weet je zeker dat je je wilt afmelden?"), - ("Service", ""), - ("Start", ""), - ("Stop", ""), - ("exceed_max_devices", ""), - ("Sync with recent sessions", ""), - ("Sort tags", ""), + ("Service", "Service"), + ("Start", "Start"), + ("Stop", "Stop"), + ("exceed_max_devices", "Het maximum aantal gecontroleerde apparaten is bereikt."), + ("Sync with recent sessions", "Recente sessies synchroniseren"), + ("Sort tags", "Labels sorteren"), ].iter().cloned().collect(); } From d649d13c97e2f26201dd98bfc40dc482959ba99e Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Mon, 31 Jul 2023 15:07:23 +0800 Subject: [PATCH 8/8] Update nl.rs --- src/lang/nl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 7c6d7ba05..c470f2270 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -1,4 +1,4 @@ -vicelazy_static::lazy_static! { +lazy_static::lazy_static! { pub static ref T: std::collections::HashMap<&'static str, &'static str> = [ ("Status", "Status"),