[rhythmbox] mtp: drop support for libmtp < 0.3.0, add GUdev based detection



commit 91e93ba16a92c1d50c2c44e23aef460b445bbf05
Author: Jonathan Matthew <jonathan d14n org>
Date:   Wed Aug 5 21:45:43 2009 +1000

    mtp: drop support for libmtp < 0.3.0, add GUdev based detection
    
    The HAL device detection code is still there, and will be until GUdev is
    widely available.
    
    This uses the new device management functions in libmtp 0.3.0, which
    means multiple devices should work (bug #563544).  Since the device
    detection is triggered by the removable media manager now, the 'scan
    removable media' menu item now finds available MTP devices (bug #561953).

 configure.ac                      |   32 ++++----
 plugins/mtpdevice/Makefile.am     |    2 +
 plugins/mtpdevice/rb-mtp-plugin.c |  138 ++++++++++++++++++++++++++++++++++---
 plugins/mtpdevice/rb-mtp-source.c |   64 +++++------------
 plugins/mtpdevice/rb-mtp-source.h |    7 ++-
 5 files changed, 173 insertions(+), 70 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index f205536..153d344 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,7 @@ VALA_REQS=0.1.0
 AVAHI_REQS=0.6
 LIBSOUP_REQS=2.26.0
 GUDEV_REQS=143
+LIBMTP_REQS=0.3.0
 
 AC_MSG_CHECKING([for GNU extension fwrite_unlocked])
 AC_LINK_IFELSE(
@@ -168,27 +169,26 @@ AC_ARG_WITH(mtp,
 			   [Enable MTP support]),,
 	      with_mtp=auto)
 if test "x$with_mtp" != "xno"; then
-
-	PKG_CHECK_MODULES(MTP, libmtp, have_libmtp=yes, have_libmtp=no)
-	if test "x$have_libmtp" = "xno" -a "x$with_mtp" = "xyes"; then
-	  AC_MSG_ERROR([MTP explicitly requested but libmtp couldn't be found])
+	can_use_mtp=no
+	if test x"$use_gudev" = "xyes" -o x"$enable_hal" = "xyes"; then
+	  can_use_mtp=yes
 	fi
-	if test "x$have_libmtp" = "xyes"; then
-          if test "x$with_hal" = xyes && test "x$enable_hal" = xno; then
-	     AC_MSG_ERROR([MTP explicitly requested but HAL not found or too old])
+
+	PKG_CHECK_MODULES(MTP, libmtp >= $LIBMTP_REQS, have_libmtp=yes, have_libmtp=no)
+	if test x"$with_mtp" = "xyes"; then
+	  if test x"$have_libmtp" = "xno"; then
+	    AC_MSG_ERROR([MTP explicitly requested but libmtp is not available])
+	  fi
+	  if test x"$can_use_mtp" = "xno"; then
+	    AC_MSG_ERROR([MTP explicitly requested but GUdev and HAL are not available])
 	  fi
-          if test "x$enable_hal" = xyes; then
-	     use_mtp=yes
-	     dnl Check for libmtp 0.3.0+
-	     PKG_CHECK_EXISTS(libmtp >= 0.3.0, found_libmtp_030_pkg=yes, found_libmtp_030_pkg=no)
-	     if test x"$found_libmtp_030_pkg" = "xyes" ; then
-	       AC_DEFINE([HAVE_LIBMTP_030], 1, [indicates whether libmtp 0.3.0 is installed])
-	     fi
-          fi
+	fi
+	if test "x$have_libmtp" = "xyes" -a "x$can_use_mtp" = "xyes"; then
+	  use_mtp=yes
 	  AC_SUBST(MTP_CFLAGS)
 	  AC_SUBST(MTP_LIBS)
 	fi
-fi			  
+fi
 AM_CONDITIONAL(USE_MTP, test x"$use_mtp" = xyes)
 
 
diff --git a/plugins/mtpdevice/Makefile.am b/plugins/mtpdevice/Makefile.am
index 599a8a6..71175aa 100644
--- a/plugins/mtpdevice/Makefile.am
+++ b/plugins/mtpdevice/Makefile.am
@@ -13,6 +13,7 @@ libmtpdevice_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
 libmtpdevice_la_LIBTOOLFLAGS = --tag=disable-static
 libmtpdevice_la_LIBADD = 				\
 	$(top_builddir)/shell/librhythmbox-core.la	\
+	$(GUDEV_LIBS)					\
 	$(HAL_LIBS)					\
 	$(MTP_LIBS)
 
@@ -35,6 +36,7 @@ INCLUDES = 						\
 	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
 	-DDATADIR=\""$(datadir)"\"			\
 	$(RHYTHMBOX_CFLAGS)				\
+	$(GUDEV_CFLAGS)					\
 	$(HAL_CFLAGS)					\
 	$(MTP_CFLAGS)					\
 	-D_XOPEN_SOURCE -D_BSD_SOURCE
diff --git a/plugins/mtpdevice/rb-mtp-plugin.c b/plugins/mtpdevice/rb-mtp-plugin.c
index 8aa40f4..c1d7053 100644
--- a/plugins/mtpdevice/rb-mtp-plugin.c
+++ b/plugins/mtpdevice/rb-mtp-plugin.c
@@ -37,10 +37,16 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <libmtp.h>
+
+#if defined(HAVE_GUDEV)
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+#else
 #include <hal/libhal.h>
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
+#endif
 
 #include "rb-source.h"
 #include "rb-sourcelist.h"
@@ -51,6 +57,7 @@
 #include "rb-util.h"
 #include "rb-shell.h"
 #include "rb-stock-icons.h"
+#include "rb-removable-media-manager.h"
 
 
 #define RB_TYPE_MTP_PLUGIN		(rb_mtp_plugin_get_type ())
@@ -69,10 +76,14 @@ typedef struct
 	GtkActionGroup *action_group;
 	guint ui_merge_id;
 
+	guint create_device_source_id;
+
 	GList *mtp_sources;
 
+#if !defined(HAVE_GUDEV)
 	LibHalContext *hal_context;
 	DBusConnection *dbus_connection;
+#endif
 } RBMtpPlugin;
 
 typedef struct
@@ -89,11 +100,14 @@ static void rb_mtp_plugin_finalize (GObject *object);
 static void impl_activate (RBPlugin *plugin, RBShell *shell);
 static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
 
+#if defined(HAVE_GUDEV)
+static RBSource* create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device, RBMtpPlugin *plugin);
+#else
 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);
-
 static RBSource* create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, const char *udi);
+#endif
 static void rb_mtp_plugin_eject  (GtkAction *action, RBMtpPlugin *plugin);
 static void rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin);
 
@@ -149,16 +163,22 @@ impl_activate (RBPlugin *bplugin, RBShell *shell)
 {
 	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
 	GtkUIManager *uimanager = NULL;
+	RBRemovableMediaManager *rmm;
 	char *file = NULL;
+#if defined(HAVE_GUDEV)
+	gboolean rmm_scanned = FALSE;
+#else
 	int num, i, ret;
 	char **devices;
 	LIBMTP_device_entry_t *entries;
 	int numentries;
+#endif
 
 	plugin->shell = shell;
 
 	g_object_get (G_OBJECT (shell),
 		     "ui-manager", &uimanager,
+		     "removable-media-manager", &rmm,
 		     NULL);
 
 	/* ui */
@@ -174,9 +194,22 @@ impl_activate (RBPlugin *bplugin, RBShell *shell)
 	g_object_unref (G_OBJECT (uimanager));
 
 	/* device detection */
-
+#if defined(HAVE_GUDEV)
+	plugin->create_device_source_id =
+		g_signal_connect_object (rmm,
+					 "create-source-device",
+					 G_CALLBACK (create_source_device_cb),
+					 plugin,
+					 0);
+
+	/* only scan if we're being loaded after the initial scan has been done */
+	g_object_get (rmm, "scanned", &rmm_scanned, NULL);
+	if (rmm_scanned)
+		rb_removable_media_manager_scan (rmm);
+#else
 	if (rb_mtp_plugin_setup_dbus_hal_connection (plugin) == FALSE) {
 		rb_debug ("not scanning for MTP devices because we couldn't get a HAL context");
+		g_object_unref (rmm);
 		return;
 	}
 
@@ -213,6 +246,10 @@ impl_activate (RBPlugin *bplugin, RBShell *shell)
 
 	libhal_free_string_array (devices);
 	rb_profile_end ("scanning for MTP devices");
+
+#endif
+
+	g_object_unref (rmm);
 }
 
 static void
@@ -220,9 +257,11 @@ impl_deactivate (RBPlugin *bplugin, RBShell *shell)
 {
 	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
 	GtkUIManager *uimanager = NULL;
+	RBRemovableMediaManager *rmm = NULL;
 
 	g_object_get (G_OBJECT (shell),
 		      "ui-manager", &uimanager,
+		      "removable-media-manager", &rmm,
 		      NULL);
 
 	gtk_ui_manager_remove_ui (uimanager, plugin->ui_merge_id);
@@ -232,6 +271,10 @@ impl_deactivate (RBPlugin *bplugin, RBShell *shell)
 	g_list_free (plugin->mtp_sources);
 	plugin->mtp_sources = NULL;
 
+#if defined(HAVE_GUDEV)
+	g_signal_handler_disconnect (rmm, plugin->create_device_source_id);
+	plugin->create_device_source_id = 0;
+#else
 	if (plugin->hal_context != NULL) {
 		DBusError error;
 		dbus_error_init (&error);
@@ -246,16 +289,89 @@ impl_deactivate (RBPlugin *bplugin, RBShell *shell)
 		dbus_connection_unref (plugin->dbus_connection);
 		plugin->dbus_connection = NULL;
 	}
+#endif
 
-	g_object_unref (G_OBJECT (uimanager));
+	g_object_unref (uimanager);
+	g_object_unref (rmm);
 }
 
 static void
-rb_mtp_plugin_source_deleted (RBMtpSource *source, RBMtpPlugin *plugin)
+source_deleted_cb (RBMtpSource *source, RBMtpPlugin *plugin)
 {
 	plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
 }
 
+#if defined(HAVE_GUDEV)
+static RBSource *
+create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device, RBMtpPlugin *plugin)
+{
+	GUdevDeviceNumber device_number;
+	int i;
+	int num_raw_devices;
+	const char *devnum_str;
+	int devnum;
+	LIBMTP_raw_device_t *raw_devices;
+
+	/* check subsystem == usb? */
+	if (g_strcmp0 (g_udev_device_get_subsystem (G_UDEV_DEVICE (device)), "usb") != 0) {
+		rb_debug ("this is not a USB device");
+		return NULL;
+	}
+
+	device_number = g_udev_device_get_device_number (G_UDEV_DEVICE (device));
+	if (device_number == 0) {
+		rb_debug ("can't get udev device number for this device");
+		return NULL;
+	}
+	/* fun thing: usb device numbers are zero padded, which causes strtol to
+	 * interpret them as octal if you don't specify a base.
+	 */
+	devnum_str = g_udev_device_get_property (G_UDEV_DEVICE (device), "DEVNUM");
+	if (devnum_str == NULL) {
+		rb_debug ("device doesn't have a USB device number");
+		return NULL;
+	}
+	devnum = strtol (devnum_str, NULL, 10);
+
+	rb_debug ("trying to match device %x (usb device %d) against detected mtp devices",
+		  device_number, devnum);
+
+	/* see what devices libmtp can find */
+	if (LIBMTP_Detect_Raw_Devices (&raw_devices, &num_raw_devices) == 0) {
+		for (i = 0; i < num_raw_devices; i++) {
+			LIBMTP_mtpdevice_t *device;
+			RBSource *source;
+
+			rb_debug ("detected mtp device: device number %d", raw_devices[i].devnum);
+
+			/* check bus number/device location somehow */
+			if (devnum != raw_devices[i].devnum) {
+				rb_debug ("device number mismatches: %d vs %d", devnum, raw_devices[i].devnum);
+				continue;
+			}
+
+			device = LIBMTP_Open_Raw_Device (&raw_devices[i]);
+			if (device == NULL) {
+				rb_debug ("unable to open device.  weird.");
+				break;
+			}
+
+			rb_debug ("device matched, creating a source");
+			source = rb_mtp_source_new (plugin->shell, device);
+			plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
+			g_signal_connect_object (G_OBJECT (source),
+						"deleted", G_CALLBACK (source_deleted_cb),
+						plugin, 0);
+			return source;
+		}
+	}
+
+	rb_debug ("device didn't match anything");
+	return NULL;
+}
+
+#else
+
 static RBSource *
 create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, const char *udi)
 {
@@ -267,15 +383,17 @@ create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, const char *u
 	plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
 
 	g_signal_connect_object (G_OBJECT (source),
-				"deleted", G_CALLBACK (rb_mtp_plugin_source_deleted),
+				"deleted", G_CALLBACK (source_deleted_cb),
 				plugin, 0);
 
 	return source;
 }
 
+#endif
+
+
 static void
-rb_mtp_plugin_eject (GtkAction *action,
-			   RBMtpPlugin *plugin)
+rb_mtp_plugin_eject (GtkAction *action, RBMtpPlugin *plugin)
 {
 	RBSourceList *sourcelist = NULL;
 	RBSource *source = NULL;
@@ -299,8 +417,7 @@ rb_mtp_plugin_eject (GtkAction *action,
 }
 
 static void
-rb_mtp_plugin_rename (GtkAction *action,
-			   RBMtpPlugin *plugin)
+rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin)
 {
 	RBSourceList *sourcelist = NULL;
 	RBSource *source = NULL;
@@ -323,6 +440,8 @@ rb_mtp_plugin_rename (GtkAction *action,
 	g_object_unref (source);
 }
 
+#if !defined(HAVE_GUDEV)
+
 static void
 rb_mtp_plugin_device_added (LibHalContext *context, const char *udi)
 {
@@ -428,3 +547,4 @@ rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin)
 	return TRUE;
 }
 
+#endif
diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index 2508d38..20513de 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -54,40 +54,6 @@
 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/mtp/paned_position"
 #define CONF_STATE_SHOW_BROWSER   CONF_PREFIX "/state/mtp/show_browser"
 
-#ifndef HAVE_LIBMTP_030
-/*
- * Helpful macros to determine filetype properties
- */
-#define LIBMTP_FILETYPE_IS_AUDIO(a)\
-(a == LIBMTP_FILETYPE_WAV ||\
- a == LIBMTP_FILETYPE_MP3 ||\
- a == LIBMTP_FILETYPE_MP2 ||\
- a == LIBMTP_FILETYPE_WMA ||\
- a == LIBMTP_FILETYPE_OGG ||\
- a == LIBMTP_FILETYPE_FLAC ||\
- a == LIBMTP_FILETYPE_AAC ||\
- a == LIBMTP_FILETYPE_M4A ||\
- a == LIBMTP_FILETYPE_UNDEF_AUDIO)
-
-#define LIBMTP_FILETYPE_IS_VIDEO(a)\
-(a == LIBMTP_FILETYPE_WMV ||\
- a == LIBMTP_FILETYPE_AVI ||\
- a == LIBMTP_FILETYPE_MPEG ||\
- a == LIBMTP_FILETYPE_UNDEF_VIDEO)
-
-#define LIBMTP_FILETYPE_IS_AUDIOVIDEO(a)\
-(a == LIBMTP_FILETYPE_MP4 ||\
- a == LIBMTP_FILETYPE_ASF ||\
- a == LIBMTP_FILETYPE_QT)
-
-#define LIBMTP_FILETYPE_IS_TRACK(a)\
-(LIBMTP_FILETYPE_IS_AUDIO(a) ||\
- LIBMTP_FILETYPE_IS_VIDEO(a) ||\
- LIBMTP_FILETYPE_IS_AUDIOVIDEO(a))
-
-#endif
-
-
 static GObject *rb_mtp_source_constructor (GType type,
 					   guint n_construct_properties,
 					   GObjectConstructParam *construct_properties);
@@ -146,7 +112,9 @@ typedef struct
 	GHashTable *entry_map;
 	GHashTable *album_map;
 	GHashTable *artwork_request_map;
+#if !defined(HAVE_GUDEV)
 	char *udi;
+#endif
 	uint16_t supported_types[LIBMTP_FILETYPE_UNKNOWN+1];
 	GList *mediatypes;
 	gboolean album_art_supported;
@@ -227,6 +195,7 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 							       "libmtp-device",
 							       "libmtp device",
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+#if !defined(HAVE_GUDEV)
 	g_object_class_install_property (object_class,
 					 PROP_UDI,
 					 g_param_spec_string ("udi",
@@ -234,6 +203,7 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 							      "udi",
 							      NULL,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+#endif
 
 	g_type_class_add_private (klass, sizeof (RBMtpSourcePrivate));
 }
@@ -422,9 +392,11 @@ rb_mtp_source_set_property (GObject *object,
 	case PROP_LIBMTP_DEVICE:
 		priv->device = g_value_get_pointer (value);
 		break;
+#if !defined(HAVE_GUDEV)
 	case PROP_UDI:
 		priv->udi = g_value_dup_string (value);
 		break;
+#endif
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -443,9 +415,11 @@ rb_mtp_source_get_property (GObject *object,
 	case PROP_LIBMTP_DEVICE:
 		g_value_set_pointer (value, priv->device);
 		break;
+#if !defined(HAVE_GUDEV)
 	case PROP_UDI:
 		g_value_set_string (value, priv->udi);
 		break;
+#endif
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -486,7 +460,9 @@ rb_mtp_source_finalize (GObject *object)
 	g_hash_table_destroy (priv->album_map);
 	g_hash_table_destroy (priv->artwork_request_map);
 
+#if !defined(HAVE_GUDEV)
 	g_free (priv->udi);
+#endif
 
 	LIBMTP_Release_Device (priv->device);
 
@@ -505,10 +481,16 @@ impl_get_paned_key (RBBrowserSource *source)
 	return g_strdup (CONF_STATE_PANED_POSITION);
 }
 
-RBBrowserSource *
+#if defined(HAVE_GUDEV)
+RBSource *
+rb_mtp_source_new (RBShell *shell,
+		   LIBMTP_mtpdevice_t *device)
+#else
+RBSource *
 rb_mtp_source_new (RBShell *shell,
 		   LIBMTP_mtpdevice_t *device,
 		   const char *udi)
+#endif
 {
 	RBMtpSource *source = NULL;
 	RhythmDBEntryType entry_type;
@@ -532,12 +514,14 @@ rb_mtp_source_new (RBShell *shell,
 					      "volume", NULL,
 					      "source-group", RB_SOURCE_GROUP_DEVICES,
 					      "libmtp-device", device,
+#if !defined(HAVE_GUDEV)
 					      "udi", udi,
+#endif
 					      NULL));
 
 	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
 
-	return RB_BROWSER_SOURCE (source);
+	return RB_SOURCE (source);
 }
 
 static void
@@ -691,11 +675,7 @@ load_mtp_db_idle_cb (RBMtpSource* source)
 		device_forgets_albums = FALSE;
 	}
 
-#ifdef HAVE_LIBMTP_030
 	tracks = LIBMTP_Get_Tracklisting_With_Callback (priv->device, NULL, NULL);
-#else
-	tracks = LIBMTP_Get_Tracklisting (priv->device);
-#endif
 	report_libmtp_errors (priv->device, FALSE);
 	if (tracks != NULL) {
 		LIBMTP_track_t *track;
@@ -1003,11 +983,7 @@ transfer_track (RBMtpSource *source,
 		  LIBMTP_Get_Filetype_Description (trackmeta->filetype),
 		  mimetype);
 
-#ifdef HAVE_LIBMTP_030
 	ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL);
-#else
-	ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL, 0);
-#endif
 	rb_debug ("LIBMTP_Send_Track_From_File (%s) returned %d", filename, ret);
 	if (ret != 0) {
 		report_libmtp_errors (device, TRUE);
diff --git a/plugins/mtpdevice/rb-mtp-source.h b/plugins/mtpdevice/rb-mtp-source.h
index 5cc90b5..7c08ab3 100644
--- a/plugins/mtpdevice/rb-mtp-source.h
+++ b/plugins/mtpdevice/rb-mtp-source.h
@@ -54,7 +54,12 @@ typedef struct
 	RBRemovableMediaSourceClass parent;
 } RBMtpSourceClass;
 
-RBBrowserSource *	rb_mtp_source_new		(RBShell *shell, LIBMTP_mtpdevice_t *device, const char *udi);
+#if defined(HAVE_GUDEV)
+RBSource *		rb_mtp_source_new		(RBShell *shell, LIBMTP_mtpdevice_t *device);
+#else
+RBSource *		rb_mtp_source_new		(RBShell *shell, LIBMTP_mtpdevice_t *device, const char *udi);
+#endif
+
 GType			rb_mtp_source_get_type		(void);
 GType			rb_mtp_source_register_type	(GTypeModule *module);
 



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