From 9dab57e529f91f63e02e701645bc85aa97930ae5 Mon Sep 17 00:00:00 2001 From: ByteAtATime Date: Tue, 1 Jul 2025 20:27:33 -0700 Subject: [PATCH] put window on layer --- src-tauri/Cargo.lock | 93 ++++++++++++++++++++----- src-tauri/Cargo.toml | 2 + src-tauri/src/lib.rs | 151 +++++++++++++++++++++++++++++++--------- src/routes/+page.svelte | 3 +- 4 files changed, 197 insertions(+), 52 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c2db08b..8a2e0ee 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -347,7 +347,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -637,7 +637,7 @@ checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -717,7 +717,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", - "target-lexicon", + "target-lexicon 0.12.16", +] + +[[package]] +name = "cfg-expr" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34e221e91c7eb5e8315b5c9cf1a61670938c0626451f954a51693ed44b37f45" +dependencies = [ + "smallvec", + "target-lexicon 0.13.2", ] [[package]] @@ -1950,7 +1960,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1967,7 +1977,7 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1981,7 +1991,7 @@ dependencies = [ "gobject-sys", "libc", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2007,7 +2017,7 @@ dependencies = [ "gdk-sys", "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", "x11", ] @@ -2133,7 +2143,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", "winapi", ] @@ -2181,7 +2191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2216,7 +2226,7 @@ checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2240,6 +2250,34 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "gtk-layer-shell" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc759b3184830a547b31549ab40c4b54450ab702bba79ba23f049bc1d1e3ca98" +dependencies = [ + "bitflags 2.9.1", + "gdk", + "glib", + "glib-sys", + "gtk", + "gtk-layer-shell-sys", + "libc", +] + +[[package]] +name = "gtk-layer-shell-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eee067e022416d53a70de69d3d3929d8a6e687f3278b8934faa671750fa6eb" +dependencies = [ + "gdk-sys", + "glib-sys", + "gtk-sys", + "libc", + "system-deps 7.0.5", +] + [[package]] name = "gtk-sys" version = "0.18.2" @@ -2255,7 +2293,7 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2846,7 +2884,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -3910,7 +3948,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -4567,7 +4605,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "simd_helpers", - "system-deps", + "system-deps 6.2.2", "thiserror 1.0.69", "v_frame", "wasm-bindgen", @@ -4608,6 +4646,8 @@ dependencies = [ "evdev", "freedesktop-file-parser", "futures-util", + "gtk", + "gtk-layer-shell", "hex", "image", "keyring", @@ -5433,7 +5473,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -5574,7 +5614,20 @@ version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr", + "cfg-expr 0.15.8", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "system-deps" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb" +dependencies = [ + "cfg-expr 0.20.0", "heck 0.5.0", "pkg-config", "toml", @@ -5643,6 +5696,12 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "target-lexicon" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" + [[package]] name = "tauri" version = "2.6.0" @@ -6985,7 +7044,7 @@ dependencies = [ "libc", "pkg-config", "soup3-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 900efe1..97bb1cd 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -64,6 +64,8 @@ notify = "6.1.1" notify-debouncer-full = "0.3.1" percent-encoding = "2.3.1" tauri-plugin-os = "2" +gtk-layer-shell = { version = "0.8.2", features = ["v0_6"] } +gtk = "0.18.2" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-global-shortcut = "2" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4cff014..98e7fed 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -22,6 +22,8 @@ use crate::{app::App, cache::AppCache}; use ai::AiUsageManager; use browser_extension::WsState; use frecency::FrecencyManager; +use gtk::glib::{ControlFlow, MainContext, Priority, Sender}; +use gtk::prelude::{GtkWindowExt, WidgetExt}; use quicklinks::QuicklinkManager; use selection::get_text; use snippets::engine::ExpansionEngine; @@ -32,6 +34,14 @@ use std::thread; use std::time::Duration; use tauri::{Emitter, Manager}; +#[derive(Clone)] +struct GtkWindowHandle(Sender); + +enum GtkCommand { + Show, + Hide, +} + #[tauri::command] fn get_installed_apps() -> Vec { match AppCache::get_apps() { @@ -157,22 +167,19 @@ fn setup_global_shortcut(app: &mut tauri::App) -> Result<(), Box Result<(), String> { + if let Some(gtk_handle) = app.try_state::() { + gtk_handle + .0 + .send(GtkCommand::Hide) + .map_err(|e| e.to_string())?; + return Ok(()); + } + + window.hide().map_err(|e| e.to_string()) +} + +#[tauri::command] +fn show_window(app: tauri::AppHandle, window: tauri::WebviewWindow) -> Result<(), String> { + if let Some(gtk_handle) = app.try_state::() { + gtk_handle + .0 + .send(GtkCommand::Show) + .map_err(|e| e.to_string())?; + return Ok(()); + } + + window.show().map_err(|e| e.to_string()) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - let app = tauri::Builder::default() + tauri::Builder::default() .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_dialog::init()) @@ -211,17 +244,17 @@ pub fn run() { if args.len() > 1 && args[1].starts_with("raycast://") { if let Some(window) = app.get_webview_window("main") { let _ = window.emit("deep-link", args[1].to_string()); - window.show().unwrap(); - window.set_focus().unwrap(); + let _ = show_window(app.clone(), window.clone()); + let _ = window.set_focus(); } return; } if let Some(window) = app.get_webview_window("main") { if let Ok(true) = window.is_visible() { - let _ = window.hide(); + let _ = hide_window(app.clone(), window.clone()); } else { - let _ = window.show(); + let _ = show_window(app.clone(), window.clone()); let _ = window.set_focus(); } } @@ -285,6 +318,8 @@ pub fn run() { ai::get_ai_settings, ai::set_ai_settings, ai::ai_can_access, + hide_window, + show_window, soulver::calculate_soulver ]) .setup(|app| { @@ -311,31 +346,79 @@ pub fn run() { soulver::initialize(soulver_core_path.to_str().unwrap()); + #[cfg(target_os = "linux")] + { + use gtk::prelude::ContainerExt; + use gtk_layer_shell::{Edge, Layer, LayerShell}; + + let webview_window = app.get_webview_window("main").unwrap(); + webview_window.hide().unwrap(); + webview_window.set_decorations(false).unwrap(); + + let window = gtk::ApplicationWindow::new( + &webview_window.gtk_window().unwrap().application().unwrap(), + ); + + window.set_app_paintable(true); + window.set_decorated(false); + window.stick(); + + webview_window + .gtk_window() + .unwrap() + .remove(&webview_window.default_vbox().unwrap()); + window.add(&webview_window.default_vbox().unwrap()); + window.init_layer_shell(); + window.set_layer(Layer::Overlay); + window.set_anchor(Edge::Top, true); + window.set_width_request(400); + window.set_height_request(400); + + if let Some(monitor) = window.display().monitor(0) { + window.set_monitor(&monitor); + } + + window.set_keyboard_mode(gtk_layer_shell::KeyboardMode::Exclusive); + + let (sender, receiver) = MainContext::channel(Priority::DEFAULT); + app.manage(GtkWindowHandle(sender)); + + let main_window_clone = window.clone(); + receiver.attach(None, move |msg| { + match msg { + GtkCommand::Show => main_window_clone.show(), + GtkCommand::Hide => main_window_clone.hide(), + } + ControlFlow::Continue + }); + + window.show_all(); + } + Ok(()) }) .build(tauri::generate_context!()) - .unwrap(); - - app.run(|app, event| { - if let tauri::RunEvent::WindowEvent { label, event, .. } = event { - if label == "main" { - match event { - tauri::WindowEvent::CloseRequested { api, .. } => { - api.prevent_close(); - if let Some(window) = app.get_webview_window("main") { - let _ = window.hide(); - } - } - tauri::WindowEvent::Focused(false) => { - if let Some(window) = app.get_webview_window("main") { - if !cfg!(debug_assertions) { - let _ = window.hide(); + .expect("error while building tauri application") + .run(|app, event| { + if let tauri::RunEvent::WindowEvent { label, event, .. } = event { + if label == "main" { + match event { + tauri::WindowEvent::CloseRequested { api, .. } => { + api.prevent_close(); + if let Some(window) = app.get_webview_window("main") { + let _ = hide_window(app.clone(), window); } } + tauri::WindowEvent::Focused(false) => { + if let Some(window) = app.get_webview_window("main") { + if !cfg!(debug_assertions) { + let _ = hide_window(app.clone(), window); + } + } + } + _ => {} } - _ => {} } } - } - }); + }); } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 1a8888f..ab0dc57 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,4 +1,5 @@