Remove CSD titlebar buttons, fix tray toggle and quit
- Replace GTK header bar with buttonless version to work around upstream bug where CSD buttons become non-interactive after hide()/show() (tauri-apps/tauri#11856, tauri-apps/tao#1046) - Tray menu now toggles between "Hide Claude" / "Show Claude" - Left-click tray icon toggles window visibility - Fix quit from tray (use std::process::exit to bypass keep-alive) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c024717934
commit
6b2c8ffa08
3 changed files with 62 additions and 21 deletions
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
|
|
@ -451,6 +451,7 @@ dependencies = [
|
|||
name = "claude-app"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ serde = { version = "1", features = ["derive"] }
|
|||
serde_json = "1"
|
||||
url = "2"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
gtk = { version = "0.18", features = ["v3_24"] }
|
||||
|
||||
[features]
|
||||
default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
|
|
|||
|
|
@ -97,11 +97,10 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![send_notification])
|
||||
.setup(|app| {
|
||||
// -- Create main window navigating directly to claude.ai --
|
||||
//
|
||||
// on_navigation and on_new_window are builder methods, so they must
|
||||
// be chained before .build(). The close-to-tray handler is set on
|
||||
// the built window via on_window_event.
|
||||
// NOTE: Decorations disabled due to upstream bug where CSD titlebar
|
||||
// buttons become non-interactive after hide()/show() on Linux.
|
||||
// Tracked at: https://github.com/tauri-apps/tauri/issues/11856
|
||||
// https://github.com/tauri-apps/tao/issues/1046
|
||||
let webview_window = WebviewWindowBuilder::new(
|
||||
app,
|
||||
"main",
|
||||
|
|
@ -110,6 +109,7 @@ pub fn run() {
|
|||
.title("Claude")
|
||||
.inner_size(1200.0, 800.0)
|
||||
.min_inner_size(400.0, 300.0)
|
||||
.resizable(true)
|
||||
// Standard WebKit user agent so claude.ai serves the full experience
|
||||
.user_agent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15")
|
||||
.initialization_script(NOTIFICATION_BRIDGE_JS)
|
||||
|
|
@ -124,38 +124,71 @@ pub fn run() {
|
|||
})
|
||||
.build()?;
|
||||
|
||||
// -- Close-to-tray: hide window instead of quitting --
|
||||
let win_clone = webview_window.clone();
|
||||
webview_window.on_window_event(move |event| {
|
||||
if let WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
let _ = win_clone.hide();
|
||||
// Replace the default GTK header bar with one that has no buttons.
|
||||
// The standard CSD buttons become non-interactive after hide()/show()
|
||||
// due to upstream bug: https://github.com/tauri-apps/tauri/issues/11856
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use gtk::prelude::*;
|
||||
if let Ok(gtk_win) = webview_window.gtk_window() {
|
||||
let header = gtk::HeaderBar::new();
|
||||
header.set_show_close_button(false);
|
||||
header.set_title(Some("Claude"));
|
||||
header.show();
|
||||
gtk_win.set_titlebar(Some(&header));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// -- System tray --
|
||||
let show_item =
|
||||
MenuItem::with_id(app, "show", "Show Claude", true, None::<&str>)?;
|
||||
let toggle_item =
|
||||
MenuItem::with_id(app, "toggle", "Hide Claude", true, None::<&str>)?;
|
||||
let quit_item =
|
||||
MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
|
||||
let menu = Menu::with_items(app, &[&show_item, &quit_item])?;
|
||||
let menu = Menu::with_items(app, &[&toggle_item, &quit_item])?;
|
||||
|
||||
let tray_icon = Image::from_bytes(include_bytes!("../icons/32x32.png"))?;
|
||||
|
||||
fn show_window(win: &tauri::WebviewWindow, toggle: &MenuItem<tauri::Wry>) {
|
||||
let _ = win.show();
|
||||
let _ = win.set_focus();
|
||||
let _ = toggle.set_text("Hide Claude");
|
||||
}
|
||||
|
||||
fn hide_window(win: &tauri::WebviewWindow, toggle: &MenuItem<tauri::Wry>) {
|
||||
let _ = win.hide();
|
||||
let _ = toggle.set_text("Show Claude");
|
||||
}
|
||||
|
||||
// -- Close-to-tray: hide window instead of quitting --
|
||||
let win_for_close = webview_window.clone();
|
||||
let toggle_for_close = toggle_item.clone();
|
||||
webview_window.on_window_event(move |event| {
|
||||
if let WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
hide_window(&win_for_close, &toggle_for_close);
|
||||
}
|
||||
});
|
||||
|
||||
let toggle_for_menu = toggle_item.clone();
|
||||
let toggle_for_tray = toggle_item.clone();
|
||||
let tray_handle = app.handle().clone();
|
||||
TrayIconBuilder::new()
|
||||
.icon(tray_icon)
|
||||
.tooltip("Claude")
|
||||
.menu(&menu)
|
||||
.on_menu_event(move |app_handle, event| match event.id().as_ref() {
|
||||
"show" => {
|
||||
"toggle" => {
|
||||
if let Some(win) = app_handle.get_webview_window("main") {
|
||||
let _ = win.show();
|
||||
let _ = win.set_focus();
|
||||
let visible = win.is_visible().unwrap_or(false);
|
||||
if visible {
|
||||
hide_window(&win, &toggle_for_menu);
|
||||
} else {
|
||||
show_window(&win, &toggle_for_menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
"quit" => {
|
||||
app_handle.exit(0);
|
||||
std::process::exit(0);
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
|
|
@ -166,8 +199,12 @@ pub fn run() {
|
|||
} = event
|
||||
{
|
||||
if let Some(win) = tray_handle.get_webview_window("main") {
|
||||
let _ = win.show();
|
||||
let _ = win.set_focus();
|
||||
let visible = win.is_visible().unwrap_or(false);
|
||||
if visible {
|
||||
hide_window(&win, &toggle_for_tray);
|
||||
} else {
|
||||
show_window(&win, &toggle_for_tray);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue