[rhythmbox] mtp: use media player source base class



commit 00902b309f172101895b986c43d79cbc9f1f936f
Author: Jonathan Matthew <jonathan d14n org>
Date:   Sun Dec 13 11:37:06 2009 +1000

    mtp: use media player source base class
    
    The main tricky thing here is that we track the amount of free space on
    the device, rather than asking it when creating the properties dialog.
    To do this, we add a new action type to the MTP thread that just calls a
    specified function on the device handler thread.  After any track
    transfer or delete action, we add a callback to update our idea of the
    amount of free space on the device.

 plugins/mtpdevice/Makefile.am     |    6 +-
 plugins/mtpdevice/mtp-info.ui     |  222 +++++++++++++++++++++++++++++++++++++
 plugins/mtpdevice/mtp-ui.xml      |    1 +
 plugins/mtpdevice/rb-mtp-plugin.c |   21 +++-
 plugins/mtpdevice/rb-mtp-source.c |  191 ++++++++++++++++++++++++++++++--
 plugins/mtpdevice/rb-mtp-source.h |   15 ++-
 plugins/mtpdevice/rb-mtp-thread.c |   22 ++++
 plugins/mtpdevice/rb-mtp-thread.h |    7 +-
 8 files changed, 465 insertions(+), 20 deletions(-)
---
diff --git a/plugins/mtpdevice/Makefile.am b/plugins/mtpdevice/Makefile.am
index 151d231..f1fbab7 100644
--- a/plugins/mtpdevice/Makefile.am
+++ b/plugins/mtpdevice/Makefile.am
@@ -53,7 +53,11 @@ uixml_DATA = mtp-ui.xml
 
 plugin_DATA = $(plugin_in_files:.rb-plugin.in=.rb-plugin)
 
-EXTRA_DIST = $(uixml_DATA) $(plugin_in_files)
+gtkbuilderdir = $(plugindir)
+gtkbuilder_DATA = 					\
+	mtp-info.ui
+
+EXTRA_DIST = $(uixml_DATA) $(plugin_in_files) $(gtkbuilder_DATA)
 
 CLEANFILES = $(plugin_DATA)
 DISTCLEANFILES = $(plugin_DATA)
diff --git a/plugins/mtpdevice/mtp-info.ui b/plugins/mtpdevice/mtp-info.ui
new file mode 100644
index 0000000..9ad5152
--- /dev/null
+++ b/plugins/mtpdevice/mtp-info.ui
@@ -0,0 +1,222 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkTable" id="mtp-basic-info">
+    <property name="visible">True</property>
+    <property name="border_width">12</property>
+    <property name="n_rows">4</property>
+    <property name="n_columns">2</property>
+    <property name="column_spacing">12</property>
+    <property name="row_spacing">6</property>
+    <child>
+      <object class="GtkEntry" id="entry-mtp-name">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label-mtp-name">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Device Name:</property>
+      </object>
+      <packing>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label-num-tracks">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Tracks:</property>
+      </object>
+      <packing>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label-num-podcasts">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Podcasts:</property>
+      </object>
+      <packing>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label-num-playlists">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Playlists:</property>
+      </object>
+      <packing>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="mtp-num-tracks">
+        <property name="visible">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="mtp-num-podcasts">
+        <property name="visible">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="mtp-num-playlists">
+        <property name="visible">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkFrame" id="mtp-advanced-tab">
+    <property name="visible">True</property>
+    <property name="border_width">12</property>
+    <property name="label_xalign">0</property>
+    <property name="shadow_type">none</property>
+    <child>
+      <object class="GtkTable" id="table2">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="n_rows">4</property>
+        <property name="n_columns">2</property>
+        <property name="column_spacing">12</property>
+        <property name="row_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="label-mtp-model-value">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">1</property>
+            <property name="bottom_attach">2</property>
+            <property name="x_options">GTK_FILL</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-mtp-model">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Model:</property>
+          </object>
+          <packing>
+            <property name="top_attach">1</property>
+            <property name="bottom_attach">2</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-serial-number-value">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">2</property>
+            <property name="bottom_attach">3</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-serial-number">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Serial Number:</property>
+          </object>
+          <packing>
+            <property name="top_attach">2</property>
+            <property name="bottom_attach">3</property>
+            <property name="x_options">GTK_FILL</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-firmware-version">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Firmware Version:</property>
+          </object>
+          <packing>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+            <property name="x_options">GTK_FILL</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-firmware-version-value">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-manufacturer">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Manufacturer:</property>
+          </object>
+          <packing>
+            <property name="x_options">GTK_FILL</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label-manufacturer-value">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="y_options"></property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="label">
+      <object class="GtkLabel" id="label-frame-system">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">&lt;b&gt;System&lt;/b&gt;</property>
+        <property name="use_markup">True</property>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/plugins/mtpdevice/mtp-ui.xml b/plugins/mtpdevice/mtp-ui.xml
index f56654e..05986df 100644
--- a/plugins/mtpdevice/mtp-ui.xml
+++ b/plugins/mtpdevice/mtp-ui.xml
@@ -2,5 +2,6 @@
   <popup name="MTPSourcePopup">
     <menuitem name="MTPSrcPopupRename" action="MTPSourceRename"/>
     <menuitem name="MTPSrcPopupEject" action="MTPSourceEject"/>
+    <menuitem name="MTPSrcPopupProperties" action="MTPSourceProperties"/>
   </popup>
 </ui>
diff --git a/plugins/mtpdevice/rb-mtp-plugin.c b/plugins/mtpdevice/rb-mtp-plugin.c
index 00ef886..0cca166 100644
--- a/plugins/mtpdevice/rb-mtp-plugin.c
+++ b/plugins/mtpdevice/rb-mtp-plugin.c
@@ -108,8 +108,10 @@ 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);
 #endif
+
 static void rb_mtp_plugin_eject  (GtkAction *action, RBSource *source);
 static void rb_mtp_plugin_rename (GtkAction *action, RBSource *source);
+static void rb_mtp_plugin_properties (GtkAction *action, RBSource *source);
 
 GType rb_mtp_src_get_type (void);
 GType rb_mtp_sink_get_type (void);
@@ -123,7 +125,10 @@ static GtkActionEntry rb_mtp_plugin_actions [] =
 	  G_CALLBACK (rb_mtp_plugin_eject) },
 	{ "MTPSourceRename", NULL, N_("_Rename"), NULL,
 	  N_("Rename MTP-device"),
-	  G_CALLBACK (rb_mtp_plugin_rename) }
+	  G_CALLBACK (rb_mtp_plugin_rename) },
+	{ "MTPSourceProperties", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL,
+	  N_("Display device properties"),
+	  G_CALLBACK (rb_mtp_plugin_properties) }
 };
 
 static void
@@ -306,6 +311,13 @@ rb_mtp_plugin_rename (GtkAction *action, RBSource *source)
 	g_object_unref (shell);
 }
 
+static void
+rb_mtp_plugin_properties (GtkAction *action, RBSource *source)
+{
+	g_return_if_fail (RB_IS_MTP_SOURCE (source));
+	rb_media_player_source_show_properties (RB_MEDIA_PLAYER_SOURCE (source));
+}
+
 
 #if defined(HAVE_GUDEV)
 static void
@@ -360,7 +372,8 @@ create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device, RBMtpPlu
 			}
 
 			rb_debug ("device matched, creating a source");
-			source = rb_mtp_source_new (plugin->shell, &raw_devices[i]);
+			source = rb_mtp_source_new (plugin->shell, RB_PLUGIN (plugin), &raw_devices[i]);
+
 			plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
 			g_signal_connect_object (G_OBJECT (source),
 						"deleted", G_CALLBACK (source_deleted_cb),
@@ -405,12 +418,12 @@ rb_mtp_plugin_maybe_add_source (RBMtpPlugin *plugin, const char *udi, LIBMTP_raw
 		rb_debug ("detected MTP device: device number %d (bus location %u)", raw_devices[i].devnum, raw_devices[i].bus_location);
 		if (raw_devices[i].devnum == device_num) {
 			RBSource *source;
+
 			rb_debug ("device matched, creating a source");
-			source = RB_SOURCE (rb_mtp_source_new (plugin->shell, &raw_devices[i], udi));
+			source = RB_SOURCE (rb_mtp_source_new (plugin->shell, RB_PLUGIN (plugin), udi, &raw_devices[i]));
 
 			rb_shell_append_source (plugin->shell, source, NULL);
 			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);
diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index f24bbdc..619fe45 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -37,6 +37,7 @@
 #include "rb-debug.h"
 #include "rb-file-helpers.h"
 #include "rb-plugin.h"
+#include "rb-builder-helpers.h"
 #include "rb-removable-media-manager.h"
 #include "rb-static-playlist-source.h"
 #include "rb-util.h"
@@ -95,6 +96,10 @@ static void artwork_notify_cb (RhythmDB *db,
 			       const GValue *metadata,
 			       RBMtpSource *source);
 
+static guint64		impl_get_capacity	(RBMediaPlayerSource *source);
+static guint64		impl_get_free_space	(RBMediaPlayerSource *source);
+static void		impl_show_properties	(RBMediaPlayerSource *source, GtkWidget *info_box, GtkWidget *notebook);
+
 static void prepare_player_source_cb (RBPlayer *player,
 				      const char *stream_uri,
 				      GstElement *src,
@@ -122,11 +127,19 @@ typedef struct
 	GList *mediatypes;
 	gboolean album_art_supported;
 
+	/* device information */
+	char *manufacturer;
+	char *serial;
+	char *device_version;
+	char *model_name;
+	guint64 capacity;
+	guint64 free_space;		/* updated by callbacks */
+
 } RBMtpSourcePrivate;
 
 RB_PLUGIN_DEFINE_TYPE(RBMtpSource,
 		       rb_mtp_source,
-		       RB_TYPE_REMOVABLE_MEDIA_SOURCE)
+		       RB_TYPE_MEDIA_PLAYER_SOURCE)
 
 #define MTP_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_MTP_SOURCE, RBMtpSourcePrivate))
 
@@ -135,6 +148,7 @@ enum
 	PROP_0,
 	PROP_RAW_DEVICE,
 	PROP_UDI,
+	PROP_DEVICE_SERIAL
 };
 
 static void
@@ -144,6 +158,7 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
 	RBRemovableMediaSourceClass *rms_class = RB_REMOVABLE_MEDIA_SOURCE_CLASS (klass);
 	RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
+	RBMediaPlayerSourceClass *mps_class = RB_MEDIA_PLAYER_SOURCE_CLASS (klass);
 
 	object_class->constructed = rb_mtp_source_constructed;
 	object_class->dispose = rb_mtp_source_dispose;
@@ -173,6 +188,10 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 	rms_class->impl_get_mime_types = impl_get_mime_types;
 	rms_class->impl_should_paste = rb_removable_media_source_should_paste_no_duplicate;
 
+	mps_class->impl_get_capacity = impl_get_capacity;
+	mps_class->impl_get_free_space = impl_get_free_space;
+	mps_class->impl_show_properties = impl_show_properties;
+
 	g_object_class_install_property (object_class,
 					 PROP_RAW_DEVICE,
 					 g_param_spec_pointer ("raw-device",
@@ -188,6 +207,7 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 							      NULL,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 #endif
+	g_object_class_override_property (object_class, PROP_DEVICE_SERIAL, "serial");
 
 	g_type_class_add_private (klass, sizeof (RBMtpSourcePrivate));
 }
@@ -324,6 +344,9 @@ rb_mtp_source_get_property (GObject *object,
 		g_value_set_string (value, priv->udi);
 		break;
 #endif
+	case PROP_DEVICE_SERIAL:
+		g_value_set_string (value, priv->serial);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -367,6 +390,10 @@ rb_mtp_source_finalize (GObject *object)
 #if !defined(HAVE_GUDEV)
 	g_free (priv->udi);
 #endif
+	g_free (priv->manufacturer);
+	g_free (priv->device_version);
+	g_free (priv->model_name);
+	g_free (priv->serial);
 
 	G_OBJECT_CLASS (rb_mtp_source_parent_class)->finalize (object);
 }
@@ -383,16 +410,13 @@ impl_get_paned_key (RBBrowserSource *source)
 	return g_strdup (CONF_STATE_PANED_POSITION);
 }
 
-#if defined(HAVE_GUDEV)
 RBSource *
 rb_mtp_source_new (RBShell *shell,
-		   LIBMTP_raw_device_t *device)
-#else
-RBSource *
-rb_mtp_source_new (RBShell *shell,
-		   LIBMTP_raw_device_t *device,
-		   const char *udi)
+		   RBPlugin *plugin,
+#if !defined(HAVE_GUDEV)
+		   const char *udi,
 #endif
+		   LIBMTP_raw_device_t *device)
 {
 	RBMtpSource *source = NULL;
 	RhythmDBEntryType entry_type;
@@ -410,6 +434,7 @@ rb_mtp_source_new (RBShell *shell,
 	g_object_unref (db);
 
 	source = RB_MTP_SOURCE (g_object_new (RB_TYPE_MTP_SOURCE,
+					      "plugin", plugin,
 					      "entry-type", entry_type,
 					      "shell", shell,
 					      "visibility", TRUE,
@@ -427,6 +452,33 @@ rb_mtp_source_new (RBShell *shell,
 }
 
 static void
+update_free_space_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	LIBMTP_devicestorage_t *storage;
+	int ret;
+
+	ret = LIBMTP_Get_Storage (device, LIBMTP_STORAGE_SORTBY_NOTSORTED);
+	if (ret != 0) {
+		rb_mtp_thread_report_errors (priv->device_thread, FALSE);
+	}
+
+	/* probably need a lock for this.. */
+	priv->free_space = 0;
+	for (storage = device->storage; storage != NULL; storage = storage->next) {
+		priv->free_space += storage->FreeSpaceInBytes;
+	}
+}
+
+static void
+queue_free_space_update (RBMtpSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	rb_mtp_thread_queue_callback (priv->device_thread,
+				      (RBMtpThreadCallback) update_free_space_cb, source, NULL);
+}
+
+static void
 entry_set_string_prop (RhythmDB *db,
 		       RhythmDBEntry *entry,
 		       RhythmDBPropType propid,
@@ -676,6 +728,25 @@ mtp_device_open_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
 		data->name = g_strdup (_("Digital Audio Player"));
 	}
 
+	/* get some other device information that doesn't change */
+	priv->manufacturer = LIBMTP_Get_Manufacturername (device);
+	priv->device_version = LIBMTP_Get_Deviceversion (device);
+	priv->model_name = LIBMTP_Get_Modelname (device);
+	priv->serial = LIBMTP_Get_Serialnumber (device);
+
+	/* calculate the device capacity */
+	priv->capacity = 0;
+	if (LIBMTP_Get_Storage (device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == 0) {
+		LIBMTP_devicestorage_t *storage;
+		for (storage = device->storage;
+		     storage != NULL;
+		     storage = storage->next) {
+			priv->capacity += storage->MaxCapacity;
+		}
+	}
+
+	update_free_space_cb (device, RB_MTP_SOURCE (source));
+
 	/* figure out the set of formats supported by the device */
 	if (LIBMTP_Get_Supported_Filetypes (device, &data->types, &data->num_types) != 0) {
 		rb_mtp_thread_report_errors (priv->device_thread, FALSE);
@@ -892,6 +963,7 @@ impl_track_added (RBRemovableMediaSource *source,
 		artdata->entry = rhythmdb_entry_ref (mtp_entry);
 		g_idle_add ((GSourceFunc) request_album_art_idle, artdata);
 	}
+	queue_free_space_update (RB_MTP_SOURCE (source));
 	return FALSE;
 }
 
@@ -910,6 +982,7 @@ impl_track_add_error (RBRemovableMediaSource *source,
 	} else {
 		rb_debug ("track-add-error called, but can't find a track for dest URI %s", dest);
 	}
+
 	return TRUE;
 }
 
@@ -1040,10 +1113,112 @@ artwork_notify_cb (RhythmDB *db,
 	pixbuf = GDK_PIXBUF (g_value_get_object (metadata));
 
 	rb_mtp_thread_set_album_image (priv->device_thread, album_name, pixbuf);
+	queue_free_space_update (source);
 
 	g_object_unref (pixbuf);		/* ? */
 }
 
+static guint64
+impl_get_capacity	(RBMediaPlayerSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	return priv->capacity;
+}
+
+static guint64
+impl_get_free_space	(RBMediaPlayerSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	/* probably need a lock for this */
+	return priv->free_space;
+}
+
+static void
+impl_show_properties (RBMediaPlayerSource *source, GtkWidget *info_box, GtkWidget *notebook)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	GtkBuilder *builder;
+	GtkWidget *widget;
+	GHashTableIter iter;
+	gpointer key, value;
+	int num_podcasts;
+	char *device_name;
+	char *builder_file;
+	RBPlugin *plugin;
+	char *text;
+
+	g_object_get (source, "plugin", &plugin, NULL);
+	builder_file = rb_plugin_find_file (plugin, "mtp-info.ui");
+	g_object_unref (plugin);
+
+	if (builder_file == NULL) {
+		g_warning ("Couldn't find mtp-info.ui");
+		return;
+	}
+
+	builder = rb_builder_load (builder_file, NULL);
+	g_free (builder_file);
+
+	if (builder == NULL) {
+		rb_debug ("Couldn't load mtp-info.ui");
+		return;
+	}
+
+	/* 'basic' tab stuff */
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtp-basic-info"));
+	gtk_box_pack_start (GTK_BOX (info_box), widget, TRUE, TRUE, 0);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "entry-mtp-name"));
+	g_object_get (source, "name", &device_name, NULL);
+	gtk_entry_set_text (GTK_ENTRY (widget), device_name);
+	g_free (device_name);
+	g_signal_connect (widget, "focus-out-event",
+			  (GCallback)rb_mtp_source_name_changed_cb, source);
+
+	num_podcasts = 0;
+	g_hash_table_iter_init (&iter, priv->entry_map);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		LIBMTP_track_t *track = value;
+		if (g_strcmp0 (track->genre, "Podcast") == 0) {
+			num_podcasts++;
+		}
+	}
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtp-num-tracks"));
+	text = g_strdup_printf ("%d", g_hash_table_size (priv->entry_map) - num_podcasts);
+	gtk_label_set_text (GTK_LABEL (widget), text);
+	g_free (text);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtp-num-podcasts"));
+	text = g_strdup_printf ("%d", num_podcasts);
+	gtk_label_set_text (GTK_LABEL (widget), text);
+	g_free (text);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtp-num-playlists"));
+	text = g_strdup_printf ("%d", 0);						/* correct, but wrong */
+	gtk_label_set_text (GTK_LABEL (widget), text);
+	g_free (text);
+
+	/* 'advanced' tab stuff */
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtp-advanced-tab"));
+	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), widget, gtk_label_new (_("Advanced")));
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "label-mtp-model-value"));
+	gtk_label_set_text (GTK_LABEL (widget), priv->model_name);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "label-serial-number-value"));
+	gtk_label_set_text (GTK_LABEL (widget), priv->serial);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "label-firmware-version-value"));
+	gtk_label_set_text (GTK_LABEL (widget), priv->device_version);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "label-manufacturer-value"));
+	gtk_label_set_text (GTK_LABEL (widget), priv->manufacturer);
+
+	g_object_unref (builder);
+}
+
 static void
 prepare_source (RBMtpSource *source, const char *stream_uri, GObject *src)
 {
diff --git a/plugins/mtpdevice/rb-mtp-source.h b/plugins/mtpdevice/rb-mtp-source.h
index 1859903..524db5e 100644
--- a/plugins/mtpdevice/rb-mtp-source.h
+++ b/plugins/mtpdevice/rb-mtp-source.h
@@ -30,6 +30,8 @@
 
 #include "rb-shell.h"
 #include "rb-removable-media-source.h"
+#include "rb-media-player-source.h"
+#include "rb-plugin.h"
 #include "rhythmdb.h"
 #include <libmtp.h>
 
@@ -44,19 +46,20 @@ G_BEGIN_DECLS
 
 typedef struct
 {
-	RBRemovableMediaSource parent;
+	RBMediaPlayerSource parent;
 } RBMtpSource;
 
 typedef struct
 {
-	RBRemovableMediaSourceClass parent;
+	RBMediaPlayerSourceClass parent;
 } RBMtpSourceClass;
 
-#if defined(HAVE_GUDEV)
-RBSource *		rb_mtp_source_new		(RBShell *shell, LIBMTP_raw_device_t *device);
-#else
-RBSource *		rb_mtp_source_new		(RBShell *shell, LIBMTP_raw_device_t *device, const char *udi);
+RBSource *		rb_mtp_source_new		(RBShell *shell,
+							 RBPlugin *plugin,
+#if !defined(HAVE_GUDEV)
+							 const char *udi,
 #endif
+							 LIBMTP_raw_device_t *device);
 
 GType			rb_mtp_source_get_type		(void);
 GType			rb_mtp_source_register_type	(GTypeModule *module);
diff --git a/plugins/mtpdevice/rb-mtp-thread.c b/plugins/mtpdevice/rb-mtp-thread.c
index 61c5fde..95af372 100644
--- a/plugins/mtpdevice/rb-mtp-thread.c
+++ b/plugins/mtpdevice/rb-mtp-thread.c
@@ -46,6 +46,7 @@ typedef struct {
 		OPEN_DEVICE = 1,
 		CLOSE_DEVICE,
 		SET_DEVICE_NAME,
+		THREAD_CALLBACK,
 
 		ADD_TO_ALBUM,
 		REMOVE_FROM_ALBUM,
@@ -78,6 +79,7 @@ task_name (RBMtpThreadTask *task)
 	case OPEN_DEVICE:	return g_strdup ("open device");
 	case CLOSE_DEVICE:	return g_strdup ("close device");
 	case SET_DEVICE_NAME:	return g_strdup_printf ("set device name to %s", task->name);
+	case THREAD_CALLBACK:	return g_strdup ("thread callback");
 
 	case ADD_TO_ALBUM:	return g_strdup_printf ("add track %u to album %s", task->track_id, task->album);
 	case REMOVE_FROM_ALBUM:	return g_strdup_printf ("remove track %u from album %s", task->track_id, task->album);
@@ -538,6 +540,13 @@ run_task (RBMtpThread *thread, RBMtpThreadTask *task)
 		}
 		break;
 
+	case THREAD_CALLBACK:
+		{
+			RBMtpThreadCallback cb = (RBMtpThreadCallback)task->callback;
+			cb (thread->device, task->user_data);
+		}
+		break;
+
 	case ADD_TO_ALBUM:
 		add_track_to_album_and_update (thread, task);
 		break;
@@ -709,6 +718,19 @@ rb_mtp_thread_download_track (RBMtpThread *thread,
 }
 
 void
+rb_mtp_thread_queue_callback (RBMtpThread *thread,
+			      RBMtpThreadCallback func,
+			      gpointer data,
+			      GDestroyNotify destroy_data)
+{
+	RBMtpThreadTask *task = create_task (THREAD_CALLBACK);
+	task->callback = func;
+	task->user_data = data;
+	task->destroy_data = destroy_data;
+	queue_task (thread, task);
+}
+
+void
 rb_mtp_thread_report_errors (RBMtpThread *thread, gboolean use_dialog)
 {
 	LIBMTP_error_t *stack;
diff --git a/plugins/mtpdevice/rb-mtp-thread.h b/plugins/mtpdevice/rb-mtp-thread.h
index c03597a..e37f2f6 100644
--- a/plugins/mtpdevice/rb-mtp-thread.h
+++ b/plugins/mtpdevice/rb-mtp-thread.h
@@ -82,7 +82,7 @@ typedef void (*RBMtpOpenCallback) (LIBMTP_mtpdevice_t *device, gpointer user_dat
 typedef void (*RBMtpTrackListCallback) (LIBMTP_track_t *tracklist, gpointer user_data);
 typedef void (*RBMtpUploadCallback) (LIBMTP_track_t *track, GError *error, gpointer user_data);
 typedef void (*RBMtpDownloadCallback) (uint32_t track_id, const char *filename, GError *error, gpointer user_data);
-typedef void (*RBMtpCreatePlaylistCallback) (LIBMTP_playlist_t *playlist, gpointer user_data);
+typedef void (*RBMtpThreadCallback) (LIBMTP_mtpdevice_t *device, gpointer user_data);
 
 GType		rb_mtp_thread_get_type (void);
 RBMtpThread *	rb_mtp_thread_new (void);
@@ -101,6 +101,11 @@ void		rb_mtp_thread_get_track_list (RBMtpThread *thread,
 
 void		rb_mtp_thread_set_device_name (RBMtpThread *thread, const char *name);
 
+void		rb_mtp_thread_queue_callback (RBMtpThread *thread,
+					      RBMtpThreadCallback func,
+					      gpointer data,
+					      GDestroyNotify destroy_data);
+
 /* albums */
 void		rb_mtp_thread_add_to_album (RBMtpThread *thread, LIBMTP_track_t *track, const char *album);
 void		rb_mtp_thread_remove_from_album (RBMtpThread *thread, LIBMTP_track_t *track, const char *album);



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