[gtksourceview/wip/better-use-gtask] FileLoader: move some of the instance variables to a TaskData struct



commit 92bbc79ab61d5241e250c0300cf52ed2b47cadd0
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sat May 7 11:46:16 2016 +0200

    FileLoader: move some of the instance variables to a TaskData struct
    
    It's not a good practice to have too many instance variables. So move
    the task-related instance variables to a TaskData struct. It's how GTask
    is meant to be used. But GtkSourceFileLoader is a bit special, since
    there can be at most one task running at a time, otherwise it would
    screw up the GtkSourceBuffer content and FileLoader state. So we still
    keep the GTask object as an instance variable.
    
    Moving chunk_buffer to the TaskData struct has the nice effect that we
    are no longer limited by the maximum size of a GType instance private
    data.
    
    Also, make the code more robust. Instead of casting the callback
    functions, put the original param types and cast the params inside the
    callback function.

 gtksourceview/gtksourcefileloader.c |  320 +++++++++++++++++++++--------------
 1 files changed, 190 insertions(+), 130 deletions(-)
---
diff --git a/gtksourceview/gtksourcefileloader.c b/gtksourceview/gtksourcefileloader.c
index 78263e5..22b9928 100644
--- a/gtksourceview/gtksourcefileloader.c
+++ b/gtksourceview/gtksourcefileloader.c
@@ -99,47 +99,81 @@ struct _GtkSourceFileLoaderPrivate
 
        GFile *location;
 
-       /* The value of the "input-stream" property. */
+       /* The value of the :input-stream property. Do not confuse with the
+        * input_stream field in TaskData.
+        */
        GInputStream *input_stream_property;
 
        GSList *candidate_encodings;
 
-       GFileInfo *info;
        const GtkSourceEncoding *auto_detected_encoding;
        GtkSourceNewlineType auto_detected_newline_type;
        GtkSourceCompressionType auto_detected_compression_type;
 
        GTask *task;
+};
+
+typedef struct _TaskData TaskData;
+struct _TaskData
+{
+       /* The two streams cannot be spliced directly, because:
+        * (1) We need to call the progress callback.
+        * (2) Sync methods must be used for the output stream, and async
+        *     methods for the input stream.
+        */
+       GInputStream *input_stream;
+       GtkSourceBufferOutputStream *output_stream;
+
+       GFileInfo *info;
 
-       goffset total_bytes_read;
-       goffset total_size;
        GFileProgressCallback progress_cb;
        gpointer progress_cb_data;
        GDestroyNotify progress_cb_notify;
 
-       /* Warning: type instances' private data are limited to a total of 64 KiB.
-        * See the GType documentation.
-        */
-       gchar chunk_buffer[READ_CHUNK_SIZE];
-       gssize chunk_bytes_read;
+       goffset total_bytes_read;
+       goffset total_size;
 
-       /* The two streams cannot be spliced directly, because
-        * (1) we need to call the progress callback
-        * (2) sync methods must be used for the output stream, and async
-        *     methods for the input stream.
-        */
-       GInputStream *input_stream;
-       GtkSourceBufferOutputStream *output_stream;
+       gssize chunk_bytes_read;
+       gchar chunk_buffer[READ_CHUNK_SIZE];
 
+       /* FIXME should be in TaskData or the Private object struct? */
        guint guess_content_type_from_content : 1;
        guint tried_mount : 1;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceFileLoader, gtk_source_file_loader, G_TYPE_OBJECT)
 
-static void open_file (GtkSourceFileLoader *loader);
+static void open_file (GTask *task);
 static void read_file_chunk (GtkSourceFileLoader *loader);
 
+static TaskData *
+task_data_new (void)
+{
+       return g_new0 (TaskData, 1);
+}
+
+static void
+task_data_free (gpointer data)
+{
+       TaskData *task_data = data;
+
+       if (task_data == NULL)
+       {
+               return;
+       }
+
+       g_clear_object (&task_data->input_stream);
+       g_clear_object (&task_data->output_stream);
+       g_clear_object (&task_data->info);
+
+       if (loader->priv->progress_cb_notify != NULL)
+       {
+               loader->priv->progress_cb_notify (loader->priv->progress_cb_data);
+       }
+
+       g_free (task_data);
+}
+
 static GtkSourceCompressionType
 get_compression_type_from_content_type (const gchar *content_type)
 {
@@ -229,30 +263,10 @@ gtk_source_file_loader_get_property (GObject    *object,
 }
 
 static void
-reset (GtkSourceFileLoader *loader)
-{
-       g_clear_object (&loader->priv->task);
-       g_clear_object (&loader->priv->input_stream);
-       g_clear_object (&loader->priv->output_stream);
-       g_clear_object (&loader->priv->info);
-
-       if (loader->priv->progress_cb_notify != NULL)
-       {
-               loader->priv->progress_cb_notify (loader->priv->progress_cb_data);
-               loader->priv->progress_cb_notify = NULL;
-       }
-
-       loader->priv->progress_cb = NULL;
-       loader->priv->progress_cb_data = NULL;
-}
-
-static void
 gtk_source_file_loader_dispose (GObject *object)
 {
        GtkSourceFileLoader *loader = GTK_SOURCE_FILE_LOADER (object);
 
-       reset (loader);
-
        if (loader->priv->source_buffer != NULL)
        {
                g_object_remove_weak_pointer (G_OBJECT (loader->priv->source_buffer),
@@ -271,6 +285,7 @@ gtk_source_file_loader_dispose (GObject *object)
 
        g_clear_object (&loader->priv->location);
        g_clear_object (&loader->priv->input_stream_property);
+       g_clear_object (&loader->priv->task);
 
        g_slist_free (loader->priv->candidate_encodings);
        loader->priv->candidate_encodings = NULL;
@@ -554,48 +569,55 @@ write_file_chunk (GtkSourceFileLoader *loader)
 }
 
 static void
-read_cb (GInputStream        *input_stream,
-        GAsyncResult        *result,
-        GtkSourceFileLoader *loader)
+read_cb (GObject      *source_object,
+        GAsyncResult *result,
+        gpointer      user_data)
 {
+       GInputStream *input_stream = G_INPUT_STREAM (source_object);
+       GTask *task = G_TASK (user_data);
+       GtkSourceFileLoader *loader;
+       TaskData *task_data;
        GError *error = NULL;
 
        DEBUG ({
               g_print ("%s\n", G_STRFUNC);
        });
 
-       loader->priv->chunk_bytes_read = g_input_stream_read_finish (input_stream, result, &error);
+       loader = g_task_get_source_object (task);
+       task_data = g_task_get_task_data (task);
+
+       task_data->chunk_bytes_read = g_input_stream_read_finish (input_stream, result, &error);
 
        if (error != NULL)
        {
-               g_task_return_error (loader->priv->task, error);
+               g_task_return_error (task, error);
                return;
        }
 
        /* Check for the extremely unlikely case where the file size overflows. */
-       if (loader->priv->total_bytes_read + loader->priv->chunk_bytes_read < loader->priv->total_bytes_read)
+       if (task_data->total_bytes_read + task_data->chunk_bytes_read < task_data->total_bytes_read)
        {
-               g_task_return_new_error (loader->priv->task,
+               g_task_return_new_error (task,
                                         GTK_SOURCE_FILE_LOADER_ERROR,
                                         GTK_SOURCE_FILE_LOADER_ERROR_TOO_BIG,
                                         "File too big");
                return;
        }
 
-       if (loader->priv->guess_content_type_from_content &&
-           loader->priv->chunk_bytes_read > 0 &&
-           loader->priv->total_bytes_read == 0)
+       if (task_data->guess_content_type_from_content &&
+           task_data->chunk_bytes_read > 0 &&
+           task_data->total_bytes_read == 0)
        {
                gchar *guessed;
 
                guessed = g_content_type_guess (NULL,
-                                               (guchar *)loader->priv->chunk_buffer,
-                                               loader->priv->chunk_bytes_read,
+                                               (guchar *)task_data->chunk_buffer,
+                                               task_data->chunk_bytes_read,
                                                NULL);
 
                if (guessed != NULL)
                {
-                       g_file_info_set_attribute_string (loader->priv->info,
+                       g_file_info_set_attribute_string (task_data->info,
                                                          G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
                                                          guessed);
 
@@ -603,74 +625,86 @@ read_cb (GInputStream        *input_stream,
                }
        }
 
-       /* Bump the size. */
-       loader->priv->total_bytes_read += loader->priv->chunk_bytes_read;
-
        /* End of the file, we are done! */
-       if (loader->priv->chunk_bytes_read == 0)
+       if (task_data->chunk_bytes_read == 0)
        {
                /* Flush the stream to ensure proper line ending detection. */
-               g_output_stream_flush (G_OUTPUT_STREAM (loader->priv->output_stream), NULL, NULL);
+               g_output_stream_flush (G_OUTPUT_STREAM (task_data->output_stream), NULL, NULL);
 
                loader->priv->auto_detected_encoding =
-                       gtk_source_buffer_output_stream_get_guessed (loader->priv->output_stream);
+                       gtk_source_buffer_output_stream_get_guessed (task_data->output_stream);
 
                loader->priv->auto_detected_newline_type =
-                       gtk_source_buffer_output_stream_detect_newline_type (loader->priv->output_stream);
+                       gtk_source_buffer_output_stream_detect_newline_type (task_data->output_stream);
 
-               write_complete (loader);
+               write_complete (task);
                return;
        }
 
-       write_file_chunk (loader);
+       task_data->total_bytes_read += task_data->chunk_bytes_read;
+
+       write_file_chunk (task);
 }
 
 static void
-read_file_chunk (GtkSourceFileLoader *loader)
+read_file_chunk (GTask *task)
 {
-       g_input_stream_read_async (loader->priv->input_stream,
-                                  loader->priv->chunk_buffer,
+       TaskData *task_data;
+
+       task_data = g_task_get_task_data (task);
+
+       g_input_stream_read_async (task_data->input_stream,
+                                  task_data->chunk_buffer,
                                   READ_CHUNK_SIZE,
-                                  g_task_get_priority (loader->priv->task),
-                                  g_task_get_cancellable (loader->priv->task),
-                                  (GAsyncReadyCallback) read_cb,
-                                  loader);
+                                  g_task_get_priority (task),
+                                  g_task_get_cancellable (task),
+                                  read_cb,
+                                  task);
 }
 
 static void
-add_gzip_decompressor_stream (GtkSourceFileLoader *loader)
+add_gzip_decompressor_stream (GTask *task)
 {
+       TaskData *task_data;
        GZlibDecompressor *decompressor;
        GInputStream *new_input_stream;
 
+       task_data = g_task_get_task_data (task);
+
        decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
 
-       new_input_stream = g_converter_input_stream_new (loader->priv->input_stream,
+       new_input_stream = g_converter_input_stream_new (task_data->input_stream,
                                                         G_CONVERTER (decompressor));
 
-       g_object_unref (loader->priv->input_stream);
+       g_object_unref (task_data->input_stream);
        g_object_unref (decompressor);
 
-       loader->priv->input_stream = new_input_stream;
+       task_data->input_stream = new_input_stream;
 }
 
 static void
-create_input_stream (GtkSourceFileLoader *loader)
+create_input_stream (GTask *task)
 {
+       GtkSourceFileLoader *loader;
+       TaskData *task_data;
+
+       loader = g_task_get_source_object (task);
+       task_data = g_task_get_task_data (task);
+
        loader->priv->auto_detected_compression_type = GTK_SOURCE_COMPRESSION_TYPE_NONE;
 
        if (loader->priv->input_stream_property != NULL)
        {
-               loader->priv->input_stream = g_object_ref (loader->priv->input_stream_property);
+               task_data->input_stream = g_object_ref (loader->priv->input_stream_property);
        }
-       else if (g_file_info_has_attribute (loader->priv->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
+       else if (g_file_info_has_attribute (task_data->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
        {
-               const gchar *content_type = g_file_info_get_content_type (loader->priv->info);
+               const gchar *content_type = g_file_info_get_content_type (task_data->info);
 
                switch (get_compression_type_from_content_type (content_type))
                {
                        case GTK_SOURCE_COMPRESSION_TYPE_GZIP:
-                               add_gzip_decompressor_stream (loader);
+                               add_gzip_decompressor_stream (task);
                                loader->priv->auto_detected_compression_type = 
GTK_SOURCE_COMPRESSION_TYPE_GZIP;
                                break;
 
@@ -683,120 +717,140 @@ create_input_stream (GtkSourceFileLoader *loader)
                }
        }
 
-       g_return_if_fail (loader->priv->input_stream != NULL);
+       g_return_if_fail (task_data->input_stream != NULL);
 
        /* start reading */
-       read_file_chunk (loader);
+       read_file_chunk (task);
 }
 
 static void
-query_info_cb (GFile               *file,
-              GAsyncResult        *result,
-              GtkSourceFileLoader *loader)
+query_info_cb (GObject      *source_object,
+              GAsyncResult *result,
+              gpointer      user_data)
 {
+       GFile *location = G_FILE (source_obejct);
+       GTask *task = G_TASK (user_data);
+       TaskData *task_data;
        GError *error = NULL;
 
        DEBUG ({
               g_print ("%s\n", G_STRFUNC);
        });
 
-       loader->priv->info = g_file_query_info_finish (file, result, &error);
+       task_data = g_task_get_task_data (task);
+
+       g_clear_object (&task_data->info);
+       task_data->info = g_file_query_info_finish (location, result, &error);
 
        if (error != NULL)
        {
-               g_task_return_error (loader->priv->task, error);
+               g_task_return_error (task, error);
                return;
        }
 
-       if (g_file_info_has_attribute (loader->priv->info, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
-           g_file_info_get_file_type (loader->priv->info) != G_FILE_TYPE_REGULAR)
+       if (g_file_info_has_attribute (task_data->info, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
+           g_file_info_get_file_type (task_data->info) != G_FILE_TYPE_REGULAR)
        {
-               g_task_return_new_error (loader->priv->task,
+               g_task_return_new_error (task,
                                         G_IO_ERROR,
                                         G_IO_ERROR_NOT_REGULAR_FILE,
                                         "Not a regular file");
                return;
        }
 
-       if (g_file_info_has_attribute (loader->priv->info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+       if (g_file_info_has_attribute (task_data->info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
        {
-               loader->priv->total_size = g_file_info_get_attribute_uint64 (loader->priv->info,
-                                                                            G_FILE_ATTRIBUTE_STANDARD_SIZE);
+               task_data->total_size = g_file_info_get_attribute_uint64 (task_data->info,
+                                                                         G_FILE_ATTRIBUTE_STANDARD_SIZE);
        }
 
-       create_input_stream (loader);
+       create_input_stream (task);
 }
 
 static void
-mount_cb (GFile               *file,
-         GAsyncResult        *result,
-         GtkSourceFileLoader *loader)
+mount_cb (GObject      *source_object,
+         GAsyncResult *result,
+         gpointer      user_data)
 {
+       GFile *location = G_FILE (source_object);
+       GTask *task = G_TASK (user_data);
        GError *error = NULL;
 
        DEBUG ({
               g_print ("%s\n", G_STRFUNC);
        });
 
-       g_file_mount_enclosing_volume_finish (file, result, &error);
+       g_file_mount_enclosing_volume_finish (location, result, &error);
 
        if (error != NULL)
        {
-               g_task_return_error (loader->priv->task, error);
+               g_task_return_error (task, error);
        }
        else
        {
                /* Try again to open the file for reading. */
-               open_file (loader);
+               open_file (task);
        }
 }
 
 static void
-recover_not_mounted (GtkSourceFileLoader *loader)
+recover_not_mounted (GTask *task)
 {
+       GtkSourceFileLoader *loader;
+       TaskData *task_data;
        GMountOperation *mount_operation;
 
+       loader = g_task_get_source_object (task);
+       task_data = g_task_get_task_data (task);
+
        mount_operation = _gtk_source_file_create_mount_operation (loader->priv->file);
 
        DEBUG ({
               g_print ("%s\n", G_STRFUNC);
        });
 
-       loader->priv->tried_mount = TRUE;
+       task_data->tried_mount = TRUE;
 
        g_file_mount_enclosing_volume (loader->priv->location,
                                       G_MOUNT_MOUNT_NONE,
                                       mount_operation,
-                                      g_task_get_cancellable (loader->priv->task),
-                                      (GAsyncReadyCallback) mount_cb,
-                                      loader);
+                                      g_task_get_cancellable (task),
+                                      mount_cb,
+                                      task);
 
        g_object_unref (mount_operation);
 }
 
 static void
-open_file_cb (GFile               *file,
-             GAsyncResult        *result,
-             GtkSourceFileLoader *loader)
+open_file_cb (GObject      *source_object,
+             GAsyncResult *result,
+             gpointer      user_data)
 {
+       GFile *location = G_FILE (source_object);
+       GTask *task = G_TASK (user_data);
+       TaskData *task_data;
        GError *error = NULL;
 
        DEBUG ({
               g_print ("%s\n", G_STRFUNC);
        });
 
-       loader->priv->input_stream = G_INPUT_STREAM (g_file_read_finish (file, result, &error));
+       task_data = g_task_get_task_data (task);
+
+       g_clear_object (&task_data->input_stream);
+       task_data->input_stream = G_INPUT_STREAM (g_file_read_finish (location, result, &error));
 
        if (error != NULL)
        {
-               if (error->code == G_IO_ERROR_NOT_MOUNTED && !loader->priv->tried_mount)
+               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED) &&
+                   !task_data->tried_mount)
                {
-                       recover_not_mounted (loader);
+                       recover_not_mounted (task);
                        g_error_free (error);
                        return;
                }
 
-               g_task_return_error (loader->priv->task, error);
+               g_task_return_error (task, error);
                return;
        }
 
@@ -806,23 +860,27 @@ open_file_cb (GFile               *file,
         * Using the file instead of the stream is slightly racy, but for
         * loading this is not too bad...
         */
-       g_file_query_info_async (file,
+       g_file_query_info_async (location,
                                 LOADER_QUERY_ATTRIBUTES,
                                  G_FILE_QUERY_INFO_NONE,
-                                g_task_get_priority (loader->priv->task),
-                                g_task_get_cancellable (loader->priv->task),
-                                (GAsyncReadyCallback) query_info_cb,
-                                loader);
+                                g_task_get_priority (task),
+                                g_task_get_cancellable (task),
+                                query_info_cb,
+                                task);
 }
 
 static void
-open_file (GtkSourceFileLoader *loader)
+open_file (GTask *task)
 {
+       GtkSourceFileLoader *loader;
+
+       loader = g_task_get_source_object (task);
+
        g_file_read_async (loader->priv->location,
-                          g_task_get_priority (loader->priv->task),
-                          g_task_get_cancellable (loader->priv->task),
-                          (GAsyncReadyCallback) open_file_cb,
-                          loader);
+                          g_task_get_priority (task),
+                          g_task_get_cancellable (task),
+                          open_file_cb,
+                          task);
 }
 
 GQuark
@@ -1026,20 +1084,22 @@ gtk_source_file_loader_load_async (GtkSourceFileLoader   *loader,
                                   GAsyncReadyCallback    callback,
                                   gpointer               user_data)
 {
+       TaskData *task_data;
        gboolean implicit_trailing_newline;
 
        g_return_if_fail (GTK_SOURCE_IS_FILE_LOADER (loader));
        g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
        g_return_if_fail (loader->priv->task == NULL);
 
-       reset (loader);
-
        loader->priv->task = g_task_new (loader, cancellable, callback, user_data);
        g_task_set_priority (loader->priv->task, io_priority);
 
-       loader->priv->progress_cb = progress_callback;
-       loader->priv->progress_cb_data = progress_callback_data;
-       loader->priv->progress_cb_notify = progress_callback_notify;
+       task_data = task_data_new ();
+       g_task_set_task_data (loader->priv->task, task_data, task_data_free);
+
+       task_data->progress_cb = progress_callback;
+       task_data->progress_cb_data = progress_callback_data;
+       task_data->progress_cb_notify = progress_callback_notify;
 
        if (loader->priv->source_buffer == NULL ||
            loader->priv->file == NULL ||
@@ -1076,20 +1136,20 @@ gtk_source_file_loader_load_async (GtkSourceFileLoader   *loader,
          * We create the BufferOutputStream here so we are sure that the
          * buffer will not be destroyed during the file loading.
          */
-       loader->priv->output_stream = gtk_source_buffer_output_stream_new (loader->priv->source_buffer,
-                                                                          loader->priv->candidate_encodings,
-                                                                          implicit_trailing_newline);
+       task_data->output_stream = gtk_source_buffer_output_stream_new (loader->priv->source_buffer,
+                                                                       loader->priv->candidate_encodings,
+                                                                       implicit_trailing_newline);
 
        if (loader->priv->input_stream_property != NULL)
        {
-               loader->priv->guess_content_type_from_content = TRUE;
-               loader->priv->info = g_file_info_new ();
+               task_data->guess_content_type_from_content = TRUE;
+               task_data->info = g_file_info_new ();
 
-               create_input_stream (loader);
+               create_input_stream (loader->priv->task);
        }
        else
        {
-               open_file (loader);
+               open_file (loader->priv->task);
        }
 }
 
@@ -1180,7 +1240,7 @@ gtk_source_file_loader_load_finish (GtkSourceFileLoader  *loader,
                }
        }
 
-       reset (loader);
+       g_clear_object (&loader->priv->task);
 
        if (real_error != NULL)
        {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]