Revised rhythmbox patches
- From: Lee Willis <lee lee-and-claire co uk>
- To: dashboard-hackers gnome org
- Subject: Revised rhythmbox patches
- Date: Fri, 19 Dec 2003 10:00:16 +0000
I've attached revised frontend and backend patches for rhythmbox.
The frontend patches are in response to feedback from Colin (Rhythmbox
maintainer) on http://bugzilla.gnome.org/show_bug.cgi?id=117083
The backend patch just checks the version of the rhythmbox library file.
If anyone can shed light on the following it would be helpful (In case
Colin thinks we need to be more portable?)
---------------------------------------------------------
The following change is required to make the dashboard cluepacket code
compile under -Wall -Werror
--- shell/Makefile.am 16 Dec 2003 15:37:00 -0000 1.36
+++ shell/Makefile.am 19 Dec 2003 09:31:40 -0000
@@ -85,7 +85,7 @@
-DDATADIR=\""$(datadir)"\" \
$(WARN_CFLAGS) \
$(RHYTHMBOX_CFLAGS) \
- -D_XOPEN_SOURCE
+ -D_GNU_SOURCE
Unfortunately without it the function getdtablesize() is undefined and
I don't know an alternative?
----------------------------------------------------------
Thanks
Lee
--
Lee Willis <lee lee-and-claire co uk>
Index: backends/backend-rhythmboxlibrary.cs
===================================================================
RCS file: /cvs/gnome/dashboard/backends/backend-rhythmboxlibrary.cs,v
retrieving revision 1.3
diff -u -r1.3 backend-rhythmboxlibrary.cs
--- backends/backend-rhythmboxlibrary.cs 12 Dec 2003 04:03:13 -0000 1.3
+++ backends/backend-rhythmboxlibrary.cs 19 Dec 2003 09:56:39 -0000
@@ -36,7 +36,7 @@
doc = new XmlDocument ();
doc.Load (path);
- songs = doc.SelectNodes ("//entry");
+ songs = doc.SelectNodes ("/rhythmdb[ version=\"1.0\"]/entry");
Console.WriteLine ("RB: Backend loaded {0} songs", songs.Count);
// FIXME: need to subscribe to clues that we
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.66
diff -u -u -r1.66 configure.ac
--- configure.ac 18 Dec 2003 03:28:24 -0000 1.66
+++ configure.ac 19 Dec 2003 09:31:40 -0000
@@ -60,6 +60,17 @@
AC_DEFINE(WITH_RHYTHMDB_TREE, 1, [Define if you are using the RhythmDB tree database])
fi
+dnl dashboard support
+AC_ARG_ENABLE(dashboard,
+ [ --disable-dashboard Disable dashboard support (http://www.nat.org/dashboard) (default enabled)])
+if test "x$enable_dashboard" = "xno" ; then
+ echo "Disabling dashboard support"
+else
+ echo "Building dashboard support"
+ enable_dashboard=yes
+ AC_DEFINE([WITH_DASHBOARD], 1, [Define to enable support for dashboard (http://www.nat.org/dashboard)])
+fi
+
dnl Sound system
AC_ARG_WITH(player,
AC_HELP_STRING([--with-player=gstreamer|xine],[Select the player to use]),,
@@ -489,6 +500,11 @@
AC_MSG_NOTICE([** MPEG-4 support is enabled])
fi
fi
+if test x"$enable_dashboard" != "xyes"; then
+ AC_MSG_NOTICE([ Dashboard support is disabled])
+else
+ AC_MSG_NOTICE([** Dashboard support is enabled])
+fi
dnl if test x"$enable_musicbrainz" != "xyes"; then
dnl AC_MSG_NOTICE([ MusicBrainz support is disabled])
dnl else
Index: shell/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/Makefile.am,v
retrieving revision 1.36
diff -u -u -r1.36 Makefile.am
--- shell/Makefile.am 16 Dec 2003 15:37:00 -0000 1.36
+++ shell/Makefile.am 19 Dec 2003 09:31:40 -0000
@@ -85,7 +85,7 @@
-DDATADIR=\""$(datadir)"\" \
$(WARN_CFLAGS) \
$(RHYTHMBOX_CFLAGS) \
- -D_XOPEN_SOURCE
+ -D_GNU_SOURCE
if USE_MONKEYMEDIA
INCLUDES += -I$(top_srcdir)/metadata/monkey-media
Index: shell/rb-dashboard.c
===================================================================
RCS file: shell/rb-dashboard.c
diff -N shell/rb-dashboard.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ shell/rb-dashboard.c 19 Dec 2003 09:31:40 -0000
@@ -0,0 +1,354 @@
+#ifndef __DASHBOARD_FRONTEND_H__
+#define __DASHBOARD_FRONTEND_H__
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#if GLIB_CHECK_VERSION (2,0,0)
+#include <glib/giochannel.h>
+#endif
+
+#define DASHBOARD_PORT 5913
+#define NATMIN(a,b) ((a) < (b) ? (a) : (b))
+
+/*
+ * Open a connection to the dashboard. We never block and at
+ * the first sign of a problem we bail.
+ */
+static int
+dashboard_connect_with_timeout (int *fd,
+ long timeout_usecs)
+{
+ struct sockaddr_in sock;
+ struct timeval timeout;
+ fd_set write_fds;
+
+ *fd = socket (PF_INET, SOCK_STREAM, 0);
+ if (*fd < 0) {
+ perror ("Dashboard: socket");
+ return 0;
+ }
+
+ /*
+ * Set the socket to be non-blocking so that connect ()
+ * doesn't block.
+ */
+ if (fcntl (*fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror ("Dashboard: setting O_NONBLOCK");
+ return 0;
+ }
+
+ bzero ((char *) &sock, sizeof (sock));
+ sock.sin_family = AF_INET;
+ sock.sin_port = htons (DASHBOARD_PORT);
+ sock.sin_addr.s_addr = inet_addr ("127.0.0.1");
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = timeout_usecs;
+
+ while (1) {
+
+ /*
+ * Try to connect.
+ */
+ if (connect (*fd, (struct sockaddr *) &sock,
+ sizeof (struct sockaddr_in)) < 0) {
+
+ if (errno != EAGAIN &&
+ errno != EINPROGRESS) {
+ perror ("Dashboard: connect");
+ return 0;
+ }
+
+ } else
+ return 1;
+
+ /*
+ * We couldn't connect, so we select on the fd and
+ * wait for the timer to run out, or for the fd to be
+ * ready.
+ */
+ FD_ZERO (&write_fds);
+ FD_SET (*fd, &write_fds);
+
+ while (select (getdtablesize (), NULL, &write_fds, NULL, &timeout) < 0) {
+ if (errno != EINTR) {
+ perror ("Dashboard: select");
+ return 0;
+ }
+ }
+
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+ fprintf (stderr, "Dashboard: Connection timed out.\n");
+ return 0;
+ }
+
+ }
+
+ return 1;
+}
+
+typedef struct {
+ char *rawcluepacket;
+ int bytes_written;
+} CluepacketInfo;
+
+#if GLIB_CHECK_VERSION(2,0,0)
+
+static gboolean
+cluepacket_write_cb (GIOChannel *channel,
+ GIOCondition cond,
+ gpointer user_data)
+{
+ CluepacketInfo *info = user_data;
+ GIOError err;
+ int total_bytes;
+
+ total_bytes = strlen (info->rawcluepacket);
+
+ do {
+ int b;
+
+ err = g_io_channel_write (channel,
+ info->rawcluepacket + info->bytes_written,
+ total_bytes - info->bytes_written,
+ &b);
+ info->bytes_written += b;
+ } while (info->bytes_written < total_bytes && err == G_IO_ERROR_NONE);
+
+ if (err == G_IO_ERROR_NONE) {
+ /* We're all done sending */
+ fprintf (stderr, "Dashboard: Sent.\n");
+ goto cleanup;
+ }
+
+ if (err == G_IO_ERROR_AGAIN) {
+ /* Hand control back to the main loop */
+ return TRUE;
+ }
+
+ /* Otherwise... */
+ fprintf (stderr, "Dashboard: Error trying to send cluepacket.\n");
+
+cleanup:
+ g_io_channel_close (channel);
+ g_free (info->rawcluepacket);
+ g_free (info);
+
+ return FALSE;
+}
+
+static void
+dashboard_send_raw_cluepacket (const char *rawcluepacket)
+{
+ int fd;
+ GIOChannel *channel;
+ CluepacketInfo *info;
+
+ fprintf (stderr, "Dashboard: Sending cluepacket...\n");
+
+ /* Connect. */
+ if (! dashboard_connect_with_timeout (&fd, 200000))
+ return;
+
+ channel = g_io_channel_unix_new (fd);
+
+ info = g_new0 (CluepacketInfo, 1);
+ info->rawcluepacket = g_strdup (rawcluepacket);
+
+ g_io_add_watch (channel,
+ G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ cluepacket_write_cb,
+ info);
+
+ g_io_channel_unref (channel);
+}
+
+#endif /* GLIB_CHECK_VERSION (2,0,0) */
+
+#if !GLIB_CHECK_VERSION (2,0,0)
+static char *
+lame_xml_quote (const char *str)
+{
+ char *retval;
+ const char *p;
+ char *q;
+
+ if (str == NULL || strlen (str) == 0)
+ return g_strdup ("");
+
+ retval = g_new (char, strlen (str) * 3);
+
+ q = retval;
+ for (p = str; *p != '\0'; p ++) {
+ switch (*p) {
+
+ case '<':
+ *q ++ = '&';
+ *q ++ = 'l';
+ *q ++ = 't';
+ *q ++ = ';';
+ break;
+
+ case '>':
+ *q ++ = '&';
+ *q ++ = 'g';
+ *q ++ = 't';
+ *q ++ = ';';
+ break;
+
+ case '&':
+ *q ++ = '&';
+ *q ++ = 'a';
+ *q ++ = 'm';
+ *q ++ = 'p';
+ *q ++ = ';';
+ break;
+ default:
+ *q ++ = *p;
+ break;
+ }
+ }
+
+ *q = '\0';
+
+ return retval;
+}
+#endif
+
+static char *
+dashboard_xml_quote (const char *str)
+{
+#if GLIB_CHECK_VERSION (2,0,0)
+ return g_markup_escape_text (str, strlen (str));
+#else
+ return lame_xml_quote (str);
+#endif
+}
+
+static char *
+dashboard_build_clue (const char *text,
+ const char *type,
+ int relevance)
+{
+ char *text_xml;
+ char *clue;
+
+ if (text == NULL || strlen (text) == 0)
+ return g_strdup ("");
+
+ text_xml = dashboard_xml_quote (text);
+
+ clue = g_strdup_printf (" <Clue Type=\"%s\" Relevance=\"%d\">%s</Clue>\n",
+ type, relevance, text_xml);
+
+ g_free (text_xml);
+
+ return clue;
+}
+
+static char *
+dashboard_build_cluepacket_from_cluelist (const char *frontend,
+ gboolean focused,
+ const char *context,
+ GList *clues)
+{
+ char *cluepacket;
+ char *new_cluepacket;
+ GList *l;
+
+ g_return_val_if_fail (frontend != NULL, NULL);
+ g_return_val_if_fail (clues != NULL, NULL);
+
+ cluepacket = g_strdup_printf (
+ "<CluePacket>\n"
+ " <Frontend>%s</Frontend>\n"
+ " <Context>%s</Context>\n"
+ " <Focused>%s</Focused>\n",
+ frontend,
+ context,
+ focused ? "true" : "false");
+
+ for (l = clues; l != NULL; l = l->next) {
+ const char *clue = (const char *) l->data;
+
+ new_cluepacket = g_strconcat (cluepacket, clue, NULL);
+ g_free (cluepacket);
+
+ cluepacket = new_cluepacket;
+ }
+
+ new_cluepacket = g_strconcat (cluepacket, "</CluePacket>\n", NULL);
+ g_free (cluepacket);
+
+ cluepacket = new_cluepacket;
+
+ return cluepacket;
+}
+
+static char *
+dashboard_build_cluepacket_v (const char *frontend,
+ gboolean focused,
+ const char *context,
+ va_list args)
+{
+ char *cluep;
+ GList *clue_list;
+ char *retval;
+
+ g_return_val_if_fail (frontend != NULL, NULL);
+
+ cluep = va_arg (args, char *);
+ clue_list = NULL;
+ while (cluep) {
+ clue_list = g_list_append (clue_list, cluep);
+ cluep = va_arg (args, char *);
+ }
+
+ retval = dashboard_build_cluepacket_from_cluelist (frontend, focused, context, clue_list);
+
+ g_list_free (clue_list);
+
+ return retval;
+}
+
+static char *
+dashboard_build_cluepacket_then_free_clues (const char *frontend,
+ gboolean focused,
+ const char *context,
+ ...)
+{
+ char *retval;
+ char *cluep;
+ va_list args;
+
+ g_return_val_if_fail (frontend != NULL, NULL);
+
+ /* Build the cluepacket */
+ va_start (args, context);
+ retval = dashboard_build_cluepacket_v (frontend, focused, context, args);
+ va_end (args);
+
+ /* Free the clues */
+ va_start (args, context);
+ cluep = va_arg (args, char *);
+ while (cluep) {
+ g_free (cluep);
+ cluep = va_arg (args, char *);
+ }
+
+ va_end (args);
+
+ return retval;
+}
+
+#endif /* ! __DASHBOARD_FRONTEND_H__ */
Index: shell/rb-shell-player.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell-player.c,v
retrieving revision 1.106
diff -u -u -r1.106 rb-shell-player.c
--- shell/rb-shell-player.c 16 Dec 2003 15:37:00 -0000 1.106
+++ shell/rb-shell-player.c 19 Dec 2003 09:31:40 -0000
@@ -58,6 +58,13 @@
#include "rb-play-order.h"
+#ifdef WITH_DASHBOARD
+#include <stdio.h>
+#include <glib.h>
+#include <sys/time.h>
+#include "rb-dashboard.c"
+#endif /* WITH_DASHBOARD */
+
typedef enum
{
PLAY_BUTTON_PLAY,
@@ -978,6 +985,8 @@
rb_debug ("Success!");
rb_entry_view_set_playing_entry (songs, entry);
rb_shell_player_play (player);
+ rb_shell_player_sync_with_source (player);
+ rb_shell_player_sync_buttons (player);
}
static void
@@ -1384,6 +1393,12 @@
char *title;
RhythmDBEntry *entry;
char *duration;
+#ifdef WITH_DASHBOARD
+ const char *album = NULL;
+ const char *genre = NULL;
+ const char *url = NULL;
+ char *cluepacket;
+#endif
entry = rb_shell_player_get_playing_entry (player);
rb_debug ("playing source: %p, active entry: %p", player->priv->source, entry);
@@ -1395,6 +1410,12 @@
entry, RHYTHMDB_PROP_TITLE);
artist = rhythmdb_entry_get_string (player->priv->db, entry,
RHYTHMDB_PROP_ARTIST);
+#ifdef WITH_DASHBOARD
+ album = rhythmdb_entry_get_string (player->priv->db, entry,
+ RHYTHMDB_PROP_ALBUM);
+ genre = rhythmdb_entry_get_string (player->priv->db, entry,
+ RHYTHMDB_PROP_GENRE);
+#endif
rhythmdb_read_unlock (player->priv->db);
}
@@ -1433,6 +1454,24 @@
g_free (title);
rb_header_set_playing_entry (player->priv->header_widget, entry);
rb_header_sync (player->priv->header_widget);
+
+#ifdef WITH_DASHBOARD
+ /* Send cluepacket to dashboard */
+ if (player->priv->playbutton_state == PLAY_BUTTON_PLAY) {
+ cluepacket = dashboard_build_cluepacket_then_free_clues (
+ "Music Player",
+ TRUE,
+ url,
+ dashboard_build_clue (entry_title, "title", 10),
+ dashboard_build_clue (artist, "artist", 10),
+ dashboard_build_clue (album, "album", 10),
+ dashboard_build_clue (genre, "genre", 10),
+ NULL);
+
+ dashboard_send_raw_cluepacket (cluepacket);
+ g_free (cluepacket);
+ }
+#endif
}
void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]