[gnome-disk-utility] Add a nautilus extension and a formatting tool



commit 1c975f399d762f4da8892b96356e5e7cc49f71fc
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Apr 30 22:22:12 2009 -0400

    Add a nautilus extension and a formatting tool
    
    This commit adds a somewhat reworked version of Tomas Bzateks
    nautilus-gdu work, see bug 575437.
---
 configure.ac                              |   30 ++
 data/icons/16x16/Makefile.am              |    3 +-
 data/icons/16x16/nautilus-gdu.png         |  Bin 0 -> 768 bytes
 data/icons/22x22/Makefile.am              |    3 +-
 data/icons/22x22/nautilus-gdu.png         |  Bin 0 -> 1052 bytes
 data/icons/48x48/Makefile.am              |    3 +-
 data/icons/48x48/nautilus-gdu.png         |  Bin 0 -> 3175 bytes
 data/icons/scalable/Makefile.am           |    3 +-
 po/POTFILES.in                            |    4 +
 src/Makefile.am                           |    6 +-
 src/format-tool/Makefile.am               |   53 ++
 src/format-tool/TODO                      |   62 +++
 src/format-tool/format-window-operation.c |  804 +++++++++++++++++++++++++++++
 src/format-tool/format-window-operation.h |   74 +++
 src/format-tool/format-window.c           |  578 +++++++++++++++++++++
 src/format-tool/format-window.h           |   91 ++++
 src/format-tool/gdu-format-tool.c         |  105 ++++
 src/format-tool/gdu-utils.c               |  148 ++++++
 src/format-tool/gdu-utils.h               |   48 ++
 src/nautilus-extension/Makefile.am        |   51 ++
 src/nautilus-extension/nautilus-gdu.c     |  301 +++++++++++
 src/nautilus-extension/nautilus-gdu.h     |   57 ++
 src/nautilus-extension/nautilus-module.c  |   58 ++
 23 files changed, 2477 insertions(+), 5 deletions(-)

diff --git a/configure.ac b/configure.ac
index 01a29c3..5689390 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,6 +128,7 @@ GTK2_REQUIRED=2.6.0
 LIBSEXY_REQUIRED=0.1.11
 UNIQUE_REQUIRED=1.0
 LIBNOTIFY_REQUIRED=0.3.0
+NAUTILUS_REQUIRED=2.24.0
 
 SCROLLKEEPER_REQUIRED=0.3.14
 INTLTOOL_REQUIRED=0.35.0
@@ -136,6 +137,7 @@ PKG_CHECK_MODULES(GLIB2, glib-2.0 >= $GLIB2_REQUIRED)
 PKG_CHECK_MODULES(GOBJECT2, gobject-2.0 >= $GOBJECT2_REQUIRED)
 PKG_CHECK_MODULES(GIO2, gio-2.0 >= $GIO2_REQUIRED)
 PKG_CHECK_MODULES(GIO_UNIX2, gio-unix-2.0 >= $GIO2_REQUIRED)
+PKG_CHECK_MODULES(GTHREAD2, gthread-2.0 >= $GLIB2_REQUIRED)
 PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= $DBUS_GLIB_REQUIRED)
 PKG_CHECK_MODULES(POLKIT_DBUS, polkit-dbus >= $POLKIT_DBUS_REQUIRED)
 PKG_CHECK_MODULES(POLKIT_GNOME, polkit-gnome >= $POLKIT_GNOME_REQUIRED)
@@ -165,6 +167,31 @@ AC_SUBST([GETTEXT_PACKAGE])
 AM_GLIB_GNU_GETTEXT
 AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"],[gettext domain])
 
+# ******************
+# Nautilus extension
+# ******************
+
+have_nautilus=no
+AC_ARG_ENABLE(nautilus, AC_HELP_STRING([--disable-nautilus], [disable nautilus extension]))
+
+if test "x$enable_nautilus" != "xno"; then
+	PKG_CHECK_MODULES(NAUTILUS, libnautilus-extension >= $NAUTILUS_REQUIRED,
+			  [AC_DEFINE(HAVE_NAUTILUS, 1, [Define if nautilus is available])
+			  have_nautilus=yes], have_nautilus=no)
+	if test "x$have_nautilus" = xno -a "x$enable_nautilus" = xyes; then
+		AC_MSG_ERROR([nautilus support requested but libraries not found])
+	fi
+
+	dnl Get nautilus extensions directory
+	NAUTILUS_EXTENSION_DIR=`$PKG_CONFIG --variable=extensiondir libnautilus-extension`
+fi
+
+AC_SUBST(NAUTILUS_LIBS)
+AC_SUBST(NAUTILUS_CFLAGS)
+AC_SUBST(NAUTILUS_EXTENSION_DIR)
+
+AM_CONDITIONAL(ENABLE_NAUTILUS, [test "$have_nautilus" = "yes"])
+
 # *************************************
 # *************************************
 
@@ -184,6 +211,8 @@ src/palimpsest/Makefile
 src/notification/Makefile
 src/playground/Makefile
 src/playground/grid/Makefile
+src/format-tool/Makefile
+src/nautilus-extension/Makefile
 po/Makefile.in
 data/Makefile
 data/gdu-notification-daemon.desktop.in.in
@@ -218,4 +247,5 @@ echo "
 
         Maintainer mode:            ${USE_MAINTAINER_MODE}
         Building api docs:          ${enable_gtk_doc}
+        Nautilus extension:         ${have_nautilus}
 "
diff --git a/data/icons/16x16/Makefile.am b/data/icons/16x16/Makefile.am
index 5910843..5e24a54 100644
--- a/data/icons/16x16/Makefile.am
+++ b/data/icons/16x16/Makefile.am
@@ -17,7 +17,8 @@ icon_DATA =				\
 	gdu-info.png			\
 	gdu-error.png			\
 	gdu-warning.png			\
-	gdu-unmountable.png
+	gdu-unmountable.png		\
+	nautilus-gdu.png
 
 EXTRA_DIST = \
 	$(icon_DATA)
diff --git a/data/icons/16x16/nautilus-gdu.png b/data/icons/16x16/nautilus-gdu.png
new file mode 100644
index 0000000..4017fd2
Binary files /dev/null and b/data/icons/16x16/nautilus-gdu.png differ
diff --git a/data/icons/22x22/Makefile.am b/data/icons/22x22/Makefile.am
index bc41bef..c78dfad 100644
--- a/data/icons/22x22/Makefile.am
+++ b/data/icons/22x22/Makefile.am
@@ -17,7 +17,8 @@ icon_DATA =				\
 	gdu-info.png			\
 	gdu-error.png			\
 	gdu-warning.png			\
-	gdu-unmountable.png
+	gdu-unmountable.png		\
+	nautilus-gdu.png
 
 EXTRA_DIST = \
 	$(icon_DATA)
diff --git a/data/icons/22x22/nautilus-gdu.png b/data/icons/22x22/nautilus-gdu.png
new file mode 100644
index 0000000..9773ab8
Binary files /dev/null and b/data/icons/22x22/nautilus-gdu.png differ
diff --git a/data/icons/48x48/Makefile.am b/data/icons/48x48/Makefile.am
index 37bb0d2..082659f 100644
--- a/data/icons/48x48/Makefile.am
+++ b/data/icons/48x48/Makefile.am
@@ -17,7 +17,8 @@ icon_DATA = 				\
 	gdu-info.png			\
 	gdu-error.png			\
 	gdu-warning.png			\
-	gdu-unmountable.png
+	gdu-unmountable.png		\
+	nautilus-gdu.png
 
 EXTRA_DIST = \
 	$(icon_DATA)
diff --git a/data/icons/48x48/nautilus-gdu.png b/data/icons/48x48/nautilus-gdu.png
new file mode 100644
index 0000000..8220209
Binary files /dev/null and b/data/icons/48x48/nautilus-gdu.png differ
diff --git a/data/icons/scalable/Makefile.am b/data/icons/scalable/Makefile.am
index 9d06b60..9c049b2 100644
--- a/data/icons/scalable/Makefile.am
+++ b/data/icons/scalable/Makefile.am
@@ -17,7 +17,8 @@ icon_DATA =				\
 	gdu-info.svg			\
 	gdu-error.svg			\
 	gdu-warning.svg			\
-	gdu-unmountable.svg
+	gdu-unmountable.svg		\
+	nautilus-gdu.svg
 
 EXTRA_DIST = \
 	$(icon_DATA)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cc22fc4..8185929 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,6 +3,9 @@
 # Please keep this file sorted alphabetically.
 data/palimpsest.desktop.in
 data/gdu-notification-daemon.desktop.in.in.in
+src/format-tool/format-window.c
+src/format-tool/format-window-operation.c
+src/format-tool/gdu-format-tool.c
 src/gdu/gdu-ata-smart-attribute.c
 src/gdu/gdu-ata-smart-attribute.h
 src/gdu/gdu-ata-smart-historical-data.c
@@ -38,6 +41,7 @@ src/gdu-gtk/gdu-gtk.h
 src/gdu-gtk/gdu-gtk-types.h
 src/gdu-gtk/gdu-time-label.c
 src/gdu-gtk/gdu-time-label.h
+src/nautilus-extension/nautilus-gdu.c
 src/notification/gdu-slow-unmount-dialog.c
 src/notification/gdu-slow-unmount-dialog.h
 src/notification/notification-main.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 6a4453c..a1bfdbf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,8 @@
-SUBDIRS = gdu gdu-gtk palimpsest notification playground
+SUBDIRS = gdu gdu-gtk palimpsest notification playground format-tool
+
+if ENABLE_NAUTILUS
+SUBDIRS += nautilus-extension
+endif
 
 clean-local :
 	rm -f *~
diff --git a/src/format-tool/Makefile.am b/src/format-tool/Makefile.am
new file mode 100644
index 0000000..752fa9d
--- /dev/null
+++ b/src/format-tool/Makefile.am
@@ -0,0 +1,53 @@
+NULL =
+
+INCLUDES =						\
+	-DDATADIR=\"$(datadir)\"			\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"	\
+	-I$(top_srcdir)/src				\
+	-I$(top_builddir)/src				\
+	$(WARN_CFLAGS)					\
+	$(AM_CFLAGS)					\
+	-DGDU_API_IS_SUBJECT_TO_CHANGE			\
+	-DGDU_GTK_API_IS_SUBJECT_TO_CHANGE		\
+	$(NULL)
+
+CORE_CFLAGS = 						\
+	$(GLIB2_CFLAGS)					\
+	$(GOBJECT2_CFLAGS)				\
+	$(GIO2_CFLAGS)					\
+	$(GIO_UNIX2_CFLAGS)				\
+	$(GTHREAD2_CFLAGS)				\
+	$(POLKIT_DBUS_CFLAGS)				\
+	$(GTK2_CFLAGS)					\
+	$(POLKIT_GNOME_CFLAGS)				\
+	$(NULL)
+
+CORE_LIBADD = 						\
+	$(GLIB2_LIBS)					\
+	$(GOBJECT2_LIBS)				\
+	$(GIO2_LIBS)					\
+	$(GIO_UNIX2_LIBS)				\
+	$(GTHREAD2_LIBS)				\
+	$(POLKIT_DBUS_LIBS)				\
+	$(GTK2_LIBS)					\
+	$(POLKIT_GNOME_LIBS)				\
+	$(INTLLIBS)					\
+	$(top_builddir)/src/gdu/libgdu.la		\
+	$(top_builddir)/src/gdu-gtk/libgdu-gtk.la	\
+	$(NULL)
+
+libexec_PROGRAMS = gdu-format-tool
+
+gdu_format_tool_SOURCES =		\
+	format-window.c			\
+	format-window.h			\
+	format-window-operation.c	\
+	format-window-operation.h	\
+	gdu-utils.c			\
+	gdu-utils.h			\
+	gdu-format-tool.c		\
+	$(NULL)
+
+gdu_format_tool_CPPFLAGS = $(CORE_CFLAGS) -DG_LOG_DOMAIN=\"GDU-Format-Tool\"
+gdu_format_tool_LDFLAGS = $(AM_LDFLAGS)
+gdu_format_tool_LDADD = $(CORE_LIBADD)
diff --git a/src/format-tool/TODO b/src/format-tool/TODO
new file mode 100644
index 0000000..ff1a315
--- /dev/null
+++ b/src/format-tool/TODO
@@ -0,0 +1,62 @@
+code.
+
+Short-term:
+  DONE, NEEDS_TESTING - refresh after operation succesfully finished, make Revert button work as expected (need to retrieve GduPresentable again)
+  DONE - PolicyKit integration
+  DONE - Stop button (once PolicyKit integration is done)
+    DONE - window close action should be ignored (+ Escape, Alt+F4 keybindings...)
+  DONE - simple standalone mode
+  REMOVED - do we need Bootable flag for something?
+  DONE - make a Fedora package
+  DONE, NEEDS_TESTING - !! set partition type too !!  (only for MBR?)
+  OK - check label length before formatting (should be done automatically) -- DK returning wrong values for FAT and NTFS
+  DONE - get rid of the Revert button
+  DONE - call luks_lock() beside unmount, that would allow formatting active LUKS devices
+  DONE - install to libexec
+  DONE - add Palimpsest button
+  - display mount warning and perform unmount of all nested partitions, in case of LUKS
+
+Standalone mode:
+  DONE - refresh volume selector on hotplug/unplug
+  DONE - carefully count references (valgrind)
+  DONE - UI cleanup: get rid of those twin icons (show them only when expanded)
+                     find a way how to expand the combo box to full width
+  DONE - desktop file
+  DONE - icon
+  DONE - display insensitive placeholder item "Please select a volume to format"
+
+
+
+- handle LUKS encrypted volumes -- creating new encrypted media works fine, but reverting back to non-encrypted doesn't (device /dev/sdb1 vs. /dev/dm-0)
+DONE, NEEDS_TESTING - monitor device/presentable events like eject, umount etc. (try to pull the USB key out and window should disappear)
+- show custom icon if user has set it in Nautilus
+REMOVED- is firmware needed for some devices?
+DONE - different partition tables?
+DONE - what to do if device is blank (zeroed, no MBR)?
+DONE - handle read only device - gdu_device_is_read_only() - test with DVD-RAM media
+- stay consistent with volume labels in Nautilus and gdu (requires gvfs-devicekit port)
+NOT NEEDED- localization (transifex? -- ask hughsie)
+- test multihead (need to ref screen of the source nautilus window)
+- nautilus integration: be able to spawn the dialog from sidebar
+DONE - make standalone mode optional (configure --enable-standalone)
+DONE - duplicate /dev/sr0 device in the list when media is present
+- don't show Nautilus menu item when no media is in drive or device is readonly
+
+
+Ideas:
+ - allow NTFS formatting and popup a PackageKit window when ntfs-3g is not available (shamelessly stolen from gnome-format discussion)
+ DONE - make standalone executable with a device/volume combo box to format
+ - maybe add a button to unmount the volume so user can close all applications properly?
+ - mount volume back if we did unmount before formatting?
+
+Bugs:
+ - Busy dialog eats too much CPU and freezes UI
+ - DeviceKit-disks should require mtools (for FAT labeling)
+ - libgdu should return always valid presentable names
+ NO - should the presentable instance from the pool::presentable-{added,changed,removed} signals be unreffed?
+ - complete CD-RW medium is not marked as readonly -- are we gonna have burning backend in DK-disks?
+ - would be great to have gdu_pool_get_toplevel_presentables()
+ - gdu_presentable_get_toplevel() always returns valid presentable even if it's already toplevel (i.e. /dev/md0), never returns NULL
+ - gdu_device_drive_get_media_compatibility() returns const char* pointers - check and document properly
+ - BUG !! gdu_device_op_partition_create() and gdu_device_op_partition_table_create() should spawn their finish callbacks only after device is ready (and pool up-to-date) so we can start another operation right away
+ SOLVED - find a way to reliably detect active LUKS on the device
diff --git a/src/format-tool/format-window-operation.c b/src/format-tool/format-window-operation.c
new file mode 100644
index 0000000..bf72abc
--- /dev/null
+++ b/src/format-tool/format-window-operation.c
@@ -0,0 +1,804 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  format-window-operation.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <gdu-gtk/gdu-gtk.h>
+
+#include <polkit-gnome/polkit-gnome.h>
+
+#include "gdu-utils.h"
+#include "format-window-operation.h"
+
+
+
+/*  TODO: find a better way for this  */
+#define DEVICE_SETTLE_TIMEOUT 3000
+
+
+/*  Look whether the device needs to be partitioned  */
+/*  - generally we don't want to have partitions on optical drives and floppy disks  */
+static gboolean
+device_needs_partition_table (GduDevice *device)
+{
+        gchar **media_compat;
+        gboolean needs = TRUE;  /*  default to TRUE  */
+
+        media_compat = gdu_device_drive_get_media_compatibility (device);
+        for (; *media_compat; media_compat++) {
+                g_debug ("     compat '%s'\n", *media_compat);
+                /*  http://hal.freedesktop.org/docs/DeviceKit-disks/Device.html#Device:drive-media-compatibility  */
+                if (strstr (*media_compat, "optical") == *media_compat ||
+                    strstr (*media_compat, "floppy") == *media_compat) {
+                        needs = FALSE;
+                        break;
+                }
+        }
+#if 0
+        g_strfreev (media_compat);   /* so, is this const then?  */
+#endif
+        g_debug ("device_needs_partition_table = %d", needs);
+        return needs;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static gboolean
+job_progress_pulse_timeout_handler (gpointer user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_val_if_fail (data != NULL, TRUE);
+
+        gtk_progress_bar_pulse (GTK_PROGRESS_BAR (data->priv->progress_bar));
+
+        return TRUE;
+}
+
+static void
+do_progress_bar_update (FormatProcessData *data,
+                        const gchar       *label,
+                        gdouble            percentage,
+                        gboolean           active)
+{
+        if (active) {
+                if (label)
+                        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (data->priv->progress_bar), label);
+
+                if (percentage < 0) {
+                        gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (data->priv->progress_bar), 2.0 / 50);
+                        gtk_progress_bar_pulse (GTK_PROGRESS_BAR (data->priv->progress_bar));
+                        if (data->job_progress_pulse_timer_id == 0) {
+                                data->job_progress_pulse_timer_id = g_timeout_add (
+                                                                                   1000 / 50,
+                                                                                   job_progress_pulse_timeout_handler,
+                                                                                   data);
+                        }
+                } else {
+                        if (data->job_progress_pulse_timer_id > 0) {
+                                g_source_remove (data->job_progress_pulse_timer_id);
+                                data->job_progress_pulse_timer_id = 0;
+                        }
+                        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (data->priv->progress_bar),
+                                                       percentage / 100.0);
+                }
+        }
+        else {
+                if (data->job_progress_pulse_timer_id > 0) {
+                        g_source_remove (data->job_progress_pulse_timer_id);
+                        data->job_progress_pulse_timer_id = 0;
+                }
+        }
+}
+
+static void
+presentable_job_changed (GduPresentable *presentable,
+                         gpointer        user_data)
+{
+        FormatProcessData *data = user_data;
+        gchar *job_description;
+        gdouble percentage;
+
+        g_return_if_fail (data != NULL);
+
+        if (data->device != NULL && gdu_device_job_in_progress (data->device)) {
+                job_description = gdu_get_job_description (gdu_device_job_get_id (data->device));
+
+                percentage = gdu_device_job_get_percentage (data->device);
+                do_progress_bar_update (data, job_description, percentage, TRUE);
+
+                g_free (job_description);
+
+        } else {
+                /*  do_progress_bar_update (data, NULL, -1, FALSE);  */
+                /*  Mask inactivity by bouncing -- this should be fixed in libgdu  */
+                do_progress_bar_update (data, NULL, -1, TRUE);
+        }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static void unmount_auth_end_callback (PolKitGnomeAction *action, gboolean gained_privilege, gpointer user_data);
+static void format_auth_end_callback (PolKitGnomeAction *action, gboolean gained_privilege, gpointer user_data);
+static void format_action_callback (GtkAction *action, gpointer user_data);
+static void part_modify_auth_end_callback (PolKitGnomeAction *action, gboolean gained_privilege, gpointer user_data);
+static void part_modify_action_callback (GtkAction *action, gpointer user_data);
+static void part_table_new_auth_end_callback (PolKitGnomeAction *action, gboolean gained_privilege, gpointer user_data);
+static void part_table_new_action_callback (GtkAction *action, gpointer user_data);
+static void part_new_auth_end_callback (PolKitGnomeAction *action, gboolean gained_privilege, gpointer user_data);
+static void part_new_action_callback (GtkAction *action, gpointer user_data);
+
+void
+update_ui_progress (FormatDialogPrivate *priv,
+                    FormatProcessData   *data,
+                    gboolean             working)
+{
+        g_return_if_fail (priv != NULL);
+
+        priv->job_running = working;
+
+        if (working) {
+                gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progress_bar), NULL);
+                gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_bar), 0.0);
+                gtk_button_set_label (GTK_BUTTON (priv->close_button), GTK_STOCK_STOP);
+                gtk_widget_show (priv->progress_bar_box);
+                gtk_widget_hide (priv->all_controls_box);
+                if (data) {
+                        g_signal_connect (data->presentable, "job-changed", G_CALLBACK (presentable_job_changed), data);
+
+                        /*  set up PolicyKit actions  */
+                        data->pk_format_action = polkit_action_new ();
+                        polkit_action_set_action_id (data->pk_format_action, "org.freedesktop.devicekit.disks.change");
+                        data->format_action = polkit_gnome_action_new_default ("format", data->pk_format_action, NULL, NULL);
+                        g_signal_connect (data->format_action, "auth-end", G_CALLBACK (format_auth_end_callback), data);
+                        g_signal_connect (data->format_action, "activate", G_CALLBACK (format_action_callback), data);
+
+                        data->pk_part_modify_action = polkit_action_new ();
+                        /*  action_id is the same as for format, but sometimes authentication is one shot  */
+                        polkit_action_set_action_id (data->pk_part_modify_action, "org.freedesktop.devicekit.disks.change");
+                        data->part_modify_action = polkit_gnome_action_new_default ("part_modify", data->pk_part_modify_action, NULL, NULL);
+                        g_signal_connect (data->part_modify_action, "auth-end", G_CALLBACK (part_modify_auth_end_callback), data);
+                        g_signal_connect (data->part_modify_action, "activate", G_CALLBACK (part_modify_action_callback), data);
+
+                        data->pk_part_table_new_action = polkit_action_new ();
+                        polkit_action_set_action_id (data->pk_part_table_new_action, "org.freedesktop.devicekit.disks.change");
+                        data->part_table_new_action = polkit_gnome_action_new_default ("part_table_new", data->pk_part_table_new_action, NULL, NULL);
+                        g_signal_connect (data->part_table_new_action, "auth-end", G_CALLBACK (part_table_new_auth_end_callback), data);
+                        g_signal_connect (data->part_table_new_action, "activate", G_CALLBACK (part_table_new_action_callback), data);
+
+                        data->pk_part_new_action = polkit_action_new ();
+                        polkit_action_set_action_id (data->pk_part_new_action, "org.freedesktop.devicekit.disks.change");
+                        data->part_new_action = polkit_gnome_action_new_default ("part_new", data->pk_part_new_action, NULL, NULL);
+                        g_signal_connect (data->part_new_action, "auth-end", G_CALLBACK (part_new_auth_end_callback), data);
+                        g_signal_connect (data->part_new_action, "activate", G_CALLBACK (part_new_action_callback), data);
+
+                }
+        }
+        else
+                {
+                        if (data) {
+                                g_signal_handlers_disconnect_matched (data->format_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data);
+                                g_signal_handlers_disconnect_matched (data->part_modify_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data);
+                                g_signal_handlers_disconnect_matched (data->part_table_new_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data);
+                                g_signal_handlers_disconnect_matched (data->part_new_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data);
+
+                                /*  destroy PolicyKit actions  */
+                                polkit_action_unref (data->pk_format_action);
+                                g_object_unref (data->format_action);
+                                polkit_action_unref (data->pk_part_modify_action);
+                                g_object_unref (data->part_modify_action);
+                                polkit_action_unref (data->pk_part_table_new_action);
+                                g_object_unref (data->part_table_new_action);
+                                polkit_action_unref (data->pk_part_new_action);
+                                g_object_unref (data->part_new_action);
+
+                                g_signal_handlers_disconnect_matched (data->presentable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data);
+                                if (data->job_progress_pulse_timer_id > 0) {
+                                        g_source_remove (data->job_progress_pulse_timer_id);
+                                        data->job_progress_pulse_timer_id = 0;
+                                }
+                        }
+                        gtk_widget_show (priv->all_controls_box);
+                        gtk_widget_hide (priv->progress_bar_box);
+                        gtk_button_set_label (GTK_BUTTON (priv->close_button), GTK_STOCK_CLOSE);
+                }
+        update_ui_controls (priv);
+}
+
+static void
+free_format_action_data (FormatProcessData *data)
+{
+        if (data) {
+                update_ui_progress (data->priv, data, FALSE);
+                if (data->presentable != NULL)
+                        g_object_unref (data->presentable);
+                if (data->device != NULL)
+                        g_object_unref (data->device);
+                g_free (data->encrypt_passphrase);
+                g_free (data->fslabel);
+                g_free (data);
+        }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+action_finished (FormatProcessData *data,
+                 gchar             *new_device_path)
+{
+        GduDevice *new_device;
+        GduPresentable *new_presentable = NULL;
+
+        g_return_if_fail (data != NULL);
+
+        /*  we don't want to destroy objects at this point, don't pass data in */
+        update_ui_progress (data->priv, NULL, FALSE);
+
+        /*  change to the new device  */
+        if (new_device_path) {
+                new_device = gdu_pool_get_by_object_path (data->priv->pool, new_device_path);
+                if (new_device) {
+                        g_object_unref (data->device);
+                        data->device = new_device;
+                        new_presentable = gdu_pool_get_volume_by_device (data->priv->pool, new_device);
+                        if (new_presentable) {
+                                /*  switch to new presentable  */
+                                g_debug ("setting new presentable...");
+                        }
+                } else {
+                        g_warning ("action_finished: cannot find device for the %s device path", new_device_path);
+                }
+                g_free (new_device_path);
+        }
+
+        /*  Force refresh of the new presentable  */
+        select_new_presentable (data->priv, new_presentable != NULL ? new_presentable : data->priv->presentable);
+        if (new_presentable)
+                g_object_unref (new_presentable);
+
+        /*  TODO: show encryption info somewhere?  */
+        if (data->encrypt_passphrase != NULL) {
+                /* now set the passphrase if requested */
+                if (data->save_in_keyring || data->save_in_keyring_session) {
+                        gdu_util_save_secret (data->device,
+                                              data->encrypt_passphrase,
+                                              data->save_in_keyring_session);
+                }
+        }
+}
+
+/* -------------------------------------------------------------------------- */
+static void
+fix_focus_cb (GtkDialog *dialog,
+              gpointer   data)
+{
+        GtkWidget *button;
+
+        button = gtk_window_get_default_widget (GTK_WINDOW (dialog));
+        gtk_widget_grab_focus (button);
+}
+
+static void
+expander_cb (GtkExpander *expander,
+             GParamSpec  *pspec,
+             GtkWindow   *dialog)
+{
+        gtk_window_set_resizable (dialog, gtk_expander_get_expanded (expander));
+}
+
+/*  keep in sync with gdu-shell.c/gdu_shell_raise_error()                                               */
+static void
+nautilus_gdu_show_error (GtkWidget      *parent_window,
+                         GduPresentable *presentable,
+                         GError         *error,
+                         const gchar    *primary_markup_format,
+                         ...)
+{
+        GtkWidget *dialog;
+        gchar *error_text;
+        gchar *window_title;
+        GIcon *window_icon;
+        va_list args;
+        GtkWidget *box, *hbox, *expander, *sw, *tv;
+        GList *children;
+        GtkTextBuffer *buffer;
+
+        g_return_if_fail (presentable != NULL);
+        g_return_if_fail (error != NULL);
+
+        window_title = gdu_presentable_get_name (presentable);
+        window_icon = gdu_presentable_get_icon (presentable);
+
+        va_start (args, primary_markup_format);
+        error_text = g_strdup_vprintf (primary_markup_format, args);
+        va_end (args);
+
+        dialog = gtk_message_dialog_new_with_markup (
+                                                     GTK_WINDOW (parent_window),
+                                                     GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                     GTK_MESSAGE_ERROR,
+                                                     GTK_BUTTONS_CLOSE,
+                                                     "<big><b>%s</b></big>",
+                                                     error_text);
+        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+                                                  trim_dk_error (error->message));
+
+        gtk_window_set_title (GTK_WINDOW (dialog), window_title);
+        /*  TODO: no support for GIcon in GtkWindow  */
+        /*  gtk_window_set_icon_name (GTK_WINDOW (dialog), window_icon_name);  */
+
+        g_signal_connect_swapped (dialog,
+                                  "response",
+                                  G_CALLBACK (gtk_main_quit),
+                                  NULL);
+        gtk_window_present (GTK_WINDOW (dialog));
+
+        g_free (window_title);
+        if (window_icon != NULL)
+                g_object_unref (window_icon);
+        g_free (error_text);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void
+modify_partition_completed (GduDevice  *device,
+                            GError     *error,
+                            gpointer    user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_debug ("modify_partition_completed");
+        g_return_if_fail (data != NULL);
+
+        if (error != NULL) {
+                nautilus_gdu_show_error (GTK_WIDGET (data->priv->dialog),
+                                         data->presentable,
+                                         error,
+                                         _("Error modifying partition"));
+                g_error_free (error);
+        }
+        else
+                {
+                        /*  -- don't refresh here, wait for the "changed" callback
+                            update_ui (data->priv);  */
+                }
+        /*  save encryption info even if operation fails  */
+        action_finished (data, NULL);
+        free_format_action_data (data);
+}
+
+static void
+part_modify_action_callback (GtkAction *action,
+                             gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_modify_action_callback");
+
+        if (data->priv->job_cancelled)
+                return;
+
+        /*  DK is buggy, passing a label string causes the operation to fail  */
+        gdu_device_op_partition_modify (data->device, data->recommended_part_type, NULL, NULL, modify_partition_completed, data);
+}
+
+static void
+part_modify_auth_end_callback (PolKitGnomeAction *action,
+                               gboolean           gained_privilege,
+                               gpointer           user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_modify_auth_end_callback");
+
+        if (! gained_privilege) {
+                /*  cancel the whole operation  */
+                free_format_action_data (data);
+        }
+        else {
+                /*  positive reply should be handled by part_modify_action_callback  */
+        }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+format_action_completed (GduDevice  *device,
+                         GError     *error,
+                         gpointer    user_data)
+{
+        FormatProcessData *data = user_data;
+        const gchar *part_type;
+        GduPresentable *toplevel_presentable;
+        GduDevice *toplevel_device;
+
+        g_debug ("format_action_completed");
+        g_return_if_fail (data != NULL);
+
+        if (error != NULL) {
+                nautilus_gdu_show_error (GTK_WIDGET (data->priv->dialog),
+                                         data->presentable,
+                                         error,
+                                         _("Error creating partition"));
+                g_error_free (error);
+        }
+        else
+                {
+                        /*  Get device scheme if needed  */
+                        if (! data->scheme || strlen (data->scheme) == 0) {
+                                toplevel_presentable = gdu_presentable_get_toplevel (data->presentable);
+                                if (toplevel_presentable) {
+                                        toplevel_device = gdu_presentable_get_device (toplevel_presentable);
+                                        if (toplevel_device) {
+                                                data->scheme = gdu_device_partition_table_get_scheme (toplevel_device);
+                                                g_object_unref (toplevel_device);
+                                        }
+                                        g_object_unref (toplevel_presentable);
+                                }
+                        }
+
+                        /*  Correct partition type  */
+                        if (! data->priv->job_cancelled && data->scheme && strlen (data->scheme) > 0) {
+                                part_type = gdu_device_partition_get_type (device);
+                                data->recommended_part_type = gdu_util_get_default_part_type_for_scheme_and_fstype (data->scheme, data->fstype, gdu_device_partition_get_size (device));
+                                g_debug ("format_action_completed: part_type = %s, recommended_part_type = %s", part_type, data->recommended_part_type);
+                                /*  Change partition type if necessary  */
+                                if (strcmp (part_type, data->recommended_part_type) != 0)
+                                        {
+                                                g_debug ("changing part type to %s, device = %s", data->recommended_part_type, gdu_device_get_device_file (device));
+                                                gtk_action_activate (GTK_ACTION (data->part_modify_action));
+                                                return;  /*  don't change the UI yet  */
+                                        }
+                        }
+
+                        /*  formatting finished  */
+                        action_finished (data, NULL);
+                }
+        free_format_action_data (data);
+}
+
+static void
+format_action_callback (GtkAction *action,
+                        gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("format_action_callback");
+
+        if (data->priv->job_cancelled)
+                return;
+
+        gdu_device_op_filesystem_create (data->device,
+                                         data->fstype,
+                                         data->fslabel,
+                                         data->encrypt_passphrase,
+                                         data->take_ownership,
+                                         format_action_completed,
+                                         data);
+}
+
+static void
+format_auth_end_callback (PolKitGnomeAction *action,
+                          gboolean           gained_privilege,
+                          gpointer           user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("format_auth_end_callback");
+
+        if (! gained_privilege) {
+                /*  cancel the whole operation  */
+                free_format_action_data (data);
+        }
+        else {
+                /*  positive reply should be handled by format_action_callback  */
+        }
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+part_table_new_timeout_handler (gpointer user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_val_if_fail (data != NULL, FALSE);
+        g_debug ("part_table_new_timeout_handler");
+
+        gtk_action_activate (GTK_ACTION (data->part_new_action));
+
+        return FALSE;
+}
+
+static void
+part_table_new_completed (GduDevice *device,
+                          GError    *error,
+                          gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+
+        /*  BUG: callback shouldn't be spawned until all changes are reflected in pool  */
+        g_return_if_fail (data != NULL);
+
+        g_debug ("part_table_new_completed");
+        update_ui_controls (data->priv);
+
+        if (error != NULL) {
+                nautilus_gdu_show_error (GTK_WIDGET (data->priv->dialog),
+                                         data->presentable,
+                                         error,
+                                         _("Error creating new partition table"));
+                free_format_action_data (data);
+                g_error_free (error);
+        }
+        else
+                {
+                        g_debug ("  creating partition...");
+                        if (data->priv->job_cancelled)
+                                return;
+                        /*  TODO: we should wait here for proper refresh  */
+                        g_timeout_add (DEVICE_SETTLE_TIMEOUT, part_table_new_timeout_handler, data);
+                        do_progress_bar_update (data, _("Waiting for device to settle..."), -1, TRUE);
+                        /*  gtk_action_activate (GTK_ACTION (data->part_new_action));  -- disabled  */
+                }
+}
+
+static void
+part_table_new_action_callback (GtkAction *action,
+                                gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_table_new_action_callback");
+
+        if (data->priv->job_cancelled)
+                return;
+
+        /*  default to MBR  */
+        data->scheme = "mbr";
+
+        gdu_device_op_partition_table_create (data->device, data->scheme, part_table_new_completed, data);
+}
+
+static void
+part_table_new_auth_end_callback (PolKitGnomeAction *action,
+                                  gboolean           gained_privilege,
+                                  gpointer           user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_table_new_auth_end_callback");
+
+        if (! gained_privilege) {
+                /*  cancel the whole operation  */
+                free_format_action_data (data);
+        }
+        else {
+                /*  positive reply should be handled by unmount_action_callback  */
+        }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void
+part_new_completed (GduDevice *device,
+                    gchar     *created_device_object_path,
+                    GError    *error,
+                    gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+
+        /*  BUG: callback shouldn't be spawned until all changes are reflected in pool  */
+        g_return_if_fail (data != NULL);
+
+        g_debug ("part_new_completed, created_device_object_path = %s", error == NULL ? created_device_object_path : NULL);
+
+        if (error != NULL) {
+                nautilus_gdu_show_error (GTK_WIDGET (data->priv->dialog),
+                                         data->presentable,
+                                         error,
+                                         _("Error creating new partition"));
+                g_error_free (error);
+        }
+        else
+                {
+                        /*  formatting finished  */
+                        /*  TODO: we should wait here for proper refresh  */
+                        action_finished (data, g_strdup (created_device_object_path));
+                }
+        free_format_action_data (data);
+}
+
+static void
+part_new_action_callback (GtkAction *action,
+                          gpointer   user_data)
+{
+        FormatProcessData *data = user_data;
+        guint64 offset;
+        guint64 size;
+        gchar *type;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_new_action_callback, device = %s", gdu_device_get_device_file (data->device));
+
+        if (data->priv->job_cancelled)
+                return;
+
+        offset = gdu_presentable_get_offset (data->presentable);
+        size = gdu_presentable_get_size (data->presentable);
+
+        if (! data->scheme || strlen (data->scheme) == 0)
+                data->scheme = gdu_device_partition_table_get_scheme (data->device);   /*  we should have toplevel device here  */
+        if (! data->scheme || strlen (data->scheme) == 0)
+                data->scheme = "mbr";   /*  default to MBR  */
+
+        type = gdu_util_get_default_part_type_for_scheme_and_fstype (data->scheme, data->fstype, size);
+
+        g_debug ("creating new partition, offset = %lu, size = %lu, scheme = %s, type = %s", offset, size, data->scheme, type);
+
+        gdu_device_op_partition_create (data->device, offset, size, type, NULL, NULL,
+                                        data->fstype, data->fslabel, data->encrypt_passphrase, data->take_ownership,
+                                        part_new_completed, data);
+        g_free (type);
+}
+
+static void
+part_new_auth_end_callback (PolKitGnomeAction *action,
+                            gboolean           gained_privilege,
+                            gpointer           user_data)
+{
+        FormatProcessData *data = user_data;
+
+        g_return_if_fail (data != NULL);
+        g_debug ("part_new_auth_end_callback");
+
+        if (! gained_privilege) {
+                /*  cancel the whole operation  */
+                free_format_action_data (data);
+        }
+        else {
+                /*  positive reply should be handled by unmount_action_callback  */
+        }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/*  taken from palimpsest/gdu-section-unrecognized.c  */
+void
+do_format (FormatDialogPrivate *priv)
+{
+        FormatProcessData *data;
+        GduPresentable *toplevel_presentable;
+        GduDevice *toplevel_device;
+        gboolean create_new_part_table = FALSE;
+        gboolean create_new_partition = FALSE;
+        GduKnownFilesystem *kfs;
+        gint part_combo_item_index;
+
+
+        priv->job_cancelled = FALSE;
+        data = g_new0 (FormatProcessData, 1);
+        data->priv = priv;
+        data->job_progress_pulse_timer_id = 0;
+        toplevel_presentable = NULL;
+        toplevel_device = NULL;
+
+
+        data->presentable = g_object_ref (priv->presentable);
+        toplevel_presentable = gdu_presentable_get_toplevel (data->presentable);
+        if (toplevel_presentable == NULL) {
+                g_warning ("%s: no toplevel presentable",  __FUNCTION__);
+        }
+        toplevel_device = gdu_presentable_get_device (toplevel_presentable);
+        if (toplevel_device == NULL) {
+                g_warning ("%s: no device for toplevel presentable",  __FUNCTION__);
+                free_format_action_data (data);
+                goto out;
+        }
+        data->device = gdu_presentable_get_device (data->presentable);
+
+        if (data->device == NULL && toplevel_device != NULL) {
+                /*  no device, i.e. partition table exists but no partition  */
+                data->device = g_object_ref (toplevel_device);
+                create_new_part_table = FALSE;
+                create_new_partition = TRUE;
+                g_debug ("Partition table exists but has no partition for the selected device.");
+        } else
+                if (toplevel_device != NULL && ! gdu_device_is_partition_table (toplevel_device)) {
+                        /*  no partition table on the device, create partition table first.  */
+                        /*  also empty (zeroed) device  */
+                        create_new_part_table = TRUE;
+                        create_new_partition = TRUE;
+                        g_debug ("Device is known but doesn't have partition table, we need to create it first.");
+                } else
+                        if (toplevel_device != NULL && data->device != NULL && toplevel_device == data->device && device_needs_partition_table (data->device)) {
+                                /*  device is toplevel, check if we need new partitions  */
+                                create_new_partition = TRUE;
+                                g_debug ("Device is known but requires partitioning, we'll create new one.");
+                        }
+
+        if (data->device == NULL) {
+                g_warning ("%s: device is not supposed to be NULL",  __FUNCTION__);
+                free_format_action_data (data);
+                goto out;
+        }
+
+        part_combo_item_index = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->part_type_combo_box));
+        if (part_combo_item_index < 0 || part_combo_item_index >= (int) G_N_ELEMENTS (filesystem_combo_items)) {
+                g_warning ("%s: no valid filesystem type specified",  __FUNCTION__);
+                free_format_action_data (data);
+                goto out;
+        }
+        data->fstype = filesystem_combo_items[part_combo_item_index].fstype;
+        data->fslabel = g_strdup (GTK_WIDGET_IS_SENSITIVE (priv->label_entry) ?
+                                  gtk_entry_get_text (GTK_ENTRY (priv->label_entry)) : "");
+
+        data->take_ownership = FALSE;
+        kfs = gdu_pool_get_known_filesystem_by_id (priv->pool, data->fstype);
+        if (kfs != NULL) {
+                if (gdu_known_filesystem_get_supports_unix_owners (kfs))
+                        data->take_ownership = TRUE;
+                g_object_unref (kfs);
+        }
+
+        update_ui_progress (priv, data, TRUE);
+
+        if (filesystem_combo_items[part_combo_item_index].encrypted) {
+                data->encrypt_passphrase = gdu_util_dialog_ask_for_new_secret (GTK_WIDGET (priv->dialog),
+                                                                               &data->save_in_keyring,
+                                                                               &data->save_in_keyring_session);
+                if (data->encrypt_passphrase == NULL) {
+                        free_format_action_data (data);
+                        goto out;
+                }
+        }
+
+        if (create_new_part_table && device_needs_partition_table (data->device)) {
+                /*  device is zeroed, create partition table first  */
+                gtk_action_activate (GTK_ACTION (data->part_table_new_action));
+        } else
+                if (create_new_partition && device_needs_partition_table (data->device)) {
+                        /*  device has partition table but has no partition  */
+                        gtk_action_activate (GTK_ACTION (data->part_new_action));
+                } else {
+                        gtk_action_activate (GTK_ACTION (data->format_action));
+                }
+
+ out:
+        if (toplevel_presentable != NULL)
+                g_object_unref (toplevel_presentable);
+        if (toplevel_device != NULL)
+                g_object_unref (toplevel_device);
+}
diff --git a/src/format-tool/format-window-operation.h b/src/format-tool/format-window-operation.h
new file mode 100644
index 0000000..39f5499
--- /dev/null
+++ b/src/format-tool/format-window-operation.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  format-window-operation.h
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#ifndef FORMAT_WINDOW_OPERATION_H
+#define FORMAT_WINDOW_OPERATION_H
+
+#include <gtk/gtk.h>
+#include <gdu/gdu.h>
+#include "format-window.h"
+
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+        FormatDialogPrivate *priv;
+        gchar *encrypt_passphrase;
+        gboolean save_in_keyring;
+        gboolean save_in_keyring_session;
+        gchar *fslabel;
+        const gchar *fstype;
+        GduDevice *device;
+        GduPresentable *presentable;
+        gboolean take_ownership;
+        const gchar *recommended_part_type;
+        const gchar *scheme;
+
+        guint job_progress_pulse_timer_id;
+
+        PolKitAction *pk_format_action;
+        PolKitGnomeAction *format_action;
+        PolKitAction *pk_part_modify_action;
+        PolKitGnomeAction *part_modify_action;
+        PolKitAction *pk_part_table_new_action;
+        PolKitGnomeAction *part_table_new_action;
+        PolKitAction *pk_part_new_action;
+        PolKitGnomeAction *part_new_action;
+} FormatProcessData;
+
+
+/*  update UI controls when operation is in progress  */
+void update_ui_progress  (FormatDialogPrivate *priv,
+                          FormatProcessData   *data,
+                          gboolean             working);
+
+/*  start the format operation  */
+void do_format           (FormatDialogPrivate *priv);
+
+
+G_END_DECLS
+
+#endif  /* FORMAT_WINDOW_OPERATION_H */
+
diff --git a/src/format-tool/format-window.c b/src/format-tool/format-window.c
new file mode 100644
index 0000000..61a8da4
--- /dev/null
+++ b/src/format-tool/format-window.c
@@ -0,0 +1,578 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  format-window.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <gdu/gdu.h>
+#include <gdu-gtk/gdu-gtk.h>
+
+#include "gdu-utils.h"
+#include "format-window.h"
+#include "format-window-operation.h"
+
+#define DISK_MANAGEMENT_UTILITY  "palimpsest"
+
+
+
+/* ---------------------------------------------------------------------------*/
+
+static void set_new_presentable (FormatDialogPrivate *priv,
+                                 GduPresentable      *presentable);
+
+/* -------------------------------------------------------------------------- */
+
+
+static void
+populate_type_combo (FormatDialogPrivate *priv)
+{
+        guint i;
+        gint old_active;
+
+        g_return_if_fail (priv != NULL);
+
+        old_active = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->part_type_combo_box));
+
+        for (i = G_N_ELEMENTS (filesystem_combo_items); i > 0; i--)
+                gtk_combo_box_remove_text (GTK_COMBO_BOX (priv->part_type_combo_box), i - 1);
+
+        for (i = 0; i < G_N_ELEMENTS (filesystem_combo_items); i++) {
+                if (! filesystem_combo_items[i].encrypted || gdu_pool_supports_luks_devices (priv->pool))
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (priv->part_type_combo_box), _(filesystem_combo_items[i].title));
+        }
+
+        gtk_combo_box_set_active (GTK_COMBO_BOX (priv->part_type_combo_box), old_active);
+        /*  fallback  */
+        if (gtk_combo_box_get_active (GTK_COMBO_BOX (priv->part_type_combo_box)) == -1)
+                gtk_combo_box_set_active (GTK_COMBO_BOX (priv->part_type_combo_box), 0);
+}
+
+static void
+type_combo_box_changed (GtkWidget           *combo_box,
+                        FormatDialogPrivate *priv)
+{
+        const gchar *fstype;
+        GduKnownFilesystem *kfs;
+        gint max_label_len;
+        gint part_combo_item_index;
+
+        fstype = NULL;
+
+        max_label_len = 0;
+
+        part_combo_item_index = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box));
+        if (part_combo_item_index < 0 || part_combo_item_index >= (int) G_N_ELEMENTS (filesystem_combo_items))
+                return;
+        fstype = filesystem_combo_items[part_combo_item_index].fstype;
+
+        kfs = gdu_pool_get_known_filesystem_by_id (priv->pool, fstype);
+        if (kfs != NULL) {
+                max_label_len = gdu_known_filesystem_get_max_label_len (kfs);
+                g_object_unref (kfs);
+        }
+
+        gtk_entry_set_max_length (GTK_ENTRY (priv->label_entry), max_label_len);
+}
+
+void
+update_ui_controls (FormatDialogPrivate *priv)
+{
+        GduDevice *device = NULL;
+        gboolean sensitive;
+
+        g_return_if_fail (priv != NULL);
+
+        if (priv->presentable && GDU_IS_PRESENTABLE (priv->presentable))
+                device = gdu_presentable_get_device (priv->presentable);
+
+        /*  mount warning box  */
+        if (device && gdu_device_is_mounted (device))
+                gtk_widget_show (priv->mount_warning);
+        else
+                gtk_widget_hide (priv->mount_warning);
+
+        /*  read only info box  */
+        if (device && gdu_device_is_read_only (device))
+                gtk_widget_show (priv->readonly_warning);
+        else
+                gtk_widget_hide (priv->readonly_warning);
+
+        /*  no media info box  */
+        if (! device || gdu_device_is_media_available (device))
+                gtk_widget_hide (priv->no_media_warning);
+        else
+                gtk_widget_show (priv->no_media_warning);
+
+        /*  controls sensitivity  */
+        sensitive = priv->presentable != NULL && GDU_IS_PRESENTABLE (priv->presentable) && (! priv->job_running);
+        if (device)
+                sensitive = sensitive && ! gdu_device_is_read_only (device) && gdu_device_is_media_available (device);
+
+        /*  volume label max length  */
+        type_combo_box_changed (priv->part_type_combo_box, priv);
+
+        gtk_widget_set_sensitive (priv->controls_box, sensitive);
+        gtk_dialog_set_response_sensitive (priv->dialog, GTK_RESPONSE_OK, sensitive && gtk_combo_box_get_active (GTK_COMBO_BOX (priv->part_type_combo_box)) >= 0);
+        gtk_dialog_set_response_sensitive (priv->dialog, GTK_RESPONSE_ACCEPT, ! priv->job_running);
+
+        if (device != NULL)
+                g_object_unref (device);
+}
+
+
+static void
+update_ui (FormatDialogPrivate *priv)
+{
+        gchar *s;
+        gchar *title;
+        const gchar *name;
+        GdkPixbuf *pixbuf;
+        GduDevice *device;
+        gchar *icon_name;
+        GIcon *presentable_icon;
+
+
+        g_return_if_fail (priv != NULL);
+        g_return_if_fail (priv->presentable != NULL);
+
+        device = gdu_presentable_get_device (priv->presentable);
+        name = gdu_presentable_get_name (priv->presentable);
+
+        /*  icon stuff  */
+        pixbuf = gdu_util_get_pixbuf_for_presentable_at_pixel_size (priv->presentable, 48);
+        gtk_image_set_from_pixbuf (GTK_IMAGE (priv->icon_image), pixbuf);
+        if (pixbuf)
+                g_object_unref (pixbuf);
+        presentable_icon = gdu_presentable_get_icon (priv->presentable);
+        if (presentable_icon) {
+                icon_name = _g_icon_get_string (presentable_icon);
+                gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), icon_name);
+                g_free (icon_name);
+                g_object_unref (presentable_icon);
+        }
+
+        /*  window title  */
+        s = g_strdup_printf (_("Format Volume '%s'"), name);
+        gtk_window_set_title (GTK_WINDOW (priv->dialog), s);
+        g_free (s);
+
+        /*  title label  */
+        title = g_strconcat ("<big><big><b>", _("Format Volume '%s'?"), "</b></big></big>", NULL);
+        s = g_strdup_printf (title, name);
+        gtk_label_set_markup (GTK_LABEL (priv->name_label), s);
+        g_free (s);
+        g_free (title);
+
+        s = g_strdup_printf (_("You are about to format the volume \"%s\" (%s). All existing data will be irrevocably erased. Make sure important data is backed up. This action cannot be undone."),
+                             name, gdu_device_get_device_file (device));
+        gtk_label_set_markup (GTK_LABEL (priv->details_label), s);
+        g_free (s);
+
+        /*  partition type combo  */
+        if (! priv->job_running) {
+                populate_type_combo (priv);
+        }
+        /*  Is device mounted?  */
+        update_ui_controls (priv);
+
+        if (device != NULL)
+                g_object_unref (device);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static void
+nautilus_gdu_destroy (FormatDialogPrivate  *priv)
+{
+        g_return_if_fail (priv != NULL);
+
+        /*  disconnect our handlers, since the presentable (resp. the pool) reference
+         *  counter doesn't really need to be zero
+         */
+        set_new_presentable (priv, NULL);
+        g_signal_handlers_disconnect_matched (priv->pool, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, priv);
+
+        /*  destroy the dialog and internal struct  */
+        gtk_widget_destroy (GTK_WIDGET (priv->dialog));
+        g_object_unref (priv->pool);
+        g_free (priv);
+
+        gtk_main_quit ();
+}
+
+static void
+presentable_removed (GduPresentable      *presentable,
+                     FormatDialogPrivate *priv)
+{
+        g_return_if_fail (priv != NULL);
+        g_warning ("Presentable removed event.");
+
+        nautilus_gdu_destroy (priv);
+}
+
+static void
+presentable_changed (GduPresentable      *presentable,
+                     FormatDialogPrivate *priv)
+{
+        g_return_if_fail (priv != NULL);
+        g_warning ("Presentable changed event.");
+
+        /*  TODO: shall we preserve label or any other settings?  */
+        update_ui (priv);
+}
+
+/*  we do ref presentable ourselves  */
+void
+select_new_presentable (FormatDialogPrivate *priv,
+                        GduPresentable      *presentable)
+{
+        /*  TODO: force refresh when no standalone mode ? */
+        /*  if (presentable != priv->presentable)  */
+        set_new_presentable (priv, presentable);
+}
+
+static void
+set_new_presentable (FormatDialogPrivate *priv,
+                     GduPresentable      *presentable)
+{
+        g_return_if_fail (priv != NULL);
+
+        if (priv->presentable) {
+                /*  first of all, disconnect handlers from the old presentable  */
+                g_signal_handlers_disconnect_matched (priv->presentable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, priv);
+                /*    g_debug ("before unreffing presentable, count = %d [%p]", ((GObject*)priv->presentable)->ref_count, priv->presentable);  */
+                g_object_unref (priv->presentable);
+                priv->presentable = NULL;
+        }
+
+        if (presentable) {
+                priv->presentable = g_object_ref (presentable);
+                /*    g_debug ("set_new_presentable: after reffing presentable, count = %d [%p]", ((GObject*)priv->presentable)->ref_count, priv->presentable);  */
+
+                /*  catch Presentable events  */
+                g_signal_connect (G_OBJECT (priv->presentable), "removed",
+                                  G_CALLBACK (presentable_removed), priv);
+                g_signal_connect (G_OBJECT (priv->presentable), "changed",
+                                  G_CALLBACK (presentable_changed), priv);
+        }
+}
+
+/* -------------------------------------------------------------------------- */
+static void
+spawn_palimpsest (FormatDialogPrivate *priv)
+{
+        gchar *argv[] = { DISK_MANAGEMENT_UTILITY, NULL, NULL };
+
+        GduDevice *device;
+
+        device = gdu_presentable_get_device (priv->presentable);
+        if (device) {
+                argv[1] = g_strdup_printf ("--%s=%s", GDU_IS_DRIVE (priv->presentable) ? "show-drive" : "show-volume", gdu_device_get_device_file (device));
+                g_object_unref (device);
+        }
+
+        g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
+        g_free (argv[1]);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void
+cancel_operation (FormatDialogPrivate *priv)
+{
+        GduDevice *device;
+
+        g_return_if_fail (priv != NULL);
+        g_return_if_fail (priv->job_running == TRUE);
+        /*  TODO: check for valid device  */
+        g_return_if_fail (priv->presentable != NULL);
+        g_warning ("Cancelling...");
+
+        priv->job_cancelled = TRUE;
+        device = gdu_presentable_get_device (priv->presentable);
+
+        g_return_if_fail (device != NULL);
+        gdu_device_op_cancel_job (device, NULL, NULL);
+        g_object_unref (device);
+}
+
+static gboolean
+window_delete_event (GtkWidget            *widget,
+                     GdkEvent             *event,
+                     FormatDialogPrivate  *priv)
+{
+        g_return_val_if_fail (priv != NULL, FALSE);
+
+        if (priv->job_running) {
+                cancel_operation (priv);
+                return TRUE;  /*  consume the event  */
+        }
+
+        return FALSE;
+}
+
+static void
+format_dialog_got_response (GtkDialog            *dialog,
+                            gint                  response_id,
+                            FormatDialogPrivate  *priv)
+{
+        if (response_id == GTK_RESPONSE_OK) {
+                do_format (priv);
+        }
+        else if (response_id == GTK_RESPONSE_ACCEPT) {
+                spawn_palimpsest (priv);
+                nautilus_gdu_destroy (priv);
+        }
+        else if (priv->job_running) {
+                cancel_operation (priv);
+        }
+        else {
+                /*  destroy the window and unref the presentable  */
+                nautilus_gdu_destroy (priv);
+        }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+static void
+set_default_volume_label (FormatDialogPrivate *priv)
+{
+        gchar *s;
+        GDate *date;
+
+        date = g_date_new ();
+        g_date_set_time_t (date, time (NULL));
+        s = g_strdup_printf (_("Data %d%.2d%.2d"), g_date_get_year (date), g_date_get_month (date), g_date_get_day (date));
+        gtk_entry_set_text (GTK_ENTRY (priv->label_entry), s);
+        g_free (s);
+        g_date_free (date);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void
+nautilus_gdu_spawn_dialog (GduPresentable *presentable)
+{
+        FormatDialogPrivate *priv;
+        GtkDialog *dialog;
+        GtkWidget *content_area;
+        GtkWidget *button;
+        GtkWidget *icon;
+        GtkWidget *label;
+        GtkWidget *align;
+        GtkWidget *vbox3;
+        GtkWidget *vbox2;
+        GtkWidget *hbox;
+        GtkWidget *image;
+        GtkWidget *table;
+        GtkWidget *entry;
+        GtkWidget *combo_box;
+        GtkWidget *progress_bar;
+        gint row;
+
+        g_return_if_fail (presentable != NULL);
+
+        priv = g_new0 (FormatDialogPrivate, 1);
+        priv->job_running = FALSE;
+        priv->pool = gdu_presentable_get_pool (presentable);
+
+        dialog = GTK_DIALOG (gtk_dialog_new ());
+        priv->dialog = dialog;
+
+        /*  HIG stuff...  */
+        gtk_dialog_set_has_separator (dialog, FALSE);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+        gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
+        gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+
+        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+        gtk_window_set_title (GTK_WINDOW (dialog), "");
+
+        gtk_dialog_add_buttons (dialog,
+                                _("_Format"), GTK_RESPONSE_OK,
+                                NULL);
+        priv->close_button = gtk_dialog_add_button (dialog, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+        button = gtk_dialog_add_button (dialog, _("Open Disk Utility"), GTK_RESPONSE_ACCEPT);
+        icon = gtk_image_new_from_icon_name ("palimpsest", GTK_ICON_SIZE_BUTTON);
+        gtk_button_set_image (GTK_BUTTON (button), icon);
+        gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (dialog)), button, TRUE);
+        gtk_widget_set_tooltip_text (button, _("Format volume using the Palimpsest Disk Utility"));
+        gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CLOSE);
+
+        content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+        gtk_container_set_border_width (GTK_CONTAINER (content_area), 10);
+
+
+        /*  headlines  */
+        priv->all_controls_box = gtk_vbox_new (FALSE, 0);
+        gtk_box_pack_start (GTK_BOX (content_area), priv->all_controls_box, FALSE, TRUE, 0);
+
+        hbox = gtk_hbox_new (FALSE, 0);
+        gtk_box_pack_start (GTK_BOX (priv->all_controls_box), hbox, TRUE, TRUE, 0);
+
+        image = gtk_image_new ();
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 5);
+        priv->icon_image = image;
+
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 5);
+        priv->name_label = label;
+
+        /*  partition  */
+        vbox3 = gtk_vbox_new (FALSE, 2);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 10, 30, 14, 10);
+        gtk_container_add (GTK_CONTAINER (align), vbox3);
+        gtk_box_pack_start (GTK_BOX (priv->all_controls_box), align, FALSE, TRUE, 0);
+
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        gtk_misc_set_padding (GTK_MISC (label), 10, 10);
+        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+        /*  gtk_label_set_width_chars (GTK_LABEL (label), 50);  */
+        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
+        priv->details_label = label;
+
+        vbox2 = gtk_vbox_new (FALSE, 5);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 24, 0);
+        gtk_container_add (GTK_CONTAINER (align), vbox2);
+        gtk_box_pack_start (GTK_BOX (vbox3), align, FALSE, TRUE, 0);
+        priv->controls_box = vbox2;
+
+        row = 0;
+
+        table = gtk_table_new (2, 2, FALSE);
+        gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+        /*  partition type  */
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Type:"));
+        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        combo_box = gtk_combo_box_new_text ();
+        gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, row, row +1,
+                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
+        priv->part_type_combo_box = combo_box;
+        row++;
+
+        /*  volume label  */
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Name:"));
+        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        entry = gtk_entry_new ();
+        gtk_table_attach (GTK_TABLE (table), entry, 1, 2, row, row + 1,
+                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+        priv->label_entry = entry;
+        row++;
+
+        /*  mounted warning box  */
+        hbox = gtk_hbox_new (FALSE, 7);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 15, 15, 20, 0);
+        gtk_container_add (GTK_CONTAINER (align), hbox);
+        gtk_box_pack_start (GTK_BOX (priv->all_controls_box), align, FALSE, TRUE, 0);
+        priv->mount_warning = align;
+        image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_LARGE_TOOLBAR);
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
+        label = gtk_label_new (_("The volume is currently mounted. Please make sure to close all open files before formatting."));
+        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 (hbox), label, FALSE, TRUE, 0);
+        gtk_widget_show_all (priv->mount_warning);
+        gtk_widget_hide (priv->mount_warning);
+        gtk_widget_set_no_show_all (priv->mount_warning, TRUE);
+
+        /*  readonly info box  */
+        hbox = gtk_hbox_new (FALSE, 7);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 10, 10, 20, 0);
+        gtk_container_add (GTK_CONTAINER (align), hbox);
+        gtk_box_pack_start (GTK_BOX (priv->all_controls_box), align, FALSE, TRUE, 0);
+        priv->readonly_warning = align;
+        image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_LARGE_TOOLBAR);
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
+        label = gtk_label_new (_("Device is read only"));
+        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 (hbox), label, FALSE, TRUE, 0);
+        gtk_widget_show_all (priv->readonly_warning);
+        gtk_widget_hide (priv->readonly_warning);
+        gtk_widget_set_no_show_all (priv->readonly_warning, TRUE);
+
+        /*  no media info box  */
+        hbox = gtk_hbox_new (FALSE, 7);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 10, 10, 20, 0);
+        gtk_container_add (GTK_CONTAINER (align), hbox);
+        gtk_box_pack_start (GTK_BOX (priv->all_controls_box), align, FALSE, TRUE, 0);
+        priv->no_media_warning = align;
+        image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_LARGE_TOOLBAR);
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
+        label = gtk_label_new (_("No media in drive"));
+        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 (hbox), label, FALSE, TRUE, 0);
+        gtk_widget_show_all (priv->no_media_warning);
+        gtk_widget_hide (priv->no_media_warning);
+        gtk_widget_set_no_show_all (priv->no_media_warning, TRUE);
+
+        /*  progress bar  */
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 75, 75, 30, 30);
+        priv->progress_bar_box = align;
+
+        progress_bar = gtk_progress_bar_new ();
+        gtk_widget_set_size_request (progress_bar, 375, -1);   /*  TODO: this is an ugly hack  */
+        priv->progress_bar = progress_bar;
+        gtk_container_add (GTK_CONTAINER (align), progress_bar);
+        gtk_box_pack_start (GTK_BOX (content_area), align, TRUE, FALSE, 0);
+        gtk_widget_show_all (priv->progress_bar_box);
+        gtk_widget_hide (priv->progress_bar_box);
+        gtk_widget_set_no_show_all (priv->progress_bar_box, TRUE);
+
+
+        g_signal_connect (priv->dialog, "delete-event",
+                          G_CALLBACK (window_delete_event), priv);
+        g_signal_connect (priv->part_type_combo_box, "changed",
+                          G_CALLBACK (type_combo_box_changed), priv);
+        /*  update sensivity and length of fs label + entry  */
+        g_signal_connect (G_OBJECT (dialog), "response",
+                          G_CALLBACK (format_dialog_got_response), priv);
+
+        gtk_widget_show_all (GTK_WIDGET (dialog));
+        gtk_widget_grab_focus (priv->close_button);
+        set_new_presentable (priv, presentable);
+        update_ui (priv);
+        update_ui_progress (priv, NULL, FALSE);
+        set_default_volume_label (priv);
+}
diff --git a/src/format-tool/format-window.h b/src/format-tool/format-window.h
new file mode 100644
index 0000000..c9d7421
--- /dev/null
+++ b/src/format-tool/format-window.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  format-window.h
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#ifndef FORMAT_WINDOW_H
+#define FORMAT_WINDOW_H
+
+#include <gtk/gtk.h>
+#include <gdu/gdu.h>
+#include <polkit-gnome/polkit-gnome.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+        GtkDialog *dialog;
+        GtkWidget *close_button;
+        GtkWidget *icon_image;
+        GtkWidget *name_label;
+        GtkWidget *details_label;
+        GtkWidget *mount_warning;
+        GtkWidget *readonly_warning;
+        GtkWidget *no_media_warning;
+        GtkWidget *label_entry;
+        GtkWidget *part_type_combo_box;
+        GtkWidget *progress_bar;
+        GtkWidget *progress_bar_box;
+        GtkWidget *controls_box;
+        GtkWidget *all_controls_box;
+
+        GduPresentable *presentable;
+        GduPool *pool;
+
+        gboolean job_running;
+        gboolean job_cancelled;
+} FormatDialogPrivate;
+
+
+typedef struct
+{
+        const char *fstype;
+        gboolean encrypted;
+        char *title;
+} FormatComboBoxItem;
+
+
+static FormatComboBoxItem filesystem_combo_items[] =
+        {
+                {"vfat", FALSE, "Compatible with all systems (FAT)"},
+                {"ext2", FALSE, "Compatible with Linux systems, no journal (ext2)"},
+                {"ext3", FALSE, "Compatible with Linux systems (ext3)"},
+                {"ext3", TRUE, "Encrypted, compatible with Linux systems (LUKS)"}
+        };
+
+
+/*  pass presentable=NULL and standalone_mode=TRUE to display volume selector */
+/*  we do ref presentable ourselves */
+void  nautilus_gdu_spawn_dialog  (GduPresentable      *presentable);
+
+/*  update sensitivity of main controls, action buttons etc.  */
+void  update_ui_controls         (FormatDialogPrivate *priv);
+
+/*  we do ref presentable ourselves  */
+void  select_new_presentable     (FormatDialogPrivate *priv,
+                                  GduPresentable      *presentable);
+
+G_END_DECLS
+
+#endif  /* FORMAT_WINDOW_H */
+
diff --git a/src/format-tool/gdu-format-tool.c b/src/format-tool/gdu-format-tool.c
new file mode 100644
index 0000000..796d9f4
--- /dev/null
+++ b/src/format-tool/gdu-format-tool.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  gnome-disk-utility-format.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gthread.h>
+#include <gio/gio.h>
+#include <gdu/gdu.h>
+#include <gtk/gtk.h>
+
+#include "gdu-utils.h"
+#include "format-window.h"
+
+
+
+static gchar *_mount = NULL;
+static gchar *_device = NULL;
+
+
+static gboolean
+setup_window ()
+{
+        GduPresentable *presentable = NULL;
+
+        if (_mount != NULL)
+                presentable = find_presentable_from_mount_path (_mount);
+        if (_device != NULL && presentable == NULL)
+                presentable = find_presentable_from_device_path (_device);
+
+        if (! presentable)
+                return FALSE;
+
+        nautilus_gdu_spawn_dialog (presentable);
+        g_object_unref (presentable);
+
+        return TRUE;
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+        static GOptionEntry entries[] =
+                {
+                        { "mount", 'm', 0, G_OPTION_ARG_STRING, &_mount, N_("Find volume by mount"), NULL },
+                        { NULL }
+                };
+
+        GError *error = NULL;
+
+        g_thread_init (NULL);
+
+        /* Initialize gettext support */
+        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+        textdomain (GETTEXT_PACKAGE);
+
+        /*  Initialize gtk  */
+        if (! gtk_init_with_args (&argc, &argv, "[device_file]", entries, GETTEXT_PACKAGE, &error)) {
+                g_printerr ("Could not parse arguments: %s\n", error->message);
+                g_error_free (error);
+                return 1;
+        }
+
+        /*  Get the device parameter  */
+        if (argc > 0 && argv[1])
+                _device = g_strdup (argv[1]);
+
+        if (! setup_window ()) {
+                g_printerr ("Could not find presentable\n");
+                return 1;
+        }
+
+        g_set_prgname ("gnome-disk-utility-format");
+        g_set_application_name (_("Gnome Disk Formatter"));
+
+        /*  Run the application  */
+        gtk_main ();
+
+        return 0;
+}
diff --git a/src/format-tool/gdu-utils.c b/src/format-tool/gdu-utils.c
new file mode 100644
index 0000000..ce9d375
--- /dev/null
+++ b/src/format-tool/gdu-utils.c
@@ -0,0 +1,148 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*  gdu-utils.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gdu/gdu.h>
+#include <gtk/gtk.h>
+
+#include "gdu-utils.h"
+
+
+GduPresentable *
+find_presentable_from_mount_path (const gchar *mount_path)
+{
+        GduPool *pool;
+        GList *devices, *l;
+        GduPresentable *presentable = NULL;
+        GduDevice *device;
+        const gchar *device_mount;
+        GFile *file1, *file2;
+
+        g_return_val_if_fail (mount_path != NULL, NULL);
+        g_return_val_if_fail (strlen (mount_path) > 1, NULL);
+
+        pool = gdu_pool_new ();
+        devices = gdu_pool_get_devices (pool);
+
+        for (l = devices; l != NULL; l = l->next) {
+                device = GDU_DEVICE (l->data);
+                device_mount = gdu_device_get_mount_path (device);
+
+                if (mount_path && device_mount && strlen (device_mount) > 1) {
+                        /*  compare via GFile routines  */
+                        file1 = g_file_new_for_commandline_arg (mount_path);
+                        file2 = g_file_new_for_path (device_mount);
+                        if (g_file_equal (file1, file2))
+                                presentable = gdu_pool_get_volume_by_device (pool, device);   /*  auto-ref here  */
+                        g_object_unref (file1);
+                        g_object_unref (file2);
+                        if (presentable)
+                                break;
+                }
+        }
+
+        g_list_foreach (devices, (GFunc) g_object_unref, NULL);
+        g_list_free (devices);
+        g_object_unref (pool);
+
+        return presentable;
+}
+
+GduPresentable *
+find_presentable_from_device_path (const gchar *device_path)
+{
+        GduPool *pool;
+        GduDevice *device;
+        GduPresentable *presentable = NULL;
+
+        g_return_val_if_fail (device_path != NULL, NULL);
+        g_return_val_if_fail (strlen (device_path) > 1, NULL);
+
+        pool = gdu_pool_new ();
+        device = gdu_pool_get_by_device_file (pool, device_path);
+        if (device) {
+                presentable = gdu_pool_get_volume_by_device (pool, device);
+                g_object_unref (device);
+        }
+        g_object_unref (pool);
+
+        return presentable;
+}
+
+
+gchar *
+_g_icon_get_string (GIcon *icon)
+{
+        const gchar *icon_text = NULL;
+        const gchar * const *icon_names;
+
+        if (! icon)
+                return NULL;
+
+        if (G_IS_THEMED_ICON (icon)) {
+                icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+                while (icon_text == NULL && icon_names != NULL && *icon_names != NULL) {
+                        if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), *icon_names))
+                                icon_text = *icon_names;
+                        icon_names++;
+                }
+        }
+
+        return g_strdup (icon_text);
+}
+
+gboolean
+is_active_luks (GduPool *pool, GduPresentable *presentable)
+{
+        gboolean res;
+        GduDevice *device;
+
+        res = FALSE;
+        device = gdu_presentable_get_device (presentable);
+
+        if (GDU_IS_VOLUME (presentable) && device && strcmp (gdu_device_id_get_usage (device), "crypto") == 0) {
+                GList *enclosed_presentables;
+                enclosed_presentables = gdu_pool_get_enclosed_presentables (pool, presentable);
+                res = (enclosed_presentables != NULL) && (g_list_length (enclosed_presentables) == 1);
+                g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
+                g_list_free (enclosed_presentables);
+                g_object_unref (device);
+        }
+
+        return res;
+}
+
+const gchar *
+trim_dk_error (const gchar *message)
+{
+        const gchar *text, *p;
+
+        if (g_str_has_prefix (message, "org.freedesktop.DeviceKit"))
+                text = (p = strchr (message, ':')) ? p + 1 : message;
+        else
+                text = message;
+
+        return text;
+}
diff --git a/src/format-tool/gdu-utils.h b/src/format-tool/gdu-utils.h
new file mode 100644
index 0000000..80d1bba
--- /dev/null
+++ b/src/format-tool/gdu-utils.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-utils.h
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ */
+
+#ifndef __GDU_UTILS_H
+#define __GDU_UTILS_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gdu/gdu.h>
+
+G_BEGIN_DECLS
+
+/*  caller must unref the returned object  */
+GduPresentable *  find_presentable_from_mount_path (const gchar *mount_path);
+
+/*  caller must unref the returned object  */
+GduPresentable *  find_presentable_from_device_path (const gchar *device_path);
+
+gchar *           _g_icon_get_string (GIcon *icon);
+
+gboolean          is_active_luks (GduPool        *pool,
+                                  GduPresentable *presentable);
+
+const gchar *     trim_dk_error (const gchar *message);
+
+G_END_DECLS
+
+#endif  /* __GDU_UTILS_H */
+
diff --git a/src/nautilus-extension/Makefile.am b/src/nautilus-extension/Makefile.am
new file mode 100644
index 0000000..ce47ae7
--- /dev/null
+++ b/src/nautilus-extension/Makefile.am
@@ -0,0 +1,51 @@
+NULL =
+
+INCLUDES =						\
+	-DDATADIR=\"$(datadir)\"			\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"	\
+	-DLIBEXECDIR=\"$(libexecdir)\"			\
+	-I$(top_srcdir)/src				\
+	-I$(top_builddir)/src				\
+	$(WARN_CFLAGS)					\
+	$(AM_CFLAGS)					\
+	-DGDU_API_IS_SUBJECT_TO_CHANGE			\
+	-DGDU_GTK_API_IS_SUBJECT_TO_CHANGE		\
+	$(NULL)
+
+CORE_CFLAGS = 						\
+	$(GLIB2_CFLAGS)					\
+	$(GOBJECT2_CFLAGS)				\
+	$(GIO2_CFLAGS)					\
+	$(GIO_UNIX2_CFLAGS)				\
+	$(GTHREAD2_CFLAGS)				\
+	$(POLKIT_DBUS_CFLAGS)				\
+	$(GTK2_CFLAGS)					\
+	$(POLKIT_GNOME_CFLAGS)				\
+	$(NULL)
+
+CORE_LIBADD = 						\
+	$(GLIB2_LIBS)					\
+	$(GOBJECT2_LIBS)				\
+	$(GIO2_LIBS)					\
+	$(GIO_UNIX2_LIBS)				\
+	$(GTHREAD2_LIBS)				\
+	$(POLKIT_DBUS_LIBS)				\
+	$(GTK2_LIBS)					\
+	$(POLKIT_GNOME_LIBS)				\
+	$(INTLLIBS)					\
+	$(top_builddir)/src/gdu/libgdu.la		\
+	$(top_builddir)/src/gdu-gtk/libgdu-gtk.la	\
+	$(NULL)
+
+
+nautilus_extensiondir = $(NAUTILUS_EXTENSION_DIR)
+nautilus_extension_LTLIBRARIES = libnautilus-gdu.la
+
+libnautilus_gdu_la_SOURCES =			\
+	nautilus-module.c			\
+	nautilus-gdu.c				\
+	nautilus-gdu.h				\
+	$(NULL)
+libnautilus_gdu_la_CPPFLAGS = $(CORE_CFLAGS) $(NAUTILUS_CFLAGS) -DG_LOG_DOMAIN=\"Nautilus-GDU\"
+libnautilus_gdu_la_LDFLAGS = $(AM_LDFLAGS) -export_dynamic -module -avoid-version -no-undefined
+libnautilus_gdu_la_LIBADD  = $(CORE_LIBADD) $(NAUTILUS_LIBS)
diff --git a/src/nautilus-extension/nautilus-gdu.c b/src/nautilus-extension/nautilus-gdu.c
new file mode 100644
index 0000000..72e2332
--- /dev/null
+++ b/src/nautilus-extension/nautilus-gdu.c
@@ -0,0 +1,301 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  nautilus-gdu.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include "nautilus-gdu.h"
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include "gdu/gdu.h"
+
+
+
+static void nautilus_gdu_instance_init (NautilusGdu      *gdu);
+static void nautilus_gdu_class_init    (NautilusGduClass *klass);
+
+
+static GType nautilus_gdu_type = 0;
+
+
+#define DISK_FORMAT_UTILITY  "gdu-format-tool"
+
+/*  TODO: push upstream  */
+#define G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE   "mountable::unix-device-file"
+
+
+/*  test if we're able to correctly find presentable from a device file  */
+static gboolean
+test_proper_device (gchar *device_file)
+{
+        GduPool *pool;
+        GduDevice *device;
+        GduPresentable *presentable = NULL;
+        gboolean res = FALSE;
+
+        if (device_file == NULL || strlen (device_file) <= 1)
+                return FALSE;
+
+        pool = gdu_pool_new ();
+        device = gdu_pool_get_by_device_file (pool, device_file);
+        if (device) {
+                presentable = gdu_pool_get_volume_by_device (pool, device);
+                if (presentable) {
+                        res = TRUE;
+                        g_object_unref (presentable);
+                }
+                g_object_unref (device);
+        }
+        g_object_unref (pool);
+
+        return res;
+}
+
+static gchar *
+find_device_from_nautilus_file (NautilusFileInfo *nautilus_file)
+{
+        GFile *file;
+        GFileInfo *info;
+        GError *error;
+        GFileType file_type;
+        GMount *mount;
+        GVolume *volume;
+        gchar *device_file = NULL;
+
+        g_return_val_if_fail (nautilus_file != NULL, NULL);
+        file = nautilus_file_info_get_location (nautilus_file);
+        g_return_val_if_fail (file != NULL, NULL);
+        file_type = nautilus_file_info_get_file_type (nautilus_file);
+
+        /* first try to find mount target from a mountable  */
+        if (file_type == G_FILE_TYPE_MOUNTABLE ||
+            file_type == G_FILE_TYPE_SHORTCUT) {
+                /* get a mount if exists and extract device file from it  */
+                mount = nautilus_file_info_get_mount (nautilus_file);
+                if (mount) {
+                        volume = g_mount_get_volume (mount);
+                        if (volume) {
+                                device_file = g_volume_get_identifier (volume,
+                                                                       G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
+                                g_object_unref (volume);
+                        }
+                        g_object_unref (mount);
+                }
+
+                /* not mounted, assuming we've been spawned from computer://  */
+                if (device_file == NULL) {
+                        error = NULL;
+                        /* retrieve DeviceKit device ID for non-mounted devices  */
+                        info = g_file_query_info (file, G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE, G_FILE_QUERY_INFO_NONE, NULL, &error);
+                        if (info) {
+                                device_file = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE);
+                                g_object_unref (info);
+                        }
+                        if (error) {
+                                g_warning ("unable to query info: %s\n", error->message);
+                                g_error_free (error);
+                        }
+                 }
+        }
+
+        if (! test_proper_device (device_file)) {
+                g_free (device_file);
+                device_file = NULL;
+        }
+
+        return device_file;
+}
+
+static void
+open_format_utility (NautilusMenuItem *item)
+{
+  gchar *argv[] = { NULL, NULL, NULL };
+  gchar *device_file;
+  GError *error = NULL;
+
+  device_file = g_object_get_data (G_OBJECT (item), "device_file");
+
+  argv[0] = g_build_filename (LIBEXECDIR, DISK_FORMAT_UTILITY, NULL);
+  argv[1] = g_strdup (device_file);
+
+  g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
+  if (error) {
+    g_warning ("%s", error->message);
+    g_error_free (error);
+  }
+
+  g_free (argv[0]);
+  g_free (argv[1]);
+}
+
+static void
+unmount_done (GObject      *object,
+              GAsyncResult *res,
+              gpointer      user_data)
+{
+  NautilusMenuItem *item = user_data;
+  GError *error = NULL;
+
+  if (g_mount_unmount_finish (G_MOUNT (object), res, &error))
+    open_format_utility (item);
+  else
+    {
+      GtkWidget *dialog;
+      gchar *name, *p, *text;
+
+      name = g_mount_get_name (G_MOUNT (object));
+      dialog = gtk_message_dialog_new (NULL, 0,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_OK,
+                                       _("Could not unmount '%s'"), name);
+      if (g_str_has_prefix (error->message, "org.freedesktop.DeviceKit"))
+        {
+          p = strchr (error->message, ':');
+          if (p)
+            text = p + 1;
+          else
+            text = error->message;
+        }
+      else
+        text = error->message;
+
+      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                "%s", text);
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      g_error_free (error);
+      g_free (name);
+    }
+}
+
+static void
+format_callback (NautilusMenuItem *item,
+                 gpointer user_data)
+{
+  NautilusFileInfo *nautilus_file;
+  GMount *mount;
+
+  nautilus_file = g_object_get_data (G_OBJECT (item), "nautilus_file");
+  mount = nautilus_file_info_get_mount (nautilus_file);
+  if (mount)
+    {
+      g_mount_unmount (mount, G_MOUNT_UNMOUNT_NONE, NULL, unmount_done, item);
+      g_object_unref (mount);
+    }
+  else
+    open_format_utility (item);
+}
+
+static GList *
+nautilus_gdu_get_file_items (NautilusMenuProvider *provider,
+			     GtkWidget            *window,
+			     GList                *files)
+{
+  NautilusMenuItem *item;
+  NautilusFileInfo *nautilus_file;
+  gchar *device_file;
+  GList *items = NULL;
+
+  if (g_list_length (files) != 1) {
+    goto out;
+  }
+
+  nautilus_file = (NautilusFileInfo*)files->data;
+  device_file = find_device_from_nautilus_file (nautilus_file);
+  if (! device_file)
+    goto out;
+
+  item = nautilus_menu_item_new ("NautilusGdu::format",
+                                 _("_Format..."),
+                                 _("Create new filesystem on the selected device"),
+                                 "nautilus-gdu");
+  g_object_set_data_full (G_OBJECT (item), "device_file",
+                          device_file,
+                          (GDestroyNotify) g_free);
+  g_object_set_data_full (G_OBJECT (item), "nautilus_file",
+                          g_object_ref (nautilus_file),
+                          (GDestroyNotify) g_object_unref);
+  g_signal_connect (item, "activate",
+                    G_CALLBACK (format_callback),
+                    NULL);
+
+  items = g_list_append (NULL, item);
+
+out:
+  return items;
+}
+
+static void
+nautilus_gdu_menu_provider_iface_init (NautilusMenuProviderIface *iface)
+{
+  iface->get_file_items = nautilus_gdu_get_file_items;
+}
+
+static void
+nautilus_gdu_instance_init (NautilusGdu *gdu)
+{
+}
+
+static void
+nautilus_gdu_class_init (NautilusGduClass *klass)
+{
+}
+
+GType
+nautilus_gdu_get_type (void)
+{
+  return nautilus_gdu_type;
+}
+
+void
+nautilus_gdu_register_type (GTypeModule *module)
+{
+  const GTypeInfo info = {
+    sizeof (NautilusGduClass),
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) nautilus_gdu_class_init,
+    NULL,
+    NULL,
+    sizeof (NautilusGdu),
+    0,
+    (GInstanceInitFunc) nautilus_gdu_instance_init,
+  };
+
+  const GInterfaceInfo menu_provider_iface_info = {
+    (GInterfaceInitFunc) nautilus_gdu_menu_provider_iface_init,
+    NULL,
+    NULL
+  };
+
+  nautilus_gdu_type = g_type_module_register_type (module,
+                                                   G_TYPE_OBJECT,
+                                                   "NautilusGdu",
+                                                   &info, 0);
+
+  g_type_module_add_interface (module,
+                               nautilus_gdu_type,
+                               NAUTILUS_TYPE_MENU_PROVIDER,
+                               &menu_provider_iface_info);
+}
+
diff --git a/src/nautilus-extension/nautilus-gdu.h b/src/nautilus-extension/nautilus-gdu.h
new file mode 100644
index 0000000..0664887
--- /dev/null
+++ b/src/nautilus-extension/nautilus-gdu.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  nautilus-gdu.h
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#ifndef NAUTILUS_GDU_H
+#define NAUTILUS_GDU_H
+
+#include <glib-object.h>
+#include <libnautilus-extension/nautilus-menu-provider.h>
+#include <gdu/gdu.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_GDU	  (nautilus_gdu_get_type ())
+#define NAUTILUS_GDU(o)		  (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_GDU, NautilusGdu))
+#define NAUTILUS_IS_GDU(o)	  (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAUTILUS_TYPE_GDU))
+
+typedef struct _NautilusGdu      NautilusGdu;
+typedef struct _NautilusGduClass NautilusGduClass;
+
+struct _NautilusGdu
+{
+	GObject parent;
+};
+
+struct _NautilusGduClass
+{
+	GObjectClass parent_class;
+};
+
+GType nautilus_gdu_get_type      (void) G_GNUC_CONST;
+void  nautilus_gdu_register_type (GTypeModule *module);
+
+G_END_DECLS
+
+#endif  /* NAUTILUS_GDU_H */
+
diff --git a/src/nautilus-extension/nautilus-module.c b/src/nautilus-extension/nautilus-module.c
new file mode 100644
index 0000000..23f869b
--- /dev/null
+++ b/src/nautilus-extension/nautilus-module.c
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  nautilus-module.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library 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 library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include "nautilus-gdu.h"
+
+#include <libintl.h>
+
+static GType type_list[1];
+
+void
+nautilus_module_initialize (GTypeModule *module)
+{
+  g_print ("Initializing nautilus-gdu extension\n");
+
+  nautilus_gdu_register_type (module);
+  type_list[0] = NAUTILUS_TYPE_GDU;
+
+  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+}
+
+void
+nautilus_module_shutdown (void)
+{
+  g_print ("Shutting down nautilus-gdu extension\n");
+}
+
+void
+nautilus_module_list_types (const GType **types,
+			    int          *num_types)
+{
+  *types = type_list;
+  *num_types = G_N_ELEMENTS (type_list);
+}
+



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