diff --git a/Cargo.lock b/Cargo.lock index cd4c98ed..b36517df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ "relm4-macros", "tokio", "tracker", - "zbus", + "zbus 2.3.2", ] [[package]] @@ -381,7 +381,7 @@ dependencies = [ "libcosmic", "libcosmic-applet", "relm4", - "zbus", + "zbus 2.3.2", ] [[package]] @@ -395,7 +395,7 @@ dependencies = [ "once_cell", "relm4-macros", "tokio", - "zbus", + "zbus 2.3.2", ] [[package]] @@ -413,7 +413,7 @@ dependencies = [ "relm4-macros", "slotmap", "tokio", - "zbus", + "zbus 2.3.2", ] [[package]] @@ -430,7 +430,7 @@ dependencies = [ "once_cell", "relm4-macros", "serde", - "zbus", + "zbus 2.3.2", "zbus_names", "zvariant", ] @@ -449,7 +449,7 @@ dependencies = [ "once_cell", "relm4-macros", "tokio", - "zbus", + "zbus 2.3.2", ] [[package]] @@ -464,8 +464,7 @@ dependencies = [ "libcosmic-applet", "once_cell", "serde", - "zbus", - "zbus_names", + "zbus 3.1.0", "zvariant", ] @@ -482,7 +481,7 @@ dependencies = [ "libcosmic-applet", "once_cell", "serde", - "zbus", + "zbus 2.3.2", "zbus_names", "zvariant", ] @@ -521,7 +520,7 @@ dependencies = [ "derive_builder", "procfs", "time 0.3.13", - "zbus", + "zbus 2.3.2", "zvariant", ] @@ -1713,7 +1712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c03958f20018a20963daf0c16ada4f271ae2da3e0017fb40caa8b0e3dc5b0226" dependencies = [ "serde", - "zbus", + "zbus 2.3.2", "zvariant", ] @@ -1761,7 +1760,7 @@ dependencies = [ "serde", "thiserror", "time 0.3.13", - "zbus", + "zbus 2.3.2", "zvariant", ] @@ -3171,7 +3170,46 @@ dependencies = [ "tracing", "uds_windows", "winapi", - "zbus_macros", + "zbus_macros 2.3.2", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e0d34b881934b987b72a91fdc1daba9ebc90c1f91b7944c680991c4443fc6" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "dirs 4.0.0", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.24.2", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "zbus_macros 3.1.0", "zbus_names", "zvariant", ] @@ -3189,6 +3227,19 @@ dependencies = [ "syn", ] +[[package]] +name = "zbus_macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7905f7c665ea41828bd69112902daa131191a85131fef0f60f7cc3bc2fbec4" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + [[package]] name = "zbus_names" version = "2.2.0" diff --git a/applets/cosmic-applet-status-area/Cargo.toml b/applets/cosmic-applet-status-area/Cargo.toml index bf33d334..5aa67b04 100644 --- a/applets/cosmic-applet-status-area/Cargo.toml +++ b/applets/cosmic-applet-status-area/Cargo.toml @@ -13,6 +13,5 @@ libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = fa libcosmic-applet = { path = "../../libcosmic-applet" } once_cell = "1.12" serde = "1" -zbus = "2.0.1" -zbus_names = "2" +zbus = "3" zvariant = "3" diff --git a/applets/cosmic-applet-status-area/src/dbus_service.rs b/applets/cosmic-applet-status-area/src/dbus_service.rs deleted file mode 100644 index 3c00b5bc..00000000 --- a/applets/cosmic-applet-status-area/src/dbus_service.rs +++ /dev/null @@ -1,53 +0,0 @@ -use futures::prelude::*; -use gtk4::glib::{self, clone}; -use std::cell::Cell; -use zbus::fdo::{DBusProxy, RequestNameFlags, RequestNameReply}; -use zbus_names::WellKnownName; - -pub async fn create< - F: Fn(zbus::ConnectionBuilder<'static>) -> zbus::Result>, ->( - well_known_name: &'static str, - serve_cb: F, -) -> zbus::Result { - let well_known_name = WellKnownName::try_from(well_known_name)?; - - let connection = serve_cb(zbus::ConnectionBuilder::session()?)? - .build() - .await?; - let dbus_proxy = DBusProxy::new(&connection).await?; - let mut name_owner_changed_stream = dbus_proxy.receive_name_owner_changed().await?; - - let flags = RequestNameFlags::AllowReplacement.into(); - match dbus_proxy - .request_name(well_known_name.as_ref(), flags) - .await? - { - RequestNameReply::InQueue => { - eprintln!("Bus name '{}' already owned", well_known_name); - } - _ => {} - } - - glib::MainContext::default().spawn_local(clone!(@strong connection => async move { - let have_bus_name = Cell::new(false); - let unique_name = connection.unique_name().map(|x| x.as_ref()); - while let Some(evt) = name_owner_changed_stream.next().await { - let args = match evt.args() { - Ok(args) => args, - Err(_) => { continue; }, - }; - if args.name.as_ref() == well_known_name { - if args.new_owner.as_ref() == unique_name.as_ref() { - eprintln!("Acquired bus name: {}", well_known_name); - have_bus_name.set(true); - } else if have_bus_name.get() { - eprintln!("Lost bus name: {}", well_known_name); - have_bus_name.set(false); - } - } - } - })); - - Ok(connection) -} diff --git a/applets/cosmic-applet-status-area/src/main.rs b/applets/cosmic-applet-status-area/src/main.rs index f43b09f7..6c7557ed 100644 --- a/applets/cosmic-applet-status-area/src/main.rs +++ b/applets/cosmic-applet-status-area/src/main.rs @@ -1,7 +1,6 @@ use cascade::cascade; use gtk4::{glib, prelude::*}; -mod dbus_service; mod deref_cell; mod status_area; mod status_menu; diff --git a/applets/cosmic-applet-status-area/src/status_notifier_watcher.rs b/applets/cosmic-applet-status-area/src/status_notifier_watcher.rs index b7bff9c5..cfefcdf2 100644 --- a/applets/cosmic-applet-status-area/src/status_notifier_watcher.rs +++ b/applets/cosmic-applet-status-area/src/status_notifier_watcher.rs @@ -1,74 +1,140 @@ #![allow(non_snake_case)] -use std::sync::{Arc, Mutex}; -use zbus::{dbus_interface, MessageHeader, Result, SignalContext}; +use futures::prelude::*; +use gtk4::glib::{self, clone}; +use std::cell::Cell; +use zbus::{ + dbus_interface, + fdo::{DBusProxy, RequestNameFlags, RequestNameReply}, + names::{BusName, UniqueName, WellKnownName}, + MessageHeader, Result, SignalContext, +}; -use crate::dbus_service; +const OBJECT_PATH: &str = "/StatusNotifierWatcher"; #[derive(Default)] struct StatusNotifierWatcher { - items: Arc>>, + items: Vec<(UniqueName<'static>, String)>, } #[dbus_interface(name = "org.kde.StatusNotifierWatcher")] impl StatusNotifierWatcher { - async fn RegisterStatusNotifierItem( - &self, + async fn register_status_notifier_item( + &mut self, service: &str, #[zbus(header)] hdr: MessageHeader<'_>, #[zbus(signal_context)] ctxt: SignalContext<'_>, ) { + let sender = hdr.sender().unwrap().unwrap(); let service = if service.starts_with('/') { - format!("{}{}", hdr.sender().unwrap().unwrap(), service) + format!("{}{}", sender, service) } else { service.to_string() }; - Self::StatusNotifierItemRegistered(&ctxt, &service) + Self::status_notifier_item_registered(&ctxt, &service) .await .unwrap(); - // XXX emit unreigstered - self.items.lock().unwrap().push(service); + self.items.push((sender.to_owned(), service)); } - fn RegisterStatusNotifierHost(&self, _service: &str) { + fn register_status_notifier_host(&self, _service: &str) { // XXX emit registed/unregistered } #[dbus_interface(property)] - fn RegisteredStatusNotifierItems(&self) -> Vec { - self.items.lock().unwrap().clone() + fn registered_status_notifier_items(&self) -> Vec { + self.items.iter().map(|(_, x)| x.clone()).collect() } #[dbus_interface(property)] - fn IsStatusNotifierHostRegistered(&self) -> bool { + fn is_status_notifier_host_registered(&self) -> bool { true } #[dbus_interface(property)] - fn ProtocolVersion(&self) -> i32 { + fn protocol_version(&self) -> i32 { 0 } #[dbus_interface(signal)] - async fn StatusNotifierItemRegistered(ctxt: &SignalContext<'_>, service: &str) -> Result<()>; + async fn status_notifier_item_registered(ctxt: &SignalContext<'_>, service: &str) + -> Result<()>; #[dbus_interface(signal)] - async fn StatusNotifierItemUnregistered(ctxt: &SignalContext<'_>, service: &str) -> Result<()>; + async fn status_notifier_item_unregistered( + ctxt: &SignalContext<'_>, + service: &str, + ) -> Result<()>; #[dbus_interface(signal)] - async fn StatusNotifierHostRegistered(ctxt: &SignalContext<'_>) -> Result<()>; + async fn status_notifier_host_registered(ctxt: &SignalContext<'_>) -> Result<()>; #[dbus_interface(signal)] - async fn StatusNotifierHostUnregistered(ctxt: &SignalContext<'_>) -> Result<()>; + async fn status_notifier_host_unregistered(ctxt: &SignalContext<'_>) -> Result<()>; +} + +async fn create_service() -> zbus::Result { + let well_known_name = WellKnownName::try_from("org.kde.StatusNotifierWatcher")?; + + let connection = zbus::ConnectionBuilder::session()?.build().await?; + connection + .object_server() + .at(OBJECT_PATH, StatusNotifierWatcher::default()) + .await?; + let interface = connection + .object_server() + .interface::<_, StatusNotifierWatcher>(OBJECT_PATH) + .await + .unwrap(); + let dbus_proxy = DBusProxy::new(&connection).await?; + let mut name_owner_changed_stream = dbus_proxy.receive_name_owner_changed().await?; + + let flags = RequestNameFlags::AllowReplacement.into(); + match dbus_proxy + .request_name(well_known_name.as_ref(), flags) + .await? + { + RequestNameReply::InQueue => { + eprintln!("Bus name '{}' already owned", well_known_name); + } + _ => {} + } + + glib::MainContext::default().spawn_local(clone!(@strong connection => async move { + let have_bus_name = Cell::new(false); + let unique_name = connection.unique_name().map(|x| x.as_ref()); + while let Some(evt) = name_owner_changed_stream.next().await { + let args = match evt.args() { + Ok(args) => args, + Err(_) => { continue; }, + }; + if args.name.as_ref() == well_known_name { + if args.new_owner.as_ref() == unique_name.as_ref() { + eprintln!("Acquired bus name: {}", well_known_name); + have_bus_name.set(true); + } else if have_bus_name.get() { + eprintln!("Lost bus name: {}", well_known_name); + have_bus_name.set(false); + } + } else if let BusName::Unique(name) = &args.name { + let mut interface = interface.get_mut().await; + if let Some(idx) = interface.items.iter().position(|(unique_name, _)| unique_name == name) { + let ctxt = zbus::SignalContext::new(&connection, OBJECT_PATH).unwrap(); + let service = interface.items.remove(idx).1; + StatusNotifierWatcher::status_notifier_item_unregistered(&ctxt, &service) + .await + .unwrap(); + } + } + } + })); + + Ok(connection) } pub async fn start() { - if let Err(err) = dbus_service::create("org.kde.StatusNotifierWatcher", |builder| { - builder.serve_at("/StatusNotifierWatcher", StatusNotifierWatcher::default()) - }) - .await - { + if let Err(err) = create_service().await { eprintln!("Failed to start `StatusNotifierWatcher` service: {}", err); } }