From 61241ae56aea685d61afbd647e1d807753b1ab9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabor=20K=C3=B6rber?= Date: Thu, 6 Jun 2024 22:55:11 +0200 Subject: [PATCH] defunct version of windows tray with winit --- src/bin/ui_tray_icon_windows.rs | 239 ++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 src/bin/ui_tray_icon_windows.rs diff --git a/src/bin/ui_tray_icon_windows.rs b/src/bin/ui_tray_icon_windows.rs new file mode 100644 index 0000000..7e5eeaf --- /dev/null +++ b/src/bin/ui_tray_icon_windows.rs @@ -0,0 +1,239 @@ +use axum::{ + routing::{self, get}, + Router, +}; +use eframe::egui; +use serde::{Deserialize, Serialize}; +use std::{ + net::SocketAddr, + sync::{Arc, Mutex}, + thread, +}; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; +use tray_icon::{TrayIconBuilder, TrayIconEvent}; +use windows::Win32::Foundation::HWND; +use windows::Win32::UI::WindowsAndMessaging::{ShowWindow, SW_HIDE, SW_SHOWDEFAULT}; + +#[derive(Debug, Clone)] +struct AppState { + settings: Arc>, + should_run: Arc>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct ServerSettings { + port: String, // Change to String for text editing +} + +async fn home() -> &'static str { + "Hello, World!" +} + +#[tokio::main] +async fn main() { + let (tx, rx) = mpsc::channel(32); + let settings = Arc::new(Mutex::new(ServerSettings { + port: "3311".to_string(), + })); + let should_run = Arc::new(Mutex::new(true)); + let app_state = AppState { + settings: settings.clone(), + should_run: should_run.clone(), + }; + + // Run the server in a separate thread + let server_thread = thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + run_server(app_state, rx).await; + }); + }); + + // Run the UI on the main thread + run_ui(settings, should_run, tx); + + // Wait for the server thread to finish + server_thread.join().unwrap(); +} + +async fn run_server(app_state: AppState, mut rx: mpsc::Receiver) { + let mut server_handle = start_server(&app_state); + + loop { + tokio::select! { + _ = &mut server_handle => { + // Server has stopped + break; + }, + Some(message) = rx.recv() => { + match message { + ServerMessage::UpdateSettings(new_settings) => { + println!("Received new settings: {:?}", new_settings); + let mut settings_guard = app_state.settings.lock().unwrap(); + *settings_guard = new_settings; + + // Restart the server with new settings + println!("Aborting current server..."); + server_handle.abort(); // Cancel the previous server task + println!("Starting new server..."); + drop(settings_guard); // Ensure the lock is released before starting the new server + server_handle = start_server(&app_state); + println!("Server started."); + }, + ServerMessage::Interact => { + // Example interaction: print current settings + let settings_guard = app_state.settings.lock().unwrap(); + println!("Current settings: {:?}", *settings_guard); + }, + ServerMessage::Shutdown => { + // Handle server shutdown + println!("Shutting down server..."); + let mut should_run_guard = app_state.should_run.lock().unwrap(); + *should_run_guard = false; + server_handle.abort(); + println!("Server shutdown."); + break; + }, + // Handle other message types here + } + } + } + } +} + +fn start_server(app_state: &AppState) -> JoinHandle<()> { + // Compute the address before entering the async block + let addr = { + let settings = app_state.settings.lock().unwrap(); + let port: u16 = settings.port.parse().unwrap_or(3311); + SocketAddr::from(([0, 0, 0, 0], port)) + }; + + let server_app_state = app_state.clone(); + + println!("listening on {}", addr); + + tokio::spawn(async move { + let app = Router::new() + .route("/", get(home)) + .with_state(server_app_state.clone()); + let server = axum::Server::bind(&addr).serve(app.into_make_service()); + + // Run the server and monitor the should_run flag + tokio::select! { + _ = server => {}, + _ = monitor_shutdown(server_app_state.should_run.clone()) => { + println!("Server shutdown signal received"); + } + } + }) +} + +async fn monitor_shutdown(should_run: Arc>) { + while *should_run.lock().unwrap() { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } +} + +fn run_ui( + settings: Arc>, + should_run: Arc>, + tx: mpsc::Sender, +) { + // Create an atomic bool to track window visibility + static VISIBLE: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| Mutex::new(true)); + + eframe::run_native( + "App", + eframe::NativeOptions::default(), + Box::new(|cc| { + // Set up the tray icon event handler + let window_handle = cc + if let raw_window_handle::RawWindowHandle(handle) = window_handle { + let context = cc.egui_ctx.clone(); + + TrayIconEvent::set_event_handler(Some(move |event: TrayIconEvent| { + if event.click_type != tray_icon::ClickType::Double { + return; + } + + let mut visible = VISIBLE.lock().unwrap(); + let window_handle = HWND(handle.hwnd as isize); + + if *visible { + unsafe { + ShowWindow(window_handle, SW_HIDE); + } + *visible = false; + } else { + unsafe { + ShowWindow(window_handle, SW_SHOWDEFAULT); + } + *visible = true; + } + })); + } else { + panic!("Unsupported platform"); + } + + Box::new(NativeApp { + settings: settings.clone(), + should_run: should_run.clone(), + tx: tx.clone(), + }) + }), + ); +} + +struct NativeApp { + settings: Arc>, + should_run: Arc>, + tx: mpsc::Sender, +} + +impl eframe::App for NativeApp { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + let mut settings = self.settings.lock().unwrap(); + + ui.heading("Server Settings"); + + ui.horizontal(|ui| { + ui.label("Port:"); + if ui.text_edit_singleline(&mut settings.port).changed() {} + }); + + if ui.button("Apply").clicked() { + if self + .tx + .try_send(ServerMessage::UpdateSettings(settings.clone())) + .is_err() + { + eprintln!("Failed to send settings update"); + } + } + + if ui.button("Interact").clicked() { + if self.tx.try_send(ServerMessage::Interact).is_err() { + eprintln!("Failed to send interaction message"); + } + } + + if ui.button("Shutdown Server").clicked() { + if self.tx.try_send(ServerMessage::Shutdown).is_err() { + eprintln!("Failed to send shutdown message"); + } + } + }); + } +} + +#[derive(Debug, Clone)] +enum ServerMessage { + UpdateSettings(ServerSettings), + Interact, + Shutdown, + // Add other message types here +}