2023-06-11 19:17:50 +05:00
|
|
|
mod menu;
|
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
use image;
|
2023-06-11 19:17:50 +05:00
|
|
|
use tray_icon::{
|
|
|
|
|
menu::{AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem},
|
2025-12-11 23:43:50 +05:00
|
|
|
TrayIconBuilder, TrayIconEvent,
|
2023-06-11 19:17:50 +05:00
|
|
|
};
|
|
|
|
|
use winit::event_loop::{ControlFlow, EventLoopBuilder};
|
|
|
|
|
use winit::platform::windows::EventLoopBuilderExtWindows;
|
|
|
|
|
|
|
|
|
|
use crate::config;
|
|
|
|
|
|
|
|
|
|
pub fn init() {
|
|
|
|
|
// spawn tray icon
|
|
|
|
|
// New thread will prevent tray icon to work on MacOS
|
|
|
|
|
// @TODO: MacOS support.
|
|
|
|
|
std::thread::spawn(|| {
|
|
|
|
|
// load tray icon
|
|
|
|
|
let icon_path = format!("{}/icons/{}", env!("CARGO_MANIFEST_DIR"), config::TRAY_ICON);
|
|
|
|
|
let icon = load_icon(std::path::Path::new(&icon_path));
|
|
|
|
|
|
|
|
|
|
// form tray menu
|
|
|
|
|
let tray_menu = Menu::with_items(&[
|
|
|
|
|
&MenuItem::new("Перезапуск", true, None),
|
|
|
|
|
&MenuItem::new("Настройки", true, None),
|
2025-12-11 23:43:50 +05:00
|
|
|
&MenuItem::new("Выход", true, None),
|
|
|
|
|
])
|
|
|
|
|
.unwrap();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
|
let mut tray_icon = Some(
|
|
|
|
|
TrayIconBuilder::new()
|
|
|
|
|
.with_menu(Box::new(tray_menu))
|
|
|
|
|
.with_tooltip(config::TRAY_TOOLTIP)
|
|
|
|
|
.with_icon(icon)
|
|
|
|
|
.build()
|
2025-12-11 23:43:50 +05:00
|
|
|
.unwrap(),
|
2023-06-11 19:17:50 +05:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Since winit doesn't use gtk on Linux, and we need gtk for
|
|
|
|
|
// the tray icon to show up, we need to initialize gtk and create the tray_icon
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
{
|
|
|
|
|
use tray_icon::menu::Menu;
|
|
|
|
|
|
|
|
|
|
gtk::init().unwrap();
|
|
|
|
|
let _tray_icon = TrayIconBuilder::new()
|
|
|
|
|
.with_menu(Box::new(tray_menu))
|
|
|
|
|
.with_tooltip(config::TRAY_TOOLTIP)
|
|
|
|
|
.with_icon(icon)
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
gtk::main();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run the event loop
|
2025-12-11 23:43:50 +05:00
|
|
|
let event_loop = EventLoopBuilder::new()
|
|
|
|
|
.with_any_thread(true)
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
let menu_channel = MenuEvent::receiver();
|
2025-12-11 23:43:50 +05:00
|
|
|
let tray_channel = TrayIconEvent::receiver();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
event_loop
|
|
|
|
|
.run(move |_event, event_loop| {
|
|
|
|
|
event_loop.set_control_flow(ControlFlow::Poll);
|
2023-06-11 19:17:50 +05:00
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
//if let Ok(event) = tray_channel.try_recv() {
|
|
|
|
|
// println!("tray event: {event:?}");
|
|
|
|
|
//}
|
2023-06-11 19:17:50 +05:00
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
if let Ok(event) = menu_channel.try_recv() {
|
|
|
|
|
println!("menu event: {:?}", event);
|
2023-06-11 19:17:50 +05:00
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
if event.id == "1002" {
|
|
|
|
|
std::process::exit(0);
|
|
|
|
|
}
|
2023-06-11 19:17:50 +05:00
|
|
|
}
|
2025-12-11 23:43:50 +05:00
|
|
|
})
|
|
|
|
|
.expect("Tray event loop run error");
|
2023-06-11 19:17:50 +05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
info!("Tray initialized.");
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
|
2023-06-11 19:17:50 +05:00
|
|
|
let (icon_rgba, icon_width, icon_height) = {
|
|
|
|
|
let image = image::open(path)
|
|
|
|
|
.expect("Failed to open icon path")
|
|
|
|
|
.into_rgba8();
|
|
|
|
|
let (width, height) = image.dimensions();
|
|
|
|
|
let rgba = image.into_raw();
|
|
|
|
|
(rgba, width, height)
|
|
|
|
|
};
|
2025-12-11 23:43:50 +05:00
|
|
|
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
|
|
|
|
|
}
|