diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/configure.in nautilus-2.30.1/configure.in
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/configure.in 2010-05-14 17:16:20.583765747 +0200
+++ nautilus-2.30.1/configure.in 2010-05-14 17:16:39.539580939 +0200
@@ -232,6 +232,52 @@ if test "x$enable_packagekit" != "xno";
msg_packagekit=yes
AC_DEFINE(ENABLE_PACKAGEKIT, 1, [define to enable PackageKit mimetype installer])
fi
+dnl ==========================================================================
+
+dnl ********************
+dnl * Check for libzfs *
+dnl ********************
+ZFS_LIBS=
+msg_zfs=no
+AC_CHECK_LIB(zfs, zfs_iter_root,
+ [AC_CHECK_HEADER(libzfs.h,
+ [AC_DEFINE(HAVE_ZFS, 1, [Define to 1 if ZFS is available])
+ ZFS_LIBS="-lzfs"
+ msg_zfs=yes])
+ ])
+AC_SUBST(ZFS_LIBS)
+
+dnl ==========================================================================
+
+dnl ********************
+dnl * Check for libscf*
+dnl ********************
+SCF_LIBS=
+msg_scf=no
+AC_CHECK_LIB(scf, scf_handle_bind,
+ [AC_CHECK_HEADER(libscf.h,
+ [AC_DEFINE(HAVE_SCF, 1, [Define to 1 if SCF is available])
+ SCF_LIBS="-lscf"
+ msg_scf=yes])
+ ])
+AC_SUBST(SCF_LIBS)
+
+dnl ==========================================================================
+
+dnl ********************
+dnl * Check for libscf*
+dnl ********************
+NVPAIR_LIBS=
+msg_nvpair=no
+AC_CHECK_LIB(nvpair, nvpair_value_match,
+ [AC_CHECK_HEADER(libscf.h,
+ [AC_DEFINE(NVPAIR_LIBS, 1, [Define to 1 if nvpair is available])
+ NVPAIR_LIBS="-lnvpair"
+ msg_nvpair=yes])
+ ])
+AC_SUBST(NVPAIR_LIBS)
+
+
dnl ==========================================================================
--- nautilus-3.1.3/icons/Makefile.am.orig 2011-04-04 19:01:22.000000000 +0100
+++ nautilus-3.1.3/icons/Makefile.am 2011-07-22 09:20:35.708887571 +0100
@@ -4,7 +4,11 @@
icon_DATA =\
audio.svg \
+ camera.png \
knob.png \
+ restore.png \
+ restore-no.png \
+ restore-search.png \
thumbnail_frame.png \
$(NULL)
--- nautilus-3.1.3/libnautilus-private/Makefile.am.orig 2011-07-22 09:23:13.721321695 +0100
+++ nautilus-3.1.3/libnautilus-private/Makefile.am 2011-07-22 09:27:45.285633388 +0100
@@ -49,6 +49,9 @@
$(BASE_LIBS) \
$(COMMON_LIBS) \
$(NAUTILUS_LIBS) \
+ $(ZFS_LIBS) \
+ $(SCF_LIBS) \
+ $(NVPAIR_LIBS) \
$(NULL)
libnautilus_private_la_SOURCES = \
@@ -192,6 +195,8 @@
nautilus-vfs-directory.h \
nautilus-vfs-file.c \
nautilus-vfs-file.h \
+ nautilus-zfs.c \
+ nautilus-zfs.h \
$(NULL)
nodist_libnautilus_private_la_SOURCES =\
--- nautilus-3.1.3/libnautilus-private/org.gnome.nautilus.gschema.xml.in.orig 2011-07-22 09:34:01.449051792 +0100
+++ nautilus-3.1.3/libnautilus-private/org.gnome.nautilus.gschema.xml.in 2011-07-22 09:38:31.164878925 +0100
@@ -72,6 +72,11 @@
<_summary>Where to position newly open tabs in browser windows.</_summary>
<_description>If set to "after-current-tab", then new tabs are inserted after the current tab. If set to "end", then new tabs are appended to the end of the tab list.</_description>
</key>
+ <key name="enable-time-slider" type="b">
+ <default>true</default>
+ <_summary>Enables the visualization of ZFS snapshots timeline</_summary>
+ <_description>If set to true, the visualization of the ZFS snapshots timeline is enabled.</_description>
+ </key>
<key name="always-use-browser" type="b">
<default>true</default>
<_summary>Enables the classic Nautilus behavior, where all windows are browsers</_summary>
--- nautilus-3.1.3/libnautilus-private/nautilus-column-utilities.c.orig 2011-04-04 19:01:22.000000000 +0100
+++ nautilus-3.1.3/libnautilus-private/nautilus-column-utilities.c 2011-07-22 09:46:21.698069053 +0100
@@ -129,6 +129,15 @@
"label", _("Location"),
"description", _("The location of the file."),
NULL));
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "restore_info",
+ "attribute", "restore_info",
+ /* SUN_BRANDING */
+ "label", _("Restore information"),
+ /* SUN_BRANDING */
+ "description", _("Restore information of the file."),
+ NULL));
return columns;
}
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory-async.c nautilus-2.30.1/libnautilus-private/nautilus-directory-async.c
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory-async.c 2010-05-14 17:16:20.620971445 +0200
+++ nautilus-2.30.1/libnautilus-private/nautilus-directory-async.c 2010-05-14 17:16:39.543203000 +0200
@@ -658,6 +658,7 @@ remove_monitor_link (NautilusDirectory *
g_list_free_1 (link);
}
}
+
static void
remove_monitor (NautilusDirectory *directory,
@@ -722,6 +723,10 @@ nautilus_directory_set_up_request (Nauti
REQUEST_SET_TYPE (request, REQUEST_FILESYSTEM_INFO);
}
+ if (file_attributes & NAUTILUS_FILE_ATTRIBUTE_RESTORE_INFO) {
+ REQUEST_SET_TYPE (request, REQUEST_RESTORE_INFO);
+ }
+
return request;
}
@@ -4759,6 +4764,18 @@ cancel_link_info_for_file (NautilusDirec
}
}
+void nautilus_directory_cancel_restore_info (NautilusDirectory *directory)
+{
+ if (NAUTILUS_IS_DIRECTORY (directory))
+ {
+ if (directory->details->restore_cancel)
+ {
+ g_cancellable_cancel (directory->details->restore_cancel);
+ directory->details->restore_cancel = NULL;
+ }
+ }
+}
+
static void
cancel_loading_attributes (NautilusDirectory *directory,
@@ -4801,7 +4818,9 @@ cancel_loading_attributes (NautilusDirec
if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
mount_cancel (directory);
}
-
+ if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO)) {
+ nautilus_directory_cancel_restore_info (directory);
+ }
nautilus_directory_async_state_changed (directory);
}
@@ -4843,7 +4862,9 @@ nautilus_directory_cancel_loading_file_a
if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
cancel_mount_for_file (directory, file);
}
-
+ if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO)) {
+ nautilus_directory_cancel_restore_info (directory);
+ }
nautilus_directory_async_state_changed (directory);
}
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory-private.h nautilus-2.30.1/libnautilus-private/nautilus-directory-private.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory-private.h 2009-12-09 12:03:51.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-directory-private.h 2010-05-14 17:16:39.543661242 +0200
@@ -58,6 +58,7 @@ typedef enum {
REQUEST_THUMBNAIL,
REQUEST_MOUNT,
REQUEST_FILESYSTEM_INFO,
+ REQUEST_RESTORE_INFO,
REQUEST_TYPE_LAST
} RequestType;
@@ -140,6 +141,9 @@ struct NautilusDirectoryDetails
guint64 free_space; /* (guint)-1 for unknown */
time_t free_space_read; /* The time free_space was updated, or 0 for never */
+ GCancellable *restore_cancel;
+ /* zfs snapshot info */
+ GList *zfs_snapshots;
};
NautilusDirectory *nautilus_directory_get_existing (GFile *location);
--- nautilus-3.1.3/libnautilus-private/nautilus-directory.c.orig 2011-07-22 15:39:09.879596935 +0100
+++ nautilus-3.1.3/libnautilus-private/nautilus-directory.c 2011-07-22 15:46:56.201033321 +0100
@@ -35,6 +35,7 @@
#include "nautilus-metadata.h"
#include "nautilus-desktop-directory.h"
#include "nautilus-vfs-directory.h"
+#include "nautilus-zfs.h"
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-macros.h>
#include <eel/eel-string.h>
@@ -129,6 +130,8 @@
directory->details->low_priority_queue = nautilus_file_queue_new ();
directory->details->extension_queue = nautilus_file_queue_new ();
directory->details->free_space = (guint64)-1;
+ directory->details->zfs_snapshots = NULL;
+ directory->details->restore_cancel = NULL;
}
NautilusDirectory *
@@ -160,7 +163,7 @@
nautilus_directory_finalize (GObject *object)
{
NautilusDirectory *directory;
-
+
directory = NAUTILUS_DIRECTORY (object);
g_hash_table_remove (directories, directory->details->location);
@@ -196,7 +199,13 @@
if (directory->details->hidden_file_hash) {
g_hash_table_destroy (directory->details->hidden_file_hash);
}
-
+
+ if (directory->details->zfs_snapshots) {
+ ts_free_snapshots (directory->details->zfs_snapshots);
+ }
+ if (directory->details->restore_cancel)
+ g_cancellable_cancel (directory->details->restore_cancel);
+
nautilus_file_queue_destroy (directory->details->high_priority_queue);
nautilus_file_queue_destroy (directory->details->low_priority_queue);
nautilus_file_queue_destroy (directory->details->extension_queue);
@@ -308,11 +317,26 @@
g_hash_table_foreach (directories, async_state_changed_one, NULL);
}
+static gboolean time_slider_enabled = TRUE;
+
+gboolean is_time_slider_enabled ()
+{
+ return time_slider_enabled;
+}
+
+static void time_slider_pref_changed_callback (gpointer callback_data)
+{
+ time_slider_enabled = g_settings_get_boolean(nautilus_preferences,
+ NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER);
+}
+
static void
add_preferences_callbacks (void)
{
nautilus_global_preferences_init ();
+ time_slider_enabled = g_settings_get_boolean(nautilus_preferences,
+ NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER);
g_signal_connect_swapped (nautilus_preferences,
"changed::" NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES,
G_CALLBACK(filtering_changed_callback),
@@ -330,6 +354,10 @@
"changed::" NAUTILUS_PREFERENCES_DATE_FORMAT,
G_CALLBACK(async_data_preference_changed_callback),
NULL);
+ g_signal_connect_swapped (nautilus_preferences,
+ "changed::" NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER,
+ G_CALLBACK(time_slider_pref_changed_callback),
+ NULL);
}
static void
@@ -534,6 +562,7 @@
{
NautilusDirectory *directory;
char *uri;
+ char *path;
uri = g_file_get_uri (location);
@@ -545,10 +574,13 @@
directory = NAUTILUS_DIRECTORY (nautilus_search_directory_new_from_saved_search (uri));
} else {
directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_VFS_DIRECTORY, NULL));
+ path = g_file_get_path (location);
+ g_free (path);
}
set_directory_location (directory, location);
+
g_free (uri);
return directory;
@@ -567,6 +599,201 @@
g_file_is_native (directory->details->location);
}
+typedef struct {
+ NautilusDirectory *dir;
+ GCancellable *cancel;
+ TsReadyCallback callback;
+ gpointer callback_user_data;
+} QuerySnapshotsAsyncData;
+
+
+static void snapshot_list_ready_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ QuerySnapshotsAsyncData *data = (QuerySnapshotsAsyncData*) user_data;
+
+ if (!g_cancellable_is_cancelled (data->cancel))
+ {
+ data->dir->details->zfs_snapshots = g_simple_async_result_get_op_res_gpointer (simple);
+ }
+
+ data->callback (data->dir, data->cancel, data->callback_user_data);
+}
+
+void
+nautilus_directory_get_snapshots_async (NautilusDirectory *directory,
+ TsReadyCallback ready_callback,
+ GCancellable *cancel,
+ gpointer callback_user_data)
+{
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+ if (directory->details->location == NULL)
+ return;
+
+ if (directory->details->zfs_snapshots) {
+ ts_free_snapshots (directory->details->zfs_snapshots);
+ directory->details->zfs_snapshots = NULL;
+ }
+
+ if (is_time_slider_enabled ())
+ {
+ QuerySnapshotsAsyncData *data;
+ data = g_new0 (QuerySnapshotsAsyncData,1);
+ data->dir = directory;
+ data->cancel = cancel;
+ data->callback = ready_callback;
+ data->callback_user_data = callback_user_data;
+
+ ts_get_snapshots_for_dir_async (directory->details->location,
+ snapshot_list_ready_callback,
+ cancel,
+ data);
+ }
+}
+
+gboolean
+nautilus_directory_has_snapshots (NautilusDirectory *directory)
+{
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+ if (directory->details->zfs_snapshots)
+ return TRUE;
+
+ return FALSE;
+}
+int
+nautilus_directory_get_num_snapshots (NautilusDirectory *directory)
+{
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+ if (directory->details->zfs_snapshots)
+ {
+ int i = 0;
+ GList *tmp;
+ for (tmp = directory->details->zfs_snapshots;tmp;tmp = tmp->next)
+ i++;
+ return i;
+ }
+ return 0;
+}
+
+gboolean
+nautilus_directory_is_in_snapshot (NautilusDirectory *directory)
+{
+ char *directory_uri;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), FALSE);
+
+ directory_uri = nautilus_directory_get_uri (directory);
+
+ result = ts_is_in_snapshot (directory_uri);
+
+ g_free (directory_uri);
+
+ return result;
+}
+
+GList *
+nautilus_directory_get_snapshots (NautilusDirectory *directory)
+{
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+ return directory->details->zfs_snapshots;
+}
+
+void nautilus_directory_remove_snapshot (NautilusDirectory *directory,
+ ZfsDataSet *snap)
+{
+ if (directory->details->zfs_snapshots)
+ {
+ directory->details->zfs_snapshots = g_list_remove (directory->details->zfs_snapshots, snap);
+ ts_free_zfs_dataset (snap);
+ }
+}
+/* return true if snapdir dir path is a dir or subdir of refdir */
+gboolean
+nautilus_directory_is_a_snapshot_dir_of (NautilusDirectory *snapdir,
+ NautilusDirectory *refdir)
+{
+
+ gboolean result = FALSE;
+
+ if (nautilus_directory_is_in_snapshot (snapdir))
+ {
+ char snapdir_root_real_path [PATH_MAX+1];
+ char refdir_real_path [PATH_MAX+1];
+ NautilusDirectory *snapdir_root = nautilus_directory_get_snap_root (snapdir);
+ GFile *snapdir_root_file = nautilus_directory_get_location (snapdir_root);
+ GFile *refdir_file = nautilus_directory_get_location (refdir);
+ char* snapdir_root_path = g_file_get_path (snapdir_root_file);
+ char* refdir_path = g_file_get_path (refdir_file);
+
+ if (ts_realpath (snapdir_root_path, snapdir_root_real_path) &&
+ ts_realpath (refdir_path, refdir_real_path))
+ {
+ if (g_strrstr (snapdir_root_real_path,refdir_real_path))
+ result = TRUE;
+ }
+
+ g_free (snapdir_root_path);
+ g_free (refdir_path);
+ g_object_unref (snapdir_root_file);
+ g_object_unref (refdir_file);
+ g_object_unref (snapdir_root);
+ }
+
+ return result;
+}
+
+NautilusDirectory *nautilus_directory_get_snap_root (NautilusDirectory *directory)
+{
+ char *directory_uri, *snap_root;
+ char *zfs, *iter;
+ int count = 0;
+ NautilusDirectory *new_dir;
+
+ g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+ directory_uri = nautilus_directory_get_uri (directory);
+
+
+ if (!nautilus_directory_is_in_snapshot (directory))
+ {
+ g_free (directory_uri);
+ return directory;
+ }
+
+ /*remove .zfs/snapshot/blah/ */
+ zfs = g_strrstr (directory_uri, ".zfs/snapshot/");
+ iter = zfs;
+
+ if (iter)
+ {
+ iter += sizeof (".zfs/snapshot/");
+ while (*iter != '/' && *iter != '\0')
+ iter++;
+
+ if (*iter == '/')
+ iter++;
+
+ *zfs = '\0';
+ snap_root = g_strdup_printf ("%s%s", directory_uri, iter);
+
+ *zfs = 'a';
+ g_free (directory_uri);
+ new_dir = nautilus_directory_get_by_uri (snap_root);
+ g_free (snap_root);
+ return new_dir;
+ }
+ return directory;
+}
+
+
+
gboolean
nautilus_directory_is_in_trash (NautilusDirectory *directory)
{
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory.h nautilus-2.30.1/libnautilus-private/nautilus-directory.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-directory.h 2009-12-08 16:17:07.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-directory.h 2010-05-14 17:16:39.545571596 +0200
@@ -28,6 +28,7 @@
#include <gtk/gtk.h>
#include <gio/gio.h>
#include <libnautilus-private/nautilus-file-attributes.h>
+#include <libnautilus-private/nautilus-zfs.h>
/* NautilusDirectory is a class that manages the model for a directory,
real or virtual, for Nautilus, mainly the file-manager component. The directory is
@@ -219,6 +220,24 @@ gboolean nautilus_directory_ar
gboolean nautilus_directory_is_local (NautilusDirectory *directory);
gboolean nautilus_directory_is_in_trash (NautilusDirectory *directory);
+typedef void (*TsReadyCallback) (NautilusDirectory *directory,
+ GCancellable *cancellable,
+ gpointer callback_data);
+
+void nautilus_directory_get_snapshots_async (NautilusDirectory *directory,
+ TsReadyCallback ready_callback,
+ GCancellable *cancel,
+ gpointer callback_user_data);
+gboolean nautilus_directory_has_snapshots (NautilusDirectory *directory);
+gboolean nautilus_directory_is_in_snapshot (NautilusDirectory *directory);
+int nautilus_directory_get_num_snapshots (NautilusDirectory *directory);
+GList * nautilus_directory_get_snapshots (NautilusDirectory *directory);
+void nautilus_directory_remove_snapshot (NautilusDirectory *directory,
+ ZfsDataSet *snap);
+NautilusDirectory *nautilus_directory_get_snap_root (NautilusDirectory *directory);
+gboolean nautilus_directory_is_a_snapshot_dir_of (NautilusDirectory *snapdir,
+ NautilusDirectory *refdir);
+void nautilus_directory_cancel_restore_info (NautilusDirectory *directory);
/* Return false if directory contains anything besides a Nautilus metafile.
* Only valid if directory is monitored. Used by the Trash monitor.
@@ -239,6 +258,7 @@ GList * nautilus_directory_li
gboolean nautilus_directory_is_desktop_directory (NautilusDirectory *directory);
gboolean nautilus_directory_is_editable (NautilusDirectory *directory);
+gboolean is_time_slider_enabled ();
#endif /* NAUTILUS_DIRECTORY_H */
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file-attributes.h nautilus-2.30.1/libnautilus-private/nautilus-file-attributes.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file-attributes.h 2009-12-09 12:03:51.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-file-attributes.h 2010-05-14 17:16:39.545856449 +0200
@@ -41,6 +41,7 @@ typedef enum {
NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL = 1 << 8,
NAUTILUS_FILE_ATTRIBUTE_MOUNT = 1 << 9,
NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO = 1 << 10,
+ NAUTILUS_FILE_ATTRIBUTE_RESTORE_INFO = 1 << 12,
} NautilusFileAttributes;
#endif /* NAUTILUS_FILE_ATTRIBUTES_H */
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file-private.h nautilus-2.30.1/libnautilus-private/nautilus-file-private.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file-private.h 2009-12-09 12:03:51.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-file-private.h 2010-05-14 17:16:39.546288851 +0200
@@ -146,6 +146,15 @@ struct NautilusFileDetails
/* Mount for mountpoint or the references GMount for a "mountable" */
GMount *mount;
+
+ /* time slider file difference information */
+
+ char *restore_info;
+
+ /* snapshot directory for versions */
+
+ char *snapshot_directory;
+ GCancellable *has_snapshot_cancel;
/* boolean fields: bitfield to save space, since there can be
many NautilusFile objects. */
@@ -194,6 +203,13 @@ struct NautilusFileDetails
eel_boolean_bit is_thumbnailing : 1;
+ eel_boolean_bit restore_info_is_up_to_date : 1;
+ eel_boolean_bit restore_info_in_progress : 1;
+
+ eel_boolean_bit has_snap_versions_is_up_to_date : 1;
+ eel_boolean_bit has_snap_versions_in_progress : 1;
+ eel_boolean_bit has_snap_versions : 1;
+
/* TRUE if the file is open in a spatial window */
eel_boolean_bit has_open_window : 1;
--- nautilus-3.1.3/libnautilus-private/nautilus-file.c.orig 2011-07-22 15:55:37.274869941 +0100
+++ nautilus-3.1.3/libnautilus-private/nautilus-file.c 2011-07-22 16:05:34.306574660 +0100
@@ -47,6 +47,7 @@
#include "nautilus-vfs-file.h"
#include "nautilus-saved-search-file.h"
#include "nautilus-lockdown.h"
+#include "nautilus-zfs.h"
#include <eel/eel-debug.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-extensions.h>
@@ -142,7 +143,8 @@
attribute_where_q,
attribute_link_target_q,
attribute_volume_q,
- attribute_free_space_q;
+ attribute_free_space_q,
+ attribute_restore_info_q;
static void nautilus_file_info_iface_init (NautilusFileInfoIface *iface);
static char * nautilus_file_get_owner_as_string (NautilusFile *file,
@@ -152,6 +154,7 @@
GFileInfo *info);
static const char * nautilus_file_peek_display_name (NautilusFile *file);
static const char * nautilus_file_peek_display_name_collation_key (NautilusFile *file);
+static void invalidate_restore_info (NautilusFile *file);
static void file_mount_unmounted (GMount *mount, gpointer data);
static void metadata_hash_free (GHashTable *hash);
@@ -486,7 +489,14 @@
eel_ref_str_unref (file->details->filesystem_id);
file->details->filesystem_id = NULL;
-
+ g_free (file->details->restore_info);
+ file->details->restore_info = NULL;
+ invalidate_restore_info (file);
+ g_free (file->details->snapshot_directory);
+ file->details->snapshot_directory = NULL;
+ file->details->has_snap_versions_in_progress = FALSE;
+ file->details->has_snap_versions_is_up_to_date = FALSE;
+ file->details->has_snap_versions = FALSE;
clear_metadata (file);
}
@@ -804,6 +814,10 @@
g_free (file->details->activation_uri);
g_clear_object (&file->details->custom_icon);
+ g_free (file->details->restore_info);
+ if (file->details->snapshot_directory)
+ g_free (file->details->snapshot_directory);
+
if (file->details->thumbnail) {
g_object_unref (file->details->thumbnail);
}
@@ -4423,6 +4437,76 @@
NULL
};
+char *
+nautilus_date_as_string (time_t time_raw, gboolean use_smallest)
+{
+ struct tm *ttime;
+ const char **formats;
+ const char *width_template;
+ const char *format;
+ char *date_string;
+ char *result;
+ GDate *today;
+ GDate *date;
+ guint32 date_age;
+ int i, date_format_pref;
+
+ ttime = localtime (&time_raw);
+
+ if (!use_smallest)
+ {
+ date_format_pref = g_settings_get_enum (nautilus_preferences,
+ NAUTILUS_PREFERENCES_DATE_FORMAT);
+ if (date_format_pref == NAUTILUS_DATE_FORMAT_LOCALE) {
+ return eel_strdup_strftime ("%c", ttime);
+ } else if (date_format_pref == NAUTILUS_DATE_FORMAT_ISO) {
+ return eel_strdup_strftime ("%Y-%m-%d %H:%M:%S",ttime);
+ }
+ }
+
+ date = eel_g_date_new_tm (ttime);
+
+ today = g_date_new ();
+ g_date_set_time_t (today, time (NULL));
+
+ /* Overflow results in a large number; fine for our purposes. */
+ date_age = (g_date_get_julian (today) -
+ g_date_get_julian (date));
+
+ g_date_free (date);
+ g_date_free (today);
+
+ /* Format varies depending on how old the date is. This minimizes
+ * the length (and thus clutter & complication) of typical dates
+ * while providing sufficient detail for recent dates to make
+ * them maximally understandable at a glance. Keep all format
+ * strings separate rather than combining bits & pieces for
+ * internationalization's sake.
+ */
+
+ if (date_age == 0) {
+ formats = TODAY_TIME_FORMATS;
+ } else if (date_age == 1) {
+ formats = YESTERDAY_TIME_FORMATS;
+ } else if (date_age < 7) {
+ formats = CURRENT_WEEK_TIME_FORMATS;
+ } else {
+ formats = CURRENT_WEEK_TIME_FORMATS;
+ }
+
+
+ if (!use_smallest)
+ format = _(formats[1]);
+ else
+ {
+ int i=0;
+ while (formats[i] != NULL)
+ i++;
+ format = _(formats[i-3]);
+ }
+ return eel_strdup_strftime (format, ttime);
+}
+
static char *
nautilus_file_fit_date_as_string (NautilusFile *file,
NautilusDateType date_type,
@@ -6103,7 +6187,9 @@
if (attribute_q == attribute_free_space_q) {
return nautilus_file_get_volume_free_space (file);
}
-
+ if (attribute_q == attribute_restore_info_q) {
+ return nautilus_file_get_restore_info_async (file);
+ }
extension_attribute = NULL;
if (file->details->pending_extension_attributes) {
@@ -7037,6 +7123,616 @@
}
+gboolean
+nautilus_file_is_in_snapshot (NautilusFile *file)
+{
+ char *file_uri = nautilus_file_get_uri (file);
+ gboolean result = ts_is_in_snapshot (file_uri);
+ g_free (file_uri);
+ return result;
+}
+
+static gboolean nautilus_file_in_snap_exist_in_current (NautilusFile *file, GCancellable *cancel)
+{
+ /* get path without /.zfs/snapshot/blah/ */
+ /* test is file exist */
+ char *file_uri = nautilus_file_get_uri (file);
+ char *file_uri_without_snap = NULL;
+ gboolean result = FALSE;
+
+ if (g_cancellable_is_cancelled (cancel))
+ {
+ g_free (file_uri);
+ return FALSE;
+ }
+
+ file_uri_without_snap = ts_remove_snapshot_dir (file_uri);
+
+ if (file_uri_without_snap)
+ {
+ GFile* root_file = g_file_new_for_uri (file_uri_without_snap);
+ char *path = g_file_get_path (root_file);
+
+ if (path)
+ {
+ result = g_file_test (path, G_FILE_TEST_EXISTS);
+ g_free (path);
+ }
+ g_object_unref (root_file);
+ g_free (file_uri_without_snap);
+
+ }
+
+ g_free (file_uri);
+
+ return result;
+}
+
+
+char * nautilus_file_in_snapshot_get_info (NautilusFile *file, GCancellable *cancel)
+{
+ char *info = NULL;
+ GFile *then_gfile = nautilus_file_get_location (file);
+ char *then_path = g_file_get_path (then_gfile);
+ g_object_unref (then_gfile);
+
+ if (g_cancellable_is_cancelled (cancel))
+ {
+ g_free (then_gfile);
+ g_free (then_path);
+ return g_strdup ("cancelled");
+ }
+ if (then_path)
+ {
+ struct stat64 now;
+ struct stat64 then;
+ char *now_path = ts_remove_snapshot_dir (then_path);
+
+ if (lstat64 (now_path, &now) == 0)
+ {
+ if (lstat64 (then_path, &then) == 0)
+ {
+
+ if (now.st_mtime != then.st_mtime)
+ {
+ if (now.st_size == then.st_size)
+ /* SUN_BRANDING */
+ info = g_strdup (_("different date, same size as latest version"));
+ else if (now.st_size > then.st_size)
+ /* SUN_BRANDING */
+ info = g_strdup (_("different date, smaller than latest version"));
+ else if ( now.st_size < then.st_size)
+ /* SUN_BRANDING */
+ info = g_strdup (_("different date, bigger than latest version"));
+ }
+ else
+ /* SUN_BRANDING */
+ info = g_strdup (_("identical to latest version"));
+ }
+ else
+ info = g_strdup_printf ("FIXME no then %s", then_path);
+ }
+ else
+ /* SUN_BRANDING */
+ info = g_strdup (_("not present in latest version"));
+
+ g_free (now_path);
+ g_free (then_path);
+ }
+
+ return info;
+}
+
+static char * restore_string (char *str, GCancellable *cancel)
+{
+ if (g_cancellable_is_cancelled (cancel))
+ {
+ g_free (str);
+ return g_strdup (_("unknown"));
+ }
+ else
+ return str;
+}
+
+gint time_cmp (time_t *a,
+ time_t *b)
+{
+ if (*a == *b)
+ return 0;
+ if (*a > *b)
+ return 1;
+ if (*a < *b)
+ return -1;
+
+}
+
+char *
+nautilus_file_get_num_snapshot_version (NautilusFile *file,
+ GCancellable *cancel,
+ gboolean stop_at_first)
+{
+ GList *tmp = NULL;
+ GList *tmp2 = NULL;
+ GList *time = NULL;
+ time_t* now_time = NULL;
+ char *result = NULL;
+ int version = 0;
+ NautilusFile *parent = NULL;
+ NautilusDirectory *dir = NULL;
+ char *snapdir = NULL;
+
+ if (NAUTILUS_IS_FILE (file))
+ {
+ parent = nautilus_file_get_parent (file);
+ if (parent)
+ {
+ dir = nautilus_directory_get_for_file (parent);
+ g_object_unref (parent);
+ }
+ }
+ if (dir)
+ {
+ struct stat64 now;
+ struct stat64 then;
+ char snap_name[PATH_MAX+1];
+ char *name = nautilus_file_get_name (file);
+
+ g_object_ref (dir);
+ tmp = nautilus_directory_get_snapshots (dir);
+
+ GFile *now_gfile = nautilus_file_get_location (file);
+ char *now_path = g_file_get_path (now_gfile);
+ g_object_unref (now_gfile);
+
+ if (now_path)
+ {
+ if (lstat64 (now_path, &now) != 0)
+ {
+ g_free (now_path);
+ g_object_unref (dir);
+ return NULL;
+ }
+ }
+
+ g_free (now_path);
+
+ time = NULL;
+
+ /* get list of mtime for all files in snapshots */
+
+ now_time = g_new0 (time_t, 1);
+ *now_time = now.st_mtim.tv_sec;
+ time = g_list_prepend (time, now_time);
+
+
+ for (tmp; tmp; tmp = tmp->next)
+ {
+ g_sprintf (snap_name, "%s/%s",
+ ((ZfsDataSet *) tmp->data)->mountpoint,
+ name);
+ if (g_cancellable_is_cancelled (cancel))
+ goto cancel;
+ if (lstat64 (snap_name, &then) == 0)
+ {
+ if (g_list_find_custom (time, &then.st_mtim.tv_sec, (GCompareFunc) time_cmp) == NULL)
+ { /*insert in list only is unique */
+ time_t* snap_time = g_new0 (time_t, 1);
+ *snap_time = then.st_mtim.tv_sec;
+ time = g_list_prepend (time, snap_time);
+ if (stop_at_first)
+ {
+ snapdir = g_strdup (((ZfsDataSet *) tmp->data)->mountpoint);
+ goto cancel;
+ }
+ }
+ }
+
+ }
+cancel:
+ g_free (name);
+ g_object_unref (dir);
+ }
+
+
+ for (tmp = time; tmp; tmp = tmp->next)
+ {
+ g_free ((time_t*) tmp->data);
+ version++;
+ }
+
+ /* remove current version */
+ version--;
+
+ g_list_free (time);
+
+ if (version == 0)
+ {
+ if (stop_at_first)
+ return NULL;
+ else /*SUN_BRANDING*/
+ return restore_string (g_strdup_printf (_("no other version")), cancel);
+ }
+
+ if (stop_at_first)
+ return snapdir;
+ else
+ return restore_string (g_strdup_printf ("%d %s", version,
+ /* SUN_BRANDING */
+ version > 1 ? _("other versions") : /* SUN_BRANDING */ _("other version")),
+ cancel);
+}
+
+static gboolean worker_thread_started = FALSE;
+
+typedef void (*ReadyCallback) (gpointer data,
+ GCancellable *cancellable);
+typedef void (*WorkerFunction) (gpointer data,
+ GCancellable *cancellable);
+typedef struct {
+ gpointer data;
+ gpointer return_data;
+ ReadyCallback ready_callback;
+ WorkerFunction worker_func;
+ GCancellable *cancellable;
+} QueryData;
+
+static void
+nautilus_file_get_restore_info (gpointer data,
+ GCancellable *cancellable)
+{
+ QueryData *qdata = (QueryData*) data;
+ NautilusFile *file = NAUTILUS_FILE (qdata->data);
+ char *result = NULL;
+
+ /*{
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+ }
+
+ {
+ GFile *f = nautilus_file_get_location (file);
+ char *path = g_file_get_uri (f);
+ printf ("start restore info for %s", path);
+ g_free (path);
+ g_object_unref (f);
+ }*/
+ if (!g_cancellable_is_cancelled (cancellable))
+ {
+
+ if (nautilus_file_is_directory (file))
+ {
+ NautilusDirectory *dir = nautilus_directory_get_for_file (file);
+ g_object_ref (dir);
+ if (nautilus_directory_is_in_snapshot (dir))
+ {
+ if (!nautilus_file_in_snap_exist_in_current (file, cancellable))
+ /* SUN_BRANDING */
+ result = g_strdup (_("not present in latest version"));
+ else
+ /* SUN_BRANDING */
+ result = g_strdup (_("present in latest version"));
+ }
+ else
+ {
+ int version = nautilus_directory_get_num_snapshots (dir);
+
+ if (version == 0)
+ /* SUN_BRANDING */
+ result = g_strdup (_("no version"));
+ else
+ result = g_strdup_printf ("%d %s",version,
+ /* SUN_BRANDING */
+ version > 1 ? _("versions") : /* SUN_BRANDING */ _("version"));
+ }
+ g_object_unref (dir);
+ }
+ else
+ {
+ if (nautilus_file_is_in_snapshot (file))
+ result = nautilus_file_in_snapshot_get_info (file, cancellable);
+ else
+ result = nautilus_file_get_num_snapshot_version (file, cancellable, FALSE);
+ }
+ }
+
+/* {
+ printf ("is %s\n", result);
+ }*/
+
+
+ qdata->return_data = restore_string (result, cancellable);
+}
+
+
+static void restore_information_ready_callback (gpointer data,
+ GCancellable *cancellable)
+{
+ QueryData *qdata = (QueryData*) data;
+ NautilusFile *file = (NautilusFile*) qdata->data;
+ char *return_data = qdata->return_data;
+
+ if (!NAUTILUS_IS_FILE (file))
+ return;
+
+ file->details->restore_info_in_progress = FALSE;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ file->details->restore_info = g_strdup (_("unknown"));
+ invalidate_restore_info (file);
+ if (return_data)
+ g_free (return_data);
+ }
+ else
+ {
+ file->details->restore_info_is_up_to_date = TRUE;
+ file->details->restore_info = return_data;
+ }
+
+ nautilus_file_changed (file);
+ nautilus_file_unref (file);
+}
+
+
+static gboolean
+complete_in_idle_cb (gpointer data)
+{
+ QueryData *qdata = (QueryData*)data;
+ qdata->ready_callback (data, qdata->cancellable);
+ g_free (qdata);
+ return FALSE;
+}
+
+static void
+worker_queue_finished_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GCancellable *cancel = (GCancellable*) user_data;
+
+ worker_thread_started = FALSE;
+
+ if (g_cancellable_is_cancelled (cancel))
+ {
+ return;
+ }
+
+ g_simple_async_result_get_op_res_gpointer (simple);
+
+}
+
+static void
+worker_queue_func (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ QueryData *data = NULL;
+
+ GTimeVal timeout;
+ GAsyncQueue *queue = (GAsyncQueue*) g_simple_async_result_get_op_res_gpointer (res);
+ g_async_queue_ref (queue);
+
+ g_get_current_time (&timeout);
+ g_time_val_add (&timeout, 3000000);
+
+ data = g_async_queue_timed_pop (queue, &timeout);
+
+ while (data)
+ {
+ GSource *source;
+
+ /* only call the worker fct if not cancel
+ * but execute ready function anyway */
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ data->worker_func (data, data->cancellable);
+
+ /*call ready callback in main loop/thread */
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_DEFAULT);
+ g_source_set_callback (source, complete_in_idle_cb, data, NULL);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ /* pop next one */
+ g_get_current_time (&timeout);
+ g_time_val_add (&timeout, 3000000);
+ data = g_async_queue_timed_pop (queue, &timeout);
+ }
+
+ g_async_queue_unref (queue);
+}
+
+char * nautilus_file_get_restore_info_async (NautilusFile *file)
+{
+ if (!is_time_slider_enabled ())
+ return NULL;
+
+ if (!ts_is_restore_column_enabled ())
+ return NULL;
+
+ if (file->details->restore_info_is_up_to_date)
+ {
+ /*if ( file->details->restore_info == NULL)
+ return g_strdup ("null cached info");*/
+ return g_strdup (file->details->restore_info);
+ }
+
+ if (file->details->restore_info_in_progress)
+ return g_strdup ("...");
+ else
+ {
+ static GAsyncQueue *queue = NULL;
+ QueryData *data = NULL;
+
+ if (!file->details->directory)
+ return g_strdup ("no directory element\n");
+
+ if (!nautilus_directory_has_snapshots (file->details->directory) && !nautilus_file_is_in_snapshot (file))
+ return g_strdup ("doesn't have snap nor is in snap\n");
+
+ if (!file->details->directory->details->restore_cancel)
+ {
+ file->details->directory->details->restore_cancel = g_cancellable_new ();
+ }
+ else
+ {
+ if (g_cancellable_is_cancelled (file->details->directory->details->restore_cancel))
+ return NULL;
+ }
+
+ g_free (file->details->restore_info);
+ file->details->restore_info = NULL;
+ file->details->restore_info_in_progress = TRUE;
+
+ if (!queue)
+ queue = g_async_queue_new ();
+
+ data = g_new0 (QueryData, 1);
+ data->data = file;
+ nautilus_file_ref (file);
+ data->cancellable = file->details->directory->details->restore_cancel;
+ data->ready_callback = restore_information_ready_callback;
+ data->worker_func = nautilus_file_get_restore_info;
+
+ g_async_queue_push (queue, data);
+
+ if (!worker_thread_started)
+ {
+ GSimpleAsyncResult *res;
+ worker_thread_started = TRUE;
+
+ res = g_simple_async_result_new (G_OBJECT (file),
+ worker_queue_finished_callback,
+ NULL,
+ (gpointer) worker_queue_func);
+
+ g_simple_async_result_set_op_res_gpointer (res, queue, NULL);
+ g_simple_async_result_run_in_thread (res,
+ worker_queue_func,
+ G_PRIORITY_DEFAULT,
+ data->cancellable);
+ }
+
+ return g_strdup ("...");
+ }
+}
+
+HasSnapshotResult
+nautilus_file_has_snapshot_version (NautilusFile *file)
+{
+ if (file->details->has_snap_versions_is_up_to_date)
+ return (file->details->has_snap_versions);
+ return UNKNOWN_STATE;
+}
+
+typedef struct {
+ NautilusFile *file;
+ GCancellable *cancel;
+ FileHasSnapshotCallback callback;
+ gpointer callback_user_data;
+ char *snap_dir;
+} HasSnapshotAsyncData;
+
+typedef void (*HasSnapReadyCallback) (NautilusDirectory *file,
+ GCancellable *cancel,
+ gpointer callback_data);
+
+
+static void has_snapshot_ready_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ HasSnapshotAsyncData *data = (HasSnapshotAsyncData*) user_data;
+
+ if (g_cancellable_is_cancelled (data->cancel))
+ {
+ data->file->details->has_snap_versions_in_progress = FALSE;
+ data->file->details->has_snap_versions_is_up_to_date = FALSE;
+ if (data->file->details->snapshot_directory)
+ g_free (data->file->details->snapshot_directory);
+
+ data->file->details->has_snapshot_cancel = NULL;
+ }
+ else
+ {
+ data->file->details->has_snap_versions_in_progress = FALSE;
+ data->file->details->has_snap_versions_is_up_to_date = TRUE;
+ if (data->file->details->snapshot_directory)
+ g_free (data->file->details->snapshot_directory);
+ data->file->details->snapshot_directory = g_simple_async_result_get_op_res_gpointer (simple);
+ if (data->file->details->snapshot_directory)
+ data->file->details->has_snap_versions = TRUE;
+ else
+ data->file->details->has_snap_versions = FALSE;
+ }
+ data->callback (data->callback_user_data);
+}
+char *
+nautilus_file_get_snapshot_dir (NautilusFile *file)
+{
+ return file->details->snapshot_directory;
+}
+void nautilus_file_real_get_snapshot_version (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ NautilusFile *file = NAUTILUS_FILE (object);
+ char *snap_info = nautilus_file_get_num_snapshot_version (file, cancellable, TRUE);
+
+ if (!snap_info) /* scan for .zfs directory*/
+ snap_info = ts_get_not_zfs_snapshot_dir (nautilus_file_get_location (file));
+/*
+ {
+ struct timespec ts;
+ ts.tv_sec = 4;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+ }
+*/
+ if (snap_info)
+ g_simple_async_result_set_op_res_gpointer (res, snap_info, (GDestroyNotify) NULL);
+ else
+ g_simple_async_result_set_op_res_gpointer (res, NULL, (GDestroyNotify) NULL);
+}
+
+void nautilus_file_get_snapshot_version (NautilusFile *file,
+ FileHasSnapshotCallback callback,
+ GCancellable *cancel,
+ gpointer user_data)
+{
+ HasSnapshotAsyncData *data;
+ GSimpleAsyncResult *res;
+
+ if (file->details->has_snap_versions_in_progress)
+ {
+ g_cancellable_cancel(file->details->has_snapshot_cancel);
+ file->details->has_snapshot_cancel = NULL;
+ file->details->has_snap_versions_in_progress = FALSE;
+ }
+
+ file->details->has_snapshot_cancel = cancel;
+ file->details->has_snap_versions_in_progress = TRUE;
+ file->details->has_snap_versions_is_up_to_date = FALSE;
+
+ data = g_new0 (HasSnapshotAsyncData, 1);
+ data->file = file;
+ data->cancel = cancel;
+ data->callback = callback;
+ data->callback_user_data = user_data;
+
+ res = g_simple_async_result_new (G_OBJECT (file),
+ has_snapshot_ready_callback,
+ data,
+ (gpointer) nautilus_file_real_get_snapshot_version);
+ g_simple_async_result_run_in_thread (res, nautilus_file_real_get_snapshot_version,
+ G_PRIORITY_DEFAULT, cancel);
+}
+
+
void
nautilus_file_mark_gone (NautilusFile *file)
{
@@ -7296,6 +7992,12 @@
file->details->mount_is_up_to_date = FALSE;
}
+static void
+invalidate_restore_info (NautilusFile *file)
+{
+ file->details->restore_info_is_up_to_date = FALSE;
+}
+
void
nautilus_file_invalidate_extension_info_internal (NautilusFile *file)
{
@@ -7350,6 +8052,9 @@
if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
invalidate_thumbnail (file);
}
+ if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO)) {
+ invalidate_restore_info (file);
+ }
if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
invalidate_mount (file);
}
@@ -7432,7 +8137,8 @@
NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT |
NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO |
NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL |
- NAUTILUS_FILE_ATTRIBUTE_MOUNT;
+ NAUTILUS_FILE_ATTRIBUTE_MOUNT |
+ NAUTILUS_FILE_ATTRIBUTE_RESTORE_INFO ;
}
void
@@ -8011,6 +8717,7 @@
attribute_link_target_q = g_quark_from_static_string ("link_target");
attribute_volume_q = g_quark_from_static_string ("volume");
attribute_free_space_q = g_quark_from_static_string ("free_space");
+ attribute_restore_info_q = g_quark_from_static_string ("restore_info");
G_OBJECT_CLASS (class)->finalize = finalize;
G_OBJECT_CLASS (class)->constructor = nautilus_file_constructor;
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file.h nautilus-2.30.1/libnautilus-private/nautilus-file.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-file.h 2009-12-09 12:03:51.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-file.h 2010-05-14 17:16:39.550338308 +0200
@@ -173,6 +173,7 @@ gboolean nautilus_file_is
const char *mime_type);
gboolean nautilus_file_is_launchable (NautilusFile *file);
gboolean nautilus_file_is_symbolic_link (NautilusFile *file);
+gboolean nautilus_file_is_in_snapshot (NautilusFile *file);
gboolean nautilus_file_is_mountpoint (NautilusFile *file);
GMount * nautilus_file_get_mount (NautilusFile *file);
char * nautilus_file_get_volume_free_space (NautilusFile *file);
@@ -228,6 +229,26 @@ char * nautilus_file_ge
NautilusFile * nautilus_file_get_trash_original_file (NautilusFile *file);
+char * nautilus_file_get_num_snapshot_version (NautilusFile *file,
+ GCancellable *cancel,
+ gboolean stop_at_first);
+char * nautilus_file_get_restore_info_async (NautilusFile *file);
+
+typedef enum {
+ NO,
+ YES,
+ UNKNOWN_STATE
+} HasSnapshotResult;
+
+HasSnapshotResult nautilus_file_has_snapshot_version (NautilusFile *file);
+char * nautilus_file_get_snapshot_dir (NautilusFile *file);
+typedef void (*FileHasSnapshotCallback) (gpointer user_data);
+
+void nautilus_file_get_snapshot_version (NautilusFile *file,
+ FileHasSnapshotCallback callback,
+ GCancellable *cancel,
+ gpointer user_data);
+
/* Permissions. */
gboolean nautilus_file_can_get_permissions (NautilusFile *file);
gboolean nautilus_file_can_set_permissions (NautilusFile *file);
--- nautilus-3.1.3/libnautilus-private/nautilus-global-preferences.h.orig 2011-07-22 10:33:34.400109504 +0100
+++ nautilus-3.1.3/libnautilus-private/nautilus-global-preferences.h 2011-07-22 10:37:38.055064000 +0100
@@ -42,6 +42,7 @@
#define NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES "show-hidden-files"
#define NAUTILUS_PREFERENCES_SHOW_ADVANCED_PERMISSIONS "show-advanced-permissions"
#define NAUTILUS_PREFERENCES_DATE_FORMAT "date-format"
+#define NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER "enable-time-slider"
/* Mouse */
#define NAUTILUS_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS "mouse-use-extra-buttons"
--- /dev/null 2011-07-25 14:19:16.000000000 +0100
+++ nautilus-3.1.3/libnautilus-private/nautilus-zfs.c 2011-07-25 14:19:15.457833851 +0100
@@ -0,0 +1,1221 @@
+/*
+ * Copyright (C) 2010 Sun Microsystems (Erwann Chenede)
+ *
+ */
+
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "nautilus-zfs.h"
+#include <time.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <stdint.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <eel/eel-glib-extensions.h>
+#include <sys/mnttab.h>
+#include <sys/mkdev.h>
+#include <libscf.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+#include "nautilus-global-preferences.h"
+#define ZFS_SNAPSHOT_DIR ".zfs/snapshot/"
+#define ZFS_BACKUP_DIR ".time-slider/rsync"
+
+char* ts_realpath (char * dir, char *resolved_name)
+{
+ char real_dir[PATH_MAX+1];
+ char real_path[PATH_MAX+1];
+ gboolean found = FALSE;
+ struct stat64 dir_stat64;
+ char *result;
+
+ result = realpath(dir, real_dir);
+
+ if (!result)
+ return NULL;
+
+ if (stat64 (real_dir, &dir_stat64) == 0)
+ {
+ if (strcmp (dir_stat64.st_fstype, "lofs") == 0)
+ {
+ FILE *fp;
+ struct extmnttab mtab;
+ int status;
+ fp = fopen (MNTTAB,"r");
+
+ resetmnttab(fp);
+ while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
+ {
+ if (strcmp (mtab.mnt_fstype, "lofs") == 0)
+ {
+ dev_t dev = NODEV;
+ dev = makedev(mtab.mnt_major, mtab.mnt_minor);
+ if (dev == dir_stat64.st_dev)
+ {
+ if (strcmp (real_dir, mtab.mnt_mountp) == 0)
+ strcpy (real_path, mtab.mnt_special);
+ else
+ {
+ gchar **split;
+ split = g_strsplit (real_dir, mtab.mnt_mountp, 2);
+ /*split 2nd part contains path without mount point */
+ sprintf (real_path,"%s%s",mtab.mnt_special,split[1]);
+ g_strfreev (split);
+ }
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ (void) fclose(fp);
+ }
+ }
+ if (found)
+ return strcpy (resolved_name, real_path);
+ else
+ return strcpy (resolved_name, real_dir);
+}
+
+static void ts_set_snapshot_used_space (zfs_handle_t *zhp, ZfsDataSet *snap)
+{
+ gchar buf[ZFS_MAXNAMELEN];
+ if (zfs_prop_get(zhp, ZFS_PROP_USED, buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0)
+ {
+ char unit[10];
+ char format_float[5] = "%f%s";
+ char format_int[5] = "%d%s";
+ char *format = format_int;
+ int used_space_int = 0;
+ gboolean success = FALSE;
+
+ snap->used_space_str = g_strdup (buf);
+
+ if (strchr (buf, '.'))
+ {
+ format = format_float;
+ if (sscanf(buf, format,&snap->used_space,unit) == 2)
+ success = TRUE;
+ }
+ else
+ {
+ if (sscanf(buf, format,&used_space_int,unit) == 2)
+ {
+ success = TRUE;
+ snap->used_space = (float) used_space_int;
+ }
+ }
+ if (strcmp (buf, "0") == 0)
+ {
+ g_free (snap->used_space_str);
+ snap->used_space_str = g_strdup ("0 K");
+ success = TRUE;
+ }
+
+ if (success)
+ {
+ if (strcmp (unit, "M") == 0)
+ snap->used_space *= 1024;
+ if (strcmp (unit, "G") == 0)
+ snap->used_space *= 1024 * 1024;
+ }
+ else
+ {
+ g_free (snap->used_space_str);
+ /* SUN_BRANDING */
+ snap->used_space_str = g_strdup (_("Unknown"));
+ }
+ }
+ else
+ {
+ g_free (snap->used_space_str);
+ /* SUN_BRANDING */
+ snap->used_space_str = g_strdup (_("Unknown"));
+ }
+}
+
+static void ts_set_snapshot_mtime_and_time_diff (zfs_handle_t *zhp, ZfsDataSet *snap)
+{
+ GDate now;
+ GDate then;
+ time_t time_now;
+ gint days_diff;
+ const gchar *format;
+ gchar *locale_format = NULL;
+ gchar buf[ZFS_MAXNAMELEN];
+ gchar *date_str = NULL;
+
+ if (zfs_prop_get(zhp, ZFS_PROP_CREATION, buf, sizeof (buf), NULL, NULL, 0, B_TRUE) == 0)
+ {
+ struct tm tms;
+
+ sscanf (buf, "%llu", &snap->mtime);
+ snap->mtime_str = nautilus_date_as_string (snap->mtime, FALSE);
+ }
+
+}
+
+void print_snap_list (char *dir, GList *snap_list)
+{
+ GList *tmp;
+ printf ("list of snapshots for %s :\n", dir);
+ for (tmp = snap_list; tmp->next; tmp = tmp->next)
+ {
+ ZfsDataSet *snap = (ZfsDataSet*) tmp->data;
+ printf (" name: %s\n mountpoint: %s\n mtime_str :%s\n space used : %s\n size in kilobytes : %f\n",
+ snap->name, snap->mountpoint, snap->mtime_str, snap->used_space_str, snap->used_space);
+
+ }
+ printf ("\n");
+}
+
+static GString *
+dump_zds (ZfsDataSet *zds)
+{
+ GString *msg;
+ gchar *type;
+
+ if (!zds)
+ return NULL;
+
+ msg = g_string_new ("");
+ g_string_printf (msg,
+ "\tname: %s\n"
+ "\tmountpoint: %s\n"
+ "\ttype: %s\n",
+ zds->name,zds->mountpoint, zfs_type_to_name(zds->type));
+ if (zds->snapshots)
+ {
+ GList *tmp;
+ g_string_append_printf(msg,"\tsnapshots :\n");
+ for (tmp=zds->snapshots;tmp;tmp = tmp->next)
+ {
+ ZfsDataSet *tmp_zds= (ZfsDataSet*) tmp->data;
+ g_string_append_printf (msg,"\t\tname: %s\n\t\tpath: %s\n",
+ tmp_zds->name,
+ tmp_zds->mountpoint);
+ }
+ }
+ g_string_append_printf (msg, "\n");
+ return msg;
+}
+
+
+static void
+dump_sds (SearchDataSet *sds)
+{
+ GString *msg;
+ gchar *type;
+ GList *tmp;
+
+ if (!sds)
+ {
+ printf ("Search DataSet is empty\n");
+ return;
+ }
+
+ msg = g_string_new ("");
+ g_string_printf (msg, "DDS Dump:\n"
+ "\tsearched_path: %s\n",
+ sds->searched_path);
+
+ g_string_append_printf (msg, "Zfs Data set :\n");
+ for (tmp=sds->datasets;tmp;tmp=tmp->next)
+ {
+ GString * zds_dump = dump_zds ((ZfsDataSet *)tmp->data);
+ g_string_append_printf (msg,"%s",zds_dump->str);
+ g_string_free (zds_dump, TRUE);
+ }
+ g_string_append_printf (msg, "\n");
+ printf ("%s", msg->str);
+ g_string_free (msg, TRUE);
+}
+
+static ZfsDataSet*
+ts_new_zfs_dataset (SearchDataSet* sds)
+{
+ ZfsDataSet *zds;
+ zds = g_new0 (ZfsDataSet, 1);
+ zds->search_dataset = sds;
+ return zds;
+}
+
+void
+ts_free_zfs_dataset (ZfsDataSet* zds)
+{
+ if (!zds)
+ return;
+ if (zds->name)
+ g_free (zds->name);
+ if (zds->mountpoint)
+ g_free (zds->mountpoint);
+ if (zds->mtime_str)
+ g_free (zds->mtime_str);
+ if (zds->used_space_str)
+ g_free (zds->used_space_str);
+
+ if (zds->snapshots)
+ {
+ GList *tmp;
+ for (tmp = zds->snapshots;tmp;tmp = tmp->next)
+ ts_free_zfs_dataset ((ZfsDataSet*)tmp->data);
+ }
+ g_free (zds);
+}
+
+static SearchDataSet *
+ts_new_search_dataset (GCancellable *cancel)
+{
+ SearchDataSet *sds;
+ sds = g_new0 (SearchDataSet, 1);
+ sds->cancel = cancel;
+ return sds;
+}
+static void
+ts_free_search_dataset (SearchDataSet *sds)
+{
+ if (!sds)
+ return;
+ if (sds->searched_path)
+ g_free (sds->searched_path);
+ if (sds->mountpoint)
+ g_free (sds->mountpoint);
+ if (sds->datasets)
+ {
+ GList *tmp;
+ for (tmp = sds->datasets;tmp;tmp = tmp->next)
+ ts_free_zfs_dataset ((ZfsDataSet*)tmp->data);
+ }
+ g_free (sds);
+}
+
+static char* construct_check_snapshot_path (SearchDataSet *sds, char* mountpoint, const char *name, char *searched_path)
+{
+ gchar *result = NULL;
+ gchar **split;
+ gchar **split2;
+
+ gchar *snap_name = NULL;
+ gchar *remaining_path = NULL;
+
+ /* get the snapshot name part pool@snap-name we are only interested in snap-name split[1] */
+ split = g_strsplit (name,"@",2);
+ /* get the path after the mountpoint */
+ split2 = g_strsplit (searched_path, mountpoint, 2);
+
+ if (split && split[1])
+ snap_name = split[1];
+
+ if (split2 && split2[1])
+ remaining_path = split2[1];
+
+/* printf ("mountpoint : %s \nname : %s \nsearched_path: %s\n", mountpoint, name, searched_path);
+ printf ("split %s at @ = [%s] [%s]\n", name, split[0],split[1]);
+ printf ("split %s at [%s] = [%s] [%s]\n", searched_path, mountpoint, split2[0],split2[1]);
+ printf ("%s/.zfs/snapshot/%s/%s\n\n", mountpoint, split[1], split2[1]);*/
+
+ if (snap_name && remaining_path)
+ result = g_strdup_printf ("%s/.zfs/snapshot/%s/%s", mountpoint, snap_name, remaining_path);
+
+ g_strfreev (split);
+ g_strfreev (split2);
+
+ /* don't test for file presence if searched path is the same as the mount point */
+ if (sds->searched_path_match_mp)
+ return result;
+
+ if (result && g_file_test (result, G_FILE_TEST_IS_DIR))
+ {
+ char real_dir[PATH_MAX+1];
+ if (!ts_realpath(result, real_dir))
+ {
+ g_free (result);
+ result = NULL;
+ }
+ else
+ {
+ g_free (result);
+ result = g_strdup (real_dir);
+ }
+ return result;
+ }
+
+ g_free (result);
+ return NULL;
+}
+
+static int
+snapshot_callback (zfs_handle_t *zhp, void *data)
+{
+ ZfsDataSet *main_zds = (ZfsDataSet*) data;
+
+ /* only add snapshot dir that exist */
+
+ if (zfs_get_type (zhp) == ZFS_TYPE_SNAPSHOT && !g_cancellable_is_cancelled (main_zds->search_dataset->cancel))
+ {
+ const char* name = zfs_get_name (zhp);
+ char *snap_path = construct_check_snapshot_path (main_zds->search_dataset,
+ main_zds->mountpoint,
+ name,
+ main_zds->search_dataset->searched_path);
+ if (snap_path)
+ {
+ ZfsDataSet *zds = ts_new_zfs_dataset (main_zds->search_dataset);
+ zds->name = g_strdup (name);
+ zds->type = ZFS_TYPE_SNAPSHOT;
+ zds->mountpoint = snap_path;
+ ts_set_snapshot_mtime_and_time_diff (zhp, zds);
+ ts_set_snapshot_used_space (zhp, zds);
+ main_zds->snapshots = g_list_append (main_zds->snapshots,zds);
+ }
+ }
+ zfs_close (zhp);
+ return 0;
+}
+
+
+static struct mnttab *
+mygetmntent(FILE *f)
+{
+ static struct mnttab mt;
+ int status;
+
+ if ((status = getmntent(f, &mt)) == 0)
+ return (&mt);
+
+ return (NULL);
+}
+
+static char *
+is_fs_mounted (const char *fs_name)
+{
+ FILE *mnttab;
+ struct mnttab *mntp;
+
+
+ mnttab = fopen (MNTTAB,"r");
+
+ while ((mntp = mygetmntent(mnttab)) != NULL)
+ {
+ if (mntp->mnt_fstype == (char *)0 || strcmp(mntp->mnt_fstype, "zfs") != 0)
+ continue;
+ if (strcmp (mntp->mnt_special, fs_name) == 0)
+ {
+ fclose (mnttab);
+ return g_strdup (mntp->mnt_mountp);
+ }
+ }
+ fclose (mnttab);
+ return NULL;
+}
+
+static char* rsync_get_smf_dir()
+{
+ char data_store[MAXPATHLEN];
+
+ int retval = -1;
+
+ scf_handle_t *handle = NULL;
+ scf_scope_t *sc = NULL;
+ scf_service_t *svc = NULL;
+ scf_instance_t *inst = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_iter_t *value_iter = NULL;
+
+
+ /* connect to the current SMF global repository */
+ handle = scf_handle_create(SCF_VERSION);
+
+ /* allocate scf resources */
+ sc = scf_scope_create(handle);
+ svc = scf_service_create(handle);
+ inst = scf_instance_create (handle);
+ pg = scf_pg_create(handle);
+ prop = scf_property_create(handle);
+ value = scf_value_create(handle);
+ value_iter = scf_iter_create(handle);
+
+ char *result = NULL;
+
+ /* if failed to allocate resources, exit */
+ if (handle == NULL || sc == NULL || svc == NULL || pg == NULL ||
+ prop == NULL || value == NULL || value_iter == NULL) {
+ /* scf handles allocation failed. */
+ goto out;
+ }
+
+ /* bind scf handle to the running svc.configd daemon */
+ if (scf_handle_bind(handle) == -1) {
+ /* scf binding failed. */
+ goto out;
+ }
+
+ /* get the scope of the localhost in the current repository */
+ if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) == -1) {
+ /* Getting scf scope failed.*/
+ goto out;
+ }
+
+ /* get the service within the scope */
+ if (scf_scope_get_service(sc, "application/time-slider/plugin", svc) == -1) {
+ /* failed getting service */
+ goto out;
+ }
+
+ /* get the instance within the service */
+ if (scf_service_get_instance(svc, "rsync", inst) == -1)
+ goto out;
+
+
+ /* get the property group within the instance */
+ if (scf_instance_get_pg(inst, "rsync", pg) == -1) {
+ /* Getting property group failed. */
+ goto out;
+ }
+
+ /*
+ * Now get the properties.
+ */
+ if (scf_pg_get_property(pg, "target_dir", prop) == -1) {
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ goto out;
+ }
+
+ data_store[0] = 0;
+ if (scf_value_get_astring(value, data_store, MAXPATHLEN) == -1) {
+ goto out;
+ }
+ else {
+ result = strdup (data_store);
+ }
+
+out:
+ /* destroy scf pointers */
+ if (value != NULL)
+ scf_value_destroy(value);
+ if (value_iter != NULL)
+ scf_iter_destroy(value_iter);
+ if (prop != NULL)
+ scf_property_destroy(prop);
+ if (pg != NULL)
+ scf_pg_destroy(pg);
+ if (inst != NULL)
+ scf_instance_destroy (inst);
+ if (svc != NULL)
+ scf_service_destroy(svc);
+ if (sc != NULL)
+ scf_scope_destroy(sc);
+ if (handle != NULL)
+ scf_handle_destroy(handle);
+
+ return result;
+}
+
+static char *rsync_get_dir (zfs_handle_t *zhp)
+{
+ nvlist_t *propval;
+
+ if (nvlist_lookup_nvlist(zfs_get_user_props(zhp),
+ "org.opensolaris:time-slider-rsync", &propval) == 0)
+ {
+ boolean_t ret_bool = FALSE;
+ char *strval;
+ char *dir;
+ nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
+
+ if (strcmp (strval, "true") == 0)
+ {
+ dir = rsync_get_smf_dir ();
+ if (dir)
+ return dir;
+ }
+ }
+ return NULL;
+}
+
+void sync_backups_add (zfs_handle_t *zhp, ZfsDataSet *main_zds)
+{
+ char *rsync_dir = rsync_get_dir (zhp);
+ DIR *d;
+ struct dirent *dir;
+ char *fs_rsync_dir;
+ struct utsname machine;
+
+ if (!rsync_dir)
+ return;
+
+ /* format SMF backup dir , TIMESLIDER, nodename from uname, path, .time-slider/rsync */
+ if (uname (&machine) == -1)
+ return;
+
+ fs_rsync_dir = g_strdup_printf ("%s/TIMESLIDER/%s/%s/%s/",
+ rsync_dir,
+ machine.nodename,
+ main_zds->name,
+ ZFS_BACKUP_DIR);
+
+ if (!g_file_test (fs_rsync_dir, G_FILE_TEST_IS_DIR))
+ {
+ g_free (rsync_dir);
+ g_free (fs_rsync_dir);
+ return;
+ }
+
+ d = opendir (fs_rsync_dir);
+
+ if (!d)
+ {
+ g_free (rsync_dir);
+ g_free (fs_rsync_dir);
+ return;
+ }
+
+ while ((dir = readdir (d)))
+ {
+ if (strstr (dir->d_name, "zfs-auto-snap_"))
+ { /* got a snap copy dir */
+ char **comma_split = NULL;
+ char **freq_split = NULL;
+ struct tm tms;
+ ZfsDataSet *zds = NULL;
+
+ /* extract creation time from dir name */
+ comma_split = g_strsplit (dir->d_name, "_", 2);
+ /* printf ("comma_split[1] = %s\n", comma_split[1]); */
+ freq_split = g_strsplit (comma_split[1], "-", 2);
+ /* printf ("freq_split[1] = %s\n", freq_split[1]); */
+
+ /* parse time string */
+ if (strptime (freq_split[1], "%Y-%m-%d-%Hh%M", &tms) != NULL)
+ {
+ zds = ts_new_zfs_dataset (main_zds->search_dataset);
+ zds->name = g_strdup (dir->d_name);
+ zds->type = NULL;
+ zds->mountpoint = g_strdup_printf ("%s%s/", fs_rsync_dir, dir->d_name);
+ zds->mtime = mktime (&tms);
+ zds->mtime_str = nautilus_date_as_string (zds->mtime, FALSE);
+ zds->used_space_str = g_strdup (_("Separate Backup"));
+ main_zds->snapshots = g_list_append (main_zds->snapshots,zds);
+ /* printf ("in sync_backups_add adding %s %s\n", zds->name, zds->mountpoint); */
+ }
+ if (comma_split)
+ g_strfreev (comma_split);
+ if (freq_split)
+ g_strfreev (freq_split);
+ }
+ }
+
+ closedir (d);
+ g_free (rsync_dir);
+}
+
+static int
+zfs_callback (zfs_handle_t *zhp, void *data)
+{
+ char buf[ZFS_MAXPROPLEN];
+ SearchDataSet *sds = (SearchDataSet*) data;
+
+ if (sds->match_found)
+ {
+ zfs_close (zhp);
+ return 0;
+ }
+
+ if (zfs_get_type (zhp) & sds->type & !g_cancellable_is_cancelled (sds->cancel))
+ {
+/* struct timespec ts;
+ ts.tv_sec = 3;
+ ts.tv_nsec = 100000000;
+ nanosleep (&ts, NULL);*/
+
+ if (sds->prop >= ZFS_PROP_TYPE && sds->prop < ZFS_NUM_PROPS)
+ {
+ zfs_prop_get(zhp, sds->prop, buf, sizeof (buf), NULL, NULL, 0, TRUE);
+
+ if (strcmp (sds->mountpoint, buf) == 0)
+ {
+ ZfsDataSet *zds = ts_new_zfs_dataset (sds);
+ zds->type = zfs_get_type (zhp);
+ zds->name = g_strdup (zfs_get_name(zhp));
+ zds->mountpoint = g_strdup (buf);
+ zfs_iter_snapshots (zhp, snapshot_callback, zds);
+ sync_backups_add (zhp, zds);
+ sds->datasets = g_list_append (sds->datasets, zds);
+ sds->match_found = TRUE;
+ }
+ else if (strcmp ("legacy", buf) == 0)
+ { /* parse /etc/mnttab to get the mount point */
+ char *mountp = is_fs_mounted (zfs_get_name(zhp));
+ if (mountp)
+ {
+ if (strcmp (sds->mountpoint, mountp) == 0)
+ {
+ ZfsDataSet *zds = ts_new_zfs_dataset (sds);
+ zds->type = zfs_get_type (zhp);
+ zds->name = g_strdup (zfs_get_name(zhp));
+ zds->mountpoint = mountp;
+ zfs_iter_snapshots (zhp, snapshot_callback, zds);
+ sync_backups_add (zhp, zds);
+ sds->datasets = g_list_append (sds->datasets, zds);
+ sds->match_found = TRUE;
+ }
+ else
+ g_free (mountp);
+ }
+ }
+ }
+ if (!sds->match_found)
+ zfs_iter_filesystems (zhp, zfs_callback, sds);
+ }
+ zfs_close (zhp);
+ return 0;
+}
+
+static SearchDataSet *
+ts_get_data_from_mountpoint (const char* searched_path, const char *mountpoint, GCancellable *cancel)
+{
+ static libzfs_handle_t *zfs_handle = NULL;
+ SearchDataSet *sds;
+
+ sds = ts_new_search_dataset (cancel);
+
+ sds->prop = ZFS_PROP_MOUNTPOINT;
+ sds->type = ZFS_TYPE_FILESYSTEM;
+ sds->searched_path = g_strdup (searched_path);
+ sds->mountpoint = g_strdup (mountpoint);
+
+ if (strcmp (searched_path, mountpoint) == 0)
+ sds->searched_path_match_mp = TRUE;
+
+ if (!zfs_handle)
+ {
+ if ((zfs_handle = libzfs_init()) == NULL) {
+ g_warning ("internal error: failed to initialize ZFS library\n");
+ ts_free_search_dataset (sds);
+ return NULL;
+ }
+ }
+ zfs_iter_root (zfs_handle, zfs_callback, sds);
+
+ return sds;
+}
+static gint
+snap_sort_by_age (gconstpointer a,
+ gconstpointer b)
+{
+ const ZfsDataSet *snap1 = a;
+ const ZfsDataSet *snap2 = b;
+
+ if (snap1->mtime == snap2->mtime)
+ return 0;
+ if (snap1->mtime < snap2->mtime)
+ return -1;
+ if (snap1->mtime > snap2->mtime)
+ return 1;
+
+}
+
+char*
+ts_get_zfs_filesystem (char *dir)
+{
+ char real_dir[PATH_MAX+1];
+ char filesystem[PATH_MAX+1];
+ gboolean found_fs= FALSE;
+ struct stat64 dir_stat64;
+
+ if (!ts_realpath(dir, real_dir))
+ {
+ return NULL;
+ }
+ if (stat64 (real_dir, &dir_stat64) == 0)
+ { /* check is fs is zfs */
+ if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
+ {
+ FILE *fp;
+ struct extmnttab mtab;
+ int status;
+
+ /* get mount point */
+
+ fp = fopen (MNTTAB,"r");
+
+ resetmnttab(fp);
+ while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
+ {
+ dev_t dev = NODEV;
+ dev = makedev(mtab.mnt_major, mtab.mnt_minor);
+ if (dev == dir_stat64.st_dev)
+ {
+ strcpy (filesystem, mtab.mnt_special);
+ found_fs = TRUE;
+ break;
+ }
+ }
+ (void) fclose(fp);
+ }
+ }
+ if (found_fs)
+ return g_strdup(filesystem);
+
+ return NULL;
+}
+
+static char * get_zfs_mountpoint (char *dir)
+{
+ char real_dir[PATH_MAX+1];
+ char mountpoint[PATH_MAX+1];
+ gboolean found_mount_point = FALSE;
+ struct stat64 dir_stat64;
+
+ if (!ts_realpath(dir, real_dir))
+ {
+ return NULL;
+ }
+ if (stat64 (real_dir, &dir_stat64) == 0)
+ { /* check is fs is zfs */
+ if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
+ {
+ FILE *fp;
+ struct extmnttab mtab;
+ int status;
+
+ /* get mount point */
+
+ fp = fopen (MNTTAB,"r");
+
+ resetmnttab(fp);
+ while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
+ {
+ dev_t dev = NODEV;
+ dev = makedev(mtab.mnt_major, mtab.mnt_minor);
+ if (dev == dir_stat64.st_dev)
+ {
+ strcpy (mountpoint, mtab.mnt_mountp);
+ found_mount_point = TRUE;
+ break;
+ }
+ }
+ (void) fclose(fp);
+ }
+ }
+ if (found_mount_point)
+ return g_strdup(mountpoint);
+
+ return NULL;
+}
+
+
+char *ts_get_snapshot_dir (char *dir)
+{
+ char *zfs_dir = get_zfs_mountpoint (dir);
+ if (zfs_dir)
+ {
+ char *snapshot_dir = g_strdup_printf ("%s/.zfs/snapshot", zfs_dir);
+ g_free (zfs_dir);
+ return snapshot_dir;
+ }
+ else
+ return NULL;
+}
+
+
+
+static void ts_get_snapshots_for_dir (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ char *mountpoint = NULL;
+ char real_dir[PATH_MAX+1];
+ SearchDataSet *sds;
+ GList* snap_result = NULL;
+ GFile *file = G_FILE (object);
+ char *dir = g_file_get_path (file);
+
+ mountpoint = get_zfs_mountpoint (dir);
+
+
+ if (!mountpoint)
+ {
+ g_simple_async_result_set_op_res_gpointer (res, snap_result, (GDestroyNotify) NULL);
+ g_free (dir);
+ return;
+ }
+
+ ts_realpath(dir, real_dir);
+
+ sds = ts_get_data_from_mountpoint (real_dir, mountpoint, cancellable);
+
+ g_free (mountpoint);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ /* printf ("ts_get_snapshots_for_dir %s cancelled\n", dir); */
+ if (sds)
+ {
+ ts_free_search_dataset (sds);
+ sds = NULL;
+ }
+ }
+
+ if (sds)
+ {
+ GList *tmp;
+ for (tmp=sds->datasets;tmp;tmp=tmp->next)
+ {
+ ZfsDataSet *zds = (ZfsDataSet*) tmp->data;
+ if (zds->snapshots)
+ {
+ snap_result = g_list_concat (snap_result, zds->snapshots);
+ zds->snapshots = NULL;
+ }
+ }
+ ts_free_search_dataset (sds);
+ }
+
+ if (snap_result)
+ {
+ snap_result = g_list_sort (snap_result, (GCompareFunc)snap_sort_by_age);
+ /* print_snap_list (dir, snap_result); */
+ }
+
+ g_free (dir);
+ g_simple_async_result_set_op_res_gpointer (res, snap_result, (GDestroyNotify) NULL);
+}
+
+
+GList *ts_get_snapshots_for_dir_async (GFile *file,
+ GAsyncReadyCallback result_ready,
+ GCancellable *cancel,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (file), result_ready, user_data, (gpointer) ts_get_snapshots_for_dir);
+ g_simple_async_result_run_in_thread (res, ts_get_snapshots_for_dir, G_PRIORITY_DEFAULT, cancel);
+ return NULL;
+}
+
+
+void ts_free_snapshots (GList *snaps)
+{
+ if (snaps)
+ {
+ GList *tmp;
+ for (tmp=snaps;tmp;tmp=tmp->next)
+ ts_free_zfs_dataset ((ZfsDataSet*) tmp->data);
+ g_list_free (snaps);
+ }
+}
+
+gboolean ts_is_in_remote_backup (char *str)
+{
+ if (str != NULL)
+ {
+ if (g_strrstr (str, ZFS_BACKUP_DIR))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+gboolean ts_is_in_snapshot (char * str)
+{
+ if (str != NULL)
+ {
+ if (g_strrstr (str, ZFS_SNAPSHOT_DIR))
+ return TRUE;
+ if (g_strrstr (str, ZFS_BACKUP_DIR))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+char* ts_remove_snapshot_dir (char *str)
+{
+ if (ts_is_in_snapshot (str))
+ {
+ char *snap_root;
+ char *zfs, *iter, point;
+ int count = 0;
+
+ /*remove .zfs/snapshot/blah/ */
+ zfs = g_strrstr (str, ZFS_SNAPSHOT_DIR);
+ iter = zfs;
+
+ if (iter)
+ {
+ iter += sizeof (ZFS_SNAPSHOT_DIR);
+ while (*iter != '/' && *iter != '\0')
+ iter++;
+
+ if (*iter == '/')
+ iter++;
+
+ point = *zfs;
+ *zfs = '\0';
+ snap_root = g_strdup_printf ("%s%s", str, iter);
+
+ *zfs = point;
+ return snap_root;
+ }
+ }
+ return NULL;
+}
+
+
+static gboolean restore_col_enabled = FALSE;
+
+gboolean
+ts_is_restore_column_enabled ()
+{
+ return restore_col_enabled;
+}
+
+void ts_is_restore_column_enabled_init ();
+
+static void
+visible_columns_changed (gpointer callback_data)
+{
+ ts_is_restore_column_enabled_init ();
+}
+
+
+void ts_is_restore_column_enabled_init ()
+{
+ char **visible_columns;
+ static gboolean init = FALSE;
+ int i = 0;
+
+ if (!init)
+ {
+ g_signal_connect_swapped(nautilus_preferences,
+ "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
+ G_CALLBACK(visible_columns_changed), NULL);
+ init = TRUE;
+ }
+
+ restore_col_enabled = FALSE;
+
+ visible_columns = g_settings_get_strv (nautilus_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
+
+ while (visible_columns[i])
+ {
+ if (strcmp (visible_columns [i], "restore_info") == 0)
+ {
+ restore_col_enabled = TRUE;
+ break;
+ }
+ i++;
+ }
+ g_strfreev (visible_columns);
+}
+
+
+static GList * get_dir_entries (char *dir_path)
+{
+ const char *entry_name;
+ GDir *dir;
+ GList *dir_entries = NULL;
+ dir = g_dir_open (dir_path, 0, NULL);
+
+ while ((entry_name = g_dir_read_name (dir)) != NULL)
+ dir_entries = g_list_prepend (dir_entries, g_strdup (entry_name));
+
+ g_dir_close (dir);
+
+ return dir_entries;
+}
+
+static void free_dir_entries (GList *entries)
+{
+ g_list_foreach (entries, (GFunc)g_free, NULL);
+ g_list_free (entries);
+}
+
+static gboolean are_entries_identical (GList *old, GList *new)
+{
+ if (g_list_length (old) != g_list_length (new))
+ return FALSE;
+
+ for (old; old; old = old->next)
+ {
+ gboolean found = FALSE;
+ for (new; new; new = new->next)
+ {
+ if (strcmp (old->data, new->data) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void monitor_zfs_snap_directory_cancel (ZfsSnapDirMonitor *monitor_data)
+{
+ if (monitor_data)
+ {
+ /* printf ("in monitor_zfs_snap_directory_cancel %s\n", monitor_data->path); */
+ g_source_remove (monitor_data->timeout_id);
+ free_dir_entries (monitor_data->entries);
+ g_free (monitor_data->path);
+ g_free (monitor_data);
+ }
+}
+
+static gboolean
+monitor_snap_dir (ZfsSnapDirMonitor *monitor_data)
+{
+ GList *new_entries;
+
+ if (!g_file_test (monitor_data->path, G_FILE_TEST_IS_DIR))
+ {
+ monitor_zfs_snap_directory_cancel (monitor_data);
+ return TRUE;
+ }
+
+ new_entries = get_dir_entries (monitor_data->path);
+
+ if (are_entries_identical (monitor_data->entries, new_entries))
+ {
+ free_dir_entries (new_entries);
+ }
+ else
+ {
+ free_dir_entries (monitor_data->entries);
+ monitor_data->entries = new_entries;
+ monitor_data->change_callback (monitor_data, monitor_data->user_data);
+ }
+
+ if (monitor_data->backup_path)
+ {
+ if (!g_file_test (monitor_data->backup_path, G_FILE_TEST_IS_DIR))
+ {
+ monitor_zfs_snap_directory_cancel (monitor_data);
+ return TRUE;
+ }
+
+ new_entries = get_dir_entries (monitor_data->backup_path);
+
+ if (are_entries_identical (monitor_data->backup_entries, new_entries))
+ {
+ free_dir_entries (new_entries);
+ }
+ else
+ {
+ free_dir_entries (monitor_data->backup_entries);
+ monitor_data->backup_entries = new_entries;
+ monitor_data->change_callback (monitor_data, monitor_data->user_data);
+ }
+ }
+ return TRUE;
+}
+
+
+ZfsSnapDirMonitor *monitor_zfs_snap_directory (char *path,
+ char *backup_path,
+ ZfsDirChangeCallback change_callback,
+ gpointer data)
+{
+ ZfsSnapDirMonitor *monitor_data = g_new0 (ZfsSnapDirMonitor, 1);
+
+ /* printf ("start monitoring %s\n", path); */
+
+ monitor_data->path = g_strdup (path);
+ monitor_data->entries = get_dir_entries (path);
+ if (backup_path)
+ {
+ monitor_data->backup_path = g_strdup (backup_path);
+ monitor_data->backup_entries = get_dir_entries (backup_path);
+ }
+ monitor_data->change_callback = change_callback;
+ monitor_data->user_data = data;
+
+ monitor_data->timeout_id = g_timeout_add_seconds (5, (GSourceFunc)monitor_snap_dir, monitor_data);
+ return monitor_data;
+}
+
+char *
+ts_get_not_zfs_snapshot_dir (GFile *file)
+{
+ char tmp_path[PATH_MAX + 1];
+ gboolean found = FALSE;
+ gboolean end_path = FALSE;
+ GFile *d = g_file_get_parent(file);
+ GFile *tmp;
+ char *full_path = g_file_get_path (file);
+ char *stripped_path = g_file_get_path (d);
+ struct stat64 dir_stat64;
+
+ if (!full_path)
+ return NULL;
+
+ if (stat64 (full_path, &dir_stat64) == 0)
+ { /* check is fs is zfs if so don't try to check for nfs mounted .zfs dir*/
+ if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
+ end_path = TRUE;
+ }
+
+ while (!found && !end_path)
+ {
+ g_sprintf (tmp_path, "%s/.zfs/snapshot", stripped_path);
+ if (g_file_test (tmp_path, G_FILE_TEST_IS_DIR))
+ {
+ GList *entries = get_dir_entries (tmp_path);
+ if (entries != NULL)
+ {
+ char *after_snap_path = full_path + strlen (stripped_path);
+
+ for (entries; entries; entries = entries->next)
+ {
+ char test_path[PATH_MAX +1];
+ g_sprintf (test_path, "%s/%s/%s", tmp_path,
+ entries->data,
+ after_snap_path);
+ if (g_file_test (test_path, G_FILE_TEST_EXISTS))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ free_dir_entries (entries);
+ }
+ }
+ tmp = d;
+ d = g_file_get_parent (tmp);
+ g_object_unref (tmp);
+ g_free (stripped_path);
+ stripped_path=NULL;
+ if (d == NULL)
+ {
+ end_path = TRUE;
+ }
+ else
+ {
+ stripped_path = g_file_get_path (d);
+ }
+ }
+
+ g_free (full_path);
+
+ if (stripped_path)
+ g_free (stripped_path);
+
+ if (found)
+ return g_strdup (tmp_path);
+ else
+ return NULL;
+
+}
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-zfs.h nautilus-2.30.1/libnautilus-private/nautilus-zfs.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/libnautilus-private/nautilus-zfs.h 1970-01-01 01:00:00.000000000 +0100
+++ nautilus-2.30.1/libnautilus-private/nautilus-zfs.h 2010-05-14 17:17:27.383965864 +0200
@@ -0,0 +1,77 @@
+/* #include <config.h> */
+#ifndef NAUTILUS_ZFS_H
+#define NAUTILUS_ZFS_H
+
+#include <glib.h>
+#include <libzfs.h>
+#include <gio/gio.h>
+
+typedef struct
+{
+ zfs_type_t type;
+ zfs_prop_t prop;
+ char *searched_path;
+ char *mountpoint;
+ GList *datasets;
+ GCancellable *cancel;
+ gboolean match_found;
+ gboolean searched_path_match_mp;
+
+} SearchDataSet;
+
+typedef struct
+{
+ char *name;
+ char *mountpoint;
+ char *mtime_str;
+ time_t mtime;
+ float used_space;
+ char *used_space_str;
+ zfs_type_t type;
+ GList *snapshots;
+ SearchDataSet *search_dataset;
+} ZfsDataSet;
+
+
+GList *ts_get_snapshots_for_dir_async (GFile *file,
+ GAsyncReadyCallback result_ready,
+ GCancellable *cancel,
+ gpointer user_data);
+void ts_free_snapshots (GList *snaps);
+void ts_free_zfs_dataset (ZfsDataSet* zds);
+
+gboolean ts_is_in_snapshot (char * str);
+gboolean ts_is_in_remote_backup (char *str);
+char* ts_remove_snapshot_dir (char *str);
+char *ts_get_snapshot_dir (char *dir);
+char *ts_get_zfs_filesystem (char *dir);
+char * ts_get_not_zfs_snapshot_dir (GFile *file);
+gboolean ts_is_restore_column_enabled ();
+void ts_is_restore_column_enabled_init ();
+void print_snap_list (char *dir, GList *snap_list);
+char* ts_realpath (char * dir, char *resolved_name);
+
+char *
+nautilus_date_as_string (time_t time_raw, gboolean use_smallest);
+
+typedef void (*ZfsDirChangeCallback) (gpointer monitor_data,
+ gpointer user_data);
+
+typedef struct
+{
+ char * path;
+ GList *entries;
+ char * backup_path;
+ GList *backup_entries;
+ guint timeout_id;
+ ZfsDirChangeCallback change_callback;
+ gpointer user_data;
+} ZfsSnapDirMonitor;
+
+void monitor_zfs_snap_directory_cancel (ZfsSnapDirMonitor *monitor_data);
+ZfsSnapDirMonitor *monitor_zfs_snap_directory (char *path,
+ char *backup_path,
+ ZfsDirChangeCallback change_callback,
+ gpointer data);
+#endif /* NAUTILUS_ZFS_H */
+
--- nautilus-3.1.3/src/Makefile.am.orig 2011-07-01 17:50:32.000000000 +0100
+++ nautilus-3.1.3/src/Makefile.am 2011-07-22 10:47:37.617231822 +0100
@@ -41,6 +41,8 @@
$(EXIF_LIBS) \
$(EXEMPI_LIBS) \
$(POPT_LIBS) \
+ $(SCF_LIBS) \
+ $(NVPAIR_LIBS) \
$(NULL)
nautilus_SOURCES = \
@@ -142,6 +144,10 @@
nautilus-window-types.h \
nautilus-x-content-bar.c \
nautilus-x-content-bar.h \
+ nautilus-zfs-bar.c \
+ nautilus-zfs-bar.h \
+ timescale.c \
+ timescale.h \
$(NULL)
EMPTY_VIEW_SOURCES = \
--- nautilus-3.1.3/src/nautilus-actions.h.orig 2011-07-22 10:54:06.075754016 +0100
+++ nautilus-3.1.3/src/nautilus-actions.h 2011-07-22 10:56:03.673858543 +0100
@@ -85,6 +85,9 @@
#define NAUTILUS_ACTION_NEW_LAUNCHER "New Launcher"
#define NAUTILUS_ACTION_NEW_LAUNCHER_DESKTOP "New Launcher Desktop"
#define NAUTILUS_ACTION_RENAME "Rename"
+#define NAUTILUS_ACTION_RESTORE_TO "Restore to"
+#define NAUTILUS_ACTION_HAS_SNAPSHOT "View Snap"
+#define NAUTILUS_ACTION_SNAP_NOW "Snap Now"
#define NAUTILUS_ACTION_DUPLICATE "Duplicate"
#define NAUTILUS_ACTION_CREATE_LINK "Create Link"
#define NAUTILUS_ACTION_SELECT_ALL "Select All"
--- nautilus-3.1.3/src/nautilus-view.c.orig 2011-07-25 14:46:18.267955464 +0100
+++ nautilus-3.1.3/src/nautilus-view.c 2011-07-25 14:45:21.541051018 +0100
@@ -1366,6 +1366,73 @@
}
static void
+action_snap_now (GtkAction *action,
+ gpointer callback_data)
+{
+ NautilusView *view = NAUTILUS_VIEW (callback_data);
+ GList *selection = nautilus_view_get_selection_for_file_transfer (view);
+ GFile *file = nautilus_file_get_location (NAUTILUS_FILE (selection->data));
+ char *path = g_file_get_path (file);
+ char *fs = ts_get_zfs_filesystem (path);
+ char *cmd = g_strdup_printf ("/usr/lib/time-slider-snapshot '%s' '%s'", path, fs);
+ nautilus_launch_application_from_command (gtk_window_get_screen (GTK_WIDGET(callback_data)), cmd, FALSE, NULL);
+
+ g_free (cmd);
+ g_free (fs);
+ g_free (path);
+ g_object_unref (file);
+}
+
+static void
+action_restore_to_desktop_callback (GtkAction *action,
+ gpointer callback_data)
+{
+ GList *locations = NULL;
+ GList *node;
+ NautilusView *view = NAUTILUS_VIEW (callback_data);
+ char *desktop_directory = nautilus_get_desktop_directory_uri();
+ GList *selection = nautilus_view_get_selection_for_file_transfer (view);
+
+ if (selection == NULL)
+ return;
+
+ if (desktop_directory == NULL)
+ return;
+
+
+ for (node = selection; node != NULL; node = node->next) {
+ locations = g_list_prepend (locations,
+ nautilus_file_get_uri ((NautilusFile *) node->data));
+ }
+
+ nautilus_view_move_copy_items (locations, NULL, desktop_directory,
+ GDK_ACTION_COPY, 0, 0, view);
+
+ nautilus_file_list_free (selection);
+}
+
+static void
+action_show_snapshot_versions_callback (GtkAction *action,
+ gpointer callback_data)
+{
+ NautilusView *view = NAUTILUS_VIEW (callback_data);
+ GList *selection = nautilus_view_get_selection_for_file_transfer (view);
+ GFile *file = nautilus_file_get_location (NAUTILUS_FILE (selection->data));
+ char *dir = nautilus_file_get_snapshot_dir (NAUTILUS_FILE (selection->data));
+ char *file_path = g_file_get_path (file);
+ char real_file_path [PATH_MAX + 1];
+ if (ts_realpath (file_path, real_file_path)) {
+ char *cmd = g_strdup_printf ("/usr/lib/time-slider-version '%s' '%s'", dir,
+ real_file_path);
+ nautilus_launch_application_from_command (gtk_window_get_screen (GTK_WIDGET(callback_data)), cmd, FALSE, NULL);
+ g_free (cmd);
+ }
+
+ g_free (file_path);
+ g_object_unref (file);
+}
+
+static void
action_trash_callback (GtkAction *action,
gpointer callback_data)
{
@@ -7076,6 +7143,24 @@
/* label, accelerator */ "RenameSelectAll", "<shift>F2",
/* tooltip */ NULL,
G_CALLBACK (action_rename_select_all_callback) },
+ /* name, stock id */ { "Restore to", NULL,
+ /* SUN_BRANDING */
+ /* label, accelerator */ N_("Restore to Desktop"), NULL,
+ /* SUN_BRANDING */
+ /* tooltip */ N_("Move each selected item to the Desktop"),
+ G_CALLBACK (action_restore_to_desktop_callback) },
+ /* name, stock id */ { "View Snap", NULL,
+ /* SUN_BRANDING */
+ /* label, accelerator */ N_("View versions"), NULL,
+ /* SUN_BRANDING */
+ /* tooltip */ N_("View the versions of this file available in ZFS snapshots"),
+ G_CALLBACK (action_show_snapshot_versions_callback) },
+ /* name, stock id */ { "Snap Now", NULL,
+ /* SUN_BRANDING */
+ /* label, accelerator */ N_("Snapshot now"), NULL,
+ /* SUN_BRANDING */
+ /* tooltip */ N_("Take a ZFS snapshot of this directory now"),
+ G_CALLBACK (action_snap_now) },
/* name, stock id */ { "Trash", NULL,
/* label, accelerator */ N_("Mo_ve to Trash"), "<control>Delete",
/* tooltip */ N_("Move each selected item to the Trash"),
@@ -8294,6 +8379,41 @@
return FALSE;
}
+typedef struct {
+ NautilusFile *file;
+ GCancellable *cancel;
+ GtkAction *action;
+} HasSnapshotData;
+
+static void
+has_snapshot_ready_callback (gpointer user_data)
+{
+ GValue name = {0,};
+ HasSnapshotData *data = (HasSnapshotData*) user_data;
+ HasSnapshotResult result = nautilus_file_has_snapshot_version (data->file);
+
+ switch (result)
+ {
+ case UNKNOWN_STATE:
+ case NO:
+ gtk_action_set_sensitive (data->action, FALSE);
+ g_value_init (&name, G_TYPE_STRING);
+ /* SUN_BRANDING */
+ g_value_set_static_string (&name, _("No versions"));
+ g_object_set_property (G_OBJECT (data->action), "label", &name);
+ break;
+ case YES:
+ gtk_action_set_sensitive (data->action, TRUE);
+ g_value_init (&name, G_TYPE_STRING);
+ /* SUN_BRANDING */
+ g_value_set_static_string (&name, _("Explore versions"));
+ g_object_set_property (G_OBJECT (data->action), "label", &name);
+ break;
+ }
+ g_free (data);
+ }
+
+
static void
real_update_menus (NautilusView *view)
{
@@ -8609,6 +8729,74 @@
NAUTILUS_ACTION_COPY);
gtk_action_set_sensitive (action, can_copy_files);
+ action = gtk_action_group_get_action (view->details->dir_action_group,
+ NAUTILUS_ACTION_RESTORE_TO);
+ gtk_action_set_visible (action, can_copy_files &&
+ nautilus_directory_is_in_snapshot (view->details->model));
+
+ action = gtk_action_group_get_action (view->details->dir_action_group,
+ NAUTILUS_ACTION_SNAP_NOW);
+
+ if (selection_count == 1 && nautilus_file_is_directory (NAUTILUS_FILE (selection->data)))
+ {
+ GFile *file = nautilus_file_get_location (NAUTILUS_FILE (selection->data));
+ char *path = g_file_get_path (file);
+ char *fs = ts_get_zfs_filesystem (path);
+ if (fs)
+ {
+ gtk_action_set_visible (action, TRUE);
+ g_free (fs);
+ }
+ g_free (path);
+ g_object_unref (file);
+ }
+ else
+ gtk_action_set_visible (action, FALSE);
+
+ action = gtk_action_group_get_action (view->details->dir_action_group,
+ NAUTILUS_ACTION_HAS_SNAPSHOT);
+ if (selection_count == 1)
+ {
+ GValue name = { 0, };
+ int result = nautilus_file_has_snapshot_version (NAUTILUS_FILE (selection->data));
+
+ switch (result)
+ {
+ case NO:
+ gtk_action_set_visible (action, FALSE);
+ break;
+ case YES:
+ gtk_action_set_visible (action, TRUE);
+ gtk_action_set_sensitive (action, TRUE);
+ g_value_init (&name,G_TYPE_STRING);
+ /* SUN_BRANDING */
+ g_value_set_static_string (&name, _("Explore versions"));
+ g_object_set_property (G_OBJECT (action), "label", &name);
+ break;
+ case UNKNOWN_STATE:
+ gtk_action_set_visible (action, TRUE);
+ gtk_action_set_sensitive (action, FALSE);
+ g_value_init (&name,G_TYPE_STRING);
+ /* SUN_BRANDING */
+ g_value_set_static_string (&name, _("Scanning for versions"));
+ g_object_set_property (G_OBJECT (action), "label", &name);
+ break;
+ }
+ if (result == UNKNOWN_STATE)
+ {
+ HasSnapshotData *data = g_new0 (HasSnapshotData, 1);
+ data->action = action;
+ data->file = NAUTILUS_FILE (selection->data);
+ data->cancel = g_cancellable_new ();
+ nautilus_file_get_snapshot_version (NAUTILUS_FILE (selection->data),
+ has_snapshot_ready_callback,
+ data->cancel,
+ data);
+ }
+ }
+ else
+ gtk_action_set_visible (action, FALSE);
+
real_update_paste_menu (view, selection, selection_count);
disable_command_line = g_settings_get_boolean (gnome_lockdown_preferences, NAUTILUS_PREFERENCES_LOCKDOWN_COMMAND_LINE);
--- nautilus-3.1.3/src/nautilus-directory-view-ui.xml.orig 2011-07-22 11:25:04.446118499 +0100
+++ nautilus-3.1.3/src/nautilus-directory-view-ui.xml 2011-07-22 11:32:36.728336937 +0100
@@ -66,6 +66,9 @@
<menuitem name="Duplicate" action="Duplicate"/>
<menuitem name="Create Link" action="Create Link"/>
<menuitem name="Rename" action="Rename"/>
+ <menuitem name="Restore to" action="Restore to"/>
+ <menuitem name="Snapshot now" action="Snap Now"/>
+ <menuitem name="Scanning...." action="View Snap"/>
<menu action="CopyToMenu">
<menuitem name="Copy to next pane" action="Copy to next pane"/>
<menuitem name="Copy to Home" action="Copy to Home"/>
@@ -161,6 +164,9 @@
<menuitem name="Create Link" action="Create Link"/>
<menuitem name="Rename" action="Rename"/>
<menu action="CopyToMenu">
+ <menuitem name="Restore to" action="Restore to"/>
+ <menuitem name="Snapshot now" action="Snap Now"/>
+ <menuitem name="Scanning...." action="View Snap"/>
<menuitem name="Copy to next pane" action="Copy to next pane"/>
<menuitem name="Copy to Home" action="Copy to Home"/>
<menuitem name="Copy to Desktop" action="Copy to Desktop"/>
@@ -173,6 +179,7 @@
</placeholder>
<separator name="Dangerous separator"/>
<placeholder name="Dangerous File Actions">
+ <menuitem name="Restore" action="Restore"/>
<menuitem name="Trash" action="Trash"/>
<menuitem name="Delete" action="Delete"/>
<menuitem name="Restore From Trash" action="Restore From Trash"/>
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-actions.h nautilus-2.30.1/src/nautilus-actions.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-actions.h 2010-01-22 16:45:17.000000000 +0100
+++ nautilus-2.30.1/src/nautilus-actions.h 2010-05-14 17:16:39.557199636 +0200
@@ -28,6 +28,7 @@
#define NAUTILUS_ACTION_STOP "Stop"
#define NAUTILUS_ACTION_RELOAD "Reload"
+#define NAUTILUS_ACTION_RESTORE "Restore"
#define NAUTILUS_ACTION_BACK "Back"
#define NAUTILUS_ACTION_UP "Up"
#define NAUTILUS_ACTION_UP_ACCEL "UpAccel"
--- nautilus-3.1.3/src/nautilus-file-management-properties.c.orig 2011-04-25 18:02:09.000000000 +0100
+++ nautilus-3.1.3/src/nautilus-file-management-properties.c 2011-07-22 11:42:27.957358494 +0100
@@ -62,6 +62,7 @@
#define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_OPEN_NEW_WINDOW_WIDGET "new_window_checkbutton"
#define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_SHOW_HIDDEN_WIDGET "hidden_files_checkbutton"
#define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_TREE_VIEW_FOLDERS_WIDGET "treeview_folders_checkbutton"
+#define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_ENABLE_TIME_SLIDER "time_slider_enabled_checkbutton"
/* int enums */
#define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_THUMBNAIL_LIMIT_WIDGET "preview_image_size_combobox"
@@ -749,6 +750,10 @@
NAUTILUS_FILE_MANAGEMENT_PROPERTIES_TREE_VIEW_FOLDERS_WIDGET,
NAUTILUS_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES);
+ bind_builder_bool (builder, nautilus_tree_sidebar_preferences,
+ NAUTILUS_FILE_MANAGEMENT_PROPERTIES_ENABLE_TIME_SLIDER,
+ NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER);
+
bind_builder_enum (builder, nautilus_preferences,
NAUTILUS_FILE_MANAGEMENT_PROPERTIES_DEFAULT_VIEW_WIDGET,
NAUTILUS_PREFERENCES_DEFAULT_FOLDER_VIEWER,
--- nautilus-3.1.3/src/nautilus-shell-ui.xml.orig 2011-07-22 13:50:25.148071442 +0100
+++ nautilus-3.1.3/src/nautilus-shell-ui.xml 2011-07-22 13:57:43.720949058 +0100
@@ -53,6 +53,7 @@
<menu action="View">
<menuitem name="Stop" action="Stop"/>
<menuitem name="Reload" action="Reload"/>
+ <menuitem name="Restore" action="Restore"/>
<separator/>
<placeholder name="Show Hide Placeholder">
<menu action="Sidebar List">
--- nautilus-3.1.3/src/nautilus-window-manage-views.c.orig 2011-07-25 08:16:41.926463390 +0100
+++ nautilus-3.1.3/src/nautilus-window-manage-views.c 2011-07-25 08:49:32.039217259 +0100
@@ -39,6 +39,7 @@
#include "nautilus-trash-bar.h"
#include "nautilus-view-factory.h"
#include "nautilus-x-content-bar.h"
+#include "nautilus-zfs-bar.h"
#include <eel/eel-accessibility.h>
#include <eel/eel-debug.h>
#include <eel/eel-gdk-extensions.h>
@@ -50,6 +51,7 @@
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <glib/gi18n.h>
+#include <stdlib.h>
#include <libnautilus-extension/nautilus-location-widget-provider.h>
#include <libnautilus-private/nautilus-file-attributes.h>
#include <libnautilus-private/nautilus-file-utilities.h>
@@ -693,7 +695,9 @@
NautilusFile *file;
gboolean force_reload;
char *current_pos;
+ GFile *old_file = NULL;
GFile *from_folder, *parent;
+ NautilusWindow *window;
g_assert (slot != NULL);
g_assert (location != NULL);
@@ -722,12 +726,43 @@
end_location_change (slot);
+ old_file = nautilus_window_slot_get_location (slot);
+ if (old_file) {
+ directory = nautilus_directory_get (old_file);
+ if (directory) {
+ nautilus_directory_cancel_restore_info (directory);
+ g_object_unref (directory);
+ directory = NULL;
+ }
+ g_object_unref (old_file);
+ old_file = NULL;
+ }
+
nautilus_window_slot_set_allow_stop (slot, TRUE);
nautilus_window_slot_set_status (slot, " ", NULL);
g_assert (slot->pending_location == NULL);
g_assert (slot->pending_selection == NULL);
+ directory = nautilus_directory_get (location);
+
+ window = slot->pane->window;
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ /* if snap and (ts is enabled and displayed )
+ * check if the directory exist
+ * if it doesn't move to the next available one */
+ if (nautilus_directory_is_in_snapshot (directory) && is_time_slider_enabled ()) {
+ if (gtk_widget_get_visible (window->details->zfs_bar)) {
+ char *path = g_file_get_path (location);
+ if (!g_file_test (path, G_FILE_TEST_IS_DIR)) {
+ nautilus_zfs_bar_remove_and_skip_snap (NAUTILUS_ZFS_BAR (window->details->zfs_bar), path);
+ g_free (path);
+ return;
+ }
+ g_free (path);
+ }
+ }
+
slot->pending_location = g_object_ref (location);
slot->location_change_type = type;
slot->location_change_distance = distance;
@@ -739,8 +774,6 @@
slot->open_callback = callback;
slot->open_callback_user_data = user_data;
- directory = nautilus_directory_get (location);
-
/* The code to force a reload is here because if we do it
* after determining an initial view (in the components), then
* we end up fetching things twice.
@@ -919,8 +952,17 @@
/* If fallback, don't use view from metadata */
if (slot->location_change_type != NAUTILUS_LOCATION_CHANGE_FALLBACK) {
/* Look in metadata for view */
- view_id = nautilus_file_get_metadata
- (file, NAUTILUS_METADATA_KEY_DEFAULT_VIEW, NULL);
+ if (nautilus_file_is_in_snapshot (file))
+ {
+ NautilusDirectory* root_dir = nautilus_zfs_bar_get_dir (NAUTILUS_ZFS_BAR (window->details->zfs_bar));
+ if (root_dir)
+ view_id = nautilus_file_get_metadata (nautilus_directory_get_corresponding_file (root_dir),
+ NAUTILUS_METADATA_KEY_DEFAULT_VIEW, NULL);
+ }
+ if (view_id == NULL)
+ view_id = nautilus_file_get_metadata
+ (file, NAUTILUS_METADATA_KEY_DEFAULT_VIEW, NULL);
+
if (view_id != NULL &&
!nautilus_view_factory_view_supports_uri (view_id,
location,
@@ -1495,6 +1537,30 @@
/* Load menus from nautilus extensions for this location */
nautilus_window_load_extension_menus (window);
}
+
+ /* time slider pref can be just enabled so we need
+ * to rescan for snapshots */
+ directory = nautilus_directory_get (slot->location);
+
+ if (window)
+ {
+ if (slot->find_zfs_snapshots_cancellable != NULL)
+ {
+ g_cancellable_cancel (slot->find_zfs_snapshots_cancellable);
+ slot->find_zfs_snapshots_cancellable = NULL;
+ }
+ slot->find_zfs_snapshots_cancellable = g_cancellable_new ();
+ nautilus_zfs_bar_display (NAUTILUS_ZFS_BAR (window->details->zfs_bar),
+ window,
+ directory,
+ slot->find_zfs_snapshots_cancellable);
+
+ }
+ else
+ nautilus_window_allow_restore (window, FALSE);
+
+ nautilus_directory_unref (directory);
+
if (location_really_changed) {
nautilus_window_slot_remove_extra_location_widgets (slot);
@@ -1833,11 +1899,19 @@
nautilus_window_slot_stop_loading (NautilusWindowSlot *slot)
{
NautilusWindow *window;
+ NautilusDirectory *directory;
window = NAUTILUS_WINDOW (slot->pane->window);
g_assert (NAUTILUS_IS_WINDOW (window));
nautilus_view_stop_loading (slot->content_view);
+
+ if (slot->find_zfs_snapshots_cancellable)
+ g_cancellable_cancel (slot->find_zfs_snapshots_cancellable);
+
+ directory = nautilus_directory_get (slot->location);
+ nautilus_directory_cancel_restore_info (directory);
+ nautilus_directory_unref (directory);
if (slot->new_content_view != NULL) {
window->details->temporarily_ignore_view_signals = TRUE;
@@ -1898,6 +1972,8 @@
nautilus_window_disconnect_content_view (slot->pane->window, slot->content_view);
}
+ nautilus_window_slot_stop_loading (slot);
+
free_location_change (slot);
cancel_viewed_file_changed_callback (slot);
}
--- nautilus-3.1.3/src/nautilus-window-menus.c.orig 2011-07-25 10:08:19.966466156 +0100
+++ nautilus-3.1.3/src/nautilus-window-menus.c 2011-07-25 10:08:46.797184803 +0100
@@ -40,6 +40,7 @@
#include "nautilus-window-private.h"
#include "nautilus-desktop-window.h"
#include "nautilus-search-bar.h"
+#include "nautilus-zfs-bar.h"
#include <gtk/gtk.h>
#include <gio/gio.h>
#include <glib/gi18n.h>
@@ -257,6 +258,33 @@
}
static void
+action_restore_callback (GtkToggleAction *action,
+ gpointer user_data)
+{
+ NautilusWindowSlot *slot;
+ GFile *directory;
+ NautilusDirectory *n_dir;
+ GtkWidget *bar = NAUTILUS_WINDOW (user_data)->details->zfs_bar;
+
+ slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (user_data));
+ directory = nautilus_window_slot_get_location (slot);
+ n_dir = nautilus_directory_get (directory);
+
+ if (gtk_toggle_action_get_active (action))
+ {
+ nautilus_zfs_bar_setup (NAUTILUS_ZFS_BAR (bar), n_dir, slot, action);
+ gtk_widget_show (bar);
+ }
+ else
+ {
+ nautilus_zfs_bar_hide (NAUTILUS_ZFS_BAR (bar));
+ nautilus_window_reload (NAUTILUS_WINDOW (user_data));
+ }
+ g_object_unref (n_dir);
+ g_object_unref (directory);
+}
+
+static void
action_zoom_in_callback (GtkAction *action,
gpointer user_data)
{
@@ -1113,6 +1141,12 @@
};
static const GtkToggleActionEntry main_toggle_entries[] = {
+ /* name, stock id */ { "Restore", "stock_help",
+ /* SUN_BRANDING */
+ /* label, accelerator */ N_("R_estore"), "<control>E",
+ /* SUN_BRANDING */
+ /* tooltip */ N_("Browse the current location snapshot history"),
+ G_CALLBACK (action_restore_callback) },
/* name, stock id */ { "Show Hidden Files", NULL,
/* label, accelerator */ N_("Show _Hidden Files"), "<control>H",
/* tooltip */ N_("Toggle the display of hidden files in the current window"),
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-window-slot.c nautilus-2.30.1/src/nautilus-window-slot.c
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-window-slot.c 2009-12-16 17:53:51.000000000 +0100
+++ nautilus-2.30.1/src/nautilus-window-slot.c 2010-05-14 17:16:39.566465378 +0200
@@ -650,6 +650,13 @@ nautilus_window_slot_dispose (GObject *o
slot->find_mount_cancellable = NULL;
}
+ if (slot->find_zfs_snapshots_cancellable)
+ {
+ g_cancellable_cancel (slot->find_zfs_snapshots_cancellable);
+ g_object_unref (slot->find_zfs_snapshots_cancellable);
+ slot->find_zfs_snapshots_cancellable = NULL;
+ }
+
slot->pane = NULL;
g_free (slot->title);
--- nautilus-3.1.3/src/nautilus-window-slot.h.orig 2011-06-28 14:41:41.000000000 +0100
+++ nautilus-3.1.3/src/nautilus-window-slot.h 2011-07-22 14:33:49.936636702 +0100
@@ -113,6 +113,7 @@
gpointer open_callback_user_data;
GCancellable *find_mount_cancellable;
+ GCancellable *find_zfs_snapshots_cancellable;
gboolean visible;
--- nautilus-3.1.3/src/nautilus-window.c.orig 2011-07-25 14:28:16.524301501 +0100
+++ nautilus-3.1.3/src/nautilus-window.c 2011-07-25 14:28:29.183307666 +0100
@@ -44,6 +44,7 @@
#include "nautilus-window-manage-views.h"
#include "nautilus-window-bookmarks.h"
#include "nautilus-window-slot.h"
+#include "nautilus-zfs-bar.h"
#include <eel/eel-debug.h>
#include <eel/eel-gtk-extensions.h>
@@ -95,6 +96,7 @@
static void mouse_back_button_changed (gpointer callback_data);
static void mouse_forward_button_changed (gpointer callback_data);
static void use_extra_mouse_buttons_changed (gpointer callback_data);
+static void restore_pref_changed (gpointer callback_data);
/* Sanity check: highest mouse button value I could find was 14. 5 is our
* lower threshold (well-documented to be the one of the button events for the
@@ -269,6 +271,18 @@
gtk_action_set_sensitive (action, allow);
}
+void
+nautilus_window_allow_restore (NautilusWindow *window, gboolean enable)
+{
+ GtkAction *action;
+
+ g_assert (NAUTILUS_IS_WINDOW (window));
+
+ action = gtk_action_group_get_action (window->details->main_action_group,
+ NAUTILUS_ACTION_RESTORE);
+ gtk_action_set_sensitive (action, enable);
+}
+
static void
update_cursor (NautilusWindow *window)
{
@@ -277,7 +291,7 @@
slot = window->details->active_pane->active_slot;
- if (slot->allow_stop) {
+ if (slot && slot->allow_stop) {
cursor = gdk_cursor_new (GDK_WATCH);
gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
g_object_unref (cursor);
@@ -303,8 +317,14 @@
if (slot != window->details->active_pane->active_slot ||
allow_stop != slot->allow_stop) {
if (slot == window->details->active_pane->active_slot) {
- gtk_action_set_sensitive (action, slot->allow_stop);
- }
+ if (!slot->allow_stop && slot->find_zfs_snapshots_cancellable != NULL) {
+ /* if slot want to stop and snap find is finished/cancel then disable */
+ if (g_cancellable_is_cancelled (slot->find_zfs_snapshots_cancellable))
+ gtk_action_set_sensitive (action, slot->allow_stop);
+ } else {
+ gtk_action_set_sensitive (action, slot->allow_stop);
+ }
+ }
if (gtk_widget_get_realized (GTK_WIDGET (window))) {
update_cursor (window);
@@ -575,7 +595,7 @@
G_OBJECT_CLASS (nautilus_window_parent_class)->constructed (self);
- table = gtk_table_new (1, 6, FALSE);
+ table = gtk_table_new (1, 7, FALSE);
window->details->table = table;
gtk_widget_show (table);
gtk_container_add (GTK_CONTAINER (window), table);
@@ -592,6 +612,7 @@
menu = gtk_ui_manager_get_widget (window->details->ui_manager, "/MenuBar");
window->details->menubar = menu;
gtk_widget_show (menu);
+
gtk_table_attach (GTK_TABLE (table),
menu,
/* X direction */ /* Y direction */
@@ -607,7 +628,7 @@
gtk_table_attach (GTK_TABLE (window->details->table),
window->details->content_paned,
/* X direction */ /* Y direction */
- 0, 1, 3, 4,
+ 0, 1, 4, 5,
GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0);
gtk_widget_show (window->details->content_paned);
@@ -632,6 +653,15 @@
nautilus_window_disable_chrome_mapping, NULL,
window, NULL);
+ /* add custom icon */
+
+ nautilus_window_set_restore_icon (window, RESTORE_SEARCH);
+ /* add preference callback */
+ g_signal_connect_swapped (nautilus_preferences,
+ "changed::" NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER,
+ G_CALLBACK(restore_pref_changed),
+ (gpointer) window);
+
pane = nautilus_window_pane_new (window);
window->details->panes = g_list_prepend (window->details->panes, pane);
@@ -656,6 +686,15 @@
slot = nautilus_window_open_slot (window->details->active_pane, 0);
nautilus_window_set_active_slot (window, slot);
nautilus_window_menus_lockdown_notify_add (window);
+
+ window->details->zfs_bar = nautilus_zfs_bar_new ();
+
+ gtk_table_attach (GTK_TABLE (NAUTILUS_WINDOW (window)->details->table),
+ window->details->zfs_bar,
+ /* X direction */ /* Y direction */
+ 0, 1, 3, 4,
+ GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0,
+ 0, 0);
}
static void
@@ -1913,7 +1952,7 @@
return slot;
}
-static void
+void
nautilus_window_reload (NautilusWindow *window)
{
NautilusWindowSlot *active_slot;
@@ -1997,6 +2036,13 @@
}
static void
+restore_pref_changed (gpointer callback_data)
+{
+ g_assert (NAUTILUS_IS_WINDOW (callback_data));
+ nautilus_window_reload (NAUTILUS_WINDOW(callback_data));
+}
+
+static void
mouse_back_button_changed (gpointer callback_data)
{
int new_back_button;
@@ -2030,7 +2076,6 @@
mouse_extra_buttons = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS);
}
-
/*
* Main API
*/
@@ -2249,3 +2294,47 @@
{
return g_list_length (NAUTILUS_WINDOW (window)->details->panes) > 1;
}
+
+void nautilus_window_set_restore_icon (NautilusWindow* window,
+ NautilusRestoreIconType type)
+{
+ static gboolean init = 0;
+ static GdkPixbuf *normal = NULL;
+ static GdkPixbuf *search = NULL;
+ static GdkPixbuf *no = NULL;
+ GdkPixbuf *pb = NULL;
+ GtkWidget *image = NULL;
+ GtkAction* action = gtk_ui_manager_get_action (nautilus_window_get_ui_manager (NAUTILUS_WINDOW (window)), "/Toolbar/Restore");
+
+ if (!init) {
+ char *path = nautilus_pixmap_file ("restore.png");
+ normal = gdk_pixbuf_new_from_file (path, NULL);
+ g_free (path);
+ path = nautilus_pixmap_file ("restore-search.png");
+ search = gdk_pixbuf_new_from_file (path, NULL);
+ g_free (path);
+ init = TRUE;
+ }
+
+ switch (type) {
+ case RESTORE_NORMAL :
+ pb = normal;
+ break;
+ case RESTORE_SEARCH:
+ pb = search;
+ break;
+ case RESTORE_NO:
+ pb = no;
+ break;
+ }
+
+ image = gtk_image_new_from_pixbuf (pb);
+ g_object_ref (image);
+ gtk_widget_show (image);
+ GSList *tmp = gtk_action_get_proxies (action);
+ for (tmp; tmp ; tmp = tmp->next) {
+ GtkWidget *proxy = (GtkWidget *)tmp->data;
+ if (GTK_IS_TOOL_BUTTON (proxy))
+ gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (proxy), image);
+ }
+}
--- nautilus-3.1.3/src/nautilus-window-private.h.orig 2011-07-25 10:54:12.777383655 +0100
+++ nautilus-3.1.3/src/nautilus-window-private.h 2011-07-25 11:06:58.227055497 +0100
@@ -94,6 +94,8 @@
GtkWidget *sidebar;
gchar *sidebar_id;
+ GtkWidget *zfs_bar;
+
/* Toolbar */
GtkWidget *toolbar;
@@ -111,6 +113,12 @@
guint sidebar_width_handler_id;
};
+typedef enum {
+ RESTORE_NORMAL,
+ RESTORE_SEARCH,
+ RESTORE_NO
+} NautilusRestoreIconType;
+
/* window geometry */
/* Min values are very small, and a Nautilus window at this tiny size is *almost*
* completely unusable. However, if all the extra bits (sidebar, location bar, etc)
@@ -176,6 +184,9 @@
void nautilus_window_update_show_hide_menu_items (NautilusWindow *window);
void nautilus_window_menus_lockdown_notify_add (NautilusWindow *window);
void nautilus_window_menus_lockdown_notify_remove (NautilusWindow *window);
+gboolean nautilus_window_zfs_bar_showing (NautilusWindow *window);
+void nautilus_window_set_restore_icon (NautilusWindow *window,
+ NautilusRestoreIconType type);
/* window toolbar */
void nautilus_window_close_pane (NautilusWindowPane *pane);
--- nautilus-3.1.3/src/nautilus-window.h.orig 2011-06-28 14:41:41.000000000 +0100
+++ nautilus-3.1.3/src/nautilus-window.h 2011-07-22 14:56:24.534238012 +0100
@@ -152,6 +152,8 @@
gboolean allow);
void nautilus_window_allow_forward (NautilusWindow *window,
gboolean allow);
+void nautilus_window_allow_restore (NautilusWindow *window,
+ gboolean allow);
void nautilus_window_clear_back_list (NautilusWindow *window);
void nautilus_window_clear_forward_list (NautilusWindow *window);
void nautilus_forget_history (void);
--- /dev/null 2011-07-25 11:57:58.000000000 +0100
+++ nautilus-3.1.3/src/nautilus-zfs-bar.c 2011-07-25 11:55:15.960654076 +0100
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2008 Sun Microsystems (Erwann Chenede)
+ *
+ */
+
+#include "config.h"
+#include <strings.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-zfs-bar.h"
+#include "nautilus-window.h"
+#include "nautilus-window-private.h"
+#include "nautilus-file-utilities.h"
+#include "timescale.h"
+#include <libnautilus-private/nautilus-zfs.h>
+#include <libnautilus-private/nautilus-file.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+#include "nautilus-window-slot.h"
+
+#define NAUTILUS_ZFS_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NAUTILUS_TYPE_ZFS_BAR, NautilusZfsBarPrivate))
+
+struct NautilusZfsBarPrivate
+{
+ NautilusDirectory *dir;
+ GtkWidget *scale;
+ GtkWidget *delete_button;
+ GdkColor in_snapshot;
+ GtkToggleAction *action;
+ NautilusWindowSlot *slot;
+ int num_range_items;
+ gboolean is_setup;
+ gboolean set_only;
+ char *current_path;
+ ZfsSnapDirMonitor *zfs_dir_monitor_data;
+ gboolean in_snapshot_dir;
+ GtkWidget *camera_image;
+ GtkWidget *delete_image;
+ gboolean explicit_user_hide;
+};
+
+G_DEFINE_TYPE (NautilusZfsBar, nautilus_zfs_bar, GTK_TYPE_EVENT_BOX)
+
+static void
+close_clicked_callback (GtkWidget *widget,
+ NautilusZfsBar *bar);
+static void
+slider_moved_callback (TimeScale *ts,
+ NautilusZfsBar *bar);
+static void
+update_delete_or_snap_button (NautilusZfsBar *bar,
+ gboolean in_snap);
+
+static void
+nautilus_zfs_bar_class_init (NautilusZfsBarClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (NautilusZfsBarPrivate));
+}
+
+static void
+set_scale_range (NautilusZfsBar *bar, gboolean set_initial_position)
+{
+ int i;
+ GList *tmp;
+
+ if (bar->priv->dir)
+ {
+ i = nautilus_directory_get_num_snapshots (bar->priv->dir);
+
+ if (i==0)
+ return;
+
+ bar->priv->num_range_items = i;
+
+ tmp = nautilus_directory_get_snapshots (bar->priv->dir);
+
+ if (set_initial_position)
+ timescale_set_snapshots (TIMESCALE (bar->priv->scale), tmp, -1);
+ else
+ timescale_set_snapshots (TIMESCALE (bar->priv->scale), tmp, bar->priv->num_range_items);
+ }
+}
+
+static void
+update_range (NautilusZfsBar *bar)
+{
+ if (nautilus_directory_get_snapshots (bar->priv->dir))
+ {
+ set_scale_range (bar, FALSE);
+ slider_moved_callback (TIMESCALE (bar->priv->scale), bar);
+ }
+ else
+ close_clicked_callback (NULL, bar);
+}
+
+static int match_func (ZfsDataSet *set, char *dir)
+{
+ /* remove trailing slash from dir */
+ char mountp[PATH_MAX+1];
+ int length = strlen (set->mountpoint);
+
+ if (set->mountpoint[length-1] == '/')
+ {
+ memcpy (mountp, set->mountpoint, length - 1);
+ mountp[length-1] = NULL;
+ return strcmp (mountp, dir);
+ }
+ else
+ return strcmp (set->mountpoint, dir);
+}
+
+void
+nautilus_zfs_bar_remove_and_skip_snap (NautilusZfsBar *bar, char *path)
+{
+ GList* match = NULL;
+ GList* snap_list = NULL;
+ ZfsDataSet *snap;
+
+ snap_list = nautilus_directory_get_snapshots (bar->priv->dir);
+ match = g_list_find_custom (snap_list, path, (GCompareFunc)match_func);
+
+ if (match)
+ {
+ snap = (ZfsDataSet*) match->data;
+ nautilus_directory_remove_snapshot (bar->priv->dir, snap);
+ update_range (bar);
+ }
+}
+
+static void
+update_delete_or_snap_button (NautilusZfsBar *bar, gboolean in_snap)
+{
+ if (in_snap)
+ {
+ if (!bar->priv->in_snapshot_dir)
+ { /*in main dir to snap */
+ bar->priv->in_snapshot_dir = TRUE;
+ g_object_ref (bar->priv->camera_image);
+ gtk_button_set_image (GTK_BUTTON (bar->priv->delete_button),
+ bar->priv->delete_image);
+ gtk_widget_set_tooltip_text (bar->priv->delete_button,
+ /* SUN_BRANDING */
+ _("Delete this snapshot"));
+ }
+ }
+ else
+ {
+ if (bar->priv->in_snapshot_dir)
+ { /* in snap to main dir */
+ bar->priv->in_snapshot_dir = FALSE;
+ g_object_ref (bar->priv->delete_image);
+ gtk_button_set_image (GTK_BUTTON (bar->priv->delete_button),
+ bar->priv->camera_image);
+ gtk_widget_set_tooltip_text (bar->priv->delete_button,
+ /* SUN_BRANDING */
+ _("Take a zfs snapshot of this directory now"));
+ }
+ }
+}
+
+static void
+slider_moved_callback (TimeScale *ts,
+ NautilusZfsBar *bar)
+{
+ GList *tmp;
+ ZfsDataSet *snap;
+ GFile *snap_file;
+ int pos = timescale_get_position (ts);
+
+ if (pos < bar->priv->num_range_items)
+ {
+ tmp = nautilus_directory_get_snapshots (bar->priv->dir);
+
+ snap = g_list_nth_data (tmp, pos);
+
+ snap_file = g_file_new_for_path (snap->mountpoint);
+ }
+ else
+ {
+ snap_file = nautilus_directory_get_location (bar->priv->dir);
+ pos = bar->priv->num_range_items;
+ }
+
+ if (!bar->priv->set_only)
+ {
+ gboolean in_snap = FALSE;
+ char *path = g_file_get_path (snap_file);
+
+ if (g_file_test (path, G_FILE_TEST_IS_DIR))
+ {
+ nautilus_window_slot_go_to (bar->priv->slot,
+ snap_file,
+ FALSE);
+ if (bar->priv->current_path)
+ g_free (bar->priv->current_path);
+ bar->priv->current_path = path;
+ }
+ else
+ { /* the snapshot diappeared try the next one */
+ g_free (path);
+ g_object_unref (snap_file);
+ /* remove snap from list */
+ nautilus_directory_remove_snapshot (bar->priv->dir, snap);
+ update_range (bar);
+ return;
+ }
+
+ in_snap = ts_is_in_snapshot (path);
+ update_delete_or_snap_button (bar, ts_is_in_snapshot (path));
+
+ }
+
+g_object_unref (snap_file);
+
+}
+
+
+static void
+delete_clicked_callback (GtkWidget *widget,
+ NautilusZfsBar *bar)
+{
+ GList *tmp;
+ ZfsDataSet *snap;
+ GFile *snap_file;
+ char *path;
+ char *full_command;
+ int pos = timescale_get_position (TIMESCALE (bar->priv->scale));
+
+ if (bar->priv->in_snapshot_dir)
+ {
+ tmp = nautilus_directory_get_snapshots (bar->priv->dir);
+ snap = g_list_nth_data (tmp, pos);
+ snap_file = g_file_new_for_path (snap->mountpoint);
+ path = g_file_get_path (snap_file);
+
+ g_object_unref (snap_file);
+ if (snap->type)
+ {
+ /*printf ("path %s snapshot to delete %s\n", path, snap->name);*/
+ full_command = g_strdup_printf ("/usr/lib/time-slider-delete '%s'", snap->name);
+ }
+ else
+ {
+ /*printf ("path %s backup to delete %s\n", path, snap->name);*/
+ full_command = g_strdup_printf ("/usr/lib/time-slider-delete '%s'", path);
+ }
+
+ nautilus_launch_application_from_command (gtk_widget_get_screen (widget),
+ full_command, NULL);
+ }
+ else
+ {
+ path = g_file_get_path (nautilus_directory_get_location (bar->priv->dir));
+ char *fs = ts_get_zfs_filesystem (path);
+ /* printf ("take a snapshot of zfs fs %s for dir %s\n", fs, path); */
+ full_command = g_strdup_printf ("/usr/lib/time-slider-snapshot '%s' '%s'", path, fs);
+ nautilus_launch_application_from_command (gtk_widget_get_screen (widget),
+ full_command, NULL);
+ g_free (fs);
+ }
+
+ g_free (full_command);
+ g_free (path);
+}
+
+static void
+close_clicked_callback (GtkWidget *widget,
+ NautilusZfsBar *bar)
+{
+ GFile *snap_file = nautilus_directory_get_location (bar->priv->dir);
+
+ nautilus_window_slot_go_to (bar->priv->slot,
+ snap_file,
+ FALSE);
+ g_object_unref (snap_file);
+
+ bar->priv->is_setup = FALSE;
+
+ gtk_widget_hide (GTK_WIDGET (bar));
+ gtk_toggle_action_set_active (bar->priv->action, FALSE);
+
+}
+
+static void
+nautilus_zfs_bar_init (NautilusZfsBar *bar)
+{
+ GtkWidget *hbox, *toolbar, *close, *delete, *image, *button_vbox;
+ GtkToolItem *item;
+ char *path;
+
+ bar->priv = NAUTILUS_ZFS_BAR_GET_PRIVATE (bar);
+
+ bar->priv->dir = NULL;
+ bar->priv->num_range_items = 0;
+ bar->priv->action = NULL;
+ bar->priv->slot = NULL;
+ bar->priv->is_setup = FALSE;
+ bar->priv->set_only = FALSE;
+
+ /* GUI init */
+
+ toolbar = gtk_toolbar_new ();
+ gtk_widget_show (toolbar);
+
+ item = gtk_tool_item_new ();
+ gtk_widget_show (GTK_WIDGET (item));
+ gtk_tool_item_set_expand (item, TRUE);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (GTK_WIDGET (hbox));
+
+ gtk_container_add (GTK_CONTAINER (item),hbox);
+
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ gtk_container_add (GTK_CONTAINER (bar),toolbar);
+ gtk_container_set_border_width (GTK_CONTAINER (bar), 0);
+
+ /* buttons */
+
+ button_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (button_vbox);
+
+ close = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close), GTK_RELIEF_NONE);
+ gtk_widget_set_tooltip_text (close,
+ /* SUN_BRANDING */
+ _("Close Time Slider and return to original directory"));
+ gtk_widget_show (close);
+
+ g_signal_connect (close,
+ "clicked",
+ G_CALLBACK (close_clicked_callback),
+ bar);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+
+ gtk_container_add (GTK_CONTAINER (close), image);
+
+ gtk_box_pack_start (GTK_BOX (button_vbox), close, FALSE, FALSE, 0);
+
+ delete = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (delete), GTK_RELIEF_NONE);
+ gtk_widget_set_tooltip_text (delete,
+ /* SUN_BRANDING */
+ _("Take a zfs snapshot of this directory now"));
+ gtk_widget_show (delete);
+
+ g_signal_connect (delete,
+ "clicked",
+ G_CALLBACK (delete_clicked_callback),
+ bar);
+
+ {
+ GtkIconTheme *it = gtk_icon_theme_get_default ();
+ GdkPixbuf * pb = gtk_icon_theme_load_icon (it,
+ "user-trash-full.png",
+ 16,
+ GTK_ICON_LOOKUP_GENERIC_FALLBACK,
+ NULL);
+ bar->priv->delete_image = gtk_image_new_from_pixbuf (pb);
+ g_object_unref (pb);
+ }
+
+ path = nautilus_pixmap_file ("camera.png");
+ bar->priv->camera_image = gtk_image_new_from_file (path);
+ g_free (path);
+
+ gtk_widget_show (bar->priv->delete_image);
+ gtk_widget_show (bar->priv->camera_image);
+
+ gtk_container_add (GTK_CONTAINER (delete), bar->priv->camera_image);
+
+ gtk_box_pack_end (GTK_BOX (button_vbox), delete, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (hbox), button_vbox, FALSE, FALSE, 0);
+
+ bar->priv->delete_button = delete;
+
+ bar->priv->scale = timescale_new();
+
+ g_signal_connect (bar->priv->scale,
+ "value-changed",
+ G_CALLBACK (slider_moved_callback),
+ bar);
+
+ gtk_widget_show (bar->priv->scale);
+
+ gtk_box_pack_start (GTK_BOX (hbox), bar->priv->scale, TRUE, TRUE, 0);
+
+}
+
+NautilusDirectory *
+nautilus_zfs_bar_get_dir (NautilusZfsBar* bar)
+{
+ g_return_val_if_fail (NAUTILUS_IS_ZFS_BAR (bar), NULL);
+ return bar->priv->dir;
+}
+
+static void snapshot_data_ready (NautilusDirectory *dir,
+ GCancellable *cancellable,
+ gpointer callback_data)
+{
+ NautilusWindowSlot *slot;
+ GFile *location;
+ GFile *dir_location;
+ NautilusWindow *window = (NautilusWindow*)callback_data;
+
+ g_return_if_fail (NAUTILUS_IS_WINDOW (window));
+
+ slot = nautilus_window_get_active_slot (window);
+ location = nautilus_window_slot_get_location (slot);
+ dir_location = nautilus_directory_get_location (dir);
+
+ if (g_cancellable_is_cancelled (cancellable) && g_file_equal (location, dir_location))
+ {
+ nautilus_window_set_restore_icon (window, RESTORE_NO);
+ }
+ else if (g_file_equal (location, dir_location))
+ {
+ char *path = g_file_get_path (dir_location);
+ g_cancellable_cancel (cancellable);
+ nautilus_window_slot_set_allow_stop (slot, FALSE);
+ nautilus_window_set_restore_icon (window,
+ nautilus_directory_has_snapshots (dir) ? RESTORE_NORMAL : RESTORE_NO);
+ if (nautilus_directory_has_snapshots (dir))
+ nautilus_window_allow_restore (window, TRUE);
+ else
+ nautilus_window_allow_restore (window, FALSE);
+ g_free (path);
+ }
+ g_object_unref (location);
+ g_object_unref (dir_location);
+}
+
+
+void nautilus_zfs_bar_cancel_tasks (NautilusWindow *window)
+{
+ if (NAUTILUS_IS_WINDOW (window))
+ {
+ if (NAUTILUS_IS_WINDOW_SLOT (window->details->active_pane->active_slot))
+ {
+ NautilusDirectory *directory = NULL;
+ g_cancellable_cancel (window->details->active_pane->active_slot->find_zfs_snapshots_cancellable);
+ g_object_unref (window->details->active_pane->active_slot->find_zfs_snapshots_cancellable);
+ window->details->active_pane->active_slot->find_zfs_snapshots_cancellable = NULL;
+ directory = nautilus_directory_get (window->details->active_pane->active_slot->location);
+ if (directory)
+ {
+ nautilus_directory_cancel_restore_info (directory);
+ nautilus_directory_unref (directory);
+ }
+ }
+ if (NAUTILUS_WINDOW (window))
+ {
+ NautilusZfsBar *bar = NAUTILUS_ZFS_BAR (window->details->zfs_bar);
+ monitor_zfs_snap_directory_cancel (bar->priv->zfs_dir_monitor_data);
+ bar->priv->zfs_dir_monitor_data = NULL;
+ }
+ }
+}
+
+void nautilus_zfs_bar_hide (NautilusZfsBar *bar)
+{
+ bar->priv->explicit_user_hide = TRUE;
+ close_clicked_callback (NULL, bar);
+}
+
+
+/* Display AND Scan */
+
+void
+nautilus_zfs_bar_display (NautilusZfsBar *bar,
+ NautilusWindow *window,
+ NautilusDirectory *new_dir,
+ GCancellable *cancellable)
+{
+ gboolean show = FALSE;
+ gboolean time_slider_enabled = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_TIME_SLIDER);
+ gboolean visible = gtk_widget_get_visible (GTK_WIDGET (bar));
+ gboolean enable_button = FALSE;
+ gboolean do_scan = FALSE;
+ gboolean do_cancel = FALSE;
+
+
+ /* if bar visible
+ * if feature disabled
+ * close bar
+ * disable button
+ * if in root dir
+ * enable button
+ * else
+ * if bar was previously displayed and in same tab
+ * if in snapshot
+ * redisplay
+ * re-align
+ * disable button
+ * if root dir
+ * redisplay
+ * re-align
+ * enable button
+ * else
+ * scan
+ * else
+ * if feature enabled
+ * scan
+ * disable button
+ *
+ *
+ * NOTE : action_restore_callback display bar when enabled
+ */
+
+ if (visible)
+ {
+ if (!time_slider_enabled)
+ {
+ close_clicked_callback (NULL, bar);
+ return;
+ }
+ if (new_dir == bar->priv->dir)
+ enable_button = TRUE;
+ if (nautilus_directory_is_a_snapshot_dir_of (new_dir, bar->priv->dir) || new_dir == bar->priv->dir)
+ {
+ show = TRUE;
+ do_cancel = TRUE;
+ enable_button = TRUE;
+ }
+ else
+ do_scan = TRUE;
+ }
+ else
+ { /* bar is not visible */
+ NautilusWindowSlot *slot = nautilus_window_get_active_slot (window);
+
+ if (bar->priv->is_setup && slot == bar->priv->slot && time_slider_enabled) /* check if we can redisplay the bar */
+ {
+ if (nautilus_directory_is_a_snapshot_dir_of (new_dir, bar->priv->dir) && !bar->priv->explicit_user_hide)
+ show = TRUE;
+
+ if (bar->priv->explicit_user_hide)
+ enable_button = FALSE;
+
+ if (new_dir == bar->priv->dir)
+ {
+ show = TRUE;
+ enable_button = TRUE;
+ }
+ else
+ do_scan = TRUE;
+ }
+ else
+ { /* icon and throbber set is snapshot_data_ready */
+ if (time_slider_enabled)
+ do_scan = TRUE;
+ }
+
+ }
+
+ if (enable_button) /* if button enabled set the icon to normal */
+ nautilus_window_set_restore_icon (window, RESTORE_NORMAL);
+
+ nautilus_window_allow_restore (window, enable_button);
+
+
+ if (show)
+ {
+ gtk_widget_show (GTK_WIDGET (bar));
+ nautilus_zfs_set_snap (bar, new_dir);
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET (bar));
+ if (bar->priv->action)
+ gtk_toggle_action_set_active (bar->priv->action, FALSE);
+ }
+
+ if (do_cancel)
+ g_cancellable_cancel (cancellable);
+
+ if (do_scan)
+ {
+ g_cancellable_reset (cancellable);
+ nautilus_window_set_restore_icon (window, RESTORE_SEARCH);
+ nautilus_window_slot_set_allow_stop (nautilus_window_get_active_slot (window), TRUE);
+ nautilus_directory_get_snapshots_async (new_dir,
+ snapshot_data_ready,
+ cancellable,
+ window);
+ }
+
+ /* {
+ GFile *file = nautilus_directory_get_location (new_dir);
+ char *path = g_file_get_path (file);
+
+ printf ("nautilus_zfs_bar_display %s\nenable_button : %s, show : %s, do_cancel : %s, do_scan : %s\n\n",
+ path,
+ enable_button ? "true" : "false",
+ show ? "true" : "false",
+ do_cancel ? "true" : "false",
+ do_scan ? "true" : "false");
+ g_free (path);
+ }*/
+
+}
+
+
+void nautilus_zfs_set_snap (NautilusZfsBar *bar,
+ NautilusDirectory *dir)
+{
+ GList* match = NULL;
+ GList* snap_list = NULL;
+ gboolean in_snap = FALSE;
+ char real_path [PATH_MAX+1];
+ GFile *file;
+ char* path;
+ int pos;
+ int set_pos = -2;
+
+ if (!bar->priv->is_setup)
+ return;
+
+ file = nautilus_directory_get_location (dir);
+ path = g_file_get_path (file);
+ ts_realpath (path, real_path);
+
+
+ if (ts_is_in_remote_backup (real_path))
+ { /* hmmm */
+ /*gnome_vfs_init();*/
+ g_object_ref (dir);
+ }
+
+ in_snap = ts_is_in_snapshot (real_path);
+
+ if (in_snap)
+ {
+ snap_list = nautilus_directory_get_snapshots (bar->priv->dir);
+ match = g_list_find_custom (snap_list, real_path, (GCompareFunc)match_func);
+ }
+ g_free (path);
+ g_object_unref (file);
+
+ timescale_set_position (TIMESCALE (bar->priv->scale), match ? ((ZfsDataSet*)match->data)->mountpoint : NULL);
+ update_delete_or_snap_button (bar, in_snap);
+
+/* printf ("nautilus_zfs_set_snap current_path %s real_path %s match %s\n", bar->priv->current_path, real_path,
+ match ? "found" : "not found");*/
+
+ if (bar->priv->current_path && (strcmp (bar->priv->current_path, real_path) != 0))
+ {
+ bar->priv->set_only = TRUE;
+ bar->priv->set_only = FALSE;
+
+ }
+}
+
+static void snapshot_data_ready_from_change (NautilusDirectory *dir,
+ GCancellable *cancellable,
+ gpointer callback_data)
+{
+ NautilusZfsBar *bar = NAUTILUS_ZFS_BAR (callback_data);
+
+ snapshot_data_ready (dir, cancellable, bar->priv->slot->pane->window);
+ update_range (bar);
+ gtk_widget_set_sensitive (bar->priv->scale, TRUE);
+}
+
+
+static void zfs_dir_change_callback (ZfsSnapDirMonitor *monitor_data,
+ NautilusZfsBar *bar)
+{
+ gtk_widget_set_sensitive (bar->priv->scale, FALSE);
+
+ g_cancellable_reset (bar->priv->slot->find_zfs_snapshots_cancellable);
+ nautilus_window_set_restore_icon (bar->priv->slot->pane->window, RESTORE_SEARCH);
+ nautilus_window_slot_set_allow_stop (bar->priv->slot, TRUE);
+ nautilus_directory_get_snapshots_async (bar->priv->dir,
+ snapshot_data_ready_from_change,
+ bar->priv->slot->find_zfs_snapshots_cancellable,
+ bar);
+}
+
+static char*
+get_backup_dir (GList *snaplist)
+{
+ GList *tmp = snaplist;
+
+ while (tmp)
+ {
+ ZfsDataSet *snap = (ZfsDataSet*) tmp->data;
+ if (snap->type == 0)
+ {
+ char **root_split = NULL;
+ char *result = NULL;
+ root_split = g_strsplit (snap->mountpoint, snap->name, 2);
+ /*printf (" name: %s\n mountpoint: %s\n mtime_str :%s\n space used : %s\n size in kilobytes : %f\n",
+ snap->name, snap->mountpoint, snap->mtime_str, snap->used_space_str, snap->used_space); */
+ result = g_strdup (root_split[0]);
+ if (root_split)
+ g_strfreev (root_split);
+ return result;
+ }
+ tmp = tmp->next;
+ }
+ return NULL;
+
+
+}
+
+void
+nautilus_zfs_bar_setup (NautilusZfsBar* bar,
+ NautilusDirectory *dir,
+ NautilusWindowSlot *active_slot,
+ GtkToggleAction* action)
+{
+ GFile *file;
+ char *path, *zfs_dir, *backup_dir = NULL;
+ bar->priv->dir = dir;
+ g_object_ref (dir);
+ bar->priv->slot = active_slot;
+ g_object_ref (active_slot);
+
+ bar->priv->action = action;
+ set_scale_range (bar, TRUE);
+ bar->priv->is_setup = TRUE;
+ bar->priv->explicit_user_hide = FALSE;
+
+ file = nautilus_directory_get_location (dir);
+ path = g_file_get_path (file);
+ zfs_dir = ts_get_snapshot_dir (path);
+ backup_dir = get_backup_dir (nautilus_directory_get_snapshots (dir));
+
+ bar->priv->zfs_dir_monitor_data = monitor_zfs_snap_directory (zfs_dir,
+ backup_dir,
+ (ZfsDirChangeCallback) zfs_dir_change_callback,
+ bar);
+ nautilus_zfs_set_snap (bar, dir);
+ g_free (path);
+ g_free (zfs_dir);
+ if (backup_dir)
+ g_free(backup_dir);
+ g_object_unref (file);
+}
+
+static void
+zfs_bar_show_column (GtkWidget *widget, gpointer user_data)
+{
+ char **visible_columns;
+ gboolean restore_col_visible = FALSE;
+ int i = 0;
+ GPtrArray *ret = NULL;
+
+ visible_columns = g_settings_get_strv (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
+
+ ret = g_ptr_array_new ();
+
+ /* convert visible_columns in ptr array without "restore_info" */
+ while (visible_columns[i])
+ {
+ if (strcmp (visible_columns [i], "restore_info") == 0)
+ {
+ restore_col_visible = TRUE;
+ break;
+ }
+ else
+ g_ptr_array_add (ret, g_strdup (visible_columns [i]));
+ i++;
+ }
+
+ g_strfreev (visible_columns);
+
+ if (restore_col_visible)
+ {
+ if (!gtk_widget_get_visible (widget)) /* hide bar remove pref */
+ {
+ char **col_array;
+ g_ptr_array_add (ret, NULL);
+ col_array = (char **)g_ptr_array_free (ret, FALSE);
+ g_settings_set_strv (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
+ (const char * const *) col_array);
+ g_strfreev (col_array);
+ ret = NULL;
+ }
+ }
+ else
+ {
+ if (gtk_widget_get_visible (widget))
+ {
+ char **col_array;
+ g_ptr_array_add (ret,strdup ("restore_info"));
+ g_ptr_array_add (ret,NULL);
+ col_array = (char **)g_ptr_array_free (ret, FALSE);
+ g_settings_set_strv (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
+ (const char * const *) col_array);
+ g_strfreev (col_array);
+ ret = NULL;
+ }
+
+ }
+
+ if (ret)
+ g_ptr_array_free (ret, TRUE);
+
+}
+
+static void
+zfs_bar_hidden (GtkWidget *widget, gpointer user_data)
+{
+ NautilusZfsBar *bar = NAUTILUS_ZFS_BAR (user_data);
+ monitor_zfs_snap_directory_cancel (bar->priv->zfs_dir_monitor_data);
+ bar->priv->zfs_dir_monitor_data = NULL;
+ nautilus_directory_cancel_restore_info (bar->priv->dir);
+}
+
+GtkWidget *
+nautilus_zfs_bar_new ()
+{
+ GObject *bar;
+ NautilusZfsBar *zfs_bar;
+
+ bar = g_object_new (NAUTILUS_TYPE_ZFS_BAR, NULL);
+
+ g_signal_connect_object (bar, "show", G_CALLBACK (zfs_bar_show_column), bar, NULL);
+ g_signal_connect_object (bar, "hide", G_CALLBACK (zfs_bar_show_column), bar, NULL);
+ g_signal_connect_object (bar, "hide", G_CALLBACK (zfs_bar_hidden), bar, NULL);
+
+ zfs_bar_show_column (GTK_WIDGET (bar), NULL);
+
+ ts_is_restore_column_enabled_init ();
+
+ zfs_bar = NAUTILUS_ZFS_BAR (bar);
+
+ return GTK_WIDGET (bar);
+}
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-zfs-bar.h nautilus-2.30.1/src/nautilus-zfs-bar.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/nautilus-zfs-bar.h 1970-01-01 01:00:00.000000000 +0100
+++ nautilus-2.30.1/src/nautilus-zfs-bar.h 2010-05-14 17:16:39.568719551 +0200
@@ -0,0 +1,57 @@
+#ifndef __NAUTILUS_ZFS_BAR_H
+#define __NAUTILUS_ZFS_BAR_H
+
+#include <gtk/gtk.h>
+#include <libnautilus-private/nautilus-directory.h>
+#include "nautilus-window-slot.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_ZFS_BAR (nautilus_zfs_bar_get_type ())
+#define NAUTILUS_ZFS_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_ZFS_BAR, NautilusZfsBar))
+#define NAUTILUS_ZFS_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NAUTILUS_TYPE_ZFS_BAR, NautilusZfsBarClass))
+#define NAUTILUS_IS_ZFS_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAUTILUS_TYPE_ZFS_BAR))
+#define NAUTILUS_IS_ZFS_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NAUTILUS_TYPE_ZFS_BAR))
+#define NAUTILUS_ZFS_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NAUTILUS_TYPE_ZFS_BAR, NautilusZfsBarClass))
+
+typedef struct NautilusZfsBarPrivate NautilusZfsBarPrivate;
+
+typedef struct
+{
+ GtkEventBox eventbox;
+ NautilusZfsBarPrivate *priv;
+} NautilusZfsBar;
+
+typedef struct
+{
+ GtkEventBoxClass parent_class;
+} NautilusZfsBarClass;
+
+GType nautilus_zfs_bar_get_type (void) G_GNUC_CONST;
+
+GtkWidget *nautilus_zfs_bar_new ();
+
+void nautilus_zfs_bar_setup (NautilusZfsBar* bar,
+ NautilusDirectory *dir,
+ NautilusWindowSlot *active_slot,
+ GtkToggleAction* action);
+
+void nautilus_zfs_bar_display (NautilusZfsBar *bar,
+ NautilusWindow *window,
+ NautilusDirectory *new_dir,
+ GCancellable* cancellable);
+
+void nautilus_zfs_set_snap (NautilusZfsBar *bar,
+ NautilusDirectory *dir);
+void nautilus_zfs_bar_remove_and_skip_snap
+ (NautilusZfsBar *bar, char *path);
+
+void nautilus_zfs_bar_hide (NautilusZfsBar *bar);
+
+void nautilus_zfs_bar_cancel_tasks (NautilusWindow *window);
+NautilusDirectory * nautilus_zfs_bar_get_dir (NautilusZfsBar* bar);
+G_END_DECLS
+
+
+
+#endif /* __NAUTILUS_ZFS_BAR_H */
--- /dev/null 2011-07-25 13:54:15.000000000 +0100
+++ nautilus-3.1.3/src/timescale.c 2011-07-25 13:53:42.519729725 +0100
@@ -0,0 +1,1278 @@
+/*
+ * Copyright (C) 2010 Sun Microsystems (Erwann Chenede)
+ *
+ */
+
+#include "config.h"
+#include "timescale.h"
+#include <math.h>
+#include <stdlib.h>
+#include <libnautilus-private/nautilus-zfs.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+
+#define BAR_W_MAX 20
+#define BAR_SPACE 2
+
+
+typedef struct
+{
+ char *name;
+ char *mountpoint;
+ char *mtime_str;
+ char *mtime_short_str;
+ time_t mtime;
+ float used_space;
+ char *used_space_str;
+ SnapType type;
+ char *type_str;
+} Snap;
+
+
+struct TimeScalePrivate
+{
+ GList* all_snaps;
+ GList* snaps;
+ int* bar_x_end;
+ int current_pos;
+ int num_snaps;
+ char *num_rev_string;
+ int current_period;
+ GList *today;
+ GList *yesterday;
+ GList *this_week;
+ GList *last_week;
+ GList *this_month;
+ GList *last_month;
+ gboolean scrollbar_set;
+ gboolean key_pressed;
+ GtkWidget *darea;
+ GtkWidget *period;
+ GtkWidget *info;
+ GtkWidget *scrolled;
+ GtkWidget *label_tip;
+};
+
+enum {
+ VALUE_CHANGED,
+ LAST_SIGNAL
+};
+
+enum {
+ ALL,
+ TODAY,
+ YESTERDAY,
+ THIS_WEEK,
+ LAST_WEEK,
+ THIS_MONTH,
+ LAST_MONTH
+};
+
+enum {
+ COLUMN_INDEX,
+ COLUMN_STRING
+};
+
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (TimeScale, timescale, GTK_TYPE_HBOX)
+
+#define TIMESCALE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_TIMESCALE, TimeScalePrivate))
+
+static gboolean
+timescale_expose (GtkWidget *widget,
+ GdkEventExpose *event, TimeScale *ts);
+static gboolean
+query_tooltip (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_tip,
+ GtkTooltip *tooltip,
+ gpointer data);
+static int
+key_pressed (GtkWidget *widget, GdkEventKey *event, TimeScale *ts);
+static void
+button_pressed (GtkWidget *widget, GdkEventButton *event, TimeScale *ts);
+
+static void print_snaps (GList *list)
+{
+ GList* tmp = list;
+ int i = 0;
+
+ while (tmp)
+ {
+ Snap *snap = (Snap*) tmp->data;
+ printf ("=-= %d =-=\nname: %s\nmountpoint: %s\nmtime: %s\nused_space: %s\n",i,
+ snap->name, snap->mountpoint, snap->mtime_str, snap->used_space_str);
+ i++;
+ tmp = tmp->next;
+ }
+}
+
+static char * get_num_snap_string (GList *snap_list)
+{
+ goffset total = 0;
+ int i = 0;
+ GList *tmp = snap_list;
+ char *num_rev;
+
+ char *size_str = NULL;
+
+ for (tmp; tmp; tmp = tmp->next)
+ {
+ Snap *snap = ((Snap*) tmp->data);
+ total += snap->used_space;
+ i++;
+ }
+
+ total *= 1024;
+
+ size_str = g_format_size_for_display (total);
+
+ /* SUN_BRANDING */
+ num_rev = g_strdup_printf (_("%d %s\n%s"),
+ i,
+ /* SUN_BRANDING */
+ ngettext ("snapshot", "snapshots", i),
+ size_str);
+ g_free (size_str);
+
+ return num_rev;
+}
+
+
+static char * get_date (GDate *date)
+{
+ return g_strdup_printf ("%d/%d/%d", g_date_get_day (date),
+ g_date_get_month (date),
+ g_date_get_year (date));
+}
+
+static GList *trim_list_by_date (GList *list, int type)
+{
+ GDate then;
+ GDate now;
+ GDate range_min;
+ GDate range_max;
+ GDateWeekday weekday;
+
+ time_t time_now;
+ int diff = 0;
+ time_now = time (NULL);
+ g_date_set_time_t (&now, time_now);
+ g_date_set_time_t (&range_min, time_now);
+ GList *return_list = NULL;
+ int days_diff = 0;
+ gboolean range = FALSE;
+
+ switch (type)
+ {
+ case TODAY:
+ days_diff = 0;
+ break;
+ case YESTERDAY:
+ days_diff = 1;
+ break;
+ case THIS_WEEK:
+ weekday = g_date_get_weekday(&now);
+ days_diff = weekday - G_DATE_MONDAY;
+ memcpy (&range_max, &range_min, sizeof (GDate));
+ g_date_subtract_days (&range_min, days_diff);
+ range = TRUE;
+ break;
+ case LAST_WEEK:
+ g_date_subtract_days (&range_min, 7);
+ weekday = g_date_get_weekday(&range_min);
+ days_diff = weekday - G_DATE_MONDAY;
+ g_date_subtract_days (&range_min, days_diff);
+ memcpy (&range_max, &range_min, sizeof (GDate));
+ g_date_add_days (&range_max, 6);
+ range = TRUE;
+ break;
+ case THIS_MONTH:
+ g_date_set_dmy (&range_min, 1, g_date_get_month (&now),
+ g_date_get_year (&now));
+ g_date_set_time_t (&range_max, time_now);
+ range = TRUE;
+ break;
+ case LAST_MONTH:
+ g_date_subtract_months (&range_min, 1);
+ g_date_set_dmy (&range_min, 1,
+ g_date_get_month (&range_min),
+ g_date_get_year (&range_min));
+ memcpy (&range_max, &range_min, sizeof (GDate));
+ g_date_add_days (&range_max, g_date_get_days_in_month (g_date_get_month (&range_min), g_date_get_year (&range_min)) - 1);
+ range = TRUE;
+ break;
+ }
+
+ while (list)
+ {
+ Snap* snap = (Snap*) list->data;
+
+ if (snap->mtime != 0)
+ {
+ g_date_set_time_t (&then, snap->mtime);
+
+ if (!range)
+ {
+ if (g_date_get_julian (&now) - g_date_get_julian (&then) == days_diff)
+ return_list = g_list_append (return_list, snap);
+ }
+ else
+ {
+ if (g_date_compare (&then, &range_min) >= 0 && g_date_compare (&then, &range_max) <= 0)
+ return_list = g_list_append (return_list, snap);
+ }
+ }
+ list = list->next;
+ }
+ return return_list;
+}
+
+
+static void
+free_periods (TimeScale *ts)
+{
+ if (ts->priv->today)
+ {
+ g_list_free (ts->priv->today);
+ ts->priv->today = NULL;
+ }
+ if (ts->priv->yesterday)
+ {
+ g_list_free (ts->priv->yesterday);
+ ts->priv->yesterday = NULL;
+ }
+ if (ts->priv->this_week)
+ {
+ g_list_free (ts->priv->this_week);
+ ts->priv->this_week = NULL;
+ }
+ if (ts->priv->last_week)
+ {
+ g_list_free (ts->priv->last_week);
+ ts->priv->last_week = NULL;
+ }
+ if (ts->priv->this_month)
+ {
+ g_list_free (ts->priv->this_month);
+ ts->priv->this_month = NULL;
+ }
+ if (ts->priv->last_month)
+ {
+ g_list_free (ts->priv->last_month);
+ ts->priv->last_month = NULL;
+ }
+}
+
+static GtkListStore *
+create_periods (TimeScale *ts)
+{
+ GtkTreeIter iter;
+ GtkListStore* periods = gtk_list_store_new (3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_POINTER);
+
+ free_periods (ts);
+
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, ALL, 1, _("All"), 2, ts->priv->all_snaps, -1);
+
+ ts->priv->today = trim_list_by_date (ts->priv->all_snaps, TODAY);
+
+ if (ts->priv->today)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, TODAY, 1, _("Today"), 2, ts->priv->today, -1);
+ }
+
+ ts->priv->yesterday = trim_list_by_date (ts->priv->all_snaps, YESTERDAY);
+ if (ts->priv->yesterday)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, YESTERDAY, 1, _("Yesterday"), 2, ts->priv->yesterday, -1);
+ }
+
+ ts->priv->this_week = trim_list_by_date (ts->priv->all_snaps, THIS_WEEK);
+ if (ts->priv->this_week)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, THIS_WEEK, 1, _("This Week"), 2, ts->priv->this_week, -1);
+ }
+
+ ts->priv->last_week = trim_list_by_date (ts->priv->all_snaps, LAST_WEEK);
+ if (ts->priv->last_week)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, LAST_WEEK, 1, _("Last Week"), 2, ts->priv->last_week, -1);
+ }
+
+ ts->priv->this_month = trim_list_by_date (ts->priv->all_snaps, THIS_MONTH);
+ if (ts->priv->this_month)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, THIS_MONTH, 1, _("This Month"), 2, ts->priv->this_month, -1);
+ }
+
+ ts->priv->last_month = trim_list_by_date (ts->priv->all_snaps, LAST_MONTH);
+ if (ts->priv->last_month)
+ {
+ gtk_list_store_append (periods, &iter);
+ gtk_list_store_set (periods, &iter, 0, LAST_MONTH, 1, _("Last Month"), 2, ts->priv->last_month, -1);
+ }
+
+ return periods;
+}
+
+static void
+period_changed (GtkComboBox *combo,
+ TimeScale *ts)
+{
+ gint type;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *period;
+
+ if (!gtk_combo_box_get_active_iter (combo, &iter))
+ return;
+
+ model = gtk_combo_box_get_model (combo);
+
+ gtk_tree_model_get (model, &iter, 0, &type, 2, &period, -1);
+
+ if (ts->priv->current_period == type)
+ return;
+
+ ts->priv->current_period = type;
+
+ ts->priv->snaps = period;
+
+ ts->priv->num_snaps = g_list_length (ts->priv->snaps);
+ if (ts->priv->bar_x_end)
+ g_free (ts->priv->bar_x_end);
+
+ ts->priv->bar_x_end = g_new (int, g_list_length (ts->priv->snaps));
+
+ ts->priv->current_pos = -1;
+
+ if (ts->priv->num_rev_string)
+ g_free (ts->priv->num_rev_string);
+
+ ts->priv->num_rev_string = get_num_snap_string (ts->priv->snaps);
+ gtk_label_set_label (GTK_LABEL (ts->priv->info), ts->priv->num_rev_string);
+
+ gtk_widget_set_size_request (ts->priv->darea, ((BAR_SPACE + BAR_W_MAX ) * ts->priv->num_snaps) + PADDING * 2, 60);
+
+ gtk_widget_queue_draw (ts->priv->darea);
+}
+
+static void
+timescale_init (TimeScale *ts)
+{
+ GtkWidget *vbox;
+ GtkCellRenderer *renderer;
+
+ ts->priv = TIMESCALE_GET_PRIVATE (ts);
+ ts->priv->snaps = NULL;
+ ts->priv->all_snaps = NULL;
+ ts->priv->num_snaps = 0;
+ ts->priv->bar_x_end = NULL;
+ ts->priv->current_pos = 0;
+ ts->priv->num_rev_string = NULL;
+ ts->priv->current_period = ALL;
+ ts->priv->today = NULL;
+ ts->priv->yesterday = NULL;
+ ts->priv->this_week = NULL;
+ ts->priv->last_week = NULL;
+ ts->priv->this_month = NULL;
+ ts->priv->last_month = NULL;
+ ts->priv->key_pressed = FALSE;
+
+ gtk_box_set_homogeneous (GTK_BOX (ts), FALSE);
+
+ /* setup drawing area */
+
+ ts->priv->darea = gtk_drawing_area_new ();
+
+ g_signal_connect(ts->priv->darea, "expose-event",
+ G_CALLBACK(timescale_expose), ts);
+
+ g_signal_connect (ts->priv->darea, "query-tooltip",
+ G_CALLBACK (query_tooltip), ts);
+
+ g_signal_connect(ts->priv->darea, "key-press-event",
+ G_CALLBACK(key_pressed), ts);
+ g_signal_connect(ts->priv->darea, "button_press_event",
+ G_CALLBACK(button_pressed), ts);
+ gtk_widget_set_can_focus (GTK_WIDGET (ts->priv->darea), TRUE);
+ gtk_widget_add_events (GTK_WIDGET (ts->priv->darea), GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK);
+ g_object_set (G_OBJECT (ts->priv->darea), "has-tooltip", TRUE, NULL);
+ gtk_widget_set_size_request (GTK_WIDGET (ts->priv->darea), -1, 60);
+
+ ts->priv->scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ts->priv->scrolled),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (ts->priv->scrolled),
+ ts->priv->darea);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (ts->priv->scrolled))), GTK_SHADOW_NONE);
+ gtk_widget_show (ts->priv->scrolled);
+
+ ts->priv->label_tip = gtk_label_new ("Hello");
+ gtk_widget_set_name (ts->priv->label_tip, "gtk-tooltip");
+ g_object_ref_sink (ts->priv->label_tip);
+ gtk_label_set_justify (GTK_LABEL (ts->priv->label_tip), GTK_JUSTIFY_CENTER);
+
+ /* setup period combo and snap info */
+
+ vbox = gtk_vbox_new (FALSE, 5);
+ ts->priv->period = gtk_combo_box_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ts->priv->period),
+ renderer,
+ TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (ts->priv->period), renderer,
+ "text", 1,
+ NULL);
+ g_signal_connect (ts->priv->period, "changed", G_CALLBACK (period_changed), ts);
+
+ ts->priv->info = gtk_label_new ("info\ninfo");
+ gtk_label_set_justify (GTK_LABEL (ts->priv->info), GTK_JUSTIFY_CENTER);
+ gtk_box_pack_start (GTK_BOX (vbox), ts->priv->period, FALSE, FALSE, 5);
+ gtk_box_pack_end (GTK_BOX (vbox), ts->priv->info, FALSE, FALSE, 5);
+
+ /* setup container */
+
+ gtk_box_pack_start (GTK_BOX (ts), vbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (ts), ts->priv->scrolled, TRUE, TRUE, 0);
+
+ gtk_widget_set_can_focus (GTK_WIDGET (ts), TRUE);
+ gtk_widget_show_all (GTK_WIDGET (ts));
+}
+
+static float
+get_max_snap_size (GList *snaps)
+{
+ Snap *snap;
+ float max_size = 0;
+ while (snaps)
+ {
+ GList *next = snaps->next;
+ snap = (Snap*) snaps->data;
+ if (snap->used_space > max_size)
+ max_size = snap->used_space;
+ snaps = next;
+ }
+ return max_size;
+}
+
+
+static Snap*
+get_now_snap (TimeScale* ts)
+{
+ Snap *last_snap;
+ last_snap = g_new0 (Snap, 1);
+ last_snap->name = g_strdup (_("Now"));
+ last_snap->mountpoint = g_strdup (_("None"));
+ last_snap->mtime_str = g_strdup (_("Now"));
+ last_snap->mtime_short_str = g_strdup (_("Now"));
+ last_snap->used_space_str = g_strdup (_("-"));
+ last_snap->used_space = 0.0;
+ last_snap->type = NOW;
+ last_snap->type_str = g_strdup (_("Current Directory"));
+ return last_snap;
+}
+
+static char *get_type_str (SnapType type)
+{
+ switch (type)
+ {
+ case LOCAL_AUTOMATIC:
+ return g_strdup (_("Automatic Snapshot"));
+ break;
+ case LOCAL_MANUAL:
+ return g_strdup (_("Manual Snapshot"));
+ break;
+ case REMOTE_AUTOMATIC:
+ return g_strdup (_("Automatic Remote Backup"));
+ break;
+ case REMOTE_MANUAL:
+ return g_strdup (_("Manual Remote Backup"));
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static SnapType
+get_type (ZfsDataSet* snap)
+{
+ if (snap->type)
+ {
+ if (strstr (snap->name, "zfs-auto-snap"))
+ return LOCAL_AUTOMATIC;
+ else
+ return LOCAL_MANUAL;
+ }
+ else
+ {
+ if (strstr (snap->name, "zfs-auto-snap"))
+ return REMOTE_AUTOMATIC;
+ else
+ return REMOTE_MANUAL;
+ }
+}
+
+static GList *
+copy_zfs_list (GList *list)
+{
+ ZfsDataSet *snap;
+ GList *new_list = NULL;
+ Snap *ts_shot;
+ GList *tmp_list = list;
+ while (tmp_list)
+ {
+ snap = (ZfsDataSet*) tmp_list->data;
+ ts_shot = g_new0 (Snap, 1);
+ ts_shot->name = g_strdup (snap->name);
+ ts_shot->mountpoint = g_strdup (snap->mountpoint);
+ ts_shot->mtime_str = g_strdup (snap->mtime_str);
+ ts_shot->mtime_short_str = nautilus_date_as_string (snap->mtime, TRUE);
+ ts_shot->used_space_str = g_strdup (snap->used_space_str);
+ ts_shot->used_space = snap->used_space;
+ ts_shot->mtime = snap->mtime;
+ ts_shot->type = get_type (snap);
+ ts_shot->type_str = get_type_str (ts_shot->type);
+ new_list = g_list_append (new_list, ts_shot);
+ tmp_list = tmp_list->next;
+ }
+ return new_list;
+}
+
+static void
+free_snap (Snap *snap)
+{
+ if (snap->name)
+ g_free (snap->name);
+ if (snap->mountpoint)
+ g_free (snap->mountpoint);
+ if (snap->mtime_str)
+ g_free (snap->mtime_str);
+ if (snap->mtime_short_str)
+ g_free (snap->mtime_short_str);
+ if (snap->used_space_str)
+ g_free (snap->used_space_str);
+ if (snap->type_str)
+ g_free (snap->type_str);
+
+ g_free (snap);
+}
+
+static void
+free_snap_list (GList *list)
+{
+ GList *tmp_list = list;
+ while (tmp_list)
+ {
+ free_snap ((Snap*) tmp_list->data);
+ tmp_list = tmp_list->next;
+ }
+}
+
+
+void
+timescale_set_snapshots (TimeScale* ts, GList *list, int init_position)
+{
+ if (ts->priv->bar_x_end)
+ g_free (ts->priv->bar_x_end);
+
+ if (ts->priv->num_rev_string)
+ g_free (ts->priv->num_rev_string);
+
+ if (ts->priv->all_snaps)
+ free_snap_list (ts->priv->all_snaps);
+
+ ts->priv->all_snaps = copy_zfs_list (list);
+ ts->priv->all_snaps = g_list_append (ts->priv->all_snaps, get_now_snap(ts));
+ ts->priv->snaps = ts->priv->all_snaps;
+ ts->priv->num_snaps = g_list_length (ts->priv->snaps);
+
+ ts->priv->bar_x_end = g_new (int, g_list_length (ts->priv->snaps));
+ ts->priv->current_pos = ts->priv->num_snaps - 1;
+
+ if (init_position >= 0 && init_position <= ts->priv->num_snaps - 1)
+ ts->priv->current_pos = init_position;
+
+ ts->priv->num_rev_string = get_num_snap_string (ts->priv->snaps);
+
+ gtk_label_set_label (GTK_LABEL (ts->priv->info), ts->priv->num_rev_string);
+ ts->priv->current_period = ALL;
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (ts->priv->period), GTK_TREE_MODEL (create_periods (ts)));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (ts->priv->period), ALL);
+
+ gtk_widget_set_size_request (ts->priv->darea, ((BAR_SPACE + BAR_W_MAX) * ts->priv->num_snaps) + PADDING * 2, 60);
+ ts->priv->scrollbar_set = FALSE;
+}
+
+GtkWidget*
+timescale_new ()
+{
+ return g_object_new (TYPE_TIMESCALE, NULL);
+}
+
+static void draw_type (cairo_t *cr, int x_c, int y_c, int w, SnapType type)
+{
+ int x = x_c - w/2;
+ int y = y_c - w/2;
+
+
+
+ switch (type)
+ {
+ case LOCAL_MANUAL:
+ cairo_move_to (cr,x,y_c);
+ cairo_line_to (cr,x+w/2,y_c-w/2);
+ cairo_line_to (cr,x+w,y_c);
+ /*y = y_c - w/4;
+ cairo_rectangle (cr, x, y, w, w/2);*/
+ break;
+ case LOCAL_AUTOMATIC:
+ cairo_arc (cr, x_c, y_c, w/2, M_PI, M_PI*2);
+ break;
+ case REMOTE_MANUAL:
+ /* cairo_rectangle (cr, x, y, w, w); */
+ cairo_move_to (cr,x,y_c);
+ cairo_line_to (cr,x+w/2,y_c+w/2);
+ cairo_line_to (cr,x+w,y_c);
+ cairo_line_to (cr,x+w/2,y_c-w/2);
+ break;
+ case REMOTE_AUTOMATIC:
+ cairo_arc (cr, x_c, y_c, w/2, 0.0, M_PI*2);
+ break;
+ default:
+ break;
+ }
+}
+
+static void draw_rounded_bar (cairo_t *cr, int x, int y, double w, double h, int r)
+{
+ /* bottom y instead of top */
+ y -= h;
+
+ if (h == 0 || h < (w / 2) + r)
+ {
+ y += h;
+ cairo_arc (cr, x+(w/2), y+.5, w/2, M_PI, M_PI*2);
+ cairo_line_to (cr,x,y+.5);
+ return;
+ }
+
+ /* A****BQ
+ H C
+ * *
+ G D
+ F****E */
+
+
+ cairo_arc (cr, x+(w/2), y+(w/2), w/2, M_PI, M_PI*2); /* arc from H to C */
+ cairo_line_to (cr,x+w,y+h-r); /* Move to D */
+ cairo_curve_to(cr, x+w,y+h,x+w,y+h,x+w-r,y+h); /* Curve to E */
+ cairo_line_to(cr, x+r,y+h); /* Line to F */
+ cairo_curve_to(cr, x,y+h,x,y+h,x,y+h-r); /* Curve to G */
+ cairo_line_to(cr, x,y+(w/2)); /* Line to H */
+
+}
+
+
+
+static void draw_rounded_rec (cairo_t *cr, int x, int y, double w, double h, int r)
+{
+ /* bottom y instead of top */
+ y -= h;
+
+ if (h == 0)
+ {
+ cairo_set_line_width (cr, 1);
+ cairo_move_to (cr,x,y - .5);
+ cairo_line_to (cr, x + w, y -.5);
+ return;
+ }
+
+ if (h < r * 2)
+ r = h / 2;
+
+ /* A****BQ
+ H C
+ * *
+ G D
+ F****E */
+
+ cairo_move_to (cr,x+r,y); /* Move to A */
+ cairo_line_to (cr,x+w-r,y); /* Straight line to B */
+ cairo_curve_to (cr,x+w,y,x+w,y,x+w,y+r); /* Curve to C, Control points are both at Q */
+ cairo_line_to (cr,x+w,y+h-r); /* Move to D */
+ cairo_curve_to(cr, x+w,y+h,x+w,y+h,x+w-r,y+h); /* Curve to E */
+ cairo_line_to(cr, x+r,y+h); /* Line to F */
+ cairo_curve_to(cr, x,y+h,x,y+h,x,y+h-r); /* Curve to G */
+ cairo_line_to(cr, x,y+r); /* Line to H */
+ cairo_curve_to(cr, x,y,x,y,x+r,y); /* Curve to A */
+}
+
+static void
+set_cr_color (GtkWidget *widget, cairo_t* cr, SnapType type, double alpha)
+{
+ GtkStyle *style = gtk_widget_get_style(widget);
+ switch (type)
+ {
+ case LOCAL_MANUAL:
+ case REMOTE_MANUAL:
+ gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_SELECTED]);
+ gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_SELECTED]);
+ break;
+ case LOCAL_AUTOMATIC:
+ case REMOTE_AUTOMATIC:
+ gdk_cairo_set_source_color (cr, &style->light[GTK_STATE_SELECTED]);
+ break;
+ case NOW:
+ gdk_cairo_set_source_color (cr, &style->black);
+ break;
+ default:
+ break;
+ }
+}
+
+int get_snap_index_from_coord (TimeScale* ts, gdouble x, gdouble y)
+{
+ int i;
+
+ for (i = 0; i < ts->priv->num_snaps; i++)
+ {
+ if (x < ts->priv->bar_x_end[i])
+ return i;
+ }
+ return -1;
+}
+
+static gboolean
+timescale_expose (GtkWidget *widget,
+ GdkEventExpose *event, TimeScale* ts)
+{
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ PangoRectangle logical_rect;
+ gint ascent, descent;
+ cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
+ int i = 0;
+ double x;
+ int y;
+ int selected_x = -1;
+ int remaining_timeline_space;
+ int remaining_x_start;
+ int remaining_x_end;
+ int bar_space = BAR_SPACE;
+ int bar_w = BAR_W_MAX;
+ int line_padding = 3;
+ float bar_max_h_inc;
+ float bar_max_h;
+ int last_bar_x;
+ int line_height = 0;
+ int timeline_line_height = 0;
+ float max_size = 0;
+ GList *view_snaps = NULL;
+ int num_view_snaps = 0;
+ PangoLayout *layout = pango_cairo_create_layout (cr);
+ Snap *tmp_snap = NULL;
+ gboolean space_left = TRUE;
+ PangoFontDescription *timeline_font = NULL;
+ GtkStyle *style = gtk_widget_get_style(widget);
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation(widget, &allocation);
+
+ if (gtk_widget_has_focus (widget))
+ gtk_paint_focus (style, cr, gtk_widget_get_state (widget),
+ widget, NULL,
+ 0, 0,
+ allocation.width-1, allocation.height-1);
+
+ if (!ts->priv->snaps)
+ goto end;
+
+ /* smaller font for timeline */
+
+ timeline_font = pango_font_description_copy_static(style->font_desc);
+ pango_font_description_set_size (timeline_font, pango_font_description_get_size (timeline_font) - (PANGO_SCALE*2));
+
+ /* determine space needed for 2 lines of text + padding with
+ * current widget->style->font_desc
+ * and widget->style->font_desc - 1*/
+
+ context = gtk_widget_get_pango_context (widget);
+ metrics = pango_context_get_metrics (context, style->font_desc,
+ pango_context_get_language (context));
+ ascent = pango_font_metrics_get_ascent (metrics);
+ descent = pango_font_metrics_get_descent (metrics);
+ pango_font_metrics_unref (metrics);
+
+ line_height = PANGO_PIXELS (ascent + descent);
+
+ metrics = pango_context_get_metrics (context, timeline_font,
+ pango_context_get_language (context));
+ ascent = pango_font_metrics_get_ascent (metrics);
+ descent = pango_font_metrics_get_descent (metrics);
+ pango_font_metrics_unref (metrics);
+
+ timeline_line_height = PANGO_PIXELS (ascent + descent);
+
+
+ x = PADDING;
+ bar_max_h = allocation.height - ((line_height + timeline_line_height) + PADDING * 4);
+ y = allocation.height - (line_height + (PADDING * 2));
+
+ num_view_snaps = ts->priv->num_snaps;
+ view_snaps = ts->priv->snaps;
+
+ max_size = log ((float)get_max_snap_size (view_snaps));
+
+ bar_max_h_inc = max_size / bar_max_h;
+
+ if (!ts->priv->scrollbar_set)
+ {
+ GtkAdjustment *adj;
+ adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled));
+ gtk_adjustment_set_value (adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
+ gtk_adjustment_set_step_increment(adj, BAR_W_MAX + BAR_SPACE);
+ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
+ ts->priv->scrollbar_set = TRUE;
+ }
+
+ /* draw the bars */
+
+ cairo_set_line_width (cr, 1);
+
+ for (i = 0; i < num_view_snaps; i++)
+ {
+ tmp_snap = g_list_nth_data (view_snaps, i);
+ int rounded_radius = ROUNDED_RADIUS;
+ int height = 0;
+ gboolean draw_bar = TRUE;
+ double alpha = 1.0;
+
+ if (tmp_snap->used_space != 0)
+ height = (int) log (tmp_snap->used_space) / bar_max_h_inc;
+
+ /*printf ("drawing %d height %d size %f log of size %f\n", i,
+ height,
+ tmp_snap->used_space, log (tmp_snap->used_space));*/
+
+ if (height == 0 & tmp_snap->used_space != 0)
+ height = 1;
+
+ if (tmp_snap->type == REMOTE_AUTOMATIC ||
+ tmp_snap->type == REMOTE_MANUAL)
+ height = bar_max_h - bar_max_h_inc; /* placeholder until we get rsync size */
+
+ if (height < ROUNDED_RADIUS)
+ height = 0;
+
+ /* printf ("height %d name %s size %s\n", height, tmp_snap->name, tmp_snap->used_space_str); */
+
+ if (i == ts->priv->current_pos)
+ {
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1);
+ draw_rounded_rec (cr, x-1, y+2, bar_w+2, bar_max_h+8, ROUNDED_RADIUS);
+
+ cairo_fill (cr);
+ cairo_stroke(cr);
+
+ alpha = 0.5;
+ selected_x = x-1 + ((bar_w+2) / 2);
+
+ if (tmp_snap->type != NOW)
+ {
+ char *selected_time_size = g_strdup_printf ("%s - %s",
+ tmp_snap->mtime_str,
+ tmp_snap->used_space_str);
+ gdk_cairo_set_source_color (cr, style->text);
+ pango_layout_set_font_description (layout, style->font_desc);
+ pango_layout_set_text (layout, selected_time_size, -1);
+ g_free (selected_time_size);
+ }
+ else
+ pango_layout_set_text (layout, tmp_snap->mtime_str, -1);
+ }
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.8);
+
+ ts->priv->bar_x_end[i] = x + bar_w;
+
+ if (draw_bar)
+ {
+ int tmp_y = y;
+ float tmp_w = bar_w;
+ set_cr_color (widget, cr, tmp_snap->type, 1.0);
+ if (tmp_snap->type == LOCAL_AUTOMATIC || tmp_snap->type == LOCAL_MANUAL)
+ {
+ tmp_y -= 1;
+ tmp_w -= 1;
+ }
+
+ if (tmp_snap->type == LOCAL_AUTOMATIC || tmp_snap->type == REMOTE_AUTOMATIC)
+ draw_rounded_bar (cr, x, tmp_y, tmp_w, height, rounded_radius);
+ else if (tmp_snap->type == LOCAL_MANUAL || tmp_snap->type == REMOTE_MANUAL)
+ draw_rounded_rec (cr, x, tmp_y, tmp_w, height, rounded_radius);
+ else /* Now Shape */
+ draw_type (cr, (x + ((bar_w+bar_space)/2)) - .5, y - (bar_max_h/2), bar_w - 4, REMOTE_MANUAL);
+
+ if (tmp_snap->type == REMOTE_MANUAL || tmp_snap->type == REMOTE_AUTOMATIC || tmp_snap->type == NOW)
+ cairo_fill (cr);
+ }
+
+ cairo_stroke(cr);
+
+ x += bar_w + bar_space;
+ }
+
+ last_bar_x = x;
+
+ /* ensure selected bar is visible on key press when scrollbar is enabled */
+
+ if (ts->priv->current_pos != -1 && ts->priv->key_pressed)
+ {
+
+ GtkAdjustment *adj;
+ adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled));
+ ts->priv->key_pressed = FALSE;
+
+ if (gtk_adjustment_get_value(adj) > selected_x)
+ {
+ gtk_adjustment_set_value (adj, selected_x - BAR_W_MAX);
+ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
+ }
+ if (gtk_adjustment_get_value(adj) + gtk_adjustment_get_page_size(adj) < selected_x)
+ {
+ gtk_adjustment_set_value (adj, (selected_x + BAR_W_MAX) - gtk_adjustment_get_page_size(adj));
+ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (ts->priv->scrolled), adj);
+ }
+ }
+
+ pango_layout_set_font_description (layout, style->font_desc);
+
+ /* try to center the selected text */
+
+ pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
+
+ if (ts->priv->current_pos != -1 && selected_x != -1)
+ {
+
+ int right_space = last_bar_x - selected_x;
+
+ if (logical_rect.width /2 > selected_x)
+ /* no space on the left, left align */
+ selected_x = PADDING;
+ else if (logical_rect.width /2 > right_space)
+ /* no space on the right, right align */
+ selected_x = last_bar_x - logical_rect.width;
+ else
+ selected_x -= logical_rect.width /2;
+
+ if (selected_x < 0)
+ selected_x = PADDING;
+
+ /* draw background */
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1);
+ draw_rounded_rec (cr, selected_x-2, line_height + 3 , logical_rect.width + 4, line_height+1, ROUNDED_RADIUS);
+ cairo_fill (cr);
+ cairo_stroke(cr);
+
+ /* then selected text */
+ gdk_cairo_set_source_color (cr, style->text);
+ cairo_move_to(cr, selected_x, PADDING);
+ pango_cairo_show_layout (cr, layout);
+ }
+
+ /* timeline */
+
+ /* what to do
+ * try to draw oldest
+ * then "now" first
+ * then in between dates
+ * draw additional is possible starting with newest first */
+
+ x = PADDING;
+
+
+ /* Can the oldest time fit ? */
+ tmp_snap = g_list_nth_data (view_snaps, 0);
+ pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
+ pango_layout_set_font_description (layout, timeline_font);
+ pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
+
+ if (logical_rect.width > allocation.width)
+ goto end;
+
+ /* draw anchor line */
+
+ x += bar_w/2 + .5;
+
+ cairo_set_line_width (cr, 1);
+ gdk_cairo_set_source_color (cr, style->text_aa);
+ cairo_move_to (cr, x, allocation.height - ((line_height + PADDING*2)-1));
+ cairo_line_to (cr, x, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_line_to (cr, x+2.5, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_stroke(cr);
+
+ x += 3;
+
+ gdk_cairo_set_source_color (cr, style->text_aa);
+ cairo_move_to(cr, x, allocation.height - (line_height + PADDING));
+ pango_cairo_show_layout (cr, layout);
+
+ remaining_timeline_space = last_bar_x - (x + logical_rect.width);
+
+ remaining_x_start = x + logical_rect.width;
+
+ /* try to draw last item */
+
+ tmp_snap = g_list_nth_data (view_snaps, num_view_snaps-1);
+ pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
+ pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
+
+ if (remaining_timeline_space < (logical_rect.width + bar_w))
+ goto end;
+
+ remaining_timeline_space -= logical_rect.width + bar_w;
+
+ x = last_bar_x;
+
+
+ x -= bar_space + bar_w/2 + 0.5;
+
+ cairo_move_to (cr, x, allocation.height - ((line_height + PADDING*2)-2));
+ cairo_line_to (cr, x, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_line_to (cr, x-2.5, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_stroke(cr);
+
+ cairo_move_to(cr, x - (logical_rect.width + 3.5),
+ allocation.height - (line_height + PADDING));
+ pango_cairo_show_layout (cr, layout);
+
+ remaining_x_end = x - (logical_rect.width + 3.5);
+
+ /* now find the next bar that we can to the timeline and loop */
+
+
+ while (space_left)
+ {
+ int bar = get_snap_index_from_coord (ts, remaining_x_start, 0);
+ /* get the next snap */
+ bar++;
+ if (bar >= num_view_snaps)
+ goto end;
+
+ tmp_snap = g_list_nth_data (view_snaps, bar);
+ pango_layout_set_text (layout, tmp_snap->mtime_short_str, -1);
+
+ pango_layout_get_pixel_extents (layout,NULL, &logical_rect);
+
+ if (remaining_timeline_space < logical_rect.width + 4)
+ goto end;
+
+ /* get middle x coord of current bar */
+
+ x = PADDING + ((bar_w + bar_space) * bar) + bar_w / 2;
+
+ if ( x + 4 + logical_rect.width > remaining_x_end)
+ goto end;
+
+ /* draw anchor and text */
+ x += 0.5;
+
+ cairo_move_to (cr, x, allocation.height - ((line_height + PADDING*2)-1));
+ cairo_line_to (cr, x, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_line_to (cr, x+2.5, allocation.height - (line_height/2 + PADDING)-.5);
+ cairo_stroke(cr);
+
+ x += 3;
+
+ cairo_move_to(cr, x, allocation.height - (line_height + PADDING));
+ pango_cairo_show_layout (cr, layout);
+
+ remaining_x_start = x + logical_rect.width;
+
+ remaining_timeline_space = remaining_x_end - remaining_x_start;
+
+ if (remaining_timeline_space <= 0)
+ space_left = FALSE;
+ }
+end:
+ if (timeline_font)
+ pango_font_description_free(timeline_font);
+ cairo_destroy(cr);
+
+ return FALSE;
+}
+
+static int
+key_pressed (GtkWidget *widget, GdkEventKey *event, TimeScale* ts)
+{
+ switch (event->keyval)
+ {
+ case GDK_KEY_KP_Left:
+ case GDK_KEY_KP_Up:
+ case GDK_KEY_Left:
+ case GDK_KEY_Up:
+
+ if (ts->priv->current_pos >= 1)
+ {
+ ts->priv->current_pos -= 1;
+ gtk_widget_queue_draw (widget);
+ ts->priv->key_pressed = TRUE;
+ g_signal_emit (ts, signals[VALUE_CHANGED], 0);
+ /* printf ("key_pressed back %d\n", ts->priv->current_pos); */
+ }
+ return TRUE;
+ case GDK_KEY_KP_Right:
+ case GDK_KEY_KP_Down:
+ case GDK_KEY_Right:
+ case GDK_KEY_Down:
+ if (ts->priv->current_pos <= ts->priv->num_snaps - 2)
+ {
+ ts->priv->current_pos += 1;
+ gtk_widget_queue_draw (widget);
+ ts->priv->key_pressed = TRUE;
+ g_signal_emit (ts, signals[VALUE_CHANGED], 0);
+ /* printf ("key_pressed forward %d\n", ts->priv->current_pos); */
+ }
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+int timescale_get_position (TimeScale* ts)
+{
+ /* translate into all_snaps position */
+ gconstpointer data;
+ data = g_list_nth_data (ts->priv->snaps, ts->priv->current_pos);
+ return g_list_index (ts->priv->all_snaps, data);
+}
+
+static int match_func (ZfsDataSet *set, char *dir)
+{
+ return strcmp (set->mountpoint, dir);
+}
+
+void
+timescale_set_position (TimeScale* ts, char *mountpoint)
+{
+ gboolean redraw = FALSE;
+ int num_snaps = g_list_length (ts->priv->all_snaps);
+ if (mountpoint)
+ {
+ int pos;
+ GList* match = NULL;
+ match = g_list_find_custom (ts->priv->all_snaps, mountpoint, (GCompareFunc)match_func);
+ pos = g_list_index (ts->priv->all_snaps, match->data);
+ if (pos != -1 && ts->priv->current_pos != pos)
+ {
+ redraw = TRUE;
+ ts->priv->current_pos = pos;
+ }
+ }
+ else
+ { /* Now special case */
+ if (ts->priv->current_pos != num_snaps - 1)
+ {
+ redraw = TRUE;
+ ts->priv->current_pos = num_snaps - 1;
+ }
+ }
+
+ if (redraw)
+ gtk_widget_queue_draw (GTK_WIDGET (ts));
+}
+
+static void
+button_pressed (GtkWidget *widget, GdkEventButton *event, TimeScale* ts)
+{
+ int new_pos;
+
+ gtk_widget_grab_focus (widget);
+ new_pos = get_snap_index_from_coord (ts, event->x, event->y);
+
+ if (new_pos == -1)
+ return;
+
+ if (new_pos != ts->priv->current_pos)
+ {
+ ts->priv->current_pos = new_pos;
+ /* printf ("button_pressed (%g,%g) selected %d\n", event->x, event->y, ts->priv->current_pos); */
+ g_signal_emit (ts, signals[VALUE_CHANGED], 0);
+ gtk_widget_queue_draw (widget);
+ }
+}
+
+static gboolean
+query_tooltip (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_tip,
+ GtkTooltip *tooltip,
+ gpointer data)
+{
+ static gboolean set = FALSE;
+ static int old_pos = -1;
+ TimeScale* ts = TIMESCALE (data);
+ int new_pos = get_snap_index_from_coord (ts, x, y);
+ /* printf ("in query_tooltip new_pos %d total %d num_snap %d\n", new_pos, g_list_length (ts->priv->snaps), ts->priv->num_snaps); */
+ Snap *tmp_snap = NULL;
+ char *tip = NULL;
+
+ if (new_pos == -1)
+ return FALSE;
+
+ if (new_pos != old_pos)
+ {
+ old_pos = new_pos;
+ return FALSE;
+ }
+
+ if (new_pos >= ts->priv->num_snaps)
+ return FALSE;
+
+ tmp_snap = g_list_nth_data (ts->priv->snaps, new_pos);
+
+ tip = g_strdup_printf ("%s\nCreated: %s\nSize: %s\nName: %s", tmp_snap->type_str, tmp_snap->mtime_str, tmp_snap->used_space_str, tmp_snap->name);
+ gtk_label_set_text (GTK_LABEL(ts->priv->label_tip), tip);
+ gtk_tooltip_set_custom (tooltip, ts->priv->label_tip);
+ g_free (tip);
+ return TRUE;
+}
+
+static void
+timescale_class_init (TimeScaleClass *class)
+{
+ GtkWidgetClass *widget_class;
+ GtkScaleClass *scale_class;
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ g_type_class_add_private (class, sizeof (TimeScalePrivate));
+
+ widget_class = GTK_WIDGET_CLASS (class);
+
+ signals[VALUE_CHANGED] =
+ g_signal_new ("value-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TimeScaleClass, value_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
diff -Nrup -x '*.orig' -x '*.rej' -x '*.*~' ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/timescale.h nautilus-2.30.1/src/timescale.h
--- ../SUNWgnome-file-mgr-2.30.0-b4/nautilus-2.30.1/src/timescale.h 1970-01-01 01:00:00.000000000 +0100
+++ nautilus-2.30.1/src/timescale.h 2010-05-14 17:16:39.569612048 +0200
@@ -0,0 +1,58 @@
+#ifndef __TIMESCALE_H__
+#define __TIMESCALE_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+
+G_BEGIN_DECLS
+
+#define TYPE_TIMESCALE (timescale_get_type ())
+#define TIMESCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TIMESCALE, TimeScale))
+#define TIMESCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TIMESCALE, TimeScaleClass))
+#define IS_TIMESCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TIMESCALE))
+#define IS_TIMESCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TIMESCALE))
+#define TIMESCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TIMESCALE, TimeScaleClass))
+
+
+typedef struct _TimeScale TimeScale;
+typedef struct _TimeScaleClass TimeScaleClass;
+typedef struct TimeScalePrivate TimeScalePrivate;
+
+struct _TimeScale
+{
+ GtkHBox hbox;
+ TimeScalePrivate *priv;
+};
+
+struct _TimeScaleClass
+{
+ GtkHBoxClass parent_class;
+ void (* value_changed) (TimeScale *timescale);
+
+};
+
+
+GType timescale_get_type (void) G_GNUC_CONST;
+GtkWidget* timescale_new ();
+void timescale_set_snapshots (TimeScale* ts, GList *list, int init_position);
+int timescale_get_position (TimeScale* ts);
+void timescale_set_position (TimeScale* ts, char *mountpoint);
+
+
+#define ROUNDED_RADIUS 6
+#define PADDING 3
+
+typedef enum {
+ LOCAL_MANUAL,
+ LOCAL_AUTOMATIC,
+ REMOTE_MANUAL,
+ REMOTE_AUTOMATIC,
+ NOW
+} SnapType;
+
+
+G_END_DECLS
+
+#endif /* __TIMESCALE_H__ */
--- nautilus-3.1.3/src/nautilus-toolbar-ui.xml.orig 2011-04-04 19:01:24.000000000 +0100
+++ nautilus-3.1.3/src/nautilus-toolbar-ui.xml 2011-07-25 09:50:58.998044977 +0100
@@ -2,6 +2,7 @@
<toolbar name="Toolbar">
<toolitem name="Back" action="Back"/>
<toolitem name="Forward" action="Forward"/>
+ <toolitem name="Restore" action="Restore"/>
<toolitem name="Search" action="Search"/>
</toolbar>
-</ui>
\ No newline at end of file
+</ui>