From 4b49d2d61735f9913c5cb4940eb19880811d5283 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 21 Nov 2023 15:18:39 -0500 Subject: [PATCH] refactor: make the single-instance feature additive --- examples/cosmic/Cargo.toml | 2 +- iced | 2 +- src/app/core.rs | 4 +- src/app/cosmic.rs | 9 ++- src/app/mod.rs | 111 ++++++++++++++----------------------- src/app/settings.rs | 4 -- 6 files changed, 54 insertions(+), 78 deletions(-) diff --git a/examples/cosmic/Cargo.toml b/examples/cosmic/Cargo.toml index 72439a97f7a..a4c3bf3e16d 100644 --- a/examples/cosmic/Cargo.toml +++ b/examples/cosmic/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] apply = "0.3.0" fraction = "0.13.0" -libcosmic = { path = "../..", features = ["debug", "winit", "tokio"] } +libcosmic = { path = "../..", features = ["debug", "winit", "tokio", "single-instance"] } once_cell = "1.18" slotmap = "1.0.6" env_logger = "0.10" diff --git a/iced b/iced index 94f8772b2f0..b3ede4f9a72 160000 --- a/iced +++ b/iced @@ -1 +1 @@ -Subproject commit 94f8772b2f05195506f7a454e41290afe02eaa40 +Subproject commit b3ede4f9a72275cfeb29fac80a31546f728783fd diff --git a/src/app/core.rs b/src/app/core.rs index 02e18d3b9dd..d401f0147b4 100644 --- a/src/app/core.rs +++ b/src/app/core.rs @@ -63,7 +63,8 @@ pub struct Core { #[cfg(feature = "applet")] pub applet: crate::applet::Context, - pub single_instance: bool, + #[cfg(feature = "single-instance")] + pub(crate) single_instance: bool, } impl Default for Core { @@ -106,6 +107,7 @@ impl Default for Core { }, #[cfg(feature = "applet")] applet: crate::applet::Context::default(), + #[cfg(feature = "single-instance")] single_instance: false, } } diff --git a/src/app/cosmic.rs b/src/app/cosmic.rs index f820649f6c2..7a89b19e140 100644 --- a/src/app/cosmic.rs +++ b/src/app/cosmic.rs @@ -97,6 +97,8 @@ where super::Message::App(message) => self.app.update(message), super::Message::Cosmic(message) => self.cosmic_update(message), super::Message::None => iced::Command::none(), + #[cfg(feature = "single-instance")] + super::Message::DbusActivation(message) => self.app.dbus_activation(message), } } @@ -184,7 +186,7 @@ where .core() .single_instance .then(|| super::single_instance_subscription::()) - .unwrap_or_else(Subscription::none), + .unwrap_or_else(|| Subscription::none()), ]) } @@ -364,11 +366,12 @@ impl Cosmic { }); } } - Message::Activate(token) => { + Message::Activate(_token) => { #[cfg(feature = "wayland")] return iced_sctk::commands::activation::activate( iced::window::Id::default(), - token, + #[allow(clippy::used_underscore_binding)] + _token, ); } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 6ce284d2ac9..45a2ae09700 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -19,6 +19,9 @@ pub mod message { App(M), /// Internal messages to be handled by libcosmic. Cosmic(super::cosmic::Message), + #[cfg(feature = "single-instance")] + /// Dbus activation messages + DbusActivation(super::DbusActivationMessage), /// Do nothing None, } @@ -36,8 +39,6 @@ pub mod message { } } -use std::str::FromStr; - pub use self::command::Command; pub use self::core::Core; pub use self::settings::Settings; @@ -57,12 +58,11 @@ use { std::collections::HashMap, zbus::{dbus_interface, dbus_proxy, zvariant::Value}, }; -/// Launch a COSMIC application with the given [`Settings`]. -/// -/// # Errors -/// -/// Returns error on application failure. -pub fn run(settings: Settings, flags: App::Flags) -> iced::Result { + +pub(crate) fn iced_settings( + settings: Settings, + flags: App::Flags, +) -> iced::Settings<(Core, App::Flags)> { if let Some(icon_theme) = settings.default_icon_theme { crate::icon_theme::set_default(icon_theme); } @@ -72,7 +72,6 @@ pub fn run(settings: Settings, flags: App::Flags) -> iced::Res core.set_scale_factor(settings.scale_factor); core.set_window_width(settings.size.0); core.set_window_height(settings.size.1); - core.single_instance = settings.single_instance; THEME.with(move |t| { let mut cosmic_theme = t.borrow_mut(); @@ -120,8 +119,20 @@ pub fn run(settings: Settings, flags: App::Flags) -> iced::Res iced.window.transparent = settings.transparent; } - cosmic::Cosmic::::run(iced) + iced +} + +/// Launch a COSMIC application with the given [`Settings`]. +/// +/// # Errors +/// +/// Returns error on application failure. +pub fn run(settings: Settings, flags: App::Flags) -> iced::Result { + let settings = iced_settings::(settings, flags); + + cosmic::Cosmic::::run(settings) } + #[cfg(feature = "single-instance")] #[derive(Debug, Clone)] pub struct DbusActivationMessage> { @@ -259,16 +270,16 @@ impl DbusActivation { } #[cfg(feature = "single-instance")] - /// Launch a COSMIC application with the given [`Settings`]. /// If the application is already running, the arguments will be passed to the /// running instance. /// # Errors /// Returns error on application failure. -pub fn run_single_instance( - mut settings: Settings, - flags: App::Flags, -) -> iced::Result { +pub fn run_single_instance(settings: Settings, flags: App::Flags) -> iced::Result +where + App::Flags: CosmicFlags + Clone, + App::Message: Clone + std::fmt::Debug + Send + 'static, +{ let activation_token = std::env::var("XDG_ACTIVATION_TOKEN").ok(); let override_single = std::env::var("COSMIC_SINGLE_INSTANCE") @@ -279,7 +290,6 @@ pub fn run_single_instance( } let path: String = format!("/{}", App::APP_ID.replace('.', "/")); - settings.single_instance = true; let Ok(conn) = zbus::blocking::Connection::session() else { tracing::warn!("Failed to connect to dbus"); @@ -322,13 +332,15 @@ pub fn run_single_instance( tracing::info!("Another instance is running"); Ok(()) } else { - run::(settings, flags) + let mut settings = iced_settings::(settings, flags); + settings.flags.0.single_instance = true; + cosmic::Cosmic::::run(settings) } } pub trait CosmicFlags { - type SubCommand: FromStr + ToString + std::fmt::Debug + Clone + Send + 'static; - type Args: TryFrom> + Into> + std::fmt::Debug + Clone + Send + 'static; + type SubCommand: ToString + std::fmt::Debug + Clone + Send + 'static; + type Args: Into> + std::fmt::Debug + Clone + Send + 'static; #[must_use] fn action(&self) -> Option<&Self::SubCommand> { None @@ -349,27 +361,9 @@ where /// Default async executor to use with the app. type Executor: iced_futures::Executor; - #[cfg(feature = "single-instance")] - /// Argument received [`Application::new`]. - type Flags: Clone + CosmicFlags; - - #[cfg(not(feature = "single-instance"))] /// Argument received [`Application::new`]. type Flags: Clone; - #[cfg(feature = "single-instance")] - /// Message type specific to our app. - type Message: Clone - + From< - DbusActivationDetails< - ::SubCommand, - ::Args, - >, - > + std::fmt::Debug - + Send - + 'static; - - #[cfg(not(feature = "single-instance"))] /// Message type specific to our app. type Message: Clone + std::fmt::Debug + Send + 'static; @@ -465,6 +459,15 @@ where fn style(&self) -> Option<::Style> { None } + + /// Handles dbus activation messages + #[cfg(feature = "single-instance")] + fn dbus_activation( + &mut self, + msg: DbusActivationMessage, + ) -> iced::Command> { + iced::Command::none() + } } /// Methods automatically derived for all types implementing [`Application`]. @@ -633,7 +636,7 @@ fn single_instance_subscription() -> Subscription(), 10, - |mut output| async move { + move |mut output| async move { let mut single_instance: DbusActivation = DbusActivation::new(); let mut rx = single_instance.rx(); if let Ok(builder) = zbus::ConnectionBuilder::session() { @@ -680,36 +683,8 @@ fn single_instance_subscription() -> Subscription { - Some(DbusActivationDetails::Activate) - } - DbusActivationDetails::Open { url } => { - Some(DbusActivationDetails::Open { url }) - } - DbusActivationDetails::ActivateAction { action, args } => { - if let (Ok(action), Ok(args)) = ( - ::SubCommand::from_str(&action), - ::Args::try_from(args), - ) { - Some(DbusActivationDetails::ActivateAction::< - ::SubCommand, - ::Args, - > { - action, - args, - }) - } else { - tracing::error!("Invalid action or args"); - None - } - } - } { - if let Err(err) = - output.send(Message::App(App::Message::from(msg))).await - { - tracing::error!(?err, "Failed to send message"); - } + if let Err(err) = output.send(Message::DbusActivation(msg)).await { + tracing::error!(?err, "Failed to send message"); } } } diff --git a/src/app/settings.rs b/src/app/settings.rs index 1e4322355dd..10ed4dd3bcb 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -62,9 +62,6 @@ pub struct Settings { /// Whether the application should exit when there are no open windows pub(crate) exit_on_close: bool, - - /// Only allow a single instance of the application to run - pub single_instance: bool, } impl Settings { @@ -100,7 +97,6 @@ impl Default for Settings { theme: crate::theme::system_preference(), transparent: false, exit_on_close: true, - single_instance: false, } } }