diff options
author | Benjamin Otte <otte@redhat.com> | 2017-11-27 04:17:36 +0100 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2017-11-29 23:03:33 -0500 |
commit | 3d4743ee62673415d3872d215fa472e883f5158f (patch) | |
tree | e94af811040dee9b612fb32ca78c9ec0cab92700 | |
parent | 138abdbc475f90b5d731d3a27c12f8649837ad6d (diff) | |
download | gtk+-3d4743ee62673415d3872d215fa472e883f5158f.tar.gz |
textview: Remove serialization API
It's unused. Plain text is not using that framework, neither is
in-process same-display transmission.
So it was only useful for sharing text with custom tags across
applications, and nobody is doing that.
-rw-r--r-- | docs/reference/gtk/gtk4-sections.txt | 19 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkclipboard.c | 185 | ||||
-rw-r--r-- | gtk/gtkclipboard.h | 8 | ||||
-rw-r--r-- | gtk/gtkselection.c | 132 | ||||
-rw-r--r-- | gtk/gtkselection.h | 11 | ||||
-rw-r--r-- | gtk/gtktextbuffer.c | 123 | ||||
-rw-r--r-- | gtk/gtktextbufferrichtext.c | 830 | ||||
-rw-r--r-- | gtk/gtktextbufferrichtext.h | 138 | ||||
-rw-r--r-- | gtk/gtktextbufferserialize.c | 1804 | ||||
-rw-r--r-- | gtk/gtktextbufferserialize.h | 41 | ||||
-rw-r--r-- | gtk/gtktextview.c | 67 | ||||
-rw-r--r-- | gtk/meson.build | 3 | ||||
-rw-r--r-- | tests/meson.build | 1 | ||||
-rw-r--r-- | tests/testrichtext.c | 190 |
15 files changed, 6 insertions, 3547 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index a408a813f2..afad3de656 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -2884,25 +2884,6 @@ gtk_text_buffer_end_user_action gtk_text_buffer_add_selection_clipboard gtk_text_buffer_remove_selection_clipboard -<SUBSECTION Serialization> -GtkTextBufferTargetInfo -GtkTextBufferDeserializeFunc -gtk_text_buffer_deserialize -gtk_text_buffer_deserialize_get_can_create_tags -gtk_text_buffer_deserialize_set_can_create_tags -gtk_text_buffer_get_copy_target_list -gtk_text_buffer_get_deserialize_formats -gtk_text_buffer_get_paste_target_list -gtk_text_buffer_get_serialize_formats -gtk_text_buffer_register_deserialize_format -gtk_text_buffer_register_deserialize_tagset -gtk_text_buffer_register_serialize_format -gtk_text_buffer_register_serialize_tagset -GtkTextBufferSerializeFunc -gtk_text_buffer_serialize -gtk_text_buffer_unregister_deserialize_format -gtk_text_buffer_unregister_serialize_format - <SUBSECTION Standard> GTK_TEXT_BUFFER GTK_IS_TEXT_BUFFER @@ -207,7 +207,6 @@ #include <gtk/gtkstyleprovider.h> #include <gtk/gtkswitch.h> #include <gtk/gtktextbuffer.h> -#include <gtk/gtktextbufferrichtext.h> #include <gtk/gtktextchild.h> #include <gtk/gtktextiter.h> #include <gtk/gtktextmark.h> diff --git a/gtk/gtkclipboard.c b/gtk/gtkclipboard.c index 20222259df..8ace68dfef 100644 --- a/gtk/gtkclipboard.c +++ b/gtk/gtkclipboard.c @@ -27,7 +27,6 @@ #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkselectionprivate.h" -#include "gtktextbufferrichtext.h" #include "gtkintl.h" #include "gdk/gdk-private.h" @@ -1065,80 +1064,6 @@ gtk_clipboard_request_text (GtkClipboard *clipboard, info); } -static void -request_rich_text_received_func (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - gpointer data) -{ - RequestRichTextInfo *info = data; - guint8 *result = NULL; - gsize length = 0; - - result = (guint8 *) gtk_selection_data_get_data (selection_data); - length = gtk_selection_data_get_length (selection_data); - - info->current_atom++; - - if ((!result || length < 1) && (info->current_atom < info->n_atoms)) - { - gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom], - request_rich_text_received_func, - info); - return; - } - - info->callback (clipboard, gtk_selection_data_get_target (selection_data), - result, length, - info->user_data); - g_free (info->atoms); - g_free (info); -} - -/** - * gtk_clipboard_request_rich_text: - * @clipboard: a #GtkClipboard - * @buffer: a #GtkTextBuffer - * @callback: (scope async): a function to call when the text is received, - * or the retrieval fails. (It will always be called one way or the other.) - * @user_data: user data to pass to @callback. - * - * Requests the contents of the clipboard as rich text. When the rich - * text is later received, @callback will be called. - * - * The @text parameter to @callback will contain the resulting rich - * text if the request succeeded, or %NULL if it failed. The @length - * parameter will contain @text’s length. This function can fail for - * various reasons, in particular if the clipboard was empty or if the - * contents of the clipboard could not be converted into rich text form. - * - * Since: 2.10 - **/ -void -gtk_clipboard_request_rich_text (GtkClipboard *clipboard, - GtkTextBuffer *buffer, - GtkClipboardRichTextReceivedFunc callback, - gpointer user_data) -{ - RequestRichTextInfo *info; - - g_return_if_fail (clipboard != NULL); - g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); - g_return_if_fail (callback != NULL); - - info = g_new (RequestRichTextInfo, 1); - info->callback = callback; - info->atoms = NULL; - info->n_atoms = 0; - info->current_atom = 0; - info->user_data = user_data; - - info->atoms = gtk_text_buffer_get_deserialize_formats (buffer, &info->n_atoms); - - gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom], - request_rich_text_received_func, - info); -} - static void request_image_received_func (GtkClipboard *clipboard, GtkSelectionData *selection_data, @@ -1455,77 +1380,6 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard) return results.data; } -static void -clipboard_rich_text_received_func (GtkClipboard *clipboard, - GdkAtom format, - const guint8 *text, - gsize length, - gpointer data) -{ - WaitResults *results = data; - - results->data = g_memdup (text, length); - results->format = format; - results->length = length; - g_main_loop_quit (results->loop); -} - -/** - * gtk_clipboard_wait_for_rich_text: - * @clipboard: a #GtkClipboard - * @buffer: a #GtkTextBuffer - * @format: (out): return location for the format of the returned data - * @length: (out): return location for the length of the returned data - * - * Requests the contents of the clipboard as rich text. This function - * waits for the data to be received using the main loop, so events, - * timeouts, etc, may be dispatched during the wait. - * - * Returns: (nullable) (array length=length) (transfer full): a - * newly-allocated binary block of data which must be - * freed with g_free(), or %NULL if retrieving the - * selection data failed. (This could happen for various - * reasons, in particular if the clipboard was empty or - * if the contents of the clipboard could not be - * converted into text form.) - * - * Since: 2.10 - **/ -guint8 * -gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard, - GtkTextBuffer *buffer, - GdkAtom *format, - gsize *length) -{ - WaitResults results; - - g_return_val_if_fail (clipboard != NULL, NULL); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (format != NULL, NULL); - g_return_val_if_fail (length != NULL, NULL); - - results.data = NULL; - results.loop = g_main_loop_new (NULL, TRUE); - - gtk_clipboard_request_rich_text (clipboard, buffer, - clipboard_rich_text_received_func, - &results); - - if (g_main_loop_is_running (results.loop)) - { - gdk_threads_leave (); - g_main_loop_run (results.loop); - gdk_threads_enter (); - } - - g_main_loop_unref (results.loop); - - *format = results.format; - *length = results.length; - - return results.data; -} - static void clipboard_image_received_func (GtkClipboard *clipboard, GdkPixbuf *pixbuf, @@ -1745,45 +1599,6 @@ gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard) } /** - * gtk_clipboard_wait_is_rich_text_available: - * @clipboard: a #GtkClipboard - * @buffer: a #GtkTextBuffer - * - * Test to see if there is rich text available to be pasted - * This is done by requesting the TARGETS atom and checking - * if it contains any of the supported rich text formats. This function - * waits for the data to be received using the main loop, so events, - * timeouts, etc, may be dispatched during the wait. - * - * This function is a little faster than calling - * gtk_clipboard_wait_for_rich_text() since it doesn’t need to retrieve - * the actual text. - * - * Returns: %TRUE is there is rich text available, %FALSE otherwise. - * - * Since: 2.10 - **/ -gboolean -gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard, - GtkTextBuffer *buffer) -{ - GtkSelectionData *data; - gboolean result = FALSE; - - g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); - - data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS")); - if (data) - { - result = gtk_selection_data_targets_include_rich_text (data, buffer); - gtk_selection_data_free (data); - } - - return result; -} - -/** * gtk_clipboard_wait_is_image_available: * @clipboard: a #GtkClipboard * diff --git a/gtk/gtkclipboard.h b/gtk/gtkclipboard.h index 0d353a4e3a..d69f41800d 100644 --- a/gtk/gtkclipboard.h +++ b/gtk/gtkclipboard.h @@ -229,11 +229,6 @@ void gtk_clipboard_request_text (GtkClipboard *clipboar GtkClipboardTextReceivedFunc callback, gpointer user_data); GDK_AVAILABLE_IN_ALL -void gtk_clipboard_request_rich_text (GtkClipboard *clipboard, - GtkTextBuffer *buffer, - GtkClipboardRichTextReceivedFunc callback, - gpointer user_data); -GDK_AVAILABLE_IN_ALL void gtk_clipboard_request_image (GtkClipboard *clipboard, GtkClipboardImageReceivedFunc callback, gpointer user_data); @@ -270,9 +265,6 @@ cairo_surface_t * gtk_clipboard_wait_for_surface (GtkClipboard *clipboard); GDK_AVAILABLE_IN_ALL gboolean gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard); GDK_AVAILABLE_IN_ALL -gboolean gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard, - GtkTextBuffer *buffer); -GDK_AVAILABLE_IN_ALL gboolean gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard); GDK_AVAILABLE_IN_ALL gboolean gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard); diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c index da5ed4855e..53603c60a1 100644 --- a/gtk/gtkselection.c +++ b/gtk/gtkselection.c @@ -86,7 +86,6 @@ #include "gtkmain.h" #include "gtkdebug.h" -#include "gtktextbufferrichtext.h" #include "gtkintl.h" #include "gdk-pixbuf/gdk-pixbuf.h" @@ -287,50 +286,6 @@ gtk_content_formats_add_text_targets (GdkContentFormats *list) } /** - * gtk_content_formats_add_rich_text_targets: - * @list: a #GdkContentFormats - * @deserializable: if %TRUE, then deserializable rich text formats - * will be added, serializable formats otherwise. - * @buffer: a #GtkTextBuffer. - * - * Appends the rich text targets registered with - * gtk_text_buffer_register_serialize_format() or - * gtk_text_buffer_register_deserialize_format() to the target list. All - * targets are added with the same @info. - * - * Since: 2.10 - **/ -GdkContentFormats * -gtk_content_formats_add_rich_text_targets (GdkContentFormats *list, - gboolean deserializable, - GtkTextBuffer *buffer) -{ - GdkContentFormatsBuilder *builder; - GdkAtom *atoms; - gint n_atoms; - gint i; - - g_return_val_if_fail (list != NULL, NULL); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - - builder = gdk_content_formats_builder_new (); - gdk_content_formats_builder_add_formats (builder, list); - gdk_content_formats_unref (list); - - if (deserializable) - atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms); - else - atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms); - - for (i = 0; i < n_atoms; i++) - gdk_content_formats_builder_add_mime_type (builder, atoms[i]); - - g_free (atoms); - - return gdk_content_formats_builder_free (builder); -} - -/** * gtk_content_formats_add_image_targets: * @list: a #GdkContentFormats * @writable: whether to add only targets for which GTK+ knows @@ -1783,56 +1738,6 @@ gtk_targets_include_text (GdkAtom *targets, } /** - * gtk_targets_include_rich_text: - * @targets: (array length=n_targets): an array of #GdkAtoms - * @n_targets: the length of @targets - * @buffer: a #GtkTextBuffer - * - * Determines if any of the targets in @targets can be used to - * provide rich text. - * - * Returns: %TRUE if @targets include a suitable target for rich text, - * otherwise %FALSE. - * - * Since: 2.10 - **/ -gboolean -gtk_targets_include_rich_text (GdkAtom *targets, - gint n_targets, - GtkTextBuffer *buffer) -{ - GdkAtom *rich_targets; - gint n_rich_targets; - gint i, j; - gboolean result = FALSE; - - g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); - - init_atoms (); - - rich_targets = gtk_text_buffer_get_deserialize_formats (buffer, - &n_rich_targets); - - for (i = 0; i < n_targets; i++) - { - for (j = 0; j < n_rich_targets; j++) - { - if (targets[i] == rich_targets[j]) - { - result = TRUE; - goto done; - } - } - } - - done: - g_free (rich_targets); - - return result; -} - -/** * gtk_selection_data_targets_include_text: * @selection_data: a #GtkSelectionData object * @@ -1864,43 +1769,6 @@ gtk_selection_data_targets_include_text (const GtkSelectionData *selection_data) } /** - * gtk_selection_data_targets_include_rich_text: - * @selection_data: a #GtkSelectionData object - * @buffer: a #GtkTextBuffer - * - * Given a #GtkSelectionData object holding a list of targets, - * determines if any of the targets in @targets can be used to - * provide rich text. - * - * Returns: %TRUE if @selection_data holds a list of targets, - * and a suitable target for rich text is included, - * otherwise %FALSE. - * - * Since: 2.10 - **/ -gboolean -gtk_selection_data_targets_include_rich_text (const GtkSelectionData *selection_data, - GtkTextBuffer *buffer) -{ - GdkAtom *targets; - gint n_targets; - gboolean result = FALSE; - - g_return_val_if_fail (selection_data != NULL, FALSE); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); - - init_atoms (); - - if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) - { - result = gtk_targets_include_rich_text (targets, n_targets, buffer); - g_free (targets); - } - - return result; -} - -/** * gtk_targets_include_image: * @targets: (array length=n_targets): an array of #GdkAtoms * @n_targets: the length of @targets diff --git a/gtk/gtkselection.h b/gtk/gtkselection.h index d597871964..3f0d69b7b4 100644 --- a/gtk/gtkselection.h +++ b/gtk/gtkselection.h @@ -39,10 +39,6 @@ G_BEGIN_DECLS GDK_AVAILABLE_IN_ALL GdkContentFormats * gtk_content_formats_add_text_targets (GdkContentFormats *list) G_GNUC_WARN_UNUSED_RESULT; GDK_AVAILABLE_IN_ALL -GdkContentFormats * gtk_content_formats_add_rich_text_targets (GdkContentFormats *list, - gboolean deserializable, - GtkTextBuffer *buffer) G_GNUC_WARN_UNUSED_RESULT; -GDK_AVAILABLE_IN_ALL GdkContentFormats * gtk_content_formats_add_image_targets (GdkContentFormats *list, gboolean writable) G_GNUC_WARN_UNUSED_RESULT; GDK_AVAILABLE_IN_ALL @@ -132,9 +128,6 @@ gboolean gtk_selection_data_get_targets (const GtkSelectionData *selec GDK_AVAILABLE_IN_ALL gboolean gtk_selection_data_targets_include_text (const GtkSelectionData *selection_data); GDK_AVAILABLE_IN_ALL -gboolean gtk_selection_data_targets_include_rich_text (const GtkSelectionData *selection_data, - GtkTextBuffer *buffer); -GDK_AVAILABLE_IN_ALL gboolean gtk_selection_data_targets_include_image (const GtkSelectionData *selection_data, gboolean writable); GDK_AVAILABLE_IN_ALL @@ -143,10 +136,6 @@ GDK_AVAILABLE_IN_ALL gboolean gtk_targets_include_text (GdkAtom *targets, gint n_targets); GDK_AVAILABLE_IN_ALL -gboolean gtk_targets_include_rich_text (GdkAtom *targets, - gint n_targets, - GtkTextBuffer *buffer); -GDK_AVAILABLE_IN_ALL gboolean gtk_targets_include_image (GdkAtom *targets, gint n_targets, gboolean writable); diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 010219452a..c55b895a5d 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -33,7 +33,6 @@ #include "gtkmarshalers.h" #include "gtktextbuffer.h" #include "gtktextbufferprivate.h" -#include "gtktextbufferrichtext.h" #include "gtktextbtree.h" #include "gtktextiterprivate.h" #include "gtktexttagprivate.h" @@ -644,9 +643,6 @@ gtk_text_buffer_init (GtkTextBuffer *buffer) buffer->priv = gtk_text_buffer_get_instance_private (buffer); buffer->priv->clipboard_contents_buffers = NULL; buffer->priv->tag_table = NULL; - - /* allow copying of arbiatray stuff in the internal rich text format */ - gtk_text_buffer_register_serialize_tagset (buffer, NULL); } static void @@ -3222,21 +3218,6 @@ clipboard_get_selection_cb (GtkClipboard *clipboard, (void*)&buffer, sizeof (buffer)); } - else if (gtk_selection_data_targets_include_rich_text (selection_data, buffer)) - { - guint8 *str; - gsize len; - - str = gtk_text_buffer_serialize (buffer, buffer, - gtk_selection_data_get_target (selection_data), - &start, &end, &len); - - gtk_selection_data_set (selection_data, - gtk_selection_data_get_target (selection_data), - 8, /* bytes */ - str, len); - g_free (str); - } else if (gtk_selection_data_targets_include_text (selection_data)) { gchar *str; @@ -3291,28 +3272,6 @@ clipboard_get_contents_cb (GtkClipboard *clipboard, (void*)&contents, sizeof (contents)); } - else if (gtk_selection_data_targets_include_rich_text (selection_data, contents)) - { - GtkTextBuffer *clipboard_source_buffer; - GtkTextIter start, end; - guint8 *str; - gsize len; - - clipboard_source_buffer = g_object_get_data (G_OBJECT (contents), - "gtk-text-buffer-clipboard-source"); - - gtk_text_buffer_get_bounds (contents, &start, &end); - - str = gtk_text_buffer_serialize (clipboard_source_buffer, contents, - gtk_selection_data_get_target (selection_data), - &start, &end, &len); - - gtk_selection_data_set (selection_data, - gtk_selection_data_get_target (selection_data), - 8, /* bytes */ - str, len); - g_free (str); - } else { gchar *str; @@ -3515,58 +3474,6 @@ restore_iter (const GtkTextIter *iter, #endif static void -clipboard_rich_text_received (GtkClipboard *clipboard, - GdkAtom format, - const guint8 *text, - gsize length, - gpointer data) -{ - ClipboardRequest *request_data = data; - GtkTextIter insert_point; - gboolean retval = TRUE; - GError *error = NULL; - - if (text != NULL && length > 0) - { - if (request_data->interactive) - gtk_text_buffer_begin_user_action (request_data->buffer); - - pre_paste_prep (request_data, &insert_point); - - if (!request_data->interactive || - gtk_text_iter_can_insert (&insert_point, - request_data->default_editable)) - { - retval = gtk_text_buffer_deserialize (request_data->buffer, - request_data->buffer, - format, - &insert_point, - text, length, - &error); - } - - if (!retval) - { - g_warning ("error pasting: %s\n", error->message); - g_clear_error (&error); - } - - if (request_data->interactive) - gtk_text_buffer_end_user_action (request_data->buffer); - - emit_paste_done (request_data->buffer, clipboard); - - if (retval) - return; - } - - /* Request the text selection instead */ - gtk_clipboard_request_text (clipboard, - clipboard_text_received, - data); -} - -static void paste_from_buffer (GtkClipboard *clipboard, ClipboardRequest *request_data, GtkTextBuffer *src_buffer, @@ -3646,22 +3553,10 @@ clipboard_clipboard_buffer_received (GtkClipboard *clipboard, } else { - if (gtk_clipboard_wait_is_rich_text_available (clipboard, - request_data->buffer)) - { - /* Request rich text */ - gtk_clipboard_request_rich_text (clipboard, - request_data->buffer, - clipboard_rich_text_received, - data); - } - else - { - /* Request the text selection instead */ - gtk_clipboard_request_text (clipboard, - clipboard_text_received, - data); - } + /* Request the text selection instead */ + gtk_clipboard_request_text (clipboard, + clipboard_text_received, + data); } } @@ -4016,10 +3911,6 @@ gtk_text_buffer_get_target_list (GtkTextBuffer *buffer, else target_list = gdk_content_formats_new (NULL, 0); - target_list = gtk_content_formats_add_rich_text_targets (target_list, - deserializable, - buffer); - target_list = gtk_content_formats_add_text_targets (target_list); return target_list; @@ -4224,8 +4115,7 @@ gtk_text_buffer_end_user_action (GtkTextBuffer *buffer) * This function returns the list of targets this text buffer can * provide for copying and as DND source. The targets in the list are * added with @info values from the #GtkTextBufferTargetInfo enum, - * using gdk_content_formats_add_rich_text_targets() and - * gdk_content_formats_add_text_targets(). + * using gdk_content_formats_add_text_targets(). * * Returns: (transfer none): the #GdkContentFormats * @@ -4254,8 +4144,7 @@ gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer) * This function returns the list of targets this text buffer supports * for pasting and as DND destination. The targets in the list are * added with @info values from the #GtkTextBufferTargetInfo enum, - * using gtk_content_formats_add_rich_text_targets() and - * gtk_content_formats_add_text_targets(). + * using gtk_content_formats_add_text_targets(). * * Returns: (transfer none): the #GdkContentFormats * diff --git a/gtk/gtktextbufferrichtext.c b/gtk/gtktextbufferrichtext.c deleted file mode 100644 index 4286d8b846..0000000000 --- a/gtk/gtktextbufferrichtext.c +++ /dev/null @@ -1,830 +0,0 @@ -/* gtkrichtext.c - * - * Copyright (C) 2006 Imendio AB - * Contact: Michael Natterer <mitch@imendio.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include <string.h> - -#include "gtktextbufferrichtext.h" -#include "gtktextbufferserialize.h" -#include "gtkintl.h" - - -typedef struct -{ - gchar *mime_type; - gboolean can_create_tags; - GdkAtom atom; - gpointer function; - gpointer user_data; - GDestroyNotify user_data_destroy; -} GtkRichTextFormat; - - -static GList * register_format (GList *formats, - const gchar *mime_type, - gpointer function, - gpointer user_data, - GDestroyNotify user_data_destroy, - GdkAtom *atom); -static GList * unregister_format (GList *formats, - GdkAtom atom); -static GdkAtom * get_formats (GList *formats, - gint *n_formats); -static void free_format (GtkRichTextFormat *format); -static void free_format_list (GList *formats); -static GQuark serialize_quark (void); -static GQuark deserialize_quark (void); - - -/** - * gtk_text_buffer_register_serialize_format: - * @buffer: a #GtkTextBuffer - * @mime_type: the format’s mime-type - * @function: the serialize function to register - * @user_data: @function’s user_data - * @user_data_destroy: a function to call when @user_data is no longer needed - * - * This function registers a rich text serialization @function along with - * its @mime_type with the passed @buffer. - * - * Returns: (transfer none): the #GdkAtom that corresponds to the - * newly registered format’s mime-type. - * - * Since: 2.10 - **/ -GdkAtom -gtk_text_buffer_register_serialize_format (GtkTextBuffer *buffer, - const gchar *mime_type, - GtkTextBufferSerializeFunc function, - gpointer user_data, - GDestroyNotify user_data_destroy) -{ - GList *formats; - GdkAtom atom; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', NULL); - g_return_val_if_fail (function != NULL, NULL); - - formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ()); - - formats = register_format (formats, mime_type, - (gpointer) function, - user_data, user_data_destroy, - &atom); - - g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (), - formats, (GDestroyNotify) free_format_list); - - g_object_notify (G_OBJECT (buffer), "copy-target-list"); - - return atom; -} - -/** - * gtk_text_buffer_register_serialize_tagset: - * @buffer: a #GtkTextBuffer - * @tagset_name: (allow-none): an optional tagset name, on %NULL - * - * This function registers GTK+’s internal rich text serialization - * format with the passed @buffer. The internal format does not comply - * to any standard rich text format and only works between #GtkTextBuffer - * instances. It is capable of serializing all of a text buffer’s tags - * and embedded pixbufs. - * - * This function is just a wrapper around - * gtk_text_buffer_register_serialize_format(). The mime type used - * for registering is “application/x-gtk-text-buffer-rich-text”, or - * “application/x-gtk-text-buffer-rich-text;format=@tagset_name” if a - * @tagset_name was passed. - * - * The @tagset_name can be used to restrict the transfer of rich text - * to buffers with compatible sets of tags, in order to avoid unknown - * tags from being pasted. It is probably the common case to pass an - * identifier != %NULL here, since the %NULL tagset requires the - * receiving buffer to deal with with pasting of arbitrary tags. - * - * Returns: (transfer none): the #GdkAtom that corresponds to the - * newly registered format’s mime-type. - * - * Since: 2.10 - **/ -GdkAtom -gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer, - const gchar *tagset_name) -{ - gchar *mime_type; - GdkAtom format; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', NULL); - - if (tagset_name) - { - mime_type = g_strconcat ("application/x-gtk-text-buffer-rich-text;format=", - tagset_name, - NULL); - } - else - { - mime_type = g_strdup ("application/x-gtk-text-buffer-rich-text"); - } - - format = gtk_text_buffer_register_serialize_format (buffer, mime_type, - _gtk_text_buffer_serialize_rich_text, - NULL, NULL); - - g_free (mime_type); - - return format; -} - -/** - * gtk_text_buffer_register_deserialize_format: - * @buffer: a #GtkTextBuffer - * @mime_type: the format’s mime-type - * @function: the deserialize function to register - * @user_data: @function’s user_data - * @user_data_destroy: a function to call when @user_data is no longer needed - * - * This function registers a rich text deserialization @function along with - * its @mime_type with the passed @buffer. - * - * Returns: (transfer none): the #GdkAtom that corresponds to the - * newly registered format’s mime-type. - * - * Since: 2.10 - **/ -GdkAtom -gtk_text_buffer_register_deserialize_format (GtkTextBuffer *buffer, - const gchar *mime_type, - GtkTextBufferDeserializeFunc function, - gpointer user_data, - GDestroyNotify user_data_destroy) -{ - GList *formats; - GdkAtom atom; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', NULL); - g_return_val_if_fail (function != NULL, NULL); - - formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ()); - - formats = register_format (formats, mime_type, - (gpointer) function, - user_data, user_data_destroy, - &atom); - - g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (), - formats, (GDestroyNotify) free_format_list); - - g_object_notify (G_OBJECT (buffer), "paste-target-list"); - - return atom; -} - -/** - * gtk_text_buffer_register_deserialize_tagset: - * @buffer: a #GtkTextBuffer - * @tagset_name: (allow-none): an optional tagset name, on %NULL - * - * This function registers GTK+’s internal rich text serialization - * format with the passed @buffer. See - * gtk_text_buffer_register_serialize_tagset() for details. - * - * Returns: (transfer none): the #GdkAtom that corresponds to the - * newly registered format’s mime-type. - * - * Since: 2.10 - **/ -GdkAtom -gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer, - const gchar *tagset_name) -{ - gchar *mime_type; - GdkAtom format; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', NULL); - - if (tagset_name) - { - mime_type = g_strconcat ("application/x-gtk-text-buffer-rich-text;format=", - tagset_name, - NULL); - } - else - { - mime_type = g_strdup ("application/x-gtk-text-buffer-rich-text"); - } - - format = gtk_text_buffer_register_deserialize_format (buffer, mime_type, - _gtk_text_buffer_deserialize_rich_text, - NULL, NULL); - - g_free (mime_type); - - return format; -} - -/** - * gtk_text_buffer_unregister_serialize_format: - * @buffer: a #GtkTextBuffer - * @format: a #GdkAtom representing a registered rich text format. - * - * This function unregisters a rich text format that was previously - * registered using gtk_text_buffer_register_serialize_format() or - * gtk_text_buffer_register_serialize_tagset() - * - * Since: 2.10 - **/ -void -gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer, - GdkAtom format) -{ - GList *formats; - - g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); - g_return_if_fail (format != NULL); - - formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ()); - - formats = unregister_format (formats, format); - - g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (), - formats, (GDestroyNotify) free_format_list); - - g_object_notify (G_OBJECT (buffer), "copy-target-list"); -} - -/** - * gtk_text_buffer_unregister_deserialize_format: - * @buffer: a #GtkTextBuffer - * @format: a #GdkAtom representing a registered rich text format. - * - * This function unregisters a rich text format that was previously - * registered using gtk_text_buffer_register_deserialize_format() or - * gtk_text_buffer_register_deserialize_tagset(). - * - * Since: 2.10 - **/ -void -gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer, - GdkAtom format) -{ - GList *formats; - - g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); - g_return_if_fail (format != NULL); - - formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ()); - - formats = unregister_format (formats, format); - - g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (), - formats, (GDestroyNotify) free_format_list); - - g_object_notify (G_OBJECT (buffer), "paste-target-list"); -} - -/** - * gtk_text_buffer_deserialize_set_can_create_tags: - * @buffer: a #GtkTextBuffer - * @format: a #GdkAtom representing a registered rich text format - * @can_create_tags: whether deserializing this format may create tags - * - * Use this function to allow a rich text deserialization function to - * create new tags in the receiving buffer. Note that using this - * function is almost always a bad idea, because the rich text - * functions you register should know how to map the rich text format - * they handler to your text buffers set of tags. - * - * The ability of creating new (arbitrary!) tags in the receiving buffer - * is meant for special rich text formats like the internal one that - * is registered using gtk_text_buffer_register_deserialize_tagset(), - * because that format is essentially a dump of the internal structure - * of the source buffer, including its tag names. - * - * You should allow creation of tags only if you know what you are - * doing, e.g. if you defined a tagset name for your application - * suite’s text buffers and you know that it’s fine to receive new - * tags from these buffers, because you know that your application can - * handle the newly created tags. - * - * Since: 2.10 - **/ -void -gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer, - GdkAtom format, - gboolean can_create_tags) -{ - GList *formats; - GList *list; - gchar *format_name; - - g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); - g_return_if_fail (format != NULL); - - formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ()); - - for (list = formats; list; list = list->next) - { - GtkRichTextFormat *fmt = list->data; - - if (fmt->atom == format) - { - fmt->can_create_tags = can_create_tags ? TRUE : FALSE; - return; - } - } - - format_name = gdk_atom_name (format); - g_warning ("%s: \"%s\" is not registered as deserializable format " - "with text buffer %p", - G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer); - g_free (format_name); -} - -/** - * gtk_text_buffer_deserialize_get_can_create_tags: - * @buffer: a #GtkTextBuffer - * @format: a #GdkAtom representing a registered rich text format - * - * This functions returns the value set with - * gtk_text_buffer_deserialize_set_can_create_tags() - * - * Returns: whether deserializing this format may create tags - * - * Since: 2.10 - **/ -gboolean -gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer, - GdkAtom format) -{ - GList *formats; - GList *list; - gchar *format_name; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); - g_return_val_if_fail (format != NULL, FALSE); - - formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ()); - - for (list = formats; list; list = list->next) - { - GtkRichTextFormat *fmt = list->data; - - if (fmt->atom == format) - { - return fmt->can_create_tags; - } - } - - format_name = gdk_atom_name (format); - g_warning ("%s: \"%s\" is not registered as deserializable format " - "with text buffer %p", - G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer); - g_free (format_name); - - return FALSE; -} - -/** - * gtk_text_buffer_get_serialize_formats: - * @buffer: a #GtkTextBuffer - * @n_formats: (out): return location for the number of formats - * - * This function returns the rich text serialize formats registered - * with @buffer using gtk_text_buffer_register_serialize_format() or - * gtk_text_buffer_register_serialize_tagset() - * - * Returns: (array length=n_formats) (transfer container): an array of - * #GdkAtoms representing the registered formats. - * - * Since: 2.10 - **/ -GdkAtom * -gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer, - gint *n_formats) -{ - GList *formats; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (n_formats != NULL, NULL); - - formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ()); - - return get_formats (formats, n_formats); -} - -/** - * gtk_text_buffer_get_deserialize_formats: - * @buffer: a #GtkTextBuffer - * @n_formats: (out): return location for the number of formats - * - * This function returns the rich text deserialize formats registered - * with @buffer using gtk_text_buffer_register_deserialize_format() or - * gtk_text_buffer_register_deserialize_tagset() - * - * Returns: (array length=n_formats) (transfer container): an array of - * #GdkAtoms representing the registered formats. - * - * Since: 2.10 - **/ -GdkAtom * -gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer, - gint *n_formats) -{ - GList *formats; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); - g_return_val_if_fail (n_formats != NULL, NULL); - - formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ()); - - return get_formats (formats, n_formats); -} - -/** - * gtk_text_buffer_serialize: - * @register_buffer: the #GtkTextBuffer @format is registered with - * @content_buffer: the #GtkTextBuffer to serialize - * @format: the rich text format to use for serializing - * @start: start of block of text to serialize - * @end: end of block of test to serialize - * @length: (out): return location for the length of the serialized data - * - * This function serializes the portion of text between @start - * and @end in the rich text format represented by @format. - * - * @formats to be used must be registered using - * gtk_text_buffer_register_serialize_format() or - * gtk_text_buffer_register_serialize_tagset() beforehand. - * - * Returns: (array length=length) (transfer full): the serialized - * data, encoded as @format - * - * Since: 2.10 - **/ -guint8 * -gtk_text_buffer_serialize (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GdkAtom format, - const GtkTextIter *start, - const GtkTextIter *end, - gsize *length) -{ - GList *formats; - GList *list; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), NULL); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), NULL); - g_return_val_if_fail (format != NULL, NULL); - g_return_val_if_fail (start != NULL, NULL); - g_return_val_if_fail (end != NULL, NULL); - g_return_val_if_fail (length != NULL, NULL); - - *length = 0; - - formats = g_object_get_qdata (G_OBJECT (register_buffer), - serialize_quark ()); - - for (list = formats; list; list = list->next) - { - GtkRichTextFormat *fmt = list->data; - - if (fmt->atom == format) - { - GtkTextBufferSerializeFunc function = fmt->function; - - return function (register_buffer, content_buffer, - start, end, length, fmt->user_data); - } - } - - return NULL; -} - -/** - * gtk_text_buffer_deserialize: - * @register_buffer: the #GtkTextBuffer @format is registered with - * @content_buffer: the #GtkTextBuffer to deserialize into - * @format: the rich text format to use for deserializing - * @iter: insertion point for the deserialized text - * @data: (array length=length): data to deserialize - * @length: length of @data - * @error: return location for a #GError - * - * This function deserializes rich text in format @format and inserts - * it at @iter. - * - * @formats to be used must be registered using - * gtk_text_buffer_register_deserialize_format() or - * gtk_text_buffer_register_deserialize_tagset() beforehand. - * - * Returns: %TRUE on success, %FALSE otherwise. - * - * Since: 2.10 - **/ -gboolean -gtk_text_buffer_deserialize (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GdkAtom format, - GtkTextIter *iter, - const guint8 *data, - gsize length, - GError **error) -{ - GList *formats; - GList *l; - - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), FALSE); - g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), FALSE); - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (length > 0, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - formats = g_object_get_qdata (G_OBJECT (register_buffer), deserialize_quark ()); - - for (l = formats; l; l = l->next) - { - GtkRichTextFormat *fmt = l->data; - - if (fmt->atom == format) - { - GtkTextBufferDeserializeFunc function = fmt->function; - gboolean success; - GSList *split_tags; - GSList *list; - GtkTextMark *left_end = NULL; - GtkTextMark *right_start = NULL; - GSList *left_start_list = NULL; - GSList *right_end_list = NULL; - - /* We don't want the tags that are effective at the insertion - * point to affect the pasted text, therefore we remove and - * remember them, so they can be re-applied left and right of - * the inserted text after pasting - */ - split_tags = gtk_text_iter_get_tags (iter); - - list = split_tags; - while (list) - { - GtkTextTag *tag = list->data; - - list = list->next; - - /* If a tag starts at the insertion point, ignore it - * because it doesn't affect the pasted text - */ - if (gtk_text_iter_starts_tag (iter, tag)) - split_tags = g_slist_remove (split_tags, tag); - } - - if (split_tags) - { - /* Need to remember text marks, because text iters - * don't survive pasting - */ - left_end = gtk_text_buffer_create_mark (content_buffer, - NULL, iter, TRUE); - right_start = gtk_text_buffer_create_mark (content_buffer, - NULL, iter, FALSE); - - for (list = split_tags; list; list = list->next) - { - GtkTextTag *tag = list->data; - GtkTextIter *backward_toggle = gtk_text_iter_copy (iter); - GtkTextIter *forward_toggle = gtk_text_iter_copy (iter); - GtkTextMark *left_start = NULL; - GtkTextMark *right_end = NULL; - - gtk_text_iter_backward_to_tag_toggle (backward_toggle, tag); - left_start = gtk_text_buffer_create_mark (content_buffer, - NULL, - backward_toggle, - FALSE); - - gtk_text_iter_forward_to_tag_toggle (forward_toggle, tag); - right_end = gtk_text_buffer_create_mark (content_buffer, - NULL, - forward_toggle, - TRUE); - - left_start_list = g_slist_prepend (left_start_list, left_start); - right_end_list = g_slist_prepend (right_end_list, right_end); - - gtk_text_buffer_remove_tag (content_buffer, tag, - backward_toggle, - forward_toggle); - - gtk_text_iter_free (forward_toggle); - gtk_text_iter_free (backward_toggle); - } - - left_start_list = g_slist_reverse (left_start_list); - right_end_list = g_slist_reverse (right_end_list); - } - - success = function (register_buffer, content_buffer, - iter, data, length, - fmt->can_create_tags, - fmt->user_data, - error); - - if (!success && error != NULL && *error == NULL) - g_set_error (error, 0, 0, - _("Unknown error when trying to deserialize %s"), - gdk_atom_name (format)); - - if (split_tags) - { - GSList *left_list; - GSList *right_list; - GtkTextIter left_e; - GtkTextIter right_s; - - /* Turn the remembered marks back into iters so they - * can by used to re-apply the remembered tags - */ - gtk_text_buffer_get_iter_at_mark (content_buffer, - &left_e, left_end); - gtk_text_buffer_get_iter_at_mark (content_buffer, - &right_s, right_start); - - for (list = split_tags, - left_list = left_start_list, - right_list = right_end_list; - list && left_list && right_list; - list = list->next, - left_list = left_list->next, - right_list = right_list->next) - { - GtkTextTag *tag = list->data; - GtkTextMark *left_start = left_list->data; - GtkTextMark *right_end = right_list->data; - GtkTextIter left_s; - GtkTextIter right_e; - - gtk_text_buffer_get_iter_at_mark (content_buffer, - &left_s, left_start); - gtk_text_buffer_get_iter_at_mark (content_buffer, - &right_e, right_end); - - gtk_text_buffer_apply_tag (content_buffer, tag, - &left_s, &left_e); - gtk_text_buffer_apply_tag (content_buffer, tag, - &right_s, &right_e); - - gtk_text_buffer_delete_mark (content_buffer, left_start); - gtk_text_buffer_delete_mark (content_buffer, right_end); - } - - gtk_text_buffer_delete_mark (content_buffer, left_end); - gtk_text_buffer_delete_mark (content_buffer, right_start); - - g_slist_free (split_tags); - g_slist_free (left_start_list); - g_slist_free (right_end_list); - } - - return success; - } - } - - g_set_error (error, 0, 0, - _("No deserialize function found for format %s"), - gdk_atom_name (format)); - - return FALSE; -} - - -/* private functions */ - -static GList * -register_format (GList *formats, - const gchar *mime_type, - gpointer function, - gpointer user_data, - GDestroyNotify user_data_destroy, - GdkAtom *atom) -{ - GtkRichTextFormat *format; - - *atom = gdk_atom_intern (mime_type, FALSE); - - formats = unregister_format (formats, *atom); - - format = g_slice_new0 (GtkRichTextFormat); - - format->mime_type = g_strdup (mime_type); - format->can_create_tags = FALSE; - format->atom = *atom; - format->function = function; - format->user_data = user_data; - format->user_data_destroy = user_data_destroy; - - return g_list_append (formats, format); -} - -static GList * -unregister_format (GList *formats, - GdkAtom atom) -{ - GList *list; - - for (list = formats; list; list = list->next) - { - GtkRichTextFormat *format = list->data; - - if (format->atom == atom) - { - free_format (format); - - return g_list_delete_link (formats, list); - } - } - - return formats; -} - -static GdkAtom * -get_formats (GList *formats, - gint *n_formats) -{ - GdkAtom *array; - GList *list; - gint i; - - *n_formats = g_list_length (formats); - array = g_new0 (GdkAtom, *n_formats); - - for (list = formats, i = 0; list; list = list->next, i++) - { - GtkRichTextFormat *format = list->data; - - array[i] = format->atom; - } - - return array; -} - -static void -free_format (GtkRichTextFormat *format) -{ - if (format->user_data_destroy) - format->user_data_destroy (format->user_data); - - g_free (format->mime_type); - g_slice_free (GtkRichTextFormat, format); -} - -static void -free_format_list (GList *formats) -{ - g_list_free_full (formats, (GDestroyNotify) free_format); -} - -static GQuark -serialize_quark (void) -{ - static GQuark quark = 0; - - if (! quark) - quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats"); - - return quark; -} - -static GQuark -deserialize_quark (void) -{ - static GQuark quark = 0; - - if (! quark) - quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats"); - - return quark; -} diff --git a/gtk/gtktextbufferrichtext.h b/gtk/gtktextbufferrichtext.h deleted file mode 100644 index ecc11001b7..0000000000 --- a/gtk/gtktextbufferrichtext.h +++ /dev/null @@ -1,138 +0,0 @@ -/* gtkrichtext.h - * - * Copyright (C) 2006 Imendio AB - * Contact: Michael Natterer <mitch@imendio.com> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __GTK_TEXT_BUFFER_RICH_TEXT_H__ -#define __GTK_TEXT_BUFFER_RICH_TEXT_H__ - -#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) -#error "Only <gtk/gtk.h> can be included directly." -#endif - -#include <gtk/gtktextbuffer.h> - -G_BEGIN_DECLS - -/** - * GtkTextBufferSerializeFunc: - * @register_buffer: the #GtkTextBuffer for which the format is registered - * @content_buffer: the #GtkTextBuffer to serialize - * @start: start of the block of text to serialize - * @end: end of the block of text to serialize - * @length: Return location for the length of the serialized data - * @user_data: user data that was specified when registering the format - * - * A function that is called to serialize the content of a text buffer. - * It must return the serialized form of the content. - * - * Returns: (nullable): a newly-allocated array of guint8 which contains - * the serialized data, or %NULL if an error occurred - */ -typedef guint8 * (* GtkTextBufferSerializeFunc) (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - const GtkTextIter *start, - const GtkTextIter *end, - gsize *length, - gpointer user_data); - -/** - * GtkTextBufferDeserializeFunc: - * @register_buffer: the #GtkTextBuffer the format is registered with - * @content_buffer: the #GtkTextBuffer to deserialize into - * @iter: insertion point for the deserialized text - * @data: (array length=length): data to deserialize - * @length: length of @data - * @create_tags: %TRUE if deserializing may create tags - * @user_data: user data that was specified when registering the format - * @error: return location for a #GError - * - * A function that is called to deserialize rich text that has been - * serialized with gtk_text_buffer_serialize(), and insert it at @iter. - * - * Returns: %TRUE on success, %FALSE otherwise - */ -typedef gboolean (* GtkTextBufferDeserializeFunc) (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GtkTextIter *iter, - const guint8 *data, - gsize length, - gboolean create_tags, - gpointer user_data, - GError **error); - -GDK_AVAILABLE_IN_ALL -GdkAtom gtk_text_buffer_register_serialize_format (GtkTextBuffer *buffer, - const gchar *mime_type, - GtkTextBufferSerializeFunc function, - gpointer user_data, - GDestroyNotify user_data_destroy); -GDK_AVAILABLE_IN_ALL -GdkAtom gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer, - const gchar *tagset_name); - -GDK_AVAILABLE_IN_ALL -GdkAtom gtk_text_buffer_register_deserialize_format (GtkTextBuffer *buffer, - const gchar *mime_type, - GtkTextBufferDeserializeFunc function, - gpointer user_data, - GDestroyNotify user_data_destroy); -GDK_AVAILABLE_IN_ALL -GdkAtom gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer, - const gchar *tagset_name); - -GDK_AVAILABLE_IN_ALL -void gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer, - GdkAtom format); -GDK_AVAILABLE_IN_ALL -void gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer, - GdkAtom format); - -GDK_AVAILABLE_IN_ALL -void gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer, - GdkAtom format, - gboolean can_create_tags); -GDK_AVAILABLE_IN_ALL -gboolean gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer, - GdkAtom format); - -GDK_AVAILABLE_IN_ALL -GdkAtom * gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer, - gint *n_formats); -GDK_AVAILABLE_IN_ALL -GdkAtom * gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer, - gint *n_formats); - -GDK_AVAILABLE_IN_ALL -guint8 * gtk_text_buffer_serialize (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GdkAtom format, - const GtkTextIter *start, - const GtkTextIter *end, - gsize *length); -GDK_AVAILABLE_IN_ALL -gboolean gtk_text_buffer_deserialize (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GdkAtom format, - GtkTextIter *iter, - const guint8 *data, - gsize length, - GError **error); - -G_END_DECLS - -#endif /* __GTK_TEXT_BUFFER_RICH_TEXT_H__ */ diff --git a/gtk/gtktextbufferserialize.c b/gtk/gtktextbufferserialize.c deleted file mode 100644 index 5df71c6ff2..0000000000 --- a/gtk/gtktextbufferserialize.c +++ /dev/null @@ -1,1804 +0,0 @@ -/* gtktextbufferserialize.c - * - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2004 Nokia Corporation - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -/* FIXME: We should use other error codes for the - * parts that deal with the format errors - */ - -#include "config.h" - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> - -#include "gdk-pixbuf/gdk-pixdata.h" -#include "gtktextbufferserialize.h" -#include "gtktexttagprivate.h" -#include "gtkintl.h" - - -typedef struct -{ - GString *tag_table_str; - GString *text_str; - GHashTable *tags; - GtkTextIter start, end; - - gint n_pixbufs; - GList *pixbufs; - gint tag_id; - GHashTable *tag_id_tags; -} SerializationContext; - -static gchar * -serialize_value (GValue *value) -{ -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - if (g_value_type_transformable (value->g_type, G_TYPE_STRING)) - { - GValue text_value = G_VALUE_INIT; - 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 - { - g_warning ("Type %s is not serializable", g_type_name (value->g_type)); - } -G_GNUC_END_IGNORE_DEPRECATIONS - - return NULL; -} - -static gboolean -deserialize_value (const gchar *str, - GValue *value) -{ -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - if (g_value_type_transformable (G_TYPE_STRING, value->g_type)) - { - GValue text_value = G_VALUE_INIT; - 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; - - errno = 0; - v = g_ascii_strtoll (str, &tmp, 10); - - if (errno || 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 (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", g_type_name (value->g_type)); - } -G_GNUC_END_IGNORE_DEPRECATIONS - - 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) -{ - 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; - gint tag_id; - GParamSpec **pspecs; - guint n_pspecs; - int i; - - g_string_append (context->tag_table_str, " <tag "); - - /* Handle anonymous tags */ - if (tag->priv->name) - { - tag_name = g_markup_escape_text (tag->priv->name, -1); - g_string_append_printf (context->tag_table_str, "name=\"%s\"", tag_name); - g_free (tag_name); - } - else - { - tag_id = GPOINTER_TO_INT (g_hash_table_lookup (context->tag_id_tags, tag)); - - g_string_append_printf (context->tag_table_str, "id=\"%d\"", tag_id); - } - - g_string_append_printf (context->tag_table_str, " priority=\"%d\">\n", tag->priv->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 = G_VALUE_INIT; - 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 */ - tmp2 = serialize_value (&value); - - if (tmp2) - { - tmp = g_markup_escape_text (pspecs[i]->name, -1); - g_string_append_printf (context->tag_table_str, " <attr name=\"%s\" ", tmp); - g_free (tmp); - - tmp = g_markup_escape_text (g_type_name (pspecs[i]->value_type), -1); - 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, " </tag>\n"); -} - -static void -serialize_tags (SerializationContext *context) -{ - g_string_append (context->tag_table_str, " <text_view_markup>\n"); - g_string_append (context->tag_table_str, " <tags>\n"); - g_hash_table_foreach (context->tags, serialize_tag, context); - g_string_append (context->tag_table_str, " </tags>\n"); -} - -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) == 26); - - 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; - GSList *active_tags; - - g_string_append (context->text_str, "<text>"); - - iter = context->start; - tag_list = NULL; - active_tags = NULL; - - 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 */ - for (tmp = removed; tmp; tmp = tmp->next) - { - GtkTextTag *tag = tmp->data; - - /* 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>"); - - /* 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>"); - } - - active_tags = g_slist_remove (active_tags, active_tags->data); - } - } - - /* Handle added tags */ - for (tmp = added; tmp; tmp = tmp->next) - { - GtkTextTag *tag = tmp->data; - gchar *tag_name; - - /* Add it to the tag hash table */ - g_hash_table_insert (context->tags, tag, tag); - - if (tag->priv->name) - { - tag_name = g_markup_escape_text (tag->priv->name, -1); - - g_string_append_printf (context->text_str, "<apply_tag name=\"%s\">", tag_name); - g_free (tag_name); - } - else - { - gpointer tag_id; - - /* We've got an anonymous tag, find out if it's been - used before */ - if (!g_hash_table_lookup_extended (context->tag_id_tags, tag, NULL, &tag_id)) - { - tag_id = GINT_TO_POINTER (context->tag_id++); - - g_hash_table_insert (context->tag_id_tags, tag, tag_id); - } - - g_string_append_printf (context->text_str, "<apply_tag id=\"%d\">", GPOINTER_TO_INT (tag_id)); - } - - 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 (TRUE) - { - gunichar ch = gtk_text_iter_get_char (&iter); - - if (ch == 0xFFFC) - { - GdkPixbuf *pixbuf = gtk_text_iter_get_pixbuf (&iter); - - if (pixbuf) - { - /* Append the text before the pixbuf */ - tmp_text = gtk_text_iter_get_slice (&old_iter, &iter); - escaped_text = g_markup_escape_text (tmp_text, -1); - g_free (tmp_text); - - /* Forward so we don't get the 0xfffc char */ - gtk_text_iter_forward_char (&iter); - old_iter = iter; - - g_string_append (context->text_str, escaped_text); - g_free (escaped_text); - - g_string_append_printf (context->text_str, "<pixbuf index=\"%d\" />", context->n_pixbufs); - - context->n_pixbufs++; - context->pixbufs = g_list_prepend (context->pixbufs, pixbuf); - } - } - else if (ch == 0) - { - break; - } - else - 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)); - - g_slist_free (tag_list); - - /* Close any open tags */ - for (tag_list = active_tags; tag_list; tag_list = tag_list->next) - g_string_append (context->text_str, "</apply_tag>"); - - g_slist_free (active_tags); - g_string_append (context->text_str, "</text>\n</text_view_markup>\n"); -} - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -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, "GTKTEXTBUFFERPIXBDATA-0001", len); - g_string_append_len (text, (gchar *) tmp, len); - g_free (tmp); - } -} -G_GNUC_END_IGNORE_DEPRECATIONS - -guint8 * -_gtk_text_buffer_serialize_rich_text (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - const GtkTextIter *start, - const GtkTextIter *end, - gsize *length, - gpointer user_data) -{ - 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; - context.tag_id = 0; - context.tag_id_tags = g_hash_table_new (NULL, NULL); - - /* We need to serialize the text before the tag table so we know - what tags are used */ - serialize_text (content_buffer, &context); - serialize_tags (&context); - - text = g_string_new (NULL); - serialize_section_header (text, "GTKTEXTBUFFERCONTENTS-0001", - 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); - g_hash_table_destroy (context.tag_id_tags); - - *length = text->len; - - return (guint8 *) 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 <tag> elements */ - GHashTable *defined_tags; - - /* Tags that are anonymous */ - GHashTable *anonymous_tags; - - /* Tag name substitutions */ - GHashTable *substitutions; - - /* Current tag */ - GtkTextTag *current_tag; - - /* Priority of current tag */ - gint current_tag_prio; - - /* Id of current tag */ - gint current_tag_id; - - /* 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, - ...) G_GNUC_PRINTF (5, 6); - -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) - - -static gboolean -check_id_or_name (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gint *id, - const gchar **name, - GError **error) -{ - gboolean has_id = FALSE; - gboolean has_name = FALSE; - int i; - - *id = 0; - *name = NULL; - - for (i = 0; attribute_names[i] != NULL; i++) - { - if (strcmp (attribute_names[i], "name") == 0) - { - *name = attribute_values[i]; - - if (has_id) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Both “id” and “name” were found on the <%s> element"), - element_name); - return FALSE; - } - - if (has_name) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("The attribute “%s” was found twice on the <%s> element"), - "name", element_name); - return FALSE; - } - - has_name = TRUE; - } - else if (strcmp (attribute_names[i], "id") == 0) - { - gchar *tmp; - - if (has_name) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Both “id” and “name” were found on the <%s> element"), - element_name); - return FALSE; - } - - if (has_id) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("The attribute “%s” was found twice on the <%s> element"), - "id", element_name); - return FALSE; - } - - has_id = TRUE; - - /* Try parsing the integer */ - tmp = NULL; - errno = 0; - *id = g_ascii_strtoll (attribute_values[i], &tmp, 10); - - if (errno || tmp == attribute_values[i]) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> element has invalid ID “%s”"), element_name, attribute_values[i]); - return FALSE; - } - } - } - - if (!has_id && !has_name) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> element has neither a “name” nor an “id” attribute"), element_name); - return FALSE; - } - - return TRUE; -} - -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, - gboolean allow_unknown_attrs, - 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 && !allow_unknown_attrs) - { - 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 GtkTextTag * -tag_exists (GMarkupParseContext *context, - const gchar *name, - gint id, - ParseInfo *info, - GError **error) -{ - GtkTextTagTable *tag_table; - const gchar *real_name; - - tag_table = gtk_text_buffer_get_tag_table (info->buffer); - - if (info->create_tags) - { - /* If we have an anonymous tag, just return it directly */ - if (!name) - return g_hash_table_lookup (info->anonymous_tags, - GINT_TO_POINTER (id)); - - /* First, try the substitutions */ - real_name = g_hash_table_lookup (info->substitutions, name); - - if (real_name) - return gtk_text_tag_table_lookup (tag_table, real_name); - - /* Next, try the list of defined tags */ - if (g_hash_table_lookup (info->defined_tags, name) != NULL) - return gtk_text_tag_table_lookup (tag_table, name); - - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Tag “%s” has not been defined."), name); - - return NULL; - } - else - { - GtkTextTag *tag; - - if (!name) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Anonymous tag found and tags can not be created.")); - return NULL; - } - - tag = gtk_text_tag_table_lookup (tag_table, name); - - if (tag) - return tag; - - 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; - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -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, - (const guint8 *) header->start, error)) - return NULL; - - pixbuf = gdk_pixbuf_from_pixdata (&pixdata, TRUE, error); - - return pixbuf; -} -G_GNUC_END_IGNORE_DEPRECATIONS - -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, *priority; - gint id; - GtkTextTag *tag; - - 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, TRUE, error, - "priority", &priority, NULL)) - return; - - if (!check_id_or_name (context, element_name, attribute_names, attribute_values, - &id, &name, error)) - return; - - - tag = tag_exists (context, name, id, info, error); - - if (!tag) - return; - - info->tag_stack = g_slist_prepend (info->tag_stack, tag); - - push_state (info, STATE_APPLY_TAG); - } - else if (ELEMENT_IS ("pixbuf")) - { - int int_id; - GdkPixbuf *pixbuf; - TextSpan *span; - const gchar *pixbuf_id; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE, error, - "index", &pixbuf_id, NULL)) - return; - - int_id = atoi (pixbuf_id); - pixbuf = get_pixbuf_from_headers (info->headers, int_id, error); - - span = g_slice_new0 (TextSpan); - 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 = G_VALUE_INIT; - GParamSpec *pspec; - - g_assert (peek_state (info) == STATE_TAG); - - if (ELEMENT_IS ("attr")) - { - if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE, 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 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) -{ - GtkTextTagTable *tag_table; - gchar *name; - gint i; - - name = g_strdup (tag_name); - - if (!info->create_tags) - return name; - - i = 0; - tag_table = gtk_text_buffer_get_tag_table (info->buffer); - - while (gtk_text_tag_table_lookup (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 id; - 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, TRUE, error, - "priority", &priority, NULL)) - return; - - if (!check_id_or_name (context, element_name, attribute_names, attribute_values, - &id, &name, error)) - return; - - if (name) - { - 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; - } - } - - tmp = NULL; - errno = 0; - prio = g_ascii_strtoll (priority, &tmp, 10); - - if (errno || tmp == priority) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Tag “%s” has invalid priority “%s”"), name, priority); - return; - } - - if (name) - { - tag_name = get_tag_name (info, name); - info->current_tag = gtk_text_tag_new (tag_name); - g_free (tag_name); - } - else - { - info->current_tag = gtk_text_tag_new (NULL); - info->current_tag_id = id; - } - - info->current_tag_prio = prio; - - 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 <text_view_markup> 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 <%s> element has already been specified"), "tags"); - 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 <%s> element has already been specified"), "text"); - return; - } - else if (!info->parsed_tags) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("A <text> element can’t occur before a <tags> 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; - case STATE_ATTR: - case STATE_PIXBUF: - 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 (gtk_text_buffer_get_tag_table (info->buffer), - 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); - - if (info->current_tag->priv->name) - { - /* Add tag to defined tags hash */ - tmp = g_strdup (info->current_tag->priv->name); - g_hash_table_insert (info->defined_tags, - tmp, tmp); - } - else - { - g_hash_table_insert (info->anonymous_tags, - GINT_TO_POINTER (info->current_tag_id), - info->current_tag); - } - - if (info->create_tags) - { - TextTagPrio *prio; - - /* add the tag to the list */ - prio = g_slice_new0 (TextTagPrio); - 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 */ - 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; - case STATE_START: - 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 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; - - if (peek_state (info) == STATE_TEXT || - peek_state (info) == STATE_APPLY_TAG) - { - if (text_len == 0) - return; - - span = g_slice_new0 (TextSpan); - span->text = g_strndup (text, text_len); - span->tags = g_slist_copy (info->tag_stack); - - info->spans = g_list_prepend (info->spans, span); - } -} - -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->anonymous_tags = g_hash_table_new_full (NULL, NULL, NULL, NULL); - 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) -{ - g_free (span->text); - g_slist_free (span->tags); - g_slice_free (TextSpan, span); -} - -static void -parse_info_free (ParseInfo *info) -{ - GList *list; - - 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_slice_free (TextTagPrio, prio); - - list = list->next; - } - g_list_free (info->tag_priorities); - -} - -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) - { - GtkTextTag *tag = tags->data; - - gtk_text_buffer_apply_tag (info->buffer, tag, - &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, strlen (id)) == 0); -} - -static GList * -read_headers (const gchar *start, - gint len, - GError **error) -{ - int i = 0; - int section_len; - Header *header; - GList *headers = NULL; - GList *l; - - while (i < len) - { - if (i + 30 >= len) - goto error; - - if (strncmp (start + i, "GTKTEXTBUFFERCONTENTS-0001", 26) == 0 || - strncmp (start + i, "GTKTEXTBUFFERPIXBDATA-0001", 26) == 0) - { - section_len = read_int ((const guchar *) start + i + 26); - - if (i + 30 + section_len > len) - goto error; - - header = g_slice_new0 (Header); - header->id = start + i; - header->length = section_len; - header->start = start + i + 30; - - i += 30 + section_len; - - headers = g_list_prepend (headers, header); - } - else - break; - } - - return g_list_reverse (headers); - - error: - for (l = headers; l != NULL; l = l->next) - { - header = l->data; - g_slice_free (Header, header); - } - - g_list_free (headers); - - g_set_error_literal (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 const 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 *register_buffer, - GtkTextBuffer *content_buffer, - GtkTextIter *iter, - const guint8 *text, - gsize length, - gboolean create_tags, - gpointer user_data, - GError **error) -{ - GList *headers; - GList *l; - Header *header; - gboolean retval; - - headers = read_headers ((gchar *) text, length, error); - - if (!headers) - return FALSE; - - header = headers->data; - if (!header_is (header, "GTKTEXTBUFFERCONTENTS-0001")) - { - g_set_error_literal (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Serialized data is malformed. First section isn’t GTKTEXTBUFFERCONTENTS-0001")); - - retval = FALSE; - goto out; - } - - retval = deserialize_text (content_buffer, iter, - header->start, header->length, - create_tags, error, headers->next); - - out: - for (l = headers; l != NULL; l = l->next) - { - header = l->data; - g_slice_free (Header, header); - } - - g_list_free (headers); - - return retval; -} diff --git a/gtk/gtktextbufferserialize.h b/gtk/gtktextbufferserialize.h deleted file mode 100644 index 4a183b62cf..0000000000 --- a/gtk/gtktextbufferserialize.h +++ /dev/null @@ -1,41 +0,0 @@ -/* gtktextbufferserialize.h - * - * Copyright (C) 2004 Nokia Corporation. - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __GTK_TEXT_BUFFER_SERIALIZE_H__ -#define __GTK_TEXT_BUFFER_SERIALIZE_H__ - -#include <gtk/gtktextbuffer.h> - -guint8 * _gtk_text_buffer_serialize_rich_text (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - const GtkTextIter *start, - const GtkTextIter *end, - gsize *length, - gpointer user_data); - -gboolean _gtk_text_buffer_deserialize_rich_text (GtkTextBuffer *register_buffer, - GtkTextBuffer *content_buffer, - GtkTextIter *iter, - const guint8 *data, - gsize length, - gboolean create_tags, - gpointer user_data, - GError **error); - - -#endif /* __GTK_TEXT_BUFFER_SERIALIZE_H__ */ diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index ec423d1e62..d774f390b4 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -42,7 +42,6 @@ #include "gtkseparatormenuitem.h" #include "gtksettings.h" #include "gtkselectionprivate.h" -#include "gtktextbufferrichtext.h" #include "gtktextdisplayprivate.h" #include "gtktextiterprivate.h" #include "gtkimmulticontext.h" @@ -7882,31 +7881,6 @@ gtk_text_view_drag_data_get (GtkWidget *widget, (void*)&buffer, sizeof (buffer)); } - else if (gtk_selection_data_targets_include_rich_text (selection_data, buffer)) - { - GtkTextIter start; - GtkTextIter end; - guint8 *str = NULL; - gsize len; - - if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end)) - { - /* Extract the selected text */ - str = gtk_text_buffer_serialize (buffer, buffer, - gtk_selection_data_get_target (selection_data), - &start, &end, - &len); - } - - if (str) - { - gtk_selection_data_set (selection_data, - gtk_selection_data_get_target (selection_data), - 8, /* bytes */ - (guchar *) str, len); - g_free (str); - } - } else { GtkTextIter start; @@ -8177,29 +8151,7 @@ gtk_text_view_drag_data_received (GtkWidget *widget, if (gtk_text_buffer_get_tag_table (src_buffer) != gtk_text_buffer_get_tag_table (buffer)) { - /* try to find a suitable rich text target instead */ - GdkAtom *atoms; - gint n_atoms; - GdkContentFormats *dnd_formats, *buffer_formats; - const char *target = NULL; - copy_tags = FALSE; - - atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms); - buffer_formats = gdk_content_formats_new (atoms, n_atoms); - dnd_formats = gdk_drag_context_get_formats (context); - - gdk_content_formats_match (dnd_formats, buffer_formats, NULL, &target); - - gdk_content_formats_unref (buffer_formats); - g_free (atoms); - - if (target != NULL) - { - gtk_drag_get_data (widget, context, target, time); - gtk_text_buffer_end_user_action (buffer); - return; - } } if (gtk_text_buffer_get_selection_bounds (src_buffer, @@ -8224,25 +8176,6 @@ gtk_text_view_drag_data_received (GtkWidget *widget, } } } - else if (gtk_selection_data_get_length (selection_data) > 0 && - gtk_selection_data_targets_include_rich_text (selection_data, buffer)) - { - gboolean retval; - GError *error = NULL; - - retval = gtk_text_buffer_deserialize (buffer, buffer, - gtk_selection_data_get_target (selection_data), - &drop_point, - (guint8 *) gtk_selection_data_get_data (selection_data), - gtk_selection_data_get_length (selection_data), - &error); - - if (!retval) - { - g_warning ("error pasting: %s", error->message); - g_clear_error (&error); - } - } else insert_text_data (text_view, &drop_point, selection_data); diff --git a/gtk/meson.build b/gtk/meson.build index c961f294b0..090f891541 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -312,8 +312,6 @@ gtk_public_sources = files([ 'gtktextattributes.c', 'gtktextbtree.c', 'gtktextbuffer.c', - 'gtktextbufferrichtext.c', - 'gtktextbufferserialize.c', 'gtktextchild.c', 'gtktextdisplay.c', 'gtktexthandle.c', @@ -554,7 +552,6 @@ gtk_public_headers = files([ 'gtkswitch.h', 'gtktestutils.h', 'gtktextbuffer.h', - 'gtktextbufferrichtext.h', 'gtktextchild.h', 'gtktextiter.h', 'gtktextmark.h', diff --git a/tests/meson.build b/tests/meson.build index 3b5bdf57f6..e6f68adf4d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -73,7 +73,6 @@ gtk_tests = [ ['testprint', ['testprintfileoperation.c']], ['testrecentchooser'], ['testrecentchoosermenu'], - ['testrichtext'], ['testscale'], ['testselection'], ['testselectionmode'], diff --git a/tests/testrichtext.c b/tests/testrichtext.c deleted file mode 100644 index 84e43cc49a..0000000000 --- a/tests/testrichtext.c +++ /dev/null @@ -1,190 +0,0 @@ -/* 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, see <http://www.gnu.org/licenses/>. - */ - -#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; - GtkTextTagTable *ttable = gtk_text_buffer_get_tag_table (buffer); - GSList *node, *slist = NULL; - GdkAtom atom; - guint i; - - tags = g_malloc (sizeof (GtkTextTag *) * tcount); - - /* 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); - - g_free (tags); - - 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 (); - - /* initialize random numbers, disable this for deterministic testing */ - if (1) - quick_rand32_accu = g_random_int(); - - 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_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 (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; -} |