project restructure with Rust workspaces
This commit is contained in:
parent
1f03a44f33
commit
6e585dd37d
428 changed files with 19372 additions and 6061 deletions
131
crates/jarvis-app/src/tray.rs
Normal file
131
crates/jarvis-app/src/tray.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
mod menu;
|
||||
|
||||
use tray_icon::{
|
||||
menu::{AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem},
|
||||
TrayIconBuilder, TrayIconEvent,
|
||||
};
|
||||
use winit::event_loop::{ControlFlow, EventLoopBuilder};
|
||||
use image;
|
||||
|
||||
#[cfg(target_os="windows")]
|
||||
use winit::platform::windows::EventLoopBuilderExtWindows;
|
||||
|
||||
use jarvis_core::config;
|
||||
|
||||
const TRAY_ICON_BYTES: &[u8] = include_bytes!("../../../resources/icons/32x32.png");
|
||||
|
||||
pub fn init_blocking() {
|
||||
// load tray icon
|
||||
//let icon_path = format!("{}/../../resources/icons/{}", env!("CARGO_MANIFEST_DIR"), config::TRAY_ICON);
|
||||
//let icon = load_icon(std::path::Path::new(&icon_path));
|
||||
let icon = load_icon_from_bytes(TRAY_ICON_BYTES);
|
||||
|
||||
// form tray menu
|
||||
let tray_menu = Menu::with_items(&[
|
||||
&MenuItem::new("Перезапуск", true, None),
|
||||
&MenuItem::new("Настройки", true, None),
|
||||
&MenuItem::new("Выход", true, None),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
let tray_menu = Menu::with_items(&[
|
||||
&MenuItem::with_id("restart", "Перезапуск", true, None),
|
||||
&MenuItem::with_id("settings", "Настройки", true, None),
|
||||
&MenuItem::with_id("exit", "Выход", true, None),
|
||||
]).unwrap();
|
||||
|
||||
let _tray_icon = TrayIconBuilder::new()
|
||||
.with_menu(Box::new(tray_menu))
|
||||
.with_tooltip(config::TRAY_TOOLTIP)
|
||||
.with_icon(icon)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let menu_channel = MenuEvent::receiver();
|
||||
// let tray_channel = TrayIconEvent::receiver();
|
||||
|
||||
// @TODO: Test on Linux
|
||||
// We need gtk for the tray icon to show up, we need to initialize gtk and create the tray_icon
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
gtk::init().unwrap();
|
||||
glib::timeout_add_local(std::time::Duration::from_millis(100), move || {
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
handle_menu_event(&event);
|
||||
}
|
||||
glib::ControlFlow::Continue
|
||||
});
|
||||
gtk::main();
|
||||
}
|
||||
|
||||
// @TODO: Test on MacOS
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
// macOS needs proper run loop - tao or winit on main thread
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
event_loop.run(move |_event, elwt| {
|
||||
elwt.set_control_flow(ControlFlow::Wait);
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
handle_menu_event(&event);
|
||||
}
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// simple polling works on Windows
|
||||
loop {
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
handle_menu_event(&event);
|
||||
}
|
||||
|
||||
// pump Windows messages
|
||||
unsafe {
|
||||
let mut msg: winapi::um::winuser::MSG = std::mem::zeroed();
|
||||
while winapi::um::winuser::PeekMessageW(
|
||||
&mut msg,
|
||||
std::ptr::null_mut(),
|
||||
0, 0,
|
||||
winapi::um::winuser::PM_REMOVE
|
||||
) != 0 {
|
||||
winapi::um::winuser::TranslateMessage(&msg);
|
||||
winapi::um::winuser::DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
}
|
||||
|
||||
info!("Tray initialized.");
|
||||
}
|
||||
|
||||
fn handle_menu_event(event: &MenuEvent) {
|
||||
match event.id.0.as_str() {
|
||||
"exit" => std::process::exit(0),
|
||||
"restart" => { /* restart logic */ }
|
||||
"settings" => { /* open settings */ }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_icon_from_bytes(bytes: &[u8]) -> tray_icon::Icon {
|
||||
let image = image::load_from_memory(bytes)
|
||||
.expect("Failed to load icon")
|
||||
.into_rgba8();
|
||||
let (width, height) = image.dimensions();
|
||||
let rgba = image.into_raw();
|
||||
tray_icon::Icon::from_rgba(rgba, width, height).expect("Failed to create icon")
|
||||
}
|
||||
|
||||
fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
|
||||
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)
|
||||
};
|
||||
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue