[gnome-flashback] Add libautomount-manager



commit 87aa3382824a806bcb06692b63981df1792a4ef7
Author: Balló György <ballogyor gmail com>
Date:   Sat Oct 18 22:45:08 2014 +0200

    Add libautomount-manager
    
    It was previously in gnome-settings-daemon.

 configure.ac                                       |    5 +
 data/org.gnome.gnome-flashback.gschema.xml.in.in   |    5 +
 gnome-flashback/Makefile.am                        |    2 +
 gnome-flashback/flashback-application.c            |   22 +-
 gnome-flashback/libautomount-manager/Makefile.am   |   17 +
 .../libautomount-manager/gsd-automount-manager.c   |  571 ++++++++++++
 .../libautomount-manager/gsd-automount-manager.h   |   58 ++
 gnome-flashback/libautomount-manager/gsd-autorun.c |  975 ++++++++++++++++++++
 gnome-flashback/libautomount-manager/gsd-autorun.h |   53 ++
 po/POTFILES.in                                     |    2 +
 10 files changed, 1709 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1ced253..6f5ee7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,10 @@ PKG_CHECK_MODULES(END_SESSION_DIALOG, gtk+-3.0 >= $GTK_REQUIRED)
 AC_SUBST(END_SESSION_DIALOG_CFLAGS)
 AC_SUBST(END_SESSION_DIALOG_LIBS)
 
+PKG_CHECK_MODULES(AUTOMOUNT_MANAGER, gtk+-3.0 >= $GTK_REQUIRED)
+AC_SUBST(AUTOMOUNT_MANAGER_CFLAGS)
+AC_SUBST(AUTOMOUNT_MANAGER_LIBS)
+
 PKG_CHECK_MODULES(DESKTOP_BACKGROUND, gtk+-3.0 >= $GTK_REQUIRED gnome-desktop-3.0 >= 
$LIBGNOME_DESKTOP_REQUIRED)
 AC_SUBST(DESKTOP_BACKGROUND_CFLAGS)
 AC_SUBST(DESKTOP_BACKGROUND_LIBS)
@@ -67,6 +71,7 @@ AC_CONFIG_FILES([
 Makefile
 data/Makefile
 gnome-flashback/Makefile
+gnome-flashback/libautomount-manager/Makefile
 gnome-flashback/libdesktop-background/Makefile
 gnome-flashback/libdisplay-config/Makefile
 gnome-flashback/libend-session-dialog/Makefile
diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in 
b/data/org.gnome.gnome-flashback.gschema.xml.in.in
index 38ed32b..5c766a2 100644
--- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
+++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
@@ -1,5 +1,10 @@
 <schemalist gettext-domain="@GETTEXT_PACKAGE@">
        <schema id="org.gnome.gnome-flashback" path="/org/gnome/gnome-flashback/">
+               <key name="automount-manager" type="b">
+                       <default>true</default>
+                       <_summary>Automount manager</_summary>
+                       <_description>If set to true, then GNOME Flashback application will be used to 
automount removable media.</_description>
+               </key>
                <key name="desktop-background" type="b">
                        <default>true</default>
                        <_summary>Desktop background</_summary>
diff --git a/gnome-flashback/Makefile.am b/gnome-flashback/Makefile.am
index 48f1b50..14f3e08 100644
--- a/gnome-flashback/Makefile.am
+++ b/gnome-flashback/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = \
+       libautomount-manager \
        libdesktop-background \
        libdisplay-config \
        libend-session-dialog \
@@ -20,6 +21,7 @@ gnome_flashback_SOURCES = \
 
 gnome_flashback_LDADD = \
        $(GNOME_FLASHBACK_LIBS) \
+       $(top_builddir)/gnome-flashback/libautomount-manager/libautomount-manager.la \
        $(top_builddir)/gnome-flashback/libdesktop-background/libdesktop-background.la \
        $(top_builddir)/gnome-flashback/libdisplay-config/libdisplay-config.la \
        $(top_builddir)/gnome-flashback/libend-session-dialog/libend-session-dialog.la \
diff --git a/gnome-flashback/flashback-application.c b/gnome-flashback/flashback-application.c
index dc5afda..2375229 100644
--- a/gnome-flashback/flashback-application.c
+++ b/gnome-flashback/flashback-application.c
@@ -19,6 +19,7 @@
 #include <gtk/gtk.h>
 #include "config.h"
 #include "flashback-application.h"
+#include "libautomount-manager/gsd-automount-manager.h"
 #include "libdesktop-background/desktop-background.h"
 #include "libdisplay-config/flashback-display-config.h"
 #include "libend-session-dialog/flashback-end-session-dialog.h"
@@ -26,6 +27,7 @@
 #include "libsound-applet/gvc-applet.h"
 
 #define FLASHBACK_SCHEMA       "org.gnome.gnome-flashback"
+#define KEY_AUTOMOUNT_MANAGER  "automount-manager"
 #define KEY_DESKTOP_BACKGROUND "desktop-background"
 #define KEY_DISPLAY_CONFIG     "display-config"
 #define KEY_END_SESSION_DIALOG "end-session-dialog"
@@ -34,7 +36,7 @@
 
 struct _FlashbackApplicationPrivate {
        GSettings                  *settings;
-
+       GsdAutomountManager        *automount;
        DesktopBackground          *background;
        FlashbackDisplayConfig     *config;
        FlashbackEndSessionDialog  *dialog;
@@ -51,6 +53,19 @@ flashback_application_settings_changed (GSettings   *settings,
 {
        FlashbackApplication *app = FLASHBACK_APPLICATION (user_data);
 
+       if (key == NULL || g_strcmp0 (key, KEY_AUTOMOUNT_MANAGER) == 0) {
+               if (g_settings_get_boolean (settings, KEY_AUTOMOUNT_MANAGER)) {
+                       if (app->priv->automount == NULL) {
+                               app->priv->automount = gsd_automount_manager_new ();
+                       }
+               } else {
+                       if (app->priv->automount) {
+                               g_object_unref (app->priv->automount);
+                               app->priv->automount = NULL;
+                       }
+               }
+       }
+
        if (key == NULL || g_strcmp0 (key, KEY_DESKTOP_BACKGROUND) == 0) {
                if (g_settings_get_boolean (settings, KEY_DESKTOP_BACKGROUND)) {
                        if (app->priv->background == NULL) {
@@ -147,6 +162,11 @@ flashback_application_shutdown (GApplication *application)
 {
        FlashbackApplication *app = FLASHBACK_APPLICATION (application);
 
+       if (app->priv->automount) {
+               g_object_unref (app->priv->automount);
+               app->priv->automount = NULL;
+       }
+
        if (app->priv->background) {
                g_object_unref (app->priv->background);
                app->priv->background = NULL;
diff --git a/gnome-flashback/libautomount-manager/Makefile.am 
b/gnome-flashback/libautomount-manager/Makefile.am
new file mode 100644
index 0000000..d73127b
--- /dev/null
+++ b/gnome-flashback/libautomount-manager/Makefile.am
@@ -0,0 +1,17 @@
+noinst_LTLIBRARIES = \
+       libautomount-manager.la
+
+AM_CPPFLAGS = \
+       $(AUTOMOUNT_MANAGER_CFLAGS) \
+       -I$(top_builddir)/gnome-flashback/libautomount-manager
+
+libautomount_manager_la_SOURCES = \
+       gsd-automount-manager.c \
+       gsd-automount-manager.h \
+       gsd-autorun.c \
+       gsd-autorun.h
+
+libautomount_manager_la_LIBADD =       \
+       $(AUTOMOUNT_MANAGER_LIBS)
+
+-include $(top_srcdir)/git.mk
diff --git a/gnome-flashback/libautomount-manager/gsd-automount-manager.c 
b/gnome-flashback/libautomount-manager/gsd-automount-manager.c
new file mode 100644
index 0000000..ffd22c8
--- /dev/null
+++ b/gnome-flashback/libautomount-manager/gsd-automount-manager.c
@@ -0,0 +1,571 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Author: Tomas Bzatek <tbzatek redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gsd-automount-manager.h"
+#include "gsd-autorun.h"
+
+#define GSD_AUTOMOUNT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_AUTOMOUNT_MANAGER, 
GsdAutomountManagerPrivate))
+
+#define GNOME_SESSION_DBUS_NAME      "org.gnome.SessionManager"
+#define GNOME_SESSION_DBUS_OBJECT    "/org/gnome/SessionManager"
+#define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
+
+struct GsdAutomountManagerPrivate
+{
+        GSettings   *settings;
+
+       GVolumeMonitor *volume_monitor;
+       unsigned int automount_idle_id;
+
+        GDBusProxy *session;
+        gboolean session_is_active;
+        gboolean screensaver_active;
+        guint ss_watch_id;
+        GDBusProxy *ss_proxy;
+
+        GList *volume_queue;
+};
+
+static void     gsd_automount_manager_class_init  (GsdAutomountManagerClass *klass);
+static void     gsd_automount_manager_init        (GsdAutomountManager      *gsd_automount_manager);
+
+G_DEFINE_TYPE (GsdAutomountManager, gsd_automount_manager, G_TYPE_OBJECT)
+
+GDBusProxy *
+get_session_proxy (void)
+{
+        static GDBusProxy *session_proxy;
+        GError *error =  NULL;
+
+        if (session_proxy != NULL) {
+                g_object_ref (session_proxy);
+        } else {
+                session_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                                               G_DBUS_PROXY_FLAGS_NONE,
+                                                               NULL,
+                                                               GNOME_SESSION_DBUS_NAME,
+                                                               GNOME_SESSION_DBUS_OBJECT,
+                                                               GNOME_SESSION_DBUS_INTERFACE,
+                                                               NULL,
+                                                               &error);
+                if (error) {
+                        g_warning ("Failed to connect to the session manager: %s", error->message);
+                        g_error_free (error);
+                } else {
+                        g_object_add_weak_pointer (G_OBJECT (session_proxy), (gpointer*)&session_proxy);
+                }
+        }
+
+        return session_proxy;
+}
+
+static GtkDialog *
+show_error_dialog (const char *primary_text,
+                  const char *secondary_text)
+{
+       GtkWidget *dialog;
+
+       dialog = gtk_message_dialog_new (NULL,
+                                        0,
+                                        GTK_MESSAGE_ERROR,
+                                        GTK_BUTTONS_OK,
+                                        "%s", "");
+
+       g_object_set (dialog,
+                     "text", primary_text,
+                     "secondary-text", secondary_text,
+                     NULL);
+
+       gtk_widget_show (GTK_WIDGET (dialog));
+
+       g_signal_connect (dialog, "response",
+                         G_CALLBACK (gtk_widget_destroy), NULL);
+
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+       return GTK_DIALOG (dialog);
+}
+
+static void
+startup_volume_mount_cb (GObject *source_object,
+                        GAsyncResult *res,
+                        gpointer user_data)
+{
+       g_volume_mount_finish (G_VOLUME (source_object), res, NULL);
+}
+
+static void
+automount_all_volumes (GsdAutomountManager *manager)
+{
+       GList *volumes, *l;
+       GMount *mount;
+       GVolume *volume;
+
+       if (g_settings_get_boolean (manager->priv->settings, "automount")) {
+               /* automount all mountable volumes at start-up */
+               volumes = g_volume_monitor_get_volumes (manager->priv->volume_monitor);
+               for (l = volumes; l != NULL; l = l->next) {
+                       volume = l->data;
+
+                       if (!g_volume_should_automount (volume) ||
+                           !g_volume_can_mount (volume)) {
+                               continue;
+                       }
+
+                       mount = g_volume_get_mount (volume);
+                       if (mount != NULL) {
+                               g_object_unref (mount);
+                               continue;
+                       }
+
+                       /* pass NULL as GMountOperation to avoid user interaction */
+                       g_volume_mount (volume, 0, NULL, NULL, startup_volume_mount_cb, NULL);
+               }
+               g_list_free_full (volumes, g_object_unref);
+       }
+}
+
+static gboolean
+automount_all_volumes_idle_cb (gpointer data)
+{
+       GsdAutomountManager *manager = GSD_AUTOMOUNT_MANAGER (data);
+
+       automount_all_volumes (manager);
+
+       manager->priv->automount_idle_id = 0;
+       return FALSE;
+}
+
+static void
+volume_mount_cb (GObject *source_object,
+                GAsyncResult *res,
+                gpointer user_data)
+{
+       GMountOperation *mount_op = user_data;
+       GError *error;
+       char *primary;
+       char *name;
+
+       error = NULL;
+       gsd_allow_autorun_for_volume_finish (G_VOLUME (source_object));
+       if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) {
+               if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+                       name = g_volume_get_name (G_VOLUME (source_object));
+                       primary = g_strdup_printf (_("Unable to mount %s"), name);
+                       g_free (name);
+                       show_error_dialog (primary,
+                                          error->message);
+                       g_free (primary);
+               }
+               g_error_free (error);
+       }
+
+       g_object_unref (mount_op);
+}
+
+static void
+do_mount_volume (GVolume *volume)
+{
+       GMountOperation *mount_op;
+
+       mount_op = gtk_mount_operation_new (NULL);
+       g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
+
+       gsd_allow_autorun_for_volume (volume);
+       g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, mount_op);
+}
+
+static void
+check_volume_queue (GsdAutomountManager *manager)
+{
+        GList *l;
+        GVolume *volume;
+
+        if (manager->priv->screensaver_active)
+                return;
+
+        l = manager->priv->volume_queue;
+
+        while (l != NULL) {
+                volume = l->data;
+
+                do_mount_volume (volume);
+                manager->priv->volume_queue =
+                        g_list_remove (manager->priv->volume_queue, volume);
+
+                g_object_unref (volume);
+                l = l->next;
+        }
+
+        manager->priv->volume_queue = NULL;
+}
+
+static void
+check_screen_lock_and_mount (GsdAutomountManager *manager,
+                             GVolume *volume)
+{
+        if (!manager->priv->session_is_active)
+                return;
+
+        if (manager->priv->screensaver_active) {
+                /* queue the volume, to mount it after the screensaver state changed */
+                g_debug ("Queuing volume %p", volume);
+                manager->priv->volume_queue = g_list_prepend (manager->priv->volume_queue,
+                                                              g_object_ref (volume));
+        } else {
+                /* mount it immediately */
+                do_mount_volume (volume);
+        }
+}
+
+static void
+volume_removed_callback (GVolumeMonitor *monitor,
+                         GVolume *volume,
+                         GsdAutomountManager *manager)
+{
+        g_debug ("Volume %p removed, removing from the queue", volume);
+
+        /* clear it from the queue, if present */
+        manager->priv->volume_queue =
+                g_list_remove (manager->priv->volume_queue, volume);
+}
+
+static void
+volume_added_callback (GVolumeMonitor *monitor,
+                      GVolume *volume,
+                      GsdAutomountManager *manager)
+{
+       if (g_settings_get_boolean (manager->priv->settings, "automount") &&
+           g_volume_should_automount (volume) &&
+           g_volume_can_mount (volume)) {
+                check_screen_lock_and_mount (manager, volume);
+       } else {
+               /* Allow gsd_autorun() to run. When the mount is later
+                * added programmatically (i.e. for a blank CD),
+                * gsd_autorun() will be called by mount_added_callback(). */
+               gsd_allow_autorun_for_volume (volume);
+               gsd_allow_autorun_for_volume_finish (volume);
+       }
+}
+
+static void
+autorun_show_window (GMount *mount, gpointer user_data)
+{
+       GFile *location;
+        char *uri;
+        GError *error;
+       char *primary;
+       char *name;
+
+       location = g_mount_get_root (mount);
+        uri = g_file_get_uri (location);
+
+        error = NULL;
+       /* use default folder handler */
+        if (! gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error)) {
+               name = g_mount_get_name (mount);
+               primary = g_strdup_printf (_("Unable to open a folder for %s"), name);
+               g_free (name);
+               show_error_dialog (primary,
+                                  error->message);
+               g_free (primary);
+               g_error_free (error);
+        }
+
+        g_free (uri);
+       g_object_unref (location);
+}
+
+static void
+mount_added_callback (GVolumeMonitor *monitor,
+                     GMount *mount,
+                     GsdAutomountManager *manager)
+{
+        /* don't autorun if the session is not active */
+        if (!manager->priv->session_is_active) {
+                return;
+        }
+
+       gsd_autorun (mount, manager->priv->settings, autorun_show_window, manager);
+}
+
+
+static void
+session_props_changed (GDBusProxy *session, GVariant *v, char **props, gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+        GsdAutomountManagerPrivate *p = manager->priv;
+        GVariant *active_v = NULL;
+        gboolean is_active;
+
+        active_v = g_dbus_proxy_get_cached_property (session, "SessionIsActive");
+        if (!active_v)
+                return;
+
+        g_variant_get (active_v, "b", &is_active);
+        g_variant_unref (active_v);
+        g_printerr ("AUTOMOUNT: session is active: %d -> %d\n", p->session_is_active, is_active);
+        p->session_is_active = is_active;
+
+        if (!p->session_is_active) {
+                if (p->volume_queue != NULL) {
+                        g_list_free_full (p->volume_queue, g_object_unref);
+                        p->volume_queue = NULL;
+                }
+        }
+}
+
+static void
+do_initialize_session (GsdAutomountManager *manager)
+{
+        manager->priv->session = get_session_proxy ();
+        g_signal_connect (manager->priv->session, "g-properties-changed",
+                          G_CALLBACK (session_props_changed), manager);
+        session_props_changed (manager->priv->session, NULL, NULL, manager);
+}
+
+#define SCREENSAVER_NAME "org.gnome.ScreenSaver"
+#define SCREENSAVER_PATH "/org/gnome/ScreenSaver"
+#define SCREENSAVER_INTERFACE "org.gnome.ScreenSaver"
+
+static void
+screensaver_signal_callback (GDBusProxy *proxy,
+                             const gchar *sender_name,
+                             const gchar *signal_name,
+                             GVariant *parameters,
+                             gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        if (g_strcmp0 (signal_name, "ActiveChanged") == 0) {
+                g_variant_get (parameters, "(b)", &manager->priv->screensaver_active);
+                g_debug ("Screensaver active changed to %d", manager->priv->screensaver_active);
+
+                check_volume_queue (manager);
+        }
+}
+
+static void
+screensaver_get_active_ready_cb (GObject *source,
+                                 GAsyncResult *res,
+                                 gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+        GDBusProxy *proxy = manager->priv->ss_proxy;
+        GVariant *result;
+        GError *error = NULL;
+
+        result = g_dbus_proxy_call_finish (proxy,
+                                           res,
+                                           &error);
+
+        if (error != NULL) {
+                g_warning ("Can't call GetActive() on the ScreenSaver object: %s",
+                           error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        g_variant_get (result, "(b)", &manager->priv->screensaver_active);
+        g_variant_unref (result);
+
+        g_debug ("Screensaver GetActive() returned %d", manager->priv->screensaver_active);
+}
+
+static void
+screensaver_proxy_ready_cb (GObject *source,
+                            GAsyncResult *res,
+                            gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+        GError *error = NULL;
+        GDBusProxy *ss_proxy;
+
+        ss_proxy = g_dbus_proxy_new_finish (res, &error);
+
+        if (error != NULL) {
+                g_warning ("Can't get proxy for the ScreenSaver object: %s",
+                           error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        g_debug ("ScreenSaver proxy ready");
+
+        manager->priv->ss_proxy = ss_proxy;
+
+        g_signal_connect (ss_proxy, "g-signal",
+                          G_CALLBACK (screensaver_signal_callback), manager);
+
+        g_dbus_proxy_call (ss_proxy,
+                           "GetActive",
+                           NULL,
+                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                           -1,
+                           NULL,
+                           screensaver_get_active_ready_cb,
+                           manager);
+}
+
+static void
+screensaver_appeared_callback (GDBusConnection *connection,
+                               const gchar *name,
+                               const gchar *name_owner,
+                               gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        g_debug ("ScreenSaver name appeared");
+
+        manager->priv->screensaver_active = FALSE;
+
+        g_dbus_proxy_new (connection,
+                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+                          NULL,
+                          name,
+                          SCREENSAVER_PATH,
+                          SCREENSAVER_INTERFACE,
+                          NULL,
+                          screensaver_proxy_ready_cb,
+                          manager);
+}
+
+static void
+screensaver_vanished_callback (GDBusConnection *connection,
+                               const gchar *name,
+                               gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        g_debug ("ScreenSaver name vanished");
+
+        manager->priv->screensaver_active = FALSE;
+        g_clear_object (&manager->priv->ss_proxy);
+
+        /* in this case force a clear of the volume queue, without
+         * mounting them.
+         */
+        if (manager->priv->volume_queue != NULL) {
+                g_list_free_full (manager->priv->volume_queue, g_object_unref);
+                manager->priv->volume_queue = NULL;
+        }
+}
+
+static void
+do_initialize_screensaver (GsdAutomountManager *manager)
+{
+        GsdAutomountManagerPrivate *p = manager->priv;
+
+        p->ss_watch_id =
+                g_bus_watch_name (G_BUS_TYPE_SESSION,
+                                  SCREENSAVER_NAME,
+                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                  screensaver_appeared_callback,
+                                  screensaver_vanished_callback,
+                                  manager,
+                                  NULL);
+}
+
+static void
+setup_automounter (GsdAutomountManager *manager)
+{
+        do_initialize_session (manager);
+        do_initialize_screensaver (manager);
+
+       manager->priv->volume_monitor = g_volume_monitor_get ();
+       g_signal_connect_object (manager->priv->volume_monitor, "mount-added",
+                                G_CALLBACK (mount_added_callback), manager, 0);
+       g_signal_connect_object (manager->priv->volume_monitor, "volume-added",
+                                G_CALLBACK (volume_added_callback), manager, 0);
+       g_signal_connect_object (manager->priv->volume_monitor, "volume-removed",
+                                G_CALLBACK (volume_removed_callback), manager, 0);
+
+       manager->priv->automount_idle_id =
+               g_idle_add_full (G_PRIORITY_LOW,
+                                automount_all_volumes_idle_cb,
+                                manager, NULL);
+}
+
+void
+gsd_automount_manager_finalize (GObject *object)
+{
+        GsdAutomountManager *manager  = GSD_AUTOMOUNT_MANAGER (object);
+        GsdAutomountManagerPrivate *p = manager->priv;
+
+        g_debug ("Stopping automounting manager");
+
+        g_clear_object (&p->session);
+        g_clear_object (&p->volume_monitor);
+        g_clear_object (&p->settings);
+        g_clear_object (&p->ss_proxy);
+
+        g_bus_unwatch_name (p->ss_watch_id);
+
+        if (p->volume_queue != NULL) {
+                g_list_free_full (p->volume_queue, g_object_unref);
+                p->volume_queue = NULL;
+        }
+
+        if (p->automount_idle_id != 0) {
+                g_source_remove (p->automount_idle_id);
+                p->automount_idle_id = 0;
+        }
+
+        G_OBJECT_CLASS (gsd_automount_manager_parent_class)->finalize (object);
+}
+
+static void
+gsd_automount_manager_init (GsdAutomountManager *manager)
+{
+        manager->priv = GSD_AUTOMOUNT_MANAGER_GET_PRIVATE (manager);
+
+        g_debug ("Starting automounting manager");
+
+        manager->priv->settings = g_settings_new ("org.gnome.desktop.media-handling");
+        setup_automounter (manager);
+}
+
+static void
+gsd_automount_manager_class_init (GsdAutomountManagerClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = gsd_automount_manager_finalize;
+
+        g_type_class_add_private (klass, sizeof (GsdAutomountManagerPrivate));
+}
+
+GsdAutomountManager *
+gsd_automount_manager_new (void)
+{
+        return GSD_AUTOMOUNT_MANAGER (g_object_new (GSD_TYPE_AUTOMOUNT_MANAGER, NULL));
+}
diff --git a/gnome-flashback/libautomount-manager/gsd-automount-manager.h 
b/gnome-flashback/libautomount-manager/gsd-automount-manager.h
new file mode 100644
index 0000000..42f9f58
--- /dev/null
+++ b/gnome-flashback/libautomount-manager/gsd-automount-manager.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Author: Tomas Bzatek <tbzatek redhat com>
+ */
+
+#ifndef __GSD_AUTOMOUNT_MANAGER_H
+#define __GSD_AUTOMOUNT_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_AUTOMOUNT_MANAGER         (gsd_automount_manager_get_type ())
+#define GSD_AUTOMOUNT_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_AUTOMOUNT_MANAGER, 
GsdAutomountManager))
+#define GSD_AUTOMOUNT_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_AUTOMOUNT_MANAGER, 
GsdAutomountManagerClass))
+#define GSD_IS_AUTOMOUNT_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_AUTOMOUNT_MANAGER))
+#define GSD_IS_AUTOMOUNT_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_AUTOMOUNT_MANAGER))
+#define GSD_AUTOMOUNT_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_AUTOMOUNT_MANAGER, 
GsdAutomountManagerClass))
+
+typedef struct GsdAutomountManagerPrivate GsdAutomountManagerPrivate;
+
+typedef struct
+{
+        GObject                     parent;
+        GsdAutomountManagerPrivate *priv;
+} GsdAutomountManager;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GsdAutomountManagerClass;
+
+GType                   gsd_automount_manager_get_type            (void);
+
+GsdAutomountManager *   gsd_automount_manager_new                 (void);
+gboolean                gsd_automount_manager_start               (GsdAutomountManager *manager,
+                                                                   GError              **error);
+void                    gsd_automount_manager_stop                (GsdAutomountManager *manager);
+
+G_END_DECLS
+
+#endif /* __GSD_AUTOMOUNT_MANAGER_H */
diff --git a/gnome-flashback/libautomount-manager/gsd-autorun.c 
b/gnome-flashback/libautomount-manager/gsd-autorun.c
new file mode 100644
index 0000000..56031b4
--- /dev/null
+++ b/gnome-flashback/libautomount-manager/gsd-autorun.c
@@ -0,0 +1,975 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * gsd-automount.c: helpers for automounting hotplugged volumes
+ *
+ * Copyright (C) 2008, 2010 Red Hat, Inc.
+ *
+ * Nautilus 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
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ *          Cosimo Cecchi <cosimoc redhat com>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gsd-autorun.h"
+
+static gboolean should_autorun_mount (GMount *mount);
+
+#define CUSTOM_ITEM_ASK "gsd-item-ask"
+#define CUSTOM_ITEM_DO_NOTHING "gsd-item-do-nothing"
+#define CUSTOM_ITEM_OPEN_FOLDER "gsd-item-open-folder"
+
+typedef struct
+{
+       GtkWidget *dialog;
+
+       GMount *mount;
+       gboolean should_eject;
+
+       gboolean selected_ignore;
+       gboolean selected_open_folder;
+       GAppInfo *selected_app;
+
+       gboolean remember;
+
+       char *x_content_type;
+
+       GsdAutorunOpenWindow open_window_func;
+       gpointer user_data;
+} AutorunDialogData;
+
+static int
+gsd_autorun_g_strv_find (char **strv, const char *find_me)
+{
+       guint index;
+
+       g_return_val_if_fail (find_me != NULL, -1);
+
+       for (index = 0; strv[index] != NULL; ++index) {
+               if (strcmp (strv[index], find_me) == 0) {
+                       return index;
+               }
+       }
+
+       return -1;
+}
+
+
+#define ICON_SIZE_STANDARD 48
+
+static gint
+get_icon_size_for_stock_size (GtkIconSize size)
+{
+       gint w, h;
+
+       if (gtk_icon_size_lookup (size, &w, &h)) {
+               return MAX (w, h);
+       }
+       return ICON_SIZE_STANDARD;
+}
+
+static GdkPixbuf *
+render_icon (GIcon *icon, gint icon_size)
+{
+       GdkPixbuf *pixbuf;
+       GtkIconInfo *info;
+
+       pixbuf = NULL;
+
+       if (G_IS_THEMED_ICON (icon)) {
+               gchar const * const *names;
+
+               info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
+                                                      icon,
+                                                      icon_size,
+                                                      0);
+
+               if (info) {
+                       pixbuf = gtk_icon_info_load_icon (info, NULL);
+                       gtk_icon_info_free (info);
+               }
+
+               if (pixbuf == NULL) {
+                       names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+                       pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                                          *names,
+                                                          icon_size,
+                                                          0, NULL);
+               }
+       }
+       else
+       if (G_IS_FILE_ICON (icon)) {
+               GFile *icon_file;
+               gchar *path;
+
+               icon_file = g_file_icon_get_file (G_FILE_ICON (icon));
+               path = g_file_get_path (icon_file);
+               pixbuf = gdk_pixbuf_new_from_file_at_size (path,
+                                                          icon_size, icon_size,
+                                                          NULL);
+               g_free (path);
+               g_object_unref (G_OBJECT (icon_file));
+       }
+
+       return pixbuf;
+}
+
+static void
+gsd_autorun_get_preferences (const char *x_content_type,
+                             gboolean *pref_start_app,
+                             gboolean *pref_ignore,
+                             gboolean *pref_open_folder)
+{
+        GSettings *settings;
+       char **x_content_start_app;
+       char **x_content_ignore;
+       char **x_content_open_folder;
+
+       g_return_if_fail (pref_start_app != NULL);
+       g_return_if_fail (pref_ignore != NULL);
+       g_return_if_fail (pref_open_folder != NULL);
+
+        settings = g_settings_new ("org.gnome.desktop.media-handling");
+
+       *pref_start_app = FALSE;
+       *pref_ignore = FALSE;
+       *pref_open_folder = FALSE;
+       x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app");
+       x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore");
+       x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder");
+       if (x_content_start_app != NULL) {
+               *pref_start_app = gsd_autorun_g_strv_find (x_content_start_app, x_content_type) != -1;
+       }
+       if (x_content_ignore != NULL) {
+               *pref_ignore = gsd_autorun_g_strv_find (x_content_ignore, x_content_type) != -1;
+       }
+       if (x_content_open_folder != NULL) {
+               *pref_open_folder = gsd_autorun_g_strv_find (x_content_open_folder, x_content_type) != -1;
+       }
+       g_strfreev (x_content_ignore);
+       g_strfreev (x_content_start_app);
+       g_strfreev (x_content_open_folder);
+        g_object_unref (settings);
+}
+
+static char **
+remove_elem_from_str_array (char **v,
+                            const char *s)
+{
+        GPtrArray *array;
+        guint idx;
+
+        array = g_ptr_array_new ();
+
+        for (idx = 0; v[idx] != NULL; idx++) {
+                if (g_strcmp0 (v[idx], s) == 0) {
+                        continue;
+                }
+
+                g_ptr_array_add (array, v[idx]);
+        }
+
+        g_ptr_array_add (array, NULL);
+
+        g_free (v);
+
+        return (char **) g_ptr_array_free (array, FALSE);
+}
+
+static char **
+add_elem_to_str_array (char **v,
+                       const char *s)
+{
+        GPtrArray *array;
+        guint idx;
+
+        array = g_ptr_array_new ();
+
+        for (idx = 0; v[idx] != NULL; idx++) {
+                g_ptr_array_add (array, v[idx]);
+        }
+
+        g_ptr_array_add (array, g_strdup (s));
+        g_ptr_array_add (array, NULL);
+
+        g_free (v);
+
+        return (char **) g_ptr_array_free (array, FALSE);
+}
+
+static void
+gsd_autorun_set_preferences (const char *x_content_type,
+                             gboolean pref_start_app,
+                             gboolean pref_ignore,
+                             gboolean pref_open_folder)
+{
+        GSettings *settings;
+       char **x_content_start_app;
+       char **x_content_ignore;
+       char **x_content_open_folder;
+
+       g_assert (x_content_type != NULL);
+
+       settings = g_settings_new ("org.gnome.desktop.media-handling");
+
+       x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app");
+       x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore");
+       x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder");
+
+       x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type);
+       if (pref_start_app) {
+               x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type);
+       }
+       g_settings_set_strv (settings, "autorun-x-content-start-app", (const gchar * const*) 
x_content_start_app);
+
+       x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type);
+       if (pref_ignore) {
+               x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type);
+       }
+       g_settings_set_strv (settings, "autorun-x-content-ignore", (const gchar * const*) x_content_ignore);
+
+       x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type);
+       if (pref_open_folder) {
+               x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type);
+       }
+       g_settings_set_strv (settings, "autorun-x-content-open-folder", (const gchar * const*) 
x_content_open_folder);
+
+       g_strfreev (x_content_open_folder);
+       g_strfreev (x_content_ignore);
+       g_strfreev (x_content_start_app);
+        g_object_unref (settings);
+}
+
+static void
+custom_item_activated_cb (GtkAppChooserButton *button,
+                          const gchar *item,
+                          gpointer user_data)
+{
+        gchar *content_type;
+        AutorunDialogData *data = user_data;
+
+        content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button));
+
+        if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) {
+                gsd_autorun_set_preferences (content_type,
+                                             FALSE, FALSE, FALSE);
+                data->selected_open_folder = FALSE;
+                data->selected_ignore = FALSE;
+        } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) {
+                gsd_autorun_set_preferences (content_type,
+                                             FALSE, FALSE, TRUE);
+                data->selected_open_folder = TRUE;
+                data->selected_ignore = FALSE;
+        } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) {
+                gsd_autorun_set_preferences (content_type,
+                                             FALSE, TRUE, FALSE);
+                data->selected_open_folder = FALSE;
+                data->selected_ignore = TRUE;
+        }
+
+        g_free (content_type);
+}
+
+static void
+combo_box_changed_cb (GtkComboBox *combo_box,
+                      gpointer user_data)
+{
+        GAppInfo *info;
+        AutorunDialogData *data = user_data;
+
+        info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box));
+
+        if (info == NULL)
+                return;
+
+        g_clear_object (&data->selected_app);
+        data->selected_app = info;
+}
+
+static void
+prepare_combo_box (GtkWidget *combo_box,
+                  AutorunDialogData *data)
+{
+        GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box);
+        GIcon *icon;
+        gboolean pref_ask;
+        gboolean pref_start_app;
+        gboolean pref_ignore;
+        gboolean pref_open_folder;
+        GAppInfo *info;
+        gchar *content_type;
+
+        content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser));
+
+        /* fetch preferences for this content type */
+        gsd_autorun_get_preferences (content_type,
+                                     &pref_start_app, &pref_ignore, &pref_open_folder);
+        pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
+
+        info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box));
+
+        /* append the separator only if we have >= 1 apps in the chooser */
+        if (info != NULL) {
+                gtk_app_chooser_button_append_separator (app_chooser);
+                g_object_unref (info);
+        }
+
+        icon = g_themed_icon_new (GTK_STOCK_DIALOG_QUESTION);
+        gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK,
+                                                   _("Ask what to do"),
+                                                   icon);
+        g_object_unref (icon);
+
+        icon = g_themed_icon_new (GTK_STOCK_CLOSE);
+        gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING,
+                                                   _("Do Nothing"),
+                                                   icon);
+        g_object_unref (icon);
+
+        icon = g_themed_icon_new ("folder-open");
+        gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER,
+                                                   _("Open Folder"),
+                                                   icon);
+        g_object_unref (icon);
+
+        gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE);
+
+        if (pref_ask) {
+                gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK);
+        } else if (pref_ignore) {
+                gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING);
+        } else if (pref_open_folder) {
+                gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER);
+        }
+
+        g_signal_connect (app_chooser, "changed",
+                          G_CALLBACK (combo_box_changed_cb), data);
+        g_signal_connect (app_chooser, "custom-item-activated",
+                          G_CALLBACK (custom_item_activated_cb), data);
+
+        g_free (content_type);
+}
+
+static gboolean
+is_shift_pressed (void)
+{
+       gboolean ret;
+       XkbStateRec state;
+       Bool status;
+
+       ret = FALSE;
+
+        gdk_error_trap_push ();
+       status = XkbGetState (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
+                             XkbUseCoreKbd, &state);
+        gdk_error_trap_pop_ignored ();
+
+       if (status == Success) {
+               ret = state.mods & ShiftMask;
+       }
+
+       return ret;
+}
+
+enum {
+       AUTORUN_DIALOG_RESPONSE_EJECT = 0
+};
+
+static void
+gsd_autorun_launch_for_mount (GMount *mount, GAppInfo *app_info)
+{
+       GFile *root;
+       GdkAppLaunchContext *launch_context;
+       GError *error;
+       gboolean result;
+       GList *list;
+       gchar *uri_scheme;
+       gchar *uri;
+
+       root = g_mount_get_root (mount);
+       list = g_list_append (NULL, root);
+
+       launch_context = gdk_app_launch_context_new ();
+
+       error = NULL;
+       result = g_app_info_launch (app_info,
+                                   list,
+                                   G_APP_LAUNCH_CONTEXT (launch_context),
+                                   &error);
+
+       g_object_unref (launch_context);
+
+       if (!result) {
+               if (error->domain == G_IO_ERROR &&
+                   error->code == G_IO_ERROR_NOT_SUPPORTED) {
+                       uri = g_file_get_uri (root);
+                       uri_scheme = g_uri_parse_scheme (uri);
+
+                       /* FIXME: Present user a dialog to choose another app when the last one failed to 
handle a file */
+                       g_warning ("Cannot open location: %s\n", error->message);
+
+                       g_free (uri_scheme);
+                       g_free (uri);
+               } else {
+                       g_warning ("Cannot open app: %s\n", error->message);
+               }
+               g_error_free (error);
+       }
+
+       g_list_free (list);
+       g_object_unref (root);
+}
+
+static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data);
+
+static void
+autorun_dialog_destroy (AutorunDialogData *data)
+{
+       g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount),
+                                             G_CALLBACK (autorun_dialog_mount_unmounted),
+                                             data);
+
+       gtk_widget_destroy (GTK_WIDGET (data->dialog));
+       if (data->selected_app != NULL) {
+               g_object_unref (data->selected_app);
+       }
+       g_object_unref (data->mount);
+       g_free (data->x_content_type);
+       g_free (data);
+}
+
+static void
+autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data)
+{
+       /* remove the dialog if the media is unmounted */
+       autorun_dialog_destroy (data);
+}
+
+static void
+unmount_mount_callback (GObject *source_object,
+                       GAsyncResult *res,
+                       gpointer user_data)
+{
+       GError *error;
+       char *primary;
+       gboolean unmounted;
+       gboolean should_eject;
+       GtkWidget *dialog;
+
+
+       should_eject = user_data != NULL;
+
+       error = NULL;
+       if (should_eject) {
+               unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object),
+                                                                res, &error);
+       } else {
+               unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object),
+                                                                  res, &error);
+       }
+
+       if (! unmounted) {
+               if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+                       if (should_eject) {
+                               primary = g_strdup_printf (_("Unable to eject %p"), source_object);
+                       } else {
+                               primary = g_strdup_printf (_("Unable to unmount %p"), source_object);
+                       }
+
+                       dialog = gtk_message_dialog_new (NULL,
+                                                        0,
+                                                        GTK_MESSAGE_INFO,
+                                                        GTK_BUTTONS_OK,
+                                                        "%s",
+                                                        primary);
+                       gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
+                                                                   "%s",
+                                                                   error->message);
+
+                       gtk_widget_show (GTK_WIDGET (dialog));
+                       g_signal_connect (dialog, "response",
+                                         G_CALLBACK (gtk_widget_destroy), NULL);
+                       g_free (primary);
+               }
+       }
+
+       if (error != NULL) {
+               g_error_free (error);
+       }
+}
+
+static void
+do_unmount (GMount *mount, gboolean should_eject, GtkWindow *window)
+{
+       GMountOperation *mount_op;
+
+       mount_op = gtk_mount_operation_new (window);
+       if (should_eject) {
+               g_mount_eject_with_operation (mount,
+                                             0,
+                                             mount_op,
+                                             NULL,
+                                             unmount_mount_callback,
+                                             (gpointer) 1);
+       } else {
+               g_mount_unmount_with_operation (mount,
+                                               0,
+                                               mount_op,
+                                               NULL,
+                                               unmount_mount_callback,
+                                               (gpointer) 0);
+       }
+       g_object_unref (mount_op);
+}
+
+static void
+autorun_dialog_response (GtkDialog *dialog, gint response, AutorunDialogData *data)
+{
+       switch (response) {
+       case AUTORUN_DIALOG_RESPONSE_EJECT:
+               do_unmount (data->mount, data->should_eject, GTK_WINDOW (dialog));
+               break;
+
+       case GTK_RESPONSE_NONE:
+               /* window was closed */
+               break;
+       case GTK_RESPONSE_CANCEL:
+               break;
+       case GTK_RESPONSE_OK:
+               /* do the selected action */
+
+               if (data->remember) {
+                       /* make sure we don't ask again */
+                       gsd_autorun_set_preferences (data->x_content_type, TRUE, data->selected_ignore, 
data->selected_open_folder);
+                       if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != 
NULL) {
+                               g_app_info_set_as_default_for_type (data->selected_app,
+                                                                   data->x_content_type,
+                                                                   NULL);
+                       }
+               } else {
+                       /* make sure we do ask again */
+                       gsd_autorun_set_preferences (data->x_content_type, FALSE, FALSE, FALSE);
+               }
+
+               if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) {
+                       gsd_autorun_launch_for_mount (data->mount, data->selected_app);
+               } else if (!data->selected_ignore && data->selected_open_folder) {
+                       if (data->open_window_func != NULL)
+                               data->open_window_func (data->mount, data->user_data);
+               }
+               break;
+       }
+
+       autorun_dialog_destroy (data);
+}
+
+static void
+autorun_always_toggled (GtkToggleButton *togglebutton, AutorunDialogData *data)
+{
+       data->remember = gtk_toggle_button_get_active (togglebutton);
+}
+
+static gboolean
+combo_box_enter_ok (GtkWidget *togglebutton, GdkEventKey *event, GtkDialog *dialog)
+{
+       if (event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_Return) {
+               gtk_dialog_response (dialog, GTK_RESPONSE_OK);
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/* returns TRUE if a folder window should be opened */
+static gboolean
+do_autorun_for_content_type (GMount *mount,
+                             const char *x_content_type,
+                             GsdAutorunOpenWindow open_window_func,
+                             gpointer user_data)
+{
+       AutorunDialogData *data;
+       GtkWidget *dialog;
+       GtkWidget *hbox;
+       GtkWidget *vbox;
+       GtkWidget *label;
+       GtkWidget *combo_box;
+       GtkWidget *always_check_button;
+       GtkWidget *eject_button;
+       GtkWidget *image;
+       char *markup;
+       char *content_description;
+       char *mount_name;
+       GIcon *icon;
+       GdkPixbuf *pixbuf;
+       int icon_size;
+       gboolean user_forced_dialog;
+       gboolean pref_ask;
+       gboolean pref_start_app;
+       gboolean pref_ignore;
+       gboolean pref_open_folder;
+       char *media_greeting;
+       gboolean ret;
+
+       ret = FALSE;
+       mount_name = NULL;
+
+       if (g_content_type_is_a (x_content_type, "x-content/win32-software")) {
+               /* don't pop up the dialog anyway if the content type says
+                * windows software.
+                */
+               goto out;
+       }
+
+       user_forced_dialog = is_shift_pressed ();
+
+       gsd_autorun_get_preferences (x_content_type, &pref_start_app, &pref_ignore, &pref_open_folder);
+       pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
+
+       if (user_forced_dialog) {
+               goto show_dialog;
+       }
+
+       if (!pref_ask && !pref_ignore && !pref_open_folder) {
+               GAppInfo *app_info;
+               app_info = g_app_info_get_default_for_type (x_content_type, FALSE);
+               if (app_info != NULL) {
+                       gsd_autorun_launch_for_mount (mount, app_info);
+               }
+               goto out;
+       }
+
+       if (pref_open_folder) {
+               ret = TRUE;
+               goto out;
+       }
+
+       if (pref_ignore) {
+               goto out;
+       }
+
+show_dialog:
+
+       mount_name = g_mount_get_name (mount);
+
+       dialog = gtk_dialog_new ();
+
+       hbox = gtk_hbox_new (FALSE, 12);
+       gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0);
+       gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
+
+       icon = g_mount_get_icon (mount);
+       icon_size = get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG);
+       image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
+       pixbuf = render_icon (icon, icon_size);
+       gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+       gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0);
+       /* also use the icon on the dialog */
+       gtk_window_set_title (GTK_WINDOW (dialog), mount_name);
+       gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf);
+       gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+       g_object_unref (icon);
+       if (pixbuf) {
+               g_object_unref (pixbuf);
+       }
+       vbox = gtk_vbox_new (FALSE, 12);
+       gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+       label = gtk_label_new (NULL);
+
+
+       /* Customize greeting for well-known x-content types */
+       if (strcmp (x_content_type, "x-content/audio-cdda") == 0) {
+               media_greeting = _("You have just inserted an Audio CD.");
+       } else if (strcmp (x_content_type, "x-content/audio-dvd") == 0) {
+               media_greeting = _("You have just inserted an Audio DVD.");
+       } else if (strcmp (x_content_type, "x-content/video-dvd") == 0) {
+               media_greeting = _("You have just inserted a Video DVD.");
+       } else if (strcmp (x_content_type, "x-content/video-vcd") == 0) {
+               media_greeting = _("You have just inserted a Video CD.");
+       } else if (strcmp (x_content_type, "x-content/video-svcd") == 0) {
+               media_greeting = _("You have just inserted a Super Video CD.");
+       } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) {
+               media_greeting = _("You have just inserted a blank CD.");
+       } else if (strcmp (x_content_type, "x-content/blank-dvd") == 0) {
+               media_greeting = _("You have just inserted a blank DVD.");
+       } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) {
+               media_greeting = _("You have just inserted a blank Blu-Ray disc.");
+       } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) {
+               media_greeting = _("You have just inserted a blank HD DVD.");
+       } else if (strcmp (x_content_type, "x-content/image-photocd") == 0) {
+               media_greeting = _("You have just inserted a Photo CD.");
+       } else if (strcmp (x_content_type, "x-content/image-picturecd") == 0) {
+               media_greeting = _("You have just inserted a Picture CD.");
+       } else if (strcmp (x_content_type, "x-content/image-dcf") == 0) {
+               media_greeting = _("You have just inserted a medium with digital photos.");
+       } else if (strcmp (x_content_type, "x-content/audio-player") == 0) {
+               media_greeting = _("You have just inserted a digital audio player.");
+       } else if (g_content_type_is_a (x_content_type, "x-content/software")) {
+               media_greeting = _("You have just inserted a medium with software intended to be 
automatically started.");
+       } else {
+               /* fallback to generic greeting */
+               media_greeting = _("You have just inserted a medium.");
+       }
+       markup = g_strdup_printf ("<big><b>%s %s</b></big>", media_greeting, _("Choose what application to 
launch."));
+       gtk_label_set_markup (GTK_LABEL (label), markup);
+       g_free (markup);
+       gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+       gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
+
+       label = gtk_label_new (NULL);
+       content_description = g_content_type_get_description (x_content_type);
+       markup = g_strdup_printf (_("Select how to open \"%s\" and whether to perform this action in the 
future for other media of type \"%s\"."), mount_name, content_description);
+       g_free (content_description);
+       gtk_label_set_markup (GTK_LABEL (label), markup);
+       g_free (markup);
+       gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+       gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
+
+       data = g_new0 (AutorunDialogData, 1);
+       data->dialog = dialog;
+       data->mount = g_object_ref (mount);
+       data->remember = !pref_ask;
+       data->selected_ignore = pref_ignore;
+       data->x_content_type = g_strdup (x_content_type);
+       data->selected_app = g_app_info_get_default_for_type (x_content_type, FALSE);
+       data->open_window_func = open_window_func;
+       data->user_data = user_data;
+
+       combo_box = gtk_app_chooser_button_new (x_content_type);
+       prepare_combo_box (combo_box, data);
+       g_signal_connect (G_OBJECT (combo_box),
+                         "key-press-event",
+                         G_CALLBACK (combo_box_enter_ok),
+                         dialog);
+
+       gtk_box_pack_start (GTK_BOX (vbox), combo_box, TRUE, TRUE, 0);
+
+       always_check_button = gtk_check_button_new_with_mnemonic (_("_Always perform this action"));
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (always_check_button), data->remember);
+       g_signal_connect (G_OBJECT (always_check_button),
+                         "toggled",
+                         G_CALLBACK (autorun_always_toggled),
+                         data);
+       gtk_box_pack_start (GTK_BOX (vbox), always_check_button, TRUE, TRUE, 0);
+
+       gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                               GTK_STOCK_OK, GTK_RESPONSE_OK,
+                               NULL);
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+       if (g_mount_can_eject (mount)) {
+               GtkWidget *eject_image;
+               eject_button = gtk_button_new_with_mnemonic (_("_Eject"));
+               eject_image = gtk_image_new_from_icon_name ("media-eject", GTK_ICON_SIZE_BUTTON);
+               gtk_button_set_image (GTK_BUTTON (eject_button), eject_image);
+               data->should_eject = TRUE;
+       } else {
+               eject_button = gtk_button_new_with_mnemonic (_("_Unmount"));
+               data->should_eject = FALSE;
+       }
+       gtk_dialog_add_action_widget (GTK_DIALOG (dialog), eject_button, AUTORUN_DIALOG_RESPONSE_EJECT);
+       gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (GTK_DIALOG 
(dialog))), eject_button, TRUE);
+
+       /* show the dialog */
+       gtk_widget_show_all (dialog);
+
+       g_signal_connect (G_OBJECT (dialog),
+                         "response",
+                         G_CALLBACK (autorun_dialog_response),
+                         data);
+
+       g_signal_connect (G_OBJECT (data->mount),
+                         "unmounted",
+                         G_CALLBACK (autorun_dialog_mount_unmounted),
+                         data);
+
+out:
+       g_free (mount_name);
+       return ret;
+}
+
+typedef struct {
+       GMount *mount;
+       GsdAutorunOpenWindow open_window_func;
+       gpointer user_data;
+       GSettings *settings;
+} AutorunData;
+
+static void
+autorun_guessed_content_type_callback (GObject *source_object,
+                                      GAsyncResult *res,
+                                      gpointer user_data)
+{
+       GError *error;
+       char **guessed_content_type;
+       AutorunData *data = user_data;
+       gboolean open_folder;
+
+       open_folder = FALSE;
+
+       error = NULL;
+       guessed_content_type = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, &error);
+       g_object_set_data_full (source_object,
+                               "gsd-content-type-cache",
+                               g_strdupv (guessed_content_type),
+                               (GDestroyNotify)g_strfreev);
+       if (error != NULL) {
+               g_warning ("Unable to guess content type for mount: %s", error->message);
+               g_error_free (error);
+       } else {
+               if (guessed_content_type != NULL && g_strv_length (guessed_content_type) > 0) {
+                       int n;
+                       for (n = 0; guessed_content_type[n] != NULL; n++) {
+                               if (do_autorun_for_content_type (data->mount, guessed_content_type[n],
+                                                                data->open_window_func, data->user_data)) {
+                                       open_folder = TRUE;
+                               }
+                       }
+                       g_strfreev (guessed_content_type);
+               } else {
+                       if (g_settings_get_boolean (data->settings, "automount-open")) {
+                               open_folder = TRUE;
+                       }
+               }
+       }
+
+       /* only open the folder once.. */
+       if (open_folder && data->open_window_func != NULL) {
+               data->open_window_func (data->mount, data->user_data);
+       }
+
+       g_object_unref (data->mount);
+       g_object_unref (data->settings);
+       g_free (data);
+}
+
+void
+gsd_autorun (GMount *mount,
+             GSettings *settings,
+             GsdAutorunOpenWindow open_window_func,
+             gpointer user_data)
+{
+       AutorunData *data;
+
+       if (!should_autorun_mount (mount) ||
+           g_settings_get_boolean (settings, "autorun-never")) {
+               return;
+       }
+
+       data = g_new0 (AutorunData, 1);
+       data->mount = g_object_ref (mount);
+       data->open_window_func = open_window_func;
+       data->user_data = user_data;
+       data->settings = g_object_ref (settings);
+
+       g_mount_guess_content_type (mount,
+                                   FALSE,
+                                   NULL,
+                                   autorun_guessed_content_type_callback,
+                                   data);
+}
+
+static gboolean
+remove_allow_volume (gpointer data)
+{
+       GVolume *volume = data;
+
+       g_object_set_data (G_OBJECT (volume), "gsd-allow-autorun", NULL);
+       return FALSE;
+}
+
+void
+gsd_allow_autorun_for_volume (GVolume *volume)
+{
+       g_object_set_data (G_OBJECT (volume), "gsd-allow-autorun", GINT_TO_POINTER (1));
+}
+
+#define INHIBIT_AUTORUN_SECONDS 10
+
+void
+gsd_allow_autorun_for_volume_finish (GVolume *volume)
+{
+       if (g_object_get_data (G_OBJECT (volume), "gsd-allow-autorun") != NULL) {
+               g_timeout_add_seconds_full (0,
+                                           INHIBIT_AUTORUN_SECONDS,
+                                           remove_allow_volume,
+                                           g_object_ref (volume),
+                                           g_object_unref);
+       }
+}
+
+static gboolean
+should_skip_native_mount_root (GFile *root)
+{
+       char *path;
+       gboolean should_skip;
+
+       /* skip any mounts in hidden directory hierarchies */
+       path = g_file_get_path (root);
+       should_skip = strstr (path, "/.") != NULL;
+       g_free (path);
+
+       return should_skip;
+}
+
+static gboolean
+should_autorun_mount (GMount *mount)
+{
+       GFile *root;
+       GVolume *enclosing_volume;
+       gboolean ignore_autorun;
+
+       ignore_autorun = TRUE;
+       enclosing_volume = g_mount_get_volume (mount);
+       if (enclosing_volume != NULL) {
+               if (g_object_get_data (G_OBJECT (enclosing_volume), "gsd-allow-autorun") != NULL) {
+                       ignore_autorun = FALSE;
+                       g_object_set_data (G_OBJECT (enclosing_volume), "gsd-allow-autorun", NULL);
+               }
+       }
+
+       if (ignore_autorun) {
+               if (enclosing_volume != NULL) {
+                       g_object_unref (enclosing_volume);
+               }
+               return FALSE;
+       }
+
+       root = g_mount_get_root (mount);
+
+       /* only do autorun on local files or files where g_volume_should_automount() returns TRUE */
+       ignore_autorun = TRUE;
+       if ((g_file_is_native (root) && !should_skip_native_mount_root (root)) ||
+           (enclosing_volume != NULL && g_volume_should_automount (enclosing_volume))) {
+               ignore_autorun = FALSE;
+       }
+       if (enclosing_volume != NULL) {
+               g_object_unref (enclosing_volume);
+       }
+       g_object_unref (root);
+
+       return !ignore_autorun;
+}
diff --git a/gnome-flashback/libautomount-manager/gsd-autorun.h 
b/gnome-flashback/libautomount-manager/gsd-autorun.h
new file mode 100644
index 0000000..85044be
--- /dev/null
+++ b/gnome-flashback/libautomount-manager/gsd-autorun.h
@@ -0,0 +1,53 @@
+/*
+ * gsd-automount.h:helpers for automounting hotplugged volumes
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * Nautilus 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
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ *          Cosimo Cecchi <cosimoc redhat com>
+ */
+
+/* TODO:
+ *
+ * - unmount all the media we've automounted on shutdown
+ * - finish x-content / * types
+ *  - finalize the semi-spec
+ *  - add probing/sniffing code
+ * - implement missing features
+ *  - "Open Folder when mounted"
+ *  - Autorun spec (e.g. $ROOT/.autostart)
+ *
+ */
+
+#ifndef __GSD_AUTORUN_H__
+#define __GSD_AUTORUN_H__
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+typedef void (*GsdAutorunOpenWindow) (GMount *mount,
+                                     gpointer user_data);
+
+void gsd_autorun (GMount *mount,
+                 GSettings *settings,
+                 GsdAutorunOpenWindow open_window_func,
+                 gpointer user_data);
+
+void gsd_allow_autorun_for_volume (GVolume *volume);
+void gsd_allow_autorun_for_volume_finish (GVolume *volume);
+
+#endif /* __GSD_AUTORUN_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c89a15b..0dcf7c7 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,6 +10,8 @@ data/gnome-flashback-metacity.session.in
 data/org.gnome.gnome-flashback.gschema.xml.in.in
 gnome-flashback/libend-session-dialog/flashback-inhibit-dialog.c
 [type: gettext/glade]gnome-flashback/libend-session-dialog/flashback-inhibit-dialog.ui
+gnome-flashback/libautomount-manager/gsd-automount-manager.c
+gnome-flashback/libautomount-manager/gsd-autorun.c
 gnome-flashback/libsound-applet/gvc-applet.c
 gnome-flashback/libsound-applet/gvc-channel-bar.c
 gnome-flashback/libsound-applet/gvc-stream-status-icon.c


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