refactor: make the single-instance feature additive
This commit is contained in:
parent
001fd744c5
commit
57f4abb8a0
5 changed files with 53 additions and 77 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::<T>())
|
||||
.unwrap_or_else(Subscription::none),
|
||||
.unwrap_or_else(|| Subscription::none()),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
111
src/app/mod.rs
111
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<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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
@ -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>> {
|
||||
|
|
@ -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")
|
||||
|
|
@ -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");
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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`].
|
||||
|
|
@ -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() {
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue