]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbufferrichtext.c
Small documentation fixes.
[~andy/gtk] / gtk / gtktextbufferrichtext.c
1 /* gtkrichtext.c
2  *
3  * Copyright (C) 2006 Imendio AB
4  * Contact: Michael Natterer <mitch@imendio.com>
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include "gtktextbufferrichtext.h"
27 #include "gtktextbufferserialize.h"
28 #include "gtkintl.h"
29 #include "gtkalias.h"
30
31
32 typedef struct
33 {
34   gchar          *mime_type;
35   gboolean        can_create_tags;
36   GdkAtom         atom;
37   gpointer        function;
38   gpointer        user_data;
39   GDestroyNotify  user_data_destroy;
40 } GtkRichTextFormat;
41
42
43 static GList   * register_format   (GList             *formats,
44                                     const gchar       *mime_type,
45                                     gpointer           function,
46                                     gpointer           user_data,
47                                     GDestroyNotify     user_data_destroy,
48                                     GdkAtom           *atom);
49 static GList   * unregister_format (GList             *formats,
50                                     GdkAtom            atom);
51 static GdkAtom * get_formats       (GList             *formats,
52                                     gint              *n_formats);
53 static void      free_format       (GtkRichTextFormat *format);
54 static void      free_format_list  (GList             *formats);
55 static GQuark    serialize_quark   (void);
56 static GQuark    deserialize_quark (void);
57
58
59 /**
60  * gtk_text_buffer_register_serialize_format:
61  * @buffer: a #GtkTextBuffer
62  * @mime_type: the format's mime-type
63  * @function: the serialize function to register
64  * @user_data: %function's user_data
65  * @user_data_destroy: a function to call when @user_data is no longer needed
66  *
67  * This function registers a rich text serialization @function along with
68  * its @mime_type with the passed @buffer.
69  *
70  * Return value: the #GdkAtom that corresponds to the newly registered
71  *               format's mime-type.
72  *
73  * Since: 2.10
74  **/
75 GdkAtom
76 gtk_text_buffer_register_serialize_format (GtkTextBuffer              *buffer,
77                                            const gchar                *mime_type,
78                                            GtkTextBufferSerializeFunc  function,
79                                            gpointer                    user_data,
80                                            GDestroyNotify              user_data_destroy)
81 {
82   GList   *formats;
83   GdkAtom  atom;
84
85   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
86   g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
87   g_return_val_if_fail (function != NULL, GDK_NONE);
88
89   formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
90
91   formats = register_format (formats, mime_type,
92                              (gpointer) function,
93                              user_data, user_data_destroy,
94                              &atom);
95
96   g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
97                            formats, (GDestroyNotify) free_format_list);
98
99   g_object_notify (G_OBJECT (buffer), "copy-target-list");
100
101   return atom;
102 }
103
104 /**
105  * gtk_text_buffer_register_serialize_tagset:
106  * @buffer: a #GtkTextBuffer
107  * @tagset_name: an optional tagset name, on %NULL
108  *
109  * This function registers GTK+'s internal rich text serialization
110  * format with the passed @buffer. The internal format does not comply
111  * to any standard rich text format and only works between #GtkTextBuffer
112  * instances. It is capable of serializing all of a text buffer's tags
113  * and embedded pixbufs.
114  *
115  * This function is just a wrapper around
116  * gtk_text_buffer_register_serialize_format(). The mime type used
117  * for registering is "application/x-gtk-text-buffer-rich-text", or
118  * "application/x-gtk-text-buffer-rich-text;format=@tagset_name" if a
119  * @tagset_name was passed.
120  *
121  * The @tagset_name can be used to restrict the transfer of rich text
122  * to buffers with compatible sets of tags, in order to avoid unknown
123  * tags from being pasted. It is probably the common case to pass an
124  * identifier != %NULL here, since the %NULL tagset requires the
125  * receiving buffer to deal with with pasting of arbitrary tags.
126  *
127  * Return value: the #GdkAtom that corresponds to the newly registered
128  *               format's mime-type.
129  *
130  * Since: 2.10
131  **/
132 GdkAtom
133 gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
134                                            const gchar   *tagset_name)
135 {
136   gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
137   GdkAtom  format;
138
139   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
140   g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
141
142   if (tagset_name)
143     mime_type =
144       g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
145                        tagset_name);
146
147   format = gtk_text_buffer_register_serialize_format (buffer, mime_type,
148                                                       _gtk_text_buffer_serialize_rich_text,
149                                                       NULL, NULL);
150
151   if (tagset_name)
152     g_free (mime_type);
153
154   return format;
155 }
156
157 /**
158  * gtk_text_buffer_register_deserialize_format:
159  * @buffer: a #GtkTextBuffer
160  * @mime_type: the format's mime-type
161  * @function: the deserialize function to register
162  * @user_data: @function's user_data
163  * @user_data_destroy: a function to call when @user_data is no longer needed
164  *
165  * This function registers a rich text deserialization @function along with
166  * its @mime_type with the passed @buffer.
167  *
168  * Return value: the #GdkAtom that corresponds to the newly registered
169  *               format's mime-type.
170  *
171  * Since: 2.10
172  **/
173 GdkAtom
174 gtk_text_buffer_register_deserialize_format (GtkTextBuffer                *buffer,
175                                              const gchar                  *mime_type,
176                                              GtkTextBufferDeserializeFunc  function,
177                                              gpointer                      user_data,
178                                              GDestroyNotify                user_data_destroy)
179 {
180   GList   *formats;
181   GdkAtom  atom;
182
183   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
184   g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
185   g_return_val_if_fail (function != NULL, GDK_NONE);
186
187   formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
188
189   formats = register_format (formats, mime_type,
190                              (gpointer) function,
191                              user_data, user_data_destroy,
192                              &atom);
193
194   g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
195                            formats, (GDestroyNotify) free_format_list);
196
197   g_object_notify (G_OBJECT (buffer), "paste-target-list");
198
199   return atom;
200 }
201
202 /**
203  * gtk_text_buffer_register_deserialize_tagset:
204  * @buffer: a #GtkTextBuffer
205  * @tagset_name: an optional tagset name, on %NULL
206  *
207  * This function registers GTK+'s internal rich text serialization
208  * format with the passed @buffer. See
209  * gtk_text_buffer_register_serialize_tagset() for details.
210  *
211  * Return value: the #GdkAtom that corresponds to the newly registered
212  *               format's mime-type.
213  *
214  * Since: 2.10
215  **/
216 GdkAtom
217 gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
218                                              const gchar   *tagset_name)
219 {
220   gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
221   GdkAtom  format;
222
223   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
224   g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
225
226   if (tagset_name)
227     mime_type =
228       g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
229                        tagset_name);
230
231   format = gtk_text_buffer_register_deserialize_format (buffer, mime_type,
232                                                         _gtk_text_buffer_deserialize_rich_text,
233                                                         NULL, NULL);
234
235   if (tagset_name)
236     g_free (mime_type);
237
238   return format;
239 }
240
241 /**
242  * gtk_text_buffer_unregister_serialize_format:
243  * @buffer: a #GtkTextBuffer
244  * @format: a #GdkAtom representing a registered rich text format.
245  *
246  * This function unregisters a rich text format that was previously
247  * registered using gtk_text_buffer_register_serialize_format() or
248  * gtk_text_buffer_register_serialize_tagset()
249  *
250  * Since: 2.10
251  **/
252 void
253 gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
254                                              GdkAtom        format)
255 {
256   GList *formats;
257
258   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
259   g_return_if_fail (format != GDK_NONE);
260
261   formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
262
263   formats = unregister_format (formats, format);
264
265   g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
266                            formats, (GDestroyNotify) free_format_list);
267
268   g_object_notify (G_OBJECT (buffer), "copy-target-list");
269 }
270
271 /**
272  * gtk_text_buffer_unregister_deserialize_format:
273  * @buffer: a #GtkTextBuffer
274  * @format: a #GdkAtom representing a registered rich text format.
275  *
276  * This function unregisters a rich text format that was previously
277  * registered using gtk_text_buffer_register_deserialize_format() or
278  * gtk_text_buffer_register_deserialize_tagset().
279  *
280  * Since: 2.10
281  **/
282 void
283 gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
284                                                GdkAtom        format)
285 {
286   GList *formats;
287
288   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
289   g_return_if_fail (format != GDK_NONE);
290
291   formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
292
293   formats = unregister_format (formats, format);
294
295   g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
296                            formats, (GDestroyNotify) free_format_list);
297
298   g_object_notify (G_OBJECT (buffer), "paste-target-list");
299 }
300
301 /**
302  * gtk_text_buffer_deserialize_set_can_create_tags:
303  * @buffer: a #GtkTextBuffer
304  * @format: a #GdkAtom representing a registered rich text format
305  * @can_create_tags: whether deserializing this format may create tags
306  *
307  * Use this function to allow a rich text deserialization function to
308  * create new tags in the receiving buffer. Note that using this
309  * function is almost always a bad idea, because the rich text
310  * functions you register should know how to map the rich text format
311  * they handler to your text buffers set of tags.
312  *
313  * The ability of creating new (arbitrary!) tags in the receiving buffer
314  * is meant for special rich text formats like the internal one that
315  * is registered using gtk_text_buffer_register_deserialize_tagset(),
316  * because that format is essentially a dump of the internal structure
317  * of the source buffer, including its tag names.
318  *
319  * You should allow creation of tags only if you know what you are
320  * doing, e.g. if you defined a tagset name for your application
321  * suite's text buffers and you know that it's fine to receive new
322  * tags from these buffers, because you know that your application can
323  * handle the newly created tags.
324  *
325  * Since: 2.10
326  **/
327 void
328 gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
329                                                  GdkAtom        format,
330                                                  gboolean       can_create_tags)
331 {
332   GList *formats;
333   GList *list;
334   gchar *format_name;
335
336   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
337   g_return_if_fail (format != GDK_NONE);
338
339   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
340
341   for (list = formats; list; list = g_list_next (list))
342     {
343       GtkRichTextFormat *fmt = list->data;
344
345       if (fmt->atom == format)
346         {
347           fmt->can_create_tags = can_create_tags ? TRUE : FALSE;
348           return;
349         }
350     }
351
352   format_name = gdk_atom_name (format);
353   g_warning ("%s: \"%s\" is not registered as deserializable format "
354              "with text buffer %p",
355              G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
356   g_free (format_name);
357 }
358
359 /**
360  * gtk_text_buffer_deserialize_get_can_create_tags:
361  * @buffer: a #GtkTextBuffer
362  * @format: a #GdkAtom representing a registered rich text format
363  *
364  * This functions returns the value set with
365  * gtk_text_buffer_deserialize_set_can_create_tags()
366  *
367  * Return value: whether deserializing this format may create tags
368  *
369  * Since: 2.10
370  **/
371 gboolean
372 gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
373                                                  GdkAtom        format)
374 {
375   GList *formats;
376   GList *list;
377   gchar *format_name;
378
379   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
380   g_return_val_if_fail (format != GDK_NONE, FALSE);
381
382   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
383
384   for (list = formats; list; list = g_list_next (list))
385     {
386       GtkRichTextFormat *fmt = list->data;
387
388       if (fmt->atom == format)
389         {
390           return fmt->can_create_tags;
391         }
392     }
393
394   format_name = gdk_atom_name (format);
395   g_warning ("%s: \"%s\" is not registered as deserializable format "
396              "with text buffer %p",
397              G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
398   g_free (format_name);
399
400   return FALSE;
401 }
402
403 /**
404  * gtk_text_buffer_get_serialize_formats:
405  * @buffer: a #GtkTextBuffer
406  * @n_formats: return location for the number of formats
407  *
408  * This function returns the rich text serialize formats registered
409  * with @buffer using gtk_text_buffer_register_serialize_format() or
410  * gtk_text_buffer_register_serialize_tagset()
411  *
412  * Return value: an array of #GdkAtom<!-- -->s representing the registered
413  *               formats.
414  *
415  * Since: 2.10
416  **/
417 GdkAtom *
418 gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
419                                        gint          *n_formats)
420 {
421   GList *formats;
422
423   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
424   g_return_val_if_fail (n_formats != NULL, NULL);
425
426   formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ());
427
428   return get_formats (formats, n_formats);
429 }
430
431 /**
432  * gtk_text_buffer_get_deserialize_formats:
433  * @buffer: a #GtkTextBuffer
434  * @n_formats: return location for the number of formats
435  *
436  * This function returns the rich text deserialize formats registered
437  * with @buffer using gtk_text_buffer_register_deserialize_format() or
438  * gtk_text_buffer_register_deserialize_tagset()
439  *
440  * Return value: an array of #GdkAtom<!-- -->s representing the registered
441  *               formats.
442  *
443  * Since: 2.10
444  **/
445 GdkAtom *
446 gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
447                                          gint          *n_formats)
448 {
449   GList *formats;
450
451   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
452   g_return_val_if_fail (n_formats != NULL, NULL);
453
454   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
455
456   return get_formats (formats, n_formats);
457 }
458
459 /**
460  * gtk_text_buffer_serialize:
461  * @register_buffer: the #GtkTextBuffer @format is registered with
462  * @content_buffer: the #GtkTextBuffer to serialize
463  * @format: the rich text format to use for serializing
464  * @start: start of block of text to serialize
465  * @end: end of block of test to serialize
466  * @length: return location for the length of the serialized data
467  *
468  * This function serializes the portion of text between @start
469  * and @end in the rich text format represented by @format.
470  *
471  * @format<!-- -->s to be used must be registered using
472  * gtk_text_buffer_register_serialize_format() or
473  * gtk_text_buffer_register_serialize_tagset() beforehand.
474  *
475  * Return value: the serialized data, encoded as @format
476  *
477  * Since: 2.10
478  **/
479 guint8 *
480 gtk_text_buffer_serialize (GtkTextBuffer     *register_buffer,
481                            GtkTextBuffer     *content_buffer,
482                            GdkAtom            format,
483                            const GtkTextIter *start,
484                            const GtkTextIter *end,
485                            gsize             *length)
486 {
487   GList *formats;
488   GList *list;
489
490   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), NULL);
491   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), NULL);
492   g_return_val_if_fail (format != GDK_NONE, NULL);
493   g_return_val_if_fail (start != NULL, NULL);
494   g_return_val_if_fail (end != NULL, NULL);
495   g_return_val_if_fail (length != NULL, NULL);
496
497   *length = 0;
498
499   formats = g_object_get_qdata (G_OBJECT (register_buffer),
500                                 serialize_quark ());
501
502   for (list = formats; list; list = g_list_next (list))
503     {
504       GtkRichTextFormat *fmt = list->data;
505
506       if (fmt->atom == format)
507         {
508           GtkTextBufferSerializeFunc function = fmt->function;
509
510           return function (register_buffer, content_buffer,
511                            start, end, length, fmt->user_data);
512         }
513     }
514
515   return NULL;
516 }
517
518 /**
519  * gtk_text_buffer_deserialize:
520  * @register_buffer: the #GtkTextBuffer @format is registered with
521  * @content_buffer: the #GtkTextBuffer to deserialize into
522  * @format: the rich text format to use for deserializing
523  * @iter: insertion point for the deserialized text
524  * @data: data to deserialize
525  * @length: length of @data
526  * @error: return location for a #GError
527  *
528  * This function deserializes rich text in format @format and inserts
529  * it at @iter.
530  *
531  * @format<!-- -->s to be used must be registered using
532  * gtk_text_buffer_register_deserialize_format() or
533  * gtk_text_buffer_register_deserialize_tagset() beforehand.
534  *
535  * Return value: %TRUE on success, %FALSE otherwise.
536  *
537  * Since: 2.10
538  **/
539 gboolean
540 gtk_text_buffer_deserialize (GtkTextBuffer  *register_buffer,
541                              GtkTextBuffer  *content_buffer,
542                              GdkAtom         format,
543                              GtkTextIter    *iter,
544                              const guint8   *data,
545                              gsize           length,
546                              GError        **error)
547 {
548   GList    *formats;
549   GList    *list;
550
551   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), FALSE);
552   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), FALSE);
553   g_return_val_if_fail (format != GDK_NONE, FALSE);
554   g_return_val_if_fail (iter != NULL, FALSE);
555   g_return_val_if_fail (data != NULL, FALSE);
556   g_return_val_if_fail (length > 0, FALSE);
557   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
558
559   formats = g_object_get_qdata (G_OBJECT (register_buffer),
560                                 deserialize_quark ());
561
562   for (list = formats; list; list = g_list_next (list))
563     {
564       GtkRichTextFormat *fmt = list->data;
565
566       if (fmt->atom == format)
567         {
568           GtkTextBufferDeserializeFunc function = fmt->function;
569           gboolean                     success;
570           GSList                      *split_tags;
571           GSList                      *list;
572           GtkTextMark                 *left_end        = NULL;
573           GtkTextMark                 *right_start     = NULL;
574           GSList                      *left_start_list = NULL;
575           GSList                      *right_end_list  = NULL;
576
577           /*  We don't want the tags that are effective at the insertion
578            *  point to affect the pasted text, therefore we remove and
579            *  remember them, so they can be re-applied left and right of
580            *  the inserted text after pasting
581            */
582           split_tags = gtk_text_iter_get_tags (iter);
583
584           list = split_tags;
585           while (list)
586             {
587               GtkTextTag *tag = list->data;
588
589               list = g_slist_next (list);
590
591               /*  If a tag begins at the insertion point, ignore it
592                *  because it doesn't affect the pasted text
593                */
594               if (gtk_text_iter_begins_tag (iter, tag))
595                 split_tags = g_slist_remove (split_tags, tag);
596             }
597
598           if (split_tags)
599             {
600               /*  Need to remember text marks, because text iters
601                *  don't survive pasting
602                */
603               left_end = gtk_text_buffer_create_mark (content_buffer,
604                                                       NULL, iter, TRUE);
605               right_start = gtk_text_buffer_create_mark (content_buffer,
606                                                          NULL, iter, FALSE);
607
608               for (list = split_tags; list; list = g_slist_next (list))
609                 {
610                   GtkTextTag  *tag             = list->data;
611                   GtkTextIter *backward_toggle = gtk_text_iter_copy (iter);
612                   GtkTextIter *forward_toggle  = gtk_text_iter_copy (iter);
613                   GtkTextMark *left_start      = NULL;
614                   GtkTextMark *right_end       = NULL;
615
616                   gtk_text_iter_backward_to_tag_toggle (backward_toggle, tag);
617                   left_start = gtk_text_buffer_create_mark (content_buffer,
618                                                             NULL,
619                                                             backward_toggle,
620                                                             FALSE);
621
622                   gtk_text_iter_forward_to_tag_toggle (forward_toggle, tag);
623                   right_end = gtk_text_buffer_create_mark (content_buffer,
624                                                            NULL,
625                                                            forward_toggle,
626                                                            TRUE);
627
628                   left_start_list = g_slist_prepend (left_start_list, left_start);
629                   right_end_list = g_slist_prepend (right_end_list, right_end);
630
631                   gtk_text_buffer_remove_tag (content_buffer, tag,
632                                               backward_toggle,
633                                               forward_toggle);
634
635                   gtk_text_iter_free (forward_toggle);
636                   gtk_text_iter_free (backward_toggle);
637                 }
638
639               left_start_list = g_slist_reverse (left_start_list);
640               right_end_list = g_slist_reverse (right_end_list);
641             }
642
643           success = function (register_buffer, content_buffer,
644                               iter, data, length,
645                               fmt->can_create_tags,
646                               fmt->user_data,
647                               error);
648
649           if (!success && error != NULL && *error == NULL)
650             g_set_error (error, 0, 0,
651                          _("Unknown error when trying to deserialize %s"),
652                          gdk_atom_name (format));
653
654           if (split_tags)
655             {
656               GSList      *left_list;
657               GSList      *right_list;
658               GtkTextIter  left_e;
659               GtkTextIter  right_s;
660
661               /*  Turn the remembered marks back into iters so they
662                *  can by used to re-apply the remembered tags
663                */
664               gtk_text_buffer_get_iter_at_mark (content_buffer,
665                                                 &left_e, left_end);
666               gtk_text_buffer_get_iter_at_mark (content_buffer,
667                                                 &right_s, right_start);
668
669               for (list = split_tags,
670                      left_list = left_start_list,
671                      right_list = right_end_list;
672                    list && left_list && right_list;
673                    list = g_slist_next (list),
674                      left_list = g_slist_next (left_list),
675                      right_list = g_slist_next (right_list))
676                 {
677                   GtkTextTag  *tag        = list->data;
678                   GtkTextMark *left_start = left_list->data;
679                   GtkTextMark *right_end  = right_list->data;
680                   GtkTextIter  left_s;
681                   GtkTextIter  right_e;
682
683                   gtk_text_buffer_get_iter_at_mark (content_buffer,
684                                                     &left_s, left_start);
685                   gtk_text_buffer_get_iter_at_mark (content_buffer,
686                                                     &right_e, right_end);
687
688                   gtk_text_buffer_apply_tag (content_buffer, tag,
689                                              &left_s, &left_e);
690                   gtk_text_buffer_apply_tag (content_buffer, tag,
691                                              &right_s, &right_e);
692
693                   gtk_text_buffer_delete_mark (content_buffer, left_start);
694                   gtk_text_buffer_delete_mark (content_buffer, right_end);
695                 }
696
697               gtk_text_buffer_delete_mark (content_buffer, left_end);
698               gtk_text_buffer_delete_mark (content_buffer, right_start);
699
700               g_slist_free (split_tags);
701               g_slist_free (left_start_list);
702               g_slist_free (right_end_list);
703             }
704
705           return success;
706         }
707     }
708
709   g_set_error (error, 0, 0,
710                _("No deserialize function found for format %s"),
711                gdk_atom_name (format));
712
713   return FALSE;
714 }
715
716
717 /*  private functions  */
718
719 static GList *
720 register_format (GList          *formats,
721                  const gchar    *mime_type,
722                  gpointer        function,
723                  gpointer        user_data,
724                  GDestroyNotify  user_data_destroy,
725                  GdkAtom        *atom)
726 {
727   GtkRichTextFormat *format;
728
729   *atom = gdk_atom_intern (mime_type, FALSE);
730
731   formats = unregister_format (formats, *atom);
732
733   format = g_new0 (GtkRichTextFormat, 1);
734
735   format->mime_type         = g_strdup (mime_type);
736   format->can_create_tags   = FALSE;
737   format->atom              = *atom;
738   format->function          = function;
739   format->user_data         = user_data;
740   format->user_data_destroy = user_data_destroy;
741
742   return g_list_append (formats, format);
743 }
744
745 static GList *
746 unregister_format (GList   *formats,
747                    GdkAtom  atom)
748 {
749   GList *list;
750
751   for (list = formats; list; list = g_list_next (list))
752     {
753       GtkRichTextFormat *format = list->data;
754
755       if (format->atom == atom)
756         {
757           free_format (format);
758
759           return g_list_delete_link (formats, list);
760         }
761     }
762
763   return formats;
764 }
765
766 static GdkAtom *
767 get_formats (GList *formats,
768              gint  *n_formats)
769 {
770   GdkAtom *array;
771   GList   *list;
772   gint     i;
773
774   *n_formats = g_list_length (formats);
775   array = g_new0 (GdkAtom, *n_formats);
776
777   for (list = formats, i = 0; list; list = g_list_next (list), i++)
778     {
779       GtkRichTextFormat *format = list->data;
780
781       array[i] = format->atom;
782     }
783
784   return array;
785 }
786
787 static void
788 free_format (GtkRichTextFormat *format)
789 {
790   if (format->user_data_destroy)
791     format->user_data_destroy (format->user_data);
792
793   g_free (format->mime_type);
794   g_free (format);
795 }
796
797 static void
798 free_format_list (GList *formats)
799 {
800   g_list_foreach (formats, (GFunc) free_format, NULL);
801   g_list_free (formats);
802 }
803
804 static GQuark
805 serialize_quark (void)
806 {
807   static GQuark quark = 0;
808
809   if (! quark)
810     quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats");
811
812   return quark;
813 }
814
815 static GQuark
816 deserialize_quark (void)
817 {
818   static GQuark quark = 0;
819
820   if (! quark)
821     quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats");
822
823   return quark;
824 }
825
826 #define __GTK_TEXT_BUFFER_RICH_TEXT_C__
827 #include "gtkaliasdef.c"