[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