status-area: Send unregistered signal in watcher
Still not working as expected...
This commit is contained in:
parent
0ecba6a6d0
commit
e52446c770
5 changed files with 155 additions and 93 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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<zbus::ConnectionBuilder<'static>>,
|
||||
>(
|
||||
well_known_name: &'static str,
|
||||
serve_cb: F,
|
||||
) -> zbus::Result<zbus::Connection> {
|
||||
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)
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use cascade::cascade;
|
||||
use gtk4::{glib, prelude::*};
|
||||
|
||||
mod dbus_service;
|
||||
mod deref_cell;
|
||||
mod status_area;
|
||||
mod status_menu;
|
||||
|
|
|
|||
|
|
@ -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<Mutex<Vec<String>>>,
|
||||
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<String> {
|
||||
self.items.lock().unwrap().clone()
|
||||
fn registered_status_notifier_items(&self) -> Vec<String> {
|
||||
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<zbus::Connection> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue