defunct version of windows tray with winit
This commit is contained in:
		
							parent
							
								
									ea29c04a32
								
							
						
					
					
						commit
						61241ae56a
					
				
							
								
								
									
										239
									
								
								src/bin/ui_tray_icon_windows.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/bin/ui_tray_icon_windows.rs
									
									
									
									
									
										Normal file
									
								
							@ -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<Mutex<ServerSettings>>,
 | 
				
			||||||
 | 
					    should_run: Arc<Mutex<bool>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[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<ServerMessage>) {
 | 
				
			||||||
 | 
					    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<Mutex<bool>>) {
 | 
				
			||||||
 | 
					    while *should_run.lock().unwrap() {
 | 
				
			||||||
 | 
					        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn run_ui(
 | 
				
			||||||
 | 
					    settings: Arc<Mutex<ServerSettings>>,
 | 
				
			||||||
 | 
					    should_run: Arc<Mutex<bool>>,
 | 
				
			||||||
 | 
					    tx: mpsc::Sender<ServerMessage>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Create an atomic bool to track window visibility
 | 
				
			||||||
 | 
					    static VISIBLE: once_cell::sync::Lazy<Mutex<bool>> =
 | 
				
			||||||
 | 
					        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<Mutex<ServerSettings>>,
 | 
				
			||||||
 | 
					    should_run: Arc<Mutex<bool>>,
 | 
				
			||||||
 | 
					    tx: mpsc::Sender<ServerMessage>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user