static void on_properties_changed (DBusGProxy *player_proxy, const gchar *cInterface, GHashTable *pChangedProps, const gchar **cInvalidProps, gpointer data)
{
	g_return_if_fail (cInterface != NULL);
	cd_debug ("");
	GValue *v;
	if (strcmp (cInterface, "org.mpris.MediaPlayer2.Player") == 0)
	{
		v = g_hash_table_lookup (pChangedProps, "PlaybackStatus");
		if (v != NULL && G_VALUE_HOLDS_STRING (v))  // status has changed
		{
			const gchar *cStatus = g_value_get_string (v);  // "Playing", "Paused" or "Stopped"
			myData.iPlayingStatus = _extract_status (cStatus);
			cd_debug ("PlaybackStatus: Status: %s, %d", cStatus, myData.iPlayingStatus);
			
			if (myData.iPlayingStatus == PLAYER_PLAYING)  // le handler est stoppe lorsque le lecteur ne joue rien.
				cd_musicplayer_relaunch_handler ();
			
			cd_musicplayer_update_icon ();
		}
		
		v = g_hash_table_lookup (pChangedProps, "Metadata");
		if (v != NULL && G_VALUE_HOLDS_BOXED (v))
		{
			GHashTable *pMetadata = g_value_get_boxed (v);
			gboolean bTrackHasChanged = _extract_metadata (pMetadata);
			
			if (bTrackHasChanged)  // new song (song changed or started playing)
			{
				myData.iPlayingStatus = PLAYER_PLAYING;  // pour les lecteurs bugues comme Exaile qui envoit un statut "stop" au changement de musique sans envoyer de status "play" par la suite. On considere donc que si le lecteur joue une nouvelle musique, c'est qu'il est en "play".
				cd_musicplayer_update_icon ();
			}
		}
		
		v = g_hash_table_lookup (pChangedProps, "LoopStatus");
		if (v != NULL && G_VALUE_HOLDS_STRING (v))  // loop status has changed
		{
			const gchar *cStatus = g_value_get_string (v);  // "Playlist", "None"
			s_bIsLoop = (cStatus && strcmp (cStatus, "Playlist") == 0);
			cd_debug ("LoopStatus: %s, %d", cStatus, s_bIsLoop);
			s_bGotLoopStatus = TRUE;
		}
		
		v = g_hash_table_lookup (pChangedProps, "Shuffle");
		if (v != NULL && G_VALUE_HOLDS_BOOLEAN (v))  // Shuffle status has changed
		{
			s_bIsShuffle = g_value_get_boolean (v);
			cd_debug ("Shuffle: %d", s_bIsShuffle);
			s_bGotShuffleStatus = TRUE;
		}
	}
	/*else if (strcmp (cInterface, "org.mpris.MediaPlayer2.TrackList") == 0)
	{
		
	}*/
	else
		cd_debug ("Another interface: %s", cInterface);
}
/* Initialise le backend de QL.
 */
static void cd_quodlibet_start (void)
{
	// register to the signals
	dbus_g_proxy_add_signal(myData.dbus_proxy_player, "paused",
		G_TYPE_INVALID);
	dbus_g_proxy_connect_signal(myData.dbus_proxy_player, "paused",
		G_CALLBACK(on_pause), NULL, NULL);

	dbus_g_proxy_add_signal(myData.dbus_proxy_player, "unpaused",
		G_TYPE_NONE,
		G_TYPE_INVALID);  // idem.
	dbus_g_proxy_connect_signal(myData.dbus_proxy_player, "unpaused",
		G_CALLBACK(on_unpaused), NULL, NULL);

	dbus_g_proxy_add_signal(myData.dbus_proxy_player, "song-started",
		QL_DBUS_TYPE_SONG_METADATA,
		G_TYPE_INVALID);
	dbus_g_proxy_connect_signal(myData.dbus_proxy_player, "song-started",
		G_CALLBACK(onChangeSong), NULL, NULL);
	
	// get the current state.
	_quodlibet_getPlaying ();
	cd_quodlibet_getSongInfos ();
	cd_musicplayer_update_icon ();
}
/* Fonction executee à chaque changement de musique.
 */
static void onChangeSong(DBusGProxy *player_proxy, GHashTable *metadata, gpointer data)
{
	CD_APPLET_ENTER;
	cd_debug ("MP : %s ()", __func__);
	
	if (metadata != NULL)
	{
		_extract_metadata (metadata);
	}
	else
	{
		g_free (myData.cPlayingUri);
		myData.cPlayingUri = NULL;
		g_free (myData.cArtist);
		myData.cArtist = NULL;
		g_free (myData.cAlbum);
		myData.cAlbum = NULL;
		g_free (myData.cTitle);
		myData.cTitle = NULL;
		g_free (myData.cCoverPath);
		myData.cCoverPath = NULL;
		myData.iSongLength = 0;
		myData.iTrackNumber = 0;
		myData.cover_exist = FALSE;
	}
	cd_musicplayer_update_icon ();
	CD_APPLET_LEAVE ();
}
/* Fonction executée à chaque changement de musique.
 */
static void onChangeSong(DBusGProxy *player_proxy,const gchar *uri, gpointer data)
{
	cd_message ("MP : %s (%s)",__func__,uri);
	
	g_free (myData.cPlayingUri);
	if(uri != NULL && *uri != '\0')
	{
		myData.cPlayingUri = g_strdup (uri);
		myData.bIsRunning = TRUE;
		cd_rhythmbox_getSongInfos (TRUE);  // TRUE <=> get all
	}
	else
	{
		myData.cPlayingUri = NULL;
		myData.cover_exist = FALSE;
		
		g_free (myData.cArtist);
		myData.cArtist = NULL;
		g_free (myData.cAlbum);
		myData.cAlbum = NULL;
		g_free (myData.cTitle);
		myData.cTitle = NULL;
		g_free (myData.cCoverPath);
		myData.cCoverPath = NULL;
		myData.iSongLength = 0;
		myData.iTrackNumber = 0;
		
		cd_musicplayer_dbus_detect_player ();
	}
	cd_musicplayer_update_icon (TRUE);
}
/* Initialise le backend de EX.
 */
static void cd_exaile_configure (void)
{
	myData.DBus_commands.service = "org.exaile.DBusInterface";
	myData.DBus_commands.path = "/DBusInterfaceObject";
	myData.DBus_commands.interface = "org.exaile.DBusInterface";
	
	myData.dbus_enable = _cd_exaile_dbus_connect_to_bus ();  // se connecte au bus.
	if (myData.dbus_enable)
	{
		cd_musicplayer_dbus_detect_player ();  // on teste la presence de EX sur le bus <=> s'il est ouvert ou pas.
		if(myData.bIsRunning)  // player en cours d'execution, on recupere son etat.
		{
			g_print ("MP : EX is running\n");
			cd_exaile_getSongInfos ();
			cd_exaile_getCoverPath ();
			cd_musicplayer_update_icon (TRUE);
		}
		else  // player eteint.
		{
			cd_musicplayer_set_surface (PLAYER_NONE);
		}
	}
	else  // sinon on signale par l'icone appropriee que le bus n'est pas accessible.
	{
		cd_musicplayer_set_surface (PLAYER_BROKEN);
	}
}
/* Initialise le backend de EX.
 */
static void cd_exaile_start (void)
{
	// get the current state.
	cd_exaile_getSongInfos ();
	cd_exaile_getCoverPath ();
	cd_musicplayer_update_icon ();
}
static void _on_got_song_infos (DBusGProxy *proxy, DBusGProxyCall *call_id, GldiModuleInstance *myApplet)
{
	cd_debug ("=== %s ()", __func__);
	CD_APPLET_ENTER;
	s_pGetSongInfosCall = NULL;
	
	GHashTable *pMetadata = NULL;
	GValue v = G_VALUE_INIT;
	GError *erreur = NULL;
	dbus_g_proxy_end_call (proxy,
		call_id,
		&erreur,
		G_TYPE_VALUE, &v,
		G_TYPE_INVALID);
	if (erreur != NULL)
	{
		cd_warning ("couldn't get MPRIS song infos (%s)\n", erreur->message);
		g_error_free (erreur);
		pMetadata = NULL;
	}
	else
	{
		if (G_VALUE_HOLDS_BOXED (&v))
		{
			pMetadata = g_value_get_boxed (&v);  // since we don't destroy the value, we'll take care of the hash-table when we're done with it.
		}
	}
	if (pMetadata != NULL)
	{
		_extract_metadata (pMetadata);
		
		g_hash_table_destroy (pMetadata);
	}
	else
	{
		cd_warning ("  can't get song properties");
		g_free (myData.cPlayingUri);
		myData.cPlayingUri = NULL;
		g_free (myData.cTitle);
		myData.cTitle = NULL;
		g_free (myData.cAlbum);
		myData.cAlbum = NULL;
		g_free (myData.cArtist);
		myData.cArtist = NULL;
		g_free (myData.cCoverPath);
		myData.cCoverPath = NULL;
		myData.iSongLength = 0;
		myData.iTrackNumber = 0;
		myData.cover_exist = FALSE;
	}
	
	cd_musicplayer_update_icon ();
	cd_musicplayer_relaunch_handler ();
	
	CD_APPLET_LEAVE ();
}
/* Initialise le backend de RB.
 */
void cd_rhythmbox_configure (void)
{
	cd_debug ("");
	myData.DBus_commands.service = "org.gnome.Rhythmbox";
	myData.DBus_commands.path = "/org/gnome/Rhythmbox/Player";
	myData.DBus_commands.path2 = "/org/gnome/Rhythmbox/Shell";
	myData.DBus_commands.interface = "org.gnome.Rhythmbox.Player";
	myData.DBus_commands.interface2 = "org.gnome.Rhythmbox.Shell";
	myData.DBus_commands.play = "playPause";
	myData.DBus_commands.pause = "playPause";
	myData.DBus_commands.stop = "";
	myData.DBus_commands.next = "next";
	myData.DBus_commands.previous = "previous";
	
	myData.dbus_enable = cd_rhythmbox_dbus_connect_to_bus ();  // se connecte au bus et aux signaux de RB.
	if (myData.dbus_enable)
	{
		cd_musicplayer_dbus_detect_player ();  // on teste la presence de RB sur le bus <=> s'il est ouvert ou pas.
		if(myData.bIsRunning)  // player en cours d'execution, on recupere son etat.
		{
			g_print ("MP : RB is running");
			_rhythmbox_getPlaying();
			_rhythmbox_getPlayingUri();
			cd_rhythmbox_getSongInfos (TRUE);  // TRUE <=> get all
			cd_musicplayer_update_icon (TRUE);
		}
		else  // player eteint.
		{
			cd_musicplayer_set_surface (PLAYER_NONE);
		}
	}
	else  // sinon on signale par l'icone appropriee que le bus n'est pas accessible.
	{
		cd_musicplayer_set_surface (PLAYER_BROKEN);
	}
}