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