[gnome-shell/hotplug: 8/21] sniffer: don't misuse x-content/audio-player and x-content/dcf-image



commit 3d9d92fc323b74163f7659962022b8dfb48be689
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Tue Jun 21 21:49:12 2011 -0400

    sniffer: don't misuse x-content/audio-player and x-content/dcf-image
    
    Instead, use new custom x-content mime types (x-content/video,
    x-content/audio, x-content/documents, x-content/pictures). Those can be
    set opt-in from applications who support removable devices as content
    repositories to browse.

 js/ui/autorunManager.js                  |   94 +++++++++++++---------------
 src/hotplug-sniffer/hotplug-mimetypes.h  |   11 +---
 src/hotplug-sniffer/hotplug-sniffer.c    |   34 +++++++---
 src/hotplug-sniffer/shell-mime-sniffer.c |  100 +++++++++++++++++++++---------
 src/hotplug-sniffer/shell-mime-sniffer.h |    6 +-
 5 files changed, 143 insertions(+), 102 deletions(-)
---
diff --git a/js/ui/autorunManager.js b/js/ui/autorunManager.js
index 1ce84cb..39ac9f3 100644
--- a/js/ui/autorunManager.js
+++ b/js/ui/autorunManager.js
@@ -56,7 +56,7 @@ const HotplugSnifferIface = {
     name: 'org.gnome.Shell.HotplugSniffer',
     methods: [{ name: 'SniffURI',
                 inSignature: 's',
-                outSignature: 's' }]
+                outSignature: 'as' }]
 };
 
 const HotplugSniffer = function() {
@@ -98,32 +98,41 @@ ContentTypeDiscoverer.prototype = {
                 + ': ' + e.toString());
         }
 
-        if (!contentTypes.length) {
+        if (contentTypes.length) {
+            this._emitCallback(mount, contentTypes);
+        } else {
             let root = mount.get_root();
 
             let hotplugSniffer = new HotplugSniffer();
             hotplugSniffer.SniffURIRemote
                 (root.get_uri(), DBus.CALL_FLAG_START,
-                 Lang.bind(this, function(contentType) {
-                     if (contentType && contentType != '') {
-                         contentTypes = new Array();
-                         contentTypes.push(contentType);
-                     }
-
+                 Lang.bind(this, function(contentTypes) {
                      this._emitCallback(mount, contentTypes);
                  }));
-        } else {
-            this._emitCallback(mount, contentTypes);
         }
     },
 
     _emitCallback: function(mount, contentTypes) {
+        if (!contentTypes || !contentTypes.length)
+            contentTypes.push('inode/directory');
+
         // we're not interested in win32 software content types here
         contentTypes = contentTypes.filter(function(type) {
             return (type != 'x-content/win32-software');
         });
 
-        this._callback(mount, contentTypes);
+        let apps = new Array();
+        contentTypes.forEach(function(type) {
+            let app = Gio.app_info_get_default_for_type(type, false);
+
+            if (app)
+                apps.push(app);
+        });
+
+        if (!apps.length)
+            apps.push(Gio.app_info_get_default_for_type('inode/directory', false));
+
+        this._callback(mount, apps, contentTypes);
     }
 }
 
@@ -152,8 +161,8 @@ AutorunManager.prototype = {
 
         mounts.forEach(Lang.bind(this, function (mount) {
             let discoverer = new ContentTypeDiscoverer(
-                Lang.bind (this, function (mount, contentTypes) {
-                    this._residentSource.addMount(mount, contentTypes);
+                Lang.bind (this, function (mount, apps) {
+                    this._residentSource.addMount(mount, apps);
                 }));
 
             discoverer.guessContentTypes(mount);
@@ -178,9 +187,9 @@ AutorunManager.prototype = {
             return;
 
         let discoverer = new ContentTypeDiscoverer
-            (Lang.bind (this, function (mount, contentTypes) {
-                this._transDispatcher.addMount(mount, contentTypes);
-                this._residentSource.addMount(mount, contentTypes);
+            (Lang.bind (this, function (mount, apps, contentTypes) {
+                this._transDispatcher.addMount(mount, apps, contentTypes);
+                this._residentSource.addMount(mount, apps);
             }));
 
         discoverer.guessContentTypes(mount);
@@ -234,7 +243,7 @@ AutorunResidentSource.prototype = {
         this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE));
     },
 
-    addMount: function(mount, contentTypes) {
+    addMount: function(mount, apps) {
         if (ignoreAutorunForMount(mount))
             return;
 
@@ -245,7 +254,7 @@ AutorunResidentSource.prototype = {
         if (filtered.length != 0)
             return;
 
-        let element = { mount: mount, contentTypes: contentTypes };
+        let element = { mount: mount, apps: apps };
         this._mounts.push(element);
         this._redisplay();
     },
@@ -315,13 +324,13 @@ AutorunResidentNotification.prototype = {
         for (let idx = 0; idx < mounts.length; idx++) {
             let element = mounts[idx];
 
-            let actor = this._itemForMount(element.mount, element.contentTypes);
+            let actor = this._itemForMount(element.mount, element.apps);
             this._layout.add(actor, { x_fill: true,
                                       expand: true });
         }
     },
 
-    _itemForMount: function(mount, contentTypes) {
+    _itemForMount: function(mount, apps) {
         let item = new St.BoxLayout();
 
         let mountLayout = new St.BoxLayout({ style_class: 'hotplug-resident-mount',
@@ -352,21 +361,15 @@ AutorunResidentNotification.prototype = {
 
         item.add(ejectButton, { x_align: St.Align.END });
 
-        // TODO: need to do something better here...
-        if (!contentTypes.length)
-            contentTypes.push('inode/directory');
-
         // now connect signals
         mountLayout.connect('button-press-event', Lang.bind(this, function(actor, event) {
             // ignore clicks not coming from the left mouse button
             if (event.get_button() != 1)
                 return false;
 
-            let app = Gio.app_info_get_default_for_type(contentTypes[0], false);
+            let app = apps[0];
+            startAppForMount(app, mount);
 
-            if (app)
-                startAppForMount(app, mount);
-            
             return true;
         }));
 
@@ -425,17 +428,17 @@ AutorunTransientDispatcher.prototype = {
         return null;
     },
 
-    _addSource: function(mount, contentTypes) {
+    _addSource: function(mount, apps) {
         // if we already have a source showing for this 
         // mount, return
         if (this._getSourceForMount(mount))
             return;
      
         // add a new source
-        this._sources.push(new AutorunTransientSource(mount, contentTypes));
+        this._sources.push(new AutorunTransientSource(mount, apps));
     },
 
-    addMount: function(mount, contentTypes) {
+    addMount: function(mount, apps, contentTypes) {
         // if autorun is disabled globally, return
         if (this._settings.get_boolean(SETTING_DISABLE_AUTORUN))
             return;
@@ -470,7 +473,7 @@ AutorunTransientDispatcher.prototype = {
         // we fallback here also in case the settings did not specify 'ask',
         // but we failed launching the default app or the default file manager
         if (!success)
-            this._addSource(mount, contentTypes);
+            this._addSource(mount, apps);
     },
 
     removeMount: function(mount) {
@@ -485,18 +488,18 @@ AutorunTransientDispatcher.prototype = {
     }
 }
 
-function AutorunTransientSource(mount, contentTypes) {
-    this._init(mount, contentTypes);
+function AutorunTransientSource(mount, apps) {
+    this._init(mount, apps);
 }
 
 AutorunTransientSource.prototype = {
     __proto__: MessageTray.Source.prototype,
 
-    _init: function(mount, contentTypes) {
+    _init: function(mount, apps) {
         MessageTray.Source.prototype._init.call(this, mount.get_name());
 
         this._mount = mount;
-        this._contentTypes = contentTypes;
+        this._apps = apps;
 
         this._buildNotification();
     },
@@ -509,22 +512,14 @@ AutorunTransientSource.prototype = {
                                        vertical: true });
         this._notification.addActor(this._box);
 
-        this._contentTypes.forEach(Lang.bind(this, function (type) {
-            let actor = this._buttonForContentType(type);
+        this._apps.forEach(Lang.bind(this, function (app) {
+            let actor = this._buttonForApp(app);
 
             if (actor)
                 this._box.add(actor, { x_fill: true,
                                        x_align: St.Align.START });
         }));
 
-        // TODO: ideally we never want to show the file manager entry here,
-        // but we want to detect which kind of files are present on the device,
-        // and use those to present a more meaningful choice.
-        if (this._contentTypes.length == 0)
-            this._box.add (this._buttonForContentType('inode/directory'),
-                           { x_fill: true,
-                             x_align: St.Align.START });
-
         this._box.add(this._buttonForEject(), { x_fill: true,
                                                 x_align: St.Align.START });
 
@@ -533,12 +528,7 @@ AutorunTransientSource.prototype = {
         this.notify(this._notification);
     },
 
-    _buttonForContentType: function(type) {
-        let app = Gio.app_info_get_default_for_type(type, false);
-
-        if (!app)
-            return null;
-
+    _buttonForApp: function(app) {
         let box = new St.BoxLayout({ style_class: 'hotplug-notification-item',
                                      track_hover: true,
                                      reactive: true });
diff --git a/src/hotplug-sniffer/hotplug-mimetypes.h b/src/hotplug-sniffer/hotplug-mimetypes.h
index 73ac0c1..2dee87d 100644
--- a/src/hotplug-sniffer/hotplug-mimetypes.h
+++ b/src/hotplug-sniffer/hotplug-mimetypes.h
@@ -3,12 +3,7 @@
 
 #include <glib.h>
 
-#include "hotplug-mimetypes.h"
-#include "shell-mime-sniffer.h"
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-static const gchar *docs_mimetypes[] = {
+G_GNUC_UNUSED static const gchar *docs_mimetypes[] = {
   "application/vnd.oasis.opendocument.text",
   "application/vnd.oasis.opendocument.presentation",
   "application/vnd.oasis.opendocument.spreadsheet",
@@ -37,7 +32,7 @@ static const gchar *docs_mimetypes[] = {
   NULL
 };
 
-static const gchar *video_mimetypes[] = {
+G_GNUC_UNUSED static const gchar *video_mimetypes[] = {
   "application/mxf",
   "application/ogg",
   "application/ram",
@@ -95,7 +90,7 @@ static const gchar *video_mimetypes[] = {
   NULL
 };
 
-static const gchar *audio_mimetypes[] = {
+G_GNUC_UNUSED static const gchar *audio_mimetypes[] = {
   "audio/3gpp",
   "audio/ac3",
   "audio/AMR",
diff --git a/src/hotplug-sniffer/hotplug-sniffer.c b/src/hotplug-sniffer/hotplug-sniffer.c
index baaa18b..cccf570 100644
--- a/src/hotplug-sniffer/hotplug-sniffer.c
+++ b/src/hotplug-sniffer/hotplug-sniffer.c
@@ -16,7 +16,8 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  *
- * Author: Cosimo Cecchi <cosimoc redhat com>
+ * Authors: David Zeuthen <davidz redhat com>
+ *          Cosimo Cecchi <cosimoc redhat com>
  *
  */
 
@@ -34,7 +35,7 @@ static const gchar introspection_xml[] =
   "  <interface name='org.gnome.Shell.HotplugSniffer'>"
   "    <method name='SniffURI'>"
   "      <arg type='s' name='uri' direction='in'/>"
-  "      <arg type='s' name='content_type' direction='out'/>"
+  "      <arg type='as' name='content_types' direction='out'/>"
   "    </method>"
   "  </interface>"
   "</node>";
@@ -111,23 +112,36 @@ sniff_async_ready_cb (GObject *source,
                       gpointer user_data)
 {
   InvocationData *data = user_data;
-  gchar *content_type;
+  gchar **types;
+  gint idx;
+  GError *error = NULL;
+  GVariantBuilder *builder;
   GVariant *result;
 
-  content_type = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
-                                                  res, NULL);
+  types = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
+                                           res, &error);
 
-  if (content_type == NULL)
-    content_type = g_strdup ("");
+  if (error != NULL)
+    {
+      g_dbus_method_invocation_return_gerror (data->invocation, error);
+      g_error_free (error);
+      goto out;
+    }
 
-  print_debug ("Sniffed mimetype %s", content_type);
+  builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
 
-  result = g_variant_new ("(s)", content_type);
+  for (idx = 0; types[idx] != NULL; idx++)
+    g_variant_builder_add (builder, "s", types[idx]);
+
+  result = g_variant_new ("(as)", builder);
   g_dbus_method_invocation_return_value (data->invocation, result);
 
   g_variant_unref (result);
-  invocation_data_free (data);
+  g_variant_builder_unref (builder);
+  g_strfreev (types);
 
+ out:
+  invocation_data_free (data);
   ensure_autoquit_on ();
 }
 
diff --git a/src/hotplug-sniffer/shell-mime-sniffer.c b/src/hotplug-sniffer/shell-mime-sniffer.c
index 3f9f1f2..d49d6b9 100644
--- a/src/hotplug-sniffer/shell-mime-sniffer.c
+++ b/src/hotplug-sniffer/shell-mime-sniffer.c
@@ -33,6 +33,8 @@
 
 #include <glib/gi18n.h>
 
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
 #define LOADER_ATTRS                          \
   G_FILE_ATTRIBUTE_STANDARD_TYPE ","          \
   G_FILE_ATTRIBUTE_STANDARD_NAME ","          \
@@ -67,6 +69,8 @@ typedef struct {
   gint image_count;
   gint document_count;
   gint video_count;
+
+  gint total_items;
 } DeepCountState;
 
 struct _ShellMimeSnifferPrivate {
@@ -76,7 +80,7 @@ struct _ShellMimeSnifferPrivate {
   guint watchdog_id;
 
   GSimpleAsyncResult *async_result;
-  gchar *content_type;
+  gchar **sniffed_mime;
 };
 
 static void deep_count_load (DeepCountState *state,
@@ -131,6 +135,8 @@ static void
 add_content_type_to_cache (DeepCountState *state,
                            const gchar *content_type)
 {
+  gboolean matched = TRUE;
+
   if (g_hash_table_lookup (image_type_table, content_type))
     state->image_count++;
   else if (g_hash_table_lookup (video_type_table, content_type))
@@ -139,46 +145,82 @@ add_content_type_to_cache (DeepCountState *state,
     state->document_count++;
   else if (g_hash_table_lookup (audio_type_table, content_type))
     state->audio_count++;
+  else
+    matched = FALSE;
+
+  if (matched)
+    state->total_items++;
+}
+
+typedef struct {
+  const gchar *type;
+  gdouble ratio;
+} SniffedResult;
+
+static gint
+results_cmp_func (gconstpointer a,
+                  gconstpointer b)
+{
+  const SniffedResult *sniffed_a = a;
+  const SniffedResult *sniffed_b = b;
+
+  if (sniffed_a->ratio < sniffed_b->ratio)
+    return 1;
+
+  if (sniffed_a->ratio > sniffed_b->ratio)
+    return -1;
+
+  return 0;
 }
 
 static void
 prepare_async_result (DeepCountState *state)
 {
   ShellMimeSniffer *self = state->self;
-  gboolean video_wins, audio_wins, image_wins;
+  GArray *results;
+  GPtrArray *sniffed_mime;
+  SniffedResult result;
 
-  audio_wins = (state->audio_count > state->image_count) &&
-    (state->audio_count > state->document_count) &&
-    (state->audio_count > state->video_count);
+  sniffed_mime = g_ptr_array_new ();
+  results = g_array_new (TRUE, TRUE, sizeof (SniffedResult));
 
-  if (audio_wins)
-    {
-      self->priv->content_type = g_strdup ("x-content/audio-player");
-      goto out;
-    }
+  result.type = "x-content/video";
+  result.ratio = (gdouble) state->video_count / (gdouble) state->total_items;
+  g_array_append_val (results, result);
 
-  image_wins = (state->image_count > state->audio_count) &&
-    (state->image_count > state->document_count) &&
-    (state->image_count > state->video_count);
+  result.type = "x-content/audio";
+  result.ratio = (gdouble) state->audio_count / (gdouble) state->total_items;
+  g_array_append_val (results, result);
 
-  if (image_wins)
-    {
-      self->priv->content_type = g_strdup ("x-content/image-dcf");
-      goto out;
-    }
+  result.type = "x-content/pictures";
+  result.ratio = (gdouble) state->image_count / (gdouble) state->total_items;
+  g_array_append_val (results, result);
 
-  video_wins = (state->video_count > state->image_count) &&
-    (state->video_count > state->document_count) &&
-    (state->video_count > state->audio_count);
+  result.type = "x-content/documents";
+  result.ratio = (gdouble) state->document_count / (gdouble) state->total_items;
+  g_array_append_val (results, result);
 
-  /* FIXME: we don't have any content type for video collections! */
-  if (video_wins)
+  g_array_sort (results, results_cmp_func);
+
+  result = g_array_index (results, SniffedResult, 0);
+  g_ptr_array_add (sniffed_mime, g_strdup (result.type));
+
+  /* if other types score high in ratio, add them, up to three */
+  result = g_array_index (results, SniffedResult, 1);
+  if (result.ratio < HIGH_SCORE_RATIO)
     goto out;
+  g_ptr_array_add (sniffed_mime, g_strdup (result.type));
 
-  /* FIXME: we don't have any content type for document collections! */
-  goto out;
+  result = g_array_index (results, SniffedResult, 2);
+  if (result.ratio < HIGH_SCORE_RATIO)
+    goto out;
+  g_ptr_array_add (sniffed_mime, g_strdup (result.type));
 
  out:
+  g_ptr_array_add (sniffed_mime, NULL);
+  self->priv->sniffed_mime = (gchar **) g_ptr_array_free (sniffed_mime, FALSE);
+
+  g_array_free (results, TRUE);
   g_simple_async_result_complete_in_idle (self->priv->async_result);
 }
 
@@ -288,7 +330,7 @@ deep_count_more_files_callback (GObject *source_object,
     {
       g_file_enumerator_next_files_async (state->enumerator,
                                           DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
-                                          G_PRIORITY_DEFAULT,
+                                          G_PRIORITY_LOW,
                                           state->self->priv->cancellable,
                                           deep_count_more_files_callback,
                                           state);
@@ -447,7 +489,7 @@ shell_mime_sniffer_finalize (GObject *object)
 {
   ShellMimeSniffer *self = SHELL_MIME_SNIFFER (object);
 
-  g_free (self->priv->content_type);
+  g_strfreev (self->priv->sniffed_mime);
 
   G_OBJECT_CLASS (shell_mime_sniffer_parent_class)->finalize (object);
 }
@@ -551,7 +593,7 @@ shell_mime_sniffer_sniff_async (ShellMimeSniffer *self,
   start_loading_file (self);
 }
 
-gchar *
+gchar **
 shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
                                  GAsyncResult *res,
                                  GError **error)
@@ -559,5 +601,5 @@ shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
   if (g_simple_async_result_propagate_error (self->priv->async_result, error))
     return NULL;
 
-  return self->priv->content_type;
+  return g_strdupv (self->priv->sniffed_mime);
 }
diff --git a/src/hotplug-sniffer/shell-mime-sniffer.h b/src/hotplug-sniffer/shell-mime-sniffer.h
index c208eb6..b87e387 100644
--- a/src/hotplug-sniffer/shell-mime-sniffer.h
+++ b/src/hotplug-sniffer/shell-mime-sniffer.h
@@ -59,9 +59,9 @@ void shell_mime_sniffer_sniff_async (ShellMimeSniffer *self,
                                      GAsyncReadyCallback callback,
                                      gpointer user_data);
 
-gchar * shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
-                                         GAsyncResult *res,
-                                         GError **error);
+gchar ** shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
+                                          GAsyncResult *res,
+                                          GError **error);
 
 G_END_DECLS
 



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