[ghex] HexBuffer{Iface,Mmap}: implement _read_async API



commit 21a984cb63f8f47a5457eaa5a814a3c6e87aeb72
Author: Logan Rathbone <poprocks gmail com>
Date:   Fri Dec 17 05:33:18 2021 -0500

    HexBuffer{Iface,Mmap}: implement _read_async API

 src/ghex-application-window.c     | 64 +++++++++++++++++++++++++++++++--------
 src/ghex-application-window.ui.in | 14 ++++++++-
 src/gtkhex.c                      | 26 +++++++++++++---
 src/hex-buffer-iface.c            | 30 +++++++++++++++++-
 src/hex-buffer-iface.h            | 15 +++++++++
 src/hex-buffer-mmap.c             | 55 ++++++++++++++++++++++++++++++++-
 src/hex-document.c                | 52 +++++++++++++++++++++++--------
 src/hex-document.h                |  2 +-
 8 files changed, 224 insertions(+), 34 deletions(-)
---
diff --git a/src/ghex-application-window.c b/src/ghex-application-window.c
index 51c1113..5b4075e 100644
--- a/src/ghex-application-window.c
+++ b/src/ghex-application-window.c
@@ -68,6 +68,7 @@ struct _GHexApplicationWindow
 
        /* From GtkBuilder: */
        GtkWidget *no_doc_label;
+       GtkWidget *doc_loading_spinner;
        GtkWidget *hex_notebook;
        GtkWidget *conversions_box;
        GtkWidget *findreplace_box;
@@ -657,7 +658,17 @@ assess_can_save (HexDocument *doc)
 }
 
 static void
-ghex_application_window_file_saved_cb (HexDocument *doc,
+do_doc_loading_spinner (GHexApplicationWindow *self)
+{
+               gtk_widget_hide (self->no_doc_label);
+               gtk_widget_hide (self->hex_notebook);
+
+               gtk_spinner_start (GTK_SPINNER(self->doc_loading_spinner));
+               gtk_widget_show (self->doc_loading_spinner);
+}
+
+static void
+file_saved_cb (HexDocument *doc,
                gpointer user_data)
 {
        GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(user_data);
@@ -668,13 +679,9 @@ ghex_application_window_file_saved_cb (HexDocument *doc,
 }
 
 static void
-ghex_application_window_document_changed_cb (HexDocument *doc,
-               gpointer change_data,
-               gboolean push_undo,
-               gpointer user_data)
+document_loaded_or_saved_common (GHexApplicationWindow *self,
+               HexDocument *doc)
 {
-       GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(user_data);
-
        g_return_if_fail (GHEX_IS_APPLICATION_WINDOW (self));
 
        /* The appwindow as a whole not interested in any document changes that
@@ -686,6 +693,31 @@ ghex_application_window_document_changed_cb (HexDocument *doc,
        ghex_application_window_set_can_save (self, assess_can_save (doc));
 }
 
+static void
+file_loaded_cb (HexDocument *doc, gpointer user_data)
+{
+       GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(user_data);
+       
+       gtk_spinner_stop (GTK_SPINNER(self->doc_loading_spinner));
+       gtk_widget_hide (self->doc_loading_spinner);
+       gtk_widget_hide (self->no_doc_label);
+       gtk_widget_show (self->hex_notebook);
+
+       document_loaded_or_saved_common (self, doc);
+}
+
+
+static void
+document_changed_cb (HexDocument *doc,
+               gpointer change_data,
+               gboolean push_undo,
+               gpointer user_data)
+{
+       GHexApplicationWindow *self = GHEX_APPLICATION_WINDOW(user_data);
+
+       document_loaded_or_saved_common (self, doc);
+}
+
 static void
 tab_close_request_cb (GHexNotebookTab *tab,
                gpointer user_data)
@@ -739,8 +771,7 @@ notebook_page_added_cb (GtkNotebook *notebook,
        /* Let's play this super dumb. If a page is added, that will generally
         * mean we don't have to count the pages to see if we have > 0.
         */
-       gtk_widget_show (self->hex_notebook);
-       gtk_widget_hide (self->no_doc_label);
+       do_doc_loading_spinner (self);
        enable_main_actions (self, TRUE);
 }
 
@@ -761,7 +792,10 @@ notebook_page_removed_cb (GtkNotebook *notebook,
                ghex_application_window_set_show_jump (self, FALSE);
                ghex_application_window_set_show_chartable (self, FALSE);
                ghex_application_window_set_show_converter (self, FALSE);
+
                gtk_widget_hide (self->hex_notebook);
+               gtk_widget_hide (self->doc_loading_spinner);
+               gtk_spinner_stop (GTK_SPINNER(self->doc_loading_spinner));
                gtk_widget_show (self->no_doc_label);
        }
 }
@@ -1035,7 +1069,7 @@ save_as_response_cb (GtkNativeDialog *dialog,
 
        if (hex_document_set_file (doc, gfile))
        {
-               hex_document_read (doc);
+               do_doc_loading_spinner (self);
        }
        else
        {
@@ -1093,6 +1127,7 @@ revert_response_cb (GtkDialog *dialog,
 
        doc = gtk_hex_get_document (ACTIVE_GH);
 
+       do_doc_loading_spinner (self);
        hex_document_read (doc);
 
 end:
@@ -1870,6 +1905,8 @@ ghex_application_window_class_init(GHexApplicationWindowClass *klass)
 
        gtk_widget_class_bind_template_child (widget_class, GHexApplicationWindow,
                        no_doc_label);
+       gtk_widget_class_bind_template_child (widget_class, GHexApplicationWindow,
+                       doc_loading_spinner);
        gtk_widget_class_bind_template_child (widget_class, GHexApplicationWindow,
                        hex_notebook);
        gtk_widget_class_bind_template_child (widget_class, GHexApplicationWindow,
@@ -1958,11 +1995,14 @@ ghex_application_window_add_hex (GHexApplicationWindow *self,
     g_signal_connect (gh, "cursor-moved",
                        G_CALLBACK(cursor_moved_cb), self);
 
+       g_signal_connect (doc, "file-loaded",
+                       G_CALLBACK(file_loaded_cb), self);
+
        g_signal_connect (doc, "document-changed",
-                       G_CALLBACK(ghex_application_window_document_changed_cb), self);
+                       G_CALLBACK(document_changed_cb), self);
 
        g_signal_connect (doc, "file-saved",
-                       G_CALLBACK(ghex_application_window_file_saved_cb), self);
+                       G_CALLBACK(file_saved_cb), self);
 }
 
 #ifndef EXPERIMENTAL_MMAP
diff --git a/src/ghex-application-window.ui.in b/src/ghex-application-window.ui.in
index a8923f4..ecafbfb 100644
--- a/src/ghex-application-window.ui.in
+++ b/src/ghex-application-window.ui.in
@@ -213,7 +213,19 @@
                                                                <property name="hexpand">true</property>
                                                                <property name="vexpand">true</property>
                                                        </object>
-                                               </child> <!-- label showing no doc loaded -->
+                                               </child> <!-- /no_doc_label -->
+
+                                               <child> <!-- label showing no doc loaded -->
+                                                       <object class="GtkSpinner" id="doc_loading_spinner">
+                                                               <property name="spinning">true</property> 
<!-- doesn't seem to work -->
+                                                               <property name="halign">center</property>
+                                                               <property name="valign">center</property>
+                                                               <property name="hexpand">true</property>
+                                                               <property name="vexpand">true</property>
+                                                               <!-- invisible by default to show the 
no_doc_label -->
+                                                               <property name="visible">false</property>
+                                                       </object>
+                                               </child> <!-- /doc_loading_spinner -->
 
                                                <child> <!-- hex_notebook - tabs for GtkHex widget -->
                                                        <object class="GtkNotebook" id="hex_notebook">
diff --git a/src/gtkhex.c b/src/gtkhex.c
index b856994..7c6e367 100644
--- a/src/gtkhex.c
+++ b/src/gtkhex.c
@@ -2225,7 +2225,21 @@ gtk_hex_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
 }
 
 static void
-gtk_hex_document_changed (HexDocument* doc, gpointer change_data,
+file_loaded_cb (HexDocument *doc, gpointer data)
+{
+       GtkHex *gh = GTK_HEX(data);
+       g_return_if_fail (GTK_IS_HEX (gh));
+
+       gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+                       "gtkhex.undo", hex_document_can_undo (doc));
+       gtk_widget_action_set_enabled (GTK_WIDGET(gh),
+                       "gtkhex.redo", hex_document_can_redo (doc));
+
+       gtk_widget_queue_draw (GTK_WIDGET(gh));
+}
+
+static void
+document_changed_cb (HexDocument* doc, gpointer change_data,
         gboolean push_undo, gpointer data)
 {
        GtkHex *gh = GTK_HEX(data);
@@ -2754,11 +2768,13 @@ gtk_hex_new (HexDocument *owner)
 
        gh->document = owner;
 
-       /* Setup document signals
-        * (can't do in _init because we don't have access to that object yet).
-        */
+       /* Setup document signals */
+
+    g_signal_connect (G_OBJECT (gh->document), "file-loaded",
+            G_CALLBACK (file_loaded_cb), gh);
+
     g_signal_connect (G_OBJECT (gh->document), "document-changed",
-            G_CALLBACK (gtk_hex_document_changed), gh);
+            G_CALLBACK (document_changed_cb), gh);
 
     g_signal_connect (G_OBJECT (gh->document), "undo",
             G_CALLBACK (doc_undo_redo_cb), gh);
diff --git a/src/hex-buffer-iface.c b/src/hex-buffer-iface.c
index 1a5baf1..91d69e4 100644
--- a/src/hex-buffer-iface.c
+++ b/src/hex-buffer-iface.c
@@ -76,7 +76,6 @@ hex_buffer_set_file (HexBuffer *self, GFile *file)
        return iface->set_file (self, file);
 }
 
-
 gboolean
 hex_buffer_read (HexBuffer *self)
 {
@@ -89,6 +88,35 @@ hex_buffer_read (HexBuffer *self)
        return iface->read (self);
 }
 
+void
+hex_buffer_read_async (HexBuffer *self,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+       HexBufferInterface *iface;
+
+       g_return_if_fail (HEX_IS_BUFFER (self));
+       iface = HEX_BUFFER_GET_IFACE (self);
+       g_return_if_fail (iface->read_async != NULL);
+
+       iface->read_async (self, cancellable, callback, user_data);
+}
+
+gboolean
+hex_buffer_read_finish (HexBuffer *self,
+               GAsyncResult *result,
+               GError **error)
+{
+       HexBufferInterface *iface;
+
+       g_return_val_if_fail (HEX_IS_BUFFER (self), FALSE);
+       iface = HEX_BUFFER_GET_IFACE (self);
+       g_return_val_if_fail (iface->read_finish != NULL, FALSE);
+
+       return iface->read_finish (self, result, error);
+}
+
 gboolean
 hex_buffer_write_to_file (HexBuffer *self, GFile *file)
 {
diff --git a/src/hex-buffer-iface.h b/src/hex-buffer-iface.h
index d61d495..43e9516 100644
--- a/src/hex-buffer-iface.h
+++ b/src/hex-buffer-iface.h
@@ -45,6 +45,15 @@ struct _HexBufferInterface
 
        gboolean (*read) (HexBuffer *self);
 
+       void (*read_async) (HexBuffer *self,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data);
+
+       gboolean (*read_finish) (HexBuffer *self,
+                       GAsyncResult *result,
+                       GError **error);
+
        gboolean (*write_to_file) (HexBuffer *self,
                        GFile *file);
 
@@ -75,6 +84,12 @@ gboolean hex_buffer_set_file (HexBuffer *self,
 
 gboolean hex_buffer_read (HexBuffer *self);
 
+void hex_buffer_read_async (HexBuffer *buf, GCancellable *cancellable,
+               GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean hex_buffer_read_finish (HexBuffer *buf, GAsyncResult *result,
+               GError **error);
+
 gboolean hex_buffer_write_to_file (HexBuffer *self,
                GFile *file);
 
diff --git a/src/hex-buffer-mmap.c b/src/hex-buffer-mmap.c
index 31193e7..8cac6df 100644
--- a/src/hex-buffer-mmap.c
+++ b/src/hex-buffer-mmap.c
@@ -563,6 +563,57 @@ hex_buffer_mmap_read (HexBuffer *buf)
        return TRUE;
 }
 
+static gboolean
+hex_buffer_mmap_read_finish (HexBuffer *buf,
+               GAsyncResult *result,
+               GError **error)
+{
+       HexBufferMmap *self = HEX_BUFFER_MMAP (buf);
+
+       g_return_val_if_fail (g_task_is_valid (result, G_OBJECT(self)), FALSE);
+
+       return g_task_propagate_boolean (G_TASK(result), error);
+}
+
+static void
+hex_buffer_mmap_thread (GTask *task,
+               gpointer source_object,
+               gpointer task_data,
+               GCancellable *cancellable)
+{
+       HexBufferMmap *self = HEX_BUFFER_MMAP (source_object);
+       gboolean success;
+
+       success = hex_buffer_mmap_read (HEX_BUFFER(self));
+       if (success)
+               g_task_return_boolean (task, TRUE);
+       else
+               g_task_return_error (task, self->error);
+}
+
+
+static void
+hex_buffer_mmap_read_async (HexBuffer *buf,
+               GCancellable *cancellable,
+               GAsyncReadyCallback callback,
+               gpointer user_data)
+{
+       HexBufferMmap *self = HEX_BUFFER_MMAP (buf);
+       GTask *task;
+
+       task = g_task_new (self, cancellable, callback, user_data);
+       g_task_run_in_thread (task, hex_buffer_mmap_thread);
+       g_object_unref (task);  /* _run_in_thread takes a ref */
+}
+
+
+
+
+
+
+
+
+
 static gboolean hex_buffer_mmap_set_data (HexBuffer *buf,
                size_t offset,
                size_t len,
@@ -594,7 +645,7 @@ static gboolean hex_buffer_mmap_write_to_file (HexBuffer *buf,
 
        hex_buffer_mmap_raw (self, &raw, 0, self->payload);
 
-       retval = g_file_replace_contents (self->file,
+       retval = g_file_replace_contents (file,
                /* const char* contents, */                     raw,    
                /* gsize length, */                                     self->payload,
                /* const char* etag, */                         NULL,
@@ -634,6 +685,8 @@ hex_buffer_mmap_iface_init (HexBufferInterface *iface)
        iface->set_data = hex_buffer_mmap_set_data;
        iface->set_file = hex_buffer_mmap_set_file;
        iface->read = hex_buffer_mmap_read;
+       iface->read_async = hex_buffer_mmap_read_async;
+       iface->read_finish = hex_buffer_mmap_read_finish;
        iface->write_to_file = hex_buffer_mmap_write_to_file;
        iface->get_payload_size = hex_buffer_mmap_get_payload_size;
 }
diff --git a/src/hex-document.c b/src/hex-document.c
index e5a5e1f..d81b80c 100644
--- a/src/hex-document.c
+++ b/src/hex-document.c
@@ -71,6 +71,7 @@ enum {
        UNDO_STACK_FORGET,
        FILE_NAME_CHANGED,
        FILE_SAVED,
+       FILE_LOADED,
        LAST_SIGNAL
 };
 
@@ -283,6 +284,15 @@ hex_document_class_init (HexDocumentClass *klass)
                                NULL, NULL, NULL,
                                G_TYPE_NONE,
                                0);
+
+       hex_signals[FILE_LOADED] =
+               g_signal_new_class_handler ("file-loaded",
+                               G_OBJECT_CLASS_TYPE (gobject_class),
+                               G_SIGNAL_RUN_FIRST,
+                               NULL,
+                               NULL, NULL, NULL,
+                               G_TYPE_NONE,
+                               0);
 }
 
 static void
@@ -325,11 +335,7 @@ hex_document_set_file (HexDocument *doc, GFile *file)
        if (had_prev_file)
                g_signal_emit (G_OBJECT(doc), hex_signals[FILE_NAME_CHANGED], 0);
 
-       if (! hex_document_read (doc))
-       {
-               g_debug ("%s: Unable to load/read file", __func__);
-               return FALSE;
-       }
+       hex_document_read (doc);
 
        return TRUE;
 }
@@ -458,17 +464,25 @@ hex_document_delete_data(HexDocument *doc, guint offset, guint len, gboolean und
        hex_document_set_data (doc, offset, 0, len, NULL, undoable);
 }
 
-gboolean
-hex_document_read (HexDocument *doc)
-{
+void
+document_ready_cb (GObject *source_object,
+               GAsyncResult *res,
+               gpointer user_data)
+{
+       gboolean success;
+       GError *local_error = NULL;
+       HexBuffer *buf = HEX_BUFFER(source_object);
+       HexDocument *doc = HEX_DOCUMENT(user_data);
        static HexChangeData change_data;
        size_t payload;
 
-       g_return_val_if_fail (G_IS_FILE (doc->file), FALSE);
+       success = hex_buffer_read_finish (buf, res, &local_error);
+       g_debug ("%s: DONE -- result: %d", __func__, success);
 
-       /* Read the actual file on disk into the buffer */
-       if (!hex_buffer_read (doc->buffer))
-               return FALSE;
+       if (local_error)
+               g_warning (local_error->message);
+
+       /* Initialize data for new doc */
 
        undo_stack_free(doc);
 
@@ -476,10 +490,22 @@ hex_document_read (HexDocument *doc)
 
        change_data.start = 0;
        change_data.end = payload - 1;
+
        doc->changed = FALSE;
        hex_document_changed (doc, &change_data, FALSE);
+       g_signal_emit (G_OBJECT(doc), hex_signals[FILE_LOADED], 0);
+}
 
-       return TRUE;
+void
+hex_document_read (HexDocument *doc)
+{
+       static HexChangeData change_data;
+       size_t payload;
+
+       g_return_if_fail (G_IS_FILE (doc->file));
+
+       /* Read the actual file on disk into the buffer */
+       hex_buffer_read_async (doc->buffer, NULL, document_ready_cb, doc);
 }
 
 gboolean
diff --git a/src/hex-document.h b/src/hex-document.h
index bedccc0..f9337af 100644
--- a/src/hex-document.h
+++ b/src/hex-document.h
@@ -69,7 +69,7 @@ void        hex_document_set_data(HexDocument *doc, size_t offset, size_t len, s
 void        hex_document_set_byte(HexDocument *doc, char val, size_t offset, gboolean insert, gboolean 
undoable);
 void        hex_document_set_nibble(HexDocument *doc, char val, size_t offset, gboolean lower_nibble, 
gboolean insert, gboolean undoable);
 void        hex_document_delete_data(HexDocument *doc, guint offset, guint len, gboolean undoable);
-gboolean   hex_document_read (HexDocument *doc);
+void           hex_document_read (HexDocument *doc);
 gboolean   hex_document_write(HexDocument *doc);
 
 gboolean   hex_document_write_to_file (HexDocument *doc, GFile *file);


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