More work on mpris controls: buttons now work
This commit is contained in:
parent
0ccab6df13
commit
1145729a9e
2 changed files with 93 additions and 26 deletions
117
src/mpris.rs
117
src/mpris.rs
|
|
@ -5,7 +5,8 @@ use gtk4::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
subclass::prelude::*,
|
subclass::prelude::*,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use once_cell::unsync::OnceCell;
|
||||||
|
use std::{cell::RefCell, collections::HashMap};
|
||||||
|
|
||||||
use crate::deref_cell::DerefCell;
|
use crate::deref_cell::DerefCell;
|
||||||
|
|
||||||
|
|
@ -15,6 +16,8 @@ pub struct MprisControlsInner {
|
||||||
backward_button: DerefCell<gtk4::Button>,
|
backward_button: DerefCell<gtk4::Button>,
|
||||||
play_pause_button: DerefCell<gtk4::Button>,
|
play_pause_button: DerefCell<gtk4::Button>,
|
||||||
forward_button: DerefCell<gtk4::Button>,
|
forward_button: DerefCell<gtk4::Button>,
|
||||||
|
dbus: OnceCell<DBus>,
|
||||||
|
players: RefCell<HashMap<String, Player>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -32,17 +35,17 @@ impl ObjectImpl for MprisControlsInner {
|
||||||
fn constructed(&self, obj: &MprisControls) {
|
fn constructed(&self, obj: &MprisControls) {
|
||||||
let backward_button = cascade! {
|
let backward_button = cascade! {
|
||||||
gtk4::Button::from_icon_name(Some("media-skip-backward-symbolic"));
|
gtk4::Button::from_icon_name(Some("media-skip-backward-symbolic"));
|
||||||
..connect_clicked(|_| {});
|
..connect_clicked(clone!(@strong obj => move |_| obj.call("Previous")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let play_pause_button = cascade! {
|
let play_pause_button = cascade! {
|
||||||
gtk4::Button::from_icon_name(Some("media-playback-start-symbolic"));
|
gtk4::Button::from_icon_name(Some("media-playback-start-symbolic"));
|
||||||
..connect_clicked(|_| {});
|
..connect_clicked(clone!(@strong obj => move |_| obj.call("PlayPause")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let forward_button = cascade! {
|
let forward_button = cascade! {
|
||||||
gtk4::Button::from_icon_name(Some("media-skip-forward-symbolic"));
|
gtk4::Button::from_icon_name(Some("media-skip-forward-symbolic"));
|
||||||
..connect_clicked(|_| {});
|
..connect_clicked(clone!(@strong obj => move |_| obj.call("Next")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let box_ = cascade! {
|
let box_ = cascade! {
|
||||||
|
|
@ -53,31 +56,41 @@ impl ObjectImpl for MprisControlsInner {
|
||||||
..append(&forward_button);
|
..append(&forward_button);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
glib::MainContext::default().spawn_local(clone!(@strong obj => async move {
|
glib::MainContext::default().spawn_local(clone!(@strong obj => async move {
|
||||||
// XXX unwrap
|
let dbus = match DBus::new().await {
|
||||||
let dbus = DBus::new().await.unwrap();
|
Ok(dbus) => dbus,
|
||||||
dbus.connect_name_owner_changed(|a, b, c| {
|
Err(err) => {
|
||||||
println!("{:?}", (a, b, c));
|
eprintln!("Failed to connect to 'org.freedesktop.DBus': {}", err);
|
||||||
});
|
return;
|
||||||
for name in dbus.list_names().await.unwrap() {
|
|
||||||
if !name.starts_with("org.mpris.MediaPlayer2.") {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
let player = Player::new(&name).await.unwrap();
|
};
|
||||||
|
|
||||||
println!("{}", name);
|
dbus.connect_name_owner_changed(clone!(@strong obj => move |name, old, new| {
|
||||||
let status = player.playback_status();
|
if name.starts_with("org.mpris.MediaPlayer2.") {
|
||||||
let metadata = player.metadata().unwrap();
|
if !old.is_empty() {
|
||||||
let title = metadata.title();
|
obj.player_removed(&name);
|
||||||
let album = metadata.album();
|
}
|
||||||
let artist = metadata.artist();
|
if !new.is_empty() {
|
||||||
let art = metadata.arturl();
|
glib::MainContext::default().spawn_local(clone!(@strong obj => async move {
|
||||||
println!("{:?}", (title, art));
|
obj.player_added(&name).await;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
match dbus.list_names().await {
|
||||||
|
Ok(names) => for name in names {
|
||||||
|
if name.starts_with("org.mpris.MediaPlayer2.") {
|
||||||
|
glib::MainContext::default().spawn_local(clone!(@strong obj => async move {
|
||||||
|
obj.player_added(&name).await;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => eprintln!("Failed to call 'ListNames: {}'", err)
|
||||||
}
|
}
|
||||||
std::mem::forget(dbus);
|
|
||||||
|
let _ = obj.inner().dbus.set(dbus);
|
||||||
}));
|
}));
|
||||||
*/
|
|
||||||
|
|
||||||
self.box_.set(box_);
|
self.box_.set(box_);
|
||||||
self.backward_button.set(backward_button);
|
self.backward_button.set(backward_button);
|
||||||
|
|
@ -85,7 +98,7 @@ impl ObjectImpl for MprisControlsInner {
|
||||||
self.forward_button.set(forward_button);
|
self.forward_button.set(forward_button);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispose(&self, obj: &MprisControls) {
|
fn dispose(&self, _obj: &MprisControls) {
|
||||||
self.box_.unparent();
|
self.box_.unparent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +114,52 @@ impl MprisControls {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
glib::Object::new(&[]).unwrap()
|
glib::Object::new(&[]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> &MprisControlsInner {
|
||||||
|
MprisControlsInner::from_instance(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn player(&self) -> Option<Player> {
|
||||||
|
// XXX correctly choose which player to show
|
||||||
|
self.inner().players.borrow().values().next().cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn player_added(&self, name: &str) {
|
||||||
|
let player = match Player::new(&name).await {
|
||||||
|
Ok(player) => player,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to connect to '{}': {}", name, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = player.playback_status();
|
||||||
|
let metadata = player.metadata().unwrap(); // XXX unwrap
|
||||||
|
let title = metadata.title();
|
||||||
|
let album = metadata.album();
|
||||||
|
let artist = metadata.artist();
|
||||||
|
let arturl = metadata.arturl();
|
||||||
|
println!("{:?}", (status, title, album, artist, arturl));
|
||||||
|
|
||||||
|
self.inner()
|
||||||
|
.players
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(name.to_owned(), player);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn player_removed(&self, name: &str) {
|
||||||
|
self.inner().players.borrow_mut().remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, method: &'static str) {
|
||||||
|
glib::MainContext::default().spawn_local(clone!(@strong self as self_ => async move {
|
||||||
|
if let Some(player) = self_.player() {
|
||||||
|
if let Err(err) = player.call(method).await {
|
||||||
|
eprintln!("Failed to call '{}': {}", method, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Metadata(glib::VariantDict);
|
struct Metadata(glib::VariantDict);
|
||||||
|
|
@ -127,6 +186,7 @@ impl Metadata {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct Player(gio::DBusProxy);
|
struct Player(gio::DBusProxy);
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
|
|
@ -143,6 +203,13 @@ impl Player {
|
||||||
Ok(Self(proxy))
|
Ok(Self(proxy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn call(&self, method: &str) -> Result<(), glib::Error> {
|
||||||
|
self.0
|
||||||
|
.call_future(method, None, gio::DBusCallFlags::NONE, 1000)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn property<T: glib::FromVariant>(&self, prop: &str) -> Option<T> {
|
fn property<T: glib::FromVariant>(&self, prop: &str) -> Option<T> {
|
||||||
self.0.cached_property(prop)?.get()
|
self.0.cached_property(prop)?.get()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ impl ObjectImpl for TimeButtonInner {
|
||||||
obj.update_time();
|
obj.update_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispose(&self, obj: &TimeButton) {
|
fn dispose(&self, _obj: &TimeButton) {
|
||||||
self.menu_button.unparent();
|
self.menu_button.unparent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue