mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
new tray
This commit is contained in:
224
src/tray.rs
224
src/tray.rs
@@ -1,11 +1,5 @@
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(target_os = "windows"))]
|
||||
use super::ui_interface::get_option_opt;
|
||||
#[cfg(target_os = "linux")]
|
||||
use hbb_common::log::{debug, error, info};
|
||||
#[cfg(target_os = "linux")]
|
||||
use libappindicator::AppIndicator;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::env::temp_dir;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -83,119 +77,10 @@ pub fn start_tray() {
|
||||
});
|
||||
}
|
||||
|
||||
/// 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() {
|
||||
use std::time::Duration;
|
||||
|
||||
use glib::{clone, Continue};
|
||||
use gtk::traits::{GtkMenuItemExt, MenuShellExt, WidgetExt};
|
||||
|
||||
info!("configuring tray");
|
||||
// init gtk context
|
||||
if let Err(err) = gtk::init() {
|
||||
error!("Error when starting the tray: {}", err);
|
||||
return;
|
||||
}
|
||||
if let Some(mut appindicator) = get_default_app_indicator() {
|
||||
let mut menu = gtk::Menu::new();
|
||||
let stoped = is_service_stopped();
|
||||
// start/stop service
|
||||
let label = if stoped {
|
||||
crate::client::translate("Start Service".to_owned())
|
||||
} else {
|
||||
crate::client::translate("Stop service".to_owned())
|
||||
};
|
||||
let menu_item_service = gtk::MenuItem::with_label(label.as_str());
|
||||
menu_item_service.connect_activate(move |_| {
|
||||
let _lock = crate::ui_interface::SENDER.lock().unwrap();
|
||||
change_service_state();
|
||||
});
|
||||
menu.append(&menu_item_service);
|
||||
// show tray item
|
||||
menu.show_all();
|
||||
appindicator.set_menu(&mut menu);
|
||||
// start event loop
|
||||
info!("Setting tray event loop");
|
||||
// check the connection status for every second
|
||||
glib::timeout_add_local(
|
||||
Duration::from_secs(1),
|
||||
clone!(@strong menu_item_service as item => move || {
|
||||
let _lock = crate::ui_interface::SENDER.lock().unwrap();
|
||||
update_tray_service_item(&item);
|
||||
// continue to trigger the next status check
|
||||
Continue(true)
|
||||
}),
|
||||
);
|
||||
gtk::main();
|
||||
} else {
|
||||
error!("Tray process exit now");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn change_service_state() {
|
||||
if is_service_stopped() {
|
||||
debug!("Now try to start service");
|
||||
crate::ipc::set_option("stop-service", "");
|
||||
} else {
|
||||
debug!("Now try to stop service");
|
||||
crate::ipc::set_option("stop-service", "Y");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn update_tray_service_item(item: >k::MenuItem) {
|
||||
use gtk::traits::GtkMenuItemExt;
|
||||
|
||||
if is_service_stopped() {
|
||||
item.set_label(&crate::client::translate("Start Service".to_owned()));
|
||||
} else {
|
||||
item.set_label(&crate::client::translate("Stop service".to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_default_app_indicator() -> Option<AppIndicator> {
|
||||
use libappindicator::AppIndicatorStatus;
|
||||
use std::io::Write;
|
||||
|
||||
let icon = include_bytes!("../res/icon.png");
|
||||
// appindicator does not support icon buffer, so we write it to tmp folder
|
||||
let mut icon_path = temp_dir();
|
||||
icon_path.push("RustDesk");
|
||||
icon_path.push("rustdesk.png");
|
||||
match std::fs::File::create(icon_path.clone()) {
|
||||
Ok(mut f) => {
|
||||
f.write_all(icon).unwrap();
|
||||
// set .png icon file to be writable
|
||||
// this ensures successful file rewrite when switching between x11 and wayland.
|
||||
let mut perm = f.metadata().unwrap().permissions();
|
||||
if perm.readonly() {
|
||||
perm.set_readonly(false);
|
||||
f.set_permissions(perm).unwrap();
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error when writing icon to {:?}: {}", icon_path, err);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
debug!("write temp icon complete");
|
||||
let mut appindicator = AppIndicator::new("RustDesk", icon_path.to_str().unwrap_or("rustdesk"));
|
||||
appindicator.set_label("RustDesk", "A remote control software.");
|
||||
appindicator.set_status(AppIndicatorStatus::Active);
|
||||
Some(appindicator)
|
||||
}
|
||||
|
||||
/// Check if service is stoped.
|
||||
/// Return [`true`] if service is stoped, [`false`] otherwise.
|
||||
#[inline]
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(target_os = "windows"))]
|
||||
fn is_service_stopped() -> bool {
|
||||
if let Some(v) = get_option_opt("stop-service") {
|
||||
v == "Y"
|
||||
@@ -204,47 +89,68 @@ fn is_service_stopped() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn make_tray() {
|
||||
extern "C" {
|
||||
fn BackingScaleFactor() -> f32;
|
||||
}
|
||||
let f = unsafe { BackingScaleFactor() };
|
||||
use tray_item::TrayItem;
|
||||
let mode = dark_light::detect();
|
||||
let icon_path = match mode {
|
||||
dark_light::Mode::Dark => {
|
||||
// still show big overflow icon in my test, so still use x1 png.
|
||||
// let's do it with objc with svg support later.
|
||||
// or use another tray crate, or find out in tauri (it has tray support)
|
||||
if f > 2. {
|
||||
"mac-tray-light-x2.png"
|
||||
} else {
|
||||
"mac-tray-light.png"
|
||||
}
|
||||
}
|
||||
dark_light::Mode::Light => {
|
||||
if f > 2. {
|
||||
"mac-tray-dark-x2.png"
|
||||
} else {
|
||||
"mac-tray-dark.png"
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) {
|
||||
tray.add_label(&format!(
|
||||
"{} {}",
|
||||
crate::get_app_name(),
|
||||
crate::lang::translate("Service is running".to_owned())
|
||||
))
|
||||
.ok();
|
||||
/// 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() {}
|
||||
|
||||
let inner = tray.inner_mut();
|
||||
inner.add_quit_item(&crate::lang::translate("Quit".to_owned()));
|
||||
inner.display();
|
||||
} else {
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(3));
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn start_tray() {
|
||||
use hbb_common::{allow_err, log};
|
||||
allow_err!(make_tray());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
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};
|
||||
use tray_icon::{TrayEvent, TrayIconBuilder};
|
||||
let mode = dark_light::detect();
|
||||
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 {
|
||||
dark_light::Mode::Dark => DARK,
|
||||
_ => LIGHT,
|
||||
};
|
||||
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")?;
|
||||
|
||||
let event_loop = EventLoopBuilder::new().build();
|
||||
|
||||
let _tray_icon = Some(
|
||||
TrayIconBuilder::new()
|
||||
.with_tooltip(format!(
|
||||
"{} {}",
|
||||
crate::get_app_name(),
|
||||
crate::lang::translate("Service is running".to_owned())
|
||||
))
|
||||
.with_icon(icon)
|
||||
.build()?,
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
*control_flow = ControlFlow::Poll;
|
||||
|
||||
if tray_channel.try_recv().is_ok() {
|
||||
crate::platform::macos::handle_application_should_open_untitled_file();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user