[rhythmbox] convert playlist manager dbus interface to use gdbus
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] convert playlist manager dbus interface to use gdbus
- Date: Sun, 6 Mar 2011 22:16:30 +0000 (UTC)
commit b5d1bf1e3de9447307305a55136f23eb81066216
Author: Jonathan Matthew <jonathan d14n org>
Date: Mon Mar 7 08:16:11 2011 +1000
convert playlist manager dbus interface to use gdbus
shell/Makefile.am | 6 +-
shell/main.c | 6 -
shell/rb-playlist-manager.c | 1548 +++++++++++++++++++++++------------------
shell/rb-playlist-manager.xml | 42 --
4 files changed, 855 insertions(+), 747 deletions(-)
---
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 192f2d9..8b1959d 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -148,15 +148,13 @@ rb-shell-glue.h: rb-shell.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell --mode=glib-server --output=$@ $<
rb-shell-player-glue.h: rb-shell-player.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell_player --mode=glib-server --output=$@ $<
-rb-playlist-manager-glue.h: rb-playlist-manager.xml Makefile
- $(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_playlist_manager --mode=glib-server --output=$@ $<
rb-shell-binding.h: rb-shell.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell --mode=glib-client --output=$@ $<
rb-shell-player-binding.h: rb-shell-player.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=rb_shell --mode=glib-client --output=$@ $<
-BUILT_SOURCES += rb-shell-glue.h rb-shell-binding.h rb-shell-player-glue.h rb-shell-player-binding.h rb-playlist-manager-glue.h
-EXTRA_DIST += rb-shell.xml rb-shell-player.xml rb-playlist-manager.xml
+BUILT_SOURCES += rb-shell-glue.h rb-shell-binding.h rb-shell-player-glue.h rb-shell-player-binding.h
+EXTRA_DIST += rb-shell.xml rb-shell-player.xml
rhythmbox_LDADD = \
librhythmbox-core.la \
diff --git a/shell/main.c b/shell/main.c
index 97d217f..36dabcc 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -295,12 +295,6 @@ main (int argc, char **argv)
path = rb_shell_get_player_path (rb_shell);
dbus_g_connection_register_g_object (session_bus, path, obj);
- /* register playlist manager object */
- dbus_g_object_type_install_info (RB_TYPE_PLAYLIST_MANAGER, &dbus_glib_rb_playlist_manager_object_info);
- obj = rb_shell_get_playlist_manager (rb_shell);
- path = rb_shell_get_playlist_manager_path (rb_shell);
- dbus_g_connection_register_g_object (session_bus, path, obj);
-
g_signal_connect (G_OBJECT (rb_shell),
"database-load-complete",
G_CALLBACK (database_load_complete),
diff --git a/shell/rb-playlist-manager.c b/shell/rb-playlist-manager.c
index 6b52a3e..acb3daa 100644
--- a/shell/rb-playlist-manager.c
+++ b/shell/rb-playlist-manager.c
@@ -65,18 +65,42 @@
#define RB_PLAYLIST_MGR_VERSION (xmlChar *) "1.0"
#define RB_PLAYLIST_MGR_PL (xmlChar *) "rhythmdb-playlists"
+#define RB_PLAYLIST_MANAGER_IFACE_NAME "org.gnome.Rhythmbox.PlaylistManager"
+#define RB_PLAYLIST_MANAGER_DBUS_PATH "/org/gnome/Rhythmbox/PlaylistManager"
+
+static const char *rb_playlist_manager_dbus_spec =
+"<node>"
+" <interface name='org.gnome.Rhythmbox.PlaylistManager'>"
+" <method name='getPlaylists'>"
+" <arg type='as' direction='out'/>"
+" </method>"
+" <method name='createPlaylist'>"
+" <arg type='s' name='name'/>"
+" </method>"
+" <method name='deletePlaylist'>"
+" <arg type='s' name='name'/>"
+" </method>"
+" <method name='addToPlaylist'>"
+" <arg type='s' name='playlist'/>"
+" <arg type='s' name='uri'/>"
+" </method>"
+" <method name='removeFromPlaylist'>"
+" <arg type='s' name='playlist'/>"
+" <arg type='s' name='uri'/>"
+" </method>"
+" <method name='exportPlaylist'>"
+" <arg type='s' name='playlist'/>"
+" <arg type='s' name='uri'/>"
+" <arg type='b' name='mp3_format'/>"
+" </method>"
+" <method name='importPlaylist'>"
+" <arg type='s' name='uri'/>"
+" </method>"
+" </interface>"
+"</node>";
+
static void rb_playlist_manager_class_init (RBPlaylistManagerClass *klass);
static void rb_playlist_manager_init (RBPlaylistManager *mgr);
-static void rb_playlist_manager_dispose (GObject *object);
-static void rb_playlist_manager_finalize (GObject *object);
-static void rb_playlist_manager_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void rb_playlist_manager_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
static void rb_playlist_manager_cmd_load_playlist (GtkAction *action,
RBPlaylistManager *mgr);
static void rb_playlist_manager_cmd_save_playlist (GtkAction *action,
@@ -200,137 +224,6 @@ static guint rb_playlist_manager_n_actions = G_N_ELEMENTS (rb_playlist_manager_a
G_DEFINE_TYPE (RBPlaylistManager, rb_playlist_manager, G_TYPE_OBJECT)
-static void
-rb_playlist_manager_class_init (RBPlaylistManagerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = rb_playlist_manager_dispose;
- object_class->finalize = rb_playlist_manager_finalize;
-
- object_class->set_property = rb_playlist_manager_set_property;
- object_class->get_property = rb_playlist_manager_get_property;
-
- g_object_class_install_property (object_class,
- PROP_PLAYLIST_NAME,
- g_param_spec_string ("playlists_file",
- "name",
- "playlists file",
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SOURCE,
- g_param_spec_object ("source",
- "RBSource",
- "RBSource object",
- RB_TYPE_SOURCE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SHELL,
- g_param_spec_object ("shell",
- "RBShell",
- "RBShell object",
- RB_TYPE_SHELL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_DISPLAY_PAGE_MODEL,
- g_param_spec_object ("display-page-model",
- "RBDisplayPageModel",
- "RBDisplayPageModel",
- RB_TYPE_DISPLAY_PAGE_MODEL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class,
- PROP_DISPLAY_PAGE_TREE,
- g_param_spec_object ("display-page-tree",
- "RBDisplayPageTree",
- "RBDisplayPageTree",
- RB_TYPE_DISPLAY_PAGE_TREE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
- /**
- * RBPlaylistManager::playlist-added:
- * @manager: the #RBPlaylistManager
- * @source: the new #RBSource
- *
- * Emitted when a playlist is added, including when being loaded
- * from the user's playlist file.
- */
- rb_playlist_manager_signals[PLAYLIST_ADDED] =
- g_signal_new ("playlist_added",
- RB_TYPE_PLAYLIST_MANAGER,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPlaylistManagerClass, playlist_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE,
- 1, G_TYPE_OBJECT);
-
- /**
- * RBPlaylistManager::playlist-created:
- * @manager: the #RBPlaylistManager
- * @source: the newly created playlist #RBSource
- *
- * Emitted when a new playlist is created.
- */
- rb_playlist_manager_signals[PLAYLIST_CREATED] =
- g_signal_new ("playlist_created",
- RB_TYPE_PLAYLIST_MANAGER,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPlaylistManagerClass, playlist_created),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE,
- 1, G_TYPE_OBJECT);
-
- /**
- * RBPlaylistManager::load-start:
- * @manager: the #RBPlaylistManager
- *
- * Emitted when the playlist manager starts loading the user's
- * playlist file.
- */
- rb_playlist_manager_signals[PLAYLIST_LOAD_START] =
- g_signal_new ("load_start",
- RB_TYPE_PLAYLIST_MANAGER,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPlaylistManagerClass, load_start),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0, G_TYPE_NONE);
- /**
- * RBPlaylistManager::load-finish
- * @manager: the #RBPlaylistManager
- *
- * Emitted when the playlist manager finishes loading the user's
- * playlist file.
- */
- rb_playlist_manager_signals[PLAYLIST_LOAD_FINISH] =
- g_signal_new ("load_finish",
- RB_TYPE_PLAYLIST_MANAGER,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPlaylistManagerClass, load_finish),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0, G_TYPE_NONE);
-
- g_type_class_add_private (klass, sizeof (RBPlaylistManagerPrivate));
-}
-
-static void
-rb_playlist_manager_init (RBPlaylistManager *mgr)
-{
- mgr->priv = G_TYPE_INSTANCE_GET_PRIVATE (mgr,
- RB_TYPE_PLAYLIST_MANAGER,
- RBPlaylistManagerPrivate);
-
- mgr->priv->saving_mutex = g_mutex_new ();
- mgr->priv->dirty = 0;
- mgr->priv->saving = 0;
-}
/**
* rb_playlist_manager_shutdown:
@@ -348,656 +241,425 @@ rb_playlist_manager_shutdown (RBPlaylistManager *mgr)
g_mutex_unlock (mgr->priv->saving_mutex);
}
-static void
-rb_playlist_manager_dispose (GObject *object)
+/**
+ * rb_playlist_manager_new:
+ * @shell: the #RBShell
+ * @page_model: the #RBDisplayPageModel
+ * @page_tree: the #RBDisplayPageTree
+ * @playlists_file: the full path to the playlist file to load
+ *
+ * Creates the #RBPlaylistManager instance
+ *
+ * Return value: the #RBPlaylistManager
+ */
+RBPlaylistManager *
+rb_playlist_manager_new (RBShell *shell,
+ RBDisplayPageModel *page_model,
+ RBDisplayPageTree *page_tree,
+ const char *playlists_file)
{
- RBPlaylistManager *mgr;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object));
+ return g_object_new (RB_TYPE_PLAYLIST_MANAGER,
+ "shell", shell,
+ "display-page-model", page_model,
+ "display-page-tree", page_tree,
+ "playlists_file", playlists_file,
+ NULL);
+}
- rb_debug ("Disposing playlist manager");
+GQuark
+rb_playlist_manager_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("rb_playlist_manager_error");
- mgr = RB_PLAYLIST_MANAGER (object);
+ return quark;
+}
- g_return_if_fail (mgr->priv != NULL);
+static void
+handle_playlist_entry_cb (TotemPlParser *playlist,
+ const char *uri_maybe,
+ GHashTable *metadata,
+ RBPlaylistManager *mgr)
+{
+ char *uri;
+ const char *title, *genre;
- if (mgr->priv->db != NULL) {
- g_object_unref (mgr->priv->db);
- mgr->priv->db = NULL;
- }
+ title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
+ genre = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_GENRE);
- if (mgr->priv->uimanager != NULL) {
- g_object_unref (mgr->priv->uimanager);
- mgr->priv->uimanager = NULL;
- }
+ uri = rb_canonicalise_uri (uri_maybe);
+ g_return_if_fail (uri != NULL);
- if (mgr->priv->page_model != NULL) {
- g_object_unref (mgr->priv->page_model);
- mgr->priv->page_model = NULL;
- }
+ rb_debug ("adding uri %s (title %s, genre %s) from playlist",
+ uri, title, genre);
+ if (!rb_shell_add_uri (mgr->priv->shell,
+ uri,
+ title,
+ genre,
+ NULL))
+ return;
- if (mgr->priv->display_page_tree != NULL) {
- g_object_unref (mgr->priv->display_page_tree);
- mgr->priv->display_page_tree = NULL;
+ if (!mgr->priv->loading_playlist) {
+ mgr->priv->loading_playlist =
+ RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, NULL, FALSE));
}
-
- if (mgr->priv->selected_source != NULL) {
- g_object_unref (mgr->priv->selected_source);
- mgr->priv->selected_source = NULL;
+ if (rb_source_want_uri (RB_SOURCE (mgr->priv->loading_playlist), uri) > 0) {
+ rb_debug ("adding uri %s to playlist", uri);
+ rb_static_playlist_source_add_location (mgr->priv->loading_playlist, uri, -1);
}
- G_OBJECT_CLASS (rb_playlist_manager_parent_class)->dispose (object);
+ g_free (uri);
}
static void
-rb_playlist_manager_finalize (GObject *object)
+playlist_load_started_cb (TotemPlParser *parser, const char *uri, GHashTable *metadata, RBPlaylistManager *mgr)
{
- RBPlaylistManager *mgr;
+ const char *title;
- g_return_if_fail (object != NULL);
- g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object));
+ rb_debug ("loading new playlist %s", uri);
- rb_debug ("Finalizing playlist manager");
+ title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
+ if (title == NULL)
+ title = _("Unnamed playlist");
- mgr = RB_PLAYLIST_MANAGER (object);
+ mgr->priv->loading_playlist =
+ RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, title, FALSE));
+}
- g_return_if_fail (mgr->priv != NULL);
+/**
+ * rb_playlist_manager_parse_file:
+ * @mgr: the #RBPlaylistManager
+ * @uri: URI of the playlist to load
+ * @error: returns a GError in case of error
+ *
+ * Parses a playlist file, adding entries to the database and to a new
+ * static playlist. If the playlist file includes a title, the static
+ * playlist created will have the same title.
+ *
+ * Return value: TRUE on success
+ **/
+gboolean
+rb_playlist_manager_parse_file (RBPlaylistManager *mgr, const char *uri, GError **error)
+{
+ rb_debug ("loading playlist from %s", uri);
- g_mutex_free (mgr->priv->saving_mutex);
+ g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_LOAD_START], 0);
- g_free (mgr->priv->playlists_file);
+ {
+ TotemPlParser *parser = totem_pl_parser_new ();
- G_OBJECT_CLASS (rb_playlist_manager_parent_class)->finalize (object);
-}
+ g_signal_connect_object (parser, "entry-parsed",
+ G_CALLBACK (handle_playlist_entry_cb),
+ mgr, 0);
-static void
-rb_playlist_manager_set_uimanager (RBPlaylistManager *mgr,
- GtkUIManager *uimanager)
-{
- if (mgr->priv->uimanager != NULL) {
- if (mgr->priv->actiongroup != NULL) {
- gtk_ui_manager_remove_action_group (mgr->priv->uimanager,
- mgr->priv->actiongroup);
+ g_signal_connect_object (parser, "playlist-started",
+ G_CALLBACK (playlist_load_started_cb),
+ mgr, 0);
+
+ g_object_set (parser, "recurse", FALSE, NULL);
+
+ if (totem_pl_parser_parse (parser, uri, TRUE) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+ g_set_error (error,
+ RB_PLAYLIST_MANAGER_ERROR,
+ RB_PLAYLIST_MANAGER_ERROR_PARSE,
+ "%s",
+ _("The playlist file may be in an unknown format or corrupted."));
+ return FALSE;
}
- g_object_unref (mgr->priv->uimanager);
- }
- mgr->priv->uimanager = uimanager;
+ if (mgr->priv->loading_playlist != NULL) {
+ char *name = NULL;
- if (mgr->priv->actiongroup == NULL) {
- mgr->priv->actiongroup = gtk_action_group_new ("PlaylistManagerActions");
- gtk_action_group_set_translation_domain (mgr->priv->actiongroup,
- GETTEXT_PACKAGE);
- gtk_action_group_add_actions (mgr->priv->actiongroup,
- rb_playlist_manager_actions,
- rb_playlist_manager_n_actions,
- mgr);
+ /* totem-plparser may not have given us the playlist name */
+ g_object_get (mgr->priv->loading_playlist, "name", &name, NULL);
+ if (name == NULL || name[0] == '\0') {
+ char *path;
+
+ rb_debug ("setting playlist name from file name");
+ path = g_filename_from_uri (uri, NULL, NULL);
+ if (path) {
+ name = g_path_get_basename (path);
+ g_object_set (mgr->priv->loading_playlist, "name", name, NULL);
+ g_free (path);
+ }
+ }
+
+ g_free (name);
+ mgr->priv->loading_playlist = NULL;
+ }
+
+ g_object_unref (parser);
}
- gtk_ui_manager_insert_action_group (mgr->priv->uimanager,
- mgr->priv->actiongroup,
- 0);
+ g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_LOAD_FINISH], 0);
+ return TRUE;
}
static void
-rb_playlist_manager_set_source (RBPlaylistManager *mgr,
- RBSource *source)
+append_new_playlist_source (RBPlaylistManager *mgr, RBPlaylistSource *source)
{
- gboolean playlist_active;
- gboolean playlist_local = FALSE;
- gboolean party_mode;
- gboolean can_save;
- gboolean can_delete;
- gboolean can_edit;
- gboolean can_rename;
- gboolean can_shuffle;
- GtkAction *action;
+ g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_ADDED], 0,
+ source);
+}
- party_mode = rb_shell_get_party_mode (mgr->priv->shell);
+/**
+ * rb_playlist_manager_load_playlists:
+ * @mgr: the #RBPlaylistManager
+ *
+ * Loads the user's playlists, or if the playlist file does not exists,
+ * reads the default playlist file. Should be called only once on startup.
+ **/
+void
+rb_playlist_manager_load_playlists (RBPlaylistManager *mgr)
+{
+ char *file;
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ xmlNodePtr child;
+ gboolean exists;
- if (mgr->priv->selected_source != NULL) {
- g_object_unref (mgr->priv->selected_source);
+ exists = FALSE;
+ file = g_strdup (mgr->priv->playlists_file);
+
+ /* block saves until the playlists have loaded */
+ g_mutex_lock (mgr->priv->saving_mutex);
+
+ exists = g_file_test (file, G_FILE_TEST_EXISTS);
+ if (! exists) {
+ rb_debug ("personal playlists not found, loading defaults");
+
+ /* try global playlists */
+ g_free (file);
+ file = g_strdup (rb_file ("playlists.xml"));
+ exists = g_file_test (file, G_FILE_TEST_EXISTS);
}
- mgr->priv->selected_source = g_object_ref (source);
- playlist_active = RB_IS_PLAYLIST_SOURCE (mgr->priv->selected_source);
- if (playlist_active) {
- g_object_get (mgr->priv->selected_source, "is-local", &playlist_local, NULL);
+ if (! exists) {
+ rb_debug ("default playlists file not found");
+ goto out;
}
- can_save = playlist_local && !party_mode;
- action = gtk_action_group_get_action (mgr->priv->actiongroup,
- "MusicPlaylistSavePlaylist");
- gtk_action_set_visible (action, can_save);
+ doc = xmlParseFile (file);
+ if (doc == NULL)
+ goto out;
- can_delete = (playlist_local && !party_mode &&
- !RB_IS_PLAY_QUEUE_SOURCE (mgr->priv->selected_source));
- action = gtk_action_group_get_action (mgr->priv->actiongroup,
- "MusicPlaylistDeletePlaylist");
- gtk_action_set_visible (action, can_delete);
+ root = xmlDocGetRootElement (doc);
- can_edit = (playlist_local && RB_IS_AUTO_PLAYLIST_SOURCE (mgr->priv->selected_source) &&
- !party_mode);
- action = gtk_action_group_get_action (mgr->priv->actiongroup,
- "EditAutomaticPlaylist");
- gtk_action_set_visible (action, can_edit);
+ for (child = root->children; child; child = child->next) {
+ RBSource *playlist;
- can_rename = playlist_local && rb_source_can_rename (mgr->priv->selected_source);
- action = gtk_action_group_get_action (mgr->priv->actiongroup,
- "MusicPlaylistRenamePlaylist");
- gtk_action_set_visible (action, can_rename);
+ if (xmlNodeIsText (child))
+ continue;
- can_shuffle = RB_IS_STATIC_PLAYLIST_SOURCE (mgr->priv->selected_source);
- action = gtk_action_group_get_action (mgr->priv->actiongroup,
- "ShufflePlaylist");
- gtk_action_set_sensitive (action, can_shuffle);
+ playlist = rb_playlist_source_new_from_xml (mgr->priv->shell,
+ child);
+ if (playlist)
+ append_new_playlist_source (mgr, RB_PLAYLIST_SOURCE (playlist));
+ }
+
+ xmlFreeDoc (doc);
+out:
+ g_mutex_unlock (mgr->priv->saving_mutex);
+ g_free (file);
}
static void
-rb_playlist_manager_set_shell_internal (RBPlaylistManager *mgr,
- RBShell *shell)
+rb_playlist_manager_set_dirty (RBPlaylistManager *mgr, gboolean dirty)
{
- GtkUIManager *uimanager = NULL;
- RhythmDB *db = NULL;
+ g_atomic_int_compare_and_exchange (&mgr->priv->dirty, dirty == FALSE, dirty == TRUE);
+}
- if (mgr->priv->db != NULL) {
- g_object_unref (mgr->priv->db);
+static gboolean
+_is_dirty_playlist (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gboolean *dirty)
+{
+ RBDisplayPage *page;
+ gboolean local;
+ gboolean ret;
+
+ gtk_tree_model_get (model,
+ iter,
+ RB_DISPLAY_PAGE_MODEL_COLUMN_PAGE,
+ &page,
+ -1);
+ if (page == NULL) {
+ return FALSE;
+ }
+ if (RB_IS_PLAYLIST_SOURCE (page) == FALSE) {
+ g_object_unref (page);
+ return FALSE;
}
- mgr->priv->shell = shell;
+ ret = FALSE;
+ g_object_get (page, "is-local", &local, NULL);
+ if (local) {
+ gboolean pdirty;
- if (mgr->priv->shell != NULL) {
- g_object_get (mgr->priv->shell,
- "ui-manager", &uimanager,
- "db", &db,
- NULL);
+ g_object_get (page, "dirty", &pdirty, NULL);
+ if (pdirty) {
+ *dirty = TRUE;
+ ret = TRUE;
+ }
}
+ g_object_unref (page);
- mgr->priv->db = db;
- rb_playlist_manager_set_uimanager (mgr, uimanager);
+ return ret;
}
-static void
-rb_playlist_manager_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+/* returns TRUE if a playlist has been created, modified, or deleted since last save */
+static gboolean
+rb_playlist_manager_is_dirty (RBPlaylistManager *mgr)
{
- RBPlaylistManager *mgr = RB_PLAYLIST_MANAGER (object);
+ gboolean dirty = FALSE;
- switch (prop_id) {
- case PROP_PLAYLIST_NAME:
- g_free (mgr->priv->playlists_file);
- mgr->priv->playlists_file = g_strdup (g_value_get_string (value));
- break;
- case PROP_SOURCE:
- rb_playlist_manager_set_source (mgr, g_value_get_object (value));
- break;
- case PROP_SHELL:
- rb_playlist_manager_set_shell_internal (mgr, g_value_get_object (value));
- break;
- case PROP_DISPLAY_PAGE_MODEL:
- mgr->priv->page_model = g_value_dup_object (value);
- break;
- case PROP_DISPLAY_PAGE_TREE:
- mgr->priv->display_page_tree = g_value_dup_object (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ gtk_tree_model_foreach (GTK_TREE_MODEL (mgr->priv->page_model),
+ (GtkTreeModelForeachFunc) _is_dirty_playlist,
+ &dirty);
+
+ if (!dirty)
+ dirty = g_atomic_int_get (&mgr->priv->dirty);
+
+ return dirty;
}
-static void
-rb_playlist_manager_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+struct RBPlaylistManagerSaveData
{
- RBPlaylistManager *mgr = RB_PLAYLIST_MANAGER (object);
+ RBPlaylistManager *mgr;
+ xmlDocPtr doc;
+};
- switch (prop_id) {
- case PROP_PLAYLIST_NAME:
- g_value_set_string (value, mgr->priv->playlists_file);
- break;
- case PROP_SOURCE:
- g_value_set_object (value, mgr->priv->selected_source);
- break;
- case PROP_SHELL:
- g_value_set_object (value, mgr->priv->shell);
- break;
- case PROP_DISPLAY_PAGE_MODEL:
- g_value_set_object (value, mgr->priv->page_model);
- break;
- case PROP_DISPLAY_PAGE_TREE:
- g_value_set_object (value, mgr->priv->display_page_tree);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/**
- * rb_playlist_manager_new:
- * @shell: the #RBShell
- * @page_model: the #RBDisplayPageModel
- * @page_tree: the #RBDisplayPageTree
- * @playlists_file: the full path to the playlist file to load
- *
- * Creates the #RBPlaylistManager instance
- *
- * Return value: the #RBPlaylistManager
- */
-RBPlaylistManager *
-rb_playlist_manager_new (RBShell *shell,
- RBDisplayPageModel *page_model,
- RBDisplayPageTree *page_tree,
- const char *playlists_file)
-{
- return g_object_new (RB_TYPE_PLAYLIST_MANAGER,
- "shell", shell,
- "display-page-model", page_model,
- "display-page-tree", page_tree,
- "playlists_file", playlists_file,
- NULL);
-}
-
-GQuark
-rb_playlist_manager_error_quark (void)
+static gpointer
+rb_playlist_manager_save_data (struct RBPlaylistManagerSaveData *data)
{
- static GQuark quark = 0;
- if (!quark)
- quark = g_quark_from_static_string ("rb_playlist_manager_error");
-
- return quark;
-}
+ char *file;
+ char *tmpname;
-static void
-handle_playlist_entry_cb (TotemPlParser *playlist,
- const char *uri_maybe,
- GHashTable *metadata,
- RBPlaylistManager *mgr)
-{
- char *uri;
- const char *title, *genre;
+ g_mutex_lock (data->mgr->priv->saving_mutex);
- title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
- genre = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_GENRE);
+ file = g_strdup (data->mgr->priv->playlists_file);
+ tmpname = g_strconcat (file, ".tmp", NULL);
- uri = rb_canonicalise_uri (uri_maybe);
- g_return_if_fail (uri != NULL);
+ if (xmlSaveFormatFile (tmpname, data->doc, 1) != -1) {
+ rename (tmpname, file);
+ } else {
+ rb_debug ("error in xmlSaveFormatFile(), not saving");
+ unlink (tmpname);
+ rb_playlist_manager_set_dirty (data->mgr, TRUE);
+ }
+ xmlFreeDoc (data->doc);
+ g_free (tmpname);
+ g_free (file);
- rb_debug ("adding uri %s (title %s, genre %s) from playlist",
- uri, title, genre);
- if (!rb_shell_add_uri (mgr->priv->shell,
- uri,
- title,
- genre,
- NULL))
- return;
+ g_atomic_int_compare_and_exchange (&data->mgr->priv->saving, 1, 0);
+ g_mutex_unlock (data->mgr->priv->saving_mutex);
- if (!mgr->priv->loading_playlist) {
- mgr->priv->loading_playlist =
- RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, NULL, FALSE));
- }
- if (rb_source_want_uri (RB_SOURCE (mgr->priv->loading_playlist), uri) > 0) {
- rb_debug ("adding uri %s to playlist", uri);
- rb_static_playlist_source_add_location (mgr->priv->loading_playlist, uri, -1);
- }
+ g_object_unref (data->mgr);
- g_free (uri);
+ g_free (data);
+ return NULL;
}
-static void
-playlist_load_started_cb (TotemPlParser *parser, const char *uri, GHashTable *metadata, RBPlaylistManager *mgr)
+static gboolean
+save_playlist_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ xmlNodePtr root)
{
- const char *title;
+ RBDisplayPage *page;
+ gboolean local;
- rb_debug ("loading new playlist %s", uri);
+ gtk_tree_model_get (model,
+ iter,
+ RB_DISPLAY_PAGE_MODEL_COLUMN_PAGE, &page,
+ -1);
+ if (page == NULL) {
+ goto out;
+ }
+ if (RB_IS_PLAYLIST_SOURCE (page) == FALSE) {
+ goto out;
+ }
- title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
- if (title == NULL)
- title = _("Unnamed playlist");
+ g_object_get (page, "is-local", &local, NULL);
+ if (local) {
+ rb_playlist_source_save_to_xml (RB_PLAYLIST_SOURCE (page), root);
+ }
+ out:
+ if (page != NULL) {
+ g_object_unref (page);
+ }
- mgr->priv->loading_playlist =
- RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, title, FALSE));
+ return FALSE;
}
/**
- * rb_playlist_manager_parse_file:
+ * rb_playlist_manager_save_playlists:
* @mgr: the #RBPlaylistManager
- * @uri: URI of the playlist to load
- * @error: returns a GError in case of error
+ * @force: if TRUE, save playlists synchronously and unconditionally
*
- * Parses a playlist file, adding entries to the database and to a new
- * static playlist. If the playlist file includes a title, the static
- * playlist created will have the same title.
+ * Saves the user's playlists. If the force flag is
+ * TRUE, the playlists will always be saved. Otherwise, the playlists
+ * will only be saved if a playlist has been created, modified, or deleted
+ * since the last time the playlists were saved, and no save operation is
+ * currently taking place.
*
- * Return value: TRUE on success
+ * Return value: TRUE if a playlist save operation has been started
**/
gboolean
-rb_playlist_manager_parse_file (RBPlaylistManager *mgr, const char *uri, GError **error)
+rb_playlist_manager_save_playlists (RBPlaylistManager *mgr, gboolean force)
{
- rb_debug ("loading playlist from %s", uri);
-
- g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_LOAD_START], 0);
-
- {
- TotemPlParser *parser = totem_pl_parser_new ();
-
- g_signal_connect_object (parser, "entry-parsed",
- G_CALLBACK (handle_playlist_entry_cb),
- mgr, 0);
-
- g_signal_connect_object (parser, "playlist-started",
- G_CALLBACK (playlist_load_started_cb),
- mgr, 0);
+ xmlNodePtr root;
+ struct RBPlaylistManagerSaveData *data;
- g_object_set (parser, "recurse", FALSE, NULL);
+ if (!force && !rb_playlist_manager_is_dirty (mgr)) {
+ /* playlists already in sync, so don't bother */
+ return FALSE;
+ }
- if (totem_pl_parser_parse (parser, uri, TRUE) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
- g_set_error (error,
- RB_PLAYLIST_MANAGER_ERROR,
- RB_PLAYLIST_MANAGER_ERROR_PARSE,
- "%s",
- _("The playlist file may be in an unknown format or corrupted."));
- return FALSE;
- }
+ if (!g_atomic_int_compare_and_exchange (&mgr->priv->saving, 0, 1) && !force) {
+ /* already saving, so don't bother */
+ return FALSE;
+ }
- if (mgr->priv->loading_playlist != NULL) {
- char *name = NULL;
+ data = g_new0 (struct RBPlaylistManagerSaveData, 1);
+ data->mgr = mgr;
+ data->doc = xmlNewDoc (RB_PLAYLIST_MGR_VERSION);
+ g_object_ref (mgr);
- /* totem-plparser may not have given us the playlist name */
- g_object_get (mgr->priv->loading_playlist, "name", &name, NULL);
- if (name == NULL || name[0] == '\0') {
- char *path;
+ root = xmlNewDocNode (data->doc, NULL, RB_PLAYLIST_MGR_PL, NULL);
+ xmlDocSetRootElement (data->doc, root);
- rb_debug ("setting playlist name from file name");
- path = g_filename_from_uri (uri, NULL, NULL);
- if (path) {
- name = g_path_get_basename (path);
- g_object_set (mgr->priv->loading_playlist, "name", name, NULL);
- g_free (path);
- }
- }
+ gtk_tree_model_foreach (GTK_TREE_MODEL (mgr->priv->page_model),
+ (GtkTreeModelForeachFunc)save_playlist_cb,
+ root);
- g_free (name);
- mgr->priv->loading_playlist = NULL;
- }
+ /* mark clean here. if the save fails, we'll mark it dirty again */
+ rb_playlist_manager_set_dirty (data->mgr, FALSE);
- g_object_unref (parser);
- }
+ if (force)
+ rb_playlist_manager_save_data (data);
+ else
+ g_thread_create ((GThreadFunc) rb_playlist_manager_save_data, data, FALSE, NULL);
- g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_LOAD_FINISH], 0);
return TRUE;
}
-static void
-append_new_playlist_source (RBPlaylistManager *mgr, RBPlaylistSource *source)
-{
- g_signal_emit (mgr, rb_playlist_manager_signals[PLAYLIST_ADDED], 0,
- source);
-}
-
/**
- * rb_playlist_manager_load_playlists:
+ * rb_playlist_manager_new_playlist:
* @mgr: the #RBPlaylistManager
+ * @suggested_name: optional name to use for the new playlist
+ * @automatic: if TRUE, create an auto playlist
*
- * Loads the user's playlists, or if the playlist file does not exists,
- * reads the default playlist file. Should be called only once on startup.
- **/
-void
-rb_playlist_manager_load_playlists (RBPlaylistManager *mgr)
-{
- char *file;
- xmlDocPtr doc;
- xmlNodePtr root;
- xmlNodePtr child;
- gboolean exists;
-
- exists = FALSE;
- file = g_strdup (mgr->priv->playlists_file);
-
- /* block saves until the playlists have loaded */
- g_mutex_lock (mgr->priv->saving_mutex);
-
- exists = g_file_test (file, G_FILE_TEST_EXISTS);
- if (! exists) {
- rb_debug ("personal playlists not found, loading defaults");
-
- /* try global playlists */
- g_free (file);
- file = g_strdup (rb_file ("playlists.xml"));
- exists = g_file_test (file, G_FILE_TEST_EXISTS);
- }
-
- if (! exists) {
- rb_debug ("default playlists file not found");
- goto out;
- }
-
- doc = xmlParseFile (file);
- if (doc == NULL)
- goto out;
-
- root = xmlDocGetRootElement (doc);
-
- for (child = root->children; child; child = child->next) {
- RBSource *playlist;
-
- if (xmlNodeIsText (child))
- continue;
-
- playlist = rb_playlist_source_new_from_xml (mgr->priv->shell,
- child);
- if (playlist)
- append_new_playlist_source (mgr, RB_PLAYLIST_SOURCE (playlist));
- }
-
- xmlFreeDoc (doc);
-out:
- g_mutex_unlock (mgr->priv->saving_mutex);
- g_free (file);
-}
-
-static void
-rb_playlist_manager_set_dirty (RBPlaylistManager *mgr, gboolean dirty)
-{
- g_atomic_int_compare_and_exchange (&mgr->priv->dirty, dirty == FALSE, dirty == TRUE);
-}
-
-static gboolean
-_is_dirty_playlist (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gboolean *dirty)
-{
- RBDisplayPage *page;
- gboolean local;
- gboolean ret;
-
- gtk_tree_model_get (model,
- iter,
- RB_DISPLAY_PAGE_MODEL_COLUMN_PAGE,
- &page,
- -1);
- if (page == NULL) {
- return FALSE;
- }
- if (RB_IS_PLAYLIST_SOURCE (page) == FALSE) {
- g_object_unref (page);
- return FALSE;
- }
-
- ret = FALSE;
- g_object_get (page, "is-local", &local, NULL);
- if (local) {
- gboolean pdirty;
-
- g_object_get (page, "dirty", &pdirty, NULL);
- if (pdirty) {
- *dirty = TRUE;
- ret = TRUE;
- }
- }
- g_object_unref (page);
-
- return ret;
-}
-
-/* returns TRUE if a playlist has been created, modified, or deleted since last save */
-static gboolean
-rb_playlist_manager_is_dirty (RBPlaylistManager *mgr)
-{
- gboolean dirty = FALSE;
-
- gtk_tree_model_foreach (GTK_TREE_MODEL (mgr->priv->page_model),
- (GtkTreeModelForeachFunc) _is_dirty_playlist,
- &dirty);
-
- if (!dirty)
- dirty = g_atomic_int_get (&mgr->priv->dirty);
-
- return dirty;
-}
-
-struct RBPlaylistManagerSaveData
-{
- RBPlaylistManager *mgr;
- xmlDocPtr doc;
-};
-
-static gpointer
-rb_playlist_manager_save_data (struct RBPlaylistManagerSaveData *data)
-{
- char *file;
- char *tmpname;
-
- g_mutex_lock (data->mgr->priv->saving_mutex);
-
- file = g_strdup (data->mgr->priv->playlists_file);
- tmpname = g_strconcat (file, ".tmp", NULL);
-
- if (xmlSaveFormatFile (tmpname, data->doc, 1) != -1) {
- rename (tmpname, file);
- } else {
- rb_debug ("error in xmlSaveFormatFile(), not saving");
- unlink (tmpname);
- rb_playlist_manager_set_dirty (data->mgr, TRUE);
- }
- xmlFreeDoc (data->doc);
- g_free (tmpname);
- g_free (file);
-
- g_atomic_int_compare_and_exchange (&data->mgr->priv->saving, 1, 0);
- g_mutex_unlock (data->mgr->priv->saving_mutex);
-
- g_object_unref (data->mgr);
-
- g_free (data);
- return NULL;
-}
-
-static gboolean
-save_playlist_cb (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- xmlNodePtr root)
-{
- RBDisplayPage *page;
- gboolean local;
-
- gtk_tree_model_get (model,
- iter,
- RB_DISPLAY_PAGE_MODEL_COLUMN_PAGE, &page,
- -1);
- if (page == NULL) {
- goto out;
- }
- if (RB_IS_PLAYLIST_SOURCE (page) == FALSE) {
- goto out;
- }
-
- g_object_get (page, "is-local", &local, NULL);
- if (local) {
- rb_playlist_source_save_to_xml (RB_PLAYLIST_SOURCE (page), root);
- }
- out:
- if (page != NULL) {
- g_object_unref (page);
- }
-
- return FALSE;
-}
-
-/**
- * rb_playlist_manager_save_playlists:
- * @mgr: the #RBPlaylistManager
- * @force: if TRUE, save playlists synchronously and unconditionally
- *
- * Saves the user's playlists. If the force flag is
- * TRUE, the playlists will always be saved. Otherwise, the playlists
- * will only be saved if a playlist has been created, modified, or deleted
- * since the last time the playlists were saved, and no save operation is
- * currently taking place.
- *
- * Return value: TRUE if a playlist save operation has been started
- **/
-gboolean
-rb_playlist_manager_save_playlists (RBPlaylistManager *mgr, gboolean force)
-{
- xmlNodePtr root;
- struct RBPlaylistManagerSaveData *data;
-
- if (!force && !rb_playlist_manager_is_dirty (mgr)) {
- /* playlists already in sync, so don't bother */
- return FALSE;
- }
-
- if (!g_atomic_int_compare_and_exchange (&mgr->priv->saving, 0, 1) && !force) {
- /* already saving, so don't bother */
- return FALSE;
- }
-
- data = g_new0 (struct RBPlaylistManagerSaveData, 1);
- data->mgr = mgr;
- data->doc = xmlNewDoc (RB_PLAYLIST_MGR_VERSION);
- g_object_ref (mgr);
-
- root = xmlNewDocNode (data->doc, NULL, RB_PLAYLIST_MGR_PL, NULL);
- xmlDocSetRootElement (data->doc, root);
-
- gtk_tree_model_foreach (GTK_TREE_MODEL (mgr->priv->page_model),
- (GtkTreeModelForeachFunc)save_playlist_cb,
- root);
-
- /* mark clean here. if the save fails, we'll mark it dirty again */
- rb_playlist_manager_set_dirty (data->mgr, FALSE);
-
- if (force)
- rb_playlist_manager_save_data (data);
- else
- g_thread_create ((GThreadFunc) rb_playlist_manager_save_data, data, FALSE, NULL);
-
- return TRUE;
-}
-
-/**
- * rb_playlist_manager_new_playlist:
- * @mgr: the #RBPlaylistManager
- * @suggested_name: optional name to use for the new playlist
- * @automatic: if TRUE, create an auto playlist
- *
- * Creates a new playlist and adds it to the source list.
- *
- * Return value: (transfer none): the new playlist object.
- */
-RBSource *
-rb_playlist_manager_new_playlist (RBPlaylistManager *mgr,
- const char *suggested_name,
- gboolean automatic)
+ * Creates a new playlist and adds it to the source list.
+ *
+ * Return value: (transfer none): the new playlist object.
+ */
+RBSource *
+rb_playlist_manager_new_playlist (RBPlaylistManager *mgr,
+ const char *suggested_name,
+ gboolean automatic)
{
RBSource *playlist;
if (automatic)
@@ -1930,3 +1592,499 @@ rb_playlist_manager_export_playlist (RBPlaylistManager *mgr,
m3u_format);
return TRUE;
}
+
+static void
+playlist_manager_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ RBPlaylistManager *mgr)
+{
+ GError *error = NULL;
+ const char *name;
+ const char *uri;
+
+ if (g_strcmp0 (interface_name, RB_PLAYLIST_MANAGER_IFACE_NAME) != 0) {
+ rb_debug ("method call on unexpected interface %s", interface_name);
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ return;
+ }
+
+ if (g_strcmp0 (method_name, "getPlaylists") == 0) {
+ char **names;
+
+ rb_playlist_manager_get_playlist_names (mgr, &names, NULL);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new_strv ((const char * const *)names, -1));
+ g_strfreev (names);
+ } else if (g_strcmp0 (method_name, "createPlaylist") == 0) {
+ g_variant_get (parameters, "(&s)", &name);
+ if (rb_playlist_manager_create_static_playlist (mgr, name, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else if (g_strcmp0 (method_name, "deletePlaylist") == 0) {
+ g_variant_get (parameters, "(&s)", &name);
+ if (rb_playlist_manager_delete_playlist (mgr, name, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else if (g_strcmp0 (method_name, "addToPlaylist") == 0) {
+ g_variant_get (parameters, "(ss)", &name, &uri);
+ if (rb_playlist_manager_add_to_playlist (mgr, name, uri, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else if (g_strcmp0 (method_name, "removeFromPlaylist") == 0) {
+ g_variant_get (parameters, "(ss)", &name, &uri);
+ if (rb_playlist_manager_remove_from_playlist (mgr, name, uri, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else if (g_strcmp0 (method_name, "exportPlaylist") == 0) {
+ gboolean m3u_format;
+ g_variant_get (parameters, "(ssb)", &name, &uri, &m3u_format);
+ if (rb_playlist_manager_export_playlist (mgr, name, uri, m3u_format, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else if (g_strcmp0 (method_name, "importPlaylist") == 0) {
+ g_variant_get (parameters, "(s)", &uri);
+ if (rb_playlist_manager_parse_file (mgr, uri, &error)) {
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_clear_error (&error);
+ }
+ } else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NOT_SUPPORTED,
+ "Method %s.%s not supported",
+ interface_name,
+ method_name);
+ }
+}
+
+static const GDBusInterfaceVTable playlist_manager_vtable = {
+ (GDBusInterfaceMethodCallFunc) playlist_manager_method_call,
+ NULL,
+ NULL
+};
+
+static void
+rb_playlist_manager_set_uimanager (RBPlaylistManager *mgr,
+ GtkUIManager *uimanager)
+{
+ if (mgr->priv->uimanager != NULL) {
+ if (mgr->priv->actiongroup != NULL) {
+ gtk_ui_manager_remove_action_group (mgr->priv->uimanager,
+ mgr->priv->actiongroup);
+ }
+ g_object_unref (mgr->priv->uimanager);
+ }
+
+ mgr->priv->uimanager = uimanager;
+
+ if (mgr->priv->actiongroup == NULL) {
+ mgr->priv->actiongroup = gtk_action_group_new ("PlaylistManagerActions");
+ gtk_action_group_set_translation_domain (mgr->priv->actiongroup,
+ GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (mgr->priv->actiongroup,
+ rb_playlist_manager_actions,
+ rb_playlist_manager_n_actions,
+ mgr);
+ }
+
+ gtk_ui_manager_insert_action_group (mgr->priv->uimanager,
+ mgr->priv->actiongroup,
+ 0);
+}
+
+static void
+rb_playlist_manager_set_source (RBPlaylistManager *mgr,
+ RBSource *source)
+{
+ gboolean playlist_active;
+ gboolean playlist_local = FALSE;
+ gboolean party_mode;
+ gboolean can_save;
+ gboolean can_delete;
+ gboolean can_edit;
+ gboolean can_rename;
+ gboolean can_shuffle;
+ GtkAction *action;
+
+ party_mode = rb_shell_get_party_mode (mgr->priv->shell);
+
+ if (mgr->priv->selected_source != NULL) {
+ g_object_unref (mgr->priv->selected_source);
+ }
+ mgr->priv->selected_source = g_object_ref (source);
+
+ playlist_active = RB_IS_PLAYLIST_SOURCE (mgr->priv->selected_source);
+ if (playlist_active) {
+ g_object_get (mgr->priv->selected_source, "is-local", &playlist_local, NULL);
+ }
+
+ can_save = playlist_local && !party_mode;
+ action = gtk_action_group_get_action (mgr->priv->actiongroup,
+ "MusicPlaylistSavePlaylist");
+ gtk_action_set_visible (action, can_save);
+
+ can_delete = (playlist_local && !party_mode &&
+ !RB_IS_PLAY_QUEUE_SOURCE (mgr->priv->selected_source));
+ action = gtk_action_group_get_action (mgr->priv->actiongroup,
+ "MusicPlaylistDeletePlaylist");
+ gtk_action_set_visible (action, can_delete);
+
+ can_edit = (playlist_local && RB_IS_AUTO_PLAYLIST_SOURCE (mgr->priv->selected_source) &&
+ !party_mode);
+ action = gtk_action_group_get_action (mgr->priv->actiongroup,
+ "EditAutomaticPlaylist");
+ gtk_action_set_visible (action, can_edit);
+
+ can_rename = playlist_local && rb_source_can_rename (mgr->priv->selected_source);
+ action = gtk_action_group_get_action (mgr->priv->actiongroup,
+ "MusicPlaylistRenamePlaylist");
+ gtk_action_set_visible (action, can_rename);
+
+ can_shuffle = RB_IS_STATIC_PLAYLIST_SOURCE (mgr->priv->selected_source);
+ action = gtk_action_group_get_action (mgr->priv->actiongroup,
+ "ShufflePlaylist");
+ gtk_action_set_sensitive (action, can_shuffle);
+}
+
+static void
+rb_playlist_manager_set_shell_internal (RBPlaylistManager *mgr,
+ RBShell *shell)
+{
+ GtkUIManager *uimanager = NULL;
+ RhythmDB *db = NULL;
+
+ if (mgr->priv->db != NULL) {
+ g_object_unref (mgr->priv->db);
+ }
+
+ mgr->priv->shell = shell;
+
+ if (mgr->priv->shell != NULL) {
+ g_object_get (mgr->priv->shell,
+ "ui-manager", &uimanager,
+ "db", &db,
+ NULL);
+ }
+
+ mgr->priv->db = db;
+ rb_playlist_manager_set_uimanager (mgr, uimanager);
+}
+
+static void
+rb_playlist_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ RBPlaylistManager *mgr = RB_PLAYLIST_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_PLAYLIST_NAME:
+ g_free (mgr->priv->playlists_file);
+ mgr->priv->playlists_file = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_SOURCE:
+ rb_playlist_manager_set_source (mgr, g_value_get_object (value));
+ break;
+ case PROP_SHELL:
+ rb_playlist_manager_set_shell_internal (mgr, g_value_get_object (value));
+ break;
+ case PROP_DISPLAY_PAGE_MODEL:
+ mgr->priv->page_model = g_value_dup_object (value);
+ break;
+ case PROP_DISPLAY_PAGE_TREE:
+ mgr->priv->display_page_tree = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+rb_playlist_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ RBPlaylistManager *mgr = RB_PLAYLIST_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_PLAYLIST_NAME:
+ g_value_set_string (value, mgr->priv->playlists_file);
+ break;
+ case PROP_SOURCE:
+ g_value_set_object (value, mgr->priv->selected_source);
+ break;
+ case PROP_SHELL:
+ g_value_set_object (value, mgr->priv->shell);
+ break;
+ case PROP_DISPLAY_PAGE_MODEL:
+ g_value_set_object (value, mgr->priv->page_model);
+ break;
+ case PROP_DISPLAY_PAGE_TREE:
+ g_value_set_object (value, mgr->priv->display_page_tree);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+rb_playlist_manager_constructed (GObject *object)
+{
+ GDBusConnection *bus;
+ RBPlaylistManager *mgr = RB_PLAYLIST_MANAGER (object);
+
+ RB_CHAIN_GOBJECT_METHOD(rb_playlist_manager_parent_class, constructed, G_OBJECT (mgr));
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ if (bus) {
+ GDBusNodeInfo *node_info;
+ GError *error = NULL;
+
+ node_info = g_dbus_node_info_new_for_xml (rb_playlist_manager_dbus_spec, &error);
+ if (error != NULL) {
+ g_warning ("Unable to parse playlist manager dbus spec: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_dbus_connection_register_object (bus,
+ RB_PLAYLIST_MANAGER_DBUS_PATH,
+ g_dbus_node_info_lookup_interface (node_info, RB_PLAYLIST_MANAGER_IFACE_NAME),
+ &playlist_manager_vtable,
+ g_object_ref (mgr),
+ g_object_unref,
+ &error);
+ if (error != NULL) {
+ g_warning ("Unable to register playlist manager dbus object: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+}
+
+static void
+rb_playlist_manager_init (RBPlaylistManager *mgr)
+{
+ mgr->priv = G_TYPE_INSTANCE_GET_PRIVATE (mgr,
+ RB_TYPE_PLAYLIST_MANAGER,
+ RBPlaylistManagerPrivate);
+
+ mgr->priv->saving_mutex = g_mutex_new ();
+ mgr->priv->dirty = 0;
+ mgr->priv->saving = 0;
+}
+
+static void
+rb_playlist_manager_dispose (GObject *object)
+{
+ RBPlaylistManager *mgr;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object));
+
+ rb_debug ("Disposing playlist manager");
+
+ mgr = RB_PLAYLIST_MANAGER (object);
+
+ g_return_if_fail (mgr->priv != NULL);
+
+ if (mgr->priv->db != NULL) {
+ g_object_unref (mgr->priv->db);
+ mgr->priv->db = NULL;
+ }
+
+ if (mgr->priv->uimanager != NULL) {
+ g_object_unref (mgr->priv->uimanager);
+ mgr->priv->uimanager = NULL;
+ }
+
+ if (mgr->priv->page_model != NULL) {
+ g_object_unref (mgr->priv->page_model);
+ mgr->priv->page_model = NULL;
+ }
+
+ if (mgr->priv->display_page_tree != NULL) {
+ g_object_unref (mgr->priv->display_page_tree);
+ mgr->priv->display_page_tree = NULL;
+ }
+
+ if (mgr->priv->selected_source != NULL) {
+ g_object_unref (mgr->priv->selected_source);
+ mgr->priv->selected_source = NULL;
+ }
+
+ G_OBJECT_CLASS (rb_playlist_manager_parent_class)->dispose (object);
+}
+
+static void
+rb_playlist_manager_finalize (GObject *object)
+{
+ RBPlaylistManager *mgr;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object));
+
+ rb_debug ("Finalizing playlist manager");
+
+ mgr = RB_PLAYLIST_MANAGER (object);
+
+ g_return_if_fail (mgr->priv != NULL);
+
+ g_mutex_free (mgr->priv->saving_mutex);
+
+ g_free (mgr->priv->playlists_file);
+
+ G_OBJECT_CLASS (rb_playlist_manager_parent_class)->finalize (object);
+}
+
+
+static void
+rb_playlist_manager_class_init (RBPlaylistManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = rb_playlist_manager_constructed;
+ object_class->dispose = rb_playlist_manager_dispose;
+ object_class->finalize = rb_playlist_manager_finalize;
+
+ object_class->set_property = rb_playlist_manager_set_property;
+ object_class->get_property = rb_playlist_manager_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_PLAYLIST_NAME,
+ g_param_spec_string ("playlists_file",
+ "name",
+ "playlists file",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SOURCE,
+ g_param_spec_object ("source",
+ "RBSource",
+ "RBSource object",
+ RB_TYPE_SOURCE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SHELL,
+ g_param_spec_object ("shell",
+ "RBShell",
+ "RBShell object",
+ RB_TYPE_SHELL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_PAGE_MODEL,
+ g_param_spec_object ("display-page-model",
+ "RBDisplayPageModel",
+ "RBDisplayPageModel",
+ RB_TYPE_DISPLAY_PAGE_MODEL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_PAGE_TREE,
+ g_param_spec_object ("display-page-tree",
+ "RBDisplayPageTree",
+ "RBDisplayPageTree",
+ RB_TYPE_DISPLAY_PAGE_TREE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * RBPlaylistManager::playlist-added:
+ * @manager: the #RBPlaylistManager
+ * @source: the new #RBSource
+ *
+ * Emitted when a playlist is added, including when being loaded
+ * from the user's playlist file.
+ */
+ rb_playlist_manager_signals[PLAYLIST_ADDED] =
+ g_signal_new ("playlist_added",
+ RB_TYPE_PLAYLIST_MANAGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBPlaylistManagerClass, playlist_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, G_TYPE_OBJECT);
+
+ /**
+ * RBPlaylistManager::playlist-created:
+ * @manager: the #RBPlaylistManager
+ * @source: the newly created playlist #RBSource
+ *
+ * Emitted when a new playlist is created.
+ */
+ rb_playlist_manager_signals[PLAYLIST_CREATED] =
+ g_signal_new ("playlist_created",
+ RB_TYPE_PLAYLIST_MANAGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBPlaylistManagerClass, playlist_created),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, G_TYPE_OBJECT);
+
+ /**
+ * RBPlaylistManager::load-start:
+ * @manager: the #RBPlaylistManager
+ *
+ * Emitted when the playlist manager starts loading the user's
+ * playlist file.
+ */
+ rb_playlist_manager_signals[PLAYLIST_LOAD_START] =
+ g_signal_new ("load_start",
+ RB_TYPE_PLAYLIST_MANAGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBPlaylistManagerClass, load_start),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, G_TYPE_NONE);
+ /**
+ * RBPlaylistManager::load-finish
+ * @manager: the #RBPlaylistManager
+ *
+ * Emitted when the playlist manager finishes loading the user's
+ * playlist file.
+ */
+ rb_playlist_manager_signals[PLAYLIST_LOAD_FINISH] =
+ g_signal_new ("load_finish",
+ RB_TYPE_PLAYLIST_MANAGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBPlaylistManagerClass, load_finish),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, G_TYPE_NONE);
+
+ g_type_class_add_private (klass, sizeof (RBPlaylistManagerPrivate));
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]