diff --git a/applets/cosmic-applet-audio/src/pa/future.rs b/applets/cosmic-applet-audio/src/pa/future.rs new file mode 100644 index 00000000..c557b9d9 --- /dev/null +++ b/applets/cosmic-applet-audio/src/pa/future.rs @@ -0,0 +1,63 @@ +use libpulse_binding::operation::Operation; +use std::{ + cell::RefCell, + future::{self, Future}, + pin::Pin, + rc::Rc, + task::{self, Poll, Waker}, +}; + +struct PAFutInner { + res: Option, + waker: Option, +} + +pub struct PAFutWaker(Rc>>); + +impl PAFutWaker { + pub fn wake(&self, res: T) { + let mut inner = self.0.borrow_mut(); + inner.res = Some(res); + if let Some(waker) = inner.waker.take() { + waker.wake(); + } + } +} + +pub struct PAFut { + inner: Rc>>, + operation: Operation, +} + +impl PAFut { + pub fn new(cb: impl FnOnce(PAFutWaker) -> Operation) -> Self { + let inner = Rc::new(RefCell::new(PAFutInner { + res: None, + waker: None, + })); + let operation = cb(PAFutWaker(inner.clone())); + Self { inner, operation } + } +} + +impl Future for PAFut { + type Output = T; + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { + let mut inner = self.inner.borrow_mut(); + if let Some(res) = inner.res.take() { + Poll::Ready(res) + } else { + inner.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl Drop for PAFut { + fn drop(&mut self) { + self.operation.cancel(); + } +} + + diff --git a/applets/cosmic-applet-audio/src/pa.rs b/applets/cosmic-applet-audio/src/pa/mod.rs similarity index 51% rename from applets/cosmic-applet-audio/src/pa.rs rename to applets/cosmic-applet-audio/src/pa/mod.rs index f3ec8e88..6b746081 100644 --- a/applets/cosmic-applet-audio/src/pa.rs +++ b/applets/cosmic-applet-audio/src/pa/mod.rs @@ -1,4 +1,3 @@ -use futures::{channel::oneshot, future::poll_fn, task::Poll}; use gtk4::glib; use libpulse_binding::{ callbacks::ListResult, @@ -12,10 +11,13 @@ use libpulse_binding::{ }; use libpulse_glib_binding::Mainloop; use std::{ - cell::{Ref, RefCell}, + cell::RefCell, rc::Rc, }; +mod future; +use future::{PAFut, PAFutWaker}; + pub struct DeviceInfo { pub name: Option, pub description: Option, @@ -90,37 +92,33 @@ impl PA { } pub async fn get_server_info(&self) -> ServerInfo { - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); - self.introspect().get_server_info(move |info| { - sender.take().unwrap().send(ServerInfo { - default_sink_name: info.default_sink_name.clone().map(|x| x.into_owned()), - default_source_name: info.default_source_name.clone().map(|x| x.into_owned()), - }); - }); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect().get_server_info(move |info| { + waker.wake(ServerInfo { + default_sink_name: info.default_sink_name.clone().map(|x| x.into_owned()), + default_source_name: info.default_source_name.clone().map(|x| x.into_owned()), + }); + }) + }) + .await } pub async fn get_sink_info_list(&self) -> Result, ()> { - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); let mut items = Some(Vec::new()); - self.introspect() - .get_sink_info_list(move |result| match result { - ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo { - name: item.name.clone().map(|x| x.into_owned()), - description: item.description.clone().map(|x| x.into_owned()), - volume: item.volume, - index: item.index, - }), - ListResult::End => { - sender.take().unwrap().send(Ok(items.take().unwrap())); - } - ListResult::Error => { - sender.take().unwrap().send(Err(())); - } - }); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect() + .get_sink_info_list(move |result| match result { + ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo { + name: item.name.clone().map(|x| x.into_owned()), + description: item.description.clone().map(|x| x.into_owned()), + volume: item.volume, + index: item.index, + }), + ListResult::End => waker.wake(Ok(items.take().unwrap())), + ListResult::Error => waker.wake(Err(())), + }) + }) + .await } pub async fn get_default_sink(&self) -> Result { @@ -130,27 +128,23 @@ impl PA { return Err(()); } }; - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); let mut sink = None; - self.introspect() - .get_sink_info_by_name(&name, move |result| match result { - ListResult::Item(item) => { - sink = Some(DeviceInfo { - name: item.name.clone().map(|x| x.into_owned()), - description: item.description.clone().map(|x| x.into_owned()), - volume: item.volume, - index: item.index, - }); - } - ListResult::End => { - sender.take().unwrap().send(sink.take().ok_or(())); - } - ListResult::Error => { - sender.take().unwrap().send(Err(())); - } - }); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect() + .get_sink_info_by_name(&name, move |result| match result { + ListResult::Item(item) => { + sink = Some(DeviceInfo { + name: item.name.clone().map(|x| x.into_owned()), + description: item.description.clone().map(|x| x.into_owned()), + volume: item.volume, + index: item.index, + }); + } + ListResult::End => waker.wake(sink.take().ok_or(())), + ListResult::Error => waker.wake(Err(())), + }) + }) + .await } // XXX async wait and handle error @@ -163,25 +157,21 @@ impl PA { } pub async fn get_source_info_list(&self) -> Result, ()> { - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); let mut items = Some(Vec::new()); - self.introspect() - .get_source_info_list(move |result| match result { - ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo { - name: item.name.clone().map(|x| x.into_owned()), - description: item.description.clone().map(|x| x.into_owned()), - volume: item.volume, - index: item.index, - }), - ListResult::End => { - sender.take().unwrap().send(Ok(items.take().unwrap())); - } - ListResult::Error => { - sender.take().unwrap().send(Err(())); - } - }); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect() + .get_source_info_list(move |result| match result { + ListResult::Item(item) => items.as_mut().unwrap().push(DeviceInfo { + name: item.name.clone().map(|x| x.into_owned()), + description: item.description.clone().map(|x| x.into_owned()), + volume: item.volume, + index: item.index, + }), + ListResult::End => waker.wake(Ok(items.take().unwrap())), + ListResult::Error => waker.wake(Err(())), + }) + }) + .await } pub async fn get_default_source(&self) -> Result { @@ -191,52 +181,44 @@ impl PA { return Err(()); } }; - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); let mut source = None; - self.introspect() - .get_source_info_by_name(&name, move |result| match result { - ListResult::Item(item) => { - source = Some(DeviceInfo { - name: item.name.clone().map(|x| x.into_owned()), - description: item.description.clone().map(|x| x.into_owned()), - volume: item.volume, - index: item.index, - }); - } - ListResult::End => { - sender.take().unwrap().send(source.take().ok_or(())); - } - ListResult::Error => { - sender.take().unwrap().send(Err(())); - } - }); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect() + .get_source_info_by_name(&name, move |result| match result { + ListResult::Item(item) => { + source = Some(DeviceInfo { + name: item.name.clone().map(|x| x.into_owned()), + description: item.description.clone().map(|x| x.into_owned()), + volume: item.volume, + index: item.index, + }); + } + ListResult::End => waker.wake(source.take().ok_or(())), + ListResult::Error => waker.wake(Err(())), + }) + }) + .await } pub async fn set_sink_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool { - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); - self.introspect().set_sink_volume_by_name( - name, - volume, - Some(Box::new(move |success| { - sender.take().unwrap().send(success); - })), - ); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect().set_sink_volume_by_name( + name, + volume, + Some(Box::new(move |success| waker.wake(success))), + ) + }) + .await } pub async fn set_source_volume_by_name(&self, name: &str, volume: &ChannelVolumes) -> bool { - let (sender, receiver) = oneshot::channel(); - let mut sender = Some(sender); - self.introspect().set_source_volume_by_name( - name, - volume, - Some(Box::new(move |success| { - sender.take().unwrap().send(success); - })), - ); - receiver.await.unwrap() + PAFut::new(|waker| { + self.introspect().set_source_volume_by_name( + name, + volume, + Some(Box::new(move |success| waker.wake(success))), + ) + }) + .await } }