From 4ee15fde29f89a7c560583114d2da4211da534ef Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 18 Oct 2021 15:07:01 +0200 Subject: [PATCH 1/5] media-keys: Add guard to MPRIS controller code --- plugins/media-keys/mpris-controller.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/media-keys/mpris-controller.c b/plugins/media-keys/mpris-controller.c index c70f0bc1a..4fcbbf04a 100644 --- a/plugins/media-keys/mpris-controller.c +++ b/plugins/media-keys/mpris-controller.c @@ -77,6 +77,9 @@ mpris_proxy_call_done (GObject *object, gboolean mpris_controller_key (MprisController *self, const gchar *key) { + g_return_val_if_fail (MPRIS_IS_CONTROLLER (self), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + if (!self->mpris_client_proxy) return FALSE; -- GitLab From b53c83c046c46bdbece89e41398dab6192687597 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 18 Oct 2021 15:07:27 +0200 Subject: [PATCH 2/5] media-keys: Add some missing methods to MPRIS controller Make it possible to handle Seek() method calls, as well as toggling Repeat and Shuffle statuses as defined in: https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html --- plugins/media-keys/mpris-controller.c | 111 ++++++++++++++++++++++++++ plugins/media-keys/mpris-controller.h | 2 + 2 files changed, 113 insertions(+) diff --git a/plugins/media-keys/mpris-controller.c b/plugins/media-keys/mpris-controller.c index 4fcbbf04a..de113adb1 100644 --- a/plugins/media-keys/mpris-controller.c +++ b/plugins/media-keys/mpris-controller.c @@ -95,6 +95,117 @@ mpris_controller_key (MprisController *self, const gchar *key) return TRUE; } +gboolean +mpris_controller_seek (MprisController *self, gint64 offset) +{ + g_return_val_if_fail (MPRIS_IS_CONTROLLER (self), FALSE); + + if (!self->mpris_client_proxy) + return FALSE; + + g_debug ("calling Seek over dbus to mpris client %s", + g_dbus_proxy_get_name (self->mpris_client_proxy)); + g_dbus_proxy_call (self->mpris_client_proxy, + "Seek", g_variant_new ("(x)", offset, NULL), + G_DBUS_CALL_FLAGS_NONE, -1, self->cancellable, + mpris_proxy_call_done, + NULL); + return TRUE; +} + +static GDBusProxy * +get_props_proxy (GDBusProxy *proxy, + GCancellable *cancellable) +{ + GDBusProxy *props = NULL; + g_autoptr(GError) error = NULL; + + g_return_val_if_fail (proxy != NULL, NULL); + + props = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy), + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + "org.freedesktop.DBus.Properties", + cancellable, + &error); + if (!props) { + g_debug ("Could not get properties proxy for %s: %s", + g_dbus_proxy_get_interface_name (proxy), + error->message); + return NULL; + } + + return props; +} + +gboolean +mpris_controller_toggle (MprisController *self, const gchar *property) +{ + g_return_val_if_fail (MPRIS_IS_CONTROLLER (self), FALSE); + g_return_val_if_fail (property != NULL, FALSE); + + if (!self->mpris_client_proxy) + return FALSE; + + if (g_str_equal (property, "Repeat")) { + g_autoptr(GDBusProxy) props = NULL; + g_autoptr(GVariant) loop_status; + const gchar *status_str, *new_status; + + loop_status = g_dbus_proxy_get_cached_property (self->mpris_client_proxy, "LoopStatus"); + if (!loop_status) + return FALSE; + if (!g_variant_is_of_type (loop_status, G_VARIANT_TYPE_STRING)) + return FALSE; + status_str = g_variant_get_string (loop_status, NULL); + if (g_str_equal (status_str, "Playlist")) + new_status = "None"; + else + new_status = "Playlist"; + + props = get_props_proxy (self->mpris_client_proxy, self->cancellable); + if (!props) + return FALSE; + g_dbus_proxy_call (props, + "Set", + g_variant_new_parsed ("('org.mpris.MediaPlayer2.Player', 'LoopStatus', %v)", + g_variant_new_string (new_status)), + G_DBUS_CALL_FLAGS_NONE, + -1, + self->cancellable, + mpris_proxy_call_done, NULL); + } else if (g_str_equal (property, "Shuffle")) { + g_autoptr(GDBusProxy) props = NULL; + g_autoptr(GVariant) shuffle_status; + gboolean status; + + shuffle_status = g_dbus_proxy_get_cached_property (self->mpris_client_proxy, "Shuffle"); + if (!shuffle_status) + return FALSE; + if (!g_variant_is_of_type (shuffle_status, G_VARIANT_TYPE_BOOLEAN)) + return FALSE; + status = g_variant_get_boolean (shuffle_status); + + props = get_props_proxy (self->mpris_client_proxy, self->cancellable); + if (!props) + return FALSE; + g_dbus_proxy_call (props, + "Set", + g_variant_new_parsed ("('org.mpris.MediaPlayer2.Player', 'Shuffle', %v)", + g_variant_new_boolean (!status)), + G_DBUS_CALL_FLAGS_NONE, + -1, + self->cancellable, + mpris_proxy_call_done, NULL); + } + + g_debug ("Unhandled toggle property '%s'", property); + + return TRUE; +} + static gboolean mpris_client_is_playing (GDBusProxy *proxy) { diff --git a/plugins/media-keys/mpris-controller.h b/plugins/media-keys/mpris-controller.h index a0044c4df..e44bc9045 100644 --- a/plugins/media-keys/mpris-controller.h +++ b/plugins/media-keys/mpris-controller.h @@ -29,6 +29,8 @@ G_DECLARE_FINAL_TYPE (MprisController, mpris_controller, MPRIS, CONTROLLER, GObj MprisController *mpris_controller_new (void); gboolean mpris_controller_key (MprisController *self, const gchar *key); +gboolean mpris_controller_seek (MprisController *self, gint64 offset); +gboolean mpris_controller_toggle (MprisController *self, const gchar *property); gboolean mpris_controller_get_has_active_player (MprisController *controller); G_END_DECLS -- GitLab From bfc8122b350217d6c15f8d81b13c0801ba16b1ed Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 18 Oct 2021 15:16:17 +0200 Subject: [PATCH 3/5] media-keys: Add support for Rewind, FastForward, Repeat and Shuffle keys As were supported in gnome-settings-daemon's MediaKeys. --- plugins/media-keys/gsd-media-keys-manager.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c index b5f9506db..c691a74c9 100644 --- a/plugins/media-keys/gsd-media-keys-manager.c +++ b/plugins/media-keys/gsd-media-keys-manager.c @@ -119,6 +119,9 @@ static const gchar introspection_xml[] = #define TOUCHPAD_ENABLED_KEY "send-events" #define HIGH_CONTRAST "HighContrast" +#define REWIND_MSEC (-10 * 1000) +#define FASTFORWARD_MSEC (45 * 1000) + #define VOLUME_STEP "volume-step" #define VOLUME_STEP_PRECISE 2 #define MAX_VOLUME 65536.0 @@ -1888,8 +1891,21 @@ gsd_media_player_key_pressed (GsdMediaKeysManager *manager, /* Prefer MPRIS players to those using the native API */ if (mpris_controller_get_has_active_player (priv->mpris_controller)) { - if (mpris_controller_key (priv->mpris_controller, key)) + if (g_str_equal (key, "Rewind")) { + if (mpris_controller_seek (priv->mpris_controller, REWIND_MSEC)) + return TRUE; + } else if (g_str_equal (key, "FastForward")) { + if (mpris_controller_seek (priv->mpris_controller, FASTFORWARD_MSEC)) + return TRUE; + } else if (g_str_equal (key, "LoopStatus")) { + if (mpris_controller_toggle (priv->mpris_controller, "LoopStatus")) + return TRUE; + } else if (g_str_equal (key, "Shuffle")) { + if (mpris_controller_toggle (priv->mpris_controller, "Shuffle")) + return TRUE; + } else if (mpris_controller_key (priv->mpris_controller, key)) { return TRUE; + } } have_listeners = (priv->media_players != NULL); -- GitLab From d08832ccbd7b714d652b507e12bd6b007dfe0db9 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 27 Oct 2021 14:38:31 +0200 Subject: [PATCH 4/5] media-keys: Fix Repeat toggling Repeat is the name of the key within gnome-settings-daemon, LoopStatus is the name of the MPRIS property. Make sure to use the correct one each time. --- plugins/media-keys/gsd-media-keys-manager.c | 2 +- plugins/media-keys/mpris-controller.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c index c691a74c9..af0e67038 100644 --- a/plugins/media-keys/gsd-media-keys-manager.c +++ b/plugins/media-keys/gsd-media-keys-manager.c @@ -1897,7 +1897,7 @@ gsd_media_player_key_pressed (GsdMediaKeysManager *manager, } else if (g_str_equal (key, "FastForward")) { if (mpris_controller_seek (priv->mpris_controller, FASTFORWARD_MSEC)) return TRUE; - } else if (g_str_equal (key, "LoopStatus")) { + } else if (g_str_equal (key, "Repeat")) { if (mpris_controller_toggle (priv->mpris_controller, "LoopStatus")) return TRUE; } else if (g_str_equal (key, "Shuffle")) { diff --git a/plugins/media-keys/mpris-controller.c b/plugins/media-keys/mpris-controller.c index de113adb1..d60d362ec 100644 --- a/plugins/media-keys/mpris-controller.c +++ b/plugins/media-keys/mpris-controller.c @@ -149,7 +149,7 @@ mpris_controller_toggle (MprisController *self, const gchar *property) if (!self->mpris_client_proxy) return FALSE; - if (g_str_equal (property, "Repeat")) { + if (g_str_equal (property, "LoopStatus")) { g_autoptr(GDBusProxy) props = NULL; g_autoptr(GVariant) loop_status; const gchar *status_str, *new_status; -- GitLab From 60a58c98efdbac973b3f9b13b1a422763e19c46e Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 27 Oct 2021 14:39:18 +0200 Subject: [PATCH 5/5] media-keys: Fix fast-forward and rewind keys MPRIS's Seek method uses microseconds, not milliseconds. --- plugins/media-keys/gsd-media-keys-manager.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c index af0e67038..166f311a2 100644 --- a/plugins/media-keys/gsd-media-keys-manager.c +++ b/plugins/media-keys/gsd-media-keys-manager.c @@ -119,8 +119,8 @@ static const gchar introspection_xml[] = #define TOUCHPAD_ENABLED_KEY "send-events" #define HIGH_CONTRAST "HighContrast" -#define REWIND_MSEC (-10 * 1000) -#define FASTFORWARD_MSEC (45 * 1000) +#define REWIND_USEC (-10 * G_USEC_PER_SEC) +#define FASTFORWARD_USEC (45 * G_USEC_PER_SEC) #define VOLUME_STEP "volume-step" #define VOLUME_STEP_PRECISE 2 @@ -1892,10 +1892,10 @@ gsd_media_player_key_pressed (GsdMediaKeysManager *manager, /* Prefer MPRIS players to those using the native API */ if (mpris_controller_get_has_active_player (priv->mpris_controller)) { if (g_str_equal (key, "Rewind")) { - if (mpris_controller_seek (priv->mpris_controller, REWIND_MSEC)) + if (mpris_controller_seek (priv->mpris_controller, REWIND_USEC)) return TRUE; } else if (g_str_equal (key, "FastForward")) { - if (mpris_controller_seek (priv->mpris_controller, FASTFORWARD_MSEC)) + if (mpris_controller_seek (priv->mpris_controller, FASTFORWARD_USEC)) return TRUE; } else if (g_str_equal (key, "Repeat")) { if (mpris_controller_toggle (priv->mpris_controller, "LoopStatus")) -- GitLab