status-area: Seperate daemon for status notifier daemon
This allows the applet to be restarted on panel configuration changes without replacing the daemon, or having races between different applet instances trying to run the watcher. Otherwise, this should behave similarly to the existing version. Should fix https://github.com/pop-os/cosmic-panel/issues/284.
This commit is contained in:
parent
fe0e4bf409
commit
aa438821b9
9 changed files with 310 additions and 4 deletions
107
cosmic-applet-status-area/src/unique_names.rs
Normal file
107
cosmic-applet-status-area/src/unique_names.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2026 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// Based on https://github.com/pop-os/cosmic-comp/blob/master/src/dbus/name_owners.rs,
|
||||
// but only tracking unique names, and using tokio executor.
|
||||
|
||||
use futures::StreamExt;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
future::{Future, poll_fn},
|
||||
sync::{Arc, Mutex, Weak},
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
use zbus::{
|
||||
fdo,
|
||||
names::{BusName, UniqueName},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Inner {
|
||||
unique_names: HashSet<UniqueName<'static>>,
|
||||
stream: fdo::NameOwnerChangedStream,
|
||||
// Waker from `update_task` is stored, so that task will still be woken after
|
||||
// polling elsewhere.
|
||||
waker: Waker,
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
// Wake `update_task` so it can terminate
|
||||
self.waker.wake_by_ref();
|
||||
}
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
/// Process all events so far on `stream`, and update `unique_names`.
|
||||
fn update_if_needed(&mut self) {
|
||||
let mut context = Context::from_waker(&self.waker);
|
||||
while let Poll::Ready(val) = self.stream.poll_next_unpin(&mut context) {
|
||||
let val = val.unwrap();
|
||||
let args = val.args().unwrap();
|
||||
match args.name {
|
||||
BusName::Unique(name) => {
|
||||
if args.new_owner.is_some() {
|
||||
self.unique_names.insert(name.to_owned());
|
||||
} else {
|
||||
self.unique_names.remove(&name.to_owned());
|
||||
}
|
||||
}
|
||||
BusName::WellKnown(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This task polls the steam regularly, to make sure events on the stream aren't just
|
||||
/// buffered indefinitely.
|
||||
fn update_task(inner: Weak<Mutex<Inner>>) -> impl Future<Output = ()> {
|
||||
poll_fn(move |context| {
|
||||
if let Some(inner) = inner.upgrade() {
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.waker = context.waker().clone();
|
||||
inner.update_if_needed();
|
||||
// Nothing to do now until waker is invoked
|
||||
Poll::Pending
|
||||
} else {
|
||||
// All strong references have been dropped, so task has nothing left to do.
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UniqueNames(Arc<Mutex<Inner>>);
|
||||
|
||||
impl UniqueNames {
|
||||
pub async fn new(connection: &zbus::Connection) -> zbus::Result<Self> {
|
||||
let dbus = fdo::DBusProxy::new(connection).await?;
|
||||
let stream = dbus.receive_name_owner_changed().await?;
|
||||
|
||||
let names = dbus.list_names().await?;
|
||||
let unique_names = names
|
||||
.iter()
|
||||
.filter_map(|n| match n.inner() {
|
||||
BusName::Unique(name) => Some(name.to_owned()),
|
||||
BusName::WellKnown(_) => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let inner = Arc::new(Mutex::new(Inner {
|
||||
unique_names,
|
||||
stream,
|
||||
waker: Waker::noop().clone(),
|
||||
}));
|
||||
|
||||
tokio::spawn(update_task(Arc::downgrade(&inner)));
|
||||
|
||||
Ok(UniqueNames(inner))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn has_unique_name(&self, name: &UniqueName<'_>) -> bool {
|
||||
let mut inner = self.0.lock().unwrap();
|
||||
inner.update_if_needed();
|
||||
inner.unique_names.contains(name)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue