Skip to content

Commit

Permalink
refactor: make the single-instance feature additive
Browse files Browse the repository at this point in the history
  • Loading branch information
wash2 committed Nov 21, 2023
1 parent c38dc6d commit 4b49d2d
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 78 deletions.
2 changes: 1 addition & 1 deletion examples/cosmic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion src/app/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -106,6 +107,7 @@ impl Default for Core {
},
#[cfg(feature = "applet")]
applet: crate::applet::Context::default(),
#[cfg(feature = "single-instance")]
single_instance: false,
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/app/cosmic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}

Expand Down Expand Up @@ -184,7 +186,7 @@ where
.core()
.single_instance
.then(|| super::single_instance_subscription::<T>())
.unwrap_or_else(Subscription::none),
.unwrap_or_else(|| Subscription::none()),
])
}

Expand Down Expand Up @@ -364,11 +366,12 @@ impl<T: Application> Cosmic<T> {
});
}
}
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,
);
}
}
Expand Down
111 changes: 43 additions & 68 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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;
Expand All @@ -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<App: Application>(settings: Settings, flags: App::Flags) -> iced::Result {

pub(crate) fn iced_settings<App: Application>(
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);
}
Expand All @@ -72,7 +72,6 @@ pub fn run<App: Application>(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();
Expand Down Expand Up @@ -120,8 +119,20 @@ pub fn run<App: Application>(settings: Settings, flags: App::Flags) -> iced::Res
iced.window.transparent = settings.transparent;
}

cosmic::Cosmic::<App>::run(iced)
iced
}

/// Launch a COSMIC application with the given [`Settings`].
///
/// # Errors
///
/// Returns error on application failure.
pub fn run<App: Application>(settings: Settings, flags: App::Flags) -> iced::Result {
let settings = iced_settings::<App>(settings, flags);

cosmic::Cosmic::<App>::run(settings)
}

#[cfg(feature = "single-instance")]
#[derive(Debug, Clone)]
pub struct DbusActivationMessage<Action = String, Args = Vec<String>> {
Expand Down Expand Up @@ -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<App: Application>(
mut settings: Settings,
flags: App::Flags,
) -> iced::Result {
pub fn run_single_instance<App: Application>(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")
Expand All @@ -279,7 +290,6 @@ pub fn run_single_instance<App: Application>(
}

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");
Expand Down Expand Up @@ -322,13 +332,15 @@ pub fn run_single_instance<App: Application>(
tracing::info!("Another instance is running");
Ok(())
} else {
run::<App>(settings, flags)
let mut settings = iced_settings::<App>(settings, flags);
settings.flags.0.single_instance = true;
cosmic::Cosmic::<App>::run(settings)
}
}

pub trait CosmicFlags {
type SubCommand: FromStr + ToString + std::fmt::Debug + Clone + Send + 'static;
type Args: TryFrom<Vec<String>> + Into<Vec<String>> + std::fmt::Debug + Clone + Send + 'static;
type SubCommand: ToString + std::fmt::Debug + Clone + Send + 'static;
type Args: Into<Vec<String>> + std::fmt::Debug + Clone + Send + 'static;
#[must_use]
fn action(&self) -> Option<&Self::SubCommand> {
None
Expand All @@ -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<
<Self::Flags as CosmicFlags>::SubCommand,
<Self::Flags as CosmicFlags>::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;

Expand Down Expand Up @@ -465,6 +459,15 @@ where
fn style(&self) -> Option<<crate::Theme as iced_style::application::StyleSheet>::Style> {
None
}

/// Handles dbus activation messages
#[cfg(feature = "single-instance")]
fn dbus_activation(
&mut self,
msg: DbusActivationMessage,
) -> iced::Command<Message<Self::Message>> {
iced::Command::none()
}
}

/// Methods automatically derived for all types implementing [`Application`].
Expand Down Expand Up @@ -633,7 +636,7 @@ fn single_instance_subscription<App: ApplicationExt>() -> Subscription<Message<A
iced::subscription::channel(
TypeId::of::<DbusActivation>(),
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() {
Expand Down Expand Up @@ -680,36 +683,8 @@ fn single_instance_subscription<App: ApplicationExt>() -> Subscription<Message<A
tracing::error!(?err, "Failed to send message");
}
}
if let Some(msg) = match msg.msg {
DbusActivationDetails::Activate => {
Some(DbusActivationDetails::Activate)
}
DbusActivationDetails::Open { url } => {
Some(DbusActivationDetails::Open { url })
}
DbusActivationDetails::ActivateAction { action, args } => {
if let (Ok(action), Ok(args)) = (
<App::Flags as CosmicFlags>::SubCommand::from_str(&action),
<App::Flags as CosmicFlags>::Args::try_from(args),
) {
Some(DbusActivationDetails::ActivateAction::<
<App::Flags as CosmicFlags>::SubCommand,
<App::Flags as CosmicFlags>::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");
}
}
}
Expand Down
4 changes: 0 additions & 4 deletions src/app/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -100,7 +97,6 @@ impl Default for Settings {
theme: crate::theme::system_preference(),
transparent: false,
exit_on_close: true,
single_instance: false,
}
}
}

0 comments on commit 4b49d2d

Please sign in to comment.