mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Merge pull request #127 from M3gA-Mind/feat/system-tray-bug
fix(tauri): restore working tray controls in desktop shell
This commit is contained in:
@@ -26,7 +26,7 @@ serde_json = "1"
|
||||
|
||||
[dependencies]
|
||||
# Tauri core and plugins
|
||||
tauri = { version = "2.10", features = ["macos-private-api"] }
|
||||
tauri = { version = "2.10", features = ["macos-private-api", "tray-icon"] }
|
||||
tauri-plugin-deep-link = "2.0.0"
|
||||
tauri-plugin-opener = "2"
|
||||
serde_json = "1"
|
||||
|
||||
+71
-15
@@ -3,7 +3,11 @@ compile_error!("src-tauri host is desktop-only. Non-desktop targets are not supp
|
||||
|
||||
mod core_process;
|
||||
|
||||
use tauri::{Manager, RunEvent};
|
||||
use tauri::{
|
||||
menu::{Menu, MenuItem},
|
||||
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
|
||||
AppHandle, Manager, RunEvent,
|
||||
};
|
||||
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
@@ -18,6 +22,65 @@ fn is_daemon_mode() -> bool {
|
||||
std::env::args().any(|arg| arg == "daemon" || arg == "--daemon")
|
||||
}
|
||||
|
||||
fn show_main_window(app: &AppHandle) {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
if let Err(err) = window.show() {
|
||||
log::error!("[tray] failed to show main window: {err}");
|
||||
}
|
||||
if let Err(err) = window.unminimize() {
|
||||
log::error!("[tray] failed to unminimize main window: {err}");
|
||||
}
|
||||
if let Err(err) = window.set_focus() {
|
||||
log::error!("[tray] failed to focus main window: {err}");
|
||||
}
|
||||
} else {
|
||||
log::error!("[tray] main window not found");
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_tray(app: &AppHandle) -> tauri::Result<()> {
|
||||
log::info!("[tray] setting up tray icon");
|
||||
|
||||
let show_item = MenuItem::with_id(app, "tray_show_window", "Open OpenHuman", true, None::<&str>)?;
|
||||
let quit_item = MenuItem::with_id(app, "tray_quit", "Quit", true, None::<&str>)?;
|
||||
let menu = Menu::with_items(app, &[&show_item, &quit_item])?;
|
||||
|
||||
let icon = app
|
||||
.default_window_icon()
|
||||
.cloned()
|
||||
.ok_or_else(|| tauri::Error::AssetNotFound("default window icon".to_string()))?;
|
||||
|
||||
TrayIconBuilder::with_id("openhuman-tray")
|
||||
.icon(icon)
|
||||
.menu(&menu)
|
||||
.on_menu_event(|app, event| match event.id().as_ref() {
|
||||
"tray_show_window" => {
|
||||
log::info!("[tray] action=show_window source=menu");
|
||||
show_main_window(app);
|
||||
}
|
||||
"tray_quit" => {
|
||||
log::info!("[tray] action=quit source=menu");
|
||||
app.exit(0);
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.on_tray_icon_event(|tray, event| {
|
||||
if let TrayIconEvent::Click {
|
||||
button: MouseButton::Left,
|
||||
button_state: MouseButtonState::Up,
|
||||
..
|
||||
} = event
|
||||
{
|
||||
log::info!("[tray] action=show_window source=left_click");
|
||||
show_main_window(tray.app_handle());
|
||||
}
|
||||
})
|
||||
.build(app)?;
|
||||
|
||||
log::info!("[tray] tray icon ready");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
let daemon_mode = is_daemon_mode();
|
||||
|
||||
@@ -59,30 +122,23 @@ pub fn run() {
|
||||
if daemon_mode {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.hide();
|
||||
log::info!("[tray] daemon_mode=true window_hidden_on_startup");
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = setup_tray(app.handle()) {
|
||||
log::error!("[tray] failed to setup tray icon: {err}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![core_rpc_url])
|
||||
.build({
|
||||
let mut context = tauri::generate_context!();
|
||||
if daemon_mode {
|
||||
context.config_mut().app.windows.clear();
|
||||
}
|
||||
context
|
||||
})
|
||||
.build(tauri::generate_context!())
|
||||
.expect("error while building tauri application")
|
||||
.run(move |app_handle, event| match event {
|
||||
#[cfg(target_os = "macos")]
|
||||
RunEvent::Reopen { .. } => {
|
||||
if !daemon_mode {
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
let _ = window.show();
|
||||
let _ = window.unminimize();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}
|
||||
show_main_window(app_handle);
|
||||
}
|
||||
RunEvent::Exit => {
|
||||
if let Some(core) = app_handle.try_state::<core_process::CoreProcessHandle>() {
|
||||
|
||||
@@ -10,7 +10,7 @@ Non-desktop targets fail at compile time (`compile_error!` in `lib.rs`).
|
||||
|
||||
```
|
||||
app/src-tauri/src/
|
||||
├── lib.rs # `run()`, tray, plugins, `generate_handler!`, core startup
|
||||
├── lib.rs # `run()`, tray/menu actions, plugins, `generate_handler!`, core startup
|
||||
├── main.rs # Binary entry
|
||||
├── core_process.rs # CoreProcessHandle, spawn/monitor openhuman sidecar
|
||||
├── core_rpc.rs # HTTP client to core JSON-RPC
|
||||
@@ -37,6 +37,13 @@ React (invoke)
|
||||
|
||||
`CoreProcessHandle` in `core_process.rs` starts or waits for the sidecar; `commands/core_relay.rs` optionally ensures a **service-managed** core is running before relaying.
|
||||
|
||||
## Window and tray behavior
|
||||
|
||||
- The shell creates a tray icon at startup and wires actions to open the main window or quit.
|
||||
- In daemon mode (`daemon` / `--daemon`), the main window is hidden on launch and can be reopened from tray actions.
|
||||
- On macOS `RunEvent::Reopen` also restores and focuses the main window.
|
||||
- Windows and Linux use the same tray actions (`Open OpenHuman`, `Quit`), with desktop-environment-specific tray rendering differences on some Linux setups.
|
||||
|
||||
## Bundled resources
|
||||
|
||||
`tauri.conf.json` bundles **`../../skills/skills`** and **`../../src/openhuman/agent/prompts`** so skills and prompt markdown ship with the app.
|
||||
|
||||
Reference in New Issue
Block a user