don't let that reference hang

This commit is contained in:
Erica Z 2024-11-02 17:29:53 +01:00
parent ad51d16a06
commit b966bc18df
2 changed files with 21 additions and 11 deletions

View file

@ -36,15 +36,16 @@ mod imp {
self.mpv.set_property("gapless-audio", true).unwrap(); self.mpv.set_property("gapless-audio", true).unwrap();
// TODO: observe properties // TODO: observe properties
glib::spawn_future_local(glib::clone!( let self_weak = self.obj().downgrade();
#[weak(rename_to = app)] glib::spawn_future_local(async move {
self, while let Some(app) = self_weak.upgrade() {
async move { // this song and dance is required so the strong reference to app
loop { // isn't uselessly preserved during the await
app.mpv.tick().await; let future = app.imp().mpv.tick();
drop(app);
future.await;
} }
} });
));
glib::spawn_future_local(async move { glib::spawn_future_local(async move {
let conn = zbus::connection::Builder::session() let conn = zbus::connection::Builder::session()

View file

@ -45,12 +45,14 @@ impl fmt::Debug for Error {
impl std::error::Error for Error {} impl std::error::Error for Error {}
use event_listener::{Event, IntoNotification}; use event_listener::{Event, IntoNotification};
use std::cell::RefCell;
use std::pin::Pin; use std::pin::Pin;
use std::ptr::NonNull; use std::ptr::NonNull;
pub struct Handle { pub struct Handle {
inner: NonNull<ffi::mpv_handle>, inner: NonNull<ffi::mpv_handle>,
wakeup: Pin<Box<Event>>, // the wakeup callback holds a pointer to this wakeup: Pin<Box<Event>>, // the wakeup callback holds a pointer to this
wait_event_cell: RefCell<()>,
} }
// The client API is generally fully thread-safe, unless otherwise noted. // The client API is generally fully thread-safe, unless otherwise noted.
@ -89,7 +91,11 @@ impl Handle {
Error::from_return_code(unsafe { ffi::mpv_initialize(inner.as_ptr()) }) Error::from_return_code(unsafe { ffi::mpv_initialize(inner.as_ptr()) })
.expect("could not initialize mpv handle"); .expect("could not initialize mpv handle");
Self { inner, wakeup } Self {
inner,
wakeup,
wait_event_cell: RefCell::new(()),
}
} }
pub fn set_property(&self, name: &str, value: impl FormatValue) -> Result<(), Error> { pub fn set_property(&self, name: &str, value: impl FormatValue) -> Result<(), Error> {
@ -104,7 +110,9 @@ impl Handle {
fn drain_event_queue(&self) { fn drain_event_queue(&self) {
loop { loop {
let borrowed = self.wait_event_cell.borrow_mut();
let event = unsafe { &*ffi::mpv_wait_event(self.inner.as_ptr(), 0.0) }; let event = unsafe { &*ffi::mpv_wait_event(self.inner.as_ptr(), 0.0) };
match event.event_id { match event.event_id {
ffi::mpv_event_id_MPV_EVENT_NONE => break, ffi::mpv_event_id_MPV_EVENT_NONE => break,
@ -112,14 +120,15 @@ impl Handle {
_ => todo!("event {}", event.event_id), _ => todo!("event {}", event.event_id),
} }
drop(borrowed); // make sure the borrow is held until here
} }
} }
pub async fn tick(&self) { pub fn tick(&self) -> impl std::future::Future<Output = ()> {
// take listener before we drain the event queue, so we don't miss any notifications // take listener before we drain the event queue, so we don't miss any notifications
let listener = self.wakeup.listen(); let listener = self.wakeup.listen();
self.drain_event_queue(); self.drain_event_queue();
listener.await; listener
} }
} }