? compile ? py-compile ? backends/Makefile ? backends/Makefile.in ? backends/gstreamer/Makefile ? backends/gstreamer/Makefile.in ? bindings/Makefile ? bindings/Makefile.in ? bindings/python/Makefile ? bindings/python/Makefile.in ? bindings/python/rb.c ? bindings/python/rhythmdb.c ? help/es/.xml2po.mo ? help/es/rhythmbox.xml ? metadata/rhythmbox-metadata ? metadata/test-metadata ? plugins/Makefile ? plugins/Makefile.in ? plugins/audioscrobbler/Makefile ? plugins/audioscrobbler/Makefile.in ? plugins/audioscrobbler/audioscrobbler.rb-plugin ? plugins/lirc/Makefile ? plugins/lirc/Makefile.in ? plugins/pythonconsole/Makefile ? plugins/pythonconsole/Makefile.in ? plugins/pythonconsole/pythonconsole.rb-plugin ? plugins/sample/Makefile ? plugins/sample/Makefile.in ? plugins/sample-python/Makefile ? plugins/sample-python/Makefile.in ? shell/rb-playlist-manager-glue.h ? widgets/libsexy/Makefile ? widgets/libsexy/Makefile.in Index: acinclude.m4 =================================================================== RCS file: acinclude.m4 diff -N acinclude.m4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ acinclude.m4 12 Apr 2006 14:50:48 -0000 @@ -0,0 +1,40 @@ +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) +dnl +dnl example +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var"="x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) Index: configure.ac =================================================================== RCS file: /cvs/gnome/rhythmbox/configure.ac,v retrieving revision 1.228 diff -u -p -r1.228 configure.ac --- configure.ac 10 Apr 2006 13:18:03 -0000 1.228 +++ configure.ac 12 Apr 2006 14:50:48 -0000 @@ -650,6 +650,12 @@ if test "x$with_bonobo" != "xno"; then fi AM_CONDITIONAL(WITH_BONOBO, test "x$enable_bonobo" = "xyes") +dnl DBUS Service files dir +AS_AC_EXPAND(DATADIR, $datadir) +DBUS_SERVICES_DIR="$DATADIR/dbus-1/services" +AC_SUBST(DBUS_SERVICES_DIR) +AC_DEFINE_UNQUOTED(DBUS_SERVICES_DIR, "$DBUS_SERVICES_DIR", [Where services dir for DBUS is]) + AM_GCONF_SOURCE_2 dnl LIRC Index: data/.cvsignore =================================================================== RCS file: /cvs/gnome/rhythmbox/data/.cvsignore,v retrieving revision 1.6 diff -u -p -r1.6 .cvsignore --- data/.cvsignore 5 Jan 2006 14:15:58 -0000 1.6 +++ data/.cvsignore 12 Apr 2006 14:50:48 -0000 @@ -8,3 +8,4 @@ playlists.xml rhythmbox.pc rhythmbox.keys .arch-ids +org.gnome.Rhythmbox.service Index: data/art/Makefile.am =================================================================== RCS file: /cvs/gnome/rhythmbox/data/art/Makefile.am,v retrieving revision 1.24 diff -u -p -r1.24 Makefile.am --- data/art/Makefile.am 5 Apr 2006 13:59:16 -0000 1.24 +++ data/art/Makefile.am 12 Apr 2006 14:50:48 -0000 @@ -5,6 +5,7 @@ art_DATA = \ rhythmbox-set-star.png \ rhythmbox-unset-star.png \ rhythmbox-no-star.png \ + rhythmbox-buddies.png \ rhythmbox-podcast.png \ media-eject.png \ about-logo.png Index: data/art/rhythmbox-buddies.png =================================================================== RCS file: data/art/rhythmbox-buddies.png diff -N data/art/rhythmbox-buddies.png Binary files /dev/null and rhythmbox-buddies.png differ Index: data/art-clearlooks/Makefile.am =================================================================== RCS file: /cvs/gnome/rhythmbox/data/art-clearlooks/Makefile.am,v retrieving revision 1.3 diff -u -p -r1.3 Makefile.am --- data/art-clearlooks/Makefile.am 20 Oct 2005 16:42:13 -0000 1.3 +++ data/art-clearlooks/Makefile.am 12 Apr 2006 14:50:48 -0000 @@ -5,6 +5,7 @@ art_DATA = rhythmbox-playback-error.png rhythmbox-set-star.png \ rhythmbox-unset-star.png \ rhythmbox-no-star.png \ + $(top_srcdir)/data/art/rhythmbox-buddies.png \ rhythmbox-podcast.png \ about-logo.png Index: lib/rb-stock-icons.c =================================================================== RCS file: /cvs/gnome/rhythmbox/lib/rb-stock-icons.c,v retrieving revision 1.26 diff -u -p -r1.26 rb-stock-icons.c --- lib/rb-stock-icons.c 5 Apr 2006 13:59:16 -0000 1.26 +++ lib/rb-stock-icons.c 12 Apr 2006 14:50:48 -0000 @@ -36,6 +36,7 @@ const char RB_STOCK_SET_STAR[] = "rhythm const char RB_STOCK_UNSET_STAR[] = "rhythmbox-unset-star"; const char RB_STOCK_NO_STAR[] = "rhythmbox-no-star"; const char RB_STOCK_PODCAST[] = "rhythmbox-podcast"; +const char RB_STOCK_BUDDIES[] = "stock_people"; const char RB_STOCK_BROWSER[] = "stock_music-library"; const char GNOME_MEDIA_SHUFFLE[] = "stock_shuffle"; const char GNOME_MEDIA_REPEAT[] = "stock_repeat"; @@ -64,7 +65,8 @@ rb_stock_icons_init (void) GNOME_MEDIA_PLAYLIST, GNOME_MEDIA_AUTO_PLAYLIST, GNOME_MEDIA_EJECT, - RB_STOCK_BROWSER + RB_STOCK_BROWSER, + RB_STOCK_BUDDIES }; g_return_if_fail (factory == NULL); Index: lib/rb-stock-icons.h =================================================================== RCS file: /cvs/gnome/rhythmbox/lib/rb-stock-icons.h,v retrieving revision 1.23 diff -u -p -r1.23 rb-stock-icons.h --- lib/rb-stock-icons.h 12 Mar 2006 23:00:59 -0000 1.23 +++ lib/rb-stock-icons.h 12 Apr 2006 14:50:48 -0000 @@ -30,6 +30,7 @@ extern const char RB_STOCK_SET_STAR[]; extern const char RB_STOCK_UNSET_STAR[]; extern const char RB_STOCK_NO_STAR[]; extern const char RB_STOCK_PODCAST[]; +extern const char RB_STOCK_BUDDIES[]; extern const char RB_STOCK_BROWSER[]; extern const char GNOME_MEDIA_SHUFFLE[]; extern const char GNOME_MEDIA_REPEAT[]; Index: player/rb-player-gst.c =================================================================== RCS file: /cvs/gnome/rhythmbox/player/rb-player-gst.c,v retrieving revision 1.58 diff -u -p -r1.58 rb-player-gst.c --- player/rb-player-gst.c 23 Feb 2006 03:54:50 -0000 1.58 +++ player/rb-player-gst.c 12 Apr 2006 14:50:49 -0000 @@ -53,6 +53,7 @@ struct RBPlayerPrivate char *uri; GstElement *playbin; + GstElement *server_thread; gboolean can_signal_direct_error; GError *error; @@ -205,6 +206,9 @@ rb_player_finalize (GObject *object) gst_element_set_state (mp->priv->playbin, GST_STATE_NULL); + gst_element_set_state (mp->priv->server_thread, + GST_STATE_NULL); + rb_player_gst_free_playbin (mp); } @@ -219,6 +223,12 @@ rb_player_gst_free_playbin (RBPlayer *pl gst_object_unref (GST_OBJECT (player->priv->playbin)); player->priv->playbin = NULL; + + if (player->priv->server_thread == NULL) + return; + + gst_object_unref (GST_OBJECT (player->priv->server_thread)); + player->priv->server_thread = NULL; } static void @@ -297,6 +307,7 @@ eos_cb (GstElement *element, (GSourceFunc) emit_signal_idle, signal, destroy_idle_signal); +// gst_element_set_state (mp->priv->server_thread, GST_STATE_PAUSED); } static void @@ -515,16 +526,29 @@ rb_player_bus_cb (GstBus * bus, GstMessa #endif +static GstCaps * +get_tee_sink_caps (GstPad *pad) +{ + /* XXX who frees this? */ + return gst_caps_new_simple ("audio/x-raw-int", + "rate", GST_TYPE_INT_RANGE, 44100, G_MAXINT, + NULL); +} + + static gboolean rb_player_construct (RBPlayer *mp, GError **error) { char *element_name = NULL; - GstElement *sink, *fakesink; + GstElement *gconf, *bin, *tee, *nowplaying, *tcpserver, *queue; + GstElement *fakesink; + GstPad *tee_sink; /* playbin */ rb_debug ("constructing element \"playbin\""); mp->priv->playbin = gst_element_factory_make ("playbin", "playbin"); if (mp->priv->playbin == NULL) { + element_name = "playbin"; goto missing_element; } @@ -542,7 +566,7 @@ rb_player_construct (RBPlayer *mp, GErro "buffering", G_CALLBACK (buffering_cb), mp, 0); - + mp->priv->error_signal_id = g_signal_connect_object (G_OBJECT (mp->priv->playbin), "error", @@ -552,21 +576,116 @@ rb_player_construct (RBPlayer *mp, GErro g_signal_connect_object (G_OBJECT (mp->priv->playbin), "eos", G_CALLBACK (eos_cb), mp, 0); - /* Output sink */ - sink = gst_gconf_get_default_audio_sink (); #endif #ifdef HAVE_GSTREAMER_0_10 gst_bus_add_watch (gst_element_get_bus (GST_ELEMENT (mp->priv->playbin)), (GstBusFunc) rb_player_bus_cb, mp); +#endif + + bin = gst_bin_new ("bin"); + if (bin == NULL) { + element_name = "bin"; + goto missing_element; + } - /* Output sink */ - sink = gst_element_factory_make ("gconfaudiosink", "audiosink"); + tee = gst_element_factory_make ("tee", "tee"); + if (tee == NULL) { + element_name = "tee"; + goto missing_element; + } + + nowplaying = gst_element_factory_make ("nowplaying", "nowplaying"); + if (nowplaying == NULL) { + rb_debug ("No gst element nowplaying, not using it.."); + } + + tcpserver = gst_element_factory_make ("tcpserversink", "tcpserversink"); + if (tcpserver == NULL) { + element_name = "tcpserversink"; + goto missing_element; + } + +#if 0 + /* This snippet will be useful when gst has really socket support + * backing up for now + */ + unlink("/tmp/rb-buddymusic"); + g_object_set (G_OBJECT (tcpserver), + "socket-type", 1, + "address", "/tmp/rb-buddymusic", + "protocol", 1, + "sync-method", 0, + "timeout", 60*GST_SECOND, + "recover-policy", 0, + NULL); #endif - - /* if we could create the gconf sink use that, otherwise let playbin decide */ - if (sink != NULL) - g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", sink, NULL); + g_object_set (G_OBJECT (tcpserver), + "host", "localhost", + "port", 10334, + "protocol", 1, + "sync-method", 0, + "timeout", 60*GST_SECOND, + "recover-policy", 0, + NULL); + + queue = gst_element_factory_make ("queue", "queue"); + if (queue == NULL) { + element_name = "queue"; + goto missing_element; + } + + mp->priv->server_thread = gst_thread_new ("serverthread"); + if (mp->priv->server_thread == NULL) { + element_name = "thread"; + goto missing_element; + } + + gconf = gst_gconf_get_default_audio_sink (); + if (gconf == NULL) { + element_name = "gconfaudiosink"; + goto missing_element; + } + + gst_bin_add (GST_BIN (bin), tee); + gst_bin_add (GST_BIN (bin), queue); + gst_bin_add (GST_BIN (bin), gconf); + + gst_element_link (tee, gconf); + gst_element_link (tee, queue); + + tee_sink = gst_element_get_pad (tee, "sink"); + gst_pad_set_getcaps_function (tee_sink, (GstPadGetCapsFunction)get_tee_sink_caps); + gst_element_add_ghost_pad (bin, tee_sink, "sink"); + + /* Setup tcpserver thread */ + if (nowplaying != NULL) { + gst_bin_add (GST_BIN (mp->priv->server_thread), nowplaying); + } + gst_bin_add (GST_BIN (mp->priv->server_thread), tcpserver); + + if (nowplaying != NULL) + { + gst_element_link (queue, nowplaying); + gst_element_link (nowplaying, tcpserver); + } + else + { + gst_element_link (queue, tcpserver); + } + + if (bin == NULL) { + g_set_error (error, + RB_PLAYER_ERROR, + RB_PLAYER_ERROR_NO_AUDIO, + _("Could not create audio output element; check your settings")); + rb_player_gst_free_playbin (mp); + return FALSE; + } + gst_element_set_state (mp->priv->server_thread, GST_STATE_PLAYING); + + g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", bin, NULL); + if (mp->priv->cur_volume > 1.0) mp->priv->cur_volume = 1.0; if (mp->priv->cur_volume < 0.0) @@ -628,20 +747,24 @@ rb_player_sync_pipeline (RBPlayer *mp) { rb_debug ("syncing pipeline"); if (mp->priv->playing) { - rb_debug ("PLAYING pipeline"); + rb_debug ("PLAYING pipeline"); #ifdef HAVE_GSTREAMER_0_8 - if (gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING) == GST_STATE_FAILURE) { + if (gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING) == GST_STATE_FAILURE || + gst_element_set_state (mp->priv->server_thread, GST_STATE_PLAYING) == GST_STATE_FAILURE) { #elif HAVE_GSTREAMER_0_10 - if (gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + if (gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE || + gst_element_set_state (mp->priv->server_thread, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { #endif - return FALSE; + return FALSE; } } else { rb_debug ("PAUSING pipeline"); #ifdef HAVE_GSTREAMER_0_8 - if (gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED) == GST_STATE_FAILURE) { + if (gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED) == GST_STATE_FAILURE || + gst_element_set_state (mp->priv->server_thread,GST_STATE_PAUSED) == GST_STATE_FAILURE) { #elif HAVE_GSTREAMER_0_10 - if (gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { + if (gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE || + gst_element_set_state (mp->priv->server_thread,GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { #endif return FALSE; } @@ -994,6 +1117,7 @@ rb_player_set_time (RBPlayer *mp, long t #ifdef HAVE_GSTREAMER_0_8 gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED); + gst_element_set_state (mp->priv->server_thread, GST_STATE_PAUSED); #elif HAVE_GSTREAMER_0_10 if (gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_ASYNC) { /* FIXME: Use a timeout on get_state. Post a GError somewhere on failed? */ @@ -1001,6 +1125,12 @@ rb_player_set_time (RBPlayer *mp, long t g_warning ("Failed to pause pipeline before seek"); } } + if (gst_element_set_state (mp->priv->server_thread, GST_STATE_PAUSED) == GST_STATE_CHANGE_ASYNC) { + /* FIXME: Use a timeout on get_state. Post a GError somewhere on failed? */ + if (gst_element_get_state (mp->priv->server_thread, NULL, NULL, 3 * GST_SECOND) != GST_STATE_CHANGE_SUCCESS) { + g_warning ("Failed to pause pipeline before seek"); + } + } #endif #ifdef WITH_DAAP_SUPPORT @@ -1039,6 +1169,7 @@ rb_player_set_time (RBPlayer *mp, long t #endif if (mp->priv->playing) { gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING); + gst_element_set_state (mp->priv->server_thread, GST_STATE_PLAYING); } } Index: shell/rb-shell.c =================================================================== RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.c,v retrieving revision 1.426 diff -u -p -r1.426 rb-shell.c --- shell/rb-shell.c 11 Apr 2006 10:27:46 -0000 1.426 +++ shell/rb-shell.c 12 Apr 2006 14:50:49 -0000 @@ -77,6 +77,7 @@ #include "rb-daap-source.h" #include "rb-daap-sharing.h" #endif /* WITH_DAAP_SUPPORT */ +#include "rb-buddymusic-source.h" #include "rb-iradio-source.h" #include "rb-shell-preferences.h" #include "rb-playlist-source.h" @@ -387,6 +388,7 @@ struct RBShellPrivate RBLibrarySource *library_source; RBIRadioSource *iradio_source; + RBBuddyMusicSource *buddymusic_source; RBPodcastSource *podcast_source; RBPlaylistSource *queue_source; RBSource *missing_files_source; @@ -1164,8 +1166,13 @@ construct_sources (RBShell *shell) shell->priv->library_source = RB_LIBRARY_SOURCE (rb_library_source_new (shell)); rb_shell_append_source (shell, RB_SOURCE (shell->priv->library_source), NULL); + shell->priv->iradio_source = RB_IRADIO_SOURCE (rb_iradio_source_new (shell)); rb_shell_append_source (shell, RB_SOURCE (shell->priv->iradio_source), NULL); + + shell->priv->buddymusic_source = RB_BUDDYMUSIC_SOURCE (rb_buddymusic_source_new (shell)); + rb_shell_append_source (shell, RB_SOURCE (shell->priv->buddymusic_source), NULL); + shell->priv->podcast_source = RB_PODCAST_SOURCE (rb_podcast_source_new (shell)); rb_shell_append_source (shell, RB_SOURCE (shell->priv->podcast_source), NULL); Index: sources/.cvsignore =================================================================== RCS file: /cvs/gnome/rhythmbox/sources/.cvsignore,v retrieving revision 1.2 diff -u -p -r1.2 .cvsignore --- sources/.cvsignore 1 Sep 2003 04:21:15 -0000 1.2 +++ sources/.cvsignore 12 Apr 2006 14:50:49 -0000 @@ -1,3 +1,4 @@ Makefile Makefile.in .arch-ids +rb-buddymusic-source-dbus.h Index: sources/Makefile.am =================================================================== RCS file: /cvs/gnome/rhythmbox/sources/Makefile.am,v retrieving revision 1.38 diff -u -p -r1.38 Makefile.am --- sources/Makefile.am 10 Apr 2006 13:18:06 -0000 1.38 +++ sources/Makefile.am 12 Apr 2006 14:50:49 -0000 @@ -14,6 +14,9 @@ libsourcesimpl_la_SOURCES = \ rb-library-source.h \ rb-iradio-source.c \ rb-iradio-source.h \ + rb-buddymusic-source.c \ + rb-buddymusic-source.h \ + rb-buddymusic-source-dbus.h \ rb-podcast-source.c \ rb-podcast-source.h \ rb-removable-media-source.c \ @@ -41,7 +44,7 @@ libsourcesimpl_la_SOURCES = \ rb-psp-source.h INCLUDES = \ - -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -DG_LOG_DOMAIN=\"Rhythmbox\" \ -I$(top_srcdir) \ -I$(top_srcdir)/lib \ @@ -54,6 +57,7 @@ INCLUDES = \ -I$(top_srcdir)/library \ -I$(top_srcdir)/player \ -I$(top_srcdir)/iradio \ + -I$(top_srcdir)/remote \ -I$(top_srcdir)/podcast \ -I$(top_srcdir)/shell \ -I$(top_srcdir)/daapsharing \ @@ -62,6 +66,7 @@ INCLUDES = \ -DSHARE_DIR=\"$(pkgdatadir)\" \ -DDATADIR=\""$(datadir)"\" \ $(WARN_CFLAGS) \ + $(DBUS_CFLAGS) \ $(TOTEM_PLPARSER_CFLAGS) \ $(HAL_CFLAGS) \ $(LIBNAUTILUS_BURN_CFLAGS) \ @@ -69,6 +74,11 @@ INCLUDES = \ libsources_la_LDFLAGS = -export-dynamic libsourcesimpl_la_LDFLAGS = -export-dynamic +libsourcesimpl_la_LIBADD = $(DBUS_LIBS) + +EXTRA_DIST = rb-buddymusic-source.xml +BUILT_SOURCES = rb-buddymusic-source-dbus.h +CLEANFILES = $(BUILT_SOURCES) ipod_files = \ rb-ipod-source.c \ @@ -100,5 +110,8 @@ endif if ENABLE_TRACK_TRANSFER INCLUDES +=$(GNOME_MEDIA_PROFILES_CFLAGS) endif + +rb-buddymusic-source-dbus.h : rb-buddymusic-source.xml + dbus-binding-tool --prefix=rb_buddymusic_source --mode=glib-server $< > $@ EXTRA_DIST = $(ipod_files) $(hal_files) $(daap_files) Index: sources/rb-buddymusic-source.c =================================================================== RCS file: sources/rb-buddymusic-source.c diff -N sources/rb-buddymusic-source.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sources/rb-buddymusic-source.c 12 Apr 2006 14:50:49 -0000 @@ -0,0 +1,657 @@ +/* + * For use with gShrooms, provide a buddy music source to rhythmbox + * + * Copyright (C) 2005 Raphael Slinckx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "rb-buddymusic-source.h" + +#include "rb-buddymusic-source-dbus.h" + +#include "rb-entry-view.h" +#include "rb-debug.h" +#include "rb-stock-icons.h" +#include "rb-util.h" +#include "rb-preferences.h" +#include "rb-remote-proxy.h" + +#include +#include +#include +#include +#include + +#define CONF_STATE_BUDDYMUSIC_SORTING CONF_PREFIX "/state/buddymusic/sorting" + +#define RHYTHMDB_ENTRY_TYPE_BUDDYMUSIC (rhythmdb_entry_buddymusic_get_type ()) +#define RB_BUDDYMUSIC_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_BUDDYMUSIC_SOURCE, RBBuddyMusicSourcePrivate)) + +struct _RBBuddyMusicSourcePrivate { + RhythmDB *db; + RBEntryView *buddies; + + GHashTable *buddyuris; + GHashTable *buddyicons; +}; + +enum { + NEED_BUDDIES_SIGNAL, + LAST_SIGNAL, +}; +static guint object_signals[LAST_SIGNAL] = {0}; + +static RhythmDBEntryType rhythmdb_entry_buddymusic_get_type (void); + +static void rb_buddymusic_source_class_init (RBBuddyMusicSourceClass *klass); +static void rb_buddymusic_source_init (RBBuddyMusicSource *source); +static GObject *rb_buddymusic_source_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void rb_buddymusic_source_finalize (GObject *object); + +static void +rb_buddymusic_source_get_alias_cell_data(GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + RBBuddyMusicSource *source); +static void +rb_buddymusic_source_get_icon_cell_data(GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + RBBuddyMusicSource *source); + +static RBEntryView *rb_buddymusic_source_get_entry_view (RBSource *asource); +static char *rb_buddymusic_source_get_status (RBSource *asource); + +static void rb_buddymusic_source_do_query (RBBuddyMusicSource *source); + +static GObjectClass *parent_class = NULL; + +GType +rb_buddymusic_source_get_type (void) +{ + static GType rb_buddymusic_source_type = 0; + if (G_UNLIKELY (rb_buddymusic_source_type == 0)) + { + static const GTypeInfo our_info = + { + sizeof (RBBuddyMusicSourceClass), + NULL, + NULL, + (GClassInitFunc) rb_buddymusic_source_class_init, + NULL, + NULL, + sizeof (RBBuddyMusicSource), + 0, + (GInstanceInitFunc) rb_buddymusic_source_init + }; + rb_buddymusic_source_type = g_type_register_static (RB_TYPE_SOURCE, + "RBBuddyMusicSource", + &our_info, 0); + } + return rb_buddymusic_source_type; +} + +RhythmDBEntryType +rhythmdb_entry_buddymusic_get_type (void) +{ + static RhythmDBEntryType buddymusic_type = -1; + if (G_UNLIKELY (buddymusic_type == -1)) { + buddymusic_type = rhythmdb_entry_register_type (); + } + return buddymusic_type; +} + +static void +rb_buddymusic_source_class_init (RBBuddyMusicSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + RBSourceClass *source_class = RB_SOURCE_CLASS (klass); + GError *error = NULL; + + parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (klass, sizeof (RBBuddyMusicSourcePrivate)); + + /* GObject methods */ + object_class->constructor = rb_buddymusic_source_constructor; + object_class->finalize = rb_buddymusic_source_finalize; + + /* rb-source implementation */ + source_class->impl_get_entry_view = rb_buddymusic_source_get_entry_view; + source_class->impl_get_status = rb_buddymusic_source_get_status; + + /* rb-source capabilities */ + source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function; + source_class->impl_can_pause = (RBSourceFeatureFunc) rb_false_function; + source_class->impl_have_url = (RBSourceFeatureFunc) rb_true_function; + + /* DBus Signal */ + object_signals[NEED_BUDDIES_SIGNAL] = + g_signal_new ("need-buddies", + G_TYPE_FROM_CLASS (object_class), + (GSignalFlags)(G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (RBBuddyMusicSourceClass, need_buddies), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /* Init the DBus connection, per-klass */ + klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (klass->connection == NULL) + { + g_warning("Unable to connect to dbus: %s", error->message); + g_error_free (error); + return; + } + + dbus_g_object_type_install_info (RB_TYPE_BUDDYMUSIC_SOURCE, &dbus_glib_rb_buddymusic_source_object_info); +} + +static void +rb_buddymusic_source_init (RBBuddyMusicSource *source) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RBBuddyMusicSourceClass *klass = RB_BUDDYMUSIC_SOURCE_GET_CLASS (source); + GtkWidget *dummy; + GdkPixbuf *pixbuf; + GError *error = NULL; + DBusGProxy *driver_proxy; + guint request_name_ret; + + /* This hashtable contains (buddy-address, feed url) mappings */ + priv->buddyuris = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + /* This hashtable contains (icon filename, buddy pixbuf) mappings */ + priv->buddyicons = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + + /* Create the buddy source icon */ + dummy = gtk_tree_view_new (); + pixbuf = gtk_widget_render_icon (dummy, + RB_STOCK_BUDDIES, + GTK_ICON_SIZE_LARGE_TOOLBAR, + NULL); + rb_source_set_pixbuf (RB_SOURCE (source), pixbuf); + if (pixbuf != NULL) { + g_object_unref (pixbuf); + } + + gtk_widget_destroy (dummy); + + + /* Register DBUS path */ + dbus_g_connection_register_g_object (klass->connection, + "/org/gnome/Rhythmbox/BuddyMusic", + G_OBJECT (source)); + + /* Register the service name */ + driver_proxy = dbus_g_proxy_new_for_name (klass->connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + if(!org_freedesktop_DBus_request_name (driver_proxy, + "org.gnome.Rhythmbox.BuddyMusic", + 0, &request_name_ret, + &error)) + { + if (error != NULL) { + g_warning("Unable to register service: %s", error->message); + g_error_free (error); + } + else { + g_warning("Unable to register dbus service"); + } + } + g_object_unref (driver_proxy); +} + +static GObject * +rb_buddymusic_source_constructor (GType type, guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + RBBuddyMusicSource *source; + RBBuddyMusicSourceClass *klass; + RBBuddyMusicSourcePrivate *priv; + GObjectClass *parent_class; + RBShell *shell; + GObject *shell_player; + + klass = RB_BUDDYMUSIC_SOURCE_CLASS (g_type_class_peek (RB_TYPE_BUDDYMUSIC_SOURCE)); + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); + + source = RB_BUDDYMUSIC_SOURCE (parent_class->constructor (type, n_construct_properties, + construct_properties)); + priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + + g_object_get (source, "shell", &shell, NULL); + g_object_get (shell, "db", &priv->db, NULL); + shell_player = rb_shell_get_player (shell); + g_object_unref (shell); + + /* set up buddy list view */ + priv->buddies = rb_entry_view_new (priv->db, shell_player, NULL, FALSE, FALSE); + + /* The columns we need */ + /* A custom one for the buddy icon */ + { + GtkTreeViewColumn *column = gtk_tree_view_column_new (); + GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_fixed_width (column, 24); + + gtk_tree_view_column_set_clickable (column, TRUE); + gtk_tree_view_column_set_cell_data_func (column, + renderer, + (GtkTreeCellDataFunc) rb_buddymusic_source_get_icon_cell_data, + source, + NULL); + rb_entry_view_append_column_custom (priv->buddies, + column, + "", + "BuddyIcon", + NULL, + 0); + } + /* A custom one for the buddy alias, stored in prop_genre */ + { + GtkTreeViewColumn *column = gtk_tree_view_column_new (); + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_column_set_clickable (column, TRUE); + gtk_tree_view_column_set_cell_data_func (column, + renderer, + (GtkTreeCellDataFunc) rb_buddymusic_source_get_alias_cell_data, + source, + NULL); + rb_entry_view_append_column_custom (priv->buddies, + column, + "Buddy", + "BuddyAlias", + NULL, + 0); + } + rb_entry_view_append_column (priv->buddies, RB_ENTRY_VIEW_COL_ARTIST, FALSE); + rb_entry_view_append_column (priv->buddies, RB_ENTRY_VIEW_COL_ALBUM, FALSE); + rb_entry_view_append_column (priv->buddies, RB_ENTRY_VIEW_COL_TITLE, FALSE); + rb_entry_view_append_column (priv->buddies, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE); + + /* Show the list */ + gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (priv->buddies)); + gtk_widget_show_all (GTK_WIDGET (source)); + + /* Populate the buddy list */ + rb_buddymusic_source_do_query (source); + + /* Emit need buddy signal so we start receiving the existing buddies */ + g_signal_emit_by_name (source, "need-buddies"); + + return G_OBJECT (source); +} + +static void +rb_buddymusic_source_finalize (GObject *object) +{ + RBBuddyMusicSource *source; + RBBuddyMusicSourcePrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (RB_IS_BUDDYMUSIC_SOURCE (object)); + + source = RB_BUDDYMUSIC_SOURCE (object); + priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + + rb_debug ("finalizing buddymusic source"); + + /* Free stuff here */ + g_hash_table_destroy (priv->buddyuris); + g_hash_table_destroy (priv->buddyicons); + g_object_unref (priv->db); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +RBSource * +rb_buddymusic_source_new (RBShell *shell) +{ + RBSource *source; + + rb_debug ("init buddymusic source"); + source = RB_SOURCE (g_object_new (RB_TYPE_BUDDYMUSIC_SOURCE, + "name", _("Buddy Music"), + "shell", shell, + "visibility", TRUE, + NULL)); + + rb_shell_register_entry_type_for_source (shell, source, + RHYTHMDB_ENTRY_TYPE_BUDDYMUSIC); + + /* + rb_buddymusic_source_add_buddy (RB_BUDDYMUSIC_SOURCE (source), + "name@network.com", + "My buddy alias", + "/home/kikidonk/.gaim/icons/44709a87", + "http://127.0.0.1:10333", + &error); + + rb_buddymusic_source_update_buddy (RB_BUDDYMUSIC_SOURCE (source), + "name@network.com", + "Some artist", + "Album name", + "My own, precious, title", + &error); + */ + return source; +} + +static void +rb_buddymusic_source_get_icon_cell_data(GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + RBBuddyMusicSource *source) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RhythmDBEntry *entry; + const gchar *location; + GdkPixbuf *icon; + GError *error = NULL; + + /* Get the favicon filename */ + gtk_tree_model_get (tree_model, iter, 0, &entry, -1); + location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT); + if (location == NULL || *location == '\0') + { + g_object_set (G_OBJECT (renderer), "pixbuf", NULL, NULL); + return; + } + + icon = g_hash_table_lookup (priv->buddyicons, location); + if (icon == NULL) + { + rb_debug ("Requesting icon for alias: %s, loc: %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT), location); + icon = gdk_pixbuf_new_from_file_at_size (location, 24, 24, &error); + if (icon == NULL) + { + g_object_set (G_OBJECT (renderer), "pixbuf", NULL, NULL); + rb_debug ("Error while creating buddy icon: %s", error->message); + g_error_free (error); + return; + } + g_hash_table_insert (priv->buddyicons, g_strdup (location), icon); + } + + g_object_set (G_OBJECT (renderer), "pixbuf", icon, NULL); +} + +static void +rb_buddymusic_source_get_alias_cell_data(GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + RBBuddyMusicSource *source) +{ + RhythmDBEntry *entry; + const gchar *alias; + + gtk_tree_model_get (tree_model, iter, 0, &entry, -1); + alias = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_GENRE); + + g_object_set (G_OBJECT (renderer), "text", alias, NULL); +} + +static RBEntryView * +rb_buddymusic_source_get_entry_view (RBSource *asource) +{ + return RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (asource)->buddies; +} + +static char * +rb_buddymusic_source_get_status (RBSource *asource) +{ +/* RBBuddyMusicSource *source = RB_BUDDYMUSIC_SOURCE (asource); + + guint num_entries = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL); (RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source)->buddies); +*/ + RhythmDBQueryModel *model; + guint num_entries; + + g_object_get (G_OBJECT (asource), "query-model", &model, NULL); + num_entries = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL); + g_object_unref (G_OBJECT (model)); + + return g_strdup_printf ("%d buddies streaming music", num_entries); +} + +static void +rb_buddymusic_source_do_query (RBBuddyMusicSource *source) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RhythmDBQueryModel *query_model; + GPtrArray *query; + + /* The empty query model */ + query_model = rhythmdb_query_model_new_empty (priv->db); + + /* We want all entries of our TYPE */ + query = rhythmdb_query_parse (priv->db, + RHYTHMDB_QUERY_PROP_EQUALS, + RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_BUDDYMUSIC, + RHYTHMDB_QUERY_END); + + /* Update the entryview with our new model, + additions will be automagically reflected in the view */ + rb_entry_view_set_model (priv->buddies, query_model); + g_object_set (G_OBJECT (source), "query-model", query_model, NULL); + + /* Go on, search, and create the tree model */ + rhythmdb_do_full_query_parsed (priv->db, + RHYTHMDB_QUERY_RESULTS (query_model), + query); + + /* Cleanup */ + rhythmdb_query_free (query); + g_object_unref (query_model); +} + + +gboolean +rb_buddymusic_source_add_buddy (RBBuddyMusicSource *source, + gchar *name, + gchar *alias, + gchar *icon, + gchar *url, + GError **error) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RhythmDBEntry *entry; + GValue val = { 0, }; + + /* FIXME: this sucks, for now. + Buddy Alias stored in RHYTHMDB_PROP_GENRE + Buddy Icon stored in RHYTHMDB_PROP_MOUNTPOINT + Title, artist, album, in their respective values + */ + + rb_debug ("adding buddy, %s|%s|%s|%s", name, alias, icon, url); + + /* First remove anyone that has the same name, or we create dups */ + rb_buddymusic_source_remove_buddy (source, name, NULL); + + /* Remember the buddy url, given the buddy address */ + g_hash_table_insert (priv->buddyuris, g_strdup (name), g_strdup (url)); + + /* Create the new database entry for this buddy */ + entry = rhythmdb_entry_new (priv->db, RHYTHMDB_ENTRY_TYPE_BUDDYMUSIC, url); + + /* FIXME: see above */ + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, alias); + rhythmdb_entry_set_uninserted (priv->db, entry, RHYTHMDB_PROP_GENRE, &val); + g_value_unset (&val); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, icon); + rhythmdb_entry_set_uninserted (priv->db, entry, RHYTHMDB_PROP_MOUNTPOINT, &val); + g_value_unset (&val); + + /* Update the database */ + rhythmdb_commit (priv->db); + + return TRUE; +} + +gboolean +rb_buddymusic_source_update_buddy (RBBuddyMusicSource *source, + gchar *name, + gchar *artist, + gchar *album, + gchar *title, + GError **error) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RhythmDBEntry *entry; + GValue val = { 0, }; + gchar *url; + + rb_debug ("trying update buddy, %s|%s|%s|%s", name, artist, album, title); + + url = g_hash_table_lookup (priv->buddyuris, name); + rb_debug ("trying update: got url: %s", url); + if (url == NULL) + { + /* Noone has this name, ignoring */ + return TRUE; + } + + entry = rhythmdb_entry_lookup_by_location (priv->db, url); + rb_debug ("trying update: got entry: %p", entry); + if (entry == NULL) + { + /* Noone has that name, ignoring */ + return TRUE; + } + + rb_debug ("update buddy, %s|%s|%s|%s", name, artist, album, title); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, artist); + rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_ARTIST, &val); + g_value_unset (&val); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, album); + rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_ALBUM, &val); + g_value_unset (&val); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, title); + rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_TITLE, &val); + g_value_unset (&val); + + rhythmdb_commit (priv->db); + + return TRUE; +} + +gboolean +rb_buddymusic_source_remove_buddy (RBBuddyMusicSource *source, + gchar *name, + GError **error) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RhythmDBEntry *entry; + gchar *url; + const gchar *favicon; + + url = g_hash_table_lookup (priv->buddyuris, name); + if (url == NULL) + { + /* Noone has this name, ignoring */ + return TRUE; + } + entry = rhythmdb_entry_lookup_by_location (priv->db, url); + if (entry == NULL) + { + /* Noone has this name, ignoring */ + return TRUE; + } + + /* Remove it from the DB */ + g_hash_table_remove (priv->buddyuris, name); + favicon = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT); + if (favicon != NULL) + { + g_hash_table_remove (priv->buddyicons, favicon); + } + rhythmdb_entry_delete (priv->db, entry); + + /* Update the database */ + rhythmdb_commit (priv->db); + + return TRUE; +} + +gboolean +rb_buddymusic_source_play_stream (RBBuddyMusicSource *source, + gchar *name, + GError **error) +{ + RBBuddyMusicSourcePrivate *priv = RB_BUDDYMUSIC_SOURCE_GET_PRIVATE (source); + RBShell *shell; + RBRemoteProxy *proxy; + gchar *url; + gchar *playing; + + url = g_hash_table_lookup (priv->buddyuris, name); + if (url == NULL) + { + /* FIXME: is that ok ? Noone has this name, ignoring */ + return TRUE; + } + + /* Get the remote control */ + g_object_get (source, "shell", &shell, NULL); + proxy = RB_REMOTE_PROXY (shell); + + /* If the currently playing song isn't this one, then switch, otherwise + let it continue without interruption */ + playing = rb_remote_proxy_get_playing_uri (proxy); + rb_debug ("Currently playing: %s, want to play: %s", playing, url); + if (playing == NULL || strcmp (playing, url) != 0) + { + rb_debug ("Switching to new feed"); + rb_remote_proxy_play_uri (proxy, url); + } + + /* Grab the focus ! */ + rb_remote_proxy_select_uri (proxy, url); + rb_remote_proxy_grab_focus (proxy); + + /* Cleanup */ + g_free (playing); + g_object_unref (shell); + + return TRUE; +} Index: sources/rb-buddymusic-source.h =================================================================== RCS file: sources/rb-buddymusic-source.h diff -N sources/rb-buddymusic-source.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sources/rb-buddymusic-source.h 12 Apr 2006 14:50:49 -0000 @@ -0,0 +1,88 @@ +/* + * For use with gShrooms, provide a buddy music source to rhythmbox + * + * Copyright (C) 2005 Raphael Slinckx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __RB_BUDDYMUSIC_SOURCE_H +#define __RB_BUDDYMUSIC_SOURCE_H + +#include +#include "rb-shell.h" +#include "rb-source.h" +#include "rhythmdb.h" + +G_BEGIN_DECLS + +#define RB_TYPE_BUDDYMUSIC_SOURCE (rb_buddymusic_source_get_type ()) +#define RB_BUDDYMUSIC_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_BUDDYMUSIC_SOURCE, RBBuddyMusicSource)) +#define RB_BUDDYMUSIC_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_BUDDYMUSIC_SOURCE, RBBuddyMusicSourceClass)) +#define RB_IS_BUDDYMUSIC_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_BUDDYMUSIC_SOURCE)) +#define RB_IS_BUDDYMUSIC_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_BUDDYMUSIC_SOURCE)) +#define RB_BUDDYMUSIC_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_BUDDYMUSIC_SOURCE, RBBuddyMusicSourceClass)) + +typedef struct _RBBuddyMusicSource RBBuddyMusicSource; +typedef struct _RBBuddyMusicSourceClass RBBuddyMusicSourceClass; +typedef struct _RBBuddyMusicSourcePrivate RBBuddyMusicSourcePrivate; + +struct _RBBuddyMusicSource +{ + RBSource parent; + + RBBuddyMusicSourcePrivate *priv; +}; + +struct _RBBuddyMusicSourceClass +{ + RBSourceClass parent; + + DBusGConnection *connection; + + /* signals */ + void (* need_buddies) (RBBuddyMusicSource *self); +}; + +GType rb_buddymusic_source_get_type (void); + +RBSource * rb_buddymusic_source_new (RBShell *shell); + +gboolean rb_buddymusic_source_add_buddy (RBBuddyMusicSource *source, + gchar *name, + gchar *alias, + gchar *icon, + gchar *url, + GError **error); + +gboolean rb_buddymusic_source_update_buddy (RBBuddyMusicSource *source, + gchar *name, + gchar *artist, + gchar *album, + gchar *title, + GError **error); + +gboolean rb_buddymusic_source_remove_buddy (RBBuddyMusicSource *source, + gchar *name, + GError **error); + +gboolean rb_buddymusic_source_play_stream (RBBuddyMusicSource *source, + gchar *name, + GError **error); + +G_END_DECLS + +#endif /* __RB_BUDDYMUSIC_SOURCE_H */ Index: sources/rb-buddymusic-source.xml =================================================================== RCS file: sources/rb-buddymusic-source.xml diff -N sources/rb-buddymusic-source.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sources/rb-buddymusic-source.xml 12 Apr 2006 14:50:49 -0000 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +