diff --git a/Cargo.lock b/Cargo.lock index 4d80748..325f668 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,6 +375,23 @@ dependencies = [ "zbus 5.7.1", ] +[[package]] +name = "ashpd" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.1", + "serde", + "serde_repr", + "tokio", + "url", + "zbus 5.7.1", +] + [[package]] name = "asn1-rs" version = "0.5.2" @@ -2038,7 +2055,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e1a09f280e29a8b00bc7e81eca5ac87dca0575639c9422a5fa25a07bb884b8" dependencies = [ - "ashpd", + "ashpd 0.10.3", "async-std", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3511,7 +3528,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.8", ] [[package]] @@ -4677,6 +4694,7 @@ version = "0.0.0" dependencies = [ "anyhow", "arboard", + "ashpd 0.11.0", "bytes", "dark-light 1.1.1", "futures", @@ -7485,7 +7503,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.103", @@ -11397,6 +11415,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.52.0", ] @@ -12789,7 +12808,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -13693,6 +13712,7 @@ dependencies = [ "ordered-stream", "serde", "serde_repr", + "tokio", "tracing", "uds_windows", "windows-sys 0.59.0", diff --git a/dev_data/config/config.toml b/dev_data/config/config.toml index 6deeabd..01ebd52 100644 --- a/dev_data/config/config.toml +++ b/dev_data/config/config.toml @@ -6,3 +6,6 @@ #main_window_surface = "xdg_shell" global_shortcuts_api = "legacy_x11_api" #global_shortcuts_api = "none" + +[linux] +native_hud = true diff --git a/rust/server/Cargo.toml b/rust/server/Cargo.toml index 54ce89c..980dbdf 100644 --- a/rust/server/Cargo.toml +++ b/rust/server/Cargo.toml @@ -44,6 +44,7 @@ url = "2.5" ureq = "2.10" dark-light = "1.1.1" schemars = "0.8" +ashpd = "0.11" [features] release = ["gauntlet-common/release", "gauntlet-plugin-runtime/release"] diff --git a/rust/server/src/plugins/js.rs b/rust/server/src/plugins/js.rs index b0398a3..d675d84 100644 --- a/rust/server/src/plugins/js.rs +++ b/rust/server/src/plugins/js.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; use std::fs::File; use std::sync::Arc; +use std::time::Duration; +use std::vec; use anyhow::Context; use anyhow::anyhow; @@ -50,6 +52,7 @@ use serde::Serialize; use tokio::sync::Mutex; use crate::model::IntermediateUiEvent; +use crate::plugins::Settings; use crate::plugins::binary_data_gatherer::BinaryDataGatherer; use crate::plugins::clipboard::Clipboard; use crate::plugins::data_db_repository::DataDbRepository; @@ -78,6 +81,7 @@ pub struct PluginRuntimeData { pub db_repository: DataDbRepository, pub search_index: SearchIndex, pub icon_cache: IconCache, + pub settings: Settings, pub frontend_api: FrontendApiProxy, pub dirs: Dirs, pub clipboard: Clipboard, @@ -159,6 +163,7 @@ pub async fn start_plugin_runtime(data: PluginRuntimeData, run_status_guard: Run data.search_index, data.clipboard, data.frontend_api, + data.settings, data.uuid.clone(), data.id.clone(), data.name, @@ -601,6 +606,7 @@ pub struct BackendForPluginRuntimeApiImpl { search_index: SearchIndex, clipboard: Clipboard, frontend_api: FrontendApiProxy, + settings: Settings, #[allow(unused)] plugin_uuid: String, plugin_id: PluginId, @@ -614,6 +620,7 @@ impl BackendForPluginRuntimeApiImpl { search_index: SearchIndex, clipboard: Clipboard, frontend_api: FrontendApiProxy, + settings: Settings, plugin_uuid: String, plugin_id: PluginId, plugin_name: String, @@ -624,6 +631,7 @@ impl BackendForPluginRuntimeApiImpl { search_index, clipboard, frontend_api, + settings, plugin_uuid, plugin_id, plugin_name, @@ -961,7 +969,16 @@ impl BackendForPluginRuntimeApi for BackendForPluginRuntimeApiImpl { } async fn ui_show_hud(&self, display: String) -> RequestResult<()> { - self.frontend_api.show_hud(display).await?; + if cfg!(target_os = "linux") { + if self.settings.config().linux_native_hud { + #[cfg(target_os = "linux")] + show_linux_native_hud(display).await?; + } else { + self.frontend_api.show_hud(display).await?; + } + } else { + self.frontend_api.show_hud(display).await?; + } Ok(()) } @@ -1201,3 +1218,27 @@ fn any_preferences_missing_value( false } + +#[cfg(target_os = "linux")] +async fn show_linux_native_hud(display: String) -> anyhow::Result<()> { + use ashpd::desktop::notification::DisplayHint; + use ashpd::desktop::notification::Notification; + use ashpd::desktop::notification::NotificationProxy; + use ashpd::desktop::notification::Priority; + + let proxy = NotificationProxy::new().await?; + + let notification_id = "sh.gauntlet.Hud"; + let notification = Notification::new(&display) + .priority(Priority::Urgent) + .display_hint(vec![DisplayHint::Transient, DisplayHint::ShowAsNew]); + + proxy.add_notification(notification_id, notification).await?; + + tokio::spawn(async move { + tokio::time::sleep(Duration::from_secs(2)).await; + let _ = proxy.remove_notification(notification_id).await; + }); + + Ok(()) +} diff --git a/rust/server/src/plugins/mod.rs b/rust/server/src/plugins/mod.rs index dfe8b50..c5c2a3e 100644 --- a/rust/server/src/plugins/mod.rs +++ b/rust/server/src/plugins/mod.rs @@ -919,6 +919,7 @@ impl ApplicationManager { search_index: self.search_index.clone(), icon_cache: self.icon_cache.clone(), frontend_api: self.frontend_api.clone(), + settings: self.settings.clone(), dirs: self.dirs.clone(), clipboard: self.clipboard.clone(), }; diff --git a/rust/server/src/plugins/settings/config.rs b/rust/server/src/plugins/settings/config.rs index f6c30db..d2fa862 100644 --- a/rust/server/src/plugins/settings/config.rs +++ b/rust/server/src/plugins/settings/config.rs @@ -5,6 +5,7 @@ use serde::Deserialize; pub struct ApplicationConfig { pub main_window: Option, pub wayland: Option, + pub linux: Option, } #[derive(Deserialize, Debug, Default)] @@ -18,6 +19,11 @@ pub struct WaylandConfig { pub global_shortcuts_api: Option, } +#[derive(Deserialize, Debug, Default)] +pub struct LinuxConfig { + pub native_hud: Option, +} + #[derive(Deserialize, Debug)] pub enum WaylandMainWindowConfig { #[serde(rename = "prefer_wlr_layer_shell")] // default @@ -40,4 +46,5 @@ pub struct EffectiveConfig { pub close_on_unfocus: bool, pub layer_shell: bool, pub wayland_use_legacy_x11_api: bool, + pub linux_native_hud: bool, } diff --git a/rust/server/src/plugins/settings/mod.rs b/rust/server/src/plugins/settings/mod.rs index 7e23978..b2dc7a9 100644 --- a/rust/server/src/plugins/settings/mod.rs +++ b/rust/server/src/plugins/settings/mod.rs @@ -298,8 +298,10 @@ impl Settings { fn effective_config(config: ApplicationConfig, layer_shell_supported: bool) -> EffectiveConfig { let window_config = config.main_window.unwrap_or_default(); let wayland_config = config.wayland.unwrap_or_default(); + let linux_config = config.linux.unwrap_or_default(); let close_on_unfocus = window_config.close_on_unfocus.unwrap_or(true); + let linux_native_hud = linux_config.native_hud.unwrap_or(true); let main_window_surface = wayland_config .main_window_surface @@ -324,5 +326,6 @@ fn effective_config(config: ApplicationConfig, layer_shell_supported: bool) -> E close_on_unfocus, layer_shell, wayland_use_legacy_x11_api, + linux_native_hud, } }