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