[gtksourceview/wip/loader-saver: 1/2] Refactor the FileSaver to fit GtkSourceFile API
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/loader-saver: 1/2] Refactor the FileSaver to fit GtkSourceFile API
- Date: Tue, 17 Dec 2013 16:05:55 +0000 (UTC)
commit 27cc48754fe61ff3de19bf3b264fc01fd2cb094c
Author: Sébastien Wilmet <swilmet gnome org>
Date: Fri Dec 13 21:48:13 2013 +0100
Refactor the FileSaver to fit GtkSourceFile API
It is compilable!
It uses internally a GTask.
The workaround for https://bugzilla.gnome.org/show_bug.cgi?id=615110 is
disabled.
And I added a lot of FIXME and TODO comments.
docs/reference/Makefile.am | 2 +
gtksourceview/gtksourcefilesaver.c | 609 ++++++++++++++----------------------
gtksourceview/gtksourcefilesaver.h | 40 +--
3 files changed, 249 insertions(+), 402 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 1987d7f..eaaee88 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -22,6 +22,7 @@ CFILE_GLOB = $(top_srcdir)/gtksourceview/*.c
IGNORE_HFILES = \
config.h \
gtksourcebuffer-private.h \
+ gtksourcebufferinputstream.h \
gtksourcecompletioncontainer.h \
gtksourcecompletionmodel.h \
gtksourcecompletion-private.h \
@@ -31,6 +32,7 @@ IGNORE_HFILES = \
gtksourcecompletionwordsutils.h \
gtksourcecontextengine.h \
gtksourceengine.h \
+ gtksourcefilesaver.h \
gtksourcegutter-private.h \
gtksourcegutterrendererlines.h \
gtksourcegutterrenderermarks.h \
diff --git a/gtksourceview/gtksourcefilesaver.c b/gtksourceview/gtksourcefilesaver.c
index fe96dac..1b379a6 100644
--- a/gtksourceview/gtksourcefilesaver.c
+++ b/gtksourceview/gtksourcefilesaver.c
@@ -41,16 +41,8 @@
#define WRITE_CHUNK_SIZE 8192
-#define REMOTE_QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
- G_FILE_ATTRIBUTE_TIME_MODIFIED
-
-enum
-{
- SAVING,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
+#define QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
+ G_FILE_ATTRIBUTE_TIME_MODIFIED
enum
{
@@ -64,6 +56,7 @@ enum
PROP_ENSURE_TRAILING_NEWLINE
};
+#if 0
typedef struct
{
GtkSourceFileSaver *saver;
@@ -74,10 +67,10 @@ typedef struct
gssize read;
GError *error;
} AsyncData;
+#endif
struct _GtkSourceFileSaverPrivate
{
- GFileInfo *info;
GtkTextBuffer *buffer;
GFile *location;
@@ -86,31 +79,44 @@ struct _GtkSourceFileSaverPrivate
GtkSourceCompressionType compression_type;
GtkSourceFileSaveFlags flags;
+ GTask *task;
+
+ GFileProgressCallback progress_cb;
+ gpointer progress_cb_data;
+
GTimeVal old_mtime;
+ /* TODO rename these two fields */
goffset size;
goffset bytes_written;
+ gchar chunk_buffer[WRITE_CHUNK_SIZE];
+ gssize chunk_bytes_read;
+ gssize chunk_bytes_written;
+
GCancellable *cancellable;
+ /* TODO find better names for these two fields */
GOutputStream *stream;
GInputStream *input;
+ GFileInfo *info;
+
GError *error;
GtkSourceMountOperationFactory mount_operation_factory;
gpointer mount_operation_userdata;
+ /* FIXME is used used? */
guint used : 1;
guint ensure_trailing_newline : 1;
+ guint tried_mount : 1;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceFileSaver, gtk_source_file_saver, G_TYPE_OBJECT)
-/* prototype, because they call each other... isn't C lovely */
-static void read_file_chunk (AsyncData *async);
-static void write_file_chunk (AsyncData *async);
-
-static void check_modified_async (AsyncData *async);
+static void read_file_chunk (GtkSourceFileSaver *saver);
+static void write_file_chunk (GtkSourceFileSaver *saver);
+static void check_externally_modified (GtkSourceFileSaver *saver);
static void
gtk_source_file_saver_set_property (GObject *object,
@@ -208,47 +214,17 @@ gtk_source_file_saver_dispose (GObject *object)
{
GtkSourceFileSaverPrivate *priv = GTK_SOURCE_FILE_SAVER (object)->priv;
- if (priv->cancellable != NULL)
- {
- g_cancellable_cancel (priv->cancellable);
- g_clear_object (&priv->cancellable);
- }
-
g_clear_error (&priv->error);
g_clear_object (&priv->stream);
g_clear_object (&priv->input);
g_clear_object (&priv->info);
g_clear_object (&priv->location);
+ g_clear_object (&priv->task);
G_OBJECT_CLASS (gtk_source_file_saver_parent_class)->dispose (object);
}
-static AsyncData *
-async_data_new (GtkSourceFileSaver *saver)
-{
- AsyncData *async;
-
- async = g_slice_new0 (AsyncData);
- async->saver = saver;
- async->cancellable = g_object_ref (saver->priv->cancellable);
-
- return async;
-}
-
-static void
-async_data_free (AsyncData *async)
-{
- g_object_unref (async->cancellable);
-
- if (async->error != NULL)
- {
- g_error_free (async->error);
- }
-
- g_slice_free (AsyncData, async);
-}
-
static void
gtk_source_file_saver_class_init (GtkSourceFileSaverClass *klass)
{
@@ -330,26 +306,12 @@ gtk_source_file_saver_class_init (GtkSourceFileSaverClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
-
- signals[SAVING] =
- g_signal_new ("saving",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkSourceFileSaverClass, saving),
- NULL, NULL,
- _gtksourceview_marshal_VOID__BOOLEAN_POINTER,
- G_TYPE_NONE,
- 2,
- G_TYPE_BOOLEAN,
- G_TYPE_POINTER);
}
static void
gtk_source_file_saver_init (GtkSourceFileSaver *saver)
{
saver->priv = gtk_source_file_saver_get_instance_private (saver);
-
- saver->priv->cancellable = g_cancellable_new ();
}
GtkSourceFileSaver *
@@ -363,6 +325,7 @@ gtk_source_file_saver_new (GtkTextBuffer *buffer,
{
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+ /* TODO move this code to set_property() */
if (encoding == NULL)
{
encoding = gtk_source_encoding_get_utf8 ();
@@ -379,26 +342,6 @@ gtk_source_file_saver_new (GtkTextBuffer *buffer,
NULL);
}
-static void
-remote_save_completed_or_failed (GtkSourceFileSaver *saver,
- AsyncData *async)
-{
- gtk_source_file_saver_saving (saver, TRUE, saver->priv->error);
-
- if (async != NULL)
- {
- async_data_free (async);
- }
-}
-
-static void
-async_failed (AsyncData *async,
- GError *error)
-{
- g_propagate_error (&async->saver->priv->error, error);
- remote_save_completed_or_failed (async->saver, async);
-}
-
/* BEGIN NOTE:
*
* This fixes an issue in GOutputStream that applies the atomic replace save
@@ -420,17 +363,18 @@ async_failed (AsyncData *async,
* errors while writing (glib/gio)
* https://bugzilla.gnome.org/show_bug.cgi?id=602412
*/
+#if 0
static void
-cancel_output_stream_ready_cb (GOutputStream *stream,
- GAsyncResult *result,
- AsyncData *async)
+cancel_output_stream_ready_cb (GOutputStream *stream,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
- GError *error;
+ GError *error = NULL;
g_output_stream_close_finish (stream, result, NULL);
/* check cancelled state manually */
- if (g_cancellable_is_cancelled (async->cancellable) || async->error == NULL)
+ if (g_cancellable_is_cancelled (saver->priv->cancellable) || async->error == NULL)
{
async_data_free (async);
return;
@@ -474,64 +418,56 @@ cancel_output_stream_and_fail (AsyncData *async,
g_propagate_error (&async->error, error);
cancel_output_stream (async);
}
+#endif
/*
* END NOTE
*/
static void
-remote_get_info_cb (GFile *source,
- GAsyncResult *res,
- AsyncData *async)
+query_info_cb (GFile *location,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
- GFileInfo *info;
GError *error = NULL;
DEBUG ({
g_print ("%s\n", G_STRFUNC);
});
+#if 0
/* check cancelled state manually */
if (g_cancellable_is_cancelled (async->cancellable))
{
async_data_free (async);
return;
}
-
- saver = async->saver;
+#endif
DEBUG ({
g_print ("Finished query info on file\n");
});
- info = g_file_query_info_finish (source, res, &error);
-
- if (info != NULL)
- {
- if (saver->priv->info != NULL)
- {
- g_object_unref (saver->priv->info);
- }
+ g_clear_object (&saver->priv->info);
+ saver->priv->info = g_file_query_info_finish (location, result, &error);
- saver->priv->info = info;
- }
- else
+ if (error != NULL)
{
DEBUG ({
g_print ("Query info failed: %s\n", error->message);
});
- g_propagate_error (&saver->priv->error, error);
+ g_task_return_error (saver->priv->task, error);
+ return;
}
- remote_save_completed_or_failed (saver, async);
+ g_task_return_boolean (saver->priv->task, TRUE);
}
static void
-close_async_ready_get_info_cb (GOutputStream *stream,
- GAsyncResult *res,
- AsyncData *async)
+close_output_stream_cb (GOutputStream *output_stream,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
GError *error = NULL;
@@ -539,85 +475,89 @@ close_async_ready_get_info_cb (GOutputStream *stream,
g_print ("%s\n", G_STRFUNC);
});
+#if 0
/* check cancelled state manually */
if (g_cancellable_is_cancelled (async->cancellable))
{
async_data_free (async);
return;
}
+#endif
- DEBUG ({
- g_print ("Finished closing stream\n");
- });
+ g_output_stream_close_finish (output_stream, result, &error);
- if (!g_output_stream_close_finish (stream, res, &error))
+ if (error != NULL)
{
DEBUG ({
g_print ("Closing stream error: %s\n", error->message);
});
- async_failed (async, error);
+ g_task_return_error (saver->priv->task, error);
return;
}
- /* get the file info: note we cannot use
- * g_file_output_stream_query_info_async since it is not able to get the
+ /* Get the file info: note we cannot use
+ * g_file_output_stream_query_info_async() since it is not able to get the
* content type etc, beside it is not supported by gvfs.
* I'm not sure this is actually necessary, can't we just use
- * g_content_type_guess (since we have the file name and the data)
+ * g_content_type_guess (since we have the file name and the data).
*/
DEBUG ({
g_print ("Query info on file\n");
});
- g_file_query_info_async (async->saver->priv->location,
- REMOTE_QUERY_ATTRIBUTES,
+ g_file_query_info_async (saver->priv->location,
+ QUERY_ATTRIBUTES,
G_FILE_QUERY_INFO_NONE,
- G_PRIORITY_HIGH,
- async->cancellable,
- (GAsyncReadyCallback) remote_get_info_cb,
- async);
+ g_task_get_priority (saver->priv->task),
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback) query_info_cb,
+ saver);
}
static void
-write_complete (AsyncData *async)
+write_complete (GtkSourceFileSaver *saver)
{
GError *error = NULL;
- /* first we close the input stream */
DEBUG ({
g_print ("Close input stream\n");
});
- if (!g_input_stream_close (async->saver->priv->input,
- async->cancellable, &error))
+ g_input_stream_close (saver->priv->input,
+ g_task_get_cancellable (saver->priv->task),
+ &error);
+
+ if (error != NULL)
{
DEBUG ({
g_print ("Closing input stream error: %s\n", error->message);
});
+#if 0
cancel_output_stream_and_fail (async, error);
+#endif
+
+ g_task_return_error (saver->priv->task, error);
return;
}
- /* now we close the output stream */
DEBUG ({
g_print ("Close output stream\n");
});
- g_output_stream_close_async (async->saver->priv->stream,
- G_PRIORITY_HIGH,
- async->cancellable,
- (GAsyncReadyCallback)close_async_ready_get_info_cb,
- async);
+ g_output_stream_close_async (saver->priv->stream,
+ g_task_get_priority (saver->priv->task),
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback) close_output_stream_cb,
+ saver);
}
static void
-async_write_cb (GOutputStream *stream,
- GAsyncResult *res,
- AsyncData *async)
+write_file_chunk_cb (GOutputStream *output_stream,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
gssize bytes_written;
GError *error = NULL;
@@ -625,119 +565,112 @@ async_write_cb (GOutputStream *stream,
g_print ("%s\n", G_STRFUNC);
});
- /* Check cancelled state manually */
- if (g_cancellable_is_cancelled (async->cancellable))
- {
- cancel_output_stream (async);
- return;
- }
-
- bytes_written = g_output_stream_write_finish (stream, res, &error);
+ bytes_written = g_output_stream_write_finish (output_stream, result, &error);
DEBUG ({
g_print ("Written: %" G_GSSIZE_FORMAT "\n", bytes_written);
});
- if (bytes_written == -1)
+ if (error != NULL)
{
DEBUG ({
g_print ("Write error: %s\n", error->message);
});
- cancel_output_stream_and_fail (async, error);
+#if 0
+ cancel_output_stream_and_fail (saver, error);
+#endif
+
+ g_task_return_error (saver->priv->task, error);
return;
}
- saver = async->saver;
- async->written += bytes_written;
+ saver->priv->chunk_bytes_written += bytes_written;
- /* write again */
- if (async->written != async->read)
+ /* Write again */
+ if (saver->priv->chunk_bytes_read != saver->priv->chunk_bytes_written)
{
- write_file_chunk (async);
+ write_file_chunk (saver);
return;
}
- /* note that this signal blocks the write... check if it isn't
- * a performance problem
- */
- gtk_source_file_saver_saving (saver,
- FALSE,
- NULL);
-
- read_file_chunk (async);
+ read_file_chunk (saver);
}
static void
-write_file_chunk (AsyncData *async)
+write_file_chunk (GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
-
DEBUG ({
g_print ("%s\n", G_STRFUNC);
});
- saver = async->saver;
-
+ /* FIXME check if a thread is created each time this function is called.
+ * If so, this is a performance problem and should be fixed.
+ */
g_output_stream_write_async (G_OUTPUT_STREAM (saver->priv->stream),
- async->buffer + async->written,
- async->read - async->written,
- G_PRIORITY_HIGH,
- async->cancellable,
- (GAsyncReadyCallback) async_write_cb,
- async);
+ saver->priv->chunk_buffer + saver->priv->chunk_bytes_written,
+ saver->priv->chunk_bytes_read - saver->priv->chunk_bytes_written,
+ g_task_get_priority (saver->priv->task),
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback) write_file_chunk_cb,
+ saver);
}
static void
-read_file_chunk (AsyncData *async)
+read_file_chunk (GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
- GtkSourceBufferInputStream *dstream;
+ GtkSourceBufferInputStream *buffer_stream;
GError *error = NULL;
DEBUG ({
g_print ("%s\n", G_STRFUNC);
});
- saver = async->saver;
- async->written = 0;
+ saver->priv->chunk_bytes_written = 0;
- /* we use sync methods on doc stream since it is in memory. Using async
- would be racy and we can endup with invalidated iters */
- async->read = g_input_stream_read (saver->priv->input,
- async->buffer,
- WRITE_CHUNK_SIZE,
- async->cancellable,
- &error);
+ /* We use sync methods on doc stream since it is in memory. Using async
+ * would be racy and we can end up with invalid iters.
+ */
+ saver->priv->chunk_bytes_read = g_input_stream_read (saver->priv->input,
+ saver->priv->chunk_buffer,
+ WRITE_CHUNK_SIZE,
+ g_task_get_cancellable (saver->priv->task),
+ &error);
if (error != NULL)
{
- cancel_output_stream_and_fail (async, error);
+#if 0
+ cancel_output_stream_and_fail (saver, error);
+#endif
+
+ g_task_return_error (saver->priv->task, error);
return;
}
- /* Check if we finished reading and writing */
- if (async->read == 0)
+ /* Check if we finished reading and writing. */
+ if (saver->priv->chunk_bytes_read == 0)
{
- write_complete (async);
+ write_complete (saver);
return;
}
- /* Get how many chars have been read */
- dstream = GTK_SOURCE_BUFFER_INPUT_STREAM (saver->priv->input);
- saver->priv->bytes_written = _gtk_source_buffer_input_stream_tell (dstream);
+ /* Get how many chars have been read. */
+ /* FIXME bytes_written, or chars_written? */
+ /* FIXME and the value must be updated after writing the chunk, not
+ * after reading it... */
+ buffer_stream = GTK_SOURCE_BUFFER_INPUT_STREAM (saver->priv->input);
+ saver->priv->bytes_written = _gtk_source_buffer_input_stream_tell (buffer_stream);
- write_file_chunk (async);
+ write_file_chunk (saver);
}
static void
-async_replace_ready_callback (GFile *source,
- GAsyncResult *res,
- AsyncData *async)
+replace_file_cb (GFile *location,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
- GCharsetConverter *converter;
GFileOutputStream *file_stream;
+ GCharsetConverter *converter;
GOutputStream *base_stream;
GError *error = NULL;
@@ -745,24 +678,17 @@ async_replace_ready_callback (GFile *source,
g_print ("%s\n", G_STRFUNC);
});
- /* Check cancelled state manually */
- if (g_cancellable_is_cancelled (async->cancellable))
- {
- async_data_free (async);
- return;
- }
-
- saver = async->saver;
- file_stream = g_file_replace_finish (source, res, &error);
+ file_stream = g_file_replace_finish (location, result, &error);
- /* handle any error that might occur */
- if (!file_stream)
+ if (error != NULL)
{
DEBUG ({
g_print ("Opening file failed: %s\n", error->message);
});
- async_failed (async, error);
+ /* FIXME check not mounted? */
+
+ g_task_return_error (saver->priv->task, error);
return;
}
@@ -788,6 +714,7 @@ async_replace_ready_callback (GFile *source,
}
/* FIXME: manage converter error? */
+
DEBUG ({
g_print ("Encoding charset: %s\n",
gtk_source_encoding_get_charset (saver->priv->encoding));
@@ -816,28 +743,20 @@ async_replace_ready_callback (GFile *source,
saver->priv->size = _gtk_source_buffer_input_stream_get_total_size (GTK_SOURCE_BUFFER_INPUT_STREAM
(saver->priv->input));
- read_file_chunk (async);
+ read_file_chunk (saver);
}
static void
-begin_write (AsyncData *async)
+begin_write (GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
gboolean make_backup;
- DEBUG ({
- g_print ("Start replacing file contents\n");
- });
-
- /* For remote files we simply use g_file_replace_async. There is no
- * backup as of yet.
- */
- saver = async->saver;
-
make_backup = (saver->priv->flags & GTK_SOURCE_FILE_SAVE_IGNORE_BACKUP) == 0 &&
(saver->priv->flags & GTK_SOURCE_FILE_SAVE_PRESERVE_BACKUP) == 0;
DEBUG ({
+ g_print ("Start replacing file contents\n");
+ /* FIXME is the size already set? */
g_print ("File contents size: %" G_GINT64_FORMAT "\n", saver->priv->size);
g_print ("Make backup: %s\n", make_backup ? "yes" : "no");
});
@@ -846,41 +765,33 @@ begin_write (AsyncData *async)
NULL,
make_backup,
G_FILE_CREATE_NONE,
- G_PRIORITY_HIGH,
- async->cancellable,
- (GAsyncReadyCallback) async_replace_ready_callback,
- async);
+ g_task_get_priority (saver->priv->task),
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback) replace_file_cb,
+ saver);
}
static void
-mount_ready_callback (GFile *file,
- GAsyncResult *res,
- AsyncData *async)
+mount_cb (GFile *location,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
GError *error = NULL;
- gboolean mounted;
DEBUG ({
g_print ("%s\n", G_STRFUNC);
});
- /* manual check for cancelled state */
- if (g_cancellable_is_cancelled (async->cancellable))
- {
- async_data_free (async);
- return;
- }
+ g_file_mount_enclosing_volume_finish (location, result, &error);
- mounted = g_file_mount_enclosing_volume_finish (file, res, &error);
-
- if (!mounted)
+ if (error != NULL)
{
- async_failed (async, error);
+ g_task_return_error (saver->priv->task, error);
}
else
{
- /* try again to get the modified state */
- check_modified_async (async);
+ /* Try again to get the modified state. */
+ check_externally_modified (saver);
}
}
@@ -893,31 +804,30 @@ create_mount_operation (GtkSourceFileSaver *saver)
}
static void
-recover_not_mounted (AsyncData *async)
+recover_not_mounted (GtkSourceFileSaver *saver)
{
- GMountOperation *mount_operation = create_mount_operation (async->saver);
+ GMountOperation *mount_operation = create_mount_operation (saver);
DEBUG ({
g_print ("%s\n", G_STRFUNC);
});
- async->tried_mount = TRUE;
- g_file_mount_enclosing_volume (async->saver->priv->location,
+ saver->priv->tried_mount = TRUE;
+ g_file_mount_enclosing_volume (saver->priv->location,
G_MOUNT_MOUNT_NONE,
mount_operation,
- async->cancellable,
- (GAsyncReadyCallback) mount_ready_callback,
- async);
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback) mount_cb,
+ saver);
g_object_unref (mount_operation);
}
static void
-check_modification_callback (GFile *source,
- GAsyncResult *res,
- AsyncData *async)
+check_externally_modified_cb (GFile *location,
+ GAsyncResult *result,
+ GtkSourceFileSaver *saver)
{
- GtkSourceFileSaver *saver;
GError *error = NULL;
GFileInfo *info;
@@ -925,37 +835,35 @@ check_modification_callback (GFile *source,
g_print ("%s\n", G_STRFUNC);
});
- /* manually check cancelled state */
- if (g_cancellable_is_cancelled (async->cancellable))
+ if (saver->priv->flags & GTK_SOURCE_FILE_SAVE_IGNORE_MTIME)
{
- async_data_free (async);
- return;
+ g_warning ("Useless check for externally modified file.");
}
- saver = async->saver;
- info = g_file_query_info_finish (source, res, &error);
- if (info == NULL)
+ info = g_file_query_info_finish (location, result, &error);
+
+ if (error != NULL)
{
- if (error->code == G_IO_ERROR_NOT_MOUNTED && !async->tried_mount)
+ if (error->code == G_IO_ERROR_NOT_MOUNTED && !saver->priv->tried_mount)
{
- recover_not_mounted (async);
+ recover_not_mounted (saver);
g_error_free (error);
return;
}
- /* it's perfectly fine if the file doesn't exist yet */
+ /* It's perfectly fine if the file doesn't exist yet. */
if (error->code != G_IO_ERROR_NOT_FOUND)
{
DEBUG ({
g_print ("Error getting modification: %s\n", error->message);
});
- async_failed (async, error);
+ g_task_return_error (saver->priv->task, error);
return;
}
}
- /* check if the mtime is > what we know about it (if we have it) */
+ /* Check if the mtime is greater from what we know about it (if we have it). */
if (info != NULL && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
{
GTimeVal mtime;
@@ -972,14 +880,12 @@ check_modification_callback (GFile *source,
g_print ("File is externally modified\n");
});
- g_set_error (&saver->priv->error,
- GTK_SOURCE_FILE_ERROR,
- GTK_SOURCE_FILE_ERROR_EXTERNALLY_MODIFIED,
- "Externally modified");
-
- remote_save_completed_or_failed (saver, async);
g_object_unref (info);
+ g_task_return_new_error (saver->priv->task,
+ GTK_SOURCE_FILE_ERROR,
+ GTK_SOURCE_FILE_ERROR_EXTERNALLY_MODIFIED,
+ "Externally modified");
return;
}
}
@@ -989,150 +895,99 @@ check_modification_callback (GFile *source,
g_object_unref (info);
}
- /* modification check passed, start write */
- begin_write (async);
+ /* Externally modified check passed, start write. */
+ begin_write (saver);
}
static void
-check_modified_async (AsyncData *async)
+check_externally_modified (GtkSourceFileSaver *saver)
{
DEBUG ({
g_print ("Check externally modified\n");
});
- g_file_query_info_async (async->saver->priv->location,
+ g_file_query_info_async (saver->priv->location,
G_FILE_ATTRIBUTE_TIME_MODIFIED,
G_FILE_QUERY_INFO_NONE,
- G_PRIORITY_HIGH,
- async->cancellable,
- (GAsyncReadyCallback) check_modification_callback,
- async);
+ g_task_get_priority (saver->priv->task),
+ g_task_get_cancellable (saver->priv->task),
+ (GAsyncReadyCallback)check_externally_modified_cb,
+ saver);
}
-static gboolean
-save_remote_file_real (GtkSourceFileSaver *saver)
+GFile *
+gtk_source_file_saver_get_location (GtkSourceFileSaver *saver)
{
- AsyncData *async;
-
- DEBUG ({
- g_print ("Starting save\n");
- });
+ g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), NULL);
- /* First find out if the file is modified externally. This requires
- * a stat, but I don't think we can do this any other way
- */
- async = async_data_new (saver);
+ return g_file_dup (saver->priv->location);
+}
- check_modified_async (async);
+void
+gtk_source_file_saver_set_mount_operation_factory (GtkSourceFileSaver *saver,
+ GtkSourceMountOperationFactory callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver));
- /* return false to stop timeout */
- return FALSE;
+ saver->priv->mount_operation_factory = callback;
+ saver->priv->mount_operation_userdata = user_data;
}
void
-gtk_source_file_saver_save (GtkSourceFileSaver *saver,
- GTimeVal *old_mtime)
+gtk_source_file_saver_save_async (GtkSourceFileSaver *saver,
+ gint io_priority,
+ GTimeVal *old_mtime,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- DEBUG ({
- g_print ("%s\n", G_STRFUNC);
- });
-
g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver));
+ g_return_if_fail (saver->priv->task == NULL);
g_return_if_fail (saver->priv->location != NULL);
+ g_return_if_fail (!saver->priv->used);
- g_return_if_fail (saver->priv->used == FALSE);
saver->priv->used = TRUE;
- /* CHECK:
- report async (in an idle handler) or sync (bool ret)
- async is extra work here, sync is special casing in the caller */
+ saver->priv->task = g_task_new (saver, cancellable, callback, user_data);
+ g_task_set_priority (saver->priv->task, io_priority);
saver->priv->old_mtime = *old_mtime;
+ saver->priv->progress_cb = progress_callback;
+ saver->priv->progress_cb_data = progress_callback_data;
- /* saving start */
- gtk_source_file_saver_saving (saver, FALSE, NULL);
-
- g_timeout_add_full (G_PRIORITY_HIGH,
- 0,
- (GSourceFunc) save_remote_file_real,
- saver,
- NULL);
-}
+ DEBUG ({
+ g_print ("Starting save\n");
+ });
-void
-gtk_source_file_saver_saving (GtkSourceFileSaver *saver,
- gboolean completed,
- GError *error)
-{
- /* the object will be unrefed in the callback of the saving
- * signal, so we need to prevent finalization.
+ /* TODO create a thread and use sync GIO functions for the first steps.
+ * Destroy the thread for the main step, reading the buffer and writing
+ * the file. Because the buffer must be read in the main thread.
*/
- if (completed)
+
+ if (saver->priv->flags & GTK_SOURCE_FILE_SAVE_IGNORE_MTIME)
{
- g_object_ref (saver);
+ begin_write (saver);
}
-
- g_signal_emit (saver, signals[SAVING], 0, completed, error);
-
- if (completed)
+ else
{
- if (error == NULL)
- {
- DEBUG ({
- g_print ("save completed\n");
- });
- }
- else
- {
- DEBUG ({
- g_print ("save failed\n");
- });
- }
-
- g_object_unref (saver);
+ /* TODO install a FileMonitor in GtkSourceFile, with an
+ * externally-modified property, or a signal.
+ */
+ check_externally_modified (saver);
}
}
-GFile *
-gtk_source_file_saver_get_location (GtkSourceFileSaver *saver)
+gboolean
+gtk_source_file_saver_save_finish (GtkSourceFileSaver *saver,
+ GAsyncResult *result,
+ GError **error)
{
- g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), NULL);
+ g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (g_task_is_valid (result, saver), FALSE);
- return g_file_dup (saver->priv->location);
-}
-
-/* Returns 0 if file size is unknown */
-goffset
-gtk_source_file_saver_get_file_size (GtkSourceFileSaver *saver)
-{
- g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), 0);
-
- return saver->priv->size;
-}
-
-goffset
-gtk_source_file_saver_get_bytes_written (GtkSourceFileSaver *saver)
-{
- g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), 0);
-
- return saver->priv->bytes_written;
-}
-
-GFileInfo *
-gtk_source_file_saver_get_info (GtkSourceFileSaver *saver)
-{
- g_return_val_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver), NULL);
-
- return saver->priv->info;
-}
-
-void
-gtk_source_file_saver_set_mount_operation_factory (GtkSourceFileSaver *saver,
- GtkSourceMountOperationFactory callback,
- gpointer user_data)
-{
- g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver));
-
- saver->priv->mount_operation_factory = callback;
- saver->priv->mount_operation_userdata = user_data;
+ return g_task_propagate_boolean (G_TASK (result), error);
}
diff --git a/gtksourceview/gtksourcefilesaver.h b/gtksourceview/gtksourcefilesaver.h
index 4f69c01..17fb62f 100644
--- a/gtksourceview/gtksourcefilesaver.h
+++ b/gtksourceview/gtksourcefilesaver.h
@@ -58,17 +58,11 @@ struct _GtkSourceFileSaver
struct _GtkSourceFileSaverClass
{
GObjectClass parent_class;
-
- /* Signals */
- void (* saving) (GtkSourceFileSaver *saver,
- gboolean completed,
- const GError *error);
};
G_GNUC_INTERNAL
GType gtk_source_file_saver_get_type (void) G_GNUC_CONST;
-/* If enconding == NULL, the encoding will be autodetected */
G_GNUC_INTERNAL
GtkSourceFileSaver *gtk_source_file_saver_new (GtkTextBuffer *buffer,
GFile *location,
@@ -79,33 +73,29 @@ GtkSourceFileSaver *gtk_source_file_saver_new (GtkTextBuffer
*
gboolean
ensure_trailing_newline);
G_GNUC_INTERNAL
-void gtk_source_file_saver_saving (GtkSourceFileSaver *saver,
- gboolean completed,
- GError *error);
-
-G_GNUC_INTERNAL
-void gtk_source_file_saver_save (GtkSourceFileSaver *saver,
- GTimeVal *old_mtime);
-
-G_GNUC_INTERNAL
GFile *gtk_source_file_saver_get_location (GtkSourceFileSaver *saver);
-/* Returns 0 if file size is unknown */
-G_GNUC_INTERNAL
-goffset gtk_source_file_saver_get_file_size (GtkSourceFileSaver *saver);
-
-G_GNUC_INTERNAL
-goffset gtk_source_file_saver_get_bytes_written (GtkSourceFileSaver *saver);
-
-G_GNUC_INTERNAL
-GFileInfo *gtk_source_file_saver_get_info (GtkSourceFileSaver *saver);
-
G_GNUC_INTERNAL
void gtk_source_file_saver_set_mount_operation_factory
(GtkSourceFileSaver *saver,
GtkSourceMountOperationFactory callback,
gpointer user_data);
+G_GNUC_INTERNAL
+void gtk_source_file_saver_save_async (GtkSourceFileSaver *saver,
+ gint io_priority,
+ GTimeVal *old_mtime,
+ GCancellable *cancellable,
+ GFileProgressCallback progress_callback,
+ gpointer
progress_callback_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+G_GNUC_INTERNAL
+gboolean gtk_source_file_saver_save_finish (GtkSourceFileSaver *saver,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* __GTK_SOURCE_FILE_SAVER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]