]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbufferrichtext.c
stylecontext: Do invalidation on first resize container
[~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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23
24 #include "gtktextbufferrichtext.h"
25 #include "gtktextbufferserialize.h"
26 #include "gtkintl.h"
27
28
29 typedef struct
30 {
31   gchar          *mime_type;
32   gboolean        can_create_tags;
33   GdkAtom         atom;
34   gpointer        function;
35   gpointer        user_data;
36   GDestroyNotify  user_data_destroy;
37 } GtkRichTextFormat;
38
39
40 static GList   * register_format   (GList             *formats,
41                                     const gchar       *mime_type,
42                                     gpointer           function,
43                                     gpointer           user_data,
44                                     GDestroyNotify     user_data_destroy,
45                                     GdkAtom           *atom);
46 static GList   * unregister_format (GList             *formats,
47                                     GdkAtom            atom);
48 static GdkAtom * get_formats       (GList             *formats,
49                                     gint              *n_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);
54
55
56 /**
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
63  *
64  * This function registers a rich text serialization @function along with
65  * its @mime_type with the passed @buffer.
66  *
67  * Return value: (transfer none): the #GdkAtom that corresponds to the
68  *               newly registered format's mime-type.
69  *
70  * Since: 2.10
71  **/
72 GdkAtom
73 gtk_text_buffer_register_serialize_format (GtkTextBuffer              *buffer,
74                                            const gchar                *mime_type,
75                                            GtkTextBufferSerializeFunc  function,
76                                            gpointer                    user_data,
77                                            GDestroyNotify              user_data_destroy)
78 {
79   GList   *formats;
80   GdkAtom  atom;
81
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);
85
86   formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
87
88   formats = register_format (formats, mime_type,
89                              (gpointer) function,
90                              user_data, user_data_destroy,
91                              &atom);
92
93   g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
94                            formats, (GDestroyNotify) free_format_list);
95
96   g_object_notify (G_OBJECT (buffer), "copy-target-list");
97
98   return atom;
99 }
100
101 /**
102  * gtk_text_buffer_register_serialize_tagset:
103  * @buffer: a #GtkTextBuffer
104  * @tagset_name: (allow-none): an optional tagset name, on %NULL
105  *
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.
111  *
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.
117  *
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.
123  *
124  * Return value: (transfer none): the #GdkAtom that corresponds to the
125  *               newly registered format's mime-type.
126  *
127  * Since: 2.10
128  **/
129 GdkAtom
130 gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
131                                            const gchar   *tagset_name)
132 {
133   gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
134   GdkAtom  format;
135
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);
138
139   if (tagset_name)
140     mime_type =
141       g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
142                        tagset_name);
143
144   format = gtk_text_buffer_register_serialize_format (buffer, mime_type,
145                                                       _gtk_text_buffer_serialize_rich_text,
146                                                       NULL, NULL);
147
148   if (tagset_name)
149     g_free (mime_type);
150
151   return format;
152 }
153
154 /**
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
161  *
162  * This function registers a rich text deserialization @function along with
163  * its @mime_type with the passed @buffer.
164  *
165  * Return value: (transfer none): the #GdkAtom that corresponds to the
166  *               newly registered format's mime-type.
167  *
168  * Since: 2.10
169  **/
170 GdkAtom
171 gtk_text_buffer_register_deserialize_format (GtkTextBuffer                *buffer,
172                                              const gchar                  *mime_type,
173                                              GtkTextBufferDeserializeFunc  function,
174                                              gpointer                      user_data,
175                                              GDestroyNotify                user_data_destroy)
176 {
177   GList   *formats;
178   GdkAtom  atom;
179
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);
183
184   formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
185
186   formats = register_format (formats, mime_type,
187                              (gpointer) function,
188                              user_data, user_data_destroy,
189                              &atom);
190
191   g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
192                            formats, (GDestroyNotify) free_format_list);
193
194   g_object_notify (G_OBJECT (buffer), "paste-target-list");
195
196   return atom;
197 }
198
199 /**
200  * gtk_text_buffer_register_deserialize_tagset:
201  * @buffer: a #GtkTextBuffer
202  * @tagset_name: (allow-none): an optional tagset name, on %NULL
203  *
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.
207  *
208  * Return value: (transfer none): the #GdkAtom that corresponds to the
209  *               newly registered format's mime-type.
210  *
211  * Since: 2.10
212  **/
213 GdkAtom
214 gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
215                                              const gchar   *tagset_name)
216 {
217   gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
218   GdkAtom  format;
219
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);
222
223   if (tagset_name)
224     mime_type =
225       g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
226                        tagset_name);
227
228   format = gtk_text_buffer_register_deserialize_format (buffer, mime_type,
229                                                         _gtk_text_buffer_deserialize_rich_text,
230                                                         NULL, NULL);
231
232   if (tagset_name)
233     g_free (mime_type);
234
235   return format;
236 }
237
238 /**
239  * gtk_text_buffer_unregister_serialize_format:
240  * @buffer: a #GtkTextBuffer
241  * @format: a #GdkAtom representing a registered rich text format.
242  *
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()
246  *
247  * Since: 2.10
248  **/
249 void
250 gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
251                                              GdkAtom        format)
252 {
253   GList *formats;
254
255   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
256   g_return_if_fail (format != GDK_NONE);
257
258   formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
259
260   formats = unregister_format (formats, format);
261
262   g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
263                            formats, (GDestroyNotify) free_format_list);
264
265   g_object_notify (G_OBJECT (buffer), "copy-target-list");
266 }
267
268 /**
269  * gtk_text_buffer_unregister_deserialize_format:
270  * @buffer: a #GtkTextBuffer
271  * @format: a #GdkAtom representing a registered rich text format.
272  *
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().
276  *
277  * Since: 2.10
278  **/
279 void
280 gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
281                                                GdkAtom        format)
282 {
283   GList *formats;
284
285   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
286   g_return_if_fail (format != GDK_NONE);
287
288   formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
289
290   formats = unregister_format (formats, format);
291
292   g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
293                            formats, (GDestroyNotify) free_format_list);
294
295   g_object_notify (G_OBJECT (buffer), "paste-target-list");
296 }
297
298 /**
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
303  *
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.
309  *
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.
315  *
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.
321  *
322  * Since: 2.10
323  **/
324 void
325 gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
326                                                  GdkAtom        format,
327                                                  gboolean       can_create_tags)
328 {
329   GList *formats;
330   GList *list;
331   gchar *format_name;
332
333   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
334   g_return_if_fail (format != GDK_NONE);
335
336   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
337
338   for (list = formats; list; list = g_list_next (list))
339     {
340       GtkRichTextFormat *fmt = list->data;
341
342       if (fmt->atom == format)
343         {
344           fmt->can_create_tags = can_create_tags ? TRUE : FALSE;
345           return;
346         }
347     }
348
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);
354 }
355
356 /**
357  * gtk_text_buffer_deserialize_get_can_create_tags:
358  * @buffer: a #GtkTextBuffer
359  * @format: a #GdkAtom representing a registered rich text format
360  *
361  * This functions returns the value set with
362  * gtk_text_buffer_deserialize_set_can_create_tags()
363  *
364  * Return value: whether deserializing this format may create tags
365  *
366  * Since: 2.10
367  **/
368 gboolean
369 gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
370                                                  GdkAtom        format)
371 {
372   GList *formats;
373   GList *list;
374   gchar *format_name;
375
376   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
377   g_return_val_if_fail (format != GDK_NONE, FALSE);
378
379   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
380
381   for (list = formats; list; list = g_list_next (list))
382     {
383       GtkRichTextFormat *fmt = list->data;
384
385       if (fmt->atom == format)
386         {
387           return fmt->can_create_tags;
388         }
389     }
390
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);
396
397   return FALSE;
398 }
399
400 /**
401  * gtk_text_buffer_get_serialize_formats:
402  * @buffer: a #GtkTextBuffer
403  * @n_formats: return location for the number of formats
404  *
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()
408  *
409  * Return value: (array length=n_formats) (transfer container): an array of
410  *               #GdkAtom<!-- -->s representing the registered formats.
411  *
412  * Since: 2.10
413  **/
414 GdkAtom *
415 gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
416                                        gint          *n_formats)
417 {
418   GList *formats;
419
420   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
421   g_return_val_if_fail (n_formats != NULL, NULL);
422
423   formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ());
424
425   return get_formats (formats, n_formats);
426 }
427
428 /**
429  * gtk_text_buffer_get_deserialize_formats:
430  * @buffer: a #GtkTextBuffer
431  * @n_formats: return location for the number of formats
432  *
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()
436  *
437  * Return value: (array length=n_formats) (transfer container): an array of
438  *               #GdkAtom<!-- -->s representing the registered formats.
439  *
440  * Since: 2.10
441  **/
442 GdkAtom *
443 gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
444                                          gint          *n_formats)
445 {
446   GList *formats;
447
448   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
449   g_return_val_if_fail (n_formats != NULL, NULL);
450
451   formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
452
453   return get_formats (formats, n_formats);
454 }
455
456 /**
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
464  *
465  * This function serializes the portion of text between @start
466  * and @end in the rich text format represented by @format.
467  *
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.
471  *
472  * Return value: (array length=length) (transfer full): the serialized
473  *               data, encoded as @format
474  *
475  * Since: 2.10
476  **/
477 guint8 *
478 gtk_text_buffer_serialize (GtkTextBuffer     *register_buffer,
479                            GtkTextBuffer     *content_buffer,
480                            GdkAtom            format,
481                            const GtkTextIter *start,
482                            const GtkTextIter *end,
483                            gsize             *length)
484 {
485   GList *formats;
486   GList *list;
487
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);
494
495   *length = 0;
496
497   formats = g_object_get_qdata (G_OBJECT (register_buffer),
498                                 serialize_quark ());
499
500   for (list = formats; list; list = g_list_next (list))
501     {
502       GtkRichTextFormat *fmt = list->data;
503
504       if (fmt->atom == format)
505         {
506           GtkTextBufferSerializeFunc function = fmt->function;
507
508           return function (register_buffer, content_buffer,
509                            start, end, length, fmt->user_data);
510         }
511     }
512
513   return NULL;
514 }
515
516 /**
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
525  *
526  * This function deserializes rich text in format @format and inserts
527  * it at @iter.
528  *
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.
532  *
533  * Return value: %TRUE on success, %FALSE otherwise.
534  *
535  * Since: 2.10
536  **/
537 gboolean
538 gtk_text_buffer_deserialize (GtkTextBuffer  *register_buffer,
539                              GtkTextBuffer  *content_buffer,
540                              GdkAtom         format,
541                              GtkTextIter    *iter,
542                              const guint8   *data,
543                              gsize           length,
544                              GError        **error)
545 {
546   GList    *formats;
547   GList    *list;
548
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);
556
557   formats = g_object_get_qdata (G_OBJECT (register_buffer),
558                                 deserialize_quark ());
559
560   for (list = formats; list; list = g_list_next (list))
561     {
562       GtkRichTextFormat *fmt = list->data;
563
564       if (fmt->atom == format)
565         {
566           GtkTextBufferDeserializeFunc function = fmt->function;
567           gboolean                     success;
568           GSList                      *split_tags;
569           GSList                      *list;
570           GtkTextMark                 *left_end        = NULL;
571           GtkTextMark                 *right_start     = NULL;
572           GSList                      *left_start_list = NULL;
573           GSList                      *right_end_list  = NULL;
574
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
579            */
580           split_tags = gtk_text_iter_get_tags (iter);
581
582           list = split_tags;
583           while (list)
584             {
585               GtkTextTag *tag = list->data;
586
587               list = g_slist_next (list);
588
589               /*  If a tag begins at the insertion point, ignore it
590                *  because it doesn't affect the pasted text
591                */
592               if (gtk_text_iter_begins_tag (iter, tag))
593                 split_tags = g_slist_remove (split_tags, tag);
594             }
595
596           if (split_tags)
597             {
598               /*  Need to remember text marks, because text iters
599                *  don't survive pasting
600                */
601               left_end = gtk_text_buffer_create_mark (content_buffer,
602                                                       NULL, iter, TRUE);
603               right_start = gtk_text_buffer_create_mark (content_buffer,
604                                                          NULL, iter, FALSE);
605
606               for (list = split_tags; list; list = g_slist_next (list))
607                 {
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;
613
614                   gtk_text_iter_backward_to_tag_toggle (backward_toggle, tag);
615                   left_start = gtk_text_buffer_create_mark (content_buffer,
616                                                             NULL,
617                                                             backward_toggle,
618                                                             FALSE);
619
620                   gtk_text_iter_forward_to_tag_toggle (forward_toggle, tag);
621                   right_end = gtk_text_buffer_create_mark (content_buffer,
622                                                            NULL,
623                                                            forward_toggle,
624                                                            TRUE);
625
626                   left_start_list = g_slist_prepend (left_start_list, left_start);
627                   right_end_list = g_slist_prepend (right_end_list, right_end);
628
629                   gtk_text_buffer_remove_tag (content_buffer, tag,
630                                               backward_toggle,
631                                               forward_toggle);
632
633                   gtk_text_iter_free (forward_toggle);
634                   gtk_text_iter_free (backward_toggle);
635                 }
636
637               left_start_list = g_slist_reverse (left_start_list);
638               right_end_list = g_slist_reverse (right_end_list);
639             }
640
641           success = function (register_buffer, content_buffer,
642                               iter, data, length,
643                               fmt->can_create_tags,
644                               fmt->user_data,
645                               error);
646
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));
651
652           if (split_tags)
653             {
654               GSList      *left_list;
655               GSList      *right_list;
656               GtkTextIter  left_e;
657               GtkTextIter  right_s;
658
659               /*  Turn the remembered marks back into iters so they
660                *  can by used to re-apply the remembered tags
661                */
662               gtk_text_buffer_get_iter_at_mark (content_buffer,
663                                                 &left_e, left_end);
664               gtk_text_buffer_get_iter_at_mark (content_buffer,
665                                                 &right_s, right_start);
666
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))
674                 {
675                   GtkTextTag  *tag        = list->data;
676                   GtkTextMark *left_start = left_list->data;
677                   GtkTextMark *right_end  = right_list->data;
678                   GtkTextIter  left_s;
679                   GtkTextIter  right_e;
680
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);
685
686                   gtk_text_buffer_apply_tag (content_buffer, tag,
687                                              &left_s, &left_e);
688                   gtk_text_buffer_apply_tag (content_buffer, tag,
689                                              &right_s, &right_e);
690
691                   gtk_text_buffer_delete_mark (content_buffer, left_start);
692                   gtk_text_buffer_delete_mark (content_buffer, right_end);
693                 }
694
695               gtk_text_buffer_delete_mark (content_buffer, left_end);
696               gtk_text_buffer_delete_mark (content_buffer, right_start);
697
698               g_slist_free (split_tags);
699               g_slist_free (left_start_list);
700               g_slist_free (right_end_list);
701             }
702
703           return success;
704         }
705     }
706
707   g_set_error (error, 0, 0,
708                _("No deserialize function found for format %s"),
709                gdk_atom_name (format));
710
711   return FALSE;
712 }
713
714
715 /*  private functions  */
716
717 static GList *
718 register_format (GList          *formats,
719                  const gchar    *mime_type,
720                  gpointer        function,
721                  gpointer        user_data,
722                  GDestroyNotify  user_data_destroy,
723                  GdkAtom        *atom)
724 {
725   GtkRichTextFormat *format;
726
727   *atom = gdk_atom_intern (mime_type, FALSE);
728
729   formats = unregister_format (formats, *atom);
730
731   format = g_new0 (GtkRichTextFormat, 1);
732
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;
739
740   return g_list_append (formats, format);
741 }
742
743 static GList *
744 unregister_format (GList   *formats,
745                    GdkAtom  atom)
746 {
747   GList *list;
748
749   for (list = formats; list; list = g_list_next (list))
750     {
751       GtkRichTextFormat *format = list->data;
752
753       if (format->atom == atom)
754         {
755           free_format (format);
756
757           return g_list_delete_link (formats, list);
758         }
759     }
760
761   return formats;
762 }
763
764 static GdkAtom *
765 get_formats (GList *formats,
766              gint  *n_formats)
767 {
768   GdkAtom *array;
769   GList   *list;
770   gint     i;
771
772   *n_formats = g_list_length (formats);
773   array = g_new0 (GdkAtom, *n_formats);
774
775   for (list = formats, i = 0; list; list = g_list_next (list), i++)
776     {
777       GtkRichTextFormat *format = list->data;
778
779       array[i] = format->atom;
780     }
781
782   return array;
783 }
784
785 static void
786 free_format (GtkRichTextFormat *format)
787 {
788   if (format->user_data_destroy)
789     format->user_data_destroy (format->user_data);
790
791   g_free (format->mime_type);
792   g_free (format);
793 }
794
795 static void
796 free_format_list (GList *formats)
797 {
798   g_list_free_full (formats, (GDestroyNotify) free_format);
799 }
800
801 static GQuark
802 serialize_quark (void)
803 {
804   static GQuark quark = 0;
805
806   if (! quark)
807     quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats");
808
809   return quark;
810 }
811
812 static GQuark
813 deserialize_quark (void)
814 {
815   static GQuark quark = 0;
816
817   if (! quark)
818     quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats");
819
820   return quark;
821 }