[rhythmbox] Add magic to support selected-source actions



commit 1d264d8f60648d4157805613579ad8d52a118804
Author: Jonathan Matthew <jonathan d14n org>
Date:   Sat Dec 5 16:29:08 2009 +1000

    Add magic to support selected-source actions
    
    Actions that operate on the current selected source are pretty common,
    and so we had a pretty common pattern where a signal handler would go
    and find the selected source from the shell, check it was the right
    type, and then unref the source before returning.  This moves all of
    that (except the type check) into a GClosure wrapper, simplifying the
    signal handler code.

 plugins/audiocd/rb-audiocd-source.c               |   33 +++--
 plugins/daap/rb-daap-plugin.c                     |   35 +++---
 plugins/generic-player/rb-generic-player-plugin.c |   70 ++++------
 plugins/ipod/rb-ipod-plugin.c                     |  124 +++++-------------
 plugins/mtpdevice/rb-mtp-plugin.c                 |   53 ++------
 shell/rb-shell.c                                  |    1 +
 sources/rb-browser-source.c                       |   77 ++++-------
 sources/rb-source.c                               |  147 +++++++++++++++++----
 sources/rb-source.h                               |   15 ++-
 9 files changed, 276 insertions(+), 279 deletions(-)
---
diff --git a/plugins/audiocd/rb-audiocd-source.c b/plugins/audiocd/rb-audiocd-source.c
index 32792f9..0eb961b 100644
--- a/plugins/audiocd/rb-audiocd-source.c
+++ b/plugins/audiocd/rb-audiocd-source.c
@@ -77,7 +77,7 @@ static void impl_pack_paned (RBBrowserSource *source, GtkWidget *paned);
 
 #ifdef HAVE_SJ_METADATA_GETTER
 static void rb_audiocd_source_cmd_reload_metadata (GtkAction *action,
-						   RBAudioCdSource *source);
+						   RBSource *source);
 #endif
 
 static gpointer rb_audiocd_load_songs (RBAudioCdSource *source);
@@ -220,11 +220,6 @@ rb_audiocd_source_dispose (GObject *object)
 
 #ifdef HAVE_SJ_METADATA_GETTER
 	if (priv->action_group != NULL) {
-		GtkUIManager *uimanager;
-		g_object_get (object, "ui-manager", &uimanager, NULL);
-		gtk_ui_manager_remove_action_group (uimanager, priv->action_group);
-		g_object_unref (uimanager);
-
 		g_object_unref (priv->action_group);
 		priv->action_group = NULL;
 	}
@@ -255,11 +250,19 @@ rb_audiocd_source_constructed (GObject *object)
 	g_object_set (G_OBJECT (source), "name", "Unknown Audio", NULL);
 
 #ifdef HAVE_SJ_METADATA_GETTER
-	priv->action_group = _rb_source_register_action_group (RB_SOURCE (source),
-							       "AudiocdActions",
-							       rb_audiocd_source_actions,
-							       G_N_ELEMENTS (rb_audiocd_source_actions),
-							       source);
+	{
+		RBShell *shell;
+		g_object_get (source, "shell", &shell, NULL);
+		priv->action_group =
+			_rb_source_register_action_group (RB_SOURCE (source),
+							  "AudiocdActions",
+							  NULL, 0, NULL);
+		_rb_action_group_add_source_actions (priv->action_group,
+						     G_OBJECT (shell),
+						     rb_audiocd_source_actions,
+						     G_N_ELEMENTS (rb_audiocd_source_actions));
+		g_object_unref (shell);
+	}
 #endif
 	/* we want audio cds to sort by track# by default */
 	entry_view = rb_source_get_entry_view (RB_SOURCE (source));
@@ -580,12 +583,14 @@ rb_audiocd_scan_songs (RBAudioCdSource *source,
 
 #ifdef HAVE_SJ_METADATA_GETTER
 static void
-rb_audiocd_source_cmd_reload_metadata (GtkAction *action, RBAudioCdSource *source)
+rb_audiocd_source_cmd_reload_metadata (GtkAction *action, RBSource *source)
 {
 	RhythmDB *db;
 
-	db = get_db_for_source (source);
-	rb_audiocd_load_metadata (source, db);
+	g_return_if_fail (RB_IS_AUDIOCD_SOURCE (source));
+
+	db = get_db_for_source (RB_AUDIOCD_SOURCE (source));
+	rb_audiocd_load_metadata (RB_AUDIOCD_SOURCE (source), db);
 	g_object_unref (db);
 }
 
diff --git a/plugins/daap/rb-daap-plugin.c b/plugins/daap/rb-daap-plugin.c
index 52edc7c..4c3b335 100644
--- a/plugins/daap/rb-daap-plugin.c
+++ b/plugins/daap/rb-daap-plugin.c
@@ -103,7 +103,7 @@ static void impl_activate (RBPlugin *plugin, RBShell *shell);
 static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
 
 static GtkWidget* impl_create_configure_dialog (RBPlugin *plugin);
-static void rb_daap_plugin_cmd_disconnect (GtkAction *action, RBDaapPlugin *plugin);
+static void rb_daap_plugin_cmd_disconnect (GtkAction *action, RBSource *source);
 static void rb_daap_plugin_cmd_connect (GtkAction *action, RBDaapPlugin *plugin);
 
 static void create_pixbufs (RBDaapPlugin *plugin);
@@ -120,16 +120,20 @@ gboolean rb_daap_remove_source (RBDaapPlugin *plugin, gchar *service_name, GErro
 
 RB_PLUGIN_REGISTER(RBDaapPlugin, rb_daap_plugin)
 
-static GtkActionEntry rb_daap_source_actions [] =
+static GtkActionEntry rb_daap_plugin_actions [] =
 {
-	{ "DaapSourceDisconnect", GTK_STOCK_DISCONNECT, N_("_Disconnect"), NULL,
-	  N_("Disconnect from DAAP share"),
-	  G_CALLBACK (rb_daap_plugin_cmd_disconnect) },
 	{ "MusicNewDAAPShare", GTK_STOCK_CONNECT, N_("Connect to _DAAP share..."), NULL,
 	  N_("Connect to a new DAAP share"),
 	  G_CALLBACK (rb_daap_plugin_cmd_connect) },
 };
 
+static GtkActionEntry rb_daap_source_actions[] =
+{
+	{ "DaapSourceDisconnect", GTK_STOCK_DISCONNECT, N_("_Disconnect"), NULL,
+	  N_("Disconnect from DAAP share"),
+	  G_CALLBACK (rb_daap_plugin_cmd_disconnect) },
+};
+
 static void
 rb_daap_plugin_class_init (RBDaapPluginClass *klass)
 {
@@ -246,8 +250,12 @@ impl_activate (RBPlugin *bplugin,
 	gtk_action_group_set_translation_domain (plugin->priv->daap_action_group,
 						 GETTEXT_PACKAGE);
 	gtk_action_group_add_actions (plugin->priv->daap_action_group,
-				      rb_daap_source_actions, G_N_ELEMENTS (rb_daap_source_actions),
+				      rb_daap_plugin_actions, G_N_ELEMENTS (rb_daap_plugin_actions),
 				      plugin);
+	_rb_action_group_add_source_actions (plugin->priv->daap_action_group,
+					     G_OBJECT (shell),
+					     rb_daap_source_actions,
+					     G_N_ELEMENTS (rb_daap_source_actions));
 	gtk_ui_manager_insert_action_group (uimanager, plugin->priv->daap_action_group, 0);
 
 	/* add UI */
@@ -601,25 +609,14 @@ enable_browsing_changed_cb (GConfClient *client,
 /* daap share connect/disconnect commands */
 
 static void
-rb_daap_plugin_cmd_disconnect (GtkAction *action,
-			       RBDaapPlugin *plugin)
+rb_daap_plugin_cmd_disconnect (GtkAction *action, RBSource *source)
 {
-	RBSource *source;
-
-	g_object_get (plugin->priv->shell,
-		      "selected-source", &source,
-		      NULL);
-
 	if (!RB_IS_DAAP_SOURCE (source)) {
-		g_critical ("got non-Daap source for Daap action");
+		g_warning ("got non-Daap source for Daap action");
 		return;
 	}
 
 	rb_daap_source_disconnect (RB_DAAP_SOURCE (source));
-
-	if (source != NULL) {
-		g_object_unref (source);
-	}
 }
 
 static void
diff --git a/plugins/generic-player/rb-generic-player-plugin.c b/plugins/generic-player/rb-generic-player-plugin.c
index 17b7c08..7891dae 100644
--- a/plugins/generic-player/rb-generic-player-plugin.c
+++ b/plugins/generic-player/rb-generic-player-plugin.c
@@ -85,10 +85,8 @@ static void rb_generic_player_plugin_finalize (GObject *object);
 static void impl_activate (RBPlugin *plugin, RBShell *shell);
 static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
 
-static void rb_generic_player_plugin_new_playlist (GtkAction *action,
-						   RBGenericPlayerPlugin *plugin);
-static void rb_generic_player_plugin_delete_playlist (GtkAction *action,
-						      RBGenericPlayerPlugin *plugin);
+static void rb_generic_player_plugin_new_playlist (GtkAction *action, RBSource *source);
+static void rb_generic_player_plugin_delete_playlist (GtkAction *action, RBSource *source);
 
 RB_PLUGIN_REGISTER(RBGenericPlayerPlugin, rb_generic_player_plugin)
 
@@ -142,53 +140,40 @@ rb_generic_player_plugin_source_deleted (RBGenericPlayerSource *source, RBGeneri
 }
 
 static void
-rb_generic_player_plugin_new_playlist (GtkAction *action, RBGenericPlayerPlugin *plugin)
+rb_generic_player_plugin_new_playlist (GtkAction *action, RBSource *source)
 {
-	RBSource *source;
+	RBShell *shell;
 	RBSourceList *sourcelist;
+	RBSource *playlist;
+	RhythmDBEntryType entry_type;
 
-	g_object_get (plugin->shell,
-		      "selected-source", &source,
-		      "sourcelist", &sourcelist,
+	g_return_if_fail (RB_IS_GENERIC_PLAYER_SOURCE (source));
+	g_object_get (source,
+		      "shell", &shell,
+		      "entry-type", &entry_type,
 		      NULL);
-	if (source != NULL && RB_IS_GENERIC_PLAYER_SOURCE (source)) {
-		RBSource *playlist;
-		RhythmDBEntryType entry_type;
-
-		g_object_get (source, "entry-type", &entry_type, NULL);
 
-		playlist = rb_generic_player_playlist_source_new (plugin->shell, RB_GENERIC_PLAYER_SOURCE (source), NULL, NULL, entry_type);
-		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	playlist = rb_generic_player_playlist_source_new (shell, RB_GENERIC_PLAYER_SOURCE (source), NULL, NULL, entry_type);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
 
-		rb_generic_player_source_add_playlist (RB_GENERIC_PLAYER_SOURCE (source),
-						       plugin->shell,
-						       playlist);
+	rb_generic_player_source_add_playlist (RB_GENERIC_PLAYER_SOURCE (source),
+					       shell,
+					       playlist);
 
-		rb_sourcelist_edit_source_name (sourcelist, playlist);
-	}
-
-	if (source != NULL) {
-		g_object_unref (source);
-	}
+	g_object_get (shell, "sourcelist", &sourcelist, NULL);
+	rb_sourcelist_edit_source_name (sourcelist, playlist);
 	g_object_unref (sourcelist);
+
+	g_object_unref (shell);
 }
 
 static void
-rb_generic_player_plugin_delete_playlist (GtkAction *actino, RBGenericPlayerPlugin *plugin)
+rb_generic_player_plugin_delete_playlist (GtkAction *action, RBSource *source)
 {
-	RBSource *source;
-	
-	g_object_get (plugin->shell,
-		      "selected-source", &source,
-		      NULL);
-	if (source != NULL && RB_IS_GENERIC_PLAYER_PLAYLIST_SOURCE (source)) {
-		if (RB_IS_GENERIC_PLAYER_PLAYLIST_SOURCE (source)) {
-			rb_generic_player_playlist_delete_from_player (RB_GENERIC_PLAYER_PLAYLIST_SOURCE (source));
-			rb_source_delete_thyself (source);
-		}
+	g_return_if_fail (RB_IS_GENERIC_PLAYER_PLAYLIST_SOURCE (source));
 
-		g_object_unref (source);
-	}
+	rb_generic_player_playlist_delete_from_player (RB_GENERIC_PLAYER_PLAYLIST_SOURCE (source));
+	rb_source_delete_thyself (source);
 }
 
 static RBSource *
@@ -206,10 +191,11 @@ create_source_cb (RBRemovableMediaManager *rmm, GMount *mount, MPIDDevice *devic
 	if (plugin->actions == NULL) {
 		plugin->actions = gtk_action_group_new ("GenericPlayerActions");
 		gtk_action_group_set_translation_domain (plugin->actions, GETTEXT_PACKAGE);
-		gtk_action_group_add_actions (plugin->actions,
-					      rb_generic_player_plugin_actions,
-					      G_N_ELEMENTS (rb_generic_player_plugin_actions),
-					      plugin);
+
+		_rb_action_group_add_source_actions (plugin->actions,
+						     G_OBJECT (plugin->shell),
+						     rb_generic_player_plugin_actions,
+						     G_N_ELEMENTS (rb_generic_player_plugin_actions));
 	}
 
 	if (source) {
diff --git a/plugins/ipod/rb-ipod-plugin.c b/plugins/ipod/rb-ipod-plugin.c
index 26fa38b..d15ba7e 100644
--- a/plugins/ipod/rb-ipod-plugin.c
+++ b/plugins/ipod/rb-ipod-plugin.c
@@ -88,16 +88,11 @@ static RBSource * create_source_cb (RBRemovableMediaManager *rmm,
 				    GMount *mount,
 				    MPIDDevice *device_info,
 				    RBIpodPlugin *plugin);
-static void  rb_ipod_plugin_cmd_rename (GtkAction *action,
-					RBIpodPlugin *plugin);
-static void  rb_ipod_plugin_cmd_playlist_new (GtkAction *action,
-					RBIpodPlugin *plugin);
-static void  rb_ipod_plugin_cmd_playlist_rename (GtkAction *action,
-					RBIpodPlugin *plugin);
-static void  rb_ipod_plugin_cmd_playlist_delete (GtkAction *action,
-					RBIpodPlugin *plugin);
-static void  rb_ipod_plugin_cmd_properties (GtkAction *action,
-					    RBIpodPlugin *plugin);
+static void  rb_ipod_plugin_cmd_rename (GtkAction *action, RBSource *source);
+static void  rb_ipod_plugin_cmd_playlist_new (GtkAction *action, RBSource *source);
+static void  rb_ipod_plugin_cmd_playlist_rename (GtkAction *action, RBSource *source);
+static void  rb_ipod_plugin_cmd_playlist_delete (GtkAction *action, RBSource *source);
+static void  rb_ipod_plugin_cmd_properties (GtkAction *action, RBSource *source);
 
 RB_PLUGIN_REGISTER(RBIpodPlugin, rb_ipod_plugin)
 
@@ -175,9 +170,10 @@ impl_activate (RBPlugin *bplugin,
 	plugin->action_group = gtk_action_group_new ("iPodActions");
 	gtk_action_group_set_translation_domain (plugin->action_group,
 						 GETTEXT_PACKAGE);
-	gtk_action_group_add_actions (plugin->action_group,
-				      rb_ipod_plugin_actions, G_N_ELEMENTS (rb_ipod_plugin_actions),
-				      plugin);
+	_rb_action_group_add_source_actions (plugin->action_group,
+					     G_OBJECT (shell),
+					     rb_ipod_plugin_actions,
+					     G_N_ELEMENTS (rb_ipod_plugin_actions));
 	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
 	file = rb_plugin_find_file (bplugin, "ipod-ui.xml");
 	plugin->ui_merge_id = gtk_ui_manager_add_ui_from_file (uimanager,
@@ -264,125 +260,69 @@ create_source_cb (RBRemovableMediaManager *rmm, GMount *mount, MPIDDevice *devic
 }
 
 static void
-rb_ipod_plugin_cmd_properties (GtkAction *action,
-			       RBIpodPlugin *plugin)
+rb_ipod_plugin_cmd_properties (GtkAction *action, RBSource *source)
 {
-	RBSource *source = NULL;
-
-	g_object_get (G_OBJECT (plugin->shell), 
-		      "selected-source", &source,
-		      NULL);
-	if ((source == NULL) || !RB_IS_IPOD_SOURCE (source)) {
-		g_critical ("got iPodSourceProperties action for non-ipod source");
-		return;
-	}
-
+	g_return_if_fail (RB_IS_IPOD_SOURCE (source));
 	rb_ipod_source_show_properties (RB_IPOD_SOURCE (source));
-	g_object_unref (G_OBJECT (source));
 }
  
 static void
-rb_ipod_plugin_cmd_rename (GtkAction *action,
-			   RBIpodPlugin *plugin)
+rb_ipod_plugin_cmd_rename (GtkAction *action, RBSource *source)
 {
 	RBSourceList *sourcelist = NULL;
-	RBSource *source = NULL;
+	RBShell *shell;
+
+	g_return_if_fail (RB_IS_IPOD_SOURCE (source));
 
 	/* FIXME: this is pretty ugly, the sourcelist should automatically add
 	 * a "rename" menu item for sources that have can_rename == TRUE.
 	 * This is a bit trickier to handle though, since playlists want
 	 * to make rename sensitive/unsensitive instead of showing/hiding it
 	 */
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      NULL);
-	if ((source == NULL) || !RB_IS_IPOD_SOURCE (source)) {
-		g_critical ("got iPodSourceRename action for non-ipod source");
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
 
-	g_object_get (plugin->shell, "sourcelist", &sourcelist, NULL);
+	g_object_get (source, "shell", &shell, NULL);
+	g_object_get (shell, "sourcelist", &sourcelist, NULL);
 
 	rb_sourcelist_edit_source_name (sourcelist, source);
 	/* Once editing is done, notify::name will be fired on the source, and
 	 * we'll catch that in our rename callback
 	 */
 	g_object_unref (sourcelist);
-	g_object_unref (source);
+	g_object_unref (shell);
 }
 
 static void
-rb_ipod_plugin_cmd_playlist_rename (GtkAction *action,
-			   RBIpodPlugin *plugin)
+rb_ipod_plugin_cmd_playlist_rename (GtkAction *action, RBSource *source)
 {
-	RBSource *source = NULL;
 	RBSourceList *sourcelist = NULL;
+	RBShell *shell;
 
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      "sourcelist", &sourcelist,
-		      NULL);
-
-	if ((source == NULL) || !RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (source)) {
-		g_critical ("got iPodPlaylistSourceRename action for non-ipod playlist source");
-		g_object_unref (sourcelist);
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
+	g_return_if_fail (RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (source));
 
+	g_object_get (source, "shell", &shell, NULL);
+	g_object_get (shell, "sourcelist", &sourcelist, NULL);
 	rb_sourcelist_edit_source_name (sourcelist, source);
-
 	g_object_unref (sourcelist);
-	g_object_unref (source);
+	g_object_unref (shell);
 }
 
 static void
-rb_ipod_plugin_cmd_playlist_delete (GtkAction *action,
-			   RBIpodPlugin *plugin)
+rb_ipod_plugin_cmd_playlist_delete (GtkAction *action, RBSource *source)
 {
-	RBIpodStaticPlaylistSource *source = NULL;
+	RBIpodStaticPlaylistSource *psource;
 	RBiPodSource *ipod_source;
 
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      NULL);
-
-	if ((source == NULL) || !RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (source)) {
-		g_critical ("got iPodPlaylistSourceDelete action for non-ipod playlist source");
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
-
-	/* delete playlist*/
-	ipod_source = rb_ipod_static_playlist_source_get_ipod_source (source);
-	rb_ipod_source_remove_playlist (ipod_source, RB_SOURCE (source));
+	g_return_if_fail (RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (source));
+	psource = RB_IPOD_STATIC_PLAYLIST_SOURCE (source);
 
-	g_object_unref (source);
+	ipod_source = rb_ipod_static_playlist_source_get_ipod_source (psource);
+	rb_ipod_source_remove_playlist (ipod_source, source);
 }
 
 static void
-rb_ipod_plugin_cmd_playlist_new (GtkAction *action,
-			   RBIpodPlugin *plugin)
+rb_ipod_plugin_cmd_playlist_new (GtkAction *action, RBSource *source)
 {
-	RBSource *source = NULL;
-
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      NULL);
-
-	if ((source == NULL) || !RB_IS_IPOD_SOURCE (source)) {
-		g_critical ("got iPodSourceRename action for non-ipod source");
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
-
+	g_return_if_fail (RB_IS_IPOD_SOURCE (source));
 	rb_ipod_source_new_playlist (RB_IPOD_SOURCE (source));
-
-	g_object_unref (source);
 }
 
diff --git a/plugins/mtpdevice/rb-mtp-plugin.c b/plugins/mtpdevice/rb-mtp-plugin.c
index 897e8f1..00ef886 100644
--- a/plugins/mtpdevice/rb-mtp-plugin.c
+++ b/plugins/mtpdevice/rb-mtp-plugin.c
@@ -108,8 +108,8 @@ static void rb_mtp_plugin_device_added (LibHalContext *context, const char *udi)
 static void rb_mtp_plugin_device_removed (LibHalContext *context, const char *udi);
 static gboolean rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin);
 #endif
-static void rb_mtp_plugin_eject  (GtkAction *action, RBMtpPlugin *plugin);
-static void rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin);
+static void rb_mtp_plugin_eject  (GtkAction *action, RBSource *source);
+static void rb_mtp_plugin_rename (GtkAction *action, RBSource *source);
 
 GType rb_mtp_src_get_type (void);
 GType rb_mtp_sink_get_type (void);
@@ -185,9 +185,10 @@ impl_activate (RBPlugin *bplugin, RBShell *shell)
 	plugin->action_group = gtk_action_group_new ("MTPActions");
 	gtk_action_group_set_translation_domain (plugin->action_group,
 						 GETTEXT_PACKAGE);
-	gtk_action_group_add_actions (plugin->action_group,
-				      rb_mtp_plugin_actions, G_N_ELEMENTS (rb_mtp_plugin_actions),
-				      plugin);
+	_rb_action_group_add_source_actions (plugin->action_group,
+					     G_OBJECT (plugin->shell),
+					     rb_mtp_plugin_actions,
+					     G_N_ELEMENTS (rb_mtp_plugin_actions));
 	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
 	file = rb_plugin_find_file (bplugin, "mtp-ui.xml");
 	plugin->ui_merge_id = gtk_ui_manager_add_ui_from_file (uimanager, file, NULL);
@@ -282,51 +283,27 @@ impl_deactivate (RBPlugin *bplugin, RBShell *shell)
 }
 
 static void
-rb_mtp_plugin_eject (GtkAction *action, RBMtpPlugin *plugin)
+rb_mtp_plugin_eject (GtkAction *action, RBSource *source)
 {
-	RBSourceList *sourcelist = NULL;
-	RBSource *source = NULL;
-
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      NULL);
-	if ((source == NULL) || !RB_IS_MTP_SOURCE (source)) {
-		g_warning ("got MTPSourceEject action for non-mtp source");
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
-
-	g_object_get (plugin->shell, "sourcelist", &sourcelist, NULL);
-
+	g_return_if_fail (RB_IS_MTP_SOURCE (source));
 	rb_source_delete_thyself (source);
-
-	g_object_unref (sourcelist);
-	g_object_unref (source);
 }
 
 static void
-rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin)
+rb_mtp_plugin_rename (GtkAction *action, RBSource *source)
 {
-	RBSourceList *sourcelist = NULL;
-	RBSource *source = NULL;
+	RBShell *shell;
+	RBSourceList *sourcelist;
 
-	g_object_get (G_OBJECT (plugin->shell),
-		      "selected-source", &source,
-		      NULL);
-	if ((source == NULL) || !RB_IS_MTP_SOURCE (source)) {
-		g_warning ("got MTPSourceEject action for non-mtp source");
-		if (source != NULL)
-			g_object_unref (source);
-		return;
-	}
+	g_return_if_fail (RB_IS_MTP_SOURCE (source));
 
-	g_object_get (plugin->shell, "sourcelist", &sourcelist, NULL);
+	g_object_get (source, "shell", &shell, NULL);
+	g_object_get (shell, "sourcelist", &sourcelist, NULL);
 
 	rb_sourcelist_edit_source_name (sourcelist, source);
 
 	g_object_unref (sourcelist);
-	g_object_unref (source);
+	g_object_unref (shell);
 }
 
 
diff --git a/shell/rb-shell.c b/shell/rb-shell.c
index dc80c00..34f0554 100644
--- a/shell/rb-shell.c
+++ b/shell/rb-shell.c
@@ -2329,6 +2329,7 @@ static gboolean
 quit_timeout (gpointer dummy)
 {
 	GDK_THREADS_ENTER ();
+	rb_debug ("quit damn you");
 	gtk_main_quit ();
 	GDK_THREADS_LEAVE ();
 	return FALSE;
diff --git a/sources/rb-browser-source.c b/sources/rb-browser-source.c
index 5f954aa..6c97de1 100644
--- a/sources/rb-browser-source.c
+++ b/sources/rb-browser-source.c
@@ -77,12 +77,9 @@ static void rb_browser_source_get_property (GObject *object,
 			                  guint prop_id,
 			                  GValue *value,
 			                  GParamSpec *pspec);
-static void rb_browser_source_cmd_choose_genre (GtkAction *action,
-						RBShell *shell);
-static void rb_browser_source_cmd_choose_artist (GtkAction *action,
-						 RBShell *shell);
-static void rb_browser_source_cmd_choose_album (GtkAction *action,
-						RBShell *shell);
+static void rb_browser_source_cmd_choose_genre (GtkAction *action, RBSource *source);
+static void rb_browser_source_cmd_choose_artist (GtkAction *action, RBSource *source);
+static void rb_browser_source_cmd_choose_album (GtkAction *action, RBSource *source);
 static void songs_view_sort_order_changed_cb (RBEntryView *view, RBBrowserSource *source);
 static void rb_browser_source_browser_changed_cb (RBLibraryBrowser *entry,
 						  GParamSpec *param,
@@ -361,9 +358,11 @@ rb_browser_source_constructed (GObject *object)
 
 	source->priv->action_group = _rb_source_register_action_group (RB_SOURCE (source),
 								       "BrowserSourceActions",
-								       rb_browser_source_actions,
-								       G_N_ELEMENTS (rb_browser_source_actions),
-								       shell);
+								       NULL, 0, NULL);
+	_rb_action_group_add_source_actions (source->priv->action_group,
+					     G_OBJECT (shell),
+					     rb_browser_source_actions,
+					     G_N_ELEMENTS (rb_browser_source_actions));
 
 	/* only add the actions if we haven't already */
 	if (gtk_action_group_get_action (source->priv->action_group,
@@ -573,65 +572,49 @@ rb_browser_source_populate (RBBrowserSource *source)
 	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
 }
 
-
 static void
-rb_browser_source_cmd_choose_genre (GtkAction *action,
-				    RBShell *shell)
+browse_property (RBBrowserSource *source, RhythmDBPropType prop)
 {
 	GList *props;
-	RBBrowserSource *source;
 	RBPropertyView *view;
 
-	rb_debug ("choosing genre");
-
-	g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
-	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_GENRE);
-	view = rb_library_browser_get_property_view (source->priv->browser, RHYTHMDB_PROP_GENRE);
-	if (view)
+	props = rb_source_gather_selected_properties (RB_SOURCE (source), prop);
+	view = rb_library_browser_get_property_view (source->priv->browser, prop);
+	if (view) {
 		rb_property_view_set_selection (view, props);
+	}
 
 	rb_list_deep_free (props);
-	g_object_unref (source);
 }
 
 static void
-rb_browser_source_cmd_choose_artist (GtkAction *action,
-				     RBShell *shell)
+rb_browser_source_cmd_choose_genre (GtkAction *action, RBSource *source)
 {
-	GList *props;
-	RBBrowserSource *source;
-	RBPropertyView *view;
+	rb_debug ("choosing genre");
 
-	rb_debug ("choosing artist");
+	if (RB_IS_BROWSER_SOURCE (source)) {
+		browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_GENRE);
+	}
+}
 
-	g_object_get (shell, "selected-source", &source, NULL);
-	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_ARTIST);
-	view = rb_library_browser_get_property_view (source->priv->browser, RHYTHMDB_PROP_ARTIST);
-	if (view)
-		rb_property_view_set_selection (view, props);
+static void
+rb_browser_source_cmd_choose_artist (GtkAction *action, RBSource *source)
+{
+	rb_debug ("choosing artist");
 
-	rb_list_deep_free (props);
-	g_object_unref (source);
+	if (RB_IS_BROWSER_SOURCE (source)) {
+		browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_ARTIST);
+	}
 }
 
 static void
-rb_browser_source_cmd_choose_album (GtkAction *action,
-				    RBShell *shell)
+rb_browser_source_cmd_choose_album (GtkAction *action, RBSource *source)
 {
-	GList *props;
-	RBBrowserSource *source;
-	RBPropertyView *view;
-
 	rb_debug ("choosing album");
 
-	g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
-	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_ALBUM);
-	view = rb_library_browser_get_property_view (source->priv->browser, RHYTHMDB_PROP_ALBUM);
-	if (view)
-		rb_property_view_set_selection (view, props);
-
-	rb_list_deep_free (props);
-	g_object_unref (source);
+	if (RB_IS_BROWSER_SOURCE (source)) {
+		browse_property (RB_BROWSER_SOURCE (source), RHYTHMDB_PROP_ALBUM);
+	}
 }
 
 static void
diff --git a/sources/rb-source.c b/sources/rb-source.c
index 2630492..aafbe01 100644
--- a/sources/rb-source.c
+++ b/sources/rb-source.c
@@ -1656,6 +1656,26 @@ rb_source_gather_selected_properties (RBSource *source,
 	return tem;
 }
 
+static GtkActionGroup *
+find_action_group (GtkUIManager *uimanager, const char *group_name)
+{
+	GList *actiongroups;
+	GList *i;
+	actiongroups = gtk_ui_manager_get_action_groups (uimanager);
+
+	/* Don't create the action group if it's already registered */
+	for (i = actiongroups; i != NULL; i = i->next) {
+		const char *name;
+
+		name = gtk_action_group_get_name (GTK_ACTION_GROUP (i->data));
+		if (name != NULL && strcmp (name, group_name) == 0) {
+			return GTK_ACTION_GROUP (i->data);
+		}
+	}
+
+	return NULL;
+}
+
 /**
  * _rb_source_register_action_group:
  * @source: a #RBSource
@@ -1676,40 +1696,121 @@ _rb_source_register_action_group (RBSource *source,
 				  gpointer user_data)
 {
 	GtkUIManager *uimanager;
-	GList *actiongroups;
-	GList *i;
 	GtkActionGroup *group;
 
 	g_return_val_if_fail (group_name != NULL, NULL);
 
 	g_object_get (source, "ui-manager", &uimanager, NULL);
-	actiongroups = gtk_ui_manager_get_action_groups (uimanager);
+	group = find_action_group (uimanager, group_name);
+	if (group == NULL) {
+		group = gtk_action_group_new (group_name);
+		gtk_action_group_set_translation_domain (group,
+							 GETTEXT_PACKAGE);
+		if (actions != NULL) {
+			gtk_action_group_add_actions (group,
+						      actions, num_actions,
+						      user_data);
+		}
+		gtk_ui_manager_insert_action_group (uimanager, group, 0);
+	} else {
+		g_object_ref (group);
+	}
+	g_object_unref (uimanager);
 
-	/* Don't create the action group if it's already registered */
-	for (i = actiongroups; i != NULL; i = i->next) {
-		const char *name;
+	return group;
+}
 
-		name = gtk_action_group_get_name (GTK_ACTION_GROUP (i->data));
-		if (name != NULL && strcmp (name, group_name) == 0) {
-			group = GTK_ACTION_GROUP (i->data);
-			/* Add a reference */
-			g_object_ref (group);
-			goto out;
-		}
+typedef void (*SourceActionCallback) (GtkAction *action, RBSource *source);
+
+typedef struct {
+	SourceActionCallback callback;
+	/*RBShell *shell;*/
+	gpointer shell;
+} SourceActionData;
+
+static void
+source_action_data_destroy (SourceActionData *data)
+{
+	if (data->shell != NULL) {
+		g_object_remove_weak_pointer (G_OBJECT (data->shell), &data->shell);
 	}
+	g_slice_free (SourceActionData, data);
+}
 
-	group = gtk_action_group_new (group_name);
-	gtk_action_group_set_translation_domain (group,
-						 GETTEXT_PACKAGE);
-	gtk_action_group_add_actions (group,
-				      actions, num_actions,
-				      user_data);
-	gtk_ui_manager_insert_action_group (uimanager, group, 0);
+static void
+source_action_cb (GtkAction *action, SourceActionData *data)
+{
+	RBSource *source;
 
- out:
-	g_object_unref (uimanager);
+	if (data->shell == NULL) {
+		return;
+	}
 
-	return group;
+	/* get current source */
+	g_object_get (G_OBJECT (data->shell), "selected-source", &source, NULL);
+	if (source != NULL) {
+		data->callback (action, source);
+		g_object_unref (source);
+	}
+}
+
+/**
+ * _rb_action_group_add_source_actions:
+ * @group: a #GtkActionGroup
+ * @shell: the #RBShell
+ * @actions: array of GtkActionEntry structures for the action group
+ * @num_actions: number of actions in the @actions array
+ *
+ * Adds actions to an action group where the action callback is
+ * called with the current selected source.  This can safely be called
+ * multiple times on the same action group.
+ */
+void
+_rb_action_group_add_source_actions (GtkActionGroup *group,
+				     GObject *shell,
+				     GtkActionEntry *actions,
+				     int num_actions)
+{
+	int i;
+	for (i = 0; i < num_actions; i++) {
+		GtkAction *action;
+		const char *label;
+		const char *tooltip;
+		SourceActionData *source_action_data;
+
+		if (gtk_action_group_get_action (group, actions[i].name) != NULL) {
+			/* action was already added */
+			continue;
+		}
+
+		label = gtk_action_group_translate_string (group, actions[i].label);
+		tooltip = gtk_action_group_translate_string (group, actions[i].tooltip);
+
+		action = gtk_action_new (actions[i].name, label, tooltip, NULL);
+		if (actions[i].stock_id != NULL) {
+			g_object_set (action, "stock-id", actions[i].stock_id, NULL);
+			if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
+						     actions[i].stock_id)) {
+				g_object_set (action, "icon-name", actions[i].stock_id, NULL);
+			}
+		}
+
+		if (actions[i].callback) {
+			GClosure *closure;
+			source_action_data = g_slice_new0 (SourceActionData);
+			source_action_data->callback = (SourceActionCallback) actions[i].callback;
+			source_action_data->shell = shell;
+			g_object_add_weak_pointer (shell, &source_action_data->shell);
+
+			closure = g_cclosure_new (G_CALLBACK (source_action_cb),
+						  source_action_data,
+						  (GClosureNotify) source_action_data_destroy);
+			g_signal_connect_closure (action, "activate", closure, FALSE);
+		}
+
+		gtk_action_group_add_action_with_accel (group, action, actions[i].accelerator);
+		g_object_unref (action);
+	}
 }
 
 /**
diff --git a/sources/rb-source.h b/sources/rb-source.h
index b32b80c..9d5f004 100644
--- a/sources/rb-source.h
+++ b/sources/rb-source.h
@@ -51,6 +51,12 @@ typedef enum {
 	RB_SOURCE_SEARCH_EXPLICIT,
 } RBSourceSearchType;
 
+typedef struct _RBSource	RBSource;
+typedef struct _RBSourceClass	RBSourceClass;
+typedef struct _RBSourcePrivate	RBSourcePrivate;
+
+typedef void (*RBSourceActionCallback) (GtkAction *action, RBSource *source);
+
 GType rb_source_eof_type_get_type (void);
 #define RB_TYPE_SOURCE_EOF_TYPE	(rb_source_eof_type_get_type())
 
@@ -66,10 +72,6 @@ GType rb_source_search_type_get_type (void);
 
 #define RB_SOURCE_ICON_SIZE	GTK_ICON_SIZE_LARGE_TOOLBAR
 
-typedef struct _RBSource	RBSource;
-typedef struct _RBSourceClass	RBSourceClass;
-typedef struct _RBSourcePrivate	RBSourcePrivate;
-
 typedef gboolean (*RBSourceFeatureFunc) (RBSource *source);
 typedef const char * (*RBSourceStringFunc) (RBSource *source);
 
@@ -221,6 +223,11 @@ GtkActionGroup *_rb_source_register_action_group (RBSource *source,
 						  GtkActionEntry *actions,
 						  int num_actions,
 						  gpointer user_data);
+void		_rb_action_group_add_source_actions (GtkActionGroup *group,
+						     GObject *shell,
+						     GtkActionEntry *actions,
+						     int num_actions);
+
 gboolean	_rb_source_check_entry_type	(RBSource *source,
 						 RhythmDBEntry *entry);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]