[evolution] Test drive EIOActivity with a simple asynchronous function.
- From: Matthew Barnes <mbarnes src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [evolution] Test drive EIOActivity with a simple asynchronous function.
- Date: Sat, 7 Nov 2009 19:02:11 +0000 (UTC)
commit aa66a17e401d73cbe394ed7f99bf73350e9b938b
Author: Matthew Barnes <mbarnes redhat com>
Date: Fri Nov 6 13:33:55 2009 -0500
Test drive EIOActivity with a simple asynchronous function.
Rename e-fsutils to e-file-utils. This is where we'll add asynchronous
functions for common file I/O operations with EActivity integration.
Start with e_file_replace_contents_async() (and corresponding finish()
function). This is a simple wrapper for g_file_replace_contents_async()
which also returns an EActivity. It replaces e_write_file_uri().
Also redesign EIOActivity to -contain- a GAsyncResult rather than
implement the interface for itself. This is easier for now but I may
change my mind again when I figure out how to tie centralized error
reporting into the EActivity framework.
e-util/Makefile.am | 4 +-
e-util/e-file-utils.c | 281 ++++++++++++++++++++++++++++++++
e-util/{e-fsutils.h => e-file-utils.h} | 26 +++-
e-util/e-fsutils.c | 158 ------------------
e-util/e-io-activity.c | 206 +++++++++++++++---------
e-util/e-io-activity.h | 12 +-
shell/e-shell-migrate.c | 2 +-
7 files changed, 441 insertions(+), 248 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index bc5e7cd..ecc3220 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -24,8 +24,8 @@ eutilinclude_HEADERS = \
e-dialog-widgets.h \
e-error.h \
e-event.h \
+ e-file-utils.h \
e-folder-map.h \
- e-fsutils.h \
e-html-utils.h \
e-icon-factory.h \
e-import.h \
@@ -98,8 +98,8 @@ libeutil_la_SOURCES = \
e-dialog-widgets.c \
e-error.c \
e-event.c \
+ e-file-utils.c \
e-folder-map.c \
- e-fsutils.c \
e-html-utils.c \
e-icon-factory.c \
e-import.c \
diff --git a/e-util/e-file-utils.c b/e-util/e-file-utils.c
new file mode 100644
index 0000000..f8adcc7
--- /dev/null
+++ b/e-util/e-file-utils.c
@@ -0,0 +1,281 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* This isn't as portable as, say, the stuff in GNU coreutils. But I care not for OSF1. */
+#ifdef HAVE_STATVFS
+# ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+# endif
+#else
+#ifdef HAVE_STATFS
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h> /* bsd interface */
+# endif
+# ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+# endif
+#endif
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-file-utils.h"
+#include "e-io-activity.h"
+
+static void
+file_replace_contents_cb (GFile *file,
+ GAsyncResult *result,
+ EActivity *activity)
+{
+ gchar *new_etag;
+ gboolean success;
+ GError *error = NULL;
+
+ success = g_file_replace_contents_finish (
+ file, result, &new_etag, &error);
+
+ result = e_io_activity_get_async_result (E_IO_ACTIVITY (activity));
+
+ g_object_set_data_full (
+ G_OBJECT (result),
+ "__new_etag__", new_etag,
+ (GDestroyNotify) g_free);
+
+ g_simple_async_result_set_op_res_gboolean (
+ G_SIMPLE_ASYNC_RESULT (result), success);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (
+ G_SIMPLE_ASYNC_RESULT (result), error);
+ g_error_free (error);
+ }
+
+ e_activity_complete (activity);
+
+ g_object_unref (activity);
+}
+
+EActivity *
+e_file_replace_contents_async (GFile *file,
+ const gchar *contents,
+ gsize length,
+ const gchar *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EActivity *activity;
+ GSimpleAsyncResult *simple;
+ GCancellable *cancellable;
+ const gchar *format;
+ gchar *description;
+ gchar *basename;
+ gchar *filename;
+ gchar *hostname;
+ gchar *uri;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (contents != NULL, NULL);
+
+ uri = g_file_get_uri (file);
+ filename = g_filename_from_uri (uri, &hostname, NULL);
+ basename = g_filename_display_basename (filename);
+
+ if (hostname != NULL) {
+ /* Translators: The string value is the basename of a file. */
+ format = _("Writing \"%s\"");
+ description = g_strdup_printf (format, basename);
+ } else {
+ /* Translators: The first string value is the basename of a
+ * remote file, the second string value is the hostname. */
+ format = _("Writing \"%s\" to %s");
+ description = g_strdup_printf (format, basename, hostname);
+ }
+
+ cancellable = g_cancellable_new ();
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (file), callback, user_data,
+ e_file_replace_contents_async);
+
+ activity = e_io_activity_new (
+ description, G_ASYNC_RESULT (simple), cancellable);
+
+ g_file_replace_contents_async (
+ file, contents, length, etag,
+ make_backup, flags, cancellable,
+ (GAsyncReadyCallback) file_replace_contents_cb,
+ activity);
+
+ g_object_unref (cancellable);
+ g_object_unref (simple);
+
+ g_free (description);
+ g_free (basename);
+ g_free (filename);
+ g_free (hostname);
+ g_free (uri);
+
+ return activity;
+}
+
+gboolean
+e_file_replace_contents_finish (GFile *file,
+ GAsyncResult *result,
+ gchar **new_etag,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (new_etag != NULL)
+ *new_etag = g_object_steal_data (
+ G_OBJECT (result), "__new_etag__");
+
+ return TRUE;
+}
+
+/**
+ * e_fsutils_usage:
+ * @path:
+ *
+ * Calculate the amount of disk space used by a given path.
+ *
+ * Return value: The number of 1024 byte blocks used by the
+ * filesystem.
+ **/
+glong e_fsutils_usage(const gchar *inpath)
+{
+ GDir *dir;
+ const gchar *d;
+ long size = 0;
+ GSList *paths;
+
+ /* iterative, depth-first scan, because i can ... */
+ paths = g_slist_prepend(NULL, g_strdup(inpath));
+
+ while (paths) {
+ gchar *path = paths->data;
+
+ paths = g_slist_remove_link(paths, paths);
+
+ dir = g_dir_open(path, 0, NULL);
+ if (dir == NULL) {
+ g_free(path);
+ goto fail;
+ }
+
+ while ((d = g_dir_read_name(dir))) {
+ gchar *full_path;
+ struct stat st;
+
+ full_path = g_build_filename(path, d, NULL);
+ if (g_stat(full_path, &st) == -1) {
+ g_free(full_path);
+ g_dir_close(dir);
+ g_free(path);
+ goto fail;
+ } else if (S_ISDIR(st.st_mode)) {
+ paths = g_slist_prepend(paths, full_path);
+ full_path = NULL;
+ } else if (S_ISREG(st.st_mode)) {
+ /* This is in 512 byte blocks. st_blksize is page size on linux,
+ on *BSD it might be significant. */
+#ifndef G_OS_WIN32
+ size += st.st_blocks/2;
+#endif
+ }
+
+ g_free(full_path);
+ }
+
+ g_dir_close(dir);
+ g_free(path);
+ }
+
+ return size;
+
+fail:
+ g_slist_foreach(paths, (GFunc)g_free, NULL);
+ g_slist_free(paths);
+
+ return -1;
+}
+
+/**
+ * e_fsutils_avail:
+ * @path:
+ *
+ * Find the available disk space at the given path.
+ *
+ * Return value: -1 if it could not be determined, otherwise the
+ * number of disk blocks, expressed as system-independent, 1024 byte
+ * blocks.
+ **/
+glong
+e_fsutils_avail(const gchar *path)
+{
+#if defined(HAVE_STATVFS)
+ struct statvfs stfs;
+
+ if (statvfs(path, &stfs) == -1)
+ return -1;
+
+ /* Assumes that frsize === power of 2 */
+ if (stfs.f_frsize >= 1024)
+ return stfs.f_bavail * (stfs.f_frsize / 1024);
+ else
+ return stfs.f_bavail / (1024 / stfs.f_frsize);
+#elif defined(HAVE_STATFS)
+ struct statfs stfs;
+
+ if (statfs(path, &stfs) == -1)
+ return -1;
+
+ /* For BSD this isn't clear, it may be dependent on f_bsize */
+ return stfs.f_bavail / 2;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
diff --git a/e-util/e-fsutils.h b/e-util/e-file-utils.h
similarity index 57%
rename from e-util/e-fsutils.h
rename to e-util/e-file-utils.h
index 6143e48..147b9b5 100644
--- a/e-util/e-fsutils.h
+++ b/e-util/e-file-utils.h
@@ -20,16 +20,30 @@
*
*/
-#ifndef E_FSUTILS_H
-#define E_FSUTILS_H
+#ifndef E_FILE_UTILS_H
+#define E_FILE_UTILS_H
-#include <glib.h>
+#include <gio/gio.h>
+#include <e-util/e-activity.h>
G_BEGIN_DECLS
-glong e_fsutils_usage(const gchar *path);
-glong e_fsutils_avail(const gchar *path);
+EActivity * e_file_replace_contents_async (GFile *file,
+ const gchar *contents,
+ gsize length,
+ const gchar *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_file_replace_contents_finish (GFile *file,
+ GAsyncResult *result,
+ gchar **new_etag,
+ GError **error);
+
+glong e_fsutils_usage (const gchar *path);
+glong e_fsutils_avail (const gchar *path);
G_END_DECLS
-#endif /* !E_FOLDER_MAP_H */
+#endif /* E_FILE_UTILS_H */
diff --git a/e-util/e-io-activity.c b/e-util/e-io-activity.c
index 086ee10..9569e42 100644
--- a/e-util/e-io-activity.c
+++ b/e-util/e-io-activity.c
@@ -26,26 +26,54 @@
((obj), E_TYPE_IO_ACTIVITY, EIOActivityPrivate))
struct _EIOActivityPrivate {
- GObject *source_object;
+ GAsyncResult *async_result;
GCancellable *cancellable;
- GAsyncReadyCallback callback;
- gpointer user_data;
};
enum {
PROP_0,
+ PROP_ASYNC_RESULT,
PROP_CANCELLABLE
};
static gpointer parent_class;
static void
+io_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ASYNC_RESULT:
+ e_io_activity_set_async_result (
+ E_IO_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_CANCELLABLE:
+ e_io_activity_set_cancellable (
+ E_IO_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
io_activity_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_ASYNC_RESULT:
+ g_value_set_object (
+ value, e_io_activity_get_async_result (
+ E_IO_ACTIVITY (object)));
+ return;
+
case PROP_CANCELLABLE:
g_value_set_object (
value, e_io_activity_get_cancellable (
@@ -63,9 +91,9 @@ io_activity_dispose (GObject *object)
priv = E_IO_ACTIVITY_GET_PRIVATE (object);
- if (priv->source_object != NULL) {
- g_object_unref (priv->source_object);
- priv->source_object = NULL;
+ if (priv->async_result != NULL) {
+ g_object_unref (priv->async_result);
+ priv->async_result = NULL;
}
if (priv->cancellable != NULL) {
@@ -80,55 +108,37 @@ io_activity_dispose (GObject *object)
static void
io_activity_cancelled (EActivity *activity)
{
- EIOActivityPrivate *priv;
-
- priv = E_IO_ACTIVITY_GET_PRIVATE (activity);
+ EIOActivity *io_activity;
+ GCancellable *cancellable;
/* Chain up to parent's cancelled() method. */
E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
- g_cancellable_cancel (priv->cancellable);
+ io_activity = E_IO_ACTIVITY (activity);
+ cancellable = e_io_activity_get_cancellable (io_activity);
+
+ if (cancellable != NULL)
+ g_cancellable_cancel (cancellable);
}
static void
io_activity_completed (EActivity *activity)
{
- EIOActivityPrivate *priv;
-
- priv = E_IO_ACTIVITY_GET_PRIVATE (activity);
+ EIOActivity *io_activity;
+ GAsyncResult *async_result;
/* Chain up to parent's completed() method. */
E_ACTIVITY_CLASS (parent_class)->completed (activity);
- /* Clear the function pointer after invoking it
- * to guarantee it will not be invoked again. */
- if (priv->callback != NULL) {
- priv->callback (
- priv->source_object,
- G_ASYNC_RESULT (activity),
- priv->user_data);
- priv->callback = NULL;
- }
-}
-
-static gpointer
-io_activity_get_user_data (GAsyncResult *async_result)
-{
- EIOActivityPrivate *priv;
+ io_activity = E_IO_ACTIVITY (activity);
+ async_result = e_io_activity_get_async_result (io_activity);
- priv = E_IO_ACTIVITY_GET_PRIVATE (async_result);
-
- return priv->user_data;
-}
-
-static GObject *
-io_activity_get_source_object (GAsyncResult *async_result)
-{
- EIOActivityPrivate *priv;
-
- priv = E_IO_ACTIVITY_GET_PRIVATE (async_result);
-
- return priv->source_object;
+ /* We know how to invoke a GSimpleAsyncResult. For any other
+ * type of GAsyncResult the caller will have to take measures
+ * to invoke it himself. */
+ if (G_IS_SIMPLE_ASYNC_RESULT (async_result))
+ g_simple_async_result_complete (
+ G_SIMPLE_ASYNC_RESULT (async_result));
}
static void
@@ -141,6 +151,7 @@ io_activity_class_init (EIOActivityClass *class)
g_type_class_add_private (class, sizeof (EIOActivityPrivate));
object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = io_activity_set_property;
object_class->get_property = io_activity_get_property;
object_class->dispose = io_activity_dispose;
@@ -150,28 +161,31 @@ io_activity_class_init (EIOActivityClass *class)
g_object_class_install_property (
object_class,
+ PROP_ASYNC_RESULT,
+ g_param_spec_object (
+ "async-result",
+ "Asynchronous Result",
+ NULL,
+ G_TYPE_ASYNC_RESULT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
PROP_CANCELLABLE,
g_param_spec_object (
"cancellable",
"Cancellable",
NULL,
G_TYPE_CANCELLABLE,
- G_PARAM_READABLE));
-}
-
-static void
-io_activity_iface_init (GAsyncResultIface *iface)
-{
- iface->get_user_data = io_activity_get_user_data;
- iface->get_source_object = io_activity_get_source_object;
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
}
static void
io_activity_init (EIOActivity *io_activity)
{
io_activity->priv = E_IO_ACTIVITY_GET_PRIVATE (io_activity);
-
- io_activity->priv->cancellable = g_cancellable_new ();
}
GType
@@ -193,45 +207,57 @@ e_io_activity_get_type (void)
NULL /* value_table */
};
- static const GInterfaceInfo iface_info = {
- (GInterfaceInitFunc) io_activity_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL /* interface_data */
- };
-
type = g_type_register_static (
E_TYPE_ACTIVITY, "EIOActivity", &type_info, 0);
-
- g_type_add_interface_static (
- type, G_TYPE_ASYNC_RESULT, &iface_info);
}
return type;
}
EActivity *
-e_io_activity_new (GObject *source_object,
- const gchar *primary_text,
- GAsyncReadyCallback callback,
- gpointer user_data)
+e_io_activity_new (const gchar *primary_text,
+ GAsyncResult *async_result,
+ GCancellable *cancellable)
{
- EActivity *activity;
- EIOActivityPrivate *priv;
-
- g_return_val_if_fail (G_IS_OBJECT (source_object), NULL);
g_return_val_if_fail (primary_text != NULL, NULL);
- g_return_val_if_fail (callback != NULL, NULL);
- activity = g_object_new (
- E_TYPE_IO_ACTIVITY, "primary-text", primary_text, NULL);
+ if (async_result != NULL)
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
- /* XXX Should these be construct properties? */
- priv = E_IO_ACTIVITY_GET_PRIVATE (activity);
- priv->source_object = g_object_ref (source_object);
- priv->callback = callback;
- priv->user_data = user_data;
+ if (cancellable != NULL)
+ g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), NULL);
- return activity;
+ return g_object_new (
+ E_TYPE_IO_ACTIVITY,
+ "async-result", async_result, "cancellable",
+ cancellable, "primary-text", primary_text, NULL);
+}
+
+GAsyncResult *
+e_io_activity_get_async_result (EIOActivity *io_activity)
+{
+ g_return_val_if_fail (E_IS_IO_ACTIVITY (io_activity), NULL);
+
+ return io_activity->priv->async_result;
+}
+
+void
+e_io_activity_set_async_result (EIOActivity *io_activity,
+ GAsyncResult *async_result)
+{
+ g_return_if_fail (E_IS_IO_ACTIVITY (io_activity));
+
+ if (async_result != NULL) {
+ g_return_if_fail (G_IS_ASYNC_RESULT (async_result));
+ g_object_ref (async_result);
+ }
+
+ if (io_activity->priv->async_result != NULL)
+ g_object_unref (io_activity->priv->async_result);
+
+ io_activity->priv->async_result = async_result;
+
+ g_object_notify (G_OBJECT (io_activity), "async-result");
}
GCancellable *
@@ -241,3 +267,29 @@ e_io_activity_get_cancellable (EIOActivity *io_activity)
return io_activity->priv->cancellable;
}
+
+void
+e_io_activity_set_cancellable (EIOActivity *io_activity,
+ GCancellable *cancellable)
+{
+ g_return_if_fail (E_IS_IO_ACTIVITY (io_activity));
+
+ if (cancellable != NULL) {
+ g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+ g_object_ref (cancellable);
+ }
+
+ if (io_activity->priv->cancellable != NULL)
+ g_object_unref (io_activity->priv->cancellable);
+
+ io_activity->priv->cancellable = cancellable;
+
+ g_object_freeze_notify (G_OBJECT (io_activity));
+
+ e_activity_set_allow_cancel (
+ E_ACTIVITY (io_activity), (cancellable != NULL));
+
+ g_object_notify (G_OBJECT (io_activity), "cancellable");
+
+ g_object_thaw_notify (G_OBJECT (io_activity));
+}
diff --git a/e-util/e-io-activity.h b/e-util/e-io-activity.h
index c94953a..7734174 100644
--- a/e-util/e-io-activity.h
+++ b/e-util/e-io-activity.h
@@ -60,11 +60,15 @@ struct _EIOActivityClass {
};
GType e_io_activity_get_type (void);
-EActivity * e_io_activity_new (GObject *source_object,
- const gchar *primary_text,
- GAsyncReadyCallback callback,
- gpointer user_data);
+EActivity * e_io_activity_new (const gchar *primary_text,
+ GAsyncResult *async_result,
+ GCancellable *cancellable);
+GAsyncResult * e_io_activity_get_async_result (EIOActivity *io_activity);
+void e_io_activity_set_async_result (EIOActivity *io_activity,
+ GAsyncResult *async_result);
GCancellable * e_io_activity_get_cancellable (EIOActivity *io_activity);
+void e_io_activity_set_cancellable (EIOActivity *io_activity,
+ GCancellable *cancellable);
G_END_DECLS
diff --git a/shell/e-shell-migrate.c b/shell/e-shell-migrate.c
index a330d9d..d7c8312 100644
--- a/shell/e-shell-migrate.c
+++ b/shell/e-shell-migrate.c
@@ -29,7 +29,7 @@
#include "e-util/e-bconf-map.h"
#include "e-util/e-error.h"
-#include "e-util/e-fsutils.h"
+#include "e-util/e-file-utils.h"
#include "e-util/e-util.h"
#include "es-event.h"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]