[gnome-settings-daemon] media-keys: Use MPRIS when no apps use the media-keys API
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon] media-keys: Use MPRIS when no apps use the media-keys API
- Date: Thu, 1 Aug 2013 08:00:56 +0000 (UTC)
commit cae0fc064b6df1edfc00ee39e6d844d375156f6b
Author: Michael Wood <michael g wood intel com>
Date: Thu Aug 1 09:55:57 2013 +0200
media-keys: Use MPRIS when no apps use the media-keys API
If the media-keys plugin gets a Play or Pause key events and we
don't have any clients registered to handle it through the native
media-keys API, look for an MPRIS interface using bus namespace
watching and try that.
This fixes integration of Spotify for example, as it's unlikely to
implement a GNOME specific interface.
https://bugzilla.gnome.org/show_bug.cgi?id=697810
plugins/media-keys/Makefile.am | 4 +
plugins/media-keys/gsd-media-keys-manager.c | 15 ++-
plugins/media-keys/mpris-controller.c | 209 +++++++++++++++++++++++++++
plugins/media-keys/mpris-controller.h | 56 +++++++
4 files changed, 281 insertions(+), 3 deletions(-)
---
diff --git a/plugins/media-keys/Makefile.am b/plugins/media-keys/Makefile.am
index 6b82014..28d1c37 100644
--- a/plugins/media-keys/Makefile.am
+++ b/plugins/media-keys/Makefile.am
@@ -38,6 +38,8 @@ libmedia_keys_la_SOURCES = \
shell-keybinding-modes.h \
bus-watch-namespace.c \
bus-watch-namespace.h \
+ mpris-controller.c \
+ mpris-controller.h \
$(BUILT_SOURCES) \
$(NULL)
@@ -82,6 +84,8 @@ gsd_test_media_keys_SOURCES = \
gsd-screenshot-utils.c \
bus-watch-namespace.c \
bus-watch-namespace.h \
+ mpris-controller.c \
+ mpris-controller.h \
test-media-keys.c \
$(BUILT_SOURCES) \
$(NULL)
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index 6bae5e3..030146a 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -44,6 +44,7 @@
#include <gudev/gudev.h>
#endif
+#include "mpris-controller.h"
#include "gnome-settings-plugin.h"
#include "gnome-settings-session.h"
#include "gnome-settings-profile.h"
@@ -184,6 +185,8 @@ struct GsdMediaKeysManagerPrivate
GCancellable *cancellable;
guint start_idle_id;
+
+ MprisController *mpris_controller;
};
static void gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass);
@@ -1511,9 +1514,11 @@ gsd_media_player_key_pressed (GsdMediaKeysManager *manager,
have_listeners = (manager->priv->media_players != NULL);
if (!have_listeners) {
- /* Popup a dialog with an (/) icon */
- show_osd (manager, "action-unavailable-symbolic", NULL, -1);
- return TRUE;
+ if (!mpris_controller_key (manager->priv->mpris_controller, key)) {
+ /* Popup a dialog with an (/) icon */
+ show_osd (manager, "action-unavailable-symbolic", NULL, -1);
+ }
+ return TRUE;
}
player = manager->priv->media_players->data;
@@ -2332,6 +2337,9 @@ start_media_keys_idle_cb (GsdMediaKeysManager *manager)
on_shell_vanished,
manager, NULL);
+ g_debug ("Starting mpris controller");
+ manager->priv->mpris_controller = mpris_controller_new ();
+
gnome_settings_profile_end (NULL);
manager->priv->start_idle_id = 0;
@@ -2393,6 +2401,7 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
g_clear_object (&priv->power_proxy);
g_clear_object (&priv->power_screen_proxy);
g_clear_object (&priv->power_keyboard_proxy);
+ g_clear_object (&priv->mpris_controller);
if (manager->priv->name_owner_id) {
g_bus_unwatch_name (manager->priv->name_owner_id);
diff --git a/plugins/media-keys/mpris-controller.c b/plugins/media-keys/mpris-controller.c
new file mode 100644
index 0000000..0e6622e
--- /dev/null
+++ b/plugins/media-keys/mpris-controller.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2013 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses>
+ *
+ * Author: Michael Wood <michael g wood intel com>
+ */
+
+#include "mpris-controller.h"
+#include "bus-watch-namespace.h"
+#include <gio/gio.h>
+
+G_DEFINE_TYPE (MprisController, mpris_controller, G_TYPE_OBJECT)
+
+#define CONTROLLER_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), MPRIS_TYPE_CONTROLLER, MprisControllerPrivate))
+
+struct _MprisControllerPrivate
+{
+ GCancellable *cancellable;
+ GDBusProxy *mpris_client_proxy;
+ guint namespace_watcher_id;
+ GSList *other_players;
+ gboolean connecting;
+};
+
+
+static void
+mpris_controller_dispose (GObject *object)
+{
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv;
+
+ g_clear_object (&priv->cancellable);
+ g_clear_object (&priv->mpris_client_proxy);
+
+ if (priv->namespace_watcher_id)
+ {
+ bus_unwatch_namespace (priv->namespace_watcher_id);
+ priv->namespace_watcher_id = 0;
+ }
+
+ if (priv->other_players)
+ {
+ g_slist_free_full (priv->other_players, g_free);
+ priv->other_players = NULL;
+ }
+
+ G_OBJECT_CLASS (mpris_controller_parent_class)->dispose (object);
+}
+
+static void
+mpris_proxy_call_done (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GVariant *ret;
+
+ if (!(ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error)))
+ {
+ g_warning ("Error calling method %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+ g_variant_unref (ret);
+}
+
+gboolean
+mpris_controller_key (MprisController *self, const gchar *key)
+{
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
+
+ if (!priv->mpris_client_proxy)
+ return FALSE;
+
+ g_debug ("calling %s over dbus to mpris client %s",
+ key, g_dbus_proxy_get_name (priv->mpris_client_proxy));
+ g_dbus_proxy_call (priv->mpris_client_proxy,
+ key, NULL, 0, -1, priv->cancellable,
+ mpris_proxy_call_done,
+ NULL);
+ return TRUE;
+}
+
+static void
+mpris_proxy_ready_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (user_data)->priv;
+ GError *error = NULL;
+
+ priv->mpris_client_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+
+ if (!priv->mpris_client_proxy)
+ g_warning ("Error connecting to mpris interface %s", error->message);
+
+ g_clear_error (&error);
+}
+
+static void
+start_mpris_proxy (MprisController *self, const gchar *name)
+{
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
+
+ g_debug ("Creating proxy for for %s", name);
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+ 0,
+ NULL,
+ name,
+ "/org/mpris/MediaPlayer2",
+ "org.mpris.MediaPlayer2.Player",
+ priv->cancellable,
+ mpris_proxy_ready_cb,
+ self);
+ priv->connecting = TRUE;
+}
+
+static void
+mpris_player_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ MprisController *self = user_data;
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
+
+ if (priv->mpris_client_proxy == NULL && !priv->connecting)
+ start_mpris_proxy (self, name);
+ else
+ self->priv->other_players = g_slist_prepend (self->priv->other_players, g_strdup (name));
+}
+
+static void
+mpris_player_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ MprisController *self = user_data;
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
+
+ if (priv->mpris_client_proxy &&
+ g_strcmp0 (name, g_dbus_proxy_get_name (priv->mpris_client_proxy)) == 0)
+ {
+ g_clear_object (&priv->mpris_client_proxy);
+
+ /* take the next one if there's one */
+ if (self->priv->other_players && !priv->connecting)
+ {
+ GSList *first;
+ gchar *name;
+
+ first = self->priv->other_players;
+ name = first->data;
+
+ start_mpris_proxy (self, name);
+
+ self->priv->other_players = self->priv->other_players->next;
+ g_free (name);
+ g_slist_free_1 (first);
+ }
+ }
+}
+
+static void
+mpris_controller_constructed (GObject *object)
+{
+ MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv;
+
+ priv->namespace_watcher_id = bus_watch_namespace (G_BUS_TYPE_SESSION,
+ "org.mpris.MediaPlayer2",
+ mpris_player_appeared,
+ mpris_player_vanished,
+ MPRIS_CONTROLLER (object),
+ NULL);
+}
+
+static void
+mpris_controller_class_init (MprisControllerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (MprisControllerPrivate));
+
+ object_class->constructed = mpris_controller_constructed;
+ object_class->dispose = mpris_controller_dispose;
+}
+
+static void
+mpris_controller_init (MprisController *self)
+{
+ self->priv = CONTROLLER_PRIVATE (self);
+}
+
+MprisController *
+mpris_controller_new (void)
+{
+ return g_object_new (MPRIS_TYPE_CONTROLLER, NULL);
+}
diff --git a/plugins/media-keys/mpris-controller.h b/plugins/media-keys/mpris-controller.h
new file mode 100644
index 0000000..5333d4e
--- /dev/null
+++ b/plugins/media-keys/mpris-controller.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2013 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses>
+ *
+ * Author: Michael Wood <michael g wood intel com>
+ */
+
+#ifndef __MPRIS_CONTROLLER_H__
+#define __MPRIS_CONTROLLER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MPRIS_TYPE_CONTROLLER mpris_controller_get_type()
+#define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MPRIS_TYPE_CONTROLLER, MprisController))
+#define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MPRIS_TYPE_CONTROLLER,
MprisControllerClass))
+#define MPRIS_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MPRIS_TYPE_CONTROLLER))
+#define MPRIS_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MPRIS_TYPE_CONTROLLER))
+#define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MPRIS_TYPE_CONTROLLER,
MprisControllerClass))
+
+typedef struct _MprisController MprisController;
+typedef struct _MprisControllerClass MprisControllerClass;
+typedef struct _MprisControllerPrivate MprisControllerPrivate;
+
+struct _MprisController
+{
+ GObject parent;
+
+ MprisControllerPrivate *priv;
+};
+
+struct _MprisControllerClass
+{
+ GObjectClass parent_class;
+};
+
+GType mpris_controller_get_type (void) G_GNUC_CONST;
+
+MprisController *mpris_controller_new (void);
+gboolean mpris_controller_key (MprisController *self, const gchar *key);
+
+G_END_DECLS
+
+#endif /* __MPRIS_CONTROLLER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]