fix(single-instance): unconventional dbus names (fixes #3184) (#3194)

Co-authored-by: FabianLars <github@fabianlars.de>
Co-authored-by: Amr Bashir <github@amrbashir.me>
This commit is contained in:
Demir Yerli
2026-02-04 01:36:48 +03:00
committed by GitHub
parent 50b159f668
commit 98e2c11eef
9 changed files with 114 additions and 51 deletions
@@ -8,12 +8,9 @@ use crate::semver_compat::semver_compat_string;
use crate::SingleInstanceCallback;
use tauri::{
plugin::{self, TauriPlugin},
AppHandle, Config, Manager, RunEvent, Runtime,
};
use zbus::{
blocking::{connection::Builder, Connection},
interface,
AppHandle, Manager, RunEvent, Runtime,
};
use zbus::{blocking::Connection, interface, names::WellKnownName};
struct ConnectionHandle(Connection);
@@ -29,35 +26,31 @@ impl<R: Runtime> SingleInstanceDBus<R> {
}
}
#[cfg(feature = "semver")]
fn dbus_id(config: &Config, version: semver::Version) -> String {
let mut id = config.identifier.replace(['.', '-'], "_");
id.push('_');
id.push_str(semver_compat_string(version).as_str());
id
}
struct DBusName(String);
#[cfg(not(feature = "semver"))]
fn dbus_id(config: &Config) -> String {
config.identifier.replace(['.', '-'], "_")
}
pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
pub fn init<R: Runtime>(
callback: Box<SingleInstanceCallback<R>>,
dbus_id: Option<String>,
) -> TauriPlugin<R> {
plugin::Builder::new("single-instance")
.setup(|app, _api| {
.setup(move |app, _api| {
let mut dbus_name = dbus_id.unwrap_or_else(|| app.config().identifier.clone());
dbus_name.push_str(".SingleInstance");
#[cfg(feature = "semver")]
let id = dbus_id(app.config(), app.package_info().version.clone());
#[cfg(not(feature = "semver"))]
let id = dbus_id(app.config());
{
dbus_name.push('_');
dbus_name.push_str(semver_compat_string(&app.package_info().version).as_str());
}
let dbus_path = dbus_name.replace('.', "/");
let single_instance_dbus = SingleInstanceDBus {
callback: f,
callback,
app_handle: app.clone(),
};
let dbus_name = format!("org.{id}.SingleInstance");
let dbus_path = format!("/org/{id}/SingleInstance");
match Builder::session()
match zbus::blocking::connection::Builder::session()
.unwrap()
.name(dbus_name.as_str())
.unwrap()
@@ -92,9 +85,11 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
_ => {}
}
app.manage(DBusName(dbus_name));
Ok(())
})
.on_event(|app, event| {
.on_event(move |app, event| {
if let RunEvent::Exit = event {
destroy(app);
}
@@ -104,15 +99,11 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
pub fn destroy<R: Runtime, M: Manager<R>>(manager: &M) {
if let Some(connection) = manager.try_state::<ConnectionHandle>() {
#[cfg(feature = "semver")]
let id = dbus_id(
manager.config(),
manager.app_handle().package_info().version.clone(),
);
#[cfg(not(feature = "semver"))]
let id = dbus_id(manager.config());
let dbus_name = format!("org.{id}.SingleInstance",);
let _ = connection.0.release_name(dbus_name);
if let Some(dbus_name) = manager
.try_state::<DBusName>()
.and_then(|name| WellKnownName::try_from(name.0.clone()).ok())
{
let _ = connection.0.release_name(dbus_name);
}
}
}
@@ -63,7 +63,7 @@ fn socket_path(config: &Config, _package_info: &tauri::PackageInfo) -> PathBuf {
#[cfg(feature = "semver")]
let identifier = format!(
"{identifier}_{}",
semver_compat_string(_package_info.version.clone()),
semver_compat_string(&_package_info.version),
);
// Use /tmp as socket path must be shorter than 100 chars.
@@ -59,7 +59,7 @@ pub fn init<R: Runtime>(callback: Box<SingleInstanceCallback<R>>) -> TauriPlugin
#[cfg(feature = "semver")]
{
id.push('_');
id.push_str(semver_compat_string(app.package_info().version.clone()).as_str());
id.push_str(semver_compat_string(&app.package_info().version).as_str());
}
let class_name = encode_wide(format!("{id}-sic"));