From d6ed5ee9f9682d7de5012fac6528f46675cfb43c Mon Sep 17 00:00:00 2001 From: Michael Lauer Date: Mon, 6 Nov 2006 07:42:50 +0000 Subject: gtk+: remove a couple of obsolete versions, major stable versions remain gtk+-2.6.10: add menu styling patch based on gtk+ 2.7 --- .../gtktextbufferserialize.c.diff | 1688 -------------------- 1 file changed, 1688 deletions(-) delete mode 100644 packages/gtk+/gtk+-2.6.4-1.osso7/gtktextbufferserialize.c.diff (limited to 'packages/gtk+/gtk+-2.6.4-1.osso7/gtktextbufferserialize.c.diff') diff --git a/packages/gtk+/gtk+-2.6.4-1.osso7/gtktextbufferserialize.c.diff b/packages/gtk+/gtk+-2.6.4-1.osso7/gtktextbufferserialize.c.diff deleted file mode 100644 index 39c8f748de..0000000000 --- a/packages/gtk+/gtk+-2.6.4-1.osso7/gtktextbufferserialize.c.diff +++ /dev/null @@ -1,1688 +0,0 @@ ---- gtk+-2.6.4/gtk/gtktextbufferserialize.c 1970-01-01 02:00:00.000000000 +0200 -+++ gtk+-2.6.4/gtk/gtktextbufferserialize.c 2005-04-06 16:19:38.024757720 +0300 -@@ -0,0 +1,1685 @@ -+/* gtktextbufferserialize.c -+ * -+ * Copyright (C) 2001 Havoc Pennington -+ * Copyright (C) 2004 Nokia -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library 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 -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library 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. -+ */ -+ -+/* FIXME: We should use other error codes for the -+ * parts that deal with the format errors -+ */ -+ -+#include -+ -+#include -+#include "gdk-pixbuf/gdk-pixdata.h" -+#include "gtktextbufferserialize.h" -+#include "gtkintl.h" -+ -+#include -+#include -+ -+typedef struct -+{ -+ GString *tag_table_str; -+ GString *text_str; -+ GHashTable *tags; -+ GtkTextIter start, end; -+ -+ gint n_pixbufs; -+ GList *pixbufs; -+} SerializationContext; -+ -+static gchar * -+serialize_value (GValue *value) -+{ -+ if (g_value_type_transformable (value->g_type, G_TYPE_STRING)) -+ { -+ GValue text_value = { 0 }; -+ gchar *tmp; -+ -+ g_value_init (&text_value, G_TYPE_STRING); -+ g_value_transform (value, &text_value); -+ -+ tmp = g_markup_escape_text (g_value_get_string (&text_value), -1); -+ g_value_unset (&text_value); -+ -+ return tmp; -+ } -+ else if (value->g_type == GDK_TYPE_COLOR) -+ { -+ GdkColor *color = g_value_get_boxed (value); -+ -+ return g_strdup_printf ("%x:%x:%x", color->red, color->green, color->blue); -+ } -+ else -+ { -+ g_warning ("Type %s is not serializable\n", g_type_name (value->g_type)); -+ } -+ -+ return NULL; -+} -+ -+static gboolean -+deserialize_value (const gchar *str, GValue *value) -+{ -+ if (g_value_type_transformable (G_TYPE_STRING, value->g_type)) -+ { -+ GValue text_value = { 0 }; -+ gboolean retval; -+ -+ g_value_init (&text_value, G_TYPE_STRING); -+ g_value_set_static_string (&text_value, str); -+ -+ retval = g_value_transform (&text_value, value); -+ g_value_unset (&text_value); -+ -+ return retval; -+ } -+ else if (value->g_type == G_TYPE_BOOLEAN) -+ { -+ gboolean v; -+ -+ v = strcmp (str, "TRUE") == 0; -+ -+ g_value_set_boolean (value, v); -+ -+ return TRUE; -+ } -+ else if (value->g_type == G_TYPE_INT) -+ { -+ gchar *tmp; -+ int v; -+ -+ v = strtol (str, &tmp, 10); -+ -+ if (tmp == NULL || tmp == str) -+ return FALSE; -+ -+ g_value_set_int (value, v); -+ -+ return TRUE; -+ } -+ else if (value->g_type == G_TYPE_DOUBLE) -+ { -+ gchar *tmp; -+ gdouble v; -+ -+ v = g_ascii_strtod (str, &tmp); -+ -+ if (tmp == NULL || tmp == str) -+ return FALSE; -+ -+ g_value_set_double (value, v); -+ -+ return TRUE; -+ } -+ else if (value->g_type == GDK_TYPE_COLOR) -+ { -+ GdkColor color; -+ const gchar *old; -+ gchar *tmp; -+ -+ old = str; -+ color.red = strtol (old, &tmp, 16); -+ -+ if (tmp == NULL || tmp == old) -+ return FALSE; -+ -+ old = tmp; -+ if (*old++ != ':') -+ return FALSE; -+ -+ color.green = strtol (old, &tmp, 16); -+ if (tmp == NULL || tmp == old) -+ return FALSE; -+ -+ old = tmp; -+ if (*old++ != ':') -+ return FALSE; -+ -+ color.blue = strtol (old, &tmp, 16); -+ -+ if (tmp == NULL || tmp == old || *tmp != '\0') -+ return FALSE; -+ -+ g_value_set_boxed (value, &color); -+ -+ return TRUE; -+ } -+ else if (G_VALUE_HOLDS_ENUM (value)) -+ { -+ GEnumClass *class = G_ENUM_CLASS (g_type_class_peek (value->g_type)); -+ GEnumValue *enum_value; -+ -+ enum_value = g_enum_get_value_by_name (class, str); -+ -+ if (enum_value) -+ { -+ g_value_set_enum (value, enum_value->value); -+ return TRUE; -+ } -+ -+ return FALSE; -+ } -+ else -+ { -+ g_warning ("Type %s can not be deserialized\n", g_type_name (value->g_type)); -+ } -+ -+ return FALSE; -+} -+ -+/* Checks if a param is set, or if it's the default value */ -+static gboolean -+is_param_set (GObject *object, GParamSpec *pspec, GValue *value) -+{ -+ /* We need to special case some attributes here */ -+ if (strcmp (pspec->name, "background-gdk") == 0) -+ { -+ gboolean is_set; -+ -+ g_object_get (object, "background-set", &is_set, NULL); -+ -+ if (is_set) -+ { -+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); -+ -+ g_object_get_property (object, pspec->name, value); -+ -+ return TRUE; -+ } -+ -+ return FALSE; -+ } -+ else if (strcmp (pspec->name, "foreground-gdk") == 0) -+ { -+ gboolean is_set; -+ -+ g_object_get (object, "foreground-set", &is_set, NULL); -+ -+ if (is_set) -+ { -+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); -+ -+ g_object_get_property (object, pspec->name, value); -+ -+ return TRUE; -+ } -+ -+ return FALSE; -+ } -+ else -+ { -+ gboolean is_set; -+ gchar *is_set_name; -+ -+ is_set_name = g_strdup_printf ("%s-set", pspec->name); -+ -+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), is_set_name) == NULL) -+ { -+ g_free (is_set_name); -+ return FALSE; -+ } -+ else -+ { -+ g_object_get (object, is_set_name, &is_set, NULL); -+ -+ if (!is_set) -+ { -+ g_free (is_set_name); -+ return FALSE; -+ } -+ -+ g_free (is_set_name); -+ -+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); -+ -+ g_object_get_property (object, pspec->name, value); -+ -+ if (g_param_value_defaults (pspec, value)) -+ { -+ g_value_unset (value); -+ -+ return FALSE; -+ } -+ } -+ return TRUE; -+ } -+} -+ -+static void -+serialize_tag (gpointer key, gpointer data, gpointer user_data) -+{ -+ SerializationContext *context = user_data; -+ GtkTextTag *tag = data; -+ gchar *tag_name; -+ GParamSpec **pspecs; -+ guint n_pspecs; -+ int i; -+ -+ tag_name = g_markup_escape_text (tag->name, -1); -+ g_string_append_printf (context->tag_table_str, " \n", tag_name, tag->priority); -+ -+ /* Serialize properties */ -+ pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (tag), &n_pspecs); -+ -+ for (i = 0; i < n_pspecs; i++) -+ { -+ GValue value = { 0 }; -+ gchar *tmp, *tmp2; -+ -+ if (!(pspecs[i]->flags & G_PARAM_READABLE) || -+ !(pspecs[i]->flags & G_PARAM_WRITABLE)) -+ continue; -+ -+ if (!is_param_set (G_OBJECT (tag), pspecs[i], &value)) -+ continue; -+ -+ /* Now serialize the attr */ -+ tmp = g_markup_escape_text (pspecs[i]->name, -1); -+ g_string_append_printf (context->tag_table_str, " value_type), -1); -+ tmp2 = serialize_value (&value); -+ g_string_append_printf (context->tag_table_str, "type=\"%s\" value=\"%s\" />\n", tmp, tmp2); -+ -+ g_free (tmp); -+ g_free (tmp2); -+ -+ g_value_unset (&value); -+ } -+ -+ g_free (pspecs); -+ -+ g_string_append (context->tag_table_str, " \n"); -+ g_free (tag_name); -+} -+ -+static void -+serialize_tags (SerializationContext *context) -+{ -+ g_string_append (context->tag_table_str, " \n"); -+ g_string_append (context->tag_table_str, " \n"); -+ g_hash_table_foreach (context->tags, serialize_tag, context); -+ g_string_append (context->tag_table_str, " \n"); -+} -+ -+#if 0 -+static void -+dump_tag_list (const gchar *str, GList *list) -+{ -+ g_print ("%s: ", str); -+ -+ if (!list) -+ g_print ("(empty)"); -+ else -+ { -+ while (list) -+ { -+ g_print ("%s ", ((GtkTextTag *)list->data)->name); -+ list = list->next; -+ } -+ } -+ -+ g_print ("\n"); -+} -+#endif -+ -+static void -+find_list_delta (GSList *old_list, GSList *new_list, -+ GList **added, GList **removed) -+{ -+ GSList *tmp; -+ GList *tmp_added, *tmp_removed; -+ -+ tmp_added = NULL; -+ tmp_removed = NULL; -+ -+ /* Find added tags */ -+ tmp = new_list; -+ while (tmp) -+ { -+ if (!g_slist_find (old_list, tmp->data)) -+ tmp_added = g_list_prepend (tmp_added, tmp->data); -+ -+ tmp = tmp->next; -+ } -+ -+ *added = tmp_added; -+ -+ /* Find removed tags */ -+ tmp = old_list; -+ while (tmp) -+ { -+ if (!g_slist_find (new_list, tmp->data)) -+ tmp_removed = g_list_prepend (tmp_removed, tmp->data); -+ -+ tmp = tmp->next; -+ } -+ -+ /* We reverse the list here to match the xml semantics */ -+ *removed = g_list_reverse (tmp_removed); -+} -+ -+static void -+serialize_section_header (GString *str, -+ const gchar *name, -+ gint length) -+{ -+ g_return_if_fail (strlen (name) == 8); -+ -+ g_string_append (str, name); -+ -+ g_string_append_c (str, length >> 24); -+ -+ g_string_append_c (str, (length >> 16) & 0xff); -+ g_string_append_c (str, (length >> 8) & 0xff); -+ g_string_append_c (str, length & 0xff); -+} -+ -+static void -+serialize_text (GtkTextBuffer *buffer, SerializationContext *context) -+{ -+ GtkTextIter iter, old_iter; -+ GSList *tag_list, *new_tag_list; -+ GQueue *active_tags; -+ int i; -+ -+ g_string_append (context->text_str, ""); -+ -+ iter = context->start; -+ tag_list = NULL; -+ active_tags = g_queue_new (); -+ -+ do -+ { -+ GList *added, *removed; -+ GList *tmp; -+ gchar *tmp_text, *escaped_text; -+ -+ new_tag_list = gtk_text_iter_get_tags (&iter); -+ find_list_delta (tag_list, new_tag_list, &added, &removed); -+ -+ /* Handle removed tags */ -+ tmp = removed; -+ while (tmp) -+ { -+ GtkTextTag *tag = tmp->data; -+ -+ g_string_append (context->text_str, ""); -+ -+ /* 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, ""); -+ } -+ -+ g_queue_pop_head (active_tags); -+ -+ tmp = tmp->next; -+ } -+ -+ /* Handle added tags */ -+ tmp = added; -+ while (tmp) -+ { -+ GtkTextTag *tag = tmp->data; -+ gchar *tag_name; -+ -+ /* Add it to the tag hash table */ -+ g_hash_table_insert (context->tags, tag, tag); -+ -+ tag_name = g_markup_escape_text (tag->name, -1); -+ -+ g_string_append_printf (context->text_str, "", tag_name); -+ g_free (tag_name); -+ -+ g_queue_push_head (active_tags, tag); -+ -+ tmp = tmp->next; -+ } -+ -+ g_slist_free (tag_list); -+ tag_list = new_tag_list; -+ -+ old_iter = iter; -+ -+ /* Now try to go to either the next tag toggle, or if a pixbuf appears */ -+ while (TRUE) -+ { -+ gunichar ch = gtk_text_iter_get_char (&iter); -+ -+ if (ch == 0xFFFC) -+ { -+ GdkPixbuf *pixbuf = gtk_text_iter_get_pixbuf (&iter); -+ -+ if (pixbuf) { -+ g_string_append_printf (context->text_str, "", context->n_pixbufs); -+ -+ context->n_pixbufs++; -+ context->pixbufs = g_list_prepend (context->pixbufs, pixbuf); -+ } -+ } -+ -+ gtk_text_iter_forward_char (&iter); -+ -+ if (gtk_text_iter_toggles_tag (&iter, NULL)) -+ break; -+ } -+ -+ /* We might have moved too far */ -+ if (gtk_text_iter_compare (&iter, &context->end) > 0) -+ iter = context->end; -+ -+ /* Append the text */ -+ tmp_text = gtk_text_iter_get_slice (&old_iter, &iter); -+ escaped_text = g_markup_escape_text (tmp_text, -1); -+ g_free (tmp_text); -+ -+ g_string_append (context->text_str, escaped_text); -+ g_free (escaped_text); -+ } -+ while (!gtk_text_iter_equal (&iter, &context->end)); -+ -+ /* Close any open tags */ -+ for (i = 0; i < g_queue_get_length (active_tags); i++) { -+ g_string_append (context->text_str, ""); -+ } -+ g_queue_free (active_tags); -+ g_string_append (context->text_str, "\n\n"); -+} -+ -+static void -+serialize_pixbufs (SerializationContext *context, -+ GString *text) -+{ -+ GList *list; -+ -+ for (list = context->pixbufs; list != NULL; list = list->next) -+ { -+ GdkPixbuf *pixbuf = list->data; -+ GdkPixdata pixdata; -+ guint8 *tmp; -+ guint len; -+ -+ gdk_pixdata_from_pixbuf (&pixdata, pixbuf, FALSE); -+ tmp = gdk_pixdata_serialize (&pixdata, &len); -+ -+ serialize_section_header (text, "PDPIXBUF", len); -+ g_string_append_len (text, tmp, len); -+ g_free (tmp); -+ } -+} -+ -+gchar * -+gtk_text_buffer_serialize_rich_text (GtkTextBuffer *buffer, -+ const GtkTextIter *start, -+ const GtkTextIter *end, -+ gint *len) -+{ -+ SerializationContext context; -+ GString *text; -+ -+ context.tags = g_hash_table_new (NULL, NULL); -+ context.text_str = g_string_new (NULL); -+ context.tag_table_str = g_string_new (NULL); -+ context.start = *start; -+ context.end = *end; -+ context.n_pixbufs = 0; -+ context.pixbufs = NULL; -+ -+ /* We need to serialize the text before the tag table so we know -+ what tags are used */ -+ serialize_text (buffer, &context); -+ serialize_tags (&context); -+ -+ text = g_string_new (NULL); -+ serialize_section_header (text, "RICHTEXT", context.tag_table_str->len + context.text_str->len); -+ -+ g_print ("when serializing length is: %d\n", context.tag_table_str->len + context.text_str->len); -+ -+ g_string_append_len (text, context.tag_table_str->str, context.tag_table_str->len); -+ g_string_append_len (text, context.text_str->str, context.text_str->len); -+ -+ context.pixbufs = g_list_reverse (context.pixbufs); -+ serialize_pixbufs (&context, text); -+ -+ g_hash_table_destroy (context.tags); -+ g_list_free (context.pixbufs); -+ g_string_free (context.text_str, TRUE); -+ g_string_free (context.tag_table_str, TRUE); -+ -+ *len = text->len; -+ -+ return g_string_free (text, FALSE); -+} -+ -+typedef enum -+{ -+ STATE_START, -+ STATE_TEXT_VIEW_MARKUP, -+ STATE_TAGS, -+ STATE_TAG, -+ STATE_ATTR, -+ STATE_TEXT, -+ STATE_APPLY_TAG, -+ STATE_PIXBUF -+} ParseState; -+ -+typedef struct -+{ -+ gchar *text; -+ GdkPixbuf *pixbuf; -+ GSList *tags; -+} TextSpan; -+ -+typedef struct -+{ -+ GtkTextTag *tag; -+ gint prio; -+} TextTagPrio; -+ -+typedef struct -+{ -+ GSList *states; -+ -+ GList *headers; -+ -+ GtkTextBuffer *buffer; -+ -+ /* Tags that are defined in elements */ -+ GHashTable *defined_tags; -+ -+ /* Tag name substitutions */ -+ GHashTable *substitutions; -+ -+ /* Current tag */ -+ GtkTextTag *current_tag; -+ -+ /* Priority of current tag */ -+ gint current_tag_prio; -+ -+ /* Tags and their priorities */ -+ GList *tag_priorities; -+ -+ GSList *tag_stack; -+ -+ GList *spans; -+ -+ gboolean create_tags; -+ -+ gboolean parsed_text; -+ gboolean parsed_tags; -+} ParseInfo; -+ -+static void -+set_error (GError **err, -+ GMarkupParseContext *context, -+ int error_domain, -+ int error_code, -+ const char *format, -+ ...) -+{ -+ int line, ch; -+ va_list args; -+ char *str; -+ -+ g_markup_parse_context_get_position (context, &line, &ch); -+ -+ va_start (args, format); -+ str = g_strdup_vprintf (format, args); -+ va_end (args); -+ -+ g_set_error (err, error_domain, error_code, -+ ("Line %d character %d: %s"), -+ line, ch, str); -+ -+ g_free (str); -+} -+ -+static void -+push_state (ParseInfo *info, -+ ParseState state) -+{ -+ info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state)); -+} -+ -+static void -+pop_state (ParseInfo *info) -+{ -+ g_return_if_fail (info->states != NULL); -+ -+ info->states = g_slist_remove (info->states, info->states->data); -+} -+ -+static ParseState -+peek_state (ParseInfo *info) -+{ -+ g_return_val_if_fail (info->states != NULL, STATE_START); -+ -+ return GPOINTER_TO_INT (info->states->data); -+} -+ -+#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) -+ -+typedef struct -+{ -+ const char *name; -+ const char **retloc; -+} LocateAttr; -+ -+static gboolean -+locate_attributes (GMarkupParseContext *context, -+ const char *element_name, -+ const char **attribute_names, -+ const char **attribute_values, -+ GError **error, -+ const char *first_attribute_name, -+ const char **first_attribute_retloc, -+ ...) -+{ -+ va_list args; -+ const char *name; -+ const char **retloc; -+ int n_attrs; -+#define MAX_ATTRS 24 -+ LocateAttr attrs[MAX_ATTRS]; -+ gboolean retval; -+ int i; -+ -+ g_return_val_if_fail (first_attribute_name != NULL, FALSE); -+ g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); -+ -+ retval = TRUE; -+ -+ n_attrs = 1; -+ attrs[0].name = first_attribute_name; -+ attrs[0].retloc = first_attribute_retloc; -+ *first_attribute_retloc = NULL; -+ -+ va_start (args, first_attribute_retloc); -+ -+ name = va_arg (args, const char*); -+ retloc = va_arg (args, const char**); -+ -+ while (name != NULL) -+ { -+ g_return_val_if_fail (retloc != NULL, FALSE); -+ -+ g_assert (n_attrs < MAX_ATTRS); -+ -+ attrs[n_attrs].name = name; -+ attrs[n_attrs].retloc = retloc; -+ n_attrs += 1; -+ *retloc = NULL; -+ -+ name = va_arg (args, const char*); -+ retloc = va_arg (args, const char**); -+ } -+ -+ va_end (args); -+ -+ if (!retval) -+ return retval; -+ -+ i = 0; -+ while (attribute_names[i]) -+ { -+ int j; -+ gboolean found; -+ -+ found = FALSE; -+ j = 0; -+ while (j < n_attrs) -+ { -+ if (strcmp (attrs[j].name, attribute_names[i]) == 0) -+ { -+ retloc = attrs[j].retloc; -+ -+ if (*retloc != NULL) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, -+ G_MARKUP_ERROR_PARSE, -+ _("Attribute \"%s\" repeated twice on the same <%s> element"), -+ attrs[j].name, element_name); -+ retval = FALSE; -+ goto out; -+ } -+ -+ *retloc = attribute_values[i]; -+ found = TRUE; -+ } -+ -+ ++j; -+ } -+ -+ if (!found) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, -+ G_MARKUP_ERROR_PARSE, -+ _("Attribute \"%s\" is invalid on <%s> element in this context"), -+ attribute_names[i], element_name); -+ retval = FALSE; -+ goto out; -+ } -+ -+ ++i; -+ } -+ -+ out: -+ return retval; -+} -+ -+static gboolean -+check_no_attributes (GMarkupParseContext *context, -+ const char *element_name, -+ const char **attribute_names, -+ const char **attribute_values, -+ GError **error) -+{ -+ if (attribute_names[0] != NULL) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, -+ G_MARKUP_ERROR_PARSE, -+ _("Attribute \"%s\" is invalid on <%s> element in this context"), -+ attribute_names[0], element_name); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static const gchar * -+tag_exists (GMarkupParseContext *context, -+ const gchar *name, -+ ParseInfo *info, -+ GError **error) -+{ -+ const gchar *real_name; -+ -+ if (info->create_tags) -+ { -+ /* First, try the substitutions */ -+ real_name = g_hash_table_lookup (info->substitutions, name); -+ -+ if (real_name) -+ return real_name; -+ -+ /* Next, try the list of defined tags */ -+ if (g_hash_table_lookup (info->defined_tags, name) != NULL) -+ return name; -+ -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Tag \"%s\" has not been defined."), name); -+ -+ return NULL; -+ } -+ else -+ { -+ if (gtk_text_tag_table_lookup (info->buffer->tag_table, name) != NULL) -+ return name; -+ -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Tag \"%s\" does not exist in buffer and tags can not be created."), name); -+ -+ return NULL; -+ } -+} -+ -+typedef struct -+{ -+ const gchar *id; -+ gint length; -+ const gchar *start; -+} Header; -+ -+static GdkPixbuf * -+get_pixbuf_from_headers (GList *headers, int id, GError **error) -+{ -+ Header *header; -+ GdkPixdata pixdata; -+ GdkPixbuf *pixbuf; -+ -+ header = g_list_nth_data (headers, id); -+ -+ if (!header) -+ return NULL; -+ -+ if (!gdk_pixdata_deserialize (&pixdata, header->length, header->start, error)) -+ return NULL; -+ -+ pixbuf = gdk_pixbuf_from_pixdata (&pixdata, TRUE, error); -+ -+ g_print ("pixbuf is: %p\n", pixbuf); -+ -+ return pixbuf; -+} -+ -+static void -+parse_apply_tag_element (GMarkupParseContext *context, -+ const gchar *element_name, -+ const gchar **attribute_names, -+ const gchar **attribute_values, -+ ParseInfo *info, -+ GError **error) -+{ -+ const gchar *name, *tag_name, *id; -+ -+ g_assert (peek_state (info) == STATE_TEXT || -+ peek_state (info) == STATE_APPLY_TAG); -+ -+ if (ELEMENT_IS ("apply_tag")) -+ { -+ if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, -+ "name", &name, NULL)) -+ return; -+ -+ tag_name = tag_exists (context, name, info, error); -+ -+ if (!tag_name) -+ return; -+ -+ info->tag_stack = g_slist_prepend (info->tag_stack, g_strdup (tag_name)); -+ -+ push_state (info, STATE_APPLY_TAG); -+ } -+ else if (ELEMENT_IS ("pixbuf")) -+ { -+ int int_id; -+ GdkPixbuf *pixbuf; -+ TextSpan *span; -+ -+ if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, -+ "index", &id, NULL)) -+ return; -+ -+ int_id = atoi (id); -+ pixbuf = get_pixbuf_from_headers (info->headers, int_id, error); -+ -+ span = g_new0 (TextSpan, 1); -+ span->pixbuf = pixbuf; -+ span->tags = NULL; -+ -+ info->spans = g_list_prepend (info->spans, span); -+ -+ if (!pixbuf) -+ return; -+ -+ push_state (info, STATE_PIXBUF); -+ } -+ else -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Element <%s> is not allowed below <%s>"), -+ element_name, peek_state(info) == STATE_TEXT ? "text" : "apply_tag"); -+} -+ -+static void -+parse_attr_element (GMarkupParseContext *context, -+ const gchar *element_name, -+ const gchar **attribute_names, -+ const gchar **attribute_values, -+ ParseInfo *info, -+ GError **error) -+{ -+ const gchar *name, *type, *value; -+ GType gtype; -+ GValue gvalue = { 0 }; -+ GParamSpec *pspec; -+ -+ g_assert (peek_state (info) == STATE_TAG); -+ -+ if (ELEMENT_IS ("attr")) -+ { -+ if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, -+ "name", &name, "type", &type, "value", &value, NULL)) -+ return; -+ -+ gtype = g_type_from_name (type); -+ -+ if (gtype == G_TYPE_INVALID) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("\"%s\" is not a valid attribute type"), type); -+ return; -+ } -+ -+ if (!(pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info->current_tag), name))) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("\"%s\" is not a valid attribute name"), name); -+ return; -+ } -+ -+ g_value_init (&gvalue, gtype); -+ -+ if (!deserialize_value (value, &gvalue)) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("\"%s\" could not be converted to a value of type \"%s\" for attribute \"%s\""), -+ value, type, name); -+ return; -+ } -+ -+ if (g_param_value_validate (pspec, &gvalue)) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("\"%s\" is not a valid value of for attribute \"%s\""), -+ value, name); -+ g_value_unset (&gvalue); -+ return; -+ } -+ -+ g_object_set_property (G_OBJECT (info->current_tag), -+ name, &gvalue); -+ -+ g_value_unset (&gvalue); -+ -+ push_state (info, STATE_ATTR); -+ } -+ else -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Element <%s> is not allowed below <%s>"), -+ element_name, "tag"); -+ } -+} -+ -+ -+static gchar * -+get_tag_name (ParseInfo *info, -+ const gchar *tag_name) -+{ -+ gchar *name; -+ gint i; -+ -+ name = g_strdup (tag_name); -+ -+ if (!info->create_tags) -+ return name; -+ -+ i = 0; -+ -+ while (gtk_text_tag_table_lookup (info->buffer->tag_table, name) != NULL) -+ { -+ g_free (name); -+ name = g_strdup_printf ("%s-%d", tag_name, ++i); -+ } -+ -+ if (i != 0) -+ { -+ g_hash_table_insert (info->substitutions, g_strdup (tag_name), g_strdup (name)); -+ } -+ -+ return name; -+} -+ -+static void -+parse_tag_element (GMarkupParseContext *context, -+ const gchar *element_name, -+ const gchar **attribute_names, -+ const gchar **attribute_values, -+ ParseInfo *info, -+ GError **error) -+{ -+ const gchar *name, *priority; -+ gchar *tag_name; -+ gint prio; -+ gchar *tmp; -+ -+ g_assert (peek_state (info) == STATE_TAGS); -+ -+ if (ELEMENT_IS ("tag")) -+ { -+ if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, -+ "name", &name, "priority", &priority, NULL)) -+ return; -+ -+ if (g_hash_table_lookup (info->defined_tags, name) != NULL) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Tag \"%s\" already defined"), name); -+ return; -+ } -+ -+ prio = strtol (priority, &tmp, 10); -+ -+ if (tmp == NULL || tmp == priority) -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Tag \"%s\" has invalid priority \"%s\""), name, priority); -+ return; -+ } -+ -+ tag_name = get_tag_name (info, name); -+ info->current_tag = gtk_text_tag_new (tag_name); -+ info->current_tag_prio = prio; -+ -+ g_free (tag_name); -+ -+ push_state (info, STATE_TAG); -+ } -+ else -+ { -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Element <%s> is not allowed below <%s>"), -+ element_name, "tags"); -+ } -+} -+ -+static void -+start_element_handler (GMarkupParseContext *context, -+ const gchar *element_name, -+ const gchar **attribute_names, -+ const gchar **attribute_values, -+ gpointer user_data, -+ GError **error) -+{ -+ ParseInfo *info = user_data; -+ -+ switch (peek_state (info)) -+ { -+ case STATE_START: -+ if (ELEMENT_IS ("text_view_markup")) -+ { -+ if (!check_no_attributes (context, element_name, -+ attribute_names, attribute_values, error)) -+ return; -+ -+ push_state (info, STATE_TEXT_VIEW_MARKUP); -+ break; -+ } -+ else -+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Outermost element in text must be not <%s>"), -+ element_name); -+ break; -+ case STATE_TEXT_VIEW_MARKUP: -+ if (ELEMENT_IS ("tags")) -+ { -+ if (info->parsed_tags) -+ { -+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("A element has already been specified")); -+ return; -+ } -+ -+ if (!check_no_attributes (context, element_name, -+ attribute_names, attribute_values, error)) -+ return; -+ -+ push_state (info, STATE_TAGS); -+ break; -+ } -+ else if (ELEMENT_IS ("text")) -+ { -+ if (info->parsed_text) -+ { -+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("A element has already been specified")); -+ return; -+ } -+ else if (!info->parsed_tags) -+ { -+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("A element can't occur before a element")); -+ return; -+ } -+ -+ if (!check_no_attributes (context, element_name, -+ attribute_names, attribute_values, error)) -+ return; -+ -+ push_state (info, STATE_TEXT); -+ break; -+ } -+ else -+ set_error (error, context, -+ G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, -+ _("Element <%s> is not allowed below <%s>"), -+ element_name, "text_view_markup"); -+ break; -+ case STATE_TAGS: -+ parse_tag_element (context, element_name, -+ attribute_names, attribute_values, -+ info, error); -+ break; -+ case STATE_TAG: -+ parse_attr_element (context, element_name, -+ attribute_names, attribute_values, -+ info, error); -+ break; -+ case STATE_TEXT: -+ case STATE_APPLY_TAG: -+ parse_apply_tag_element (context, element_name, -+ attribute_names, attribute_values, -+ info, error); -+ break; -+ default: -+ g_assert_not_reached (); -+ break; -+ } -+} -+ -+static gint -+sort_tag_prio (TextTagPrio *a, -+ TextTagPrio *b) -+{ -+ if (a->prio < b->prio) -+ return -1; -+ else if (a->prio > b->prio) -+ return 1; -+ else -+ return 0; -+} -+ -+static void -+end_element_handler (GMarkupParseContext *context, -+ const gchar *element_name, -+ gpointer user_data, -+ GError **error) -+{ -+ ParseInfo *info = user_data; -+ gchar *tmp; -+ GList *list; -+ -+ switch (peek_state (info)) -+ { -+ case STATE_TAGS: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP); -+ -+ info->parsed_tags = TRUE; -+ -+ /* Sort list and add the tags */ -+ info->tag_priorities = g_list_sort (info->tag_priorities, -+ (GCompareFunc)sort_tag_prio); -+ list = info->tag_priorities; -+ while (list) -+ { -+ TextTagPrio *prio = list->data; -+ -+ if (info->create_tags) -+ gtk_text_tag_table_add (info->buffer->tag_table, prio->tag); -+ -+ g_object_unref (prio->tag); -+ prio->tag = NULL; -+ -+ list = list->next; -+ } -+ -+ break; -+ case STATE_TAG: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_TAGS); -+ -+ /* Add tag to defined tags hash */ -+ tmp = g_strdup (info->current_tag->name); -+ g_hash_table_insert (info->defined_tags, -+ tmp, tmp); -+ -+ if (info->create_tags) -+ { -+ TextTagPrio *prio; -+ -+ /* add the tag to the list */ -+ prio = g_new0 (TextTagPrio, 1); -+ prio->prio = info->current_tag_prio; -+ prio->tag = info->current_tag; -+ -+ info->tag_priorities = g_list_prepend (info->tag_priorities, prio); -+ } -+ -+ info->current_tag = NULL; -+ break; -+ case STATE_ATTR: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_TAG); -+ break; -+ case STATE_APPLY_TAG: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_APPLY_TAG || -+ peek_state (info) == STATE_TEXT); -+ -+ /* Pop tag */ -+ g_free (info->tag_stack->data); -+ info->tag_stack = g_slist_delete_link (info->tag_stack, -+ info->tag_stack); -+ -+ break; -+ case STATE_TEXT: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP); -+ -+ info->spans = g_list_reverse (info->spans); -+ info->parsed_text = TRUE; -+ break; -+ case STATE_TEXT_VIEW_MARKUP: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_START); -+ break; -+ case STATE_PIXBUF: -+ pop_state (info); -+ g_assert (peek_state (info) == STATE_APPLY_TAG || -+ peek_state (info) == STATE_TEXT); -+ break; -+ default: -+ g_assert_not_reached (); -+ break; -+ } -+} -+ -+static gboolean -+all_whitespace (const char *text, -+ int text_len) -+{ -+ const char *p; -+ const char *end; -+ -+ p = text; -+ end = text + text_len; -+ -+ while (p != end) -+ { -+ if (!g_ascii_isspace (*p)) -+ return FALSE; -+ -+ p = g_utf8_next_char (p); -+ } -+ -+ return TRUE; -+} -+ -+static GSList * -+copy_tag_list (GSList *tag_list) -+{ -+ GSList *tmp = NULL; -+ -+ while (tag_list) -+ { -+ tmp = g_slist_prepend (tmp, g_strdup (tag_list->data)); -+ -+ tag_list = tag_list->next; -+ } -+ -+ return tmp; -+} -+ -+static void -+text_handler (GMarkupParseContext *context, -+ const gchar *text, -+ gsize text_len, -+ gpointer user_data, -+ GError **error) -+{ -+ ParseInfo *info = user_data; -+ TextSpan *span; -+ -+ if (all_whitespace (text, text_len) && -+ peek_state (info) != STATE_TEXT && -+ peek_state (info) != STATE_APPLY_TAG) -+ return; -+ -+ switch (peek_state (info)) -+ { -+ case STATE_START: -+ g_assert_not_reached (); /* gmarkup shouldn't do this */ -+ break; -+ case STATE_TEXT: -+ case STATE_APPLY_TAG: -+ if (text_len == 0) -+ return; -+ -+ span = g_new0 (TextSpan, 1); -+ span->text = g_strndup (text, text_len); -+ span->tags = copy_tag_list (info->tag_stack); -+ -+ info->spans = g_list_prepend (info->spans, span); -+ break; -+ default: -+ g_assert_not_reached (); -+ break; -+ } -+} -+ -+static void -+parse_info_init (ParseInfo *info, -+ GtkTextBuffer *buffer, -+ gboolean create_tags, -+ GList *headers) -+{ -+ info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START)); -+ -+ info->create_tags = create_tags; -+ info->headers = headers; -+ info->defined_tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); -+ info->substitutions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -+ info->tag_stack = NULL; -+ info->spans = NULL; -+ info->parsed_text = FALSE; -+ info->parsed_tags = FALSE; -+ info->current_tag = NULL; -+ info->current_tag_prio = -1; -+ info->tag_priorities = NULL; -+ -+ info->buffer = buffer; -+} -+ -+static void -+text_span_free (TextSpan *span) -+{ -+ GSList *tmp; -+ -+ g_free (span->text); -+ -+ tmp = span->tags; -+ while (tmp) -+ { -+ g_free (tmp->data); -+ -+ tmp = tmp->next; -+ } -+ g_slist_free (span->tags); -+ g_free (span); -+} -+ -+static void -+parse_info_free (ParseInfo *info) -+{ -+ GSList *slist; -+ GList *list; -+ -+ slist = info->tag_stack; -+ while (slist) -+ { -+ g_free (slist->data); -+ -+ slist = slist->next; -+ } -+ -+ g_slist_free (info->tag_stack); -+ g_slist_free (info->states); -+ -+ g_hash_table_destroy (info->substitutions); -+ g_hash_table_destroy (info->defined_tags); -+ -+ if (info->current_tag) -+ g_object_unref (info->current_tag); -+ -+ list = info->spans; -+ while (list) -+ { -+ text_span_free (list->data); -+ -+ list = list->next; -+ } -+ g_list_free (info->spans); -+ -+ list = info->tag_priorities; -+ while (list) -+ { -+ TextTagPrio *prio = list->data; -+ -+ if (prio->tag) -+ g_object_unref (prio->tag); -+ g_free (prio); -+ -+ list = list->next; -+ } -+ g_list_free (info->tag_priorities); -+ -+} -+ -+static const gchar * -+get_tag_substitution (ParseInfo *info, -+ const gchar *name) -+{ -+ gchar *subst; -+ -+ if ((subst = g_hash_table_lookup (info->substitutions, name))) -+ return subst; -+ else -+ return name; -+} -+ -+static void -+insert_text (ParseInfo *info, -+ GtkTextIter *iter) -+{ -+ GtkTextIter start_iter; -+ GtkTextMark *mark; -+ GList *tmp; -+ GSList *tags; -+ -+ start_iter = *iter; -+ -+ mark = gtk_text_buffer_create_mark (info->buffer, "deserialize_insert_point", -+ &start_iter, TRUE); -+ -+ tmp = info->spans; -+ while (tmp) -+ { -+ TextSpan *span = tmp->data; -+ -+ if (span->text) -+ gtk_text_buffer_insert (info->buffer, iter, span->text, -1); -+ else -+ { -+ gtk_text_buffer_insert_pixbuf (info->buffer, iter, span->pixbuf); -+ g_object_unref (span->pixbuf); -+ } -+ gtk_text_buffer_get_iter_at_mark (info->buffer, &start_iter, mark); -+ -+ /* Apply tags */ -+ tags = span->tags; -+ while (tags) -+ { -+ const gchar *tag_name = get_tag_substitution (info, tags->data); -+ -+ gtk_text_buffer_apply_tag_by_name (info->buffer, tag_name, -+ &start_iter, iter); -+ -+ tags = tags->next; -+ } -+ -+ gtk_text_buffer_move_mark (info->buffer, mark, iter); -+ -+ tmp = tmp->next; -+ } -+ -+ gtk_text_buffer_delete_mark (info->buffer, mark); -+} -+ -+ -+ -+static int -+read_int (const guchar *start) -+{ -+ int result; -+ -+ result = -+ start[0] << 24 | -+ start[1] << 16 | -+ start[2] << 8 | -+ start[3]; -+ -+ return result; -+} -+ -+static gboolean -+header_is (Header *header, const gchar *id) -+{ -+ return (strncmp (header->id, id, 8) == 0); -+} -+ -+static GList * -+read_headers (const gchar *start, -+ gint len, -+ GError **error) -+{ -+ int i = 0; -+ int section_len; -+ Header *header; -+ GList *headers = NULL; -+ -+ while (i < len) -+ { -+ if (i + 12 >= len) -+ goto error; -+ -+ if (strncmp (start + i, "RICHTEXT", 8) == 0 || -+ strncmp (start + i, "PIXBDATA", 8) == 0) -+ { -+ -+ section_len = read_int (start + i + 8); -+ -+ if (i + 12 + section_len > len) -+ goto error; -+ -+ header = g_new0 (Header, 1); -+ header->id = start + i; -+ header->length = section_len; -+ header->start = start + i + 12; -+ -+ i += 12 + section_len; -+ -+ headers = g_list_prepend (headers, header); -+ } -+ else -+ break; -+ -+ } -+ -+ return g_list_reverse (headers); -+ -+ error: -+ g_list_foreach (headers, (GFunc) g_free, NULL); -+ g_list_free (headers); -+ -+ g_set_error (error, -+ G_MARKUP_ERROR, -+ G_MARKUP_ERROR_PARSE, -+ _("Serialized data is malformed")); -+ -+ return NULL; -+} -+ -+static gboolean -+deserialize_text (GtkTextBuffer *buffer, -+ GtkTextIter *iter, -+ const gchar *text, -+ gint len, -+ gboolean create_tags, -+ GError **error, -+ GList *headers) -+{ -+ GMarkupParseContext *context; -+ ParseInfo info; -+ gboolean retval = FALSE; -+ -+ -+ static GMarkupParser rich_text_parser = { -+ start_element_handler, -+ end_element_handler, -+ text_handler, -+ NULL, -+ NULL -+ }; -+ -+ parse_info_init (&info, buffer, create_tags, headers); -+ -+ context = g_markup_parse_context_new (&rich_text_parser, -+ 0, &info, NULL); -+ -+ if (!g_markup_parse_context_parse (context, -+ text, -+ len, -+ error)) -+ goto out; -+ -+ if (!g_markup_parse_context_end_parse (context, error)) -+ goto out; -+ -+ retval = TRUE; -+ -+ /* Now insert the text */ -+ insert_text (&info, iter); -+ -+ out: -+ parse_info_free (&info); -+ -+ g_markup_parse_context_free (context); -+ -+ return retval; -+} -+ -+gboolean -+gtk_text_buffer_deserialize_rich_text (GtkTextBuffer *buffer, -+ GtkTextIter *iter, -+ const gchar *text, -+ gint len, -+ gboolean create_tags, -+ GError **error) -+{ -+ GList *headers; -+ Header *header; -+ gboolean retval; -+ -+ headers = read_headers (text, len, error); -+ -+ if (!headers) -+ return FALSE; -+ -+ header = headers->data; -+ if (!header_is (header, "RICHTEXT")) -+ { -+ g_set_error (error, -+ G_MARKUP_ERROR, -+ G_MARKUP_ERROR_PARSE, -+ _("Serialized data is malformed. First section isn't RICHTEXT")); -+ -+ retval = FALSE; -+ goto out; -+ } -+ -+ retval = deserialize_text (buffer, iter, -+ header->start, header->length, -+ create_tags, error, headers->next); -+ -+ out: -+ g_list_foreach (headers, (GFunc)g_free, NULL); -+ g_list_free (headers); -+ -+ return retval; -+} -- cgit v1.2.3