[Xfce4-commits] <parole:master> Add basic org.mpris.MediaPlayer2 and org.mpris.MediaPlayer2.Player. Tested with xfce4-soundmenu-plugin. Please, see TODOS in file.
matiasdelellis
noreply at xfce.org
Thu Dec 12 00:18:03 CET 2013
Updating branch refs/heads/master
to 3d28ecece50ca5127918c5d55d8138a0517a5fa1 (commit)
from 303674839f58a610ed1dfc99b036704faf240568 (commit)
commit 3d28ecece50ca5127918c5d55d8138a0517a5fa1
Author: matiasdelellis <mati86dl at hotmail.com>
Date: Tue Nov 5 14:31:48 2013 -0300
Add basic org.mpris.MediaPlayer2 and org.mpris.MediaPlayer2.Player.
Tested with xfce4-soundmenu-plugin. Please, see TODOS in file.
src/plugins/mpris2/mpris2-provider.c | 762 +++++++++++++++++++++++++++++++++-
1 file changed, 761 insertions(+), 1 deletion(-)
diff --git a/src/plugins/mpris2/mpris2-provider.c b/src/plugins/mpris2/mpris2-provider.c
index 43f8477..9887dc4 100644
--- a/src/plugins/mpris2/mpris2-provider.c
+++ b/src/plugins/mpris2/mpris2-provider.c
@@ -27,6 +27,8 @@
static void mpris2_provider_iface_init (ParoleProviderPluginIface *iface);
static void mpris2_provider_finalize (GObject *object);
+#define MPRIS_NAME "org.mpris.MediaPlayer2.parole"
+#define MPRIS_PATH "/org/mpris/MediaPlayer2"
struct _Mpris2ProviderClass
{
@@ -37,6 +39,17 @@ struct _Mpris2Provider
{
GObject parent;
ParoleProviderPlayer *player;
+
+ guint owner_id;
+ GDBusNodeInfo *introspection_data;
+ GDBusConnection *dbus_connection;
+ GQuark interface_quarks[4];
+
+ gboolean saved_playbackstatus;
+ gboolean saved_shuffle;
+ gchar *saved_title;
+ gdouble volume;
+ ParoleState state;
};
PAROLE_DEFINE_TYPE_WITH_CODE (Mpris2Provider,
@@ -44,7 +57,739 @@ PAROLE_DEFINE_TYPE_WITH_CODE (Mpris2Provider,
G_TYPE_OBJECT,
PAROLE_IMPLEMENT_INTERFACE (PAROLE_TYPE_PROVIDER_PLUGIN,
mpris2_provider_iface_init));
-
+
+
+static const gchar mpris2xml[] =
+"<node>"
+" <interface name='org.mpris.MediaPlayer2'>"
+" <method name='Raise'/>"
+" <method name='Quit'/>"
+" <property name='CanQuit' type='b' access='read'/>"
+" <property name='CanRaise' type='b' access='read'/>"
+" <property name='HasTrackList' type='b' access='read'/>"
+" <property name='Identity' type='s' access='read'/>"
+" <property name='DesktopEntry' type='s' access='read'/>"
+" <property name='SupportedUriSchemes' type='as' access='read'/>"
+" <property name='SupportedMimeTypes' type='as' access='read'/>"
+" </interface>"
+" <interface name='org.mpris.MediaPlayer2.Player'>"
+" <method name='Next'/>"
+" <method name='Previous'/>"
+" <method name='Pause'/>"
+" <method name='PlayPause'/>"
+" <method name='Stop'/>"
+" <method name='Play'/>"
+" <method name='Seek'>"
+" <arg direction='in' name='Offset' type='x'/>"
+" </method>"
+" <method name='SetPosition'>"
+" <arg direction='in' name='TrackId' type='o'/>"
+" <arg direction='in' name='Position' type='x'/>"
+" </method>"
+" <method name='OpenUri'>"
+" <arg direction='in' name='Uri' type='s'/>"
+" </method>"
+" <signal name='Seeked'><arg name='Position' type='x'/></signal>"
+" <property name='PlaybackStatus' type='s' access='read'/>"
+" <property name='LoopStatus' type='s' access='readwrite'/>"
+" <property name='Rate' type='d' access='readwrite'/>"
+" <property name='Shuffle' type='b' access='readwrite'/>"
+" <property name='Metadata' type='a{sv}' access='read'/>"
+" <property name='Volume' type='d' access='readwrite'/>"
+" <property name='Position' type='x' access='read'/>"
+" <property name='MinimumRate' type='d' access='read'/>"
+" <property name='MaximumRate' type='d' access='read'/>"
+" <property name='CanGoNext' type='b' access='read'/>"
+" <property name='CanGoPrevious' type='b' access='read'/>"
+" <property name='CanPlay' type='b' access='read'/>"
+" <property name='CanPause' type='b' access='read'/>"
+" <property name='CanSeek' type='b' access='read'/>"
+" <property name='CanControl' type='b' access='read'/>"
+" </interface>"
+"</node>";
+
+/* some MFCisms */
+#define BEGIN_INTERFACE(x) \
+ if(g_quark_try_string(interface_name)==provider->interface_quarks[x]) {
+#define MAP_METHOD(x,y) \
+ if(!g_strcmp0(#y, method_name)) { \
+ mpris_##x##_##y(invocation, parameters, provider); return; }
+#define PROPGET(x,y) \
+ if(!g_strcmp0(#y, property_name)) \
+ return mpris_##x##_get_##y(error, provider);
+#define PROPPUT(x,y) \
+ if(g_quark_try_string(property_name)==g_quark_from_static_string(#y)) \
+ mpris_##x##_put_##y(value, error, provider);
+#define END_INTERFACE }
+
+/*
+ * org.mpris.MediaPlayer2
+ */
+static void mpris_Root_Raise (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+
+ // TODO:
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Root_Quit (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ // TODO:
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static GVariant* mpris_Root_get_CanQuit (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant* mpris_Root_get_CanRaise (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant* mpris_Root_get_HasTrackList (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant* mpris_Root_get_Identity (GError **error, Mpris2Provider *provider)
+{
+ // TODO: Set true name.
+ return g_variant_new_string("Parole");
+}
+
+static GVariant* mpris_Root_get_DesktopEntry (GError **error, Mpris2Provider *provider)
+{
+ GVariant* ret_val = g_variant_new_string("parole");
+ return ret_val;
+}
+
+static GVariant* mpris_Root_get_SupportedUriSchemes (GError **error, Mpris2Provider *provider)
+{
+ // TODO Complete uris schemes
+ return g_variant_parse(G_VARIANT_TYPE("as"),
+ "['file', 'cdda']", NULL, NULL, NULL);
+}
+
+static GVariant* mpris_Root_get_SupportedMimeTypes (GError **error, Mpris2Provider *provider)
+{
+ // TODO Fixs mime tyme. This are of Pragha
+ return g_variant_parse(G_VARIANT_TYPE("as"),
+ "['audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg', 'audio/mpeg3', "
+ "'audio/mp3', 'application/ogg', 'application/x-ogg', 'audio/vorbis', "
+ "'audio/x-vorbis', 'audio/ogg', 'audio/x-ogg', 'audio/x-flac', "
+ "'video/x-ms-asf', 'audio/x-ms-wma', 'audio/x-m4a', "
+ "'application/x-ape', 'audio/ape', 'audio/x-ape', "
+ "'application/x-flac', 'audio/flac', 'audio/x-wav']", NULL, NULL, NULL);
+}
+
+/*
+ * org.mpris.MediaPlayer2.Player
+ */
+static void mpris_Player_Play (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ // FIXME: How to play any song
+ parole_provider_player_play_next (provider->player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_Next (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ parole_provider_player_play_next (provider->player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_Previous (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ parole_provider_player_play_previous (provider->player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_Pause (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ parole_provider_player_pause (provider->player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_PlayPause (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ ParoleState state = PAROLE_STATE_STOPPED;
+ ParoleProviderPlayer *player = provider->player;
+
+ state = parole_provider_player_get_state (player);
+
+ // FIXME: Need handle the rest of the states?
+ if (state == PAROLE_STATE_PAUSED)
+ parole_provider_player_resume (player);
+ else if (state == PAROLE_STATE_PLAYING)
+ parole_provider_player_pause (player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_Stop (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ parole_provider_player_stop (provider->player);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_Seek (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ // TODO: Implement seek..
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_SetPosition (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ // TODO: Implement set position..
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void mpris_Player_OpenUri (GDBusMethodInvocation *invocation, GVariant* parameters, Mpris2Provider *provider)
+{
+ gchar *uri = NULL;
+ gboolean happened = FALSE;
+ ParoleProviderPlayer *player = provider->player;
+
+ g_variant_get(parameters, "(s)", &uri);
+ if (uri) {
+ happened = parole_provider_player_play_uri (player, uri);
+ g_free(uri);
+ }
+
+ if(happened)
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ else
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_FILE_CONTENT,
+ "This file does not play here.");
+}
+
+static GVariant* mpris_Player_get_PlaybackStatus (GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+
+ switch (parole_provider_player_get_state(player)) {
+ case PAROLE_STATE_PLAYING:
+ return g_variant_new_string("Playing");
+ case PAROLE_STATE_PAUSED:
+ return g_variant_new_string("Paused");
+ default:
+ return g_variant_new_string("Stopped");
+ }
+}
+
+static GVariant* mpris_Player_get_LoopStatus (GError **error, Mpris2Provider *provider)
+{
+ gboolean repeat = FALSE;
+ /* TODO: How to get conf properties?
+ g_object_get (G_OBJECT (player->priv->conf),
+ "shuffle", &shuffle,
+ "repeat", &repeat,
+ NULL);*/
+
+ return g_variant_new_string(repeat ? "Playlist" : "None");
+}
+
+static void mpris_Player_put_LoopStatus (GVariant *value, GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+
+ const gchar *new_loop = g_variant_get_string(value, NULL);
+
+ gboolean repeat = g_strcmp0("Playlist", new_loop) ? FALSE : TRUE;
+
+ /* TODO: How to set conf properties?
+ g_object_set (G_OBJECT (player->priv->conf),
+ "repeat", repeat,
+ NULL);*/
+}
+
+static GVariant* mpris_Player_get_Rate (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_double(1.0);
+}
+
+static void mpris_Player_put_Rate (GVariant *value, GError **error, Mpris2Provider *provider)
+{
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This is not alsaplayer.");
+}
+
+static GVariant* mpris_Player_get_Shuffle (GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+ gboolean shuffle = FALSE;
+
+ /* TODO: How to get conf properties?
+ g_object_get (G_OBJECT (player->priv->conf),
+ "shuffle", &shuffle,
+ "repeat", &repeat,
+ NULL);*/
+ return g_variant_new_boolean(shuffle);
+}
+
+static void mpris_Player_put_Shuffle (GVariant *value, GError **error, Mpris2Provider *provider)
+{
+ gboolean shuffle = g_variant_get_boolean(value);
+
+ ParoleProviderPlayer *player = provider->player;
+ /* TODO: How to set conf properties?
+ /*g_object_set (G_OBJECT (player->priv->conf),
+ "shuffle", shuffle,
+ NULL);*/
+}
+
+static GVariant * handle_get_trackid(const ParoleStream *stream)
+{
+ gchar *o = alloca(260);
+ if(NULL == stream)
+ return g_variant_new_object_path("/");
+
+ g_snprintf(o, 260, "%s/TrackList/%p", MPRIS_PATH, stream);
+
+ return g_variant_new_object_path(o);
+}
+
+static void handle_strings_request(GVariantBuilder *b, const gchar *tag, const gchar *val)
+{
+ GVariant *vval = g_variant_new_string(val);
+ GVariant *vvals = g_variant_new_array(G_VARIANT_TYPE_STRING, &vval, 1);
+
+ g_variant_builder_add (b, "{sv}", tag, vvals);
+}
+
+static void handle_get_metadata (const ParoleStream *stream, GVariantBuilder *b)
+{
+ gchar *title, *album, *artist, *year, *comment, *stream_uri;
+ gint64 duration;
+
+ g_object_get (G_OBJECT (stream),
+ "title", &title,
+ "album", &album,
+ "artist", &artist,
+ "year", &year,
+ "comment", &comment,
+ "duration", &duration,
+ "uri", &stream_uri,
+ NULL);
+
+ g_variant_builder_add (b, "{sv}", "mpris:trackid",
+ handle_get_trackid(stream));
+ g_variant_builder_add (b, "{sv}", "xesam:url",
+ g_variant_new_string(stream_uri));
+ g_variant_builder_add (b, "{sv}", "xesam:title",
+ g_variant_new_string(title));
+ handle_strings_request(b, "xesam:artist", artist);
+ g_variant_builder_add (b, "{sv}", "xesam:album",
+ g_variant_new_string(album));
+ handle_strings_request(b, "xesam:genre", "unknown"); // FIXME: genre was mandatory?
+ g_variant_builder_add (b, "{sv}", "xesam:contentCreated",
+ g_variant_new_string(year));
+ g_variant_builder_add (b, "{sv}", "xesam:trackNumber",
+ g_variant_new_int32(0));
+ handle_strings_request(b, "xesam:comment", comment);
+ g_variant_builder_add (b, "{sv}", "mpris:length",
+ g_variant_new_int64((gint64)duration * 1000000));
+ g_variant_builder_add (b, "{sv}", "audio-bitrate", // TODO: How get audio properties?
+ g_variant_new_int32(0));
+ g_variant_builder_add (b, "{sv}", "audio-channels",
+ g_variant_new_int32(0));
+ g_variant_builder_add (b, "{sv}", "audio-samplerate",
+ g_variant_new_int32(0));
+
+ g_free(title);
+ g_free(album);
+ g_free(artist);
+ g_free(year);
+ g_free(comment);
+ g_free(stream_uri);
+}
+
+static GVariant* mpris_Player_get_Metadata (GError **error, Mpris2Provider *provider)
+{
+ GVariantBuilder b;
+ const ParoleStream *stream;
+ ParoleProviderPlayer *player = provider->player;
+
+ g_variant_builder_init(&b, G_VARIANT_TYPE ("a{sv}"));
+
+ if (parole_provider_player_get_state(player) != PAROLE_STATE_STOPPED) {
+ stream = parole_provider_player_get_stream(player);
+
+ handle_get_metadata (stream, &b);
+ }
+ else {
+ g_variant_builder_add (&b, "{sv}", "mpris:trackid",
+ handle_get_trackid(NULL));
+ }
+ return g_variant_builder_end(&b);
+}
+
+static GVariant* mpris_Player_get_Volume (GError **error, Mpris2Provider *provider)
+{
+ gdouble volume = 0;
+ ParoleProviderPlayer *player = provider->player;
+
+ /* TODO: How to get conf properties?
+ g_object_get (G_OBJECT (player->priv->conf),
+ "volume", &volume,
+ NULL);*/
+
+ return g_variant_new_double(volume);
+}
+
+static void mpris_Player_put_Volume (GVariant *value, GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+
+ gdouble volume = g_variant_get_double(value);
+
+ /* TODO: How set volume volume?
+ parole_gst_set_volume (PAROLE_GST (player->priv->gst), value);*/
+}
+
+static GVariant* mpris_Player_get_Position (GError **error, Mpris2Provider *provider)
+{
+ gdouble position = 0;
+
+ /* TODO: How get position?
+ gdouble position = parole_gst_get_stream_position (PAROLE_GST (player->priv->gst))*/
+
+ return g_variant_new_int64(position);
+}
+
+static GVariant* mpris_Player_get_MinimumRate (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_double(1.0);
+}
+
+static GVariant* mpris_Player_get_MaximumRate (GError **error, Mpris2Provider *provider)
+{
+ return g_variant_new_double(1.0);
+}
+
+static GVariant* mpris_Player_get_CanGoNext (GError **error, Mpris2Provider *provider)
+{
+ // do we need to go into such detail?
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant* mpris_Player_get_CanGoPrevious (GError **error, Mpris2Provider *provider)
+{
+ // do we need to go into such detail?
+ return g_variant_new_boolean(TRUE);
+}
+
+static GVariant* mpris_Player_get_CanPlay (GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+ return g_variant_new_boolean(parole_provider_player_get_state (player) == PAROLE_STATE_PAUSED);
+}
+
+static GVariant* mpris_Player_get_CanPause (GError **error, Mpris2Provider *provider)
+{
+ ParoleProviderPlayer *player = provider->player;
+ return g_variant_new_boolean(parole_provider_player_get_state (player) == PAROLE_STATE_PLAYING);
+}
+
+static GVariant* mpris_Player_get_CanSeek (GError **error, Mpris2Provider *provider)
+{
+ gboolean seekable = FALSE;
+ ParoleProviderPlayer *player = provider->player;
+
+ const ParoleStream *stream;
+ stream = parole_provider_player_get_stream(player);
+
+ g_object_get (G_OBJECT (stream),
+ "seekable", &seekable,
+ NULL);
+
+ return g_variant_new_boolean (seekable);
+}
+
+static GVariant* mpris_Player_get_CanControl (GError **error, Mpris2Provider *provider)
+{
+ // always?
+ return g_variant_new_boolean(TRUE);
+}
+
+/*
+ * Update state.
+ */
+
+static void parole_mpris_update_any (Mpris2Provider *provider)
+{
+ const ParoleStream *stream;
+ gboolean change_detected = FALSE, shuffle = FALSE, repeat = FALSE;
+ gchar *stream_uri = NULL;
+ GVariantBuilder b;
+ gdouble curr_vol = 0;
+
+ ParoleProviderPlayer *player = provider->player;
+
+ if(NULL == provider->dbus_connection)
+ return; /* better safe than sorry */
+
+ g_debug ("MPRIS update any");
+
+ stream = parole_provider_player_get_stream(player);
+ g_object_get (G_OBJECT (stream),
+ "uri", &stream_uri,
+ NULL);
+
+ g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
+
+ //shuffle = pragha_preferences_get_shuffle (preferences);
+ if(provider->saved_shuffle != shuffle)
+ {
+ change_detected = TRUE;
+ provider->saved_shuffle = shuffle;
+ g_variant_builder_add (&b, "{sv}", "Shuffle", mpris_Player_get_Shuffle (NULL, provider));
+ }
+ if(provider->state != parole_provider_player_get_state (player))
+ {
+ change_detected = TRUE;
+ provider->state = parole_provider_player_get_state (player);
+ g_variant_builder_add (&b, "{sv}", "PlaybackStatus", mpris_Player_get_PlaybackStatus (NULL, provider));
+ }
+ //repeat = pragha_preferences_get_repeat (preferences);
+ if(provider->saved_playbackstatus != repeat)
+ {
+ change_detected = TRUE;
+ provider->saved_playbackstatus = repeat;
+ g_variant_builder_add (&b, "{sv}", "LoopStatus", mpris_Player_get_LoopStatus (NULL, provider));
+ }
+ //curr_vol = pragha_backend_get_volume (backend);
+ if(provider->volume != curr_vol)
+ {
+ change_detected = TRUE;
+ provider->volume = curr_vol;
+ g_variant_builder_add (&b, "{sv}", "Volume", mpris_Player_get_Volume (NULL, provider));
+ }
+ if(g_strcmp0(provider->saved_title, stream_uri))
+ {
+ change_detected = TRUE;
+ if(provider->saved_title)
+ g_free(provider->saved_title);
+ if (stream_uri && (stream_uri)[0])
+ provider->saved_title = stream_uri;
+ else
+ provider->saved_title = NULL;
+
+ g_variant_builder_add (&b, "{sv}", "Metadata", mpris_Player_get_Metadata (NULL, provider));
+ }
+ if(change_detected)
+ {
+ GVariant * tuples[] = {
+ g_variant_new_string("org.mpris.MediaPlayer2.Player"),
+ g_variant_builder_end(&b),
+ g_variant_new_strv(NULL, 0)
+ };
+
+ g_dbus_connection_emit_signal(provider->dbus_connection, NULL, MPRIS_PATH,
+ "org.freedesktop.DBus.Properties", "PropertiesChanged",
+ g_variant_new_tuple(tuples, 3) , NULL);
+ }
+ else
+ {
+ g_variant_builder_clear(&b);
+ }
+}
+
+
+static void
+state_changed_cb (ParoleProviderPlayer *player, const ParoleStream *stream, ParoleState state, Mpris2Provider *provider)
+{
+ parole_mpris_update_any (provider);
+}
+
+/*
+ * Dbus callbacks
+ */
+static void
+handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ Mpris2Provider *provider;
+ ParoleProviderPlugin *plugin = user_data;
+ provider = MPRIS2_PROVIDER (plugin);
+
+ /* org.mpris.MediaPlayer2 */
+ BEGIN_INTERFACE(0)
+ MAP_METHOD(Root, Raise)
+ MAP_METHOD(Root, Quit)
+ END_INTERFACE
+ /* org.mpris.MediaPlayer2.Player */
+ BEGIN_INTERFACE(1)
+ MAP_METHOD(Player, Next)
+ MAP_METHOD(Player, Previous)
+ MAP_METHOD(Player, Pause)
+ MAP_METHOD(Player, PlayPause)
+ MAP_METHOD(Player, Stop)
+ MAP_METHOD(Player, Play)
+ MAP_METHOD(Player, Seek)
+ MAP_METHOD(Player, SetPosition)
+ MAP_METHOD(Player, OpenUri)
+ END_INTERFACE
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ Mpris2Provider *provider;
+ ParoleProviderPlugin *plugin = user_data;
+ provider = MPRIS2_PROVIDER (plugin);
+
+ /* org.mpris.MediaPlayer2 */
+ BEGIN_INTERFACE(0)
+ PROPGET(Root, CanQuit)
+ PROPGET(Root, CanRaise)
+ PROPGET(Root, HasTrackList)
+ PROPGET(Root, Identity)
+ PROPGET(Root, DesktopEntry)
+ PROPGET(Root, SupportedUriSchemes)
+ PROPGET(Root, SupportedMimeTypes)
+ END_INTERFACE
+ /* org.mpris.MediaPlayer2.Player */
+ BEGIN_INTERFACE(1)
+ PROPGET(Player, PlaybackStatus)
+ PROPGET(Player, LoopStatus)
+ PROPGET(Player, Rate)
+ PROPGET(Player, Shuffle)
+ PROPGET(Player, Metadata)
+ PROPGET(Player, Volume)
+ PROPGET(Player, Position)
+ PROPGET(Player, MinimumRate)
+ PROPGET(Player, MaximumRate)
+ PROPGET(Player, CanGoNext)
+ PROPGET(Player, CanGoPrevious)
+ PROPGET(Player, CanPlay)
+ PROPGET(Player, CanPause)
+ PROPGET(Player, CanSeek)
+ PROPGET(Player, CanControl)
+ END_INTERFACE
+
+ return NULL;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ ParoleProviderPlugin *plugin)
+{
+ Mpris2Provider *provider;
+ provider = MPRIS2_PROVIDER (plugin);
+
+ /* org.mpris.MediaPlayer2 */
+ BEGIN_INTERFACE(0)
+ /* all properties readonly */
+ END_INTERFACE
+ /* org.mpris.MediaPlayer2.Player */
+ BEGIN_INTERFACE(1)
+ PROPPUT(Player, LoopStatus)
+ PROPPUT(Player, Rate)
+ PROPPUT(Player, Shuffle)
+ PROPPUT(Player, Volume)
+ END_INTERFACE
+
+ return (NULL == *error);
+}
+
+static const
+GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ handle_get_property,
+ handle_set_property
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ Mpris2Provider *provider;
+ guint registration_id;
+ gint i;
+
+ ParoleProviderPlugin *plugin = user_data;
+
+ provider = MPRIS2_PROVIDER (plugin);
+
+ for(i = 0; i < 2; i++)
+ {
+ provider->interface_quarks[i] = g_quark_from_string(provider->introspection_data->interfaces[i]->name);
+ registration_id = g_dbus_connection_register_object (connection,
+ MPRIS_PATH,
+ provider->introspection_data->interfaces[i],
+ &interface_vtable,
+ plugin, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert (registration_id > 0);
+ }
+
+ provider->dbus_connection = connection;
+ g_object_ref(G_OBJECT(provider->dbus_connection));
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_debug("Acquired DBus name %s", name);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+
+{
+ Mpris2Provider *provider;
+ ParoleProviderPlugin *plugin = user_data;
+ provider = MPRIS2_PROVIDER (plugin);
+
+ if (NULL != provider->dbus_connection) {
+ g_object_unref(G_OBJECT(provider->dbus_connection));
+ provider->dbus_connection = NULL;
+ }
+
+ g_warning ("Lost DBus name %s", name);
+}
+
+/*
+ * Plugin interface.
+ */
+
static gboolean mpris2_provider_is_configurable (ParoleProviderPlugin *plugin)
{
return FALSE;
@@ -57,6 +802,21 @@ mpris2_provider_set_player (ParoleProviderPlugin *plugin, ParoleProviderPlayer *
provider = MPRIS2_PROVIDER (plugin);
provider->player = player;
+
+ provider->introspection_data = g_dbus_node_info_new_for_xml (mpris2xml, NULL);
+ g_assert (provider->introspection_data != NULL);
+
+ provider->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ MPRIS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ plugin,
+ NULL);
+
+ g_signal_connect (player, "state_changed",
+ G_CALLBACK (state_changed_cb), plugin);
}
static void
More information about the Xfce4-commits
mailing list