[clutter] text: Make :use-markup set idempotent
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter] text: Make :use-markup set idempotent
- Date: Wed, 7 Sep 2011 12:01:10 +0000 (UTC)
commit 0bd1e47b22de3692c37abaa4582dfb9c802ee493
Author: Emmanuele Bassi <ebassi linux intel com>
Date: Tue Sep 6 12:45:41 2011 +0100
text: Make :use-markup set idempotent
Setting :use-markup and :text is currently not idempotent, and it
depends on the ordering, e.g.:
g_object_set (actor, "use-markup", TRUE, "text", value, NULL);
does not yield the same results as:
g_object_set (actor, "text", value, "use-markup", TRUE, NULL);
This is particularly jarring when using ClutterText from ClutterScript,
but in general GObject properties should not rely on the order when used
from g_object_set().
The fix is to store the contents of the ClutterText as a separate string
from the displayed text, and use the contents, instead of the displayed
text, when toggling the :use-markup property.
Let's also add a unit test for good measure, to try and catch
regressions.
https://bugzilla.gnome.org/show_bug.cgi?id=651940
clutter/clutter-text.c | 52 +++++++++++++++++----
tests/conform/test-clutter-text.c | 92 +++++++++++++++++++++++++++++++++++++
tests/conform/test-conform-main.c | 1 +
3 files changed, 135 insertions(+), 10 deletions(-)
---
diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c
index 7d65cb2..5423b77 100644
--- a/clutter/clutter-text.c
+++ b/clutter/clutter-text.c
@@ -112,6 +112,9 @@ struct _ClutterTextPrivate
{
PangoFontDescription *font_desc;
+ /* the text passed to set_text and set_markup */
+ gchar *contents;
+
/* the displayed text */
gchar *text;
@@ -1028,11 +1031,36 @@ clutter_text_set_positions (ClutterText *self,
}
static inline void
+clutter_text_set_contents (ClutterText *self,
+ const gchar *str)
+{
+ ClutterTextPrivate *priv = self->priv;
+
+ g_free (priv->contents);
+
+ if (str == NULL || *str == '\0')
+ priv->contents = g_strdup ("");
+ else
+ priv->contents = g_strdup (str);
+}
+
+static inline void
clutter_text_set_text_internal (ClutterText *self,
const gchar *text)
{
ClutterTextPrivate *priv = self->priv;
+ g_signal_emit (self, text_signals[DELETE_TEXT], 0, 0, -1);
+ if (text != NULL && *text != '\0')
+ {
+ gint tmp_pos = 0;
+
+ g_signal_emit (self, text_signals[INSERT_TEXT], 0,
+ text,
+ strlen (text),
+ &tmp_pos);
+ }
+
g_object_freeze_notify (G_OBJECT (self));
if (priv->max_length > 0)
@@ -1154,7 +1182,15 @@ clutter_text_set_property (GObject *gobject,
switch (prop_id)
{
case PROP_TEXT:
- clutter_text_set_text_internal (self, g_value_get_string (value));
+ {
+ const char *str = g_value_get_string (value);
+
+ clutter_text_set_contents (self, str);
+ if (self->priv->use_markup)
+ clutter_text_set_markup_internal (self, str);
+ else
+ clutter_text_set_text_internal (self, str);
+ }
break;
case PROP_COLOR:
@@ -1422,6 +1458,7 @@ clutter_text_finalize (GObject *gobject)
clutter_text_dirty_paint_volume (self);
+ g_free (priv->contents);
g_free (priv->text);
g_free (priv->font_name);
@@ -3550,6 +3587,7 @@ clutter_text_init (ClutterText *self)
* or strcmp() on it
*/
priv->text = g_strdup ("");
+ priv->contents = g_strdup ("");
priv->text_color = default_text_color;
priv->cursor_color = default_cursor_color;
@@ -4453,15 +4491,8 @@ clutter_text_set_text (ClutterText *self,
{
g_return_if_fail (CLUTTER_IS_TEXT (self));
- g_signal_emit (self, text_signals[DELETE_TEXT], 0, 0, -1);
- if (text)
- {
- gint tmp_pos = 0;
- g_signal_emit (self, text_signals[INSERT_TEXT], 0, text,
- strlen (text), &tmp_pos);
- }
-
clutter_text_set_use_markup_internal (self, FALSE);
+ clutter_text_set_contents (self, text);
clutter_text_set_text_internal (self, text ? text : "");
}
@@ -4490,6 +4521,7 @@ clutter_text_set_markup (ClutterText *self,
g_return_if_fail (CLUTTER_IS_TEXT (self));
clutter_text_set_use_markup_internal (self, TRUE);
+ clutter_text_set_contents (self, markup);
if (markup != NULL && *markup != '\0')
clutter_text_set_markup_internal (self, markup);
@@ -4883,7 +4915,7 @@ clutter_text_set_use_markup (ClutterText *self,
priv = self->priv;
- str = g_strdup (priv->text);
+ str = g_strdup (priv->contents);
clutter_text_set_use_markup_internal (self, setting);
diff --git a/tests/conform/test-clutter-text.c b/tests/conform/test-clutter-text.c
index ca24fe2..95d6ce8 100644
--- a/tests/conform/test-clutter-text.c
+++ b/tests/conform/test-clutter-text.c
@@ -410,3 +410,95 @@ text_event (void)
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
+static inline void
+validate_markup_attributes (ClutterText *text,
+ PangoAttrType attr_type,
+ int start_index,
+ int end_index)
+{
+ PangoLayout *layout;
+ PangoAttrList *attrs;
+ PangoAttrIterator *iter;
+
+ layout = clutter_text_get_layout (text);
+ g_assert (layout != NULL);
+
+ attrs = pango_layout_get_attributes (layout);
+ g_assert (attrs != NULL);
+
+ iter = pango_attr_list_get_iterator (attrs);
+ while (pango_attr_iterator_next (iter))
+ {
+ GSList *attributes = pango_attr_iterator_get_attrs (iter);
+ PangoAttribute *a;
+
+ if (attributes == NULL)
+ break;
+
+ g_assert (attributes->data != NULL);
+
+ a = attributes->data;
+
+ g_assert (a->klass->type == attr_type);
+ g_assert_cmpint (a->start_index, ==, start_index);
+ g_assert_cmpint (a->end_index, ==, end_index);
+
+ g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
+ }
+
+ pango_attr_iterator_destroy (iter);
+}
+
+void
+idempotent_use_markup (void)
+{
+ ClutterText *text;
+ const char *contents = "foo <b>bar</b>";
+ const char *display = "foo bar";
+ int bar_start_index = strstr (display, "bar") - display;
+ int bar_end_index = bar_start_index + strlen ("bar");
+
+ /* case 1: text -> use_markup */
+ if (g_test_verbose ())
+ g_print ("text: '%s' -> use-markup: TRUE\n", contents);
+
+ text = g_object_new (CLUTTER_TYPE_TEXT,
+ "text", contents, "use-markup", TRUE,
+ NULL);
+
+ if (g_test_verbose ())
+ g_print ("Contents: '%s' (expected: '%s')\n",
+ clutter_text_get_text (text),
+ display);
+
+ g_assert_cmpstr (clutter_text_get_text (text), ==, display);
+
+ validate_markup_attributes (text,
+ PANGO_ATTR_WEIGHT,
+ bar_start_index,
+ bar_end_index);
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+
+ /* case 2: use_markup -> text */
+ if (g_test_verbose ())
+ g_print ("use-markup: TRUE -> text: '%s'\n", contents);
+
+ text = g_object_new (CLUTTER_TYPE_TEXT,
+ "use-markup", TRUE, "text", contents,
+ NULL);
+
+ if (g_test_verbose ())
+ g_print ("Contents: '%s' (expected: '%s')\n",
+ clutter_text_get_text (text),
+ display);
+
+ g_assert_cmpstr (clutter_text_get_text (text), ==, display);
+
+ validate_markup_attributes (text,
+ PANGO_ATTR_WEIGHT,
+ bar_start_index,
+ bar_end_index);
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index d29fc83..39d1fcd 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -162,6 +162,7 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/text", text_get_chars);
TEST_CONFORM_SIMPLE ("/text", text_cache);
TEST_CONFORM_SIMPLE ("/text", text_password_char);
+ TEST_CONFORM_SIMPLE ("/text", idempotent_use_markup);
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_size);
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_color);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]