2023-02-19 12:52:41 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-11-10 21:25:12 +08:00
|
|
|
use super::ui_interface::get_option_opt;
|
2022-11-10 23:26:09 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-11-10 21:25:12 +08:00
|
|
|
use std::sync::{Arc, Mutex};
|
2022-11-04 19:56:17 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-05-12 17:35:25 +08:00
|
|
|
use trayicon::{MenuBuilder, TrayIconBuilder};
|
2022-11-04 19:56:17 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-05-12 17:35:25 +08:00
|
|
|
use winit::{
|
|
|
|
event::Event,
|
|
|
|
event_loop::{ControlFlow, EventLoop},
|
|
|
|
};
|
|
|
|
|
2022-11-10 23:26:09 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-05-12 17:35:25 +08:00
|
|
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
|
|
|
enum Events {
|
|
|
|
DoubleClickTrayIcon,
|
|
|
|
StopService,
|
|
|
|
StartService,
|
|
|
|
}
|
|
|
|
|
2022-11-04 19:20:51 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-11-10 21:25:12 +08:00
|
|
|
pub fn start_tray() {
|
2022-05-12 17:35:25 +08:00
|
|
|
let event_loop = EventLoop::<Events>::with_user_event();
|
|
|
|
let proxy = event_loop.create_proxy();
|
2022-09-18 11:22:30 +08:00
|
|
|
let icon = include_bytes!("../res/tray-icon.ico");
|
2022-05-12 17:35:25 +08:00
|
|
|
let mut tray_icon = TrayIconBuilder::new()
|
|
|
|
.sender_winit(proxy)
|
|
|
|
.icon_from_buffer(icon)
|
|
|
|
.tooltip("RustDesk")
|
|
|
|
.on_double_click(Events::DoubleClickTrayIcon)
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let old_state = Arc::new(Mutex::new(0));
|
2022-10-31 16:08:51 +08:00
|
|
|
let _sender = crate::ui_interface::SENDER.lock().unwrap();
|
2022-05-12 17:35:25 +08:00
|
|
|
event_loop.run(move |event, _, control_flow| {
|
2022-11-10 21:25:12 +08:00
|
|
|
if get_option_opt("ipc-closed").is_some() {
|
2022-05-12 17:35:25 +08:00
|
|
|
*control_flow = ControlFlow::Exit;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
*control_flow = ControlFlow::Wait;
|
|
|
|
}
|
2022-12-29 14:28:15 +08:00
|
|
|
let stopped = is_service_stopped();
|
2022-11-10 23:26:09 +08:00
|
|
|
let state = if stopped { 2 } else { 1 };
|
2022-05-12 17:35:25 +08:00
|
|
|
let old = *old_state.lock().unwrap();
|
2022-11-10 23:26:09 +08:00
|
|
|
if state != old {
|
2022-05-12 17:35:25 +08:00
|
|
|
hbb_common::log::info!("State changed");
|
|
|
|
let mut m = MenuBuilder::new();
|
2022-11-10 23:26:09 +08:00
|
|
|
if state == 2 {
|
2022-05-12 17:35:25 +08:00
|
|
|
m = m.item(
|
2022-10-29 21:53:18 +08:00
|
|
|
&crate::client::translate("Start Service".to_owned()),
|
2022-05-12 17:35:25 +08:00
|
|
|
Events::StartService,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
m = m.item(
|
|
|
|
&crate::client::translate("Stop service".to_owned()),
|
|
|
|
Events::StopService,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
tray_icon.set_menu(&m).ok();
|
2022-11-10 23:26:09 +08:00
|
|
|
*old_state.lock().unwrap() = state;
|
2022-05-12 17:35:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
match event {
|
|
|
|
Event::UserEvent(e) => match e {
|
|
|
|
Events::DoubleClickTrayIcon => {
|
|
|
|
crate::run_me(Vec::<&str>::new()).ok();
|
|
|
|
}
|
|
|
|
Events::StopService => {
|
|
|
|
crate::ipc::set_option("stop-service", "Y");
|
|
|
|
}
|
|
|
|
Events::StartService => {
|
|
|
|
crate::ipc::set_option("stop-service", "");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2022-11-04 19:20:51 +08:00
|
|
|
|
2022-11-10 23:26:09 +08:00
|
|
|
/// Check if service is stoped.
|
|
|
|
/// Return [`true`] if service is stoped, [`false`] otherwise.
|
2022-11-04 19:20:51 +08:00
|
|
|
#[inline]
|
2023-02-19 12:52:41 +08:00
|
|
|
#[cfg(target_os = "windows")]
|
2022-12-29 14:28:15 +08:00
|
|
|
fn is_service_stopped() -> bool {
|
2022-11-10 23:26:09 +08:00
|
|
|
if let Some(v) = get_option_opt("stop-service") {
|
|
|
|
v == "Y"
|
2022-11-04 19:20:51 +08:00
|
|
|
} else {
|
2022-11-10 23:26:09 +08:00
|
|
|
false
|
2022-11-04 19:20:51 +08:00
|
|
|
}
|
|
|
|
}
|
2022-11-18 18:36:25 +08:00
|
|
|
|
2023-02-09 21:28:42 +08:00
|
|
|
/// Start a tray icon in Linux
|
|
|
|
///
|
|
|
|
/// [Block]
|
|
|
|
/// This function will block current execution, show the tray icon and handle events.
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
pub fn start_tray() {}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub fn start_tray() {
|
|
|
|
use hbb_common::{allow_err, log};
|
|
|
|
allow_err!(make_tray());
|
|
|
|
}
|
|
|
|
|
2022-11-18 18:36:25 +08:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-09 21:28:42 +08:00
|
|
|
pub fn make_tray() -> hbb_common::ResultType<()> {
|
|
|
|
// https://github.com/tauri-apps/tray-icon/blob/dev/examples/tao.rs
|
|
|
|
use hbb_common::anyhow::Context;
|
|
|
|
use tao::event_loop::{ControlFlow, EventLoopBuilder};
|
2023-02-23 20:01:50 +08:00
|
|
|
use tray_icon::{
|
|
|
|
menu::{Menu, MenuEvent, MenuItem},
|
|
|
|
ClickEvent, TrayEvent, TrayIconBuilder,
|
|
|
|
};
|
2022-11-18 18:36:25 +08:00
|
|
|
let mode = dark_light::detect();
|
2023-02-09 21:28:42 +08:00
|
|
|
const LIGHT: &[u8] = include_bytes!("../res/mac-tray-light-x2.png");
|
|
|
|
const DARK: &[u8] = include_bytes!("../res/mac-tray-dark-x2.png");
|
|
|
|
let icon = match mode {
|
2023-02-23 19:28:30 +08:00
|
|
|
dark_light::Mode::Dark => LIGHT,
|
|
|
|
_ => DARK,
|
2023-01-11 15:35:35 +08:00
|
|
|
};
|
2023-02-09 21:28:42 +08:00
|
|
|
let (icon_rgba, icon_width, icon_height) = {
|
|
|
|
let image = image::load_from_memory(icon)
|
|
|
|
.context("Failed to open icon path")?
|
|
|
|
.into_rgba8();
|
|
|
|
let (width, height) = image.dimensions();
|
|
|
|
let rgba = image.into_raw();
|
|
|
|
(rgba, width, height)
|
|
|
|
};
|
|
|
|
let icon = tray_icon::icon::Icon::from_rgba(icon_rgba, icon_width, icon_height)
|
|
|
|
.context("Failed to open icon")?;
|
2022-11-18 18:36:25 +08:00
|
|
|
|
2023-02-09 21:28:42 +08:00
|
|
|
let event_loop = EventLoopBuilder::new().build();
|
|
|
|
|
2023-02-23 20:01:50 +08:00
|
|
|
let tray_menu = Menu::new();
|
|
|
|
let quit_i = MenuItem::new(crate::client::translate("Exit".to_owned()), true, None);
|
|
|
|
tray_menu.append_items(&[&quit_i]);
|
|
|
|
|
2023-02-09 21:28:42 +08:00
|
|
|
let _tray_icon = Some(
|
|
|
|
TrayIconBuilder::new()
|
2023-02-23 20:01:50 +08:00
|
|
|
.with_menu(Box::new(tray_menu))
|
2023-02-09 21:28:42 +08:00
|
|
|
.with_tooltip(format!(
|
|
|
|
"{} {}",
|
|
|
|
crate::get_app_name(),
|
|
|
|
crate::lang::translate("Service is running".to_owned())
|
|
|
|
))
|
|
|
|
.with_icon(icon)
|
|
|
|
.build()?,
|
|
|
|
);
|
|
|
|
|
2023-02-23 20:01:50 +08:00
|
|
|
let menu_channel = MenuEvent::receiver();
|
2023-02-09 21:28:42 +08:00
|
|
|
let tray_channel = TrayEvent::receiver();
|
|
|
|
let mut docker_hiden = false;
|
|
|
|
|
|
|
|
event_loop.run(move |_event, _, control_flow| {
|
|
|
|
if !docker_hiden {
|
|
|
|
crate::platform::macos::hide_dock();
|
|
|
|
docker_hiden = true;
|
2022-11-18 18:36:25 +08:00
|
|
|
}
|
2023-02-23 19:28:30 +08:00
|
|
|
*control_flow = ControlFlow::Wait;
|
2023-02-09 21:28:42 +08:00
|
|
|
|
2023-02-23 20:01:50 +08:00
|
|
|
if let Ok(event) = menu_channel.try_recv() {
|
|
|
|
if event.id == quit_i.id() {
|
|
|
|
crate::platform::macos::uninstall(false);
|
|
|
|
}
|
|
|
|
println!("{event:?}");
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Ok(event) = tray_channel.try_recv() {
|
|
|
|
if event.event == ClickEvent::Double {
|
|
|
|
crate::platform::macos::handle_application_should_open_untitled_file();
|
|
|
|
}
|
2023-02-09 21:28:42 +08:00
|
|
|
}
|
|
|
|
});
|
2022-11-18 18:36:25 +08:00
|
|
|
}
|