diff --git a/Cargo.lock b/Cargo.lock index 9fa18f4..62d68cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,7 @@ dependencies = [ "serde", "tokio", "url", + "zbus 5.0.1", ] [[package]] @@ -1596,9 +1597,9 @@ dependencies = [ "serde", "sha2", "subtle", - "zbus", + "zbus 4.4.0", "zeroize", - "zvariant", + "zvariant 4.2.0", ] [[package]] @@ -2740,9 +2741,44 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333be40ef37976542e10832ba961e3e44ea215a6b1e2673066b303ee3e0ede10" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-util", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "xdg-home", + "zbus_macros 5.0.1", + "zbus_names 4.0.0", + "zvariant 5.0.1", ] [[package]] @@ -2755,7 +2791,20 @@ dependencies = [ "proc-macro2", "quote", "syn", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381be624000c82e716c2a45d9213fabacf82177591fa8a6ff655d2825450601a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils 3.0.1", ] [[package]] @@ -2766,7 +2815,18 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_names" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc27fbd3593ff015cef906527a2ec4115e2e3dbf6204a24d952ac4975c80614" +dependencies = [ + "serde", + "static_assertions", + "zvariant 5.0.1", ] [[package]] @@ -2820,7 +2880,21 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c690a1da8858fd4377b8cc3134a753b0bea1d8ebd78ad6e5897fab821c5e184e" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "zvariant_derive 5.0.1", + "zvariant_utils 3.0.1", ] [[package]] @@ -2833,7 +2907,20 @@ dependencies = [ "proc-macro2", "quote", "syn", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b6ddc1fed08493e4f2bd9350e7d00a3383467228735f3f169a9f8820fde755" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils 3.0.1", ] [[package]] @@ -2846,3 +2933,17 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zvariant_utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d85190ba70bc7b9540430df078bb529620b1464ed4a606010de584e27094d" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn", + "winnow", +] diff --git a/Cargo.toml b/Cargo.toml index a47a864..881b26b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ reqwest = { version = "0.12.9", features = ["json"] } serde = { version = "1.0.214", features = ["derive"] } tokio = { version = "1", features = ["rt-multi-thread"] } url = "2.5.2" +zbus = "5.0.1" [build-dependencies] bindgen = "0.70.1" diff --git a/src/application.rs b/src/application.rs index ffed76a..5a99cab 100644 --- a/src/application.rs +++ b/src/application.rs @@ -20,7 +20,28 @@ mod imp { fn activate(&self) { self.parent_activate(); match self.obj().active_window() { - None => ui::Window::new(self.obj().as_ref()).present(), + None => { + let window = ui::Window::new(self.obj().as_ref()); + window.present(); + + let mpris = crate::Mpris::new(&window); + glib::spawn_future_local(async { + // run this in glib's main loop + let conn = zbus::connection::Builder::session() + .expect("could not create dbus connection builder") + .internal_executor(false) + .name("org.mpris.MediaPlayer2.audrey") + .expect("could not register name in session bus") + .serve_at("/org/mpris/MediaPlayer2", mpris) + .expect("could not serve mpris") + .build() + .await + .expect("could not build dbus connection"); + loop { + conn.executor().tick().await; + } + }); + } Some(win) => win.present(), } } diff --git a/src/mpris.rs b/src/mpris.rs index e8ad8ad..018d2ec 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -1,30 +1,108 @@ mod player; pub use player::Player; -mod ffi { - use gtk::glib; - - #[repr(C)] - pub struct AudreyMpris { - parent_instance: glib::gobject_ffi::GObject, - } - - #[repr(C)] - pub struct AudreyMprisClass { - parent_class: glib::gobject_ffi::GObjectClass, - } - - extern "C" { - pub fn audrey_mpris_get_type() -> glib::ffi::GType; - } -} - +use adw::prelude::*; +use async_channel::Sender; use gtk::glib; -glib::wrapper! { - pub struct Mpris(Object); +pub struct Mpris { + // needs to be Send, so can't store handle to the window... + raise_send: Sender<()>, + quit_send: Sender<()>, +} - match fn { - type_ => || ffi::audrey_mpris_get_type(), +impl Mpris { + pub fn new(window: &crate::ui::Window) -> Self { + let (raise_send, raise_recv) = async_channel::bounded(1); + let (quit_send, quit_recv) = async_channel::bounded(1); + + glib::spawn_future_local(glib::clone!( + #[weak] + window, + async move { + while let Ok(()) = raise_recv.recv().await { + window.present(); + } + } + )); + + glib::spawn_future_local(glib::clone!( + #[weak] + window, + async move { + while let Ok(()) = quit_recv.recv().await { + window.close(); + } + } + )); + + Self { + raise_send: raise_send, + quit_send: quit_send, + } + } +} + +#[zbus::interface(name = "org.mpris.MediaPlayer2")] +impl Mpris { + async fn raise(&self) { + // FIXME: don't unwrap + self.raise_send.send(()).await.unwrap() + } + + async fn quit(&self) { + // FIXME: don't unwrap + self.quit_send.send(()).await.unwrap() + } + + #[zbus(property)] + fn can_quit(&self) -> bool { + true + } + + #[zbus(property)] + fn fullscreen(&self) -> bool { + false + } + + #[zbus(property)] + // TODO: report that if the argument is just _ the attribute panics + async fn set_fullscreen(&self, _fullscreen: bool) -> zbus::Result<()> { + Err(zbus::Error::Unsupported) + } + + #[zbus(property)] + fn can_set_fullscreen(&self) -> bool { + false + } + + #[zbus(property)] + fn can_raise(&self) -> bool { + true + } + + #[zbus(property)] + fn has_track_list(&self) -> bool { + false // TODO? + } + + #[zbus(property)] + fn identity(&self) -> String { + "audrey".to_string() + } + + #[zbus(property)] + fn desktop_entry(&self) -> String { + crate::APP_ID.to_string() + } + + #[zbus(property)] + fn supported_uri_schemes(&self) -> Vec { + vec![] + } + + #[zbus(property)] + fn supported_mime_types(&self) -> Vec { + vec![] } } diff --git a/src/mpris.vala b/src/mpris.vala index 3ae6307..674f24f 100644 --- a/src/mpris.vala +++ b/src/mpris.vala @@ -1,3 +1,4 @@ +/* [DBus (name = "org.mpris.MediaPlayer2")] class Audrey.Mpris : Object { internal signal void on_raise (); @@ -30,6 +31,7 @@ class Audrey.Mpris : Object { debug ("destroying mpris"); } } +*/ [DBus (name = "org.mpris.MediaPlayer2.Player")] class Audrey.MprisPlayer : Object { diff --git a/src/rust.h b/src/rust.h index 8effb57..fcaa73c 100644 --- a/src/rust.h +++ b/src/rust.h @@ -1,5 +1,6 @@ #include #include +#include // ui::playbar typedef void AudreyUiPlaybar; @@ -18,3 +19,8 @@ void audrey_ui_play_queue_song_unbind(AudreyUiPlayQueueSong *self); // ui::PlayQueue typedef void AudreyUiPlayQueue; + +// Mpris +typedef void AudreyMpris; +AudreyMpris *audrey_mpris_new(void *window); +guint audrey_mpris_register_object(AudreyMpris *self, GDBusConnection *conn, const gchar *object_path, GError **error); diff --git a/src/ui/window.rs b/src/ui/window.rs index 337e2b9..d1df364 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -1,4 +1,4 @@ -mod ffi { +pub mod ffi { use gtk::glib; #[repr(C)] diff --git a/src/ui/window.vala b/src/ui/window.vala index d500442..dfac7ca 100644 --- a/src/ui/window.vala +++ b/src/ui/window.vala @@ -1,5 +1,5 @@ [GtkTemplate (ui = "/eu/callcc/audrey/window.ui")] -class Audrey.Ui.Window : Adw.ApplicationWindow { +public class Audrey.Ui.Window : Adw.ApplicationWindow { [GtkChild] public unowned PlayQueue play_queue; [GtkChild] public unowned Playbar playbar; //[GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks; @@ -29,7 +29,6 @@ class Audrey.Ui.Window : Adw.ApplicationWindow { Object (application: app); } - private Mpris mpris; private MprisPlayer mpris_player; private void now_playing (PlaybinSong song) { @@ -59,16 +58,15 @@ class Audrey.Ui.Window : Adw.ApplicationWindow { } construct { + /* Bus.own_name ( BusType.SESSION, "org.mpris.MediaPlayer2.audrey", BusNameOwnerFlags.NONE, (conn) => { try { - this.mpris = new Mpris (this); this.mpris_player = new MprisPlayer (conn, this.playbin); - conn.register_object ("/org/mpris/MediaPlayer2", this.mpris); conn.register_object ("/org/mpris/MediaPlayer2", this.mpris_player); } catch (IOError e) { error ("could not register dbus service: %s", e.message); @@ -76,13 +74,14 @@ class Audrey.Ui.Window : Adw.ApplicationWindow { }, () => {}, () => { error ("could not acquire dbus name"); }); + */ this.setup = new Setup (); this.setup.connected.connect ((api) => { this.api = api; this.playbin.api = api; - this.mpris_player.api = api; + //this.mpris_player.api = api; this.can_click_shuffle_all = true; }); this.setup.load ();