[Rhythmbox-devel] xine metadata, and iPod HAL support
- From: Bastien Nocera <hadess hadess net>
- To: rhythmbox-devel gnome org
- Subject: [Rhythmbox-devel] xine metadata, and iPod HAL support
- Date: Mon, 21 Jun 2004 02:30:06 +0100
Heya,
Here's my free time's worth. First is a xine-lib metadata backend (which
I sent some time ago). It's not finished quite yet, but it's disabled by
default.
The rest is HAL support for the iPod source, with a bit of refactoring
for the existing code.
http://www.hadess.net/files/shots/21-06-2004.1.jpg
Enjoy.
---
Bastien Nocera <hadess hadess net>
She walked into my office like a centipede with 98 missing legs.
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.113
diff -u -r1.113 configure.ac
--- configure.ac 4 Jun 2004 18:50:03 -0000 1.113
+++ configure.ac 21 Jun 2004 01:16:59 -0000
@@ -15,6 +15,7 @@
AM_PROG_LIBTOOL
AC_C_BIGENDIAN
AC_CHECK_SIZEOF(long)
+AC_SUBST(mkdir_p)
ACLOCAL="$ACLOCAL -I macros"
@@ -32,6 +33,23 @@
AC_MSG_RESULT([no])
fi
+dnl iPod support
+dnl enable_ipod = "no"
+
+HAL_REQUIRED=0.2.92
+
+AC_ARG_ENABLE(ipod,
+ AC_HELP_STRING([--enable-ipod],
+ [Enable iPod support in Rhythmbox]))
+AM_CONDITIONAL(USE_IPOD, test x"$enable_ipod" = xyes)
+if test x"$enable_ipod" = xyes; then
+ AC_DEFINE(WITH_IPOD_SUPPORT, 1, [Define if iPod support is enabled])
+ USE_HAL=""
+ PKG_CHECK_MODULES(HAL, hal,
+ [ AC_DEFINE([HAVE_HAL], 1, [Use the HAL library]) ]
+ [ USE_HAL="hal >= $HAL_REQUIRED" ], :)
+fi
+
PKG_CHECK_MODULES(RHYTHMBOX, \
gtk+-2.0 >= 2.2.2 \
libgnomeui-2.0 \
@@ -39,7 +57,8 @@
gnome-vfs-2.0 \
gnome-vfs-module-2.0 \
libbonobo-2.0 \
- bonobo-activation-2.0)
+ bonobo-activation-2.0 \
+ $USE_HAL)
RHYTHMBOX_CFLAGS="$CFLAGS $RHYTHMBOX_CFLAGS"
PKG_CHECK_MODULES(UNUSED, gtk+-2.0 >= 2.4.0, [have_gtk_23=yes], [have_gtk_23=no])
@@ -48,16 +67,6 @@
fi
AM_CONDITIONAL(WITH_GTK22, test x"$have_gtk_23" != xyes)
-dnl iPod support
-dnl enable_ipod = "no"
-AC_ARG_ENABLE(ipod,
- AC_HELP_STRING([--enable-ipod],
- [Enable iPod support in Rhythmbox]))
-AM_CONDITIONAL(USE_IPOD, test x"$enable_ipod" = xyes)
-if test x"$enable_ipod" = xyes; then
- AC_DEFINE(WITH_IPOD_SUPPORT, 1, [Define if iPod support is enabled])
-fi
-
dnl Database
AC_ARG_WITH(database,
AC_HELP_STRING([--with-database=tree],
@@ -169,23 +178,30 @@
dnl Tagging
AC_ARG_WITH(metadata,
- AC_HELP_STRING([--with-metadata=gstreamer|monkeymedia|auto],
+ AC_HELP_STRING([--with-metadata=gstreamer|monkeymedia|xine|auto],
[Select the metadata reader to use]),,
with_metadata=auto)
if test x"$with_player" = xxine && test x"$with_metadata" = xgstreamer; then
AC_MSG_ERROR([cannot use xine as player with gstreamer for metadata])
fi
+if test x"$with_player" = xgstreamer && test x"$with_metadata" = xxine; then
+ AC_MSG_ERROR([cannot use gstreamer as player with xine for metadata])
+fi
+
if test x"$with_metadata" = xauto; then
if test x"$with_player" = xgstreamer; then
with_metadata=gstreamer
else
with_metadata=monkeymedia
fi
-fi
+fi
AM_CONDITIONAL(USE_MONKEYMEDIA, test x"$with_metadata" = xmonkeymedia)
if test x"$with_metadata" = xmonkeymedia; then
AC_DEFINE(WITH_MONKEYMEDIA, 1, [Define if you are using the monkeymedia metadata reader])
-fi
+fi
+
+AM_CONDITIONAL(WITH_XINE_METADATA, test x"$with_metadata" = "xxine")
+AM_CONDITIONAL(WITH_GST_METADATA, test x"$with_metadata" = "xgstreamer")
dnl Stolen from D-BUS configury
dnl Atomic integers (checks by Sebastian Wilhelmi for GLib)
Index: metadata/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/metadata/Makefile.am,v
retrieving revision 1.3
diff -u -r1.3 Makefile.am
--- metadata/Makefile.am 19 Dec 2003 03:50:38 -0000 1.3
+++ metadata/Makefile.am 21 Jun 2004 01:17:00 -0000
@@ -24,6 +24,12 @@
librbmetadata_la_LIBADD += $(top_builddir)/metadata/monkey-media/libmonkey-media.la
librbmetadata_la_SOURCES += rb-metadata-mm.c
INCLUDES += -I$(top_srcdir)/metadata/monkey-media
-else
+endif
+
+if WITH_XINE_METADATA
+librbmetadata_la_SOURCES += rb-metadata-xine.c
+endif
+
+if WITH_GST_METADATA
librbmetadata_la_SOURCES += rb-metadata-gst.c
endif
Index: metadata/rb-metadata-xine.c
===================================================================
RCS file: metadata/rb-metadata-xine.c
diff -N metadata/rb-metadata-xine.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ metadata/rb-metadata-xine.c 21 Jun 2004 01:17:01 -0000
@@ -0,0 +1,334 @@
+/*
+ * arch-tag: Implementation of xine-lib metadata loading
+ *
+ * Copyright (C) 2003-2004 Bastien Nocera <hadess hadess net>
+ *
+ * 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 <libgnomevfs/gnome-vfs.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <xine.h>
+
+#include "rb-string-helpers.h"
+
+#include "rb-metadata.h"
+
+static void rb_metadata_class_init (RBMetaDataClass *klass);
+static void rb_metadata_init (RBMetaData *md);
+static void rb_metadata_finalize (GObject *object);
+
+struct RBMetaDataPrivate
+{
+ xine_t *xine;
+ xine_stream_t *stream;
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+rb_metadata_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (RBMetaDataClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) rb_metadata_class_init,
+ NULL,
+ NULL,
+ sizeof (RBMetaData),
+ 0,
+ (GInstanceInitFunc) rb_metadata_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "RBMetaData",
+ &our_info, 0);
+ }
+
+ return type;
+}
+
+static void
+rb_metadata_class_init (RBMetaDataClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = rb_metadata_finalize;
+}
+
+static void
+rb_metadata_init (RBMetaData *md)
+{
+ char *path;
+
+ md->priv = g_new0 (RBMetaDataPrivate, 1);
+ md->priv->xine = xine_new ();
+ path = g_build_filename (g_get_home_dir(), ".gnome2",
+ "xine-config", NULL);
+ xine_config_load (md->priv->xine, path);
+
+ xine_init (md->priv->xine);
+ md->priv->stream = xine_stream_new (md->priv->xine, NULL, NULL);
+}
+
+RBMetaData *
+rb_metadata_new (void)
+{
+ return RB_METADATA (g_object_new (RB_TYPE_METADATA, NULL));
+}
+
+static void
+rb_metadata_finalize (GObject *object)
+{
+ RBMetaData *md;
+
+ md = RB_METADATA (object);
+
+ xine_close (md->priv->stream);
+ xine_dispose (md->priv->stream);
+ xine_exit (md->priv->xine);
+
+ g_free (md->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* FIXME implement error collapsing like in Totem */
+static gboolean
+xine_error (RBMetaData *md, GError **error)
+{
+ int err;
+
+ err = xine_get_error (md->priv->stream);
+ if (err == XINE_ERROR_NONE)
+ return TRUE;
+
+ /* FIXME actualise to the current metadata errors */
+#if 0
+ switch (err)
+ {
+ case XINE_ERROR_NO_INPUT_PLUGIN:
+ case XINE_ERROR_NO_DEMUX_PLUGIN:
+ *error = g_error_new (RB_METADATA_ERROR, RB_METADATA_ERROR_OPEN_FAILED, _("There is no plugin to handle this song"));
+ break;
+ case XINE_ERROR_DEMUX_FAILED:
+ *error = g_error_new (RB_METADATA_ERROR, RB_METADATA_ERROR_OPEN_FAILED, _("This song is broken and can not be played further"));
+ break;
+ case XINE_ERROR_MALFORMED_MRL:
+ *error = g_error_new (RB_METADATA_ERROR, RB_METADATA_ERROR_OPEN_FAILED, _("This location is not a valid one"));
+ break;
+ case XINE_ERROR_INPUT_FAILED:
+ *error = g_error_new (RB_METADATA_ERROR, RB_METADATA_ERROR_OPEN_FAILED, _("This song could not be opened")); break;
+ default:
+ *error = g_error_new (RB_METADATA_ERROR, RB_METADATA_ERROR_OPEN_FAILED, _("Generic Error"));
+ break;
+ }
+#endif
+ return FALSE;
+}
+
+void
+rb_metadata_load (RBMetaData *md, const char *uri, GError **error)
+{
+ int err;
+
+ xine_close (md->priv->stream);
+ err = xine_open (md->priv->stream, uri);
+
+ if (error == 0)
+ {
+ if (xine_error (md, error) == FALSE)
+ {
+ xine_close (md->priv->stream);
+ g_object_set (G_OBJECT (md), "error", error, NULL);
+ return;
+ }
+ }
+
+ if (xine_get_stream_info (md->priv->stream,
+ XINE_STREAM_INFO_HAS_AUDIO) == FALSE)
+ {
+#if 0
+ error = g_error_new (RB_METADATA_ERROR,
+ RB_METADATA_ERROR_OPEN_FAILED,
+ _("File is not an audio file"));
+ g_object_set (G_OBJECT (md), "error", error, NULL);
+#endif
+ return;
+ }
+
+ if (xine_get_stream_info (md->priv->stream,
+ XINE_STREAM_INFO_AUDIO_HANDLED) == FALSE)
+ {
+#if 0
+ error = g_error_new (RB_METADATA_ERROR,
+ RB_METADATA_ERROR_OPEN_FAILED,
+ _("Song is not handled"));
+ g_object_set (G_OBJECT (md), "error", error, NULL);
+#endif
+ return;
+ }
+}
+
+gboolean
+rb_metadata_get (RBMetaData *md,
+ RBMetaDataField field,
+ GValue *value)
+{
+ const char *tmp = NULL;
+
+ switch (field)
+ {
+ /* tags */
+ case RB_METADATA_FIELD_TITLE:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_TITLE);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_ARTIST:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_ARTIST);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_ALBUM:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_ALBUM);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_DATE:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_YEAR);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_GENRE:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_GENRE);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_COMMENT:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_COMMENT);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_TRACK_NUMBER:
+#if 0
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, xine_get_stream_info (md->priv->stream,
+ XINE_STREAM_INFO_TRACK_NUMBER));
+#endif
+ break;
+ case RB_METADATA_FIELD_MAX_TRACK_NUMBER:
+#if 0
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, xine_get_stream_info (md->priv->stream,
+ XINE_STREAM_INFO_MAX_TRACK_NUMBER));
+#endif
+ break;
+ case RB_METADATA_FIELD_DESCRIPTION:
+ case RB_METADATA_FIELD_VERSION:
+ case RB_METADATA_FIELD_ISRC:
+ case RB_METADATA_FIELD_ORGANIZATION:
+ case RB_METADATA_FIELD_COPYRIGHT:
+ case RB_METADATA_FIELD_CONTACT:
+ case RB_METADATA_FIELD_LICENSE:
+ case RB_METADATA_FIELD_PERFORMER:
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, "");
+ break;
+ case RB_METADATA_FIELD_DURATION:
+ {
+ int length = 0;
+ int pos_stream, pos_time;
+
+ xine_get_pos_length (md->priv->stream,
+ &pos_stream, &pos_time, &length);
+
+ g_value_init (value, G_TYPE_LONG);
+ g_value_set_long (value, length / 1000);
+ }
+ break;
+ case RB_METADATA_FIELD_CODEC:
+ g_value_init (value, G_TYPE_STRING);
+ tmp = xine_get_meta_info (md->priv->stream,
+ XINE_META_INFO_AUDIOCODEC);
+ g_value_set_string (value, tmp);
+ break;
+ case RB_METADATA_FIELD_BITRATE:
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, xine_get_stream_info (md->priv->stream,
+ XINE_STREAM_INFO_AUDIO_BITRATE) / 1000);
+ break;
+ case RB_METADATA_FIELD_ALBUM_GAIN:
+ case RB_METADATA_FIELD_TRACK_GAIN:
+ case RB_METADATA_FIELD_ALBUM_PEAK:
+ case RB_METADATA_FIELD_TRACK_PEAK:
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, 0.0);
+ break;
+
+ /* default */
+ default:
+ g_warning ("Invalid field!");
+ g_value_init (value, G_TYPE_NONE);
+ break;
+ }
+
+ return TRUE;
+}
+
+gboolean
+rb_metadata_set (RBMetaData *md,
+ RBMetaDataField field,
+ const GValue *value)
+{
+ return FALSE;
+}
+
+gboolean
+rb_metadata_can_save (RBMetaData *md, const char *mimetype)
+{
+ return FALSE;
+}
+
+const char *
+rb_metadata_get_mime (RBMetaData *md)
+{
+ return "application/x-fixme";
+}
+
+void
+rb_metadata_save (RBMetaData *md, GError **error)
+{
+ return;
+}
+
Index: sources/rb-ipod-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.c,v
retrieving revision 1.2
diff -u -r1.2 rb-ipod-source.c
--- sources/rb-ipod-source.c 21 Mar 2004 18:50:40 -0000 1.2
+++ sources/rb-ipod-source.c 21 Jun 2004 01:17:09 -0000
@@ -18,8 +18,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
+
+#include <config.h>
+
#include <gtk/gtktreeview.h>
#include <string.h>
+#ifdef HAVE_HAL
+#include <libhal.h>
+#include <dbus/dbus-glib.h>
+#endif
#include "itunesdb.h"
#include "rhythmdb.h"
#include <libgnome/gnome-i18n.h>
@@ -34,13 +41,28 @@
static void rb_ipod_source_finalize (GObject *object);
static void rb_ipod_source_class_init (RBiPodSourceClass *klass);
+static void ipod_itunesdb_monitor (RBiPodSource *source, gboolean enable);
static gboolean ipod_itunesdb_monitor_cb (RBiPodSource *source);
+#ifdef HAVE_HAL
+static gboolean ipod_itunesdb_monitor_hal (RBiPodSource *source,
+ gboolean enable);
+#endif
+static void ipod_set_present (RBiPodSource *source, gboolean is_present);
+
struct RBiPodSourcePrivate
{
guint ipod_polling_id;
+ gboolean was_present;
+ RhythmDB *db;
+
+#ifdef HAVE_HAL
+ LibHalContext *ctx;
+#endif
+ char *mount_path;
+ char *itunesdb_path;
};
@@ -84,8 +106,7 @@
static void
rb_ipod_source_init (RBiPodSource *source)
{
- source->priv = g_new0 (RBiPodSourcePrivate, 1);
- source->priv->ipod_polling_id = g_timeout_add (1000, (GSourceFunc)ipod_itunesdb_monitor_cb, source);
+ source->priv = g_new0 (RBiPodSourcePrivate, 1);
}
@@ -94,19 +115,22 @@
{
RBiPodSource *source = RB_IPOD_SOURCE (object);
- if (source->priv->ipod_polling_id) {
- g_source_remove (source->priv->ipod_polling_id);
- }
+ ipod_itunesdb_monitor (source, FALSE);
+ g_free (source->priv->itunesdb_path);
+ g_free (source->priv->mount_path);
}
RBSource *
rb_ipod_source_new (RBShell *shell, RhythmDB *db, BonoboUIComponent *component)
{
+ RBiPodSource *ipod_source;
RBSource *source;
GtkWidget *dummy = gtk_tree_view_new ();
GdkPixbuf *icon;
+ g_message ("new");
+
icon = gtk_widget_render_icon (dummy, RB_STOCK_IPOD,
GTK_ICON_SIZE_LARGE_TOOLBAR,
NULL);
@@ -117,14 +141,18 @@
"name", _("iPod"),
"entry-type", RHYTHMDB_ENTRY_TYPE_IPOD,
"internal-name", "<ipod>",
- "icon", icon,
"db", db,
+ "icon", icon,
"component", component,
NULL));
+ ipod_source = RB_IPOD_SOURCE (source);
+ ipod_source->priv->db = db;
+
rb_shell_register_entry_type_for_source (shell, source,
RHYTHMDB_ENTRY_TYPE_IPOD);
+ ipod_itunesdb_monitor (ipod_source, TRUE);
return source;
}
@@ -149,7 +177,7 @@
gchar *mount_path = ipod_get_mount_path ();
result = g_build_filename (mount_path,
- "iPod_Control/iTunes/iTunesDB",
+ "/iPod_Control/iTunes/iTunesDB",
NULL);
g_free (mount_path);
return result;
@@ -302,22 +330,16 @@
/* We need to be locked to use this function */
static GnomeVFSResult
-add_ipod_songs_to_db (RhythmDB *db)
+add_ipod_songs_to_db (RBiPodSource *source)
{
- char *path;
iPodParser *parser;
RBiPodSongAdderCtxt *ctxt;
ctxt = g_new0 (RBiPodSongAdderCtxt, 1);
- if (ctxt == NULL) {
- return GNOME_VFS_ERROR_NO_MEMORY;
- }
+ g_message ("mount point: %s", source->priv->mount_path);
+ parser = ipod_parser_new (source->priv->mount_path);
- path = ipod_get_mount_path ();
- parser = ipod_parser_new (path);
- g_free (path);
-
- ctxt->db = db;
+ ctxt->db = source->priv->db;
ctxt->parser = parser;
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
@@ -327,13 +349,12 @@
return GNOME_VFS_OK;
}
-
static void
-ipod_load_songs (RhythmDB *rdb)
+ipod_load_songs (RBiPodSource *source)
{
GnomeVFSResult res;
- res = add_ipod_songs_to_db (rdb);
+ res = add_ipod_songs_to_db (source);
if (res != GNOME_VFS_OK) {
g_warning ("Error loading iPod database");
@@ -341,11 +362,26 @@
}
static void
-ipod_unload_songs (RhythmDB *db)
+ipod_unload_songs (RBiPodSource *source)
{
- rhythmdb_write_lock (db);
- rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_IPOD);
- rhythmdb_write_unlock (db);
+ rhythmdb_write_lock (source->priv->db);
+ rhythmdb_entry_delete_by_type (source->priv->db, RHYTHMDB_ENTRY_TYPE_IPOD);
+ rhythmdb_write_unlock (source->priv->db);
+}
+
+static void
+ipod_itunesdb_monitor (RBiPodSource *source, gboolean enable)
+{
+#ifdef HAVE_HAL
+ if (ipod_itunesdb_monitor_hal (source, enable) != FALSE) {
+ return;
+ }
+#endif
+ if (enable) {
+ source->priv->ipod_polling_id = g_timeout_add (1000, (GSourceFunc)ipod_itunesdb_monitor_cb, source);
+ } else {
+ g_source_remove (source->priv->ipod_polling_id);
+ }
}
static gboolean
@@ -353,32 +389,201 @@
{
gboolean is_present;
gchar *itunesdb_path;
- static gboolean was_present = FALSE;
itunesdb_path = ipod_get_itunesdb_path ();
- g_assert (itunesdb_path != NULL);
- is_present = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
+ g_return_val_if_fail (itunesdb_path != NULL, TRUE);
- if (is_present && !was_present) {
- RhythmDB *db;
+ is_present = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
- g_print ("iPod plugged\n");
- was_present = TRUE;
- g_object_get (G_OBJECT (source), "db", &db, NULL);
- ipod_load_songs (db);
+ if (is_present && !source->priv->was_present) {
/* FIXME: should we suspend this monitor until the iPod
- * database has been read and fed to rhythmbox?
- */
- } else if (!is_present && was_present) {
- RhythmDB *db;
-
- g_print ("iPod unplugged\n");
- was_present = FALSE;
- g_object_get (G_OBJECT (source), "db", &db, NULL);
- ipod_unload_songs (db);
+ * database has been read and fed to rhythmbox? */
+ source->priv->itunesdb_path = itunesdb_path;
+ source->priv->mount_path = ipod_get_mount_path ();
+ ipod_set_present (source, TRUE);
+ } else if (!is_present && source->priv->was_present) {
+ ipod_set_present (source, TRUE);
+ g_free (source->priv->itunesdb_path);
+ g_free (source->priv->mount_path);
+ source->priv->mount_path = source->priv->itunesdb_path = NULL;
}
+
g_free (itunesdb_path);
return TRUE;
+}
+#ifdef HAVE_HAL
+static void
+hal_mainloop_integration (LibHalContext *ctx,
+ DBusConnection * dbus_connection)
+{
+ dbus_connection_setup_with_g_main (dbus_connection, NULL);
+}
+
+static void
+hal_check_udi (LibHalContext *ctx, const char *udi)
+{
+ dbus_bool_t val;
+ RBiPodSource *source;
+
+ source = hal_ctx_get_user_data (ctx);
+
+ val = hal_device_get_property_bool (ctx, udi,
+ "volume.is_mounted");
+
+ if (val != FALSE) {
+ g_message ("Mounted: %s\n", udi);
+ source->priv->mount_path = hal_device_get_property_string (ctx,
+ udi, "volume.mount_point");
+ source->priv->itunesdb_path = g_build_filename
+ (source->priv->mount_path,
+ "/iPod_Control/iTunes/iTunesDB",
+ NULL);
+ } else {
+ g_message ("Unmounted: %s\n", udi);
+ g_free (source->priv->itunesdb_path);
+ g_free (source->priv->mount_path);
+ source->priv->mount_path = NULL;
+ source->priv->itunesdb_path = NULL;
+ }
+
+ source = hal_ctx_get_user_data (ctx);
+ ipod_set_present (source, val);
+}
+
+static void
+hal_property_modified (LibHalContext *ctx,
+ const char *udi,
+ const char *key,
+ dbus_bool_t is_removed,
+ dbus_bool_t is_added)
+{
+ char *parent_udi, *parent_name;
+
+ if (g_strcasecmp (key, "volume.is_mounted") != 0) {
+ return;
+ }
+
+ parent_udi = hal_device_get_property_string (ctx, udi,
+ "info.parent");
+ parent_name = hal_device_get_property_string (ctx, parent_udi,
+ "storage.model");
+ g_free (parent_udi);
+
+ if (parent_name != NULL && strcmp (parent_name, "iPod") == 0) {
+ hal_check_udi (ctx, udi);
+ }
+
+ g_free (parent_name);
+}
+
+static void
+hal_find_existing (LibHalContext *ctx)
+{
+ int i;
+ int num_devices;
+ char **devices_names;
+ char *parent_udi;
+
+ parent_udi = NULL;
+ devices_names = hal_manager_find_device_string_match (ctx,
+ "info.product", "iPod", &num_devices);
+
+ for (i = 0; i < num_devices; i++)
+ {
+ char *string;
+
+ string = hal_device_get_property_string (ctx,
+ devices_names[i], "storage.drive_type");
+ if (string == NULL || strcmp (string, "disk") != 0) {
+ g_free (string);
+ continue;
+ }
+ g_free (string);
+
+ parent_udi = hal_device_get_property_string (ctx,
+ devices_names[i], "info.udi");
+ break;
+ }
+
+ g_message ("found iPod");
+
+ g_strfreev (devices_names);
+
+ if (parent_udi == NULL) {
+ return;
+ }
+
+ devices_names = hal_manager_find_device_string_match (ctx,
+ "info.parent", parent_udi, &num_devices);
+
+ g_free (parent_udi);
+
+ for (i = 0; i < num_devices; i++)
+ {
+ gboolean mounted;
+
+ mounted = hal_device_get_property_bool (ctx,
+ devices_names[i], "volume.is_mounted");
+ if (mounted != FALSE) {
+ g_message ("found udi %s", devices_names[i]);
+ hal_check_udi (ctx, devices_names[i]);
+ break;
+ }
+ }
+
+ g_strfreev (devices_names);
+}
+
+static gboolean
+ipod_itunesdb_monitor_hal (RBiPodSource *source, gboolean enable)
+{
+ if (enable) {
+ LibHalFunctions hal_functions = {
+ hal_mainloop_integration,
+ NULL, /* hal_device_added */
+ NULL, /* hal_device_removed */
+ NULL, /* hal_device_new_capability */
+ NULL, /* hal_device_lost_capability */
+ hal_property_modified,
+ NULL /* hal_device_condition */
+ };
+
+ source->priv->ctx = hal_initialize (&hal_functions, FALSE);
+ if (source->priv->ctx == NULL) {
+ return FALSE;
+ }
+
+ if (hal_device_property_watch_all (source->priv->ctx)) {
+ return FALSE;
+ }
+
+ hal_ctx_set_user_data (source->priv->ctx, source);
+
+ hal_find_existing (source->priv->ctx);
+ } else {
+ if (source->priv->ctx == NULL) {
+ return FALSE;
+ }
+ hal_shutdown (source->priv->ctx);
+ source->priv->ctx = NULL;
+ }
+
+ return TRUE;
+}
+#endif /* HAVE_HAL */
+
+static void
+ipod_set_present (RBiPodSource *source, gboolean is_present)
+{
+ if (is_present) {
+ g_print ("iPod plugged\n");
+ source->priv->was_present = TRUE;
+ ipod_load_songs (source);
+ } else {
+ g_print ("iPod unplugged\n");
+ source->priv->was_present = FALSE;
+ ipod_unload_songs (source);
+ }
}
RhythmDBEntryType rhythmdb_entry_ipod_get_type (void)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]