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.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.chdir('flutter')
|
||||
os.system("flutter build windows --release")
|
||||
@ -203,6 +203,8 @@ def build_flutter_windows_portable():
|
||||
else:
|
||||
os.rename("./target/release/rustdesk-portable-packer.exe", "./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():
|
||||
parser = make_parser()
|
||||
@ -227,8 +229,8 @@ def main():
|
||||
os.system('python3 res/inline-sciter.py')
|
||||
portable = args.portable
|
||||
if windows:
|
||||
if portable:
|
||||
build_flutter_windows_portable()
|
||||
if flutter:
|
||||
build_flutter_windows(version)
|
||||
return
|
||||
os.system('cargo build --release --features ' + features)
|
||||
# os.system('upx.exe target/release/rustdesk.exe')
|
||||
@ -239,7 +241,7 @@ def main():
|
||||
'target\\release\\rustdesk.exe')
|
||||
else:
|
||||
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'):
|
||||
# pacman -S -needed base-devel
|
||||
os.system("sed -i 's/pkgver=.*/pkgver=%s/g' PKGBUILD" % version)
|
||||
|
@ -3,7 +3,7 @@ import 'dart:io';
|
||||
|
||||
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 kAppTypeDesktopRemote = "remote";
|
||||
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_hbb/desktop/pages/desktop_tab_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_port_forward_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;
|
||||
await windowManager.ensureInitialized();
|
||||
runConnectionManagerScreen();
|
||||
} else if (args.contains('--install')) {
|
||||
runInstallPage();
|
||||
} else {
|
||||
desktopType = DesktopType.main;
|
||||
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}) {
|
||||
return WindowOptions(
|
||||
size: size,
|
||||
|
@ -7,7 +7,8 @@
|
||||
#include "utils.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);
|
||||
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;
|
||||
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;
|
||||
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
|
||||
// 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 =
|
||||
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));
|
||||
|
||||
FlutterWindow window(project);
|
||||
|
@ -12,29 +12,37 @@ pub mod bin_reader;
|
||||
const APP_PREFIX: &str = "rustdesk";
|
||||
const APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME";
|
||||
|
||||
fn setup(reader: BinaryReader) -> Option<PathBuf> {
|
||||
// home dir
|
||||
if let Some(dir) = dirs::data_local_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))
|
||||
fn setup(reader: BinaryReader, dir: Option<PathBuf>, clear: bool) -> Option<PathBuf> {
|
||||
let dir = if let Some(dir) = dir {
|
||||
dir
|
||||
} else {
|
||||
eprintln!("not found data local dir");
|
||||
None
|
||||
// home dir
|
||||
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());
|
||||
// setup env
|
||||
let exe = std::env::current_exe().unwrap();
|
||||
let exe_name = exe.file_name().unwrap();
|
||||
// run executable
|
||||
Command::new(path)
|
||||
.args(args)
|
||||
.env(APPNAME_RUNTIME_ENV_KEY, exe_name)
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
@ -43,9 +51,24 @@ fn execute(path: PathBuf) {
|
||||
.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() {
|
||||
let is_setup = is_setup(
|
||||
&std::env::current_exe()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
let reader = BinaryReader::default();
|
||||
if let Some(exe) = setup(reader) {
|
||||
execute(exe);
|
||||
if let Some(exe) = setup(reader, None, is_setup) {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -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
|
||||
// let mut _async_logger_holder: Option<flexi_logger::LoggerHandle> = None;
|
||||
let mut args = Vec::new();
|
||||
let mut flutter_args = Vec::new();
|
||||
let mut i = 0;
|
||||
let mut is_setup = false;
|
||||
let mut _is_elevate = false;
|
||||
@ -25,13 +26,18 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if args.contains(&"--install".to_string()) {
|
||||
is_setup = true;
|
||||
}
|
||||
if is_setup {
|
||||
if args.is_empty() {
|
||||
args.push("--install".to_owned());
|
||||
} else if args[0] == "--noinstall" {
|
||||
args.clear();
|
||||
flutter_args.push("--install".to_string());
|
||||
}
|
||||
}
|
||||
if args.contains(&"--noinstall".to_string()) {
|
||||
args.clear();
|
||||
}
|
||||
if args.len() > 0 && args[0] == "--version" {
|
||||
println!("{}", crate::VERSION);
|
||||
return None;
|
||||
@ -171,7 +177,10 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
}
|
||||
//_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) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::CString,
|
||||
os::raw::{c_char, c_int},
|
||||
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
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
pub struct FlutterHandler {
|
||||
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 {
|
||||
Event(String),
|
||||
Rgba(ZeroCopyBuffer<Vec<u8>>),
|
||||
@ -1041,6 +1031,22 @@ pub fn main_update_me() -> SyncReturn<bool> {
|
||||
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")]
|
||||
pub mod server_side {
|
||||
use jni::{
|
||||
|
@ -1025,6 +1025,18 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\"
|
||||
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 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}
|
||||
chcp 65001
|
||||
md \"{path}\"
|
||||
{flutter_copy}
|
||||
copy /Y \"{src_exe}\" \"{exe}\"
|
||||
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
||||
\"{src_exe}\" --extract \"{path}\"
|
||||
@ -1114,6 +1127,7 @@ sc delete {app_name}
|
||||
} else {
|
||||
&dels
|
||||
},
|
||||
flutter_copy = flutter_copy,
|
||||
);
|
||||
run_cmds(cmds, debug, "install")?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
|
Loading…
x
Reference in New Issue
Block a user