mod imp { use crate::{mpv, ui}; use adw::{prelude::*, subclass::prelude::*}; use gtk::glib; use std::rc::Rc; #[derive(Default)] pub struct Application { // FIXME: move somewhere else mpv: Rc, } #[glib::object_subclass] impl ObjectSubclass for Application { const NAME: &'static str = "AudreyApplication"; type Type = super::Application; type ParentType = adw::Application; } impl ObjectImpl for Application {} impl ApplicationImpl for Application { fn activate(&self) { self.parent_activate(); match self.obj().active_window() { None => { let window = ui::Window::new(self.obj().as_ref()); window.present(); self.mpv .set_property("audio-client-name", "audrey") .unwrap(); self.mpv .set_property("user-agent", crate::USER_AGENT) .unwrap(); self.mpv.set_property("video", false).unwrap(); self.mpv.set_property("prefetch-playlist", true).unwrap(); self.mpv.set_property("gapless-audio", true).unwrap(); // TODO: observe properties let mpv_weak = Rc::downgrade(&self.mpv); glib::spawn_future_local(async move { while let Some(mpv) = mpv_weak.upgrade() { match mpv.tick() { None => break, Some(listener) => listener.await, } } }); glib::spawn_future_local(async move { let conn = zbus::connection::Builder::session() .expect("could not connect to the session bus") .internal_executor(false) .build() .await .expect("could not build connection to the session bus"); // run this in glib's main loop glib::spawn_future_local(glib::clone!( #[strong] conn, async move { loop { conn.executor().tick().await; } } )); crate::Mpris::setup(conn.object_server(), &window) .await .expect("could not serve mpris"); crate::mpris::Player::setup(conn.object_server(), &window.playbin()) .await .expect("could not serve mpris player"); drop(window); // don't keep this alive // always set up handlers before requesting service name conn.request_name("org.mpris.MediaPlayer2.audrey") .await .expect("could not register name in session bus"); }); } Some(win) => win.present(), } } } impl GtkApplicationImpl for Application {} impl AdwApplicationImpl for Application {} impl Application {} impl Drop for Application { fn drop(&mut self) { println!("dropping AudreyApplication"); self.mpv.command(["quit"]).unwrap(); } } } use gtk::{gio, glib}; glib::wrapper! { pub struct Application(ObjectSubclass) @extends adw::Application, gtk::Application, gio::Application, @implements gio::ActionGroup, gio::ActionMap; } impl Default for Application { fn default() -> Self { glib::Object::builder::() .property("application-id", crate::APP_ID) .property("flags", gio::ApplicationFlags::default()) .build() } } impl Application { pub fn new() -> Self { Self::default() } }