[gtk/async-highlight: 14/15] gtk-demo: Insert markup incrementally
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/async-highlight: 14/15] gtk-demo: Insert markup incrementally
- Date: Thu, 13 Aug 2020 17:13:19 +0000 (UTC)
commit aacb06dbee85dfe11d0f55573ab7bc045141d626
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Aug 13 12:59:52 2020 -0400
gtk-demo: Insert markup incrementally
The slowest step of highlighting our buffers is
inserting the markup into the buffer. Do that
incrementally, to avoid blocking the UI for
extended periods.
demos/gtk-demo/main.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 250 insertions(+), 1 deletion(-)
---
diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c
index 5755070938..d22a673e94 100644
--- a/demos/gtk-demo/main.c
+++ b/demos/gtk-demo/main.c
@@ -237,6 +237,255 @@ activate_run (GSimpleAction *action,
gtk_demo_run (demo, window);
}
+static void
+insert_tags_for_attributes (GtkTextBuffer *buffer,
+ PangoAttrIterator *iter,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ GtkTextTagTable *table;
+ PangoAttribute *attr;
+ GtkTextTag *tag;
+ char name[256];
+
+ table = gtk_text_buffer_get_tag_table (buffer);
+
+#define STRING_ATTR(pango_attr_name, attr_name) \
+ attr = pango_attr_iterator_get (iter, pango_attr_name); \
+ if (attr) \
+ { \
+ const char *string = ((PangoAttrString*)attr)->value; \
+ g_snprintf (name, 256, #attr_name "=%s", string); \
+ tag = gtk_text_tag_table_lookup (table, name); \
+ if (!tag) \
+ { \
+ tag = gtk_text_tag_new (name); \
+ g_object_set (tag, #attr_name, string, NULL); \
+ gtk_text_tag_table_add (table, tag); \
+ g_object_unref (tag); \
+ } \
+ gtk_text_buffer_apply_tag (buffer, tag, start, end); \
+ }
+
+#define INT_ATTR(pango_attr_name, attr_name) \
+ attr = pango_attr_iterator_get (iter, pango_attr_name); \
+ if (attr) \
+ { \
+ int value = ((PangoAttrInt*)attr)->value; \
+ g_snprintf (name, 256, #attr_name "=%d", value); \
+ tag = gtk_text_tag_table_lookup (table, name); \
+ if (!tag) \
+ { \
+ tag = gtk_text_tag_new (name); \
+ g_object_set (tag, #attr_name, value, NULL); \
+ gtk_text_tag_table_add (table, tag); \
+ g_object_unref (tag); \
+ } \
+ gtk_text_buffer_apply_tag (buffer, tag, start, end); \
+ }
+
+#define FLOAT_ATTR(pango_attr_name, attr_name) \
+ attr = pango_attr_iterator_get (iter, pango_attr_name); \
+ if (attr) \
+ { \
+ float value = ((PangoAttrFloat*)attr)->value; \
+ g_snprintf (name, 256, #attr_name "=%g", value); \
+ tag = gtk_text_tag_table_lookup (table, name); \
+ if (!tag) \
+ { \
+ tag = gtk_text_tag_new (name); \
+ g_object_set (tag, #attr_name, value, NULL); \
+ gtk_text_tag_table_add (table, tag); \
+ g_object_unref (tag); \
+ } \
+ gtk_text_buffer_apply_tag (buffer, tag, start, end); \
+ }
+
+#define RGBA_ATTR(pango_attr_name, attr_name) \
+ attr = pango_attr_iterator_get (iter, pango_attr_name); \
+ if (attr) \
+ { \
+ PangoColor *color; \
+ GdkRGBA rgba; \
+ color = &((PangoAttrColor*)attr)->color; \
+ rgba.red = color->red / 65535.; \
+ rgba.green = color->green / 65535.; \
+ rgba.blue = color->blue / 65535.; \
+ rgba.alpha = 1.; \
+ char *str = gdk_rgba_to_string (&rgba); \
+ g_snprintf (name, 256, #attr_name "=%s", str); \
+ g_free (str); \
+ tag = gtk_text_tag_table_lookup (table, name); \
+ if (!tag) \
+ { \
+ tag = gtk_text_tag_new (name); \
+ g_object_set (tag, #attr_name, &rgba, NULL); \
+ gtk_text_tag_table_add (table, tag); \
+ g_object_unref (tag); \
+ } \
+ gtk_text_buffer_apply_tag (buffer, tag, start, end); \
+ }
+
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE);
+ if (attr)
+ {
+ const char *language = pango_language_to_string (((PangoAttrLanguage*)attr)->value);
+ g_snprintf (name, 256, "language=%s", language);
+ tag = gtk_text_tag_table_lookup (table, name);
+ if (!tag)
+ {
+ tag = gtk_text_tag_new (name);
+ g_object_set (tag, "language", language, NULL);
+ gtk_text_tag_table_add (table, tag);
+ g_object_unref (tag);
+ }
+ gtk_text_buffer_apply_tag (buffer, tag, start, end);
+ }
+
+ STRING_ATTR (PANGO_ATTR_FAMILY, family)
+ INT_ATTR (PANGO_ATTR_STYLE, style)
+ INT_ATTR (PANGO_ATTR_WEIGHT, weight)
+ INT_ATTR (PANGO_ATTR_VARIANT, variant)
+ INT_ATTR (PANGO_ATTR_STRETCH, stretch)
+ INT_ATTR (PANGO_ATTR_SIZE, size)
+
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_DESC);
+ if (attr)
+ {
+ PangoFontDescription *desc = ((PangoAttrFontDesc*)attr)->desc;
+ char *str = pango_font_description_to_string (desc);
+ g_snprintf (name, 256, "font-desc=%s", str);
+ g_free (str);
+ tag = gtk_text_tag_table_lookup (table, name);
+ if (!tag)
+ {
+ tag = gtk_text_tag_new (name);
+ g_object_set (tag, "font-desc", desc, NULL);
+ gtk_text_tag_table_add (table, tag);
+ g_object_unref (tag);
+ }
+ gtk_text_buffer_apply_tag (buffer, tag, start, end);
+ }
+
+ RGBA_ATTR (PANGO_ATTR_FOREGROUND, foreground_rgba)
+ RGBA_ATTR (PANGO_ATTR_BACKGROUND, background_rgba)
+ INT_ATTR (PANGO_ATTR_UNDERLINE, underline)
+ RGBA_ATTR (PANGO_ATTR_UNDERLINE_COLOR, underline_rgba)
+ INT_ATTR (PANGO_ATTR_OVERLINE, overline)
+ RGBA_ATTR (PANGO_ATTR_OVERLINE_COLOR, overline_rgba)
+ INT_ATTR (PANGO_ATTR_STRIKETHROUGH, strikethrough)
+ RGBA_ATTR (PANGO_ATTR_STRIKETHROUGH_COLOR, strikethrough_rgba)
+ INT_ATTR (PANGO_ATTR_RISE, rise)
+ FLOAT_ATTR (PANGO_ATTR_SCALE, scale)
+ INT_ATTR (PANGO_ATTR_FALLBACK, fallback)
+ INT_ATTR (PANGO_ATTR_LETTER_SPACING, letter_spacing)
+ STRING_ATTR (PANGO_ATTR_FONT_FEATURES, font_features)
+ INT_ATTR (PANGO_ATTR_ALLOW_BREAKS, allow_breaks)
+ INT_ATTR (PANGO_ATTR_SHOW, show_spaces)
+ INT_ATTR (PANGO_ATTR_INSERT_HYPHENS, insert_hyphens)
+}
+
+typedef struct
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ GtkTextMark *mark;
+ PangoAttrList *attributes;
+ char *text;
+ PangoAttrIterator *attr;
+} MarkupData;
+
+static void
+free_markup_data (MarkupData *mdata)
+{
+ gtk_text_buffer_delete_mark (mdata->buffer, mdata->mark);
+ pango_attr_iterator_destroy (mdata->attr);
+ pango_attr_list_unref (mdata->attributes);
+ g_free (mdata->text);
+ g_object_unref (mdata->buffer);
+ g_free (mdata);
+}
+
+static gboolean
+insert_markup_idle (gpointer data)
+{
+ MarkupData *mdata = data;
+ gint64 begin;
+
+ begin = g_get_monotonic_time ();
+
+ do
+ {
+ int start, end;
+ int start_offset;
+ GtkTextIter start_iter;
+
+ if (g_get_monotonic_time () - begin > G_TIME_SPAN_MILLISECOND)
+ {
+ g_idle_add (insert_markup_idle, data);
+ return G_SOURCE_REMOVE;
+ }
+
+ pango_attr_iterator_range (mdata->attr, &start, &end);
+
+ if (end == G_MAXINT) /* last chunk */
+ end = start - 1; /* resulting in -1 to be passed to _insert */
+
+ start_offset = gtk_text_iter_get_offset (&mdata->iter);
+ gtk_text_buffer_insert (mdata->buffer, &mdata->iter, mdata->text + start, end - start);
+ gtk_text_buffer_get_iter_at_offset (mdata->buffer, &start_iter, start_offset);
+
+ insert_tags_for_attributes (mdata->buffer, mdata->attr, &start_iter, &mdata->iter);
+
+ gtk_text_buffer_get_iter_at_mark (mdata->buffer, &mdata->iter, mdata->mark);
+ }
+ while (pango_attr_iterator_next (mdata->attr));
+
+ free_markup_data (mdata);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+insert_markup (GtkTextBuffer *buffer,
+ GtkTextIter *iter,
+ const char *markup,
+ int len)
+{
+ char *text;
+ PangoAttrList *attributes;
+ GError *error = NULL;
+ MarkupData *data;
+
+ g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+ if (!pango_parse_markup (markup, len, 0, &attributes, &text, NULL, &error))
+ {
+ g_warning ("Invalid markup string: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (!attributes)
+ {
+ gtk_text_buffer_insert (buffer, iter, text, -1);
+ g_free (text);
+ return;
+ }
+
+ data = g_new (MarkupData, 1);
+
+ data->buffer = g_object_ref (buffer);
+ data->iter = *iter;
+ data->attributes = attributes;
+ data->text = text;
+
+ /* 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);
+}
+
static void
fontify_finish (GObject *source,
GAsyncResult *result,
@@ -292,7 +541,7 @@ fontify_finish (GObject *source,
for (p = markup + strlen ("<span "); *p != '>'; p++) *p = ' ';
gtk_text_buffer_get_start_iter (buffer, &start);
- gtk_text_buffer_insert_markup (buffer, &start, markup, len);
+ insert_markup (buffer, &start, markup, len);
}
g_object_unref (buffer);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]