[gtk/async-highlight] gtk-demo: Do markup parsing incrementally too



commit 8bcc20beb665750102764341f4aea4d0c5f116fa
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Aug 13 14:19:13 2020 -0400

    gtk-demo: Do markup parsing incrementally too
    
    Pango has a markup parser api, might as well
    use it to keep things responsive.

 demos/gtk-demo/fontify.c | 97 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 73 insertions(+), 24 deletions(-)
---
diff --git a/demos/gtk-demo/fontify.c b/demos/gtk-demo/fontify.c
index ce8efe51a7..8f8231442b 100644
--- a/demos/gtk-demo/fontify.c
+++ b/demos/gtk-demo/fontify.c
@@ -165,6 +165,10 @@ insert_tags_for_attributes (GtkTextBuffer     *buffer,
 
 typedef struct
 {
+  GMarkupParseContext *parser;
+  char *markup;
+  gsize pos;
+  gsize len;
   GtkTextBuffer *buffer;
   GtkTextIter iter;
   GtkTextMark *mark;
@@ -176,9 +180,11 @@ typedef struct
 static void
 free_markup_data (MarkupData *mdata)
 {
+  g_free (mdata->markup);
+  g_clear_pointer (&mdata->parser, g_markup_parse_context_free);
   gtk_text_buffer_delete_mark (mdata->buffer, mdata->mark);
-  pango_attr_iterator_destroy (mdata->attr);
-  pango_attr_list_unref (mdata->attributes);
+  g_clear_pointer (&mdata->attr, pango_attr_iterator_destroy);
+  g_clear_pointer (&mdata->attributes, pango_attr_list_unref);
   g_free (mdata->text);
   g_object_unref (mdata->buffer);
   g_free (mdata);
@@ -223,51 +229,94 @@ insert_markup_idle (gpointer data)
   return G_SOURCE_REMOVE;
 }
 
-static void
-insert_markup (GtkTextBuffer *buffer,
-               GtkTextIter   *iter,
-               const char    *markup,
-               int            len)
+static gboolean
+parse_markup_idle (gpointer data)
 {
-  char *text;
-  PangoAttrList *attributes;
+  MarkupData *mdata = data;
+  gint64 begin;
   GError *error = NULL;
-  MarkupData *data;
 
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  begin = g_get_monotonic_time ();
 
-  if (!pango_parse_markup (markup, len, 0, &attributes, &text, NULL, &error))
+  do {
+    if (g_get_monotonic_time () - begin > G_TIME_SPAN_MILLISECOND)
+      {
+        g_idle_add (parse_markup_idle, data);
+        return G_SOURCE_REMOVE;
+      }
+
+    if (!g_markup_parse_context_parse (mdata->parser,
+                                       mdata->markup + mdata->pos,
+                                       MIN (4096, mdata->len - mdata->pos),
+                                       &error))
+      {
+        g_warning ("Invalid markup string: %s", error->message);
+        g_error_free (error);
+        free_markup_data (mdata);
+        return G_SOURCE_REMOVE;
+      }
+
+    mdata->pos += 4096;
+  } while (mdata->pos < mdata->len);
+
+  if (!pango_markup_parser_finish (mdata->parser,
+                                   &mdata->attributes,
+                                   &mdata->text,
+                                   NULL,
+                                   &error))
     {
       g_warning ("Invalid markup string: %s", error->message);
       g_error_free (error);
-      return;
+      free_markup_data (mdata);
+      return G_SOURCE_REMOVE;
     }
 
-  if (!attributes)
+  if (!mdata->attributes)
     {
-      gtk_text_buffer_insert (buffer, iter, text, -1);
-      g_free (text);
-      return;
+      gtk_text_buffer_insert (mdata->buffer, &mdata->iter, mdata->text, -1);
+      free_markup_data (mdata);
+      return G_SOURCE_REMOVE;
     }
 
-  data = g_new (MarkupData, 1);
+  mdata->attr = pango_attr_list_get_iterator (mdata->attributes);
+  insert_markup_idle (data);
+
+  return G_SOURCE_REMOVE;
+}
+
+/* Takes a ref on @buffer while it is operating,
+ * and consumes @markup.
+ */
+static void
+insert_markup (GtkTextBuffer *buffer,
+               GtkTextIter   *iter,
+               char          *markup,
+               int            len)
+{
+  MarkupData *data;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  data = g_new0 (MarkupData, 1);
 
   data->buffer = g_object_ref (buffer);
   data->iter = *iter;
-  data->attributes = attributes;
-  data->text = text;
+  data->markup = markup;
+  data->len = len;
+
+  data->parser = pango_markup_parser_new (0);
+  data->pos = 0;
 
   /* create mark with right gravity */
   data->mark = gtk_text_buffer_create_mark (buffer, NULL, iter, FALSE);
-  data->attr = pango_attr_list_get_iterator (attributes);
 
-  insert_markup_idle (data);
+  parse_markup_idle (data);
 }
 
 static void
-fontify_finish (GObject *source,
+fontify_finish (GObject      *source,
                 GAsyncResult *result,
-                gpointer data)
+                gpointer      data)
 {
   GSubprocess *subprocess = G_SUBPROCESS (source);
   GtkTextBuffer *buffer = data;


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