Merge pull request #1698 from 21pages/install-page
windows install page
This commit is contained in:
commit
5756bee266
10
build.py
10
build.py
@ -189,7 +189,7 @@ def build_flutter_arch_manjaro():
|
|||||||
os.chdir('..')
|
os.chdir('..')
|
||||||
os.system('HBB=`pwd` FLUTTER=1 makepkg -f')
|
os.system('HBB=`pwd` FLUTTER=1 makepkg -f')
|
||||||
|
|
||||||
def build_flutter_windows_portable():
|
def build_flutter_windows(version):
|
||||||
os.system("cargo build --lib --features flutter --release")
|
os.system("cargo build --lib --features flutter --release")
|
||||||
os.chdir('flutter')
|
os.chdir('flutter')
|
||||||
os.system("flutter build windows --release")
|
os.system("flutter build windows --release")
|
||||||
@ -203,6 +203,8 @@ def build_flutter_windows_portable():
|
|||||||
else:
|
else:
|
||||||
os.rename("./target/release/rustdesk-portable-packer.exe", "./rustdesk_portable.exe")
|
os.rename("./target/release/rustdesk-portable-packer.exe", "./rustdesk_portable.exe")
|
||||||
print(f"output location: {os.path.abspath(os.curdir)}/rustdesk_portable.exe")
|
print(f"output location: {os.path.abspath(os.curdir)}/rustdesk_portable.exe")
|
||||||
|
os.system(f"cp -rf ./rustdesk_portable.exe ./rustdesk-{version}-install.exe")
|
||||||
|
print(f"output location: {os.path.abspath(os.curdir)}/rustdesk-{version}-install.exe")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = make_parser()
|
parser = make_parser()
|
||||||
@ -227,8 +229,8 @@ def main():
|
|||||||
os.system('python3 res/inline-sciter.py')
|
os.system('python3 res/inline-sciter.py')
|
||||||
portable = args.portable
|
portable = args.portable
|
||||||
if windows:
|
if windows:
|
||||||
if portable:
|
if flutter:
|
||||||
build_flutter_windows_portable()
|
build_flutter_windows(version)
|
||||||
return
|
return
|
||||||
os.system('cargo build --release --features ' + features)
|
os.system('cargo build --release --features ' + features)
|
||||||
# os.system('upx.exe target/release/rustdesk.exe')
|
# os.system('upx.exe target/release/rustdesk.exe')
|
||||||
@ -239,7 +241,7 @@ def main():
|
|||||||
'target\\release\\rustdesk.exe')
|
'target\\release\\rustdesk.exe')
|
||||||
else:
|
else:
|
||||||
print('Not signed')
|
print('Not signed')
|
||||||
os.system(f'cp -rf target/release/RustDesk.exe rustdesk-{version}-setdown.exe')
|
os.system(f'cp -rf target/release/RustDesk.exe rustdesk-{version}-win7-install.exe')
|
||||||
elif os.path.isfile('/usr/bin/pacman'):
|
elif os.path.isfile('/usr/bin/pacman'):
|
||||||
# pacman -S -needed base-devel
|
# pacman -S -needed base-devel
|
||||||
os.system("sed -i 's/pkgver=.*/pkgver=%s/g' PKGBUILD" % version)
|
os.system("sed -i 's/pkgver=.*/pkgver=%s/g' PKGBUILD" % version)
|
||||||
|
@ -3,7 +3,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
const double kDesktopRemoteTabBarHeight = 28.0;
|
const double kDesktopRemoteTabBarHeight = 28.0;
|
||||||
|
|
||||||
/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)' , 'Desktop CM Page'
|
/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)' , 'Desktop CM Page', "Install Page"
|
||||||
const String kAppTypeMain = "main";
|
const String kAppTypeMain = "main";
|
||||||
const String kAppTypeDesktopRemote = "remote";
|
const String kAppTypeDesktopRemote = "remote";
|
||||||
const String kAppTypeDesktopFileTransfer = "file transfer";
|
const String kAppTypeDesktopFileTransfer = "file transfer";
|
||||||
|
198
flutter/lib/desktop/pages/install_page.dart
Normal file
198
flutter/lib/desktop/pages/install_page.dart
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
|
class InstallPage extends StatefulWidget {
|
||||||
|
const InstallPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InstallPage> createState() => _InstallPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InstallPageState extends State<InstallPage> with WindowListener {
|
||||||
|
late final TextEditingController controller;
|
||||||
|
final RxBool startmenu = true.obs;
|
||||||
|
final RxBool desktopicon = true.obs;
|
||||||
|
final RxBool showProgress = false.obs;
|
||||||
|
final RxBool btnEnabled = true.obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
windowManager.addListener(this);
|
||||||
|
controller = TextEditingController(text: bind.installInstallPath());
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
windowManager.removeListener(this);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onWindowClose() {
|
||||||
|
gFFI.close();
|
||||||
|
super.onWindowClose();
|
||||||
|
windowManager.setPreventClose(false);
|
||||||
|
windowManager.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double em = 13;
|
||||||
|
final btnFontSize = 0.9 * em;
|
||||||
|
final double button_radius = 6;
|
||||||
|
final buttonStyle = OutlinedButton.styleFrom(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(button_radius)),
|
||||||
|
));
|
||||||
|
final inputBorder = OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
borderSide: BorderSide(color: Colors.black12));
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
translate('Installation'),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 2 * em, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('${translate('Installation Path')}: '),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: controller,
|
||||||
|
readOnly: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 1.5 * em, fontWeight: FontWeight.w400),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: EdgeInsets.all(0.75 * em),
|
||||||
|
enabledBorder: inputBorder,
|
||||||
|
border: inputBorder,
|
||||||
|
focusedBorder: inputBorder,
|
||||||
|
constraints: BoxConstraints(maxHeight: 3 * em),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Obx(() => OutlinedButton(
|
||||||
|
onPressed:
|
||||||
|
btnEnabled.value ? selectInstallPath : null,
|
||||||
|
style: buttonStyle,
|
||||||
|
child: Text(translate('Change Path'),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black87,
|
||||||
|
fontSize: btnFontSize)))
|
||||||
|
.marginOnly(left: em))
|
||||||
|
],
|
||||||
|
).marginSymmetric(vertical: 2 * em),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Obx(() => Checkbox(
|
||||||
|
value: startmenu.value,
|
||||||
|
onChanged: (b) {
|
||||||
|
if (b != null) startmenu.value = b;
|
||||||
|
})),
|
||||||
|
Text(translate('Create start menu shortcuts'))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Obx(() => Checkbox(
|
||||||
|
value: desktopicon.value,
|
||||||
|
onChanged: (b) {
|
||||||
|
if (b != null) desktopicon.value = b;
|
||||||
|
})),
|
||||||
|
Text(translate('Create desktop icon'))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => launchUrlString('http://rustdesk.com/privacy'),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(translate('End-user license agreement'),
|
||||||
|
style: const TextStyle(
|
||||||
|
decoration: TextDecoration.underline))
|
||||||
|
],
|
||||||
|
)).marginOnly(top: 2 * em),
|
||||||
|
Row(children: [Text(translate('agreement_tip'))])
|
||||||
|
.marginOnly(top: em),
|
||||||
|
Divider(color: Colors.black87)
|
||||||
|
.marginSymmetric(vertical: 0.5 * em),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Obx(() => Offstage(
|
||||||
|
offstage: !showProgress.value,
|
||||||
|
child: LinearProgressIndicator(),
|
||||||
|
))),
|
||||||
|
Obx(() => OutlinedButton(
|
||||||
|
onPressed: btnEnabled.value
|
||||||
|
? () => windowManager.close()
|
||||||
|
: null,
|
||||||
|
style: buttonStyle,
|
||||||
|
child: Text(translate('Cancel'),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black87,
|
||||||
|
fontSize: btnFontSize)))
|
||||||
|
.marginOnly(right: 2 * em)),
|
||||||
|
Obx(() => ElevatedButton(
|
||||||
|
onPressed: btnEnabled.value ? install : null,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: MyTheme.button,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(button_radius)),
|
||||||
|
)),
|
||||||
|
child: Text(
|
||||||
|
translate('Accept and Install'),
|
||||||
|
style: TextStyle(fontSize: btnFontSize),
|
||||||
|
))),
|
||||||
|
Offstage(
|
||||||
|
offstage: bind.installShowRunWithoutInstall(),
|
||||||
|
child: Obx(() => OutlinedButton(
|
||||||
|
onPressed: btnEnabled.value
|
||||||
|
? () => bind.installRunWithoutInstall()
|
||||||
|
: null,
|
||||||
|
style: buttonStyle,
|
||||||
|
child: Text(translate('Run without install'),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black87,
|
||||||
|
fontSize: btnFontSize)))
|
||||||
|
.marginOnly(left: 2 * em)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
).paddingSymmetric(horizontal: 8 * em, vertical: 2 * em),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void install() {
|
||||||
|
btnEnabled.value = false;
|
||||||
|
showProgress.value = true;
|
||||||
|
String args = '--flutter';
|
||||||
|
if (startmenu.value) args += ' startmenu';
|
||||||
|
if (desktopicon.value) args += ' desktopicon';
|
||||||
|
bind.installInstallMe(options: args, path: controller.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectInstallPath() async {
|
||||||
|
String? install_path = await FilePicker.platform
|
||||||
|
.getDirectoryPath(initialDirectory: controller.text);
|
||||||
|
if (install_path != null) {
|
||||||
|
install_path = '$install_path\\${await bind.mainGetAppName()}';
|
||||||
|
controller.text = install_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import 'package:desktop_multi_window/desktop_multi_window.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
||||||
|
import 'package:flutter_hbb/desktop/pages/install_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart';
|
import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart';
|
||||||
import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart';
|
import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart';
|
||||||
import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart';
|
import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart';
|
||||||
@ -64,6 +65,8 @@ Future<void> main(List<String> args) async {
|
|||||||
desktopType = DesktopType.cm;
|
desktopType = DesktopType.cm;
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
runConnectionManagerScreen();
|
runConnectionManagerScreen();
|
||||||
|
} else if (args.contains('--install')) {
|
||||||
|
runInstallPage();
|
||||||
} else {
|
} else {
|
||||||
desktopType = DesktopType.main;
|
desktopType = DesktopType.main;
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
@ -215,6 +218,30 @@ void runConnectionManagerScreen() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void runInstallPage() async {
|
||||||
|
await windowManager.ensureInitialized();
|
||||||
|
await initEnv(kAppTypeMain);
|
||||||
|
runApp(GetMaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
theme: MyTheme.lightTheme,
|
||||||
|
themeMode: ThemeMode.light,
|
||||||
|
localizationsDelegates: const [
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
],
|
||||||
|
supportedLocales: supportedLocales,
|
||||||
|
home: const InstallPage(),
|
||||||
|
builder: _keepScaleBuilder()));
|
||||||
|
windowManager.waitUntilReadyToShow(
|
||||||
|
WindowOptions(size: Size(800, 600), center: true), () async {
|
||||||
|
windowManager.show();
|
||||||
|
windowManager.focus();
|
||||||
|
windowManager.setOpacity(1);
|
||||||
|
windowManager.setAlignment(Alignment.center); // ensure
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
WindowOptions getHiddenTitleBarWindowOptions({Size? size}) {
|
WindowOptions getHiddenTitleBarWindowOptions({Size? size}) {
|
||||||
return WindowOptions(
|
return WindowOptions(
|
||||||
size: size,
|
size: size,
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
// #include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
// #include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||||
|
|
||||||
typedef bool (*FUNC_RUSTDESK_CORE_MAIN)(void);
|
typedef char** (*FUNC_RUSTDESK_CORE_MAIN)(int*);
|
||||||
|
typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int);
|
||||||
|
|
||||||
// auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
|
// auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
|
||||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||||
@ -26,11 +27,23 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|||||||
std::cout << "Failed to get rustdesk_core_main" << std::endl;
|
std::cout << "Failed to get rustdesk_core_main" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!rustdesk_core_main())
|
FUNC_RUSTDESK_FREE_ARGS free_c_args =
|
||||||
|
(FUNC_RUSTDESK_FREE_ARGS)GetProcAddress(hInstance, "free_c_args");
|
||||||
|
if (!free_c_args)
|
||||||
|
{
|
||||||
|
std::cout << "Failed to get free_c_args" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int args_len = 0;
|
||||||
|
char** c_args = rustdesk_core_main(&args_len);
|
||||||
|
if (!c_args)
|
||||||
{
|
{
|
||||||
std::cout << "Rustdesk core returns false, exiting without launching Flutter app" << std::endl;
|
std::cout << "Rustdesk core returns false, exiting without launching Flutter app" << std::endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
std::vector<std::string> rust_args(c_args, c_args + args_len);
|
||||||
|
free_c_args(c_args, args_len);
|
||||||
|
|
||||||
// Attach to console when present (e.g., 'flutter run') or create a
|
// Attach to console when present (e.g., 'flutter run') or create a
|
||||||
// new console when running with a debugger.
|
// new console when running with a debugger.
|
||||||
@ -48,6 +61,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|||||||
std::vector<std::string> command_line_arguments =
|
std::vector<std::string> command_line_arguments =
|
||||||
GetCommandLineArguments();
|
GetCommandLineArguments();
|
||||||
|
|
||||||
|
command_line_arguments.insert(command_line_arguments.end(), rust_args.begin(), rust_args.end());
|
||||||
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
||||||
|
|
||||||
FlutterWindow window(project);
|
FlutterWindow window(project);
|
||||||
|
@ -12,29 +12,37 @@ pub mod bin_reader;
|
|||||||
const APP_PREFIX: &str = "rustdesk";
|
const APP_PREFIX: &str = "rustdesk";
|
||||||
const APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME";
|
const APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME";
|
||||||
|
|
||||||
fn setup(reader: BinaryReader) -> Option<PathBuf> {
|
fn setup(reader: BinaryReader, dir: Option<PathBuf>, clear: bool) -> Option<PathBuf> {
|
||||||
// home dir
|
let dir = if let Some(dir) = dir {
|
||||||
if let Some(dir) = dirs::data_local_dir() {
|
dir
|
||||||
let dir = dir.join(APP_PREFIX);
|
|
||||||
for file in reader.files.iter() {
|
|
||||||
file.write_to_file(&dir);
|
|
||||||
}
|
|
||||||
#[cfg(unix)]
|
|
||||||
reader.configure_permission(&dir);
|
|
||||||
Some(dir.join(&reader.exe))
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!("not found data local dir");
|
// home dir
|
||||||
None
|
if let Some(dir) = dirs::data_local_dir() {
|
||||||
|
dir.join(APP_PREFIX)
|
||||||
|
} else {
|
||||||
|
eprintln!("not found data local dir");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if clear {
|
||||||
|
std::fs::remove_dir_all(&dir).ok();
|
||||||
}
|
}
|
||||||
|
for file in reader.files.iter() {
|
||||||
|
file.write_to_file(&dir);
|
||||||
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
|
reader.configure_permission(&dir);
|
||||||
|
Some(dir.join(&reader.exe))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(path: PathBuf) {
|
fn execute(path: PathBuf, args: Vec<String>) {
|
||||||
println!("executing {}", path.display());
|
println!("executing {}", path.display());
|
||||||
// setup env
|
// setup env
|
||||||
let exe = std::env::current_exe().unwrap();
|
let exe = std::env::current_exe().unwrap();
|
||||||
let exe_name = exe.file_name().unwrap();
|
let exe_name = exe.file_name().unwrap();
|
||||||
// run executable
|
// run executable
|
||||||
Command::new(path)
|
Command::new(path)
|
||||||
|
.args(args)
|
||||||
.env(APPNAME_RUNTIME_ENV_KEY, exe_name)
|
.env(APPNAME_RUNTIME_ENV_KEY, exe_name)
|
||||||
.stdin(Stdio::inherit())
|
.stdin(Stdio::inherit())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
@ -43,9 +51,24 @@ fn execute(path: PathBuf) {
|
|||||||
.expect(&format!("failed to execute {:?}", exe_name));
|
.expect(&format!("failed to execute {:?}", exe_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_setup(name: &str) -> bool {
|
||||||
|
name.to_lowercase().ends_with("install.exe") || name.to_lowercase().ends_with("安装.exe")
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let is_setup = is_setup(
|
||||||
|
&std::env::current_exe()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
let reader = BinaryReader::default();
|
let reader = BinaryReader::default();
|
||||||
if let Some(exe) = setup(reader) {
|
if let Some(exe) = setup(reader, None, is_setup) {
|
||||||
execute(exe);
|
let args = if is_setup {
|
||||||
|
vec!["--install".to_owned()]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
execute(exe, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,7 +544,7 @@ pub fn is_ip(id: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_setup(name: &str) -> bool {
|
pub fn is_setup(name: &str) -> bool {
|
||||||
name.to_lowercase().ends_with("setdown.exe") || name.to_lowercase().ends_with("安装.exe")
|
name.to_lowercase().ends_with("install.exe") || name.to_lowercase().ends_with("安装.exe")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_custom_rendezvous_server(custom: String) -> String {
|
pub fn get_custom_rendezvous_server(custom: String) -> String {
|
||||||
|
@ -6,6 +6,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
// though async logger more efficient, but it also causes more problems, disable it for now
|
// though async logger more efficient, but it also causes more problems, disable it for now
|
||||||
// let mut _async_logger_holder: Option<flexi_logger::LoggerHandle> = None;
|
// let mut _async_logger_holder: Option<flexi_logger::LoggerHandle> = None;
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
|
let mut flutter_args = Vec::new();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut is_setup = false;
|
let mut is_setup = false;
|
||||||
let mut _is_elevate = false;
|
let mut _is_elevate = false;
|
||||||
@ -25,13 +26,18 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
if args.contains(&"--install".to_string()) {
|
||||||
|
is_setup = true;
|
||||||
|
}
|
||||||
if is_setup {
|
if is_setup {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
args.push("--install".to_owned());
|
args.push("--install".to_owned());
|
||||||
} else if args[0] == "--noinstall" {
|
flutter_args.push("--install".to_string());
|
||||||
args.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if args.contains(&"--noinstall".to_string()) {
|
||||||
|
args.clear();
|
||||||
|
}
|
||||||
if args.len() > 0 && args[0] == "--version" {
|
if args.len() > 0 && args[0] == "--version" {
|
||||||
println!("{}", crate::VERSION);
|
println!("{}", crate::VERSION);
|
||||||
return None;
|
return None;
|
||||||
@ -171,7 +177,10 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//_async_logger_holder.map(|x| x.flush());
|
//_async_logger_holder.map(|x| x.flush());
|
||||||
Some(args)
|
#[cfg(feature = "flutter")]
|
||||||
|
return Some(flutter_args);
|
||||||
|
#[cfg(not(feature = "flutter"))]
|
||||||
|
return Some(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_config(path: &str) {
|
fn import_config(path: &str) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
ffi::CString,
|
||||||
|
os::raw::{c_char, c_int},
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,6 +26,78 @@ lazy_static::lazy_static! {
|
|||||||
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
|
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FFI for rustdesk core's main entry.
|
||||||
|
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rustdesk_core_main() -> bool {
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
return crate::core_main::core_main().is_some();
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rustdesk_core_main(args_len: *mut c_int) -> *mut *mut c_char {
|
||||||
|
unsafe { std::ptr::write(args_len, 0) };
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
{
|
||||||
|
if let Some(args) = crate::core_main::core_main() {
|
||||||
|
return rust_args_to_c_args(args, args_len);
|
||||||
|
}
|
||||||
|
return std::ptr::null_mut() as _;
|
||||||
|
}
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
|
return std::ptr::null_mut() as _;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://gist.github.com/iskakaushik/1c5b8aa75c77479c33c4320913eebef6
|
||||||
|
fn rust_args_to_c_args(args: Vec<String>, outlen: *mut c_int) -> *mut *mut c_char {
|
||||||
|
let mut v = vec![];
|
||||||
|
|
||||||
|
// Let's fill a vector with null-terminated strings
|
||||||
|
for s in args {
|
||||||
|
v.push(CString::new(s).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turning each null-terminated string into a pointer.
|
||||||
|
// `into_raw` takes ownershop, gives us the pointer and does NOT drop the data.
|
||||||
|
let mut out = v.into_iter().map(|s| s.into_raw()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Make sure we're not wasting space.
|
||||||
|
out.shrink_to_fit();
|
||||||
|
assert!(out.len() == out.capacity());
|
||||||
|
|
||||||
|
// Get the pointer to our vector.
|
||||||
|
let len = out.len();
|
||||||
|
let ptr = out.as_mut_ptr();
|
||||||
|
std::mem::forget(out);
|
||||||
|
|
||||||
|
// Let's write back the length the caller can expect
|
||||||
|
unsafe { std::ptr::write(outlen, len as c_int) };
|
||||||
|
|
||||||
|
// Finally return the data
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn free_c_args(ptr: *mut *mut c_char, len: c_int) {
|
||||||
|
let len = len as usize;
|
||||||
|
|
||||||
|
// Get back our vector.
|
||||||
|
// Previously we shrank to fit, so capacity == length.
|
||||||
|
let v = Vec::from_raw_parts(ptr, len, len);
|
||||||
|
|
||||||
|
// Now drop one string at a time.
|
||||||
|
for elem in v {
|
||||||
|
let s = CString::from_raw(elem);
|
||||||
|
std::mem::drop(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Afterwards the vector will be dropped and thus freed.
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct FlutterHandler {
|
pub struct FlutterHandler {
|
||||||
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
|
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
|
||||||
|
@ -43,16 +43,6 @@ fn initialize(app_dir: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FFI for rustdesk core's main entry.
|
|
||||||
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rustdesk_core_main() -> bool {
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
||||||
return crate::core_main::core_main().is_some();
|
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum EventToUI {
|
pub enum EventToUI {
|
||||||
Event(String),
|
Event(String),
|
||||||
Rgba(ZeroCopyBuffer<Vec<u8>>),
|
Rgba(ZeroCopyBuffer<Vec<u8>>),
|
||||||
@ -1041,6 +1031,22 @@ pub fn main_update_me() -> SyncReturn<bool> {
|
|||||||
SyncReturn(true)
|
SyncReturn(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn install_show_run_without_install() -> SyncReturn<bool> {
|
||||||
|
SyncReturn(show_run_without_install())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install_run_without_install() {
|
||||||
|
run_without_install();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install_install_me(options: String, path: String) {
|
||||||
|
install_me(options, path, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install_install_path() -> SyncReturn<String> {
|
||||||
|
SyncReturn(install_path())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
pub mod server_side {
|
pub mod server_side {
|
||||||
use jni::{
|
use jni::{
|
||||||
|
@ -1025,6 +1025,18 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\"
|
|||||||
app_name = crate::get_app_name(),
|
app_name = crate::get_app_name(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let mut flutter_copy = Default::default();
|
||||||
|
if options.contains("--flutter") {
|
||||||
|
flutter_copy = format!(
|
||||||
|
"XCOPY \"{}\" \"{}\" /Y /E /H /C /I /K /R /Z",
|
||||||
|
std::env::current_exe()?
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let meta = std::fs::symlink_metadata(std::env::current_exe()?)?;
|
let meta = std::fs::symlink_metadata(std::env::current_exe()?)?;
|
||||||
let size = meta.len() / 1024;
|
let size = meta.len() / 1024;
|
||||||
@ -1052,6 +1064,7 @@ if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name}
|
|||||||
{uninstall_str}
|
{uninstall_str}
|
||||||
chcp 65001
|
chcp 65001
|
||||||
md \"{path}\"
|
md \"{path}\"
|
||||||
|
{flutter_copy}
|
||||||
copy /Y \"{src_exe}\" \"{exe}\"
|
copy /Y \"{src_exe}\" \"{exe}\"
|
||||||
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
||||||
\"{src_exe}\" --extract \"{path}\"
|
\"{src_exe}\" --extract \"{path}\"
|
||||||
@ -1114,6 +1127,7 @@ sc delete {app_name}
|
|||||||
} else {
|
} else {
|
||||||
&dels
|
&dels
|
||||||
},
|
},
|
||||||
|
flutter_copy = flutter_copy,
|
||||||
);
|
);
|
||||||
run_cmds(cmds, debug, "install")?;
|
run_cmds(cmds, debug, "install")?;
|
||||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user