~aw/rhythmbox/swedishradio

« back to all changes in this revision

Viewing changes to plugins/mpris/rb-mpris-plugin.c

  • Committer: Jonathan Matthew
  • Date: 2010-08-13 11:40:27 UTC
  • Revision ID: git-v1:7e201bb65239b5a7313434380833290634f00a05
mpris: rewrite for version 2 of the spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
 
39
39
#include <lib/rb-util.h>
40
40
#include <lib/rb-debug.h>
 
41
#include <lib/eggdesktopfile.h>
41
42
#include <shell/rb-plugin.h>
42
43
#include <shell/rb-shell.h>
43
44
#include <shell/rb-shell-player.h>
 
45
#include <backends/rb-player.h>
44
46
 
45
47
#define RB_TYPE_MPRIS_PLUGIN            (rb_mpris_plugin_get_type ())
46
48
#define RB_MPRIS_PLUGIN(o)              (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_MPRIS_PLUGIN, RBMprisPlugin))
49
51
#define RB_IS_MPRIS_PLUGIN_CLASS(k)     (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_MPRIS_PLUGIN))
50
52
#define RB_MPRIS_PLUGIN_GET_CLASS(o)    (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_MPRIS_PLUGIN, RBMprisPluginClass))
51
53
 
 
54
#define ENTRY_OBJECT_PATH_PREFIX        "/org/mpris/MediaPlayer2/Track/"
 
55
 
52
56
#include "mpris-spec.h"
53
57
 
54
58
typedef struct
55
59
{
56
60
        RBPlugin parent;
57
61
 
 
62
        GDBusConnection *connection;
 
63
        GDBusNodeInfo *node_info;
58
64
        guint name_own_id;
59
 
 
60
 
        GDBusConnection *connection;
61
65
        guint root_id;
62
 
        guint tracklist_id;
63
66
        guint player_id;
64
67
 
65
68
        RBShell *shell;
66
69
        RBShellPlayer *player;
67
70
        RhythmDB *db;
68
 
 
 
71
        GtkAction *next_action;
 
72
        GtkAction *prev_action;
 
73
 
 
74
        GHashTable *player_property_changes;
 
75
        guint player_property_emit_id;
 
76
 
 
77
        gint64 last_elapsed;
69
78
} RBMprisPlugin;
70
79
 
71
80
typedef struct
86
95
{
87
96
}
88
97
 
89
 
/* MPRIS root object */
 
98
/* property change stuff */
 
99
 
 
100
static gboolean
 
101
emit_player_properties_idle (RBMprisPlugin *plugin)
 
102
{
 
103
        GError *error = NULL;
 
104
        GVariantBuilder *properties;
 
105
        GVariant *parameters;
 
106
        const char *invalidated[] = { NULL };
 
107
        gpointer propname, propvalue;
 
108
        GHashTableIter iter;
 
109
 
 
110
        /* build property changes */
 
111
        properties = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
 
112
        g_hash_table_iter_init (&iter, plugin->player_property_changes);
 
113
        while (g_hash_table_iter_next (&iter, &propname, &propvalue)) {
 
114
                g_variant_builder_add (properties,
 
115
                                       "{sv}",
 
116
                                       propname,
 
117
                                       propvalue);
 
118
        }
 
119
        g_hash_table_destroy (plugin->player_property_changes);
 
120
        plugin->player_property_changes = NULL;
 
121
 
 
122
        /* build set of invalidated properties (not supported yet) */
 
123
 
 
124
        parameters = g_variant_new ("(sa{sv}^as)",
 
125
                                    MPRIS_PLAYER_INTERFACE,
 
126
                                    properties,
 
127
                                    invalidated);
 
128
        g_variant_builder_unref (properties);
 
129
        g_dbus_connection_emit_signal (plugin->connection,
 
130
                                       NULL,
 
131
                                       MPRIS_OBJECT_NAME,
 
132
                                       MPRIS_PLAYER_INTERFACE,
 
133
                                       "PropertiesChanged",
 
134
                                       parameters,
 
135
                                       &error);
 
136
        if (error != NULL) {
 
137
                g_warning ("Unable to send MPRIS property changes: %s",
 
138
                           error->message);
 
139
                g_clear_error (&error);
 
140
        }
 
141
 
 
142
        plugin->player_property_emit_id = 0;
 
143
        return FALSE;
 
144
}
 
145
 
 
146
static void
 
147
add_player_property_change (RBMprisPlugin *plugin,
 
148
                            const char *property,
 
149
                            GVariant *value)
 
150
{
 
151
        if (plugin->player_property_changes == NULL) {
 
152
                plugin->player_property_changes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
153
        }
 
154
        g_hash_table_insert (plugin->player_property_changes, g_strdup (property), value);
 
155
 
 
156
        if (plugin->player_property_emit_id == 0) {
 
157
                plugin->player_property_emit_id = g_idle_add ((GSourceFunc)emit_player_properties_idle, plugin);
 
158
        }
 
159
}
 
160
 
 
161
/* MPRIS root interface */
90
162
 
91
163
static void
92
164
handle_root_method_call (GDBusConnection *connection,
98
170
                         GDBusMethodInvocation *invocation,
99
171
                         RBMprisPlugin *plugin)
100
172
{
101
 
        if (g_strcmp0 (object_path, "/") != 0 ||
102
 
            g_strcmp0 (interface_name, mpris_iface_name) != 0) {
103
 
                rb_debug ("?!");
 
173
        if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
 
174
            g_strcmp0 (interface_name, MPRIS_ROOT_INTERFACE) != 0) {
 
175
                g_dbus_method_invocation_return_error (invocation,
 
176
                                                       G_DBUS_ERROR,
 
177
                                                       G_DBUS_ERROR_NOT_SUPPORTED,
 
178
                                                       "Method %s.%s not supported",
 
179
                                                       interface_name,
 
180
                                                       method_name);
104
181
                return;
105
182
        }
106
183
 
107
 
        if (g_strcmp0 (method_name, "Identity") == 0) {
108
 
                g_dbus_method_invocation_return_value (invocation,
109
 
                                                       g_variant_new ("(s)", "Rhythmbox " VERSION));
 
184
        if (g_strcmp0 (method_name, "Raise") == 0) {
 
185
                rb_shell_present (plugin->shell, GDK_CURRENT_TIME, NULL);
 
186
                g_dbus_method_invocation_return_value (invocation, NULL);
110
187
        } else if (g_strcmp0 (method_name, "Quit") == 0) {
111
188
                rb_shell_quit (plugin->shell, NULL);
112
189
                g_dbus_method_invocation_return_value (invocation, NULL);
113
 
        } else if (g_strcmp0 (method_name, "MprisVersion") == 0) {
114
 
                g_dbus_method_invocation_return_value (invocation, g_variant_new ("((qq))", 1, 0));     /* what is the version number, anyway? */
115
 
        }
 
190
        }
 
191
 
 
192
        g_dbus_method_invocation_return_error (invocation,
 
193
                                               G_DBUS_ERROR,
 
194
                                               G_DBUS_ERROR_NOT_SUPPORTED,
 
195
                                               "Method %s.%s not supported",
 
196
                                               interface_name,
 
197
                                               method_name);
 
198
}
 
199
 
 
200
static GVariant *
 
201
get_root_property (GDBusConnection *connection,
 
202
                   const char *sender,
 
203
                   const char *object_path,
 
204
                   const char *interface_name,
 
205
                   const char *property_name,
 
206
                   GError **error,
 
207
                   RBMprisPlugin *plugin)
 
208
{
 
209
        if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
 
210
            g_strcmp0 (interface_name, MPRIS_ROOT_INTERFACE) != 0) {
 
211
                g_set_error (error,
 
212
                             G_DBUS_ERROR,
 
213
                             G_DBUS_ERROR_NOT_SUPPORTED,
 
214
                             "Property %s.%s not supported",
 
215
                             interface_name,
 
216
                             property_name);
 
217
                return NULL;
 
218
        }
 
219
 
 
220
        if (g_strcmp0 (property_name, "CanQuit") == 0) {
 
221
                return g_variant_new_boolean (TRUE);
 
222
        } else if (g_strcmp0 (property_name, "CanRaise") == 0) {
 
223
                return g_variant_new_boolean (TRUE);
 
224
        } else if (g_strcmp0 (property_name, "HasTrackList") == 0) {
 
225
                return g_variant_new_boolean (FALSE);
 
226
        } else if (g_strcmp0 (property_name, "Identity") == 0) {
 
227
                EggDesktopFile *desktop_file;
 
228
                desktop_file = egg_get_desktop_file ();
 
229
                return g_variant_new_string (egg_desktop_file_get_name (desktop_file));
 
230
        } else if (g_strcmp0 (property_name, "DesktopEntry") == 0) {
 
231
                EggDesktopFile *desktop_file;
 
232
                GVariant *v = NULL;
 
233
                char *path;
 
234
 
 
235
                desktop_file = egg_get_desktop_file ();
 
236
                path = g_filename_from_uri (egg_desktop_file_get_source (desktop_file), NULL, error);
 
237
                if (path != NULL) {
 
238
                        v = g_variant_new_string (path);
 
239
                        g_free (path);
 
240
                } else {
 
241
                        g_warning ("Unable to return desktop file path to MPRIS client: %s", (*error)->message);
 
242
                }
 
243
 
 
244
                return v;
 
245
        } else if (g_strcmp0 (property_name, "SupportedUriSchemes") == 0) {
 
246
                /* not planning to support this seriously */
 
247
                const char *fake_supported_schemes[] = {
 
248
                        "file", "http", "cdda", "smb", "sftp", NULL
 
249
                };
 
250
                return g_variant_new_strv (fake_supported_schemes, -1);
 
251
        } else if (g_strcmp0 (property_name, "SupportedMimeTypes") == 0) {
 
252
                /* nor this */
 
253
                const char *fake_supported_mimetypes[] = {
 
254
                        "application/ogg", "audio/x-vorbis+ogg", "audio/x-flac", "audio/mpeg", NULL
 
255
                };
 
256
                return g_variant_new_strv (fake_supported_mimetypes, -1);
 
257
        }
 
258
 
 
259
        g_set_error (error,
 
260
                     G_DBUS_ERROR,
 
261
                     G_DBUS_ERROR_NOT_SUPPORTED,
 
262
                     "Property %s.%s not supported",
 
263
                     interface_name,
 
264
                     property_name);
 
265
        return NULL;
116
266
}
117
267
 
118
268
static const GDBusInterfaceVTable root_vtable =
119
269
{
120
270
        (GDBusInterfaceMethodCallFunc) handle_root_method_call,
121
 
        NULL,
122
 
        NULL
123
 
};
124
 
 
125
 
/* MPRIS tracklist object (not implemented) */
126
 
 
127
 
static void
128
 
handle_tracklist_call (GDBusConnection *connection,
129
 
                       const char *sender,
130
 
                       const char *object_path,
131
 
                       const char *interface_name,
132
 
                       const char *method_name,
133
 
                       GVariant *parameters,
134
 
                       GDBusMethodInvocation *invocation,
135
 
                       RBMprisPlugin *plugin)
136
 
{
137
 
        /* do nothing */
138
 
}
139
 
 
140
 
static const GDBusInterfaceVTable tracklist_vtable =
141
 
{
142
 
        (GDBusInterfaceMethodCallFunc) handle_tracklist_call,
143
 
        NULL,
144
 
        NULL
145
 
};
146
 
 
147
 
 
148
 
/* MPRIS player object */
 
271
        (GDBusInterfaceGetPropertyFunc) get_root_property,
 
272
        NULL
 
273
};
 
274
 
 
275
/* MPRIS player interface */
149
276
 
150
277
static void
151
278
handle_result (GDBusMethodInvocation *invocation, gboolean ret, GError *error)
255
382
                      RhythmDBEntry *entry)
256
383
{
257
384
        GValue *md;
 
385
        char *trackid_str;
 
386
 
 
387
        trackid_str = g_strdup_printf(ENTRY_OBJECT_PATH_PREFIX "%lu",
 
388
                                      rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID));
 
389
        g_variant_builder_add (builder,
 
390
                               "{sv}",
 
391
                               "trackid",
 
392
                               g_variant_new ("s", trackid_str));
 
393
        g_free (trackid_str);
258
394
 
259
395
        add_string_property (builder, entry, RHYTHMDB_PROP_LOCATION, "location");
260
396
        add_string_property_2 (builder, plugin->db, entry, RHYTHMDB_PROP_TITLE, "title", RHYTHMDB_PROP_STREAM_SONG_TITLE);
262
398
        add_string_property_2 (builder, plugin->db, entry, RHYTHMDB_PROP_ALBUM, "album", RHYTHMDB_PROP_STREAM_SONG_ALBUM);
263
399
        add_string_property (builder, entry, RHYTHMDB_PROP_GENRE, "genre");
264
400
        add_string_property (builder, entry, RHYTHMDB_PROP_COMMENT, "comment");
 
401
        add_string_property (builder, entry, RHYTHMDB_PROP_ALBUM_ARTIST, "album-artist");       /* extension */
265
402
 
266
403
        add_string_property (builder, entry, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID, "mb track id");
267
404
        add_string_property (builder, entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID, "mb album id");
270
407
 
271
408
        add_string_property (builder, entry, RHYTHMDB_PROP_ARTIST_SORTNAME, "mb artist sort name");
272
409
        add_string_property (builder, entry, RHYTHMDB_PROP_ALBUM_SORTNAME, "mb album sort name");       /* extension */
 
410
        add_string_property (builder, entry, RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME, "mb album artist sort name"); /* extension */
273
411
 
274
412
        add_ulong_property (builder, entry, RHYTHMDB_PROP_DURATION, "time");
275
413
        add_ulong_property (builder, entry, RHYTHMDB_PROP_BITRATE, "audio-bitrate");
280
418
        add_ulong_string_property (builder, entry, RHYTHMDB_PROP_DISC_NUMBER, "discnumber");    /* extension */
281
419
 
282
420
        add_double_property (builder, entry, RHYTHMDB_PROP_RATING, "rating");
 
421
        add_double_property (builder, entry, RHYTHMDB_PROP_BPM, "bpm");                         /* extension */
283
422
 
284
423
        md = rhythmdb_entry_request_extra_metadata (plugin->db, entry, RHYTHMDB_PROP_COVER_ART_URI);
285
424
        if (md != NULL) {
294
433
        }
295
434
}
296
435
 
297
 
static GVariant *
298
 
get_player_state (RBMprisPlugin *plugin, GError **error)
299
 
{
300
 
        RhythmDBEntry *entry;
301
 
        int playback_state;
302
 
        gboolean random;
303
 
        gboolean repeat;
304
 
        gboolean loop;
305
 
 
306
 
        entry = rb_shell_player_get_playing_entry (plugin->player);
307
 
        if (entry != NULL) {
308
 
                gboolean playing;
309
 
 
310
 
                rhythmdb_entry_unref (entry);
311
 
                playing = FALSE;
312
 
                if (rb_shell_player_get_playing (plugin->player, &playing, error) == FALSE) {
313
 
                        return NULL;
314
 
                }
315
 
 
316
 
                if (playing) {
317
 
                        playback_state = 0;
318
 
                } else {
319
 
                        playback_state = 1;
320
 
                }
321
 
        } else {
322
 
                playback_state = 2;
323
 
        }
324
 
 
325
 
        random = FALSE;
326
 
        loop = FALSE;
327
 
        rb_shell_player_get_playback_state (plugin->player, &random, &loop);
328
 
 
329
 
        /* repeat is not supported */
330
 
        repeat = FALSE;
331
 
 
332
 
        return g_variant_new ("((iiii))", playback_state, random, repeat, loop);
333
 
}
334
 
 
335
436
static void
336
437
handle_player_method_call (GDBusConnection *connection,
337
438
                           const char *sender,
345
446
{
346
447
        GError *error = NULL;
347
448
        gboolean ret;
348
 
        if (g_strcmp0 (object_path, "/Player") != 0 ||
349
 
            g_strcmp0 (interface_name, mpris_iface_name) != 0) {
350
 
                rb_debug ("?!");
 
449
        if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
 
450
            g_strcmp0 (interface_name, MPRIS_PLAYER_INTERFACE) != 0) {
 
451
                g_dbus_method_invocation_return_error (invocation,
 
452
                                                       G_DBUS_ERROR,
 
453
                                                       G_DBUS_ERROR_NOT_SUPPORTED,
 
454
                                                       "Method %s.%s not supported",
 
455
                                                       interface_name,
 
456
                                                       method_name);
351
457
                return;
352
458
        }
353
459
 
354
460
        if (g_strcmp0 (method_name, "Next") == 0) {
355
461
                ret = rb_shell_player_do_next (plugin->player, &error);
356
462
                handle_result (invocation, ret, error);
357
 
        } else if (g_strcmp0 (method_name, "Prev") == 0) {
 
463
        } else if (g_strcmp0 (method_name, "Previous") == 0) {
358
464
                ret = rb_shell_player_do_previous (plugin->player, &error);
359
465
                handle_result (invocation, ret, error);
360
 
        } else if ((g_strcmp0 (method_name, "Pause") == 0)
361
 
                  || (g_strcmp0 (method_name, "PlayPause") == 0)) {
 
466
        } else if (g_strcmp0 (method_name, "Pause") == 0) {
 
467
                ret = rb_shell_player_pause (plugin->player, &error);
 
468
                handle_result (invocation, ret, error);
 
469
        } else if (g_strcmp0 (method_name, "PlayPause") == 0) {
362
470
                ret = rb_shell_player_playpause (plugin->player, TRUE, &error);
363
471
                handle_result (invocation, ret, error);
364
472
        } else if (g_strcmp0 (method_name, "Stop") == 0) {
365
473
                rb_shell_player_stop (plugin->player);
366
474
                handle_result (invocation, TRUE, NULL);
367
475
        } else if (g_strcmp0 (method_name, "Play") == 0) {
 
476
                ret = rb_shell_player_play (plugin->player, &error);
 
477
                handle_result (invocation, ret, error);
 
478
        } else if (g_strcmp0 (method_name, "Seek") == 0) {
 
479
                gint64 offset;
 
480
                g_variant_get (parameters, "(x)", &offset);
 
481
                rb_shell_player_seek (plugin->player, offset / G_USEC_PER_SEC);
 
482
                g_dbus_method_invocation_return_value (invocation, NULL);
 
483
        } else if (g_strcmp0 (method_name, "SetPositionSet") == 0) {
 
484
                RhythmDBEntry *playing_entry;
 
485
                RhythmDBEntry *client_entry;
 
486
                gint64 position;
 
487
                const char *client_entry_path;
 
488
 
 
489
                playing_entry = rb_shell_player_get_playing_entry (plugin->player);
 
490
                if (playing_entry == NULL) {
 
491
                        /* not playing, so we can't seek */
 
492
                        g_dbus_method_invocation_return_value (invocation, NULL);
 
493
                        return;
 
494
                }
 
495
 
 
496
                g_variant_get (parameters, "(&ox)", &client_entry_path, &position);
 
497
 
 
498
                if (g_str_has_prefix (client_entry_path, ENTRY_OBJECT_PATH_PREFIX) == FALSE) {
 
499
                        /* this can't possibly be the current playing track, so ignore it */
 
500
                        g_dbus_method_invocation_return_value (invocation, NULL);
 
501
                        rhythmdb_entry_unref (playing_entry);
 
502
                        return;
 
503
                }
 
504
 
 
505
                client_entry_path += strlen (ENTRY_OBJECT_PATH_PREFIX);
 
506
                client_entry = rhythmdb_entry_lookup_from_string (plugin->db, client_entry_path, TRUE);
 
507
                if (client_entry == NULL) {
 
508
                        /* ignore it */
 
509
                        g_dbus_method_invocation_return_value (invocation, NULL);
 
510
                        rhythmdb_entry_unref (playing_entry);
 
511
                        return;
 
512
                }
 
513
 
 
514
                if (playing_entry != client_entry) {
 
515
                        /* client got the wrong entry, ignore it */
 
516
                        g_dbus_method_invocation_return_value (invocation, NULL);
 
517
                        rhythmdb_entry_unref (playing_entry);
 
518
                        rhythmdb_entry_unref (client_entry);
 
519
                        return;
 
520
                }
 
521
                rhythmdb_entry_unref (playing_entry);
 
522
                rhythmdb_entry_unref (client_entry);
 
523
 
 
524
                ret = rb_shell_player_set_playing_time (plugin->player, position / G_USEC_PER_SEC, &error);
 
525
                handle_result (invocation, ret, error);
 
526
        } else if (g_strcmp0 (method_name, "OpenUri") == 0) {
 
527
                const char *uri;
 
528
                g_variant_get (parameters, "(&s)", &uri);
 
529
                ret = rb_shell_load_uri (plugin->shell, uri, TRUE, &error);
 
530
                handle_result (invocation, ret, error);
 
531
        }
 
532
 
 
533
        g_dbus_method_invocation_return_error (invocation,
 
534
                                               G_DBUS_ERROR,
 
535
                                               G_DBUS_ERROR_NOT_SUPPORTED,
 
536
                                               "Method %s.%s not supported",
 
537
                                               interface_name,
 
538
                                               method_name);
 
539
}
 
540
 
 
541
static GVariant *
 
542
get_playback_status (RBMprisPlugin *plugin)
 
543
{
 
544
        RhythmDBEntry *entry;
 
545
 
 
546
        entry = rb_shell_player_get_playing_entry (plugin->player);
 
547
        if (entry == NULL) {
 
548
                return g_variant_new_string ("Stopped");
 
549
        } else {
 
550
                GVariant *v;
368
551
                gboolean playing;
369
 
                g_object_get (plugin->player, "playing", &playing, NULL);
370
 
                if (playing) {
371
 
                        ret = rb_shell_player_set_playing_time (plugin->player, 0, &error);
372
 
                } else {
373
 
                        ret = rb_shell_player_playpause (plugin->player, TRUE, &error);
374
 
                }
375
 
                handle_result (invocation, ret, error);
376
 
        } else if (g_strcmp0 (method_name, "Repeat") == 0) {
377
 
                /* not actually supported */
378
 
        } else if (g_strcmp0 (method_name, "GetStatus") == 0) {
379
 
                GVariant *state;
380
 
 
381
 
                state = get_player_state (plugin, &error);
382
 
                if (state == NULL) {
383
 
                        handle_result (invocation, FALSE, error);
384
 
                } else {
385
 
                        g_dbus_method_invocation_return_value (invocation, state);
386
 
                }
387
 
 
388
 
        } else if (g_strcmp0 (method_name, "GetCaps") == 0) {
389
 
                /* values here are:
390
 
                 * CAN_GO_NEXT: 1
391
 
                 * CAN_GO_PREV: 2
392
 
                 * CAN_PAUSE: 4
393
 
                 * CAN_PLAY: 8
394
 
                 * CAN_SEEK: 16
395
 
                 * CAN_PROVIDE_METADATA: 32
396
 
                 * CAN_HAS_TRACKLIST: 64
397
 
                 */
398
 
                g_dbus_method_invocation_return_value (invocation,
399
 
                                                       g_variant_new ("i", 63));
400
 
        } else if (g_strcmp0 (method_name, "GetMetadata") == 0) {
 
552
                if (rb_shell_player_get_playing (plugin->player, &playing, NULL)) {
 
553
                        if (playing) {
 
554
                                v = g_variant_new_string ("Playing");
 
555
                        } else {
 
556
                                v = g_variant_new_string ("Paused");
 
557
                        }
 
558
                } else {
 
559
                        v = NULL;
 
560
                }
 
561
                rhythmdb_entry_unref (entry);
 
562
                return v;
 
563
        }
 
564
}
 
565
 
 
566
static GVariant *
 
567
get_loop_status (RBMprisPlugin *plugin)
 
568
{
 
569
        gboolean loop = FALSE;
 
570
        rb_shell_player_get_playback_state (plugin->player, NULL, &loop);
 
571
        if (loop) {
 
572
                return g_variant_new_string ("Playlist");
 
573
        } else {
 
574
                return g_variant_new_string ("None");
 
575
        }
 
576
}
 
577
 
 
578
static GVariant *
 
579
get_shuffle (RBMprisPlugin *plugin)
 
580
{
 
581
        gboolean random = FALSE;
 
582
 
 
583
        rb_shell_player_get_playback_state (plugin->player, &random, NULL);
 
584
        return g_variant_new_boolean (random);
 
585
}
 
586
 
 
587
static GVariant *
 
588
get_volume (RBMprisPlugin *plugin)
 
589
{
 
590
        gdouble vol;
 
591
        if (rb_shell_player_get_volume (plugin->player, &vol, NULL)) {
 
592
                return g_variant_new_double (vol);
 
593
        } else {
 
594
                return NULL;
 
595
        }
 
596
}
 
597
 
 
598
static GVariant *
 
599
get_can_pause (RBMprisPlugin *plugin)
 
600
{
 
601
        RBSource *source;
 
602
        source = rb_shell_player_get_playing_source (plugin->player);
 
603
        if (source != NULL) {
 
604
                return g_variant_new_boolean (rb_source_can_pause (source));
 
605
        } else {
 
606
                return g_variant_new_boolean (TRUE);
 
607
        }
 
608
}
 
609
 
 
610
static GVariant *
 
611
get_can_seek (RBMprisPlugin *plugin)
 
612
{
 
613
        RBPlayer *player;
 
614
        GVariant *v;
 
615
 
 
616
        g_object_get (plugin->player, "player", &player, NULL);
 
617
        if (player != NULL) {
 
618
                v = g_variant_new_boolean (rb_player_seekable (player));
 
619
                g_object_unref (player);
 
620
        } else {
 
621
                v = g_variant_new_boolean (FALSE);
 
622
        }
 
623
        return v;
 
624
}
 
625
 
 
626
static GVariant *
 
627
get_player_property (GDBusConnection *connection,
 
628
                     const char *sender,
 
629
                     const char *object_path,
 
630
                     const char *interface_name,
 
631
                     const char *property_name,
 
632
                     GError **error,
 
633
                     RBMprisPlugin *plugin)
 
634
{
 
635
        gboolean ret;
 
636
 
 
637
        if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
 
638
            g_strcmp0 (interface_name, MPRIS_PLAYER_INTERFACE) != 0) {
 
639
                g_set_error (error,
 
640
                             G_DBUS_ERROR,
 
641
                             G_DBUS_ERROR_NOT_SUPPORTED,
 
642
                             "Property %s.%s not supported",
 
643
                             interface_name,
 
644
                             property_name);
 
645
                return NULL;
 
646
        }
 
647
 
 
648
        if (g_strcmp0 (property_name, "PlaybackStatus") == 0) {
 
649
                return get_playback_status (plugin);
 
650
        } else if (g_strcmp0 (property_name, "LoopStatus") == 0) {
 
651
                return get_loop_status (plugin);
 
652
        } else if (g_strcmp0 (property_name, "Rate") == 0) {
 
653
                return g_variant_new_double (1.0);
 
654
        } else if (g_strcmp0 (property_name, "Shuffle") == 0) {
 
655
                return get_shuffle (plugin);
 
656
        } else if (g_strcmp0 (property_name, "Metadata") == 0) {
401
657
                RhythmDBEntry *entry;
402
658
                GVariantBuilder *builder;
403
 
 
404
 
                builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
405
 
 
 
659
                GVariant *v;
 
660
 
 
661
                builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
406
662
                entry = rb_shell_player_get_playing_entry (plugin->player);
407
663
                if (entry != NULL) {
408
664
                        build_track_metadata (plugin, builder, entry);
409
 
                } else {
410
 
                        g_variant_builder_add (builder,
411
 
                                               "{sv}",
412
 
                                               "location",
413
 
                                               g_variant_new ("s", ""));
414
 
                }
415
 
 
416
 
                g_dbus_method_invocation_return_value (invocation,
417
 
                                                       g_variant_new ("(a{sv})", builder));
418
 
        } else if (g_strcmp0 (method_name, "VolumeGet") == 0) {
419
 
                gdouble v;
420
 
                ret = rb_shell_player_get_volume (plugin->player, &v, &error);
421
 
                if (ret == FALSE) {
422
 
                        handle_result (invocation, ret, error);
423
 
                } else {
424
 
                        int iv;
425
 
                        iv = (int)(v * 100.0);
426
 
                        g_dbus_method_invocation_return_value (invocation,
427
 
                                                               g_variant_new ("(i)", iv));
428
 
                }
429
 
        } else if (g_strcmp0 (method_name, "VolumeSet") == 0) {
430
 
                int iv;
431
 
                gdouble v;
432
 
                g_variant_get (parameters, "(i)", &iv);
433
 
                v = ((gdouble)iv / 100.0);
434
 
                ret = rb_shell_player_set_volume (plugin->player, v, &error);
435
 
                handle_result (invocation, ret, error);
436
 
 
437
 
        } else if (g_strcmp0 (method_name, "PositionGet") == 0) {
438
 
                guint t;
439
 
                ret = rb_shell_player_get_playing_time (plugin->player, &t, &error);
440
 
                if (ret == FALSE) {
441
 
                        handle_result (invocation, ret, error);
442
 
                } else {
443
 
                        g_dbus_method_invocation_return_value (invocation,
444
 
                                                               g_variant_new ("(i)", t * 1000));
445
 
                }
446
 
        } else if (g_strcmp0 (method_name, "PositionSet") == 0) {
447
 
                guint t;
448
 
                g_variant_get (parameters, "(i)", &t);
449
 
                ret = rb_shell_player_set_playing_time (plugin->player, t, &error);
450
 
                handle_result (invocation, ret, error);
451
 
        }
 
665
                        rhythmdb_entry_unref (entry);
 
666
                }
 
667
 
 
668
                v = g_variant_builder_end (builder);
 
669
                g_variant_builder_unref (builder);
 
670
                return v;
 
671
        } else if (g_strcmp0 (property_name, "Volume") == 0) {
 
672
                return get_volume (plugin);
 
673
        } else if (g_strcmp0 (property_name, "Position") == 0) {
 
674
                guint t;
 
675
                ret = rb_shell_player_get_playing_time (plugin->player, &t, error);
 
676
                if (ret) {
 
677
                        return g_variant_new_int64 (t * G_USEC_PER_SEC);
 
678
                } else {
 
679
                        return NULL;
 
680
                }
 
681
        } else if (g_strcmp0 (property_name, "MinimumRate") == 0) {
 
682
                return g_variant_new_double (1.0);
 
683
        } else if (g_strcmp0 (property_name, "MaximumRate") == 0) {
 
684
                return g_variant_new_double (1.0);
 
685
        } else if (g_strcmp0 (property_name, "CanGoNext") == 0) {
 
686
                return g_variant_new_boolean (gtk_action_get_sensitive (plugin->next_action));
 
687
        } else if (g_strcmp0 (property_name, "CanGoPrevious") == 0) {
 
688
                return g_variant_new_boolean (gtk_action_get_sensitive (plugin->prev_action));
 
689
        } else if (g_strcmp0 (property_name, "CanPlay") == 0) {
 
690
                /* uh.. under what conditions can we not play?  nothing in the source? */
 
691
                return g_variant_new_boolean (TRUE);
 
692
        } else if (g_strcmp0 (property_name, "CanPause") == 0) {
 
693
                return get_can_pause (plugin);
 
694
        } else if (g_strcmp0 (property_name, "CanSeek") == 0) {
 
695
                return get_can_seek (plugin);
 
696
        } else if (g_strcmp0 (property_name, "CanControl") == 0) {
 
697
                return g_variant_new_boolean (TRUE);
 
698
        }
 
699
 
 
700
        g_set_error (error,
 
701
                     G_DBUS_ERROR,
 
702
                     G_DBUS_ERROR_NOT_SUPPORTED,
 
703
                     "Property %s.%s not supported",
 
704
                     interface_name,
 
705
                     property_name);
 
706
        return NULL;
 
707
}
 
708
 
 
709
static gboolean
 
710
set_player_property (GDBusConnection *connection,
 
711
                     const char *sender,
 
712
                     const char *object_path,
 
713
                     const char *interface_name,
 
714
                     const char *property_name,
 
715
                     GVariant *value,
 
716
                     GError **error,
 
717
                     RBMprisPlugin *plugin)
 
718
{
 
719
        if (g_strcmp0 (object_path, MPRIS_OBJECT_NAME) != 0 ||
 
720
            g_strcmp0 (interface_name, MPRIS_PLAYER_INTERFACE) != 0) {
 
721
                g_set_error (error,
 
722
                             G_DBUS_ERROR,
 
723
                             G_DBUS_ERROR_NOT_SUPPORTED,
 
724
                             "%s:%s not supported",
 
725
                             object_path,
 
726
                             interface_name);
 
727
                return FALSE;
 
728
        }
 
729
 
 
730
        if (g_strcmp0 (property_name, "LoopStatus") == 0) {
 
731
                gboolean shuffle;
 
732
                gboolean repeat;
 
733
                const char *status;
 
734
 
 
735
                rb_shell_player_get_playback_state (plugin->player, &shuffle, &repeat);
 
736
 
 
737
                status = g_variant_get_string (value, NULL);
 
738
                if (g_strcmp0 (status, "None") == 0) {
 
739
                        repeat = FALSE;
 
740
                } else if (g_strcmp0 (status, "Playlist") == 0) {
 
741
                        repeat = TRUE;
 
742
                } else {
 
743
                        repeat = FALSE;
 
744
                }
 
745
                rb_shell_player_set_playback_state (plugin->player, shuffle, repeat);
 
746
                return TRUE;
 
747
        } else if (g_strcmp0 (property_name, "Rate") == 0) {
 
748
                /* not supported */
 
749
                g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Can't modify playback rate");
 
750
                return FALSE;
 
751
        } else if (g_strcmp0 (property_name, "Shuffle") == 0) {
 
752
                gboolean shuffle;
 
753
                gboolean repeat;
 
754
 
 
755
                rb_shell_player_get_playback_state (plugin->player, &shuffle, &repeat);
 
756
                shuffle = g_variant_get_boolean (value);
 
757
                rb_shell_player_set_playback_state (plugin->player, shuffle, repeat);
 
758
                return TRUE;
 
759
        } else if (g_strcmp0 (property_name, "Volume") == 0) {
 
760
                rb_shell_player_set_volume (plugin->player, g_variant_get_double (value), error);
 
761
                return TRUE;
 
762
        }
 
763
 
 
764
        g_set_error (error,
 
765
                     G_DBUS_ERROR,
 
766
                     G_DBUS_ERROR_NOT_SUPPORTED,
 
767
                     "Property %s.%s not supported",
 
768
                     interface_name,
 
769
                     property_name);
 
770
        return FALSE;
452
771
}
453
772
 
454
773
static const GDBusInterfaceVTable player_vtable =
455
774
{
456
775
        (GDBusInterfaceMethodCallFunc) handle_player_method_call,
457
 
        NULL,
458
 
        NULL
 
776
        (GDBusInterfaceGetPropertyFunc) get_player_property,
 
777
        (GDBusInterfaceSetPropertyFunc) set_player_property,
459
778
};
460
779
 
461
 
/* MPRIS signals */
462
 
 
463
 
static void
464
 
emit_status_change (RBMprisPlugin *plugin)
465
 
{
466
 
        GError *error = NULL;
467
 
        GVariant *state;
468
 
        state = get_player_state (plugin, &error);
469
 
        if (state == NULL) {
470
 
                g_warning ("Unable to emit MPRIS StatusChange signal: %s", error->message);
471
 
                g_error_free (error);
472
 
                return;
473
 
        }
474
 
 
475
 
        g_dbus_connection_emit_signal (plugin->connection,
476
 
                                       NULL,
477
 
                                       "/Player",
478
 
                                       mpris_iface_name,
479
 
                                       "StatusChange",
480
 
                                       state,
481
 
                                       &error);
482
 
        if (error != NULL) {
483
 
                g_warning ("Unable to emit MPRIS StatusChange signal: %s", error->message);
484
 
                g_error_free (error);
485
 
        }
486
 
}
487
 
 
488
780
static void
489
781
play_order_changed_cb (GObject *object, GParamSpec *pspec, RBMprisPlugin *plugin)
490
782
{
491
 
        emit_status_change (plugin);
 
783
        rb_debug ("emitting LoopStatus and Shuffle change");
 
784
        add_player_property_change (plugin, "LoopStatus", get_loop_status (plugin));
 
785
        add_player_property_change (plugin, "Shuffle", get_shuffle (plugin));
 
786
}
 
787
 
 
788
static void
 
789
volume_changed_cb (GObject *object, GParamSpec *pspec, RBMprisPlugin *plugin)
 
790
{
 
791
        rb_debug ("emitting Volume change");
 
792
        add_player_property_change (plugin, "Volume", get_volume (plugin));
492
793
}
493
794
 
494
795
static void
495
796
playing_changed_cb (RBShellPlayer *player, gboolean playing, RBMprisPlugin *plugin)
496
797
{
497
 
        emit_status_change (plugin);
 
798
        rb_debug ("emitting PlaybackStatus change");
 
799
        add_player_property_change (plugin, "PlaybackStatus", get_playback_status (plugin));
498
800
}
499
801
 
500
802
static void
501
 
emit_track_change (RBMprisPlugin *plugin, RhythmDBEntry *entry)
 
803
metadata_changed (RBMprisPlugin *plugin, RhythmDBEntry *entry)
502
804
{
503
 
        GError *error = NULL;
504
805
        GVariantBuilder *builder;
505
 
        if (entry == NULL) {
506
 
                return;
507
 
        }
508
 
 
509
 
        builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
510
 
        build_track_metadata (plugin, builder, entry);
511
 
 
512
 
        g_dbus_connection_emit_signal (plugin->connection,
513
 
                                       NULL,
514
 
                                       "/Player",
515
 
                                       mpris_iface_name,
516
 
                                       "TrackChange",
517
 
                                       g_variant_new ("(a{sv})", builder),
518
 
                                       &error);
519
 
        if (error != NULL) {
520
 
                g_warning ("Unable to emit MPRIS TrackChange signal: %s", error->message);
521
 
                g_error_free (error);
522
 
        }
 
806
 
 
807
        builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
 
808
        if (entry != NULL) {
 
809
                build_track_metadata (plugin, builder, entry);
 
810
        }
 
811
        add_player_property_change (plugin, "Metadata", g_variant_builder_end (builder));
 
812
        g_variant_builder_unref (builder);
523
813
}
524
814
 
525
815
static void
526
816
playing_entry_changed_cb (RBShellPlayer *player, RhythmDBEntry *entry, RBMprisPlugin *plugin)
527
817
{
528
 
        rb_debug ("emitting track change due to playing entry change");
529
 
        emit_track_change (plugin, entry);
 
818
        rb_debug ("emitting Metadata and CanSeek changed");
 
819
        plugin->last_elapsed = 0;
 
820
        metadata_changed (plugin, entry);
 
821
        add_player_property_change (plugin, "CanSeek", get_can_seek (plugin));
530
822
}
531
823
 
532
824
static void
533
825
entry_extra_metadata_notify_cb (RhythmDB *db, RhythmDBEntry *entry, const char *field, GValue *metadata, RBMprisPlugin *plugin)
534
826
{
535
 
        if (entry == rb_shell_player_get_playing_entry (plugin->player)) {
536
 
                rb_debug ("emitting track change due to extra metadata field %s", field);
537
 
                emit_track_change (plugin, entry);
538
 
        }
539
 
}
 
827
        RhythmDBEntry *playing_entry = rb_shell_player_get_playing_entry (plugin->player);
 
828
        if (entry == playing_entry) {
 
829
                rb_debug ("emitting Metadata change due to extra metadata field %s", field);
 
830
                metadata_changed (plugin, entry);
 
831
        }
 
832
        if (playing_entry != NULL) {
 
833
                rhythmdb_entry_unref (playing_entry);
 
834
        }
 
835
}
 
836
 
 
837
static void
 
838
entry_changed_cb (RhythmDB *db, RhythmDBEntry *entry, GValueArray *changes, RBMprisPlugin *plugin)
 
839
{
 
840
        RhythmDBEntry *playing_entry = rb_shell_player_get_playing_entry (plugin->player);
 
841
        if (playing_entry == NULL) {
 
842
                return;
 
843
        }
 
844
        if (playing_entry == entry) {
 
845
                int i;
 
846
                gboolean emit = FALSE;
 
847
 
 
848
                /* make sure there's an interesting property change in there */
 
849
                for (i = 0; i < changes->n_values; i++) {
 
850
                        RhythmDBEntryChange *change = g_value_get_boxed (g_value_array_get_nth (changes, i));
 
851
                        switch (change->prop) {
 
852
                                /* probably not complete */
 
853
                                case RHYTHMDB_PROP_MOUNTPOINT:
 
854
                                case RHYTHMDB_PROP_MTIME:
 
855
                                case RHYTHMDB_PROP_FIRST_SEEN:
 
856
                                case RHYTHMDB_PROP_LAST_SEEN:
 
857
                                case RHYTHMDB_PROP_LAST_PLAYED:
 
858
                                case RHYTHMDB_PROP_MIMETYPE:
 
859
                                case RHYTHMDB_PROP_PLAYBACK_ERROR:
 
860
                                        break;
 
861
 
 
862
                                default:
 
863
                                        emit = TRUE;
 
864
                                        break;
 
865
                        }
 
866
                }
 
867
 
 
868
                if (emit) {
 
869
                        rb_debug ("emitting Metadata change due to property changes");
 
870
                        metadata_changed (plugin, playing_entry);
 
871
                }
 
872
        }
 
873
        rhythmdb_entry_unref (playing_entry);
 
874
}
 
875
 
 
876
static void
 
877
playing_source_changed_cb (RBShellPlayer *player,
 
878
                           RBSource *source,
 
879
                           RBMprisPlugin *plugin)
 
880
{
 
881
        rb_debug ("emitting CanPause change");
 
882
        add_player_property_change (plugin, "CanPause", get_can_pause (plugin));
 
883
}
 
884
 
 
885
static void
 
886
next_action_sensitive_cb (GObject *object, GParamSpec *pspec, RBMprisPlugin *plugin)
 
887
{
 
888
        GVariant *v;
 
889
        rb_debug ("emitting CanGoNext change");
 
890
        v = g_variant_new_boolean (gtk_action_get_sensitive (plugin->next_action));
 
891
        add_player_property_change (plugin, "CanGoNext", v);
 
892
}
 
893
 
 
894
static void
 
895
prev_action_sensitive_cb (GObject *object, GParamSpec *pspec, RBMprisPlugin *plugin)
 
896
{
 
897
        GVariant *v;
 
898
        rb_debug ("emitting CanGoPrevious change");
 
899
        v = g_variant_new_boolean (gtk_action_get_sensitive (plugin->prev_action));
 
900
        add_player_property_change (plugin, "CanGoPrevious", v);
 
901
}
 
902
 
 
903
static void
 
904
elapsed_nano_changed_cb (RBShellPlayer *player, gint64 elapsed, RBMprisPlugin *plugin)
 
905
{
 
906
        GError *error = NULL;
 
907
 
 
908
        /* interpret any change in the elapsed time other than an
 
909
         * increase of less than one second as a seek.  this includes
 
910
         * the seek back that we do after pausing (with crossfading),
 
911
         * which we intentionally report as a seek to help clients get
 
912
         * their time displays right.
 
913
         */
 
914
        if (elapsed >= plugin->last_elapsed &&
 
915
            (elapsed - plugin->last_elapsed < (G_USEC_PER_SEC * 1000))) {
 
916
                plugin->last_elapsed = elapsed;
 
917
                return;
 
918
        }
 
919
 
 
920
        rb_debug ("emitting Seeked; new time %" G_GINT64_FORMAT, elapsed/1000);
 
921
        g_dbus_connection_emit_signal (plugin->connection,
 
922
                                       NULL,
 
923
                                       MPRIS_OBJECT_NAME,
 
924
                                       MPRIS_PLAYER_INTERFACE,
 
925
                                       "Seeked",
 
926
                                       g_variant_new ("(x)", elapsed / 1000),
 
927
                                       &error);
 
928
        if (error != NULL) {
 
929
                g_warning ("Unable to set MPRIS Seeked signal: %s", error->message);
 
930
                g_clear_error (&error);
 
931
        }
 
932
        plugin->last_elapsed = elapsed;
 
933
}
 
934
 
 
935
 
540
936
 
541
937
static void
542
938
name_acquired_cb (GDBusConnection *connection, const char *name, RBMprisPlugin *plugin)
543
939
{
544
940
        GError *error = NULL;
545
 
        GDBusNodeInfo *nodeinfo;
546
941
        GDBusInterfaceInfo *ifaceinfo;
 
942
        GtkUIManager *ui_manager;
547
943
 
548
944
        plugin->connection = g_object_ref (connection);
549
945
 
550
 
        /* register root object */
551
 
        nodeinfo = g_dbus_node_info_new_for_xml (mpris_root_spec, &error);
 
946
        /* parse introspection data */
 
947
        plugin->node_info = g_dbus_node_info_new_for_xml (mpris_introspection_xml, &error);
552
948
        if (error != NULL) {
553
 
                g_warning ("Unable to read MPRIS root object specificiation: %s", error->message);
554
 
                g_assert_not_reached ();
 
949
                g_error ("Unable to read MPRIS root object specificiation: %s", error->message);
555
950
                return;
556
951
        }
557
 
        ifaceinfo = g_dbus_node_info_lookup_interface (nodeinfo, mpris_iface_name);
558
952
 
 
953
        /* register root interface */
 
954
        ifaceinfo = g_dbus_node_info_lookup_interface (plugin->node_info, MPRIS_ROOT_INTERFACE);
559
955
        plugin->root_id = g_dbus_connection_register_object (plugin->connection,
560
 
                                                             "/",
 
956
                                                             MPRIS_OBJECT_NAME,
561
957
                                                             ifaceinfo,
562
958
                                                             &root_vtable,
563
959
                                                             plugin,
564
960
                                                             NULL,
565
961
                                                             &error);
566
962
        if (error != NULL) {
567
 
                g_warning ("unable to register MPRIS root object: %s", error->message);
568
 
                g_error_free (error);
569
 
        }
570
 
 
571
 
        /* register fake tracklist object */
572
 
        nodeinfo = g_dbus_node_info_new_for_xml (mpris_tracklist_spec, &error);
573
 
        if (error != NULL) {
574
 
                g_warning ("Unable to read MPRIS tracklist object specificiation: %s", error->message);
575
 
                g_assert_not_reached ();
576
 
                return;
577
 
        }
578
 
        ifaceinfo = g_dbus_node_info_lookup_interface (nodeinfo, mpris_iface_name);
579
 
 
580
 
        plugin->tracklist_id = g_dbus_connection_register_object (plugin->connection,
581
 
                                                                  "/TrackList",
582
 
                                                                  ifaceinfo,
583
 
                                                                  &tracklist_vtable,
584
 
                                                                  plugin,
585
 
                                                                  NULL,
586
 
                                                                  &error);
587
 
        if (error != NULL) {
588
 
                g_warning ("unable to register MPRIS tracklist object: %s", error->message);
589
 
                g_error_free (error);
590
 
        }
591
 
 
592
 
        /* register player object */
593
 
        nodeinfo = g_dbus_node_info_new_for_xml (mpris_player_spec, &error);
594
 
        if (error != NULL) {
595
 
                g_warning ("Unable to read MPRIS player object specificiation: %s", error->message);
596
 
                g_assert_not_reached ();
597
 
                return;
598
 
        }
599
 
        ifaceinfo = g_dbus_node_info_lookup_interface (nodeinfo, mpris_iface_name);
 
963
                g_warning ("unable to register MPRIS root interface: %s", error->message);
 
964
                g_error_free (error);
 
965
        }
 
966
 
 
967
        /* register player interface */
 
968
        ifaceinfo = g_dbus_node_info_lookup_interface (plugin->node_info, MPRIS_PLAYER_INTERFACE);
600
969
        plugin->player_id = g_dbus_connection_register_object (plugin->connection,
601
 
                                                               "/Player",
 
970
                                                               MPRIS_OBJECT_NAME,
602
971
                                                               ifaceinfo,
603
972
                                                               &player_vtable,
604
973
                                                               plugin,
605
974
                                                               NULL,
606
975
                                                               &error);
607
976
        if (error != NULL) {
608
 
                g_warning ("Unable to register MPRIS player object: %s", error->message);
 
977
                g_warning ("Unable to register MPRIS player interface: %s", error->message);
609
978
                g_error_free (error);
610
979
        }
611
980
 
615
984
                                 G_CALLBACK (play_order_changed_cb),
616
985
                                 plugin, 0);
617
986
        g_signal_connect_object (plugin->player,
 
987
                                 "notify::volume",
 
988
                                 G_CALLBACK (volume_changed_cb),
 
989
                                 plugin, 0);
 
990
        g_signal_connect_object (plugin->player,
618
991
                                 "playing-changed",
619
992
                                 G_CALLBACK (playing_changed_cb),
620
993
                                 plugin, 0);
626
999
                                 "entry-extra-metadata-notify",
627
1000
                                 G_CALLBACK (entry_extra_metadata_notify_cb),
628
1001
                                 plugin, 0);
 
1002
        g_signal_connect_object (plugin->db,
 
1003
                                 "entry-changed",
 
1004
                                 G_CALLBACK (entry_changed_cb),
 
1005
                                 plugin, 0);
 
1006
        g_signal_connect_object (plugin->player,
 
1007
                                 "playing-source-changed",
 
1008
                                 G_CALLBACK (playing_source_changed_cb),
 
1009
                                 plugin, 0);
 
1010
        g_signal_connect_object (plugin->player,
 
1011
                                 "elapsed-nano-changed",
 
1012
                                 G_CALLBACK (elapsed_nano_changed_cb),
 
1013
                                 plugin, 0);
 
1014
 
 
1015
        /*
 
1016
         * This is a pretty awful hack.  The shell player should expose this
 
1017
         * information as properties, and we should bind those to the actions
 
1018
         * elsewhere.
 
1019
         */
 
1020
 
 
1021
        g_object_get (plugin->shell, "ui-manager", &ui_manager, NULL);
 
1022
        plugin->next_action = gtk_ui_manager_get_action (ui_manager, "/MenuBar/ControlMenu/ControlNextMenu");
 
1023
        plugin->prev_action = gtk_ui_manager_get_action (ui_manager, "/MenuBar/ControlMenu/ControlPreviousMenu");
 
1024
        g_object_unref (ui_manager);
 
1025
 
 
1026
        g_signal_connect_object (plugin->next_action,
 
1027
                                 "notify::sensitive",
 
1028
                                 G_CALLBACK (next_action_sensitive_cb),
 
1029
                                 plugin, 0);
 
1030
        g_signal_connect_object (plugin->prev_action,
 
1031
                                 "notify::sensitive",
 
1032
                                 G_CALLBACK (prev_action_sensitive_cb),
 
1033
                                 plugin, 0);
629
1034
}
630
1035
 
631
1036
static void
635
1040
                g_dbus_connection_unregister_object (plugin->connection, plugin->root_id);
636
1041
                plugin->root_id = 0;
637
1042
        }
638
 
        if (plugin->tracklist_id != 0) {
639
 
                g_dbus_connection_unregister_object (plugin->connection, plugin->tracklist_id);
640
 
                plugin->tracklist_id = 0;
641
 
        }
642
1043
        if (plugin->player_id != 0) {
643
1044
                g_dbus_connection_unregister_object (plugin->connection, plugin->player_id);
644
1045
                plugin->player_id = 0;
668
1069
        plugin->shell = g_object_ref (shell);
669
1070
 
670
1071
        plugin->name_own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
671
 
                                              "org.mpris.rhythmbox",
 
1072
                                              MPRIS_BUS_NAME_PREFIX ".rhythmbox",
672
1073
                                              G_BUS_NAME_OWNER_FLAGS_NONE,
673
1074
                                              NULL,
674
1075
                                              (GBusNameAcquiredCallback) name_acquired_cb,