[gnome-builder] color-picker: make recolorizing phases async
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] color-picker: make recolorizing phases async
- Date: Wed, 19 Jul 2017 11:19:34 +0000 (UTC)
commit 383de42a084771d2dba5d5633a73d6af544f795f
Author: Christian Hergert <chergert redhat com>
Date: Fri Jul 14 19:20:49 2017 -0700
color-picker: make recolorizing phases async
These need to be run from the main loop so that we can be
absolutely sure we are not in an event handler where the iter
must be preserved.
.../gb-color-picker-document-monitor.c | 286 +++++++++++++++-----
.../gb-color-picker-document-monitor.h | 14 +-
2 files changed, 232 insertions(+), 68 deletions(-)
---
diff --git a/plugins/color-picker/gb-color-picker-document-monitor.c
b/plugins/color-picker/gb-color-picker-document-monitor.c
index 0b0e02b..a29b793 100644
--- a/plugins/color-picker/gb-color-picker-document-monitor.c
+++ b/plugins/color-picker/gb-color-picker-document-monitor.c
@@ -39,6 +39,20 @@ struct _GbColorPickerDocumentMonitor
guint is_in_user_action : 1;
};
+typedef struct
+{
+ guint line;
+ guint line_offset;
+} Position;
+
+typedef struct
+{
+ GbColorPickerDocumentMonitor *self;
+ GtkTextMark *begin;
+ GtkTextMark *end;
+ guint uncolorize : 1;
+} QueuedColorize;
+
G_DEFINE_TYPE (GbColorPickerDocumentMonitor, gb_color_picker_document_monitor, G_TYPE_OBJECT)
enum {
@@ -47,14 +61,29 @@ enum {
N_PROPS
};
-static GParamSpec *properties [N_PROPS];
-
enum {
COLOR_FOUND,
- LAST_SIGNAL
+ N_SIGNALS
};
-static guint signals [LAST_SIGNAL];
+static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
+
+static void
+position_save (Position *pos,
+ const GtkTextIter *iter)
+{
+ pos->line = gtk_text_iter_get_line (iter);
+ pos->line_offset = gtk_text_iter_get_line_offset (iter);
+}
+
+static void
+position_restore (Position *pos,
+ GtkTextBuffer *buffer,
+ GtkTextIter *iter)
+{
+ gtk_text_buffer_get_iter_at_line_offset (buffer, iter, pos->line, pos->line_offset);
+}
static void
block_signals (GbColorPickerDocumentMonitor *self)
@@ -106,42 +135,38 @@ gb_color_picker_document_monitor_set_color_tag_at_cursor (GbColorPickerDocumentM
}
static void
-remove_color_tag_foreach_cb (GtkTextTag *tag,
- GPtrArray *taglist)
+collect_tag_names (GtkTextTag *tag,
+ GPtrArray *taglist)
{
- const gchar *name;
+ g_autofree gchar *name = NULL;
g_assert (GTK_IS_TEXT_TAG (tag));
g_assert (taglist != NULL);
g_object_get (G_OBJECT (tag), "name", &name, NULL);
if (!ide_str_empty0 (name) && g_str_has_prefix (name, COLOR_TAG_PREFIX))
- g_ptr_array_add (taglist, tag);
+ g_ptr_array_add (taglist, g_steal_pointer (&name));
}
-void
+static void
gb_color_picker_document_monitor_uncolorize (GbColorPickerDocumentMonitor *self,
GtkTextIter *begin,
GtkTextIter *end)
{
- g_autoptr (GPtrArray) taglist = NULL;
- g_autofree gchar *name = NULL;
- g_autoptr (GSList) tags = NULL;
GtkTextTagTable *tag_table;
GtkTextIter real_begin;
GtkTextIter real_end;
- GtkTextTag *color_tag;
- GtkTextTag *tag;
- GSList *l;
g_return_if_fail (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
g_return_if_fail (self->buffer != NULL);
tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (self->buffer));
+
if (begin == NULL && end == NULL)
{
- taglist = g_ptr_array_new ();
- gtk_text_tag_table_foreach (tag_table, (GtkTextTagTableForeach)remove_color_tag_foreach_cb, taglist);
+ g_autoptr(GPtrArray) taglist = g_ptr_array_new_with_free_func (g_free);
+
+ gtk_text_tag_table_foreach (tag_table, (GtkTextTagTableForeach)collect_tag_names, taglist);
for (guint n = 0; n < taglist->len; ++n)
gtk_text_tag_table_remove (tag_table, g_ptr_array_index (taglist, n));
@@ -160,13 +185,19 @@ gb_color_picker_document_monitor_uncolorize (GbColorPickerDocumentMonitor *self,
while (TRUE)
{
- color_tag = NULL;
+ g_autoptr(GSList) tags = NULL;
+ GtkTextTag *color_tag = NULL;
+
tags = gtk_text_iter_get_toggled_tags (&real_begin, TRUE);
- for (l = tags; l != NULL; l = g_slist_next (l))
+
+ for (const GSList *l = tags; l != NULL; l = l->next)
{
- tag = l->data;
+ g_autofree gchar *name = NULL;
+ GtkTextTag *tag = l->data;
+
g_object_get (G_OBJECT (tag), "name", &name, NULL);
- if (!ide_str_empty0 (name) && g_str_has_prefix (name, COLOR_TAG_PREFIX))
+
+ if (name != NULL && g_str_has_prefix (name, COLOR_TAG_PREFIX))
{
color_tag = tag;
break;
@@ -187,7 +218,7 @@ gb_color_picker_document_monitor_uncolorize (GbColorPickerDocumentMonitor *self,
}
}
-void
+static void
gb_color_picker_document_monitor_colorize (GbColorPickerDocumentMonitor *self,
GtkTextIter *begin,
GtkTextIter *end)
@@ -195,7 +226,6 @@ gb_color_picker_document_monitor_colorize (GbColorPickerDocumentMonitor *self,
g_autofree gchar *text = NULL;
g_autoptr(GPtrArray) items = NULL;
GstyleColorItem *item;
- GstyleColor *color;
GtkTextTag *tag;
GtkTextIter real_begin;
GtkTextIter real_end;
@@ -227,6 +257,8 @@ gb_color_picker_document_monitor_colorize (GbColorPickerDocumentMonitor *self,
items = gstyle_color_parse (text);
for (guint n = 0; n < items->len; ++n)
{
+ GstyleColor *color;
+
item = g_ptr_array_index (items, n);
pos = offset + gstyle_color_item_get_start (item);
gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (self->buffer), &tag_begin, pos);
@@ -247,8 +279,8 @@ text_inserted_cb (GbColorPickerDocumentMonitor *self,
gint len,
GtkTextBuffer *buffer)
{
+ g_autoptr(GstyleColor) color = NULL;
GtkTextTag *tag;
- GstyleColor *color;
GtkTextIter begin, end;
g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
@@ -256,13 +288,14 @@ text_inserted_cb (GbColorPickerDocumentMonitor *self,
g_assert (cursor != NULL);
tag = gb_color_picker_helper_get_tag_at_iter (cursor, &color, &begin, &end);
+
if (tag != NULL )
{
gtk_text_iter_set_line_offset (&begin, 0);
if (!gtk_text_iter_ends_line (&end))
gtk_text_iter_forward_to_line_end (&end);
- gb_color_picker_document_monitor_uncolorize (self, &begin, &end);
+ gb_color_picker_document_monitor_queue_uncolorize (self, &begin, &end);
}
}
@@ -289,7 +322,7 @@ text_inserted_after_cb (GbColorPickerDocumentMonitor *self,
if (!gtk_text_iter_ends_line (&end))
gtk_text_iter_forward_to_line_end (&end);
- gb_color_picker_document_monitor_colorize (self, &begin, &end);
+ gb_color_picker_document_monitor_queue_colorize (self, &begin, &end);
}
static void
@@ -301,20 +334,26 @@ remove_tag_cb (GbColorPickerDocumentMonitor *self,
{
GtkTextTagTable *tag_table;
g_autofree gchar *name = NULL;
+ Position spos;
+ Position epos;
g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
g_assert (GTK_IS_TEXT_BUFFER (buffer));
g_assert (GTK_IS_TEXT_TAG (tag));
+ position_save (&spos, start);
+ position_save (&epos, end);
+
tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (self->buffer));
g_object_get (G_OBJECT (tag), "name", &name, NULL);
if (!ide_str_empty0 (name) &&
g_str_has_prefix (name, COLOR_TAG_PREFIX) &&
gtk_text_tag_table_lookup (tag_table, name))
- {
- gtk_text_tag_table_remove (tag_table, tag);
- }
+ gtk_text_tag_table_remove (tag_table, tag);
+
+ position_restore (&spos, buffer, start);
+ position_restore (&epos, buffer, end);
}
static void
@@ -325,10 +364,15 @@ text_deleted_cb (GbColorPickerDocumentMonitor *self,
{
GtkTextIter recolor_begin;
GtkTextIter recolor_end;
+ Position spos;
+ Position epos;
g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
g_assert (GTK_IS_TEXT_BUFFER (buffer));
+ position_save (&spos, begin);
+ position_save (&epos, end);
+
self->remove_tag_handler_id = g_signal_connect_object (GTK_TEXT_BUFFER (self->buffer),
"remove-tag",
G_CALLBACK (remove_tag_cb),
@@ -345,6 +389,9 @@ text_deleted_cb (GbColorPickerDocumentMonitor *self,
/* FIXME: we only need to remove color tag */
gtk_text_buffer_remove_all_tags (buffer, &recolor_begin, &recolor_end);
g_signal_handler_disconnect (GTK_TEXT_BUFFER (self->buffer), self->remove_tag_handler_id);
+
+ position_restore (&spos, buffer, begin);
+ position_restore (&epos, buffer, end);
}
static void
@@ -368,18 +415,17 @@ text_deleted_after_cb (GbColorPickerDocumentMonitor *self,
if (!gtk_text_iter_ends_line (&recolor_end))
gtk_text_iter_forward_to_line_end (&recolor_end);
- gb_color_picker_document_monitor_colorize (self, &recolor_begin, &recolor_end);
+ gb_color_picker_document_monitor_queue_colorize (self, &recolor_begin, &recolor_end);
}
static void
cursor_moved_cb (GbColorPickerDocumentMonitor *self,
- GParamSpec *prop,
+ const GtkTextIter *location,
GtkTextBuffer *buffer)
{
+ g_autoptr(GstyleColor) current_color = NULL;
GtkTextTag *tag;
- GtkTextMark *insert;
GtkTextIter cursor;
- GstyleColor *current_color;
GtkTextIter begin, end;
g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
@@ -391,8 +437,7 @@ cursor_moved_cb (GbColorPickerDocumentMonitor *self,
self->is_in_user_action = FALSE;
}
- insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER(self->buffer));
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER(self->buffer), &cursor, insert);
+ cursor = *location;
/* TODO: fast path: check if we are in the last already detected color tag */
tag = gb_color_picker_helper_get_tag_at_iter (&cursor, ¤t_color, &begin, &end);
@@ -429,11 +474,11 @@ start_monitor (GbColorPickerDocumentMonitor *self)
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- self->cursor_notify_handler_id = g_signal_connect_object (GTK_TEXT_BUFFER (self->buffer),
- "notify::cursor-position",
+ self->cursor_notify_handler_id = g_signal_connect_object (self->buffer,
+ "cursor-moved",
G_CALLBACK (cursor_moved_cb),
self,
- G_CONNECT_SWAPPED);
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
}
static void
@@ -453,11 +498,10 @@ gb_color_picker_document_monitor_set_buffer (GbColorPickerDocumentMonitor *self,
IdeBuffer *buffer)
{
g_return_if_fail (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
- g_return_if_fail (IDE_IS_BUFFER (buffer));
+ g_return_if_fail (!buffer || IDE_IS_BUFFER (buffer));
- if (self->buffer != buffer)
+ if (ide_set_weak_pointer (&self->buffer, buffer))
{
- self->buffer = buffer;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUFFER]);
if (buffer != NULL)
@@ -486,6 +530,10 @@ gb_color_picker_document_monitor_new (IdeBuffer *buffer)
static void
gb_color_picker_document_monitor_finalize (GObject *object)
{
+ GbColorPickerDocumentMonitor *self = (GbColorPickerDocumentMonitor *)object;
+
+ ide_clear_weak_pointer (&self->buffer);
+
G_OBJECT_CLASS (gb_color_picker_document_monitor_parent_class)->finalize (object);
}
@@ -529,16 +577,6 @@ gb_color_picker_document_monitor_set_property (GObject *object,
}
static void
-color_found_handler_cb (GbColorPickerDocumentMonitor *self,
- GstyleColor *color)
-{
- g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
- g_assert (GSTYLE_IS_COLOR (color));
-
- g_object_unref (color);
-}
-
-static void
gb_color_picker_document_monitor_class_init (GbColorPickerDocumentMonitorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -547,7 +585,7 @@ gb_color_picker_document_monitor_class_init (GbColorPickerDocumentMonitorClass *
object_class->get_property = gb_color_picker_document_monitor_get_property;
object_class->set_property = gb_color_picker_document_monitor_set_property;
- properties[PROP_BUFFER] =
+ properties [PROP_BUFFER] =
g_param_spec_object ("buffer",
"Buffer",
"The GtkTextBuffer for the monitor.",
@@ -556,18 +594,144 @@ gb_color_picker_document_monitor_class_init (GbColorPickerDocumentMonitorClass *
g_object_class_install_properties (object_class, N_PROPS, properties);
-/* do not work, try with class offset ? */
- signals [COLOR_FOUND] = g_signal_new_class_handler ("color-found",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_CLEANUP,
- G_CALLBACK (color_found_handler_cb),
- NULL, NULL, NULL,
- G_TYPE_NONE,
- 1,
- GSTYLE_TYPE_COLOR);
+ signals [COLOR_FOUND] =
+ g_signal_new_class_handler ("color-found",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ NULL, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GSTYLE_TYPE_COLOR);
}
static void
gb_color_picker_document_monitor_init (GbColorPickerDocumentMonitor *self)
{
}
+
+static void
+queued_colorize_free (gpointer data)
+{
+ QueuedColorize *qc = data;
+
+ g_clear_object (&qc->self);
+ g_clear_object (&qc->begin);
+ g_clear_object (&qc->end);
+ g_slice_free (QueuedColorize, qc);
+}
+
+static gboolean
+gb_color_picker_document_monitor_queue_oper_cb (gpointer data)
+{
+ QueuedColorize *qc = data;
+
+ g_assert (qc != NULL);
+ g_assert (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (qc->self));
+ g_assert (GTK_IS_TEXT_MARK (qc->begin));
+ g_assert (GTK_IS_TEXT_MARK (qc->end));
+
+ block_signals (qc->self);
+
+ if (qc->self->buffer != NULL)
+ {
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (qc->self->buffer);
+ GtkTextIter begin;
+ GtkTextIter end;
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &begin, qc->begin);
+ gtk_text_buffer_get_iter_at_mark (buffer, &end, qc->end);
+
+ if (qc->uncolorize)
+ gb_color_picker_document_monitor_uncolorize (qc->self, &begin, &end);
+ else
+ gb_color_picker_document_monitor_colorize (qc->self, &begin, &end);
+
+ gtk_text_buffer_delete_mark (buffer, qc->begin);
+ gtk_text_buffer_delete_mark (buffer, qc->end);
+ }
+
+ unblock_signals (qc->self);
+
+ return G_SOURCE_REMOVE;
+}
+
+/**
+ * gb_color_picker_document_monitor_queue_colorize:
+ * @self: a #GbColorPickerDocumentMonitor
+ *
+ * This queues a region to be recolorized but does so after returning
+ * to the main loop. This can be useful for situations where you do not
+ * know if you are in a path that must retain a valid GtkTextIter.
+ *
+ * Since: 3.26
+ */
+static void
+gb_color_picker_document_monitor_queue_oper (GbColorPickerDocumentMonitor *self,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ gboolean uncolorize)
+{
+ QueuedColorize queued = { 0 };
+ GtkTextBuffer *buffer;
+ GtkTextIter real_begin;
+ GtkTextIter real_end;
+
+ g_return_if_fail (GB_IS_COLOR_PICKER_DOCUMENT_MONITOR (self));
+ g_return_if_fail (self->buffer != NULL);
+ g_return_if_fail (begin == NULL || GTK_TEXT_BUFFER (self->buffer) == gtk_text_iter_get_buffer (begin));
+ g_return_if_fail (end == NULL || GTK_TEXT_BUFFER (self->buffer) == gtk_text_iter_get_buffer (end));
+
+ buffer = GTK_TEXT_BUFFER (self->buffer);
+
+ gtk_text_buffer_get_bounds (buffer, &real_begin, &real_end);
+
+ if (begin)
+ real_begin = *begin;
+
+ if (end)
+ real_end = *end;
+
+ queued.self = g_object_ref (self);
+ queued.begin = g_object_ref (gtk_text_buffer_create_mark (buffer, NULL, &real_begin, TRUE));
+ queued.end = g_object_ref (gtk_text_buffer_create_mark (buffer, NULL, &real_end, FALSE));
+ queued.uncolorize = !!uncolorize;
+
+ gdk_threads_add_idle_full (G_PRIORITY_LOW,
+ gb_color_picker_document_monitor_queue_oper_cb,
+ g_slice_dup (QueuedColorize, &queued),
+ queued_colorize_free);
+}
+
+/**
+ * gb_color_picker_document_monitor_queue_colorize:
+ * @self: a #GbColorPickerDocumentMonitor
+ *
+ * This queues a region to be recolorized but does so after returning
+ * to the main loop. This can be useful for situations where you do not
+ * know if you are in a path that must retain a valid GtkTextIter.
+ *
+ * Since: 3.26
+ */
+void
+gb_color_picker_document_monitor_queue_colorize (GbColorPickerDocumentMonitor *self,
+ const GtkTextIter *begin,
+ const GtkTextIter *end)
+{
+ gb_color_picker_document_monitor_queue_oper (self, begin, end, FALSE);
+}
+
+/**
+ * gb_color_picker_document_monitor_queue_uncolorize:
+ * @self: a #GbColorPickerDocumentMonitor
+ *
+ * This queues a region to be uncolorized but does so after returning
+ * to the main loop. This can be useful for situations where you do not
+ * know if you are in a path that must retain a valid GtkTextIter.
+ *
+ * Since: 3.26
+ */
+void
+gb_color_picker_document_monitor_queue_uncolorize (GbColorPickerDocumentMonitor *self,
+ const GtkTextIter *begin,
+ const GtkTextIter *end)
+{
+ gb_color_picker_document_monitor_queue_oper (self, begin, end, TRUE);
+}
diff --git a/plugins/color-picker/gb-color-picker-document-monitor.h
b/plugins/color-picker/gb-color-picker-document-monitor.h
index 75c0fc4..6e221a2 100644
--- a/plugins/color-picker/gb-color-picker-document-monitor.h
+++ b/plugins/color-picker/gb-color-picker-document-monitor.h
@@ -30,19 +30,19 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbColorPickerDocumentMonitor, gb_color_picker_document_monitor, GB,
COLOR_PICKER_DOCUMENT_MONITOR, GObject)
-GbColorPickerDocumentMonitor *gb_color_picker_document_monitor_new (IdeBuffer
*buffer);
-void gb_color_picker_document_monitor_colorize
(GbColorPickerDocumentMonitor *self,
- GtkTextIter
*begin,
- GtkTextIter
*end);
+GbColorPickerDocumentMonitor *gb_color_picker_document_monitor_new (IdeBuffer
*buffer);
IdeBuffer *gb_color_picker_document_monitor_get_buffer
(GbColorPickerDocumentMonitor *self);
void gb_color_picker_document_monitor_set_buffer
(GbColorPickerDocumentMonitor *self,
IdeBuffer
*buffer);
void gb_color_picker_document_monitor_set_color_tag_at_cursor
(GbColorPickerDocumentMonitor *self,
GstyleColor
*color);
-void gb_color_picker_document_monitor_uncolorize
(GbColorPickerDocumentMonitor *self,
- GtkTextIter
*begin,
- GtkTextIter
*end);
+void gb_color_picker_document_monitor_queue_colorize
(GbColorPickerDocumentMonitor *self,
+ const GtkTextIter
*begin,
+ const GtkTextIter
*end);
+void gb_color_picker_document_monitor_queue_uncolorize
(GbColorPickerDocumentMonitor *self,
+ const GtkTextIter
*begin,
+ const GtkTextIter
*end);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]