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