3 * Copyright (C) 2006 Imendio AB
4 * Contact: Michael Natterer <mitch@imendio.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24 #include "gtktextbufferrichtext.h"
25 #include "gtktextbufferserialize.h"
32 gboolean can_create_tags;
36 GDestroyNotify user_data_destroy;
40 static GList * register_format (GList *formats,
41 const gchar *mime_type,
44 GDestroyNotify user_data_destroy,
46 static GList * unregister_format (GList *formats,
48 static GdkAtom * get_formats (GList *formats,
50 static void free_format (GtkRichTextFormat *format);
51 static void free_format_list (GList *formats);
52 static GQuark serialize_quark (void);
53 static GQuark deserialize_quark (void);
57 * gtk_text_buffer_register_serialize_format:
58 * @buffer: a #GtkTextBuffer
59 * @mime_type: the format's mime-type
60 * @function: the serialize function to register
61 * @user_data: %function's user_data
62 * @user_data_destroy: a function to call when @user_data is no longer needed
64 * This function registers a rich text serialization @function along with
65 * its @mime_type with the passed @buffer.
67 * Return value: (transfer none): the #GdkAtom that corresponds to the
68 * newly registered format's mime-type.
73 gtk_text_buffer_register_serialize_format (GtkTextBuffer *buffer,
74 const gchar *mime_type,
75 GtkTextBufferSerializeFunc function,
77 GDestroyNotify user_data_destroy)
82 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
83 g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
84 g_return_val_if_fail (function != NULL, GDK_NONE);
86 formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
88 formats = register_format (formats, mime_type,
90 user_data, user_data_destroy,
93 g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
94 formats, (GDestroyNotify) free_format_list);
96 g_object_notify (G_OBJECT (buffer), "copy-target-list");
102 * gtk_text_buffer_register_serialize_tagset:
103 * @buffer: a #GtkTextBuffer
104 * @tagset_name: (allow-none): an optional tagset name, on %NULL
106 * This function registers GTK+'s internal rich text serialization
107 * format with the passed @buffer. The internal format does not comply
108 * to any standard rich text format and only works between #GtkTextBuffer
109 * instances. It is capable of serializing all of a text buffer's tags
110 * and embedded pixbufs.
112 * This function is just a wrapper around
113 * gtk_text_buffer_register_serialize_format(). The mime type used
114 * for registering is "application/x-gtk-text-buffer-rich-text", or
115 * "application/x-gtk-text-buffer-rich-text;format=@tagset_name" if a
116 * @tagset_name was passed.
118 * The @tagset_name can be used to restrict the transfer of rich text
119 * to buffers with compatible sets of tags, in order to avoid unknown
120 * tags from being pasted. It is probably the common case to pass an
121 * identifier != %NULL here, since the %NULL tagset requires the
122 * receiving buffer to deal with with pasting of arbitrary tags.
124 * Return value: (transfer none): the #GdkAtom that corresponds to the
125 * newly registered format's mime-type.
130 gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
131 const gchar *tagset_name)
133 gchar *mime_type = "application/x-gtk-text-buffer-rich-text";
136 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
137 g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
141 g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
144 format = gtk_text_buffer_register_serialize_format (buffer, mime_type,
145 _gtk_text_buffer_serialize_rich_text,
155 * gtk_text_buffer_register_deserialize_format:
156 * @buffer: a #GtkTextBuffer
157 * @mime_type: the format's mime-type
158 * @function: the deserialize function to register
159 * @user_data: @function's user_data
160 * @user_data_destroy: a function to call when @user_data is no longer needed
162 * This function registers a rich text deserialization @function along with
163 * its @mime_type with the passed @buffer.
165 * Return value: (transfer none): the #GdkAtom that corresponds to the
166 * newly registered format's mime-type.
171 gtk_text_buffer_register_deserialize_format (GtkTextBuffer *buffer,
172 const gchar *mime_type,
173 GtkTextBufferDeserializeFunc function,
175 GDestroyNotify user_data_destroy)
180 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
181 g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
182 g_return_val_if_fail (function != NULL, GDK_NONE);
184 formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
186 formats = register_format (formats, mime_type,
188 user_data, user_data_destroy,
191 g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
192 formats, (GDestroyNotify) free_format_list);
194 g_object_notify (G_OBJECT (buffer), "paste-target-list");
200 * gtk_text_buffer_register_deserialize_tagset:
201 * @buffer: a #GtkTextBuffer
202 * @tagset_name: (allow-none): an optional tagset name, on %NULL
204 * This function registers GTK+'s internal rich text serialization
205 * format with the passed @buffer. See
206 * gtk_text_buffer_register_serialize_tagset() for details.
208 * Return value: (transfer none): the #GdkAtom that corresponds to the
209 * newly registered format's mime-type.
214 gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
215 const gchar *tagset_name)
217 gchar *mime_type = "application/x-gtk-text-buffer-rich-text";
220 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
221 g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
225 g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
228 format = gtk_text_buffer_register_deserialize_format (buffer, mime_type,
229 _gtk_text_buffer_deserialize_rich_text,
239 * gtk_text_buffer_unregister_serialize_format:
240 * @buffer: a #GtkTextBuffer
241 * @format: a #GdkAtom representing a registered rich text format.
243 * This function unregisters a rich text format that was previously
244 * registered using gtk_text_buffer_register_serialize_format() or
245 * gtk_text_buffer_register_serialize_tagset()
250 gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
255 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
256 g_return_if_fail (format != GDK_NONE);
258 formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
260 formats = unregister_format (formats, format);
262 g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
263 formats, (GDestroyNotify) free_format_list);
265 g_object_notify (G_OBJECT (buffer), "copy-target-list");
269 * gtk_text_buffer_unregister_deserialize_format:
270 * @buffer: a #GtkTextBuffer
271 * @format: a #GdkAtom representing a registered rich text format.
273 * This function unregisters a rich text format that was previously
274 * registered using gtk_text_buffer_register_deserialize_format() or
275 * gtk_text_buffer_register_deserialize_tagset().
280 gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
285 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
286 g_return_if_fail (format != GDK_NONE);
288 formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
290 formats = unregister_format (formats, format);
292 g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
293 formats, (GDestroyNotify) free_format_list);
295 g_object_notify (G_OBJECT (buffer), "paste-target-list");
299 * gtk_text_buffer_deserialize_set_can_create_tags:
300 * @buffer: a #GtkTextBuffer
301 * @format: a #GdkAtom representing a registered rich text format
302 * @can_create_tags: whether deserializing this format may create tags
304 * Use this function to allow a rich text deserialization function to
305 * create new tags in the receiving buffer. Note that using this
306 * function is almost always a bad idea, because the rich text
307 * functions you register should know how to map the rich text format
308 * they handler to your text buffers set of tags.
310 * The ability of creating new (arbitrary!) tags in the receiving buffer
311 * is meant for special rich text formats like the internal one that
312 * is registered using gtk_text_buffer_register_deserialize_tagset(),
313 * because that format is essentially a dump of the internal structure
314 * of the source buffer, including its tag names.
316 * You should allow creation of tags only if you know what you are
317 * doing, e.g. if you defined a tagset name for your application
318 * suite's text buffers and you know that it's fine to receive new
319 * tags from these buffers, because you know that your application can
320 * handle the newly created tags.
325 gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
327 gboolean can_create_tags)
333 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
334 g_return_if_fail (format != GDK_NONE);
336 formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
338 for (list = formats; list; list = g_list_next (list))
340 GtkRichTextFormat *fmt = list->data;
342 if (fmt->atom == format)
344 fmt->can_create_tags = can_create_tags ? TRUE : FALSE;
349 format_name = gdk_atom_name (format);
350 g_warning ("%s: \"%s\" is not registered as deserializable format "
351 "with text buffer %p",
352 G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
353 g_free (format_name);
357 * gtk_text_buffer_deserialize_get_can_create_tags:
358 * @buffer: a #GtkTextBuffer
359 * @format: a #GdkAtom representing a registered rich text format
361 * This functions returns the value set with
362 * gtk_text_buffer_deserialize_set_can_create_tags()
364 * Return value: whether deserializing this format may create tags
369 gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
376 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
377 g_return_val_if_fail (format != GDK_NONE, FALSE);
379 formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
381 for (list = formats; list; list = g_list_next (list))
383 GtkRichTextFormat *fmt = list->data;
385 if (fmt->atom == format)
387 return fmt->can_create_tags;
391 format_name = gdk_atom_name (format);
392 g_warning ("%s: \"%s\" is not registered as deserializable format "
393 "with text buffer %p",
394 G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
395 g_free (format_name);
401 * gtk_text_buffer_get_serialize_formats:
402 * @buffer: a #GtkTextBuffer
403 * @n_formats: return location for the number of formats
405 * This function returns the rich text serialize formats registered
406 * with @buffer using gtk_text_buffer_register_serialize_format() or
407 * gtk_text_buffer_register_serialize_tagset()
409 * Return value: (array length=n_formats) (transfer container): an array of
410 * #GdkAtom<!-- -->s representing the registered formats.
415 gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
420 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
421 g_return_val_if_fail (n_formats != NULL, NULL);
423 formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ());
425 return get_formats (formats, n_formats);
429 * gtk_text_buffer_get_deserialize_formats:
430 * @buffer: a #GtkTextBuffer
431 * @n_formats: return location for the number of formats
433 * This function returns the rich text deserialize formats registered
434 * with @buffer using gtk_text_buffer_register_deserialize_format() or
435 * gtk_text_buffer_register_deserialize_tagset()
437 * Return value: (array length=n_formats) (transfer container): an array of
438 * #GdkAtom<!-- -->s representing the registered formats.
443 gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
448 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
449 g_return_val_if_fail (n_formats != NULL, NULL);
451 formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
453 return get_formats (formats, n_formats);
457 * gtk_text_buffer_serialize:
458 * @register_buffer: the #GtkTextBuffer @format is registered with
459 * @content_buffer: the #GtkTextBuffer to serialize
460 * @format: the rich text format to use for serializing
461 * @start: start of block of text to serialize
462 * @end: end of block of test to serialize
463 * @length: return location for the length of the serialized data
465 * This function serializes the portion of text between @start
466 * and @end in the rich text format represented by @format.
468 * @format<!-- -->s to be used must be registered using
469 * gtk_text_buffer_register_serialize_format() or
470 * gtk_text_buffer_register_serialize_tagset() beforehand.
472 * Return value: (array length=length) (transfer full): the serialized
473 * data, encoded as @format
478 gtk_text_buffer_serialize (GtkTextBuffer *register_buffer,
479 GtkTextBuffer *content_buffer,
481 const GtkTextIter *start,
482 const GtkTextIter *end,
488 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), NULL);
489 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), NULL);
490 g_return_val_if_fail (format != GDK_NONE, NULL);
491 g_return_val_if_fail (start != NULL, NULL);
492 g_return_val_if_fail (end != NULL, NULL);
493 g_return_val_if_fail (length != NULL, NULL);
497 formats = g_object_get_qdata (G_OBJECT (register_buffer),
500 for (list = formats; list; list = g_list_next (list))
502 GtkRichTextFormat *fmt = list->data;
504 if (fmt->atom == format)
506 GtkTextBufferSerializeFunc function = fmt->function;
508 return function (register_buffer, content_buffer,
509 start, end, length, fmt->user_data);
517 * gtk_text_buffer_deserialize:
518 * @register_buffer: the #GtkTextBuffer @format is registered with
519 * @content_buffer: the #GtkTextBuffer to deserialize into
520 * @format: the rich text format to use for deserializing
521 * @iter: insertion point for the deserialized text
522 * @data: (array length=length): data to deserialize
523 * @length: length of @data
524 * @error: return location for a #GError
526 * This function deserializes rich text in format @format and inserts
529 * @format<!-- -->s to be used must be registered using
530 * gtk_text_buffer_register_deserialize_format() or
531 * gtk_text_buffer_register_deserialize_tagset() beforehand.
533 * Return value: %TRUE on success, %FALSE otherwise.
538 gtk_text_buffer_deserialize (GtkTextBuffer *register_buffer,
539 GtkTextBuffer *content_buffer,
549 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), FALSE);
550 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), FALSE);
551 g_return_val_if_fail (format != GDK_NONE, FALSE);
552 g_return_val_if_fail (iter != NULL, FALSE);
553 g_return_val_if_fail (data != NULL, FALSE);
554 g_return_val_if_fail (length > 0, FALSE);
555 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
557 formats = g_object_get_qdata (G_OBJECT (register_buffer),
558 deserialize_quark ());
560 for (list = formats; list; list = g_list_next (list))
562 GtkRichTextFormat *fmt = list->data;
564 if (fmt->atom == format)
566 GtkTextBufferDeserializeFunc function = fmt->function;
570 GtkTextMark *left_end = NULL;
571 GtkTextMark *right_start = NULL;
572 GSList *left_start_list = NULL;
573 GSList *right_end_list = NULL;
575 /* We don't want the tags that are effective at the insertion
576 * point to affect the pasted text, therefore we remove and
577 * remember them, so they can be re-applied left and right of
578 * the inserted text after pasting
580 split_tags = gtk_text_iter_get_tags (iter);
585 GtkTextTag *tag = list->data;
587 list = g_slist_next (list);
589 /* If a tag begins at the insertion point, ignore it
590 * because it doesn't affect the pasted text
592 if (gtk_text_iter_begins_tag (iter, tag))
593 split_tags = g_slist_remove (split_tags, tag);
598 /* Need to remember text marks, because text iters
599 * don't survive pasting
601 left_end = gtk_text_buffer_create_mark (content_buffer,
603 right_start = gtk_text_buffer_create_mark (content_buffer,
606 for (list = split_tags; list; list = g_slist_next (list))
608 GtkTextTag *tag = list->data;
609 GtkTextIter *backward_toggle = gtk_text_iter_copy (iter);
610 GtkTextIter *forward_toggle = gtk_text_iter_copy (iter);
611 GtkTextMark *left_start = NULL;
612 GtkTextMark *right_end = NULL;
614 gtk_text_iter_backward_to_tag_toggle (backward_toggle, tag);
615 left_start = gtk_text_buffer_create_mark (content_buffer,
620 gtk_text_iter_forward_to_tag_toggle (forward_toggle, tag);
621 right_end = gtk_text_buffer_create_mark (content_buffer,
626 left_start_list = g_slist_prepend (left_start_list, left_start);
627 right_end_list = g_slist_prepend (right_end_list, right_end);
629 gtk_text_buffer_remove_tag (content_buffer, tag,
633 gtk_text_iter_free (forward_toggle);
634 gtk_text_iter_free (backward_toggle);
637 left_start_list = g_slist_reverse (left_start_list);
638 right_end_list = g_slist_reverse (right_end_list);
641 success = function (register_buffer, content_buffer,
643 fmt->can_create_tags,
647 if (!success && error != NULL && *error == NULL)
648 g_set_error (error, 0, 0,
649 _("Unknown error when trying to deserialize %s"),
650 gdk_atom_name (format));
659 /* Turn the remembered marks back into iters so they
660 * can by used to re-apply the remembered tags
662 gtk_text_buffer_get_iter_at_mark (content_buffer,
664 gtk_text_buffer_get_iter_at_mark (content_buffer,
665 &right_s, right_start);
667 for (list = split_tags,
668 left_list = left_start_list,
669 right_list = right_end_list;
670 list && left_list && right_list;
671 list = g_slist_next (list),
672 left_list = g_slist_next (left_list),
673 right_list = g_slist_next (right_list))
675 GtkTextTag *tag = list->data;
676 GtkTextMark *left_start = left_list->data;
677 GtkTextMark *right_end = right_list->data;
681 gtk_text_buffer_get_iter_at_mark (content_buffer,
682 &left_s, left_start);
683 gtk_text_buffer_get_iter_at_mark (content_buffer,
684 &right_e, right_end);
686 gtk_text_buffer_apply_tag (content_buffer, tag,
688 gtk_text_buffer_apply_tag (content_buffer, tag,
691 gtk_text_buffer_delete_mark (content_buffer, left_start);
692 gtk_text_buffer_delete_mark (content_buffer, right_end);
695 gtk_text_buffer_delete_mark (content_buffer, left_end);
696 gtk_text_buffer_delete_mark (content_buffer, right_start);
698 g_slist_free (split_tags);
699 g_slist_free (left_start_list);
700 g_slist_free (right_end_list);
707 g_set_error (error, 0, 0,
708 _("No deserialize function found for format %s"),
709 gdk_atom_name (format));
715 /* private functions */
718 register_format (GList *formats,
719 const gchar *mime_type,
722 GDestroyNotify user_data_destroy,
725 GtkRichTextFormat *format;
727 *atom = gdk_atom_intern (mime_type, FALSE);
729 formats = unregister_format (formats, *atom);
731 format = g_new0 (GtkRichTextFormat, 1);
733 format->mime_type = g_strdup (mime_type);
734 format->can_create_tags = FALSE;
735 format->atom = *atom;
736 format->function = function;
737 format->user_data = user_data;
738 format->user_data_destroy = user_data_destroy;
740 return g_list_append (formats, format);
744 unregister_format (GList *formats,
749 for (list = formats; list; list = g_list_next (list))
751 GtkRichTextFormat *format = list->data;
753 if (format->atom == atom)
755 free_format (format);
757 return g_list_delete_link (formats, list);
765 get_formats (GList *formats,
772 *n_formats = g_list_length (formats);
773 array = g_new0 (GdkAtom, *n_formats);
775 for (list = formats, i = 0; list; list = g_list_next (list), i++)
777 GtkRichTextFormat *format = list->data;
779 array[i] = format->atom;
786 free_format (GtkRichTextFormat *format)
788 if (format->user_data_destroy)
789 format->user_data_destroy (format->user_data);
791 g_free (format->mime_type);
796 free_format_list (GList *formats)
798 g_list_free_full (formats, (GDestroyNotify) free_format);
802 serialize_quark (void)
804 static GQuark quark = 0;
807 quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats");
813 deserialize_quark (void)
815 static GQuark quark = 0;
818 quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats");