{
GtkTextIter iter, old_iter;
GSList *tag_list, *new_tag_list;
- GQueue *active_tags;
- int i;
+ GSList *active_tags;
g_string_append (context->text_str, "<text>");
iter = context->start;
tag_list = NULL;
- active_tags = g_queue_new ();
+ active_tags = NULL;
do
{
find_list_delta (tag_list, new_tag_list, &added, &removed);
/* Handle removed tags */
- tmp = removed;
- while (tmp)
+ for (tmp = removed; tmp; tmp = tmp->next)
{
GtkTextTag *tag = tmp->data;
- g_string_append (context->text_str, "</apply_tag>");
-
- /* We might need to drop some of the tags and re-add them afterwards */
- while (g_queue_peek_head (active_tags) != tag &&
- !g_queue_is_empty (active_tags))
- {
- added = g_list_prepend (added, g_queue_pop_head (active_tags));
- g_string_append_printf (context->text_str, "</apply_tag>");
- }
+ /* Only close the tag if we didn't close it before (by using
+ * the stack logic in the while() loop below)
+ */
+ if (g_slist_find (active_tags, tag))
+ {
+ g_string_append (context->text_str, "</apply_tag>");
- g_queue_pop_head (active_tags);
+ /* Drop all tags that were opened after this one (which are
+ * above this on in the stack)
+ */
+ while (active_tags->data != tag)
+ {
+ added = g_list_prepend (added, active_tags->data);
+ active_tags = g_slist_remove (active_tags, active_tags->data);
+ g_string_append_printf (context->text_str, "</apply_tag>");
+ }
- tmp = tmp->next;
+ active_tags = g_slist_remove (active_tags, active_tags->data);
+ }
}
/* Handle added tags */
- tmp = added;
- while (tmp)
+ for (tmp = added; tmp; tmp = tmp->next)
{
GtkTextTag *tag = tmp->data;
gchar *tag_name;
g_string_append_printf (context->text_str, "<apply_tag id=\"%d\">", GPOINTER_TO_INT (tag_id));
}
- g_queue_push_head (active_tags, tag);
- tmp = tmp->next;
+ active_tags = g_slist_prepend (active_tags, tag);
}
g_slist_free (tag_list);
tag_list = new_tag_list;
+ g_list_free (added);
+ g_list_free (removed);
+
old_iter = iter;
/* Now try to go to either the next tag toggle, or if a pixbuf appears */
while (!gtk_text_iter_equal (&iter, &context->end));
/* Close any open tags */
- for (i = 0; i < g_queue_get_length (active_tags); i++) {
+ for (tag_list = active_tags; tag_list; tag_list = tag_list->next)
g_string_append (context->text_str, "</apply_tag>");
- }
- g_queue_free (active_tags);
+
+ g_slist_free (active_tags);
g_string_append (context->text_str, "</text>\n</text_view_markup>\n");
}
--- /dev/null
+/* testrichtext.c
+ * Copyright (C) 2006 Imendio AB
+ * Authors: Michael Natterer, Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+
+static guint32 quick_rand32_accu = 2147483563;
+
+static inline guint32
+quick_rand32 (void)
+{
+ quick_rand32_accu = 1664525 * quick_rand32_accu + 1013904223;
+ return quick_rand32_accu;
+}
+
+static gboolean
+delete_event (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer user_data)
+{
+ gtk_main_quit ();
+
+ return TRUE;
+}
+
+static void
+text_tag_enqueue (GtkTextTag *tag,
+ gpointer data)
+{
+ GSList **slist_p = data;
+ *slist_p = g_slist_prepend (*slist_p, tag);
+}
+
+static const gchar *example_text =
+"vkndsk vfds vkfds vkdsv fdlksnvkfdvnkfdvnkdsnvs\n"
+"kmvofdmvfdsvkv fdskvnkfdv nnd.mckfdvnknsknvdnvs"
+"fdlvmfdsvlkfdsmvnskdnvfdsnvf sbskjnvlknfd cvdvnd"
+"mvlfdsv vfdkjv m, ds vkfdks v df,v j kfds v d\n"
+"vnfdskv kjvnfv cfdkvndfnvcm fd,vk kdsf vj d\n"
+"KLJHkjh kjh klhjKLJH Kjh kjl h34kj h34kj3h klj 23 "
+"kjlkjlhsdjk 34kljh klj hklj 23k4jkjkjh234kjh 52kj "
+"2h34 sdaf ukklj kjl32l jkkjl 23j jkl ljk23 jkl\n"
+"hjhjhj2hj23jh jh jk jk2h3 hj kjj jk jh21 jhhj32.";
+
+static GdkAtom
+setup_buffer (GtkTextBuffer *buffer)
+{
+ const guint tlen = strlen (example_text);
+ const guint tcount = 17;
+ GtkTextTag *tags[tcount];
+ GtkTextTagTable *ttable = gtk_text_buffer_get_tag_table (buffer);
+ GSList *node, *slist = NULL;
+ GdkAtom atom;
+ guint i;
+
+ /* cleanup */
+ gtk_text_buffer_set_text (buffer, "", 0);
+ gtk_text_tag_table_foreach (ttable, text_tag_enqueue, &slist);
+ for (node = slist; node; node = node->next)
+ gtk_text_tag_table_remove (ttable, node->data);
+ g_slist_free (slist);
+
+ /* create new tags */
+ for (i = 0; i < tcount; i++)
+ {
+ char *s = g_strdup_printf ("tag%u", i);
+ tags[i] = gtk_text_buffer_create_tag (buffer, s,
+ "weight", quick_rand32() >> 31 ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
+ "style", quick_rand32() >> 31 ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL,
+ "underline", quick_rand32() >> 31,
+ NULL);
+ g_free (s);
+ }
+
+ /* assign text and tags */
+ gtk_text_buffer_set_text (buffer, example_text, -1);
+ for (i = 0; i < tcount * 5; i++)
+ {
+ gint a = quick_rand32() % tlen, b = quick_rand32() % tlen;
+ GtkTextIter start, end;
+ gtk_text_buffer_get_iter_at_offset (buffer, &start, MIN (a, b));
+ gtk_text_buffer_get_iter_at_offset (buffer, &end, MAX (a, b));
+ gtk_text_buffer_apply_tag (buffer, tags[i % tcount], &start, &end);
+ }
+
+ /* return serialization format */
+ atom = gtk_text_buffer_register_deserialize_tagset (buffer, NULL);
+ gtk_text_buffer_deserialize_set_can_create_tags (buffer, atom, TRUE);
+
+ return atom;
+}
+
+static gboolean
+test_serialize_deserialize (GtkTextBuffer *buffer,
+ GdkAtom atom,
+ GError **error)
+{
+ GtkTextIter start, end;
+ guint8 *spew;
+ gsize spew_length;
+ gboolean success;
+
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+
+ spew = gtk_text_buffer_serialize (buffer, buffer, atom,
+ &start, &end, &spew_length);
+
+ success = gtk_text_buffer_deserialize (buffer, buffer, atom, &end,
+ spew, spew_length, error);
+
+ g_free (spew);
+
+ return success;
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *sw;
+ GtkWidget *view;
+ GtkTextBuffer *buffer;
+ GdkAtom atom;
+ guint i, broken = 0;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_size_request (window, 400, 300);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+ GTK_SHADOW_IN);
+ gtk_container_set_border_width (GTK_CONTAINER (sw), 12);
+ gtk_container_add (GTK_CONTAINER (window), sw);
+
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (delete_event),
+ NULL);
+
+ buffer = gtk_text_buffer_new (NULL);
+ view = gtk_text_view_new_with_buffer (buffer);
+ g_object_unref (buffer);
+
+ gtk_container_add (GTK_CONTAINER (sw), view);
+
+ gtk_widget_show_all (window);
+ if (0)
+ gtk_main ();
+
+ for (i = 0; i < 250; i++)
+ {
+ GError *error = NULL;
+ g_printerr ("creating randomly tagged text buffer with accu=0x%x...\n", quick_rand32_accu);
+ atom = setup_buffer (buffer);
+ if (test_serialize_deserialize (buffer, atom, &error))
+ g_printerr ("ok.\n");
+ else
+ {
+ g_printerr ("FAIL: serialization/deserialization failed:\n %s\n", error->message);
+ broken += 1;
+ }
+ g_clear_error (&error);
+ }
+
+ return broken > 0;
+}