diff --git a/configure.ac b/configure.ac
index 01a29c3..07ce6ad 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/gdu-format-tool/Makefile
+src/gdu-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/data/icons/scalable/nautilus-gdu.svg b/data/icons/scalable/nautilus-gdu.svg
new file mode 100644
index 0000000..f9d9274
--- /dev/null
+++ b/data/icons/scalable/nautilus-gdu.svg
@@ -0,0 +1,654 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg1306"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/lapo/Icone/cvs/gnome-icon-theme/scalable/devices"
+   sodipodi:docname="nautilus-gdu.svg"
+   inkscape:export-filename="/home/jimmac/Desktop/drive-optical.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs1308">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3401">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3403" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3405" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3327">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3329" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3331" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3298">
+      <stop
+         style="stop-color:#b87b74;stop-opacity:1;"
+         offset="0"
+         id="stop3300" />
+      <stop
+         style="stop-color:#d09993;stop-opacity:1;"
+         offset="1"
+         id="stop3302" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3290">
+      <stop
+         style="stop-color:#dda0a0;stop-opacity:1;"
+         offset="0"
+         id="stop3292" />
+      <stop
+         style="stop-color:#f2c6c3;stop-opacity:1;"
+         offset="1"
+         id="stop3294" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 24 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="48 : 24 : 1"
+       inkscape:persp3d-origin="24 : 16 : 1"
+       id="perspective69" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3725">
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0"
+         id="stop3727" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:0;"
+         offset="1"
+         id="stop3729" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3709">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop3711" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop3713" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2809">
+      <stop
+         style="stop-color:#d3d7cf;stop-opacity:1;"
+         offset="0"
+         id="stop2811" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:0;"
+         offset="1"
+         id="stop2813" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3763">
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="0"
+         id="stop3765" />
+      <stop
+         style="stop-color:#babdb6;stop-opacity:1"
+         offset="1"
+         id="stop3767" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3942">
+      <stop
+         id="stop3944"
+         offset="0"
+         style="stop-color:#888a85;stop-opacity:1" />
+      <stop
+         id="stop3946"
+         offset="1"
+         style="stop-color:#eeeeec;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3877">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop3879" />
+      <stop
+         style="stop-color:white;stop-opacity:0.77319586;"
+         offset="1"
+         id="stop3881" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3859">
+      <stop
+         id="stop3861"
+         offset="0"
+         style="stop-color:#d3d7cf;stop-opacity:1" />
+      <stop
+         id="stop3037"
+         offset="0.30973485"
+         style="stop-color:#eeeeec;stop-opacity:1;" />
+      <stop
+         style="stop-color:white;stop-opacity:1;"
+         offset="0.88648254"
+         id="stop3039" />
+      <stop
+         id="stop3863"
+         offset="1"
+         style="stop-color:#d3d7cf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5060">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop5062" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5064" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="0"
+         id="stop5050" />
+      <stop
+         id="stop5056"
+         offset="0.5"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5052" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3859"
+       id="linearGradient2899"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.169513,0,0,1.866794,-4.088508,-1.190714)"
+       x1="39.846634"
+       y1="17.288595"
+       x2="9.0151443"
+       y2="17.469774" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3942"
+       id="linearGradient2925"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.168352,0,0,0.940121,-5.224048,8.010627)"
+       x1="31.259865"
+       y1="28.921469"
+       x2="31.259865"
+       y2="30.105555" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3877"
+       id="linearGradient3883"
+       x1="75"
+       y1="56.9375"
+       x2="75"
+       y2="63.920155"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.196864,0,0,1.232642,-76.53167,-35.470266)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5048"
+       id="linearGradient3903"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
+       x1="302.85715"
+       y1="366.64789"
+       x2="302.85715"
+       y2="609.50507" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient3905"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient3907"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3763"
+       id="linearGradient3769"
+       x1="36.05172"
+       y1="34.193111"
+       x2="35.23922"
+       y2="32.023624"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(1,6.302554)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2809"
+       id="linearGradient2815"
+       x1="22.777416"
+       y1="32.072342"
+       x2="22.777416"
+       y2="34.00016"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.166667,0,1.635887)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3709"
+       id="linearGradient3715"
+       x1="19.5625"
+       y1="31.8125"
+       x2="19.5625"
+       y2="33.65863"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.333333,0,-4.030776)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3725"
+       id="linearGradient3731"
+       x1="29.521708"
+       y1="32.023651"
+       x2="29.521708"
+       y2="33.553349"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.333333,0,-4.030776)" />
+    <inkscape:perspective
+       id="perspective2506"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3290"
+       id="linearGradient3343"
+       gradientUnits="userSpaceOnUse"
+       x1="14.714939"
+       y1="11.929246"
+       x2="3.7296934"
+       y2="-3.3674014" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3298"
+       id="linearGradient3345"
+       gradientUnits="userSpaceOnUse"
+       x1="18.560616"
+       y1="17.419044"
+       x2="3.7296934"
+       y2="-3.3674014" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3327"
+       id="linearGradient3347"
+       gradientUnits="userSpaceOnUse"
+       x1="4.1692066"
+       y1="9.2838445"
+       x2="16.702452"
+       y2="9.6172552" />
+    <filter
+       inkscape:collect="always"
+       id="filter3387"
+       x="-0.12384643"
+       width="1.2476929"
+       y="-1.1513131"
+       height="3.3026262">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.2214324"
+         id="feGaussianBlur3389" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter3397"
+       x="-0.14896551"
+       width="1.297931"
+       y="-0.61714285"
+       height="2.2342857">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="1.3579567"
+         id="feGaussianBlur3399" />
+    </filter>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3401"
+       id="radialGradient3409"
+       cx="24.809027"
+       cy="28.027508"
+       fx="24.809027"
+       fy="28.027508"
+       r="10.939096"
+       gradientTransform="matrix(1.7672414,1.8247677e-8,1.3228305e-2,0.2413793,-20.732959,21.262244)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#c5c5c5"
+     borderopacity="1"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="10.604167"
+     inkscape:cx="24.011432"
+     inkscape:cy="23.042829"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="false"
+     inkscape:document-units="px"
+     stroke="#888a85"
+     fill="#babdb6"
+     inkscape:window-width="1021"
+     inkscape:window-height="921"
+     inkscape:window-x="8"
+     inkscape:window-y="48"
+     inkscape:showpageshadow="false"
+     inkscape:guide-points="false"
+     inkscape:object-points="false"
+     inkscape:object-paths="false"
+     inkscape:guide-bbox="true"
+     inkscape:grid-points="true"
+     showguides="false"
+     showborder="true"
+     inkscape:object-bbox="true">
+    <sodipodi:guide
+       orientation="horizontal"
+       position="2.8125"
+       id="guide2906" />
+    <inkscape:grid
+       id="GridFromPre046Settings"
+       type="xygrid"
+       originx="0px"
+       originy="0px"
+       spacingx="0.5px"
+       spacingy="0.5px"
+       color="#0000ff"
+       empcolor="#0000ff"
+       opacity="0.2"
+       empopacity="0.4"
+       empspacing="2"
+       visible="true"
+       enabled="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata1311">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Drive Removable Media</dc:title>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Lapo Calamandrei</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:description />
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+        <dc:source>http://www.gnome.org</dc:source>
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <dc:date>2006</dc:date>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>drive</rdf:li>
+            <rdf:li>removable</rdf:li>
+            <rdf:li>media</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/SourceCode" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       transform="matrix(2.364027e-2,0,0,3.669526e-2,45.52649,35.838964)"
+       id="g3895">
+      <rect
+         style="opacity:0.40206185;fill:url(#linearGradient3903);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect3897"
+         width="1339.6335"
+         height="478.35718"
+         x="-1559.2523"
+         y="-150.69685" />
+      <path
+         style="opacity:0.40206185;fill:url(#radialGradient3905);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+         id="path3899"
+         sodipodi:nodetypes="cccc" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path3901"
+         d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+         style="opacity:0.40206185;fill:url(#radialGradient3907);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    </g>
+    <path
+       style="fill:url(#linearGradient2899);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.06704879px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+       d="M 12.84375,12.833804 C 10.231846,12.833804 8.4897001,14.631543 7.53125,17.646304 C 7.5312501,17.646304 3.78125,34.708804 3.78125,34.708804 C 3.5381132,35.724742 3.5313229,36.768898 3.5,37.802554 C 3.5,41.674825 6.6277285,44.802555 10.5,44.802554 L 38.5,44.802554 C 42.372271,44.802554 45.500001,41.674825 45.5,37.802554 C 45.4683,36.409288 45.393092,35.083645 45.09375,33.708804 L 40.8125,17.333804 C 39.878744,14.75622 38.12813,12.833804 35.625,12.833804 L 12.84375,12.833804 z"
+       id="path2897"
+       sodipodi:nodetypes="cccsccscccc" />
+    <path
+       style="opacity:0.4;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999964px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 39.663187,30.513594 L 36.556647,14.857025"
+       id="path3925"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.7;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 12.815683,13.935064 C 10.75685,13.935064 9.4360576,15.17301 8.6847245,17.738917 C 8.6847245,17.738917 5.0003906,34.805701 5.0003906,34.805701 C 4.5061245,37.745358 5.9863446,42.434902 10.636644,43.499009 L 38.372114,43.499009 C 43.735507,43.29398 45.340775,38.51259 44.122253,34.429947 C 44.122253,34.429947 39.790203,17.95708 39.790203,17.95708 C 38.996151,15.517156 37.453588,13.813514 35.48279,13.813514 L 12.815683,13.935064 z"
+       id="path2960"
+       sodipodi:nodetypes="ccccccccc" />
+    <rect
+       style="opacity:1;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999911;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect2909"
+       width="39.993874"
+       height="11.979301"
+       x="4.5061245"
+       y="31.823252"
+       rx="5.8864155"
+       ry="5.9896455" />
+    <rect
+       ry="4.9305935"
+       rx="4.7874789"
+       y="32.802551"
+       x="5.5"
+       height="10"
+       width="38"
+       id="rect2898"
+       style="opacity:0.3;fill:#babdb6;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3883);stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <rect
+       style="fill:#babdb6;fill-opacity:1;stroke:url(#linearGradient3769);stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1949"
+       width="5.9999943"
+       height="1.999993"
+       x="34.560654"
+       y="38.830318"
+       rx="0.99999648"
+       ry="0.99999648" />
+    <rect
+       style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect1916"
+       width="31"
+       height="4"
+       x="9"
+       y="34.302551"
+       rx="1.09375"
+       ry="1.09375" />
+    <rect
+       style="opacity:0.8;fill:url(#linearGradient2815);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2807"
+       width="11"
+       height="7"
+       x="19"
+       y="34.302551"
+       rx="0"
+       ry="0" />
+    <rect
+       style="opacity:0.5;fill:url(#linearGradient3731);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect3704"
+       width="1"
+       height="4"
+       x="29"
+       y="37.302551" />
+    <rect
+       style="opacity:0.1;fill:url(#linearGradient3715);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect3706"
+       width="1"
+       height="4"
+       x="19"
+       y="37.302551" />
+    <path
+       style="fill:#babdb6;fill-opacity:1;stroke:url(#linearGradient2925);stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 10.125903,34.802572 L 38.874097,34.802572 C 39.220847,34.802572 39.5,35.027194 39.5,35.306209 L 39.5,36.292942 C 39.5,36.571957 39.220847,36.796579 38.874097,36.796579 L 30,36.796579 L 28.5,37.802554 L 20.5,37.802554 L 19,36.796579 L 10.125903,36.796579 C 9.7791528,36.796579 9.5,36.571957 9.5,36.292942 L 9.5,35.306209 C 9.5,35.027194 9.7791528,34.802572 10.125903,34.802572 z"
+       id="rect1951"
+       sodipodi:nodetypes="ccccccccccccc" />
+    <g
+       id="g1933"
+       transform="translate(-1,7.302554)">
+      <rect
+         ry="0.5"
+         rx="0.51535469"
+         y="32.532925"
+         x="9.5883884"
+         height="1"
+         width="3"
+         id="rect1965"
+         style="fill:#eeeeec;fill-opacity:1;stroke:#eeeeec;stroke-width:0.99999934;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         transform="matrix(1.678725,0,0,2.171835,-111.8336,-100.6562)"
+         d="M 73.078125,61.46875 A 0.484375,0.359375 0 1 1 72.109375,61.46875 A 0.484375,0.359375 0 1 1 73.078125,61.46875 z"
+         sodipodi:ry="0.359375"
+         sodipodi:rx="0.484375"
+         sodipodi:cy="61.46875"
+         sodipodi:cx="72.59375"
+         id="path3893"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         sodipodi:type="arc" />
+    </g>
+    <path
+       style="opacity:1;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999964px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 8.4628116,30.778759 L 11.677347,15.158801"
+       id="path3921"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.7;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.15657115px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 12.541942,30.645688 L 13.88327,14.713262"
+       id="path3923"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.4;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.15657115px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 36.467941,30.5573 L 34.357005,14.70882"
+       id="path3927"
+       sodipodi:nodetypes="cc" />
+    <rect
+       style="opacity:0.35;fill:url(#radialGradient3409);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3397)"
+       id="rect3391"
+       width="21.878193"
+       height="5.2809429"
+       x="14.994105"
+       y="25.387033"
+       rx="8"
+       ry="4.0244823"
+       transform="matrix(1,0,7.1428573e-2,1,-2.0019647,0)" />
+    <g
+       id="g3335"
+       transform="translate(24,0)">
+      <rect
+         ry="2.9556434"
+         transform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,0,0)"
+         y="-4.3152542"
+         x="3.6570795"
+         height="27.064833"
+         width="16.691551"
+         id="rect2518"
+         style="fill:url(#linearGradient3343);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3345);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         rx="2.9556434" />
+      <path
+         id="rect3306"
+         d="M -6.6875,12.59375 L -11.34375,17.25 C -12.127224,18.033474 -12.127224,19.279026 -11.34375,20.0625 L -3.1875,28.21875 C -2.4040257,29.002224 -1.1272243,29.002224 -0.34375,28.21875 L 4.3125,23.5625 L -6.6875,12.59375 z"
+         style="opacity:0.52314818;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="rect3311"
+         d="M 14.75,9.34375 L -3.84375,27.96875 L -3.15625,28.65625 C -2.3744277,29.440343 -1.0943223,29.440344 -0.3125,28.65625 L 15.4375,12.84375 C 16.219322,12.059657 16.219322,10.815343 15.4375,10.03125 L 14.75,9.34375 z"
+         style="opacity:0.41666667;fill:#b97d76;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path3323"
+         d="M 2.5,21.6875 L 14.78125,9.375 L 14.0625,8.625 L 1.75,20.9375 L 2.5,21.6875 z"
+         style="opacity:0.83796297;fill:#cc8b85;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="rect3318"
+         d="M 2.5,21.6875 L 1.75,20.9375 L -4.34375,27.03125 L -3.625,27.78125 L 2.5,21.6875 z"
+         style="opacity:0.5462963;fill:#cc8b85;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <rect
+         transform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,0,0)"
+         ry="2"
+         rx="2"
+         y="-3.2102599"
+         x="4.6308427"
+         height="24.988209"
+         width="15.410846"
+         id="rect3325"
+         style="opacity:0.45;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3347);stroke-width:0.92327225px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cc22fc4..4d19101 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -33,11 +33,15 @@ src/gdu/gdu-volume.c
 src/gdu/gdu-volume.h
 src/gdu/gdu-volume-hole.c
 src/gdu/gdu-volume-hole.h
+src/gdu-format-tool/format-window.c
+src/gdu-format-tool/format-window-operation.c
+src/gdu-format-tool/gdu-format-tool.c
 src/gdu-gtk/gdu-gtk.c
 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/gdu-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..fdf6b20 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 gdu-format-tool
+
+if ENABLE_NAUTILUS
+SUBDIRS += gdu-nautilus-extension
+endif
 
 clean-local :
 	rm -f *~
diff --git a/src/gdu-format-tool/Makefile.am b/src/gdu-format-tool/Makefile.am
new file mode 100644
index 0000000..752fa9d
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/TODO b/src/gdu-format-tool/TODO
new file mode 100644
index 0000000..742110a
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/format-window-operation.c b/src/gdu-format-tool/format-window-operation.c
new file mode 100644
index 0000000..7c50439
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/format-window-operation.h b/src/gdu-format-tool/format-window-operation.h
new file mode 100644
index 0000000..7463e57
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/format-window.c b/src/gdu-format-tool/format-window.c
new file mode 100644
index 0000000..f4c22b5
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/format-window.h b/src/gdu-format-tool/format-window.h
new file mode 100644
index 0000000..b8692c1
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/gdu-format-tool.c b/src/gdu-format-tool/gdu-format-tool.c
new file mode 100644
index 0000000..796d9f4
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/gdu-utils.c b/src/gdu-format-tool/gdu-utils.c
new file mode 100644
index 0000000..ce9d375
--- /dev/null
+++ b/src/gdu-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/gdu-format-tool/gdu-utils.h b/src/gdu-format-tool/gdu-utils.h
new file mode 100644
index 0000000..80d1bba
--- /dev/null
+++ b/src/gdu-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/gdu-nautilus-extension/Makefile.am b/src/gdu-nautilus-extension/Makefile.am
new file mode 100644
index 0000000..ce47ae7
--- /dev/null
+++ b/src/gdu-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/gdu-nautilus-extension/nautilus-gdu.c b/src/gdu-nautilus-extension/nautilus-gdu.c
new file mode 100644
index 0000000..72e2332
--- /dev/null
+++ b/src/gdu-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/gdu-nautilus-extension/nautilus-gdu.h b/src/gdu-nautilus-extension/nautilus-gdu.h
new file mode 100644
index 0000000..0664887
--- /dev/null
+++ b/src/gdu-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/gdu-nautilus-extension/nautilus-module.c b/src/gdu-nautilus-extension/nautilus-module.c
new file mode 100644
index 0000000..23f869b
--- /dev/null
+++ b/src/gdu-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);
+}
+
