resolution, mid commit, to debug
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
a603e046e3
commit
07500013ff
@ -19,8 +19,6 @@ import '../../common/widgets/peer_tab_page.dart';
|
|||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
import '../widgets/button.dart';
|
import '../widgets/button.dart';
|
||||||
|
|
||||||
import 'package:flutter_hbb/common/widgets/dialog.dart';
|
|
||||||
|
|
||||||
/// Connection page for connecting to a remote peer.
|
/// Connection page for connecting to a remote peer.
|
||||||
class ConnectionPage extends StatefulWidget {
|
class ConnectionPage extends StatefulWidget {
|
||||||
const ConnectionPage({Key? key}) : super(key: key);
|
const ConnectionPage({Key? key}) : super(key: key);
|
||||||
|
@ -664,71 +664,24 @@ class _ControlMenu extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DisplayMenu extends StatefulWidget {
|
class ScreenAdjustor {
|
||||||
final String id;
|
final String id;
|
||||||
final FFI ffi;
|
final FFI ffi;
|
||||||
final MenubarState state;
|
final VoidCallback cbExitFullscreen;
|
||||||
final Function(bool) setFullscreen;
|
|
||||||
final Widget pluginItem;
|
|
||||||
_DisplayMenu(
|
|
||||||
{Key? key,
|
|
||||||
required this.id,
|
|
||||||
required this.ffi,
|
|
||||||
required this.state,
|
|
||||||
required this.setFullscreen})
|
|
||||||
: pluginItem = LocationItem.createLocationItem(
|
|
||||||
id,
|
|
||||||
ffi,
|
|
||||||
kLocationClientRemoteToolbarDisplay,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_DisplayMenu> createState() => _DisplayMenuState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DisplayMenuState extends State<_DisplayMenu> {
|
|
||||||
window_size.Screen? _screen;
|
window_size.Screen? _screen;
|
||||||
|
|
||||||
|
ScreenAdjustor({
|
||||||
|
required this.id,
|
||||||
|
required this.ffi,
|
||||||
|
required this.cbExitFullscreen,
|
||||||
|
});
|
||||||
|
|
||||||
bool get isFullscreen => stateGlobal.fullscreen;
|
bool get isFullscreen => stateGlobal.fullscreen;
|
||||||
|
|
||||||
int get windowId => stateGlobal.windowId;
|
int get windowId => stateGlobal.windowId;
|
||||||
|
|
||||||
Map<String, bool> get perms => widget.ffi.ffiModel.permissions;
|
|
||||||
RxBool _isOrignalResolution = true.obs;
|
|
||||||
RxBool _isFitLocalResolution = false.obs;
|
|
||||||
|
|
||||||
PeerInfo get pi => widget.ffi.ffiModel.pi;
|
|
||||||
FfiModel get ffiModel => widget.ffi.ffiModel;
|
|
||||||
FFI get ffi => widget.ffi;
|
|
||||||
String get id => widget.id;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
_updateScreen();
|
|
||||||
return _IconSubmenuButton(
|
|
||||||
tooltip: 'Display Settings',
|
|
||||||
svg: "assets/display.svg",
|
|
||||||
ffi: widget.ffi,
|
|
||||||
color: _MenubarTheme.blueColor,
|
|
||||||
hoverColor: _MenubarTheme.hoverBlueColor,
|
|
||||||
menuChildren: [
|
|
||||||
adjustWindow(),
|
|
||||||
viewStyle(),
|
|
||||||
scrollStyle(),
|
|
||||||
imageQuality(),
|
|
||||||
codec(),
|
|
||||||
resolutions(),
|
|
||||||
Divider(),
|
|
||||||
toggles(),
|
|
||||||
widget.pluginItem,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustWindow() {
|
adjustWindow() {
|
||||||
return futureBuilder(
|
return futureBuilder(
|
||||||
future: _isWindowCanBeAdjusted(),
|
future: isWindowCanBeAdjusted(),
|
||||||
hasData: (data) {
|
hasData: (data) {
|
||||||
final visible = data as bool;
|
final visible = data as bool;
|
||||||
if (!visible) return Offstage();
|
if (!visible) return Offstage();
|
||||||
@ -736,18 +689,18 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
children: [
|
children: [
|
||||||
MenuButton(
|
MenuButton(
|
||||||
child: Text(translate('Adjust Window')),
|
child: Text(translate('Adjust Window')),
|
||||||
onPressed: _doAdjustWindow,
|
onPressed: doAdjustWindow,
|
||||||
ffi: widget.ffi),
|
ffi: ffi),
|
||||||
Divider(),
|
Divider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_doAdjustWindow() async {
|
doAdjustWindow() async {
|
||||||
await _updateScreen();
|
await updateScreen();
|
||||||
if (_screen != null) {
|
if (_screen != null) {
|
||||||
widget.setFullscreen(false);
|
cbExitFullscreen();
|
||||||
double scale = _screen!.scaleFactor;
|
double scale = _screen!.scaleFactor;
|
||||||
final wndRect = await WindowController.fromWindowId(windowId).getFrame();
|
final wndRect = await WindowController.fromWindowId(windowId).getFrame();
|
||||||
final mediaSize = MediaQueryData.fromWindow(ui.window).size;
|
final mediaSize = MediaQueryData.fromWindow(ui.window).size;
|
||||||
@ -758,7 +711,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
double magicHeight =
|
double magicHeight =
|
||||||
wndRect.bottom - wndRect.top - mediaSize.height * scale;
|
wndRect.bottom - wndRect.top - mediaSize.height * scale;
|
||||||
|
|
||||||
final canvasModel = widget.ffi.canvasModel;
|
final canvasModel = ffi.canvasModel;
|
||||||
final width = (canvasModel.getDisplayWidth() * canvasModel.scale +
|
final width = (canvasModel.getDisplayWidth() * canvasModel.scale +
|
||||||
CanvasModel.leftToEdge +
|
CanvasModel.leftToEdge +
|
||||||
CanvasModel.rightToEdge) *
|
CanvasModel.rightToEdge) *
|
||||||
@ -793,7 +746,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateScreen() async {
|
updateScreen() async {
|
||||||
final v = await rustDeskWinManager.call(
|
final v = await rustDeskWinManager.call(
|
||||||
WindowType.Main, kWindowGetWindowInfo, '');
|
WindowType.Main, kWindowGetWindowInfo, '');
|
||||||
final String valueStr = v;
|
final String valueStr = v;
|
||||||
@ -813,8 +766,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _isWindowCanBeAdjusted() async {
|
Future<bool> isWindowCanBeAdjusted() async {
|
||||||
final viewStyle = await bind.sessionGetViewStyle(id: widget.id) ?? '';
|
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? '';
|
||||||
if (viewStyle != kRemoteViewStyleOriginal) {
|
if (viewStyle != kRemoteViewStyleOriginal) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -833,7 +786,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
selfHeight = _screen!.frame.height;
|
selfHeight = _screen!.frame.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
final canvasModel = widget.ffi.canvasModel;
|
final canvasModel = ffi.canvasModel;
|
||||||
final displayWidth = canvasModel.getDisplayWidth();
|
final displayWidth = canvasModel.getDisplayWidth();
|
||||||
final displayHeight = canvasModel.getDisplayHeight();
|
final displayHeight = canvasModel.getDisplayHeight();
|
||||||
final requiredWidth =
|
final requiredWidth =
|
||||||
@ -843,6 +796,77 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
return selfWidth > (requiredWidth * scale) &&
|
return selfWidth > (requiredWidth * scale) &&
|
||||||
selfHeight > (requiredHeight * scale);
|
selfHeight > (requiredHeight * scale);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DisplayMenu extends StatefulWidget {
|
||||||
|
final String id;
|
||||||
|
final FFI ffi;
|
||||||
|
final MenubarState state;
|
||||||
|
final Function(bool) setFullscreen;
|
||||||
|
final Widget pluginItem;
|
||||||
|
_DisplayMenu(
|
||||||
|
{Key? key,
|
||||||
|
required this.id,
|
||||||
|
required this.ffi,
|
||||||
|
required this.state,
|
||||||
|
required this.setFullscreen})
|
||||||
|
: pluginItem = LocationItem.createLocationItem(
|
||||||
|
id,
|
||||||
|
ffi,
|
||||||
|
kLocationClientRemoteToolbarDisplay,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_DisplayMenu> createState() => _DisplayMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DisplayMenuState extends State<_DisplayMenu> {
|
||||||
|
late final ScreenAdjustor _screenAdjustor = ScreenAdjustor(
|
||||||
|
id: widget.id,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
cbExitFullscreen: () => widget.setFullscreen(false),
|
||||||
|
);
|
||||||
|
|
||||||
|
bool get isFullscreen => stateGlobal.fullscreen;
|
||||||
|
int get windowId => stateGlobal.windowId;
|
||||||
|
Map<String, bool> get perms => widget.ffi.ffiModel.permissions;
|
||||||
|
PeerInfo get pi => widget.ffi.ffiModel.pi;
|
||||||
|
FfiModel get ffiModel => widget.ffi.ffiModel;
|
||||||
|
FFI get ffi => widget.ffi;
|
||||||
|
String get id => widget.id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_screenAdjustor.updateScreen();
|
||||||
|
return _IconSubmenuButton(
|
||||||
|
tooltip: 'Display Settings',
|
||||||
|
svg: "assets/display.svg",
|
||||||
|
ffi: widget.ffi,
|
||||||
|
color: _MenubarTheme.blueColor,
|
||||||
|
hoverColor: _MenubarTheme.hoverBlueColor,
|
||||||
|
menuChildren: [
|
||||||
|
_screenAdjustor.adjustWindow(),
|
||||||
|
viewStyle(),
|
||||||
|
scrollStyle(),
|
||||||
|
imageQuality(),
|
||||||
|
codec(),
|
||||||
|
_ResolutionsMenu(
|
||||||
|
id: widget.id,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
screenAdjustor: _screenAdjustor,
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
toggles(),
|
||||||
|
widget.pluginItem,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
viewStyle() {
|
viewStyle() {
|
||||||
return futureBuilder(
|
return futureBuilder(
|
||||||
@ -941,70 +965,6 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolutions() {
|
|
||||||
final resolutions = pi.resolutions;
|
|
||||||
final visible = ffiModel.keyboard && resolutions.length > 1;
|
|
||||||
if (!visible) return Offstage();
|
|
||||||
final display = ffiModel.display;
|
|
||||||
final groupValue = "${display.width}x${display.height}";
|
|
||||||
onChanged(String? value) async {
|
|
||||||
if (value == null) return;
|
|
||||||
|
|
||||||
final list = value.split('x');
|
|
||||||
if (list.length == 2) {
|
|
||||||
final w = int.tryParse(list[0]);
|
|
||||||
final h = int.tryParse(list[1]);
|
|
||||||
if (w != null && h != null) {
|
|
||||||
await bind.sessionChangeResolution(
|
|
||||||
id: widget.id, width: w, height: h);
|
|
||||||
Future.delayed(Duration(seconds: 3), () async {
|
|
||||||
final display = ffiModel.display;
|
|
||||||
if (w == display.width && h == display.height) {
|
|
||||||
if (await _isWindowCanBeAdjusted()) {
|
|
||||||
_doAdjustWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _SubmenuButton(
|
|
||||||
ffi: widget.ffi,
|
|
||||||
menuChildren: [
|
|
||||||
RdoMenuButton(
|
|
||||||
value: _kResolutionOrigin,
|
|
||||||
groupValue: groupValue,
|
|
||||||
onChanged: onChanged,
|
|
||||||
ffi: widget.ffi,
|
|
||||||
child: Text('Origin'),
|
|
||||||
),
|
|
||||||
RdoMenuButton(
|
|
||||||
value: _kResolutionFitLocal,
|
|
||||||
groupValue: groupValue,
|
|
||||||
onChanged: onChanged,
|
|
||||||
ffi: widget.ffi,
|
|
||||||
child: Text('Fit local'),
|
|
||||||
),
|
|
||||||
// RdoMenuButton(
|
|
||||||
// value: _kResolutionCustom,
|
|
||||||
// groupValue: groupValue,
|
|
||||||
// onChanged: onChanged,
|
|
||||||
// ffi: widget.ffi,
|
|
||||||
// child: Text('Custom resolution'),
|
|
||||||
// ),
|
|
||||||
] +
|
|
||||||
resolutions
|
|
||||||
.map((e) => RdoMenuButton(
|
|
||||||
value: '${e.width}x${e.height}',
|
|
||||||
groupValue: groupValue,
|
|
||||||
onChanged: onChanged,
|
|
||||||
ffi: widget.ffi,
|
|
||||||
child: Text('${e.width}x${e.height}')))
|
|
||||||
.toList(),
|
|
||||||
child: Text(translate("Resolution")));
|
|
||||||
}
|
|
||||||
|
|
||||||
toggles() {
|
toggles() {
|
||||||
return futureBuilder(
|
return futureBuilder(
|
||||||
future: toolbarDisplayToggle(context, id, ffi),
|
future: toolbarDisplayToggle(context, id, ffi),
|
||||||
@ -1023,6 +983,242 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ResolutionsMenu extends StatefulWidget {
|
||||||
|
final String id;
|
||||||
|
final FFI ffi;
|
||||||
|
final ScreenAdjustor screenAdjustor;
|
||||||
|
|
||||||
|
_ResolutionsMenu({
|
||||||
|
Key? key,
|
||||||
|
required this.id,
|
||||||
|
required this.ffi,
|
||||||
|
required this.screenAdjustor,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ResolutionsMenu> createState() => _ResolutionsMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ResolutionsMenuState extends State<_ResolutionsMenu> {
|
||||||
|
String _groupValue = '';
|
||||||
|
Resolution? _localResolution;
|
||||||
|
late final _customWidth =
|
||||||
|
TextEditingController(text: display.width.toString());
|
||||||
|
late final _customHeight =
|
||||||
|
TextEditingController(text: display.height.toString());
|
||||||
|
|
||||||
|
PeerInfo get pi => widget.ffi.ffiModel.pi;
|
||||||
|
FfiModel get ffiModel => widget.ffi.ffiModel;
|
||||||
|
Display get display => ffiModel.display;
|
||||||
|
List<Resolution> get resolutions => pi.resolutions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final visible = ffiModel.keyboard && resolutions.length > 1;
|
||||||
|
if (!visible) return Offstage();
|
||||||
|
_groupValue = "${display.width}x${display.height}";
|
||||||
|
|
||||||
|
_getLocalResolution();
|
||||||
|
return _SubmenuButton(
|
||||||
|
ffi: widget.ffi,
|
||||||
|
menuChildren: <Widget>[
|
||||||
|
_OriginalResolutionMenuButton(),
|
||||||
|
_FitLocalResolutionMenuButton(),
|
||||||
|
_customResolutionMenuButton(),
|
||||||
|
] +
|
||||||
|
_supportedResolutionMenuButtons(),
|
||||||
|
child: Text(translate("Resolution")));
|
||||||
|
}
|
||||||
|
|
||||||
|
_getLocalResolution() {
|
||||||
|
_localResolution = null;
|
||||||
|
final String currentDisplay = bind.mainGetCurrentDisplay();
|
||||||
|
if (currentDisplay.isNotEmpty) {
|
||||||
|
try {
|
||||||
|
final display = json.decode(currentDisplay);
|
||||||
|
if (display['w'] != null && display['h'] != null) {
|
||||||
|
_localResolution = Resolution(display['w'], display['h']);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Failed to decode $currentDisplay, $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onChanged(String? value) async {
|
||||||
|
if (value == null) return;
|
||||||
|
|
||||||
|
int? w;
|
||||||
|
int? h;
|
||||||
|
if (value == _kResolutionOrigin) {
|
||||||
|
w = display.originalWidth;
|
||||||
|
h = display.originalHeight;
|
||||||
|
} else if (value == _kResolutionFitLocal) {
|
||||||
|
final resolution = _getBestFitResolution();
|
||||||
|
if (resolution != null) {
|
||||||
|
w = resolution.width;
|
||||||
|
h = resolution.height;
|
||||||
|
}
|
||||||
|
} else if (value == _kResolutionCustom) {
|
||||||
|
debugPrint(
|
||||||
|
'REMOVE ME ======================= ${_customWidth.value} ${_customHeight.value}');
|
||||||
|
w = int.tryParse(_customWidth.value as String);
|
||||||
|
h = int.tryParse(_customHeight.value as String);
|
||||||
|
} else {
|
||||||
|
final list = value.split('x');
|
||||||
|
if (list.length == 2) {
|
||||||
|
w = int.tryParse(list[0]);
|
||||||
|
h = int.tryParse(list[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w != null && h != null) {
|
||||||
|
await bind.sessionChangeResolution(
|
||||||
|
id: widget.id,
|
||||||
|
width: w,
|
||||||
|
height: h,
|
||||||
|
);
|
||||||
|
Future.delayed(Duration(seconds: 3), () async {
|
||||||
|
final display = ffiModel.display;
|
||||||
|
if (w == display.width && h == display.height) {
|
||||||
|
if (await widget.screenAdjustor.isWindowCanBeAdjusted()) {
|
||||||
|
widget.screenAdjustor.doAdjustWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _OriginalResolutionMenuButton() {
|
||||||
|
return Offstage(
|
||||||
|
offstage: display.isOriginalResolution,
|
||||||
|
child: RdoMenuButton(
|
||||||
|
value: _kResolutionOrigin,
|
||||||
|
groupValue: _groupValue,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: Text(
|
||||||
|
'${translate('Original')} ${display.originalWidth}x${display.originalHeight}'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _FitLocalResolutionMenuButton() {
|
||||||
|
return Offstage(
|
||||||
|
offstage: _isRemoteResolutionFitLocal(),
|
||||||
|
child: RdoMenuButton(
|
||||||
|
value: _kResolutionFitLocal,
|
||||||
|
groupValue: _groupValue,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: Text(
|
||||||
|
'${translate('Fit Local')} ${display.originalWidth}x${display.originalHeight}'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _supportedResolutionMenuButtons() => resolutions
|
||||||
|
.map((e) => RdoMenuButton(
|
||||||
|
value: '${e.width}x${e.height}',
|
||||||
|
groupValue: _groupValue,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: Text('${e.width}x${e.height}')))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Widget _customResolutionMenuButton() {
|
||||||
|
return Offstage(
|
||||||
|
offstage: _isRemoteResolutionFitLocal(),
|
||||||
|
child: RdoMenuButton(
|
||||||
|
value: _kResolutionCustom,
|
||||||
|
groupValue: _groupValue,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: _customResolutionWidget(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _customResolutionWidget() {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(translate('Custom')),
|
||||||
|
SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
|
_resolutionInput(_customWidth),
|
||||||
|
SizedBox(
|
||||||
|
width: 3,
|
||||||
|
),
|
||||||
|
Text('x'),
|
||||||
|
SizedBox(
|
||||||
|
width: 3,
|
||||||
|
),
|
||||||
|
_resolutionInput(_customHeight),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField _resolutionInput(TextEditingController controller) {
|
||||||
|
return TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
LengthLimitingTextInputFormatter(4),
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||||
|
],
|
||||||
|
controller: controller,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Resolution? _getBestFitResolution() {
|
||||||
|
if (_localResolution == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
squareDistance(Resolution lhs, Resolution rhs) =>
|
||||||
|
(lhs.width - rhs.width) * (lhs.width - rhs.width) +
|
||||||
|
(lhs.height - rhs.height) * (lhs.height - rhs.height);
|
||||||
|
|
||||||
|
Resolution? res;
|
||||||
|
for (final r in resolutions) {
|
||||||
|
if (r.width <= _localResolution!.width &&
|
||||||
|
r.height <= _localResolution!.height) {
|
||||||
|
if (res == null) {
|
||||||
|
res = r;
|
||||||
|
} else {
|
||||||
|
if (squareDistance(r, _localResolution!) <
|
||||||
|
squareDistance(res, _localResolution!)) {
|
||||||
|
res = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isRemoteResolutionFitLocal() {
|
||||||
|
if (_localResolution == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final bestFitResolution = _getBestFitResolution();
|
||||||
|
if (bestFitResolution == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return bestFitResolution.width == display.width &&
|
||||||
|
bestFitResolution.height == display.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _KeyboardMenu extends StatelessWidget {
|
class _KeyboardMenu extends StatelessWidget {
|
||||||
final String id;
|
final String id;
|
||||||
final FFI ffi;
|
final FFI ffi;
|
||||||
|
@ -295,11 +295,15 @@ class FfiModel with ChangeNotifier {
|
|||||||
handleSwitchDisplay(Map<String, dynamic> evt, String peerId) {
|
handleSwitchDisplay(Map<String, dynamic> evt, String peerId) {
|
||||||
_pi.currentDisplay = int.parse(evt['display']);
|
_pi.currentDisplay = int.parse(evt['display']);
|
||||||
var newDisplay = Display();
|
var newDisplay = Display();
|
||||||
newDisplay.x = double.parse(evt['x']);
|
newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x;
|
||||||
newDisplay.y = double.parse(evt['y']);
|
newDisplay.y = double.tryParse(evt['y']) ?? newDisplay.y;
|
||||||
newDisplay.width = int.parse(evt['width']);
|
newDisplay.width = int.tryParse(evt['width']) ?? newDisplay.width;
|
||||||
newDisplay.height = int.parse(evt['height']);
|
newDisplay.height = int.tryParse(evt['height']) ?? newDisplay.height;
|
||||||
newDisplay.cursorEmbedded = int.parse(evt['cursor_embedded']) == 1;
|
newDisplay.cursorEmbedded = int.tryParse(evt['cursor_embedded']) == 1;
|
||||||
|
newDisplay.originalWidth =
|
||||||
|
int.tryParse(evt['original_width']) ?? newDisplay.originalWidth;
|
||||||
|
newDisplay.originalHeight =
|
||||||
|
int.tryParse(evt['original_height']) ?? newDisplay.originalHeight;
|
||||||
|
|
||||||
_updateCurDisplay(peerId, newDisplay);
|
_updateCurDisplay(peerId, newDisplay);
|
||||||
|
|
||||||
@ -466,14 +470,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
_pi.displays = [];
|
_pi.displays = [];
|
||||||
List<dynamic> displays = json.decode(evt['displays']);
|
List<dynamic> displays = json.decode(evt['displays']);
|
||||||
for (int i = 0; i < displays.length; ++i) {
|
for (int i = 0; i < displays.length; ++i) {
|
||||||
Map<String, dynamic> d0 = displays[i];
|
_pi.displays.add(evtToDisplay(displays[i]));
|
||||||
var d = Display();
|
|
||||||
d.x = d0['x'].toDouble();
|
|
||||||
d.y = d0['y'].toDouble();
|
|
||||||
d.width = d0['width'];
|
|
||||||
d.height = d0['height'];
|
|
||||||
d.cursorEmbedded = d0['cursor_embedded'] == 1;
|
|
||||||
_pi.displays.add(d);
|
|
||||||
}
|
}
|
||||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||||
if (_pi.currentDisplay < _pi.displays.length) {
|
if (_pi.currentDisplay < _pi.displays.length) {
|
||||||
@ -533,20 +530,25 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Display evtToDisplay(Map<String, dynamic> evt) {
|
||||||
|
var d = Display();
|
||||||
|
d.x = evt['x']?.toDouble() ?? d.x;
|
||||||
|
d.y = evt['y']?.toDouble() ?? d.y;
|
||||||
|
d.width = evt['width'] ?? d.width;
|
||||||
|
d.height = evt['height'] ?? d.height;
|
||||||
|
d.cursorEmbedded = evt['cursor_embedded'] == 1;
|
||||||
|
d.originalWidth = evt['original_width'] ?? d.originalWidth;
|
||||||
|
d.originalHeight = evt['original_height'] ?? d.originalHeight;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the peer info synchronization event based on [evt].
|
/// Handle the peer info synchronization event based on [evt].
|
||||||
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async {
|
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async {
|
||||||
if (evt['displays'] != null) {
|
if (evt['displays'] != null) {
|
||||||
List<dynamic> displays = json.decode(evt['displays']);
|
List<dynamic> displays = json.decode(evt['displays']);
|
||||||
List<Display> newDisplays = [];
|
List<Display> newDisplays = [];
|
||||||
for (int i = 0; i < displays.length; ++i) {
|
for (int i = 0; i < displays.length; ++i) {
|
||||||
Map<String, dynamic> d0 = displays[i];
|
newDisplays.add(evtToDisplay(displays[i]));
|
||||||
var d = Display();
|
|
||||||
d.x = d0['x'].toDouble();
|
|
||||||
d.y = d0['y'].toDouble();
|
|
||||||
d.width = d0['width'];
|
|
||||||
d.height = d0['height'];
|
|
||||||
d.cursorEmbedded = d0['cursor_embedded'] == 1;
|
|
||||||
newDisplays.add(d);
|
|
||||||
}
|
}
|
||||||
_pi.displays = newDisplays;
|
_pi.displays = newDisplays;
|
||||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||||
@ -1718,6 +1720,8 @@ class Display {
|
|||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
bool cursorEmbedded = false;
|
bool cursorEmbedded = false;
|
||||||
|
int originalWidth = 0;
|
||||||
|
int originalHeight = 0;
|
||||||
|
|
||||||
Display() {
|
Display() {
|
||||||
width = (isDesktop || isWebDesktop)
|
width = (isDesktop || isWebDesktop)
|
||||||
@ -1740,6 +1744,9 @@ class Display {
|
|||||||
other.width == width &&
|
other.width == width &&
|
||||||
other.height == height &&
|
other.height == height &&
|
||||||
other.cursorEmbedded == cursorEmbedded;
|
other.cursorEmbedded == cursorEmbedded;
|
||||||
|
|
||||||
|
bool get isOriginalResolution =>
|
||||||
|
width == originalWidth && height == originalHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Resolution {
|
class Resolution {
|
||||||
|
@ -1211,6 +1211,14 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
s.cursor_embedded,
|
s.cursor_embedded,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let custom_resolution = if s.width != s.original_resolution.width
|
||||||
|
|| s.height != s.original_resolution.height
|
||||||
|
{
|
||||||
|
Some((s.width, s.height))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
self.handler.set_custom_resolution(custom_resolution);
|
||||||
}
|
}
|
||||||
Some(misc::Union::CloseReason(c)) => {
|
Some(misc::Union::CloseReason(c)) => {
|
||||||
self.handler.msgbox("error", "Connection Error", &c, "");
|
self.handler.msgbox("error", "Connection Error", &c, "");
|
||||||
|
@ -286,6 +286,8 @@ impl FlutterHandler {
|
|||||||
h.insert("width", d.width);
|
h.insert("width", d.width);
|
||||||
h.insert("height", d.height);
|
h.insert("height", d.height);
|
||||||
h.insert("cursor_embedded", if d.cursor_embedded { 1 } else { 0 });
|
h.insert("cursor_embedded", if d.cursor_embedded { 1 } else { 0 });
|
||||||
|
h.insert("original_width", d.original_resolution.width);
|
||||||
|
h.insert("original_height", d.original_resolution.height);
|
||||||
msg_vec.push(h);
|
msg_vec.push(h);
|
||||||
}
|
}
|
||||||
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
||||||
@ -618,6 +620,14 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
("resolutions", &resolutions),
|
("resolutions", &resolutions),
|
||||||
|
(
|
||||||
|
"original_width",
|
||||||
|
&display.original_resolution.width.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"original_height",
|
||||||
|
&display.original_resolution.height.to_string(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -880,6 +880,18 @@ pub fn main_handle_relay_id(id: String) -> String {
|
|||||||
handle_relay_id(id)
|
handle_relay_id(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main_get_current_display() -> SyncReturn<String> {
|
||||||
|
let display_info = match crate::video_service::get_current_display() {
|
||||||
|
Ok((_, _, display)) => serde_json::to_string(&HashMap::from([
|
||||||
|
("w", display.width()),
|
||||||
|
("h", display.height()),
|
||||||
|
]))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
Err(..) => "".to_string(),
|
||||||
|
};
|
||||||
|
SyncReturn(display_info)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn session_add_port_forward(
|
pub fn session_add_port_forward(
|
||||||
id: String,
|
id: String,
|
||||||
local_port: i32,
|
local_port: i32,
|
||||||
@ -1426,10 +1438,10 @@ pub fn plugin_event(_id: String, _peer: String, _event: Vec<u8>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin_register_event_stream(id: String, event2ui: StreamSink<EventToUI>) {
|
pub fn plugin_register_event_stream(_id: String, _event2ui: StreamSink<EventToUI>) {
|
||||||
#[cfg(feature = "plugin_framework")]
|
#[cfg(feature = "plugin_framework")]
|
||||||
{
|
{
|
||||||
crate::plugin::native_handlers::session::session_register_event_stream(id, event2ui);
|
crate::plugin::native_handlers::session::session_register_event_stream(_id, _event2ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1577,16 +1589,16 @@ pub fn plugin_list_reload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin_install(id: String, b: bool) {
|
pub fn plugin_install(_id: String, _b: bool) {
|
||||||
#[cfg(feature = "plugin_framework")]
|
#[cfg(feature = "plugin_framework")]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
{
|
{
|
||||||
if b {
|
if _b {
|
||||||
if let Err(e) = crate::plugin::install_plugin(&id) {
|
if let Err(e) = crate::plugin::install_plugin(&id) {
|
||||||
log::error!("Failed to install plugin '{}': {}", id, e);
|
log::error!("Failed to install plugin '{}': {}", id, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
crate::plugin::uninstall_plugin(&id, true);
|
crate::plugin::uninstall_plugin(&_id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,11 +829,12 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_custom_resolution(&mut self, wh: Option<(i32, i32)>) {
|
||||||
|
self.lc.write().unwrap().set_custom_resolution(wh);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn change_resolution(&self, width: i32, height: i32) {
|
pub fn change_resolution(&self, width: i32, height: i32) {
|
||||||
self.lc
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.set_custom_resolution(Some((width, height)));
|
|
||||||
let mut misc = Misc::new();
|
let mut misc = Misc::new();
|
||||||
misc.set_change_resolution(Resolution {
|
misc.set_change_resolution(Resolution {
|
||||||
width,
|
width,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user