]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
Remove unnecessary NULL checks before g_free(). (#369666, Morten Welinder,
[~andy/gtk] / gtk / gtktextbuffer.c
1 /* GTK - The GIMP Toolkit
2  * gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
3  *                 Copyright (C) 2004 Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26  */
27
28 #include <config.h>
29 #include <string.h>
30 #include <stdarg.h>
31
32 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
33 #include "gtkclipboard.h"
34 #include "gtkdnd.h"
35 #include "gtkinvisible.h"
36 #include "gtkmarshalers.h"
37 #include "gtktextbuffer.h"
38 #include "gtktextbufferrichtext.h"
39 #include "gtktextbtree.h"
40 #include "gtktextiterprivate.h"
41 #include "gtkprivate.h"
42 #include "gtkintl.h"
43 #include "gtkalias.h"
44
45
46 #define GTK_TEXT_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_BUFFER, GtkTextBufferPrivate))
47
48 typedef struct _GtkTextBufferPrivate GtkTextBufferPrivate;
49
50 struct _GtkTextBufferPrivate
51 {
52   GtkTargetList  *copy_target_list;
53   GtkTargetEntry *copy_target_entries;
54   gint            n_copy_target_entries;
55
56   GtkTargetList  *paste_target_list;
57   GtkTargetEntry *paste_target_entries;
58   gint            n_paste_target_entries;
59 };
60
61
62 typedef struct _ClipboardRequest ClipboardRequest;
63
64 struct _ClipboardRequest
65 {
66   GtkTextBuffer *buffer;
67   gboolean interactive;
68   gboolean default_editable;
69   gboolean is_clipboard;
70   gboolean replace_selection;
71 };
72
73 enum {
74   INSERT_TEXT,
75   INSERT_PIXBUF,
76   INSERT_CHILD_ANCHOR,
77   DELETE_RANGE,
78   CHANGED,
79   MODIFIED_CHANGED,
80   MARK_SET,
81   MARK_DELETED,
82   APPLY_TAG,
83   REMOVE_TAG,
84   BEGIN_USER_ACTION,
85   END_USER_ACTION,
86   LAST_SIGNAL
87 };
88
89 enum {
90   PROP_0,
91
92   /* Construct */
93   PROP_TAG_TABLE,
94
95   /* Normal */
96   PROP_TEXT,
97   PROP_HAS_SELECTION,
98   PROP_CURSOR_POSITION,
99   PROP_COPY_TARGET_LIST,
100   PROP_PASTE_TARGET_LIST
101 };
102
103 static void gtk_text_buffer_finalize   (GObject            *object);
104
105 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
106                                                         GtkTextIter       *iter,
107                                                         const gchar       *text,
108                                                         gint               len);
109 static void gtk_text_buffer_real_insert_pixbuf         (GtkTextBuffer     *buffer,
110                                                         GtkTextIter       *iter,
111                                                         GdkPixbuf         *pixbuf);
112 static void gtk_text_buffer_real_insert_anchor         (GtkTextBuffer     *buffer,
113                                                         GtkTextIter       *iter,
114                                                         GtkTextChildAnchor *anchor);
115 static void gtk_text_buffer_real_delete_range          (GtkTextBuffer     *buffer,
116                                                         GtkTextIter       *start,
117                                                         GtkTextIter       *end);
118 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
119                                                         GtkTextTag        *tag,
120                                                         const GtkTextIter *start_char,
121                                                         const GtkTextIter *end_char);
122 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
123                                                         GtkTextTag        *tag,
124                                                         const GtkTextIter *start_char,
125                                                         const GtkTextIter *end_char);
126 static void gtk_text_buffer_real_changed               (GtkTextBuffer     *buffer);
127 static void gtk_text_buffer_real_mark_set              (GtkTextBuffer     *buffer,
128                                                         const GtkTextIter *iter,
129                                                         GtkTextMark       *mark);
130
131 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
132 static void          free_log_attr_cache (GtkTextLogAttrCache *cache);
133
134 static void remove_all_selection_clipboards       (GtkTextBuffer *buffer);
135 static void update_selection_clipboards           (GtkTextBuffer *buffer);
136
137 static GtkTextBuffer *create_clipboard_contents_buffer (GtkTextBuffer *buffer);
138
139 static void gtk_text_buffer_free_target_lists     (GtkTextBuffer *buffer);
140
141 static guint signals[LAST_SIGNAL] = { 0 };
142
143 static void gtk_text_buffer_set_property (GObject         *object,
144                                           guint            prop_id,
145                                           const GValue    *value,
146                                           GParamSpec      *pspec);
147 static void gtk_text_buffer_get_property (GObject         *object,
148                                           guint            prop_id,
149                                           GValue          *value,
150                                           GParamSpec      *pspec);
151 static void gtk_text_buffer_notify       (GObject         *object,
152                                           GParamSpec      *pspec);
153
154 G_DEFINE_TYPE (GtkTextBuffer, gtk_text_buffer, G_TYPE_OBJECT)
155
156 static void
157 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
158 {
159   GObjectClass *object_class = G_OBJECT_CLASS (klass);
160
161   object_class->finalize = gtk_text_buffer_finalize;
162   object_class->set_property = gtk_text_buffer_set_property;
163   object_class->get_property = gtk_text_buffer_get_property;
164   object_class->notify       = gtk_text_buffer_notify;
165  
166   klass->insert_text = gtk_text_buffer_real_insert_text;
167   klass->insert_pixbuf = gtk_text_buffer_real_insert_pixbuf;
168   klass->insert_child_anchor = gtk_text_buffer_real_insert_anchor;
169   klass->delete_range = gtk_text_buffer_real_delete_range;
170   klass->apply_tag = gtk_text_buffer_real_apply_tag;
171   klass->remove_tag = gtk_text_buffer_real_remove_tag;
172   klass->changed = gtk_text_buffer_real_changed;
173   klass->mark_set = gtk_text_buffer_real_mark_set;
174
175   /* Construct */
176   g_object_class_install_property (object_class,
177                                    PROP_TAG_TABLE,
178                                    g_param_spec_object ("tag-table",
179                                                         P_("Tag Table"),
180                                                         P_("Text Tag Table"),
181                                                         GTK_TYPE_TEXT_TAG_TABLE,
182                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
183
184   /* Normal properties*/
185   
186   /**
187    * GtkTextBuffer:text:
188    *
189    * The text content of the buffer. Without child widgets and images,
190    * see gtk_text_buffer_get_text () for more information.
191    *
192    * Since: 2.8
193    */
194   g_object_class_install_property (object_class,
195                                    PROP_TEXT,
196                                    g_param_spec_string ("text",
197                                                         P_("Text"),
198                                                         P_("Current text of the buffer"),
199                                                         "",
200                                                         GTK_PARAM_READWRITE));
201
202   /**
203    * GtkTextBuffer:has-selection:
204    *
205    * Whether the buffer has some text currently selected.
206    *
207    * Since: 2.10
208    */
209   g_object_class_install_property (object_class,
210                                    PROP_HAS_SELECTION,
211                                    g_param_spec_boolean ("has-selection",
212                                                          P_("Has selection"),
213                                                          P_("Whether the buffer has some text currently selected"),
214                                                          FALSE,
215                                                          GTK_PARAM_READABLE));
216
217   /**
218    * GtkTextBuffer:cursor-position:
219    *
220    * The position of the insert mark (as offset from the beginning of the buffer). 
221    * It is useful for getting notified when the cursor moves.
222    *
223    * Since: 2.10
224    */
225   g_object_class_install_property (object_class,
226                                    PROP_CURSOR_POSITION,
227                                    g_param_spec_int ("cursor-position",
228                                                      P_("Cursor position"),
229                                                      P_("The position of the insert mark (as offset from the beginning of the buffer)"),
230                                                      0, G_MAXINT, 0,
231                                                      GTK_PARAM_READABLE));
232
233   /**
234    * GtkTextBuffer:copy-target-list:
235    *
236    * The list of targets this buffer supports for clipboard copying
237    * and as DND source.
238    *
239    * Since: 2.10
240    */
241   g_object_class_install_property (object_class,
242                                    PROP_COPY_TARGET_LIST,
243                                    g_param_spec_boxed ("copy-target-list",
244                                                        P_("Copy target list"),
245                                                        P_("The list of targets this buffer supports for clipboard copying and DND source"),
246                                                        GTK_TYPE_TARGET_LIST,
247                                                        GTK_PARAM_READABLE));
248
249   /**
250    * GtkTextBuffer:paste-target-list:
251    *
252    * The list of targets this buffer supports for clipboard pasting
253    * and as DND destination.
254    *
255    * Since: 2.10
256    */
257   g_object_class_install_property (object_class,
258                                    PROP_PASTE_TARGET_LIST,
259                                    g_param_spec_boxed ("paste-target-list",
260                                                        P_("Paste target list"),
261                                                        P_("The list of targets this buffer supports for clipboard pasting and DND destination"),
262                                                        GTK_TYPE_TARGET_LIST,
263                                                        GTK_PARAM_READABLE));
264
265   /**
266    * GtkTextBuffer::insert-text:
267    * @textbuffer: the object which received the signal
268    * @location: position to insert @text in @textbuffer
269    * @text: the UTF-8 text to be inserted
270    * @len: length of the inserted text in bytes
271    * 
272    * The insert_text signal is emitted to insert text in a #GtkTextBuffer.
273    * Insertion actually occurs in the default handler.  
274    * 
275    * Note that if your handler runs before the default handler it must not 
276    * invalidate the @location iter (or has to revalidate it). 
277    * The default signal handler revalidates it to point to the end of the 
278    * inserted text.
279    * 
280    * See also: 
281    * gtk_text_buffer_insert(), 
282    * gtk_text_buffer_insert_range().
283    */
284   signals[INSERT_TEXT] =
285     g_signal_new (I_("insert_text"),
286                   G_OBJECT_CLASS_TYPE (object_class),
287                   G_SIGNAL_RUN_LAST,
288                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_text),
289                   NULL, NULL,
290                   _gtk_marshal_VOID__BOXED_STRING_INT,
291                   G_TYPE_NONE,
292                   3,
293                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
294                   G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
295                   G_TYPE_INT);
296
297   /**
298    * GtkTextBuffer::insert-pixbuf:
299    * @textbuffer: the object which received the signal
300    * @location: position to insert @pixbuf in @textbuffer
301    * @pixbuf: the #GdkPixbuf to be inserted
302    * 
303    * The insert_pixbuf signal is emitted to insert a
304    * #GdkPixbuf in a #GtkTextBuffer.
305    * Insertion actually occurs in the default handler.
306    * 
307    * Note that if your handler runs before the default handler it must not 
308    * invalidate the @location iter (or has to revalidate it). 
309    * The default signal handler revalidates it to be placed after the 
310    * inserted @pixbuf.
311    * 
312    * See also:
313    * gtk_text_buffer_insert_pixbuf().
314    */
315   signals[INSERT_PIXBUF] =
316     g_signal_new (I_("insert_pixbuf"),
317                   G_OBJECT_CLASS_TYPE (object_class),
318                   G_SIGNAL_RUN_LAST,
319                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_pixbuf),
320                   NULL, NULL,
321                   _gtk_marshal_VOID__BOXED_OBJECT,
322                   G_TYPE_NONE,
323                   2,
324                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
325                   GDK_TYPE_PIXBUF);
326
327
328   /**
329    * GtkTextBuffer::insert-child-anchor:
330    * @textbuffer: the object which received the signal
331    * @location: position to insert @anchor in @textbuffer
332    * @anchor: the #GtkTextChildAnchor to be inserted
333    * 
334    * The insert_child_anchor signal is emitted to insert a
335    * #GtkTextChildAnchor in a #GtkTextBuffer.
336    * Insertion actually occurs in the default handler.
337    * 
338    * Note that if your handler runs before the default handler it must not 
339    * invalidate the @location iter (or has to revalidate it). 
340    * The default signal handler revalidates it to be placed after the 
341    * inserted @anchor.
342    * 
343    * See also:
344    * gtk_text_buffer_insert_child_anchor().
345    */
346   signals[INSERT_CHILD_ANCHOR] =
347     g_signal_new (I_("insert_child_anchor"),
348                   G_OBJECT_CLASS_TYPE (object_class),
349                   G_SIGNAL_RUN_LAST,
350                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_child_anchor),
351                   NULL, NULL,
352                   _gtk_marshal_VOID__BOXED_OBJECT,
353                   G_TYPE_NONE,
354                   2,
355                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
356                   GTK_TYPE_TEXT_CHILD_ANCHOR);
357   
358   /**
359    * GtkTextBuffer::delete-range:
360    * @textbuffer: the object which received the signal
361    * @start: the start of the range to be deleted
362    * @end: the end of the range to be deleted
363    * 
364    * The delete_range signal is emitted to delete a range 
365    * from a #GtkTextBuffer. 
366    * 
367    * Note that if your handler runs before the default handler it must not 
368    * invalidate the @start and @end iters (or has to revalidate them). 
369    * The default signal handler revalidates the @start and @end iters to 
370    * both point point to the location where text was deleted. Handlers
371    * which run after the default handler (see g_signal_connect_after())
372    * do not have access to the deleted text.
373    * 
374    * See also:
375    * gtk_text_buffer_delete().
376    */
377   signals[DELETE_RANGE] =
378     g_signal_new (I_("delete_range"),
379                   G_OBJECT_CLASS_TYPE (object_class),
380                   G_SIGNAL_RUN_LAST,
381                   G_STRUCT_OFFSET (GtkTextBufferClass, delete_range),
382                   NULL, NULL,
383                   _gtk_marshal_VOID__BOXED_BOXED,
384                   G_TYPE_NONE,
385                   2,
386                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
387                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
388
389   /**
390    * GtkTextBuffer::changed:
391    * @textbuffer: the object which received the signal
392    * 
393    * The changed signal is emitted when the content of a #GtkTextBuffer 
394    * has changed.
395    */
396   signals[CHANGED] =
397     g_signal_new (I_("changed"),
398                   G_OBJECT_CLASS_TYPE (object_class),
399                   G_SIGNAL_RUN_LAST,                   
400                   G_STRUCT_OFFSET (GtkTextBufferClass, changed),
401                   NULL, NULL,
402                   _gtk_marshal_VOID__VOID,
403                   G_TYPE_NONE,
404                   0);
405
406   /**
407    * GtkTextBuffer::modified-changed:
408    * @textbuffer: the object which received the signal
409    * 
410    * The modified_changed signal is emitted when the modified bit of a 
411    * #GtkTextBuffer flips.
412    * 
413    * See also:
414    * gtk_text_buffer_set_modified().
415    */
416   signals[MODIFIED_CHANGED] =
417     g_signal_new (I_("modified_changed"),
418                   G_OBJECT_CLASS_TYPE (object_class),
419                   G_SIGNAL_RUN_LAST,
420                   G_STRUCT_OFFSET (GtkTextBufferClass, modified_changed),
421                   NULL, NULL,
422                   _gtk_marshal_VOID__VOID,
423                   G_TYPE_NONE,
424                   0);
425
426   /**
427    * GtkTextBuffer::mark-set:
428    * @textbuffer: the object which received the signal
429    * @location: The location of @mark in @textbuffer
430    * @mark: The mark that is set
431    * 
432    * The mark_set signal is emitted as notification
433    * after a #GtkTextMark is set.
434    * 
435    * See also: 
436    * gtk_text_buffer_create_mark(),
437    * gtk_text_buffer_move_mark().
438    */
439   signals[MARK_SET] =
440     g_signal_new (I_("mark_set"),
441                   G_OBJECT_CLASS_TYPE (object_class),
442                   G_SIGNAL_RUN_LAST,                   
443                   G_STRUCT_OFFSET (GtkTextBufferClass, mark_set),
444                   NULL, NULL,
445                   _gtk_marshal_VOID__BOXED_OBJECT,
446                   G_TYPE_NONE,
447                   2,
448                   GTK_TYPE_TEXT_ITER,
449                   GTK_TYPE_TEXT_MARK);
450
451   /**
452    * GtkTextBuffer::mark-deleted:
453    * @textbuffer: the object which received the signal
454    * @mark: The mark that was deleted
455    * 
456    * The mark_deleted signal is emitted as notification
457    * after a #GtkTextMark is deleted. 
458    * 
459    * See also:
460    * gtk_text_buffer_delete_mark().
461    */
462   signals[MARK_DELETED] =
463     g_signal_new (I_("mark_deleted"),
464                   G_OBJECT_CLASS_TYPE (object_class),
465                   G_SIGNAL_RUN_LAST,                   
466                   G_STRUCT_OFFSET (GtkTextBufferClass, mark_deleted),
467                   NULL, NULL,
468                   _gtk_marshal_VOID__OBJECT,
469                   G_TYPE_NONE,
470                   1,
471                   GTK_TYPE_TEXT_MARK);
472
473    /**
474    * GtkTextBuffer::apply-tag:
475    * @textbuffer: the object which received the signal
476    * @tag: the applied tag
477    * @start: the start of the range the tag is applied to
478    * @end: the end of the range the tag is applied to
479    * 
480    * The apply_tag signal is emitted to apply a tag to a
481    * range of text in a #GtkTextBuffer. 
482    * Applying actually occurs in the default handler.
483    * 
484    * Note that if your handler runs before the default handler it must not 
485    * invalidate the @start and @end iters (or has to revalidate them). 
486    * 
487    * See also: 
488    * gtk_text_buffer_apply_tag(),
489    * gtk_text_buffer_insert_with_tags(),
490    * gtk_text_buffer_insert_range().
491    */ 
492   signals[APPLY_TAG] =
493     g_signal_new (I_("apply_tag"),
494                   G_OBJECT_CLASS_TYPE (object_class),
495                   G_SIGNAL_RUN_LAST,
496                   G_STRUCT_OFFSET (GtkTextBufferClass, apply_tag),
497                   NULL, NULL,
498                   _gtk_marshal_VOID__OBJECT_BOXED_BOXED,
499                   G_TYPE_NONE,
500                   3,
501                   GTK_TYPE_TEXT_TAG,
502                   GTK_TYPE_TEXT_ITER,
503                   GTK_TYPE_TEXT_ITER);
504
505
506    /**
507    * GtkTextBuffer::remove-tag:
508    * @textbuffer: the object which received the signal
509    * @tag: the tag to be removed
510    * @start: the start of the range the tag is removed from
511    * @end: the end of the range the tag is removed from
512    * 
513    * The remove_tag signal is emitted to remove all occurrences of @tag from a
514    * range of text in a #GtkTextBuffer. 
515    * Removal actually occurs in the default handler.
516    * 
517    * Note that if your handler runs before the default handler it must not 
518    * invalidate the @start and @end iters (or has to revalidate them). 
519    * 
520    * See also: 
521    * gtk_text_buffer_remove_tag(). 
522    */ 
523   signals[REMOVE_TAG] =
524     g_signal_new (I_("remove_tag"),
525                   G_OBJECT_CLASS_TYPE (object_class),
526                   G_SIGNAL_RUN_LAST,
527                   G_STRUCT_OFFSET (GtkTextBufferClass, remove_tag),
528                   NULL, NULL,
529                   _gtk_marshal_VOID__OBJECT_BOXED_BOXED,
530                   G_TYPE_NONE,
531                   3,
532                   GTK_TYPE_TEXT_TAG,
533                   GTK_TYPE_TEXT_ITER,
534                   GTK_TYPE_TEXT_ITER);
535
536    /**
537    * GtkTextBuffer::begin-user-action:
538    * @textbuffer: the object which received the signal
539    * 
540    * The begin_user_action signal is emitted at the beginning of a single
541    * user-visible operation on a #GtkTextBuffer.
542    * 
543    * See also: 
544    * gtk_text_buffer_begin_user_action(),
545    * gtk_text_buffer_insert_interactive(),
546    * gtk_text_buffer_insert_range_interactive(),
547    * gtk_text_buffer_delete_interactive(),
548    * gtk_text_buffer_backspace(),
549    * gtk_text_buffer_delete_selection().
550    */ 
551   signals[BEGIN_USER_ACTION] =
552     g_signal_new (I_("begin_user_action"),
553                   G_OBJECT_CLASS_TYPE (object_class),
554                   G_SIGNAL_RUN_LAST,                   
555                   G_STRUCT_OFFSET (GtkTextBufferClass, begin_user_action),
556                   NULL, NULL,
557                   _gtk_marshal_VOID__VOID,
558                   G_TYPE_NONE,
559                   0);
560
561    /**
562    * GtkTextBuffer::end-user-action:
563    * @textbuffer: the object which received the signal
564    * 
565    * The end_user_action signal is emitted at the end of a single
566    * user-visible operation #GtkTextBuffer.
567    * 
568    * See also: 
569    * gtk_text_buffer_end_user_action(),
570    * gtk_text_buffer_insert_interactive(),
571    * gtk_text_buffer_insert_range_interactive(),
572    * gtk_text_buffer_delete_interactive(),
573    * gtk_text_buffer_backspace(),
574    * gtk_text_buffer_delete_selection(),
575    * gtk_text_buffer_backspace().
576    */ 
577   signals[END_USER_ACTION] =
578     g_signal_new (I_("end_user_action"),
579                   G_OBJECT_CLASS_TYPE (object_class),
580                   G_SIGNAL_RUN_LAST,                   
581                   G_STRUCT_OFFSET (GtkTextBufferClass, end_user_action),
582                   NULL, NULL,
583                   _gtk_marshal_VOID__VOID,
584                   G_TYPE_NONE,
585                   0);
586
587   g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
588 }
589
590 static void
591 gtk_text_buffer_init (GtkTextBuffer *buffer)
592 {
593   buffer->clipboard_contents_buffers = NULL;
594   buffer->tag_table = NULL;
595
596   /* allow copying of arbiatray stuff in the internal rich text format */
597   gtk_text_buffer_register_serialize_tagset (buffer, NULL);
598 }
599
600 static void
601 set_table (GtkTextBuffer *buffer, GtkTextTagTable *table)
602 {
603   g_return_if_fail (buffer->tag_table == NULL);
604
605   if (table)
606     {
607       buffer->tag_table = table;
608       g_object_ref (buffer->tag_table);
609       _gtk_text_tag_table_add_buffer (table, buffer);
610     }
611 }
612
613 static GtkTextTagTable*
614 get_table (GtkTextBuffer *buffer)
615 {
616   if (buffer->tag_table == NULL)
617     {
618       buffer->tag_table = gtk_text_tag_table_new ();
619       _gtk_text_tag_table_add_buffer (buffer->tag_table, buffer);
620     }
621
622   return buffer->tag_table;
623 }
624
625 static void
626 gtk_text_buffer_set_property (GObject         *object,
627                               guint            prop_id,
628                               const GValue    *value,
629                               GParamSpec      *pspec)
630 {
631   GtkTextBuffer *text_buffer;
632
633   text_buffer = GTK_TEXT_BUFFER (object);
634
635   switch (prop_id)
636     {
637     case PROP_TAG_TABLE:
638       set_table (text_buffer, g_value_get_object (value));
639       break;
640
641     case PROP_TEXT:
642       gtk_text_buffer_set_text (text_buffer,
643                                 g_value_get_string (value), -1);
644       break;
645
646     default:
647       break;
648     }
649 }
650
651 static void
652 gtk_text_buffer_get_property (GObject         *object,
653                               guint            prop_id,
654                               GValue          *value,
655                               GParamSpec      *pspec)
656 {
657   GtkTextBuffer *text_buffer;
658   GtkTextIter iter;
659
660   text_buffer = GTK_TEXT_BUFFER (object);
661
662   switch (prop_id)
663     {
664     case PROP_TAG_TABLE:
665       g_value_set_object (value, get_table (text_buffer));
666       break;
667
668     case PROP_TEXT:
669       {
670         GtkTextIter start, end;
671
672         gtk_text_buffer_get_start_iter (text_buffer, &start);
673         gtk_text_buffer_get_end_iter (text_buffer, &end);
674
675         g_value_take_string (value,
676                             gtk_text_buffer_get_text (text_buffer,
677                                                       &start, &end, FALSE));
678         break;
679       }
680
681     case PROP_HAS_SELECTION:
682       g_value_set_boolean (value, text_buffer->has_selection);
683       break;
684
685     case PROP_CURSOR_POSITION:
686       gtk_text_buffer_get_iter_at_mark (text_buffer, &iter, 
687                                         gtk_text_buffer_get_insert (text_buffer));
688       g_value_set_int (value, gtk_text_iter_get_offset (&iter));
689       break;
690
691     case PROP_COPY_TARGET_LIST:
692       g_value_set_boxed (value, gtk_text_buffer_get_copy_target_list (text_buffer));
693       break;
694
695     case PROP_PASTE_TARGET_LIST:
696       g_value_set_boxed (value, gtk_text_buffer_get_paste_target_list (text_buffer));
697       break;
698
699     default:
700       break;
701     }
702 }
703
704 static void
705 gtk_text_buffer_notify (GObject    *object,
706                         GParamSpec *pspec)
707 {
708   if (!strcmp (pspec->name, "copy-target-list") ||
709       !strcmp (pspec->name, "paste-target-list"))
710     {
711       gtk_text_buffer_free_target_lists (GTK_TEXT_BUFFER (object));
712     }
713 }
714
715 /**
716  * gtk_text_buffer_new:
717  * @table: a tag table, or NULL to create a new one
718  *
719  * Creates a new text buffer.
720  *
721  * Return value: a new text buffer
722  **/
723 GtkTextBuffer*
724 gtk_text_buffer_new (GtkTextTagTable *table)
725 {
726   GtkTextBuffer *text_buffer;
727
728   text_buffer = g_object_new (GTK_TYPE_TEXT_BUFFER, "tag-table", table, NULL);
729
730   return text_buffer;
731 }
732
733 static void
734 gtk_text_buffer_finalize (GObject *object)
735 {
736   GtkTextBuffer *buffer;
737
738   buffer = GTK_TEXT_BUFFER (object);
739
740   remove_all_selection_clipboards (buffer);
741
742   if (buffer->tag_table)
743     {
744       _gtk_text_tag_table_remove_buffer (buffer->tag_table, buffer);
745       g_object_unref (buffer->tag_table);
746       buffer->tag_table = NULL;
747     }
748
749   if (buffer->btree)
750     {
751       _gtk_text_btree_unref (buffer->btree);
752       buffer->btree = NULL;
753     }
754
755   if (buffer->log_attr_cache)
756     free_log_attr_cache (buffer->log_attr_cache);
757
758   buffer->log_attr_cache = NULL;
759
760   gtk_text_buffer_free_target_lists (buffer);
761
762   G_OBJECT_CLASS (gtk_text_buffer_parent_class)->finalize (object);
763 }
764
765 static GtkTextBTree*
766 get_btree (GtkTextBuffer *buffer)
767 {
768   if (buffer->btree == NULL)
769     buffer->btree = _gtk_text_btree_new (gtk_text_buffer_get_tag_table (buffer),
770                                          buffer);
771
772   return buffer->btree;
773 }
774
775 GtkTextBTree*
776 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
777 {
778   return get_btree (buffer);
779 }
780
781 /**
782  * gtk_text_buffer_get_tag_table:
783  * @buffer: a #GtkTextBuffer
784  *
785  * Get the #GtkTextTagTable associated with this buffer.
786  *
787  * Return value: the buffer's tag table
788  **/
789 GtkTextTagTable*
790 gtk_text_buffer_get_tag_table (GtkTextBuffer  *buffer)
791 {
792   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
793
794   return get_table (buffer);
795 }
796
797 /**
798  * gtk_text_buffer_set_text:
799  * @buffer: a #GtkTextBuffer
800  * @text: UTF-8 text to insert
801  * @len: length of @text in bytes
802  *
803  * Deletes current contents of @buffer, and inserts @text instead. If
804  * @len is -1, @text must be nul-terminated. @text must be valid UTF-8.
805  **/
806 void
807 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
808                           const gchar   *text,
809                           gint           len)
810 {
811   GtkTextIter start, end;
812
813   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
814   g_return_if_fail (text != NULL);
815
816   if (len < 0)
817     len = strlen (text);
818
819   gtk_text_buffer_get_bounds (buffer, &start, &end);
820
821   gtk_text_buffer_delete (buffer, &start, &end);
822
823   if (len > 0)
824     {
825       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
826       gtk_text_buffer_insert (buffer, &start, text, len);
827     }
828   
829   g_object_notify (G_OBJECT (buffer), "text");
830 }
831
832  
833
834 /*
835  * Insertion
836  */
837
838 static void
839 gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
840                                   GtkTextIter *iter,
841                                   const gchar *text,
842                                   gint len)
843 {
844   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
845   g_return_if_fail (iter != NULL);
846   
847   _gtk_text_btree_insert (iter, text, len);
848
849   g_signal_emit (buffer, signals[CHANGED], 0);
850   g_object_notify (G_OBJECT (buffer), "cursor-position");
851 }
852
853 static void
854 gtk_text_buffer_emit_insert (GtkTextBuffer *buffer,
855                              GtkTextIter   *iter,
856                              const gchar   *text,
857                              gint           len)
858 {
859   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
860   g_return_if_fail (iter != NULL);
861   g_return_if_fail (text != NULL);
862
863   if (len < 0)
864     len = strlen (text);
865
866   g_return_if_fail (g_utf8_validate (text, len, NULL));
867   
868   if (len > 0)
869     {
870       g_signal_emit (buffer, signals[INSERT_TEXT], 0,
871                      iter, text, len);
872     }
873 }
874
875 /**
876  * gtk_text_buffer_insert:
877  * @buffer: a #GtkTextBuffer
878  * @iter: a position in the buffer
879  * @text: UTF-8 format text to insert
880  * @len: length of text in bytes, or -1
881  *
882  * Inserts @len bytes of @text at position @iter.  If @len is -1,
883  * @text must be nul-terminated and will be inserted in its
884  * entirety. Emits the "insert_text" signal; insertion actually occurs
885  * in the default handler for the signal. @iter is invalidated when
886  * insertion occurs (because the buffer contents change), but the
887  * default signal handler revalidates it to point to the end of the
888  * inserted text.
889  *
890  **/
891 void
892 gtk_text_buffer_insert (GtkTextBuffer *buffer,
893                         GtkTextIter *iter,
894                         const gchar *text,
895                         gint len)
896 {
897   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
898   g_return_if_fail (iter != NULL);
899   g_return_if_fail (text != NULL);
900   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
901   
902   gtk_text_buffer_emit_insert (buffer, iter, text, len);
903 }
904
905 /**
906  * gtk_text_buffer_insert_at_cursor:
907  * @buffer: a #GtkTextBuffer
908  * @text: some text in UTF-8 format
909  * @len: length of text, in bytes
910  *
911  * Simply calls gtk_text_buffer_insert (), using the current
912  * cursor position as the insertion point.
913  **/
914 void
915 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
916                                   const gchar *text,
917                                   gint len)
918 {
919   GtkTextIter iter;
920
921   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
922   g_return_if_fail (text != NULL);
923
924   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
925                                     gtk_text_buffer_get_mark (buffer,
926                                                               "insert"));
927
928   gtk_text_buffer_insert (buffer, &iter, text, len);
929 }
930
931 /**
932  * gtk_text_buffer_insert_interactive:
933  * @buffer: a #GtkTextBuffer
934  * @iter: a position in @buffer
935  * @text: some UTF-8 text
936  * @len: length of text in bytes, or -1
937  * @default_editable: default editability of buffer
938  *
939  * Like gtk_text_buffer_insert(), but the insertion will not occur if
940  * @iter is at a non-editable location in the buffer.  Usually you
941  * want to prevent insertions at ineditable locations if the insertion
942  * results from a user action (is interactive).
943  *
944  * @default_editable indicates the editability of text that doesn't
945  * have a tag affecting editability applied to it. Typically the
946  * result of gtk_text_view_get_editable() is appropriate here.
947  *
948  * Return value: whether text was actually inserted
949  **/
950 gboolean
951 gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer,
952                                     GtkTextIter   *iter,
953                                     const gchar   *text,
954                                     gint           len,
955                                     gboolean       default_editable)
956 {
957   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
958   g_return_val_if_fail (text != NULL, FALSE);
959   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, FALSE);
960
961   if (gtk_text_iter_can_insert (iter, default_editable))
962     {
963       gtk_text_buffer_begin_user_action (buffer);
964       gtk_text_buffer_emit_insert (buffer, iter, text, len);
965       gtk_text_buffer_end_user_action (buffer);
966       return TRUE;
967     }
968   else
969     return FALSE;
970 }
971
972 /**
973  * gtk_text_buffer_insert_interactive_at_cursor:
974  * @buffer: a #GtkTextBuffer
975  * @text: text in UTF-8 format
976  * @len: length of text in bytes, or -1
977  * @default_editable: default editability of buffer
978  *
979  * Calls gtk_text_buffer_insert_interactive () at the cursor
980  * position.
981  *
982  * @default_editable indicates the editability of text that doesn't
983  * have a tag affecting editability applied to it. Typically the
984  * result of gtk_text_view_get_editable() is appropriate here.
985  * 
986  * Return value: whether text was actually inserted
987  **/
988 gboolean
989 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
990                                               const gchar   *text,
991                                               gint           len,
992                                               gboolean       default_editable)
993 {
994   GtkTextIter iter;
995
996   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
997   g_return_val_if_fail (text != NULL, FALSE);
998
999   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
1000                                     gtk_text_buffer_get_mark (buffer,
1001                                                               "insert"));
1002
1003   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
1004                                              default_editable);
1005 }
1006
1007 static gboolean
1008 possibly_not_text (gunichar ch,
1009                    gpointer user_data)
1010 {
1011   return ch == GTK_TEXT_UNKNOWN_CHAR;
1012 }
1013
1014 static void
1015 insert_text_range (GtkTextBuffer     *buffer,
1016                    GtkTextIter       *iter,
1017                    const GtkTextIter *orig_start,
1018                    const GtkTextIter *orig_end,
1019                    gboolean           interactive)
1020 {
1021   gchar *text;
1022
1023   text = gtk_text_iter_get_text (orig_start, orig_end);
1024
1025   gtk_text_buffer_emit_insert (buffer, iter, text, -1);
1026
1027   g_free (text);
1028 }
1029
1030 typedef struct _Range Range;
1031 struct _Range
1032 {
1033   GtkTextBuffer *buffer;
1034   GtkTextMark *start_mark;
1035   GtkTextMark *end_mark;
1036   GtkTextMark *whole_end_mark;
1037   GtkTextIter *range_start;
1038   GtkTextIter *range_end;
1039   GtkTextIter *whole_end;
1040 };
1041
1042 static Range*
1043 save_range (GtkTextIter *range_start,
1044             GtkTextIter *range_end,
1045             GtkTextIter *whole_end)
1046 {
1047   Range *r;
1048
1049   r = g_new (Range, 1);
1050
1051   r->buffer = gtk_text_iter_get_buffer (range_start);
1052   g_object_ref (r->buffer);
1053   
1054   r->start_mark = 
1055     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1056                                  NULL,
1057                                  range_start,
1058                                  FALSE);
1059   r->end_mark = 
1060     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1061                                  NULL,
1062                                  range_end,
1063                                  TRUE);
1064
1065   r->whole_end_mark = 
1066     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1067                                  NULL,
1068                                  whole_end,
1069                                  TRUE);
1070
1071   r->range_start = range_start;
1072   r->range_end = range_end;
1073   r->whole_end = whole_end;
1074
1075   return r;
1076 }
1077
1078 static void
1079 restore_range (Range *r)
1080 {
1081   gtk_text_buffer_get_iter_at_mark (r->buffer,
1082                                     r->range_start,
1083                                     r->start_mark);
1084       
1085   gtk_text_buffer_get_iter_at_mark (r->buffer,
1086                                     r->range_end,
1087                                     r->end_mark);
1088       
1089   gtk_text_buffer_get_iter_at_mark (r->buffer,
1090                                     r->whole_end,
1091                                     r->whole_end_mark);  
1092   
1093   gtk_text_buffer_delete_mark (r->buffer, r->start_mark);
1094   gtk_text_buffer_delete_mark (r->buffer, r->end_mark);
1095   gtk_text_buffer_delete_mark (r->buffer, r->whole_end_mark);
1096
1097   /* Due to the gravities on the marks, the ordering could have
1098    * gotten mangled; we switch to an empty range in that
1099    * case
1100    */
1101   
1102   if (gtk_text_iter_compare (r->range_start, r->range_end) > 0)
1103     *r->range_start = *r->range_end;
1104
1105   if (gtk_text_iter_compare (r->range_end, r->whole_end) > 0)
1106     *r->range_end = *r->whole_end;
1107   
1108   g_object_unref (r->buffer);
1109   g_free (r); 
1110 }
1111
1112 static void
1113 insert_range_untagged (GtkTextBuffer     *buffer,
1114                        GtkTextIter       *iter,
1115                        const GtkTextIter *orig_start,
1116                        const GtkTextIter *orig_end,
1117                        gboolean           interactive)
1118 {
1119   GtkTextIter range_start;
1120   GtkTextIter range_end;
1121   GtkTextIter start, end;
1122   Range *r;
1123   
1124   if (gtk_text_iter_equal (orig_start, orig_end))
1125     return;
1126
1127   start = *orig_start;
1128   end = *orig_end;
1129   
1130   range_start = start;
1131   range_end = start;
1132   
1133   while (TRUE)
1134     {
1135       if (gtk_text_iter_equal (&range_start, &range_end))
1136         {
1137           /* Figure out how to move forward */
1138
1139           g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1140           
1141           if (gtk_text_iter_equal (&range_end, &end))
1142             {
1143               /* nothing left to do */
1144               break;
1145             }
1146           else if (gtk_text_iter_get_char (&range_end) == GTK_TEXT_UNKNOWN_CHAR)
1147             {
1148               GdkPixbuf *pixbuf = NULL;
1149               GtkTextChildAnchor *anchor = NULL;
1150               pixbuf = gtk_text_iter_get_pixbuf (&range_end);
1151               anchor = gtk_text_iter_get_child_anchor (&range_end);
1152
1153               if (pixbuf)
1154                 {
1155                   r = save_range (&range_start,
1156                                   &range_end,
1157                                   &end);
1158
1159                   gtk_text_buffer_insert_pixbuf (buffer,
1160                                                  iter,
1161                                                  pixbuf);
1162
1163                   restore_range (r);
1164                   r = NULL;
1165                   
1166                   gtk_text_iter_forward_char (&range_end);
1167                   
1168                   range_start = range_end;
1169                 }
1170               else if (anchor)
1171                 {
1172                   /* Just skip anchors */
1173
1174                   gtk_text_iter_forward_char (&range_end);
1175                   range_start = range_end;
1176                 }
1177               else
1178                 {
1179                   /* The GTK_TEXT_UNKNOWN_CHAR was in a text segment, so
1180                    * keep going. 
1181                    */
1182                   gtk_text_iter_forward_find_char (&range_end,
1183                                                    possibly_not_text, NULL,
1184                                                    &end);
1185                   
1186                   g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1187                 }
1188             }
1189           else
1190             {
1191               /* Text segment starts here, so forward search to
1192                * find its possible endpoint
1193                */
1194               gtk_text_iter_forward_find_char (&range_end,
1195                                                possibly_not_text, NULL,
1196                                                &end);
1197               
1198               g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1199             }
1200         }
1201       else
1202         {
1203           r = save_range (&range_start,
1204                           &range_end,
1205                           &end);
1206           
1207           insert_text_range (buffer,
1208                              iter,
1209                              &range_start,
1210                              &range_end,
1211                              interactive);
1212
1213           restore_range (r);
1214           r = NULL;
1215           
1216           range_start = range_end;
1217         }
1218     }
1219 }
1220
1221 static void
1222 insert_range_not_inside_self (GtkTextBuffer     *buffer,
1223                               GtkTextIter       *iter,
1224                               const GtkTextIter *orig_start,
1225                               const GtkTextIter *orig_end,
1226                               gboolean           interactive)
1227 {
1228   /* Find each range of uniformly-tagged text, insert it,
1229    * then apply the tags.
1230    */
1231   GtkTextIter start = *orig_start;
1232   GtkTextIter end = *orig_end;
1233   GtkTextIter range_start;
1234   GtkTextIter range_end;
1235   
1236   if (gtk_text_iter_equal (orig_start, orig_end))
1237     return;
1238   
1239   gtk_text_iter_order (&start, &end);
1240
1241   range_start = start;
1242   range_end = start;  
1243   
1244   while (TRUE)
1245     {
1246       gint start_offset;
1247       GtkTextIter start_iter;
1248       GSList *tags;
1249       GSList *tmp_list;
1250       Range *r;
1251       
1252       if (gtk_text_iter_equal (&range_start, &end))
1253         break; /* All done */
1254
1255       g_assert (gtk_text_iter_compare (&range_start, &end) < 0);
1256       
1257       gtk_text_iter_forward_to_tag_toggle (&range_end, NULL);
1258
1259       g_assert (!gtk_text_iter_equal (&range_start, &range_end));
1260
1261       /* Clamp to the end iterator */
1262       if (gtk_text_iter_compare (&range_end, &end) > 0)
1263         range_end = end;
1264       
1265       /* We have a range with unique tags; insert it, and
1266        * apply all tags.
1267        */
1268       start_offset = gtk_text_iter_get_offset (iter);
1269
1270       r = save_range (&range_start, &range_end, &end);
1271       
1272       insert_range_untagged (buffer, iter, &range_start, &range_end, interactive);
1273
1274       restore_range (r);
1275       r = NULL;
1276       
1277       gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
1278       
1279       tags = gtk_text_iter_get_tags (&range_start);
1280       tmp_list = tags;
1281       while (tmp_list != NULL)
1282         {
1283           gtk_text_buffer_apply_tag (buffer,
1284                                      tmp_list->data,
1285                                      &start_iter,
1286                                      iter);
1287           
1288           tmp_list = g_slist_next (tmp_list);
1289         }
1290       g_slist_free (tags);
1291
1292       range_start = range_end;
1293     }
1294 }
1295
1296 static void
1297 gtk_text_buffer_real_insert_range (GtkTextBuffer     *buffer,
1298                                    GtkTextIter       *iter,
1299                                    const GtkTextIter *orig_start,
1300                                    const GtkTextIter *orig_end,
1301                                    gboolean           interactive)
1302 {
1303   GtkTextBuffer *src_buffer;
1304   
1305   /* Find each range of uniformly-tagged text, insert it,
1306    * then apply the tags.
1307    */  
1308   if (gtk_text_iter_equal (orig_start, orig_end))
1309     return;
1310
1311   if (interactive)
1312     gtk_text_buffer_begin_user_action (buffer);
1313   
1314   src_buffer = gtk_text_iter_get_buffer (orig_start);
1315   
1316   if (gtk_text_iter_get_buffer (iter) != src_buffer ||
1317       !gtk_text_iter_in_range (iter, orig_start, orig_end))
1318     {
1319       insert_range_not_inside_self (buffer, iter, orig_start, orig_end, interactive);
1320     }
1321   else
1322     {
1323       /* If you insert a range into itself, it could loop infinitely
1324        * because the region being copied keeps growing as we insert. So
1325        * we have to separately copy the range before and after
1326        * the insertion point.
1327        */
1328       GtkTextIter start = *orig_start;
1329       GtkTextIter end = *orig_end;
1330       GtkTextIter range_start;
1331       GtkTextIter range_end;
1332       Range *first_half;
1333       Range *second_half;
1334
1335       gtk_text_iter_order (&start, &end);
1336       
1337       range_start = start;
1338       range_end = *iter;
1339       first_half = save_range (&range_start, &range_end, &end);
1340
1341       range_start = *iter;
1342       range_end = end;
1343       second_half = save_range (&range_start, &range_end, &end);
1344
1345       restore_range (first_half);
1346       insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive);
1347
1348       restore_range (second_half);
1349       insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive);
1350     }
1351   
1352   if (interactive)
1353     gtk_text_buffer_end_user_action (buffer);
1354 }
1355
1356 /**
1357  * gtk_text_buffer_insert_range:
1358  * @buffer: a #GtkTextBuffer
1359  * @iter: a position in @buffer
1360  * @start: a position in a #GtkTextBuffer
1361  * @end: another position in the same buffer as @start
1362  *
1363  * Copies text, tags, and pixbufs between @start and @end (the order
1364  * of @start and @end doesn't matter) and inserts the copy at @iter.
1365  * Used instead of simply getting/inserting text because it preserves
1366  * images and tags. If @start and @end are in a different buffer from
1367  * @buffer, the two buffers must share the same tag table.
1368  *
1369  * Implemented via emissions of the insert_text and apply_tag signals,
1370  * so expect those.
1371  **/
1372 void
1373 gtk_text_buffer_insert_range (GtkTextBuffer     *buffer,
1374                               GtkTextIter       *iter,
1375                               const GtkTextIter *start,
1376                               const GtkTextIter *end)
1377 {
1378   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1379   g_return_if_fail (iter != NULL);
1380   g_return_if_fail (start != NULL);
1381   g_return_if_fail (end != NULL);
1382   g_return_if_fail (gtk_text_iter_get_buffer (start) ==
1383                     gtk_text_iter_get_buffer (end));
1384   g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
1385                     buffer->tag_table);  
1386   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1387   
1388   gtk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE);
1389 }
1390
1391 /**
1392  * gtk_text_buffer_insert_range_interactive:
1393  * @buffer: a #GtkTextBuffer
1394  * @iter: a position in @buffer
1395  * @start: a position in a #GtkTextBuffer
1396  * @end: another position in the same buffer as @start
1397  * @default_editable: default editability of the buffer
1398  *
1399  * Same as gtk_text_buffer_insert_range(), but does nothing if the
1400  * insertion point isn't editable. The @default_editable parameter
1401  * indicates whether the text is editable at @iter if no tags
1402  * enclosing @iter affect editability. Typically the result of
1403  * gtk_text_view_get_editable() is appropriate here.
1404  *
1405  * Returns: whether an insertion was possible at @iter
1406  **/
1407 gboolean
1408 gtk_text_buffer_insert_range_interactive (GtkTextBuffer     *buffer,
1409                                           GtkTextIter       *iter,
1410                                           const GtkTextIter *start,
1411                                           const GtkTextIter *end,
1412                                           gboolean           default_editable)
1413 {
1414   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1415   g_return_val_if_fail (iter != NULL, FALSE);
1416   g_return_val_if_fail (start != NULL, FALSE);
1417   g_return_val_if_fail (end != NULL, FALSE);
1418   g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
1419                         gtk_text_iter_get_buffer (end), FALSE);
1420   g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
1421                         buffer->tag_table, FALSE);
1422
1423
1424   if (gtk_text_iter_can_insert (iter, default_editable))
1425     {
1426       gtk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE);
1427       return TRUE;
1428     }
1429   else
1430     return FALSE;
1431 }
1432
1433 /**
1434  * gtk_text_buffer_insert_with_tags:
1435  * @buffer: a #GtkTextBuffer
1436  * @iter: an iterator in @buffer
1437  * @text: UTF-8 text
1438  * @len: length of @text, or -1
1439  * @first_tag: first tag to apply to @text
1440  * @Varargs: NULL-terminated list of tags to apply
1441  *
1442  * Inserts @text into @buffer at @iter, applying the list of tags to
1443  * the newly-inserted text. The last tag specified must be NULL to
1444  * terminate the list. Equivalent to calling gtk_text_buffer_insert (),
1445  * then gtk_text_buffer_apply_tag () on the inserted text;
1446  * gtk_text_buffer_insert_with_tags () is just a convenience function.
1447  **/
1448 void
1449 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
1450                                   GtkTextIter   *iter,
1451                                   const gchar   *text,
1452                                   gint           len,
1453                                   GtkTextTag    *first_tag,
1454                                   ...)
1455 {
1456   gint start_offset;
1457   GtkTextIter start;
1458   va_list args;
1459   GtkTextTag *tag;
1460
1461   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1462   g_return_if_fail (iter != NULL);
1463   g_return_if_fail (text != NULL);
1464   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1465   
1466   start_offset = gtk_text_iter_get_offset (iter);
1467
1468   gtk_text_buffer_insert (buffer, iter, text, len);
1469
1470   if (first_tag == NULL)
1471     return;
1472
1473   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1474
1475   va_start (args, first_tag);
1476   tag = first_tag;
1477   while (tag)
1478     {
1479       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1480
1481       tag = va_arg (args, GtkTextTag*);
1482     }
1483
1484   va_end (args);
1485 }
1486
1487 /**
1488  * gtk_text_buffer_insert_with_tags_by_name:
1489  * @buffer: a #GtkTextBuffer
1490  * @iter: position in @buffer
1491  * @text: UTF-8 text
1492  * @len: length of @text, or -1
1493  * @first_tag_name: name of a tag to apply to @text
1494  * @Varargs: more tag names
1495  *
1496  * Same as gtk_text_buffer_insert_with_tags (), but allows you
1497  * to pass in tag names instead of tag objects.
1498  **/
1499 void
1500 gtk_text_buffer_insert_with_tags_by_name  (GtkTextBuffer *buffer,
1501                                            GtkTextIter   *iter,
1502                                            const gchar   *text,
1503                                            gint           len,
1504                                            const gchar   *first_tag_name,
1505                                            ...)
1506 {
1507   gint start_offset;
1508   GtkTextIter start;
1509   va_list args;
1510   const gchar *tag_name;
1511
1512   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1513   g_return_if_fail (iter != NULL);
1514   g_return_if_fail (text != NULL);
1515   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1516   
1517   start_offset = gtk_text_iter_get_offset (iter);
1518
1519   gtk_text_buffer_insert (buffer, iter, text, len);
1520
1521   if (first_tag_name == NULL)
1522     return;
1523
1524   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1525
1526   va_start (args, first_tag_name);
1527   tag_name = first_tag_name;
1528   while (tag_name)
1529     {
1530       GtkTextTag *tag;
1531
1532       tag = gtk_text_tag_table_lookup (buffer->tag_table,
1533                                        tag_name);
1534
1535       if (tag == NULL)
1536         {
1537           g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
1538           return;
1539         }
1540
1541       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1542
1543       tag_name = va_arg (args, const gchar*);
1544     }
1545
1546   va_end (args);
1547 }
1548
1549
1550 /*
1551  * Deletion
1552  */
1553
1554 static void
1555 gtk_text_buffer_real_delete_range (GtkTextBuffer *buffer,
1556                                    GtkTextIter   *start,
1557                                    GtkTextIter   *end)
1558 {
1559   gboolean has_selection;
1560
1561   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1562   g_return_if_fail (start != NULL);
1563   g_return_if_fail (end != NULL);
1564
1565   _gtk_text_btree_delete (start, end);
1566
1567   /* may have deleted the selection... */
1568   update_selection_clipboards (buffer);
1569
1570   has_selection = gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
1571   if (has_selection != buffer->has_selection)
1572     {
1573       buffer->has_selection = has_selection;
1574       g_object_notify (G_OBJECT (buffer), "has-selection");
1575     }
1576
1577   g_signal_emit (buffer, signals[CHANGED], 0);
1578   g_object_notify (G_OBJECT (buffer), "cursor-position");
1579 }
1580
1581 static void
1582 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
1583                              GtkTextIter *start,
1584                              GtkTextIter *end)
1585 {
1586   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1587   g_return_if_fail (start != NULL);
1588   g_return_if_fail (end != NULL);
1589
1590   if (gtk_text_iter_equal (start, end))
1591     return;
1592
1593   gtk_text_iter_order (start, end);
1594
1595   g_signal_emit (buffer,
1596                  signals[DELETE_RANGE],
1597                  0,
1598                  start, end);
1599 }
1600
1601 /**
1602  * gtk_text_buffer_delete:
1603  * @buffer: a #GtkTextBuffer
1604  * @start: a position in @buffer
1605  * @end: another position in @buffer
1606  *
1607  * Deletes text between @start and @end. The order of @start and @end
1608  * is not actually relevant; gtk_text_buffer_delete () will reorder
1609  * them. This function actually emits the "delete_range" signal, and
1610  * the default handler of that signal deletes the text. Because the
1611  * buffer is modified, all outstanding iterators become invalid after
1612  * calling this function; however, the @start and @end will be
1613  * re-initialized to point to the location where text was deleted.
1614  *
1615  **/
1616 void
1617 gtk_text_buffer_delete (GtkTextBuffer *buffer,
1618                         GtkTextIter   *start,
1619                         GtkTextIter   *end)
1620 {
1621   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1622   g_return_if_fail (start != NULL);
1623   g_return_if_fail (end != NULL);
1624   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
1625   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
1626   
1627   gtk_text_buffer_emit_delete (buffer, start, end);
1628 }
1629
1630 /**
1631  * gtk_text_buffer_delete_interactive:
1632  * @buffer: a #GtkTextBuffer
1633  * @start_iter: start of range to delete
1634  * @end_iter: end of range
1635  * @default_editable: whether the buffer is editable by default
1636  *
1637  * Deletes all <emphasis>editable</emphasis> text in the given range.
1638  * Calls gtk_text_buffer_delete () for each editable sub-range of
1639  * [@start,@end). @start and @end are revalidated to point to
1640  * the location of the last deleted range, or left untouched if
1641  * no text was deleted.
1642  *
1643  * Return value: whether some text was actually deleted
1644  **/
1645 gboolean
1646 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
1647                                     GtkTextIter   *start_iter,
1648                                     GtkTextIter   *end_iter,
1649                                     gboolean       default_editable)
1650 {
1651   GtkTextMark *end_mark;
1652   GtkTextMark *start_mark;
1653   GtkTextIter iter;
1654   gboolean current_state;
1655   gboolean deleted_stuff = FALSE;
1656
1657   /* Delete all editable text in the range start_iter, end_iter */
1658
1659   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1660   g_return_val_if_fail (start_iter != NULL, FALSE);
1661   g_return_val_if_fail (end_iter != NULL, FALSE);
1662   g_return_val_if_fail (gtk_text_iter_get_buffer (start_iter) == buffer, FALSE);
1663   g_return_val_if_fail (gtk_text_iter_get_buffer (end_iter) == buffer, FALSE);
1664
1665   
1666   gtk_text_buffer_begin_user_action (buffer);
1667   
1668   gtk_text_iter_order (start_iter, end_iter);
1669
1670   start_mark = gtk_text_buffer_create_mark (buffer, NULL,
1671                                             start_iter, TRUE);
1672   end_mark = gtk_text_buffer_create_mark (buffer, NULL,
1673                                           end_iter, FALSE);
1674
1675   gtk_text_buffer_get_iter_at_mark (buffer, &iter, start_mark);
1676
1677   current_state = gtk_text_iter_editable (&iter, default_editable);
1678
1679   while (TRUE)
1680     {
1681       gboolean new_state;
1682       gboolean done = FALSE;
1683       GtkTextIter end;
1684
1685       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
1686
1687       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
1688
1689       if (gtk_text_iter_compare (&iter, &end) >= 0)
1690         {
1691           done = TRUE;
1692           iter = end; /* clamp to the last boundary */
1693         }
1694
1695       new_state = gtk_text_iter_editable (&iter, default_editable);
1696
1697       if (current_state == new_state)
1698         {
1699           if (done)
1700             {
1701               if (current_state)
1702                 {
1703                   /* We're ending an editable region. Delete said region. */
1704                   GtkTextIter start;
1705
1706                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1707
1708                   gtk_text_buffer_emit_delete (buffer, &start, &iter);
1709
1710                   deleted_stuff = TRUE;
1711
1712                   /* revalidate user's iterators. */
1713                   *start_iter = start;
1714                   *end_iter = iter;
1715                 }
1716
1717               break;
1718             }
1719           else
1720             continue;
1721         }
1722
1723       if (current_state && !new_state)
1724         {
1725           /* End of an editable region. Delete it. */
1726           GtkTextIter start;
1727
1728           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1729
1730           gtk_text_buffer_emit_delete (buffer, &start, &iter);
1731
1732           current_state = FALSE;
1733           deleted_stuff = TRUE;
1734
1735           /* revalidate user's iterators. */
1736           *start_iter = start;
1737           *end_iter = iter;
1738         }
1739       else
1740         {
1741           /* We are at the start of an editable region. We won't be deleting
1742            * the previous region. Move start mark to start of this region.
1743            */
1744
1745           g_assert (!current_state && new_state);
1746
1747           gtk_text_buffer_move_mark (buffer, start_mark,
1748                                      &iter);
1749
1750
1751           current_state = TRUE;
1752         }
1753
1754       if (done)
1755         break;
1756     }
1757
1758
1759   gtk_text_buffer_delete_mark (buffer, start_mark);
1760   gtk_text_buffer_delete_mark (buffer, end_mark);
1761
1762   gtk_text_buffer_end_user_action (buffer);
1763   
1764   return deleted_stuff;
1765 }
1766
1767 /*
1768  * Extracting textual buffer contents
1769  */
1770
1771 /**
1772  * gtk_text_buffer_get_text:
1773  * @buffer: a #GtkTextBuffer
1774  * @start: start of a range
1775  * @end: end of a range
1776  * @include_hidden_chars: whether to include invisible text
1777  *
1778  * Returns the text in the range [@start,@end). Excludes undisplayed
1779  * text (text marked with tags that set the invisibility attribute) if
1780  * @include_hidden_chars is %FALSE. Does not include characters
1781  * representing embedded images, so byte and character indexes into
1782  * the returned string do <emphasis>not</emphasis> correspond to byte
1783  * and character indexes into the buffer. Contrast with
1784  * gtk_text_buffer_get_slice ().
1785  *
1786  * Return value: an allocated UTF-8 string
1787  **/
1788 gchar*
1789 gtk_text_buffer_get_text (GtkTextBuffer      *buffer,
1790                           const GtkTextIter *start,
1791                           const GtkTextIter *end,
1792                           gboolean             include_hidden_chars)
1793 {
1794   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1795   g_return_val_if_fail (start != NULL, NULL);
1796   g_return_val_if_fail (end != NULL, NULL);
1797   g_return_val_if_fail (gtk_text_iter_get_buffer (start) == buffer, NULL);
1798   g_return_val_if_fail (gtk_text_iter_get_buffer (end) == buffer, NULL);
1799   
1800   if (include_hidden_chars)
1801     return gtk_text_iter_get_text (start, end);
1802   else
1803     return gtk_text_iter_get_visible_text (start, end);
1804 }
1805
1806 /**
1807  * gtk_text_buffer_get_slice:
1808  * @buffer: a #GtkTextBuffer
1809  * @start: start of a range
1810  * @end: end of a range
1811  * @include_hidden_chars: whether to include invisible text
1812  *
1813  * Returns the text in the range [@start,@end). Excludes undisplayed
1814  * text (text marked with tags that set the invisibility attribute) if
1815  * @include_hidden_chars is %FALSE. The returned string includes a
1816  * 0xFFFC character whenever the buffer contains
1817  * embedded images, so byte and character indexes into
1818  * the returned string <emphasis>do</emphasis> correspond to byte
1819  * and character indexes into the buffer. Contrast with
1820  * gtk_text_buffer_get_text (). Note that 0xFFFC can occur in normal
1821  * text as well, so it is not a reliable indicator that a pixbuf or
1822  * widget is in the buffer.
1823  *
1824  * Return value: an allocated UTF-8 string
1825  **/
1826 gchar*
1827 gtk_text_buffer_get_slice (GtkTextBuffer      *buffer,
1828                            const GtkTextIter *start,
1829                            const GtkTextIter *end,
1830                            gboolean             include_hidden_chars)
1831 {
1832   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1833   g_return_val_if_fail (start != NULL, NULL);
1834   g_return_val_if_fail (end != NULL, NULL);
1835   g_return_val_if_fail (gtk_text_iter_get_buffer (start) == buffer, NULL);
1836   g_return_val_if_fail (gtk_text_iter_get_buffer (end) == buffer, NULL);
1837   
1838   if (include_hidden_chars)
1839     return gtk_text_iter_get_slice (start, end);
1840   else
1841     return gtk_text_iter_get_visible_slice (start, end);
1842 }
1843
1844 /*
1845  * Pixbufs
1846  */
1847
1848 static void
1849 gtk_text_buffer_real_insert_pixbuf (GtkTextBuffer     *buffer,
1850                                     GtkTextIter       *iter,
1851                                     GdkPixbuf         *pixbuf)
1852
1853   _gtk_text_btree_insert_pixbuf (iter, pixbuf);
1854
1855   g_signal_emit (buffer, signals[CHANGED], 0);
1856 }
1857
1858 /**
1859  * gtk_text_buffer_insert_pixbuf:
1860  * @buffer: a #GtkTextBuffer
1861  * @iter: location to insert the pixbuf
1862  * @pixbuf: a #GdkPixbuf
1863  *
1864  * Inserts an image into the text buffer at @iter. The image will be
1865  * counted as one character in character counts, and when obtaining
1866  * the buffer contents as a string, will be represented by the Unicode
1867  * "object replacement character" 0xFFFC. Note that the "slice"
1868  * variants for obtaining portions of the buffer as a string include
1869  * this character for pixbufs, but the "text" variants do
1870  * not. e.g. see gtk_text_buffer_get_slice() and
1871  * gtk_text_buffer_get_text().
1872  * 
1873  **/
1874 void
1875 gtk_text_buffer_insert_pixbuf         (GtkTextBuffer      *buffer,
1876                                        GtkTextIter        *iter,
1877                                        GdkPixbuf          *pixbuf)
1878 {
1879   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1880   g_return_if_fail (iter != NULL);
1881   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1882   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1883   
1884   g_signal_emit (buffer, signals[INSERT_PIXBUF], 0,
1885                  iter, pixbuf);
1886 }
1887
1888 /*
1889  * Child anchor
1890  */
1891
1892
1893 static void
1894 gtk_text_buffer_real_insert_anchor (GtkTextBuffer      *buffer,
1895                                     GtkTextIter        *iter,
1896                                     GtkTextChildAnchor *anchor)
1897 {
1898   _gtk_text_btree_insert_child_anchor (iter, anchor);
1899
1900   g_signal_emit (buffer, signals[CHANGED], 0);
1901 }
1902
1903 /**
1904  * gtk_text_buffer_insert_child_anchor:
1905  * @buffer: a #GtkTextBuffer
1906  * @iter: location to insert the anchor
1907  * @anchor: a #GtkTextChildAnchor
1908  *
1909  * Inserts a child widget anchor into the text buffer at @iter. The
1910  * anchor will be counted as one character in character counts, and
1911  * when obtaining the buffer contents as a string, will be represented
1912  * by the Unicode "object replacement character" 0xFFFC. Note that the
1913  * "slice" variants for obtaining portions of the buffer as a string
1914  * include this character for child anchors, but the "text" variants do
1915  * not. e.g. see gtk_text_buffer_get_slice() and
1916  * gtk_text_buffer_get_text(). Consider
1917  * gtk_text_buffer_create_child_anchor() as a more convenient
1918  * alternative to this function. The buffer will add a reference to
1919  * the anchor, so you can unref it after insertion.
1920  * 
1921  **/
1922 void
1923 gtk_text_buffer_insert_child_anchor (GtkTextBuffer      *buffer,
1924                                      GtkTextIter        *iter,
1925                                      GtkTextChildAnchor *anchor)
1926 {
1927   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1928   g_return_if_fail (iter != NULL);
1929   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
1930   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1931   
1932   g_signal_emit (buffer, signals[INSERT_CHILD_ANCHOR], 0,
1933                  iter, anchor);
1934 }
1935
1936
1937 /**
1938  * gtk_text_buffer_create_child_anchor:
1939  * @buffer: a #GtkTextBuffer
1940  * @iter: location in the buffer
1941  * 
1942  * This is a convenience function which simply creates a child anchor
1943  * with gtk_text_child_anchor_new() and inserts it into the buffer
1944  * with gtk_text_buffer_insert_child_anchor(). The new anchor is
1945  * owned by the buffer; no reference count is returned to
1946  * the caller of gtk_text_buffer_create_child_anchor().
1947  * 
1948  * Return value: the created child anchor
1949  **/
1950 GtkTextChildAnchor*
1951 gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
1952                                      GtkTextIter   *iter)
1953 {
1954   GtkTextChildAnchor *anchor;
1955   
1956   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1957   g_return_val_if_fail (iter != NULL, NULL);
1958   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, NULL);
1959   
1960   anchor = gtk_text_child_anchor_new ();
1961
1962   gtk_text_buffer_insert_child_anchor (buffer, iter, anchor);
1963
1964   g_object_unref (anchor);
1965
1966   return anchor;
1967 }
1968
1969 /*
1970  * Mark manipulation
1971  */
1972
1973 static void
1974 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
1975                           const GtkTextIter *location,
1976                           GtkTextMark       *mark)
1977 {
1978   /* IMO this should NOT work like insert_text and delete_range,
1979    * where the real action happens in the default handler.
1980    * 
1981    * The reason is that the default handler would be _required_,
1982    * i.e. the whole widget would start breaking and segfaulting if the
1983    * default handler didn't get run. So you can't really override the
1984    * default handler or stop the emission; that is, this signal is
1985    * purely for notification, and not to allow users to modify the
1986    * default behavior.
1987    */
1988
1989   g_object_ref (mark);
1990
1991   g_signal_emit (buffer,
1992                  signals[MARK_SET],
1993                  0,
1994                  location,
1995                  mark);
1996
1997   g_object_unref (mark);
1998 }
1999
2000 /**
2001  * gtk_text_buffer_set_mark:
2002  * @buffer:       a #GtkTextBuffer
2003  * @mark_name:    name of the mark
2004  * @iter:         location for the mark.
2005  * @left_gravity: if the mark is created by this function, gravity for the new
2006  *                mark.
2007  * @should_exist: if %TRUE, warn if the mark does not exist, and return
2008  *                immediately.
2009  *
2010  * Move the mark to the given position, if not @should_exist, create the mark.
2011  *
2012  * Return value: mark
2013  **/
2014 static GtkTextMark*
2015 gtk_text_buffer_set_mark (GtkTextBuffer *buffer,
2016                           GtkTextMark *existing_mark,
2017                           const gchar *mark_name,
2018                           const GtkTextIter *iter,
2019                           gboolean left_gravity,
2020                           gboolean should_exist)
2021 {
2022   GtkTextIter location;
2023   GtkTextMark *mark;
2024
2025   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, NULL);
2026   
2027   mark = _gtk_text_btree_set_mark (get_btree (buffer),
2028                                    existing_mark,
2029                                    mark_name,
2030                                    left_gravity,
2031                                    iter,
2032                                    should_exist);
2033   
2034   _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
2035                                    &location,
2036                                    mark);
2037
2038   gtk_text_buffer_mark_set (buffer, &location, mark);
2039
2040   return mark;
2041 }
2042
2043 /**
2044  * gtk_text_buffer_create_mark:
2045  * @buffer: a #GtkTextBuffer
2046  * @mark_name: name for mark, or %NULL
2047  * @where: location to place mark
2048  * @left_gravity: whether the mark has left gravity
2049  *
2050  * Creates a mark at position @where. If @mark_name is %NULL, the mark
2051  * is anonymous; otherwise, the mark can be retrieved by name using
2052  * gtk_text_buffer_get_mark (). If a mark has left gravity, and text is
2053  * inserted at the mark's current location, the mark will be moved to
2054  * the left of the newly-inserted text. If the mark has right gravity
2055  * (@left_gravity = %FALSE), the mark will end up on the right of
2056  * newly-inserted text. The standard left-to-right cursor is a mark
2057  * with right gravity (when you type, the cursor stays on the right
2058  * side of the text you're typing).
2059  *
2060  * The caller of this function does <emphasis>not</emphasis> own a reference
2061  * to the returned #GtkTextMark, so you can ignore the return value
2062  * if you like. Marks are owned by the buffer and go away when the
2063  * buffer does.
2064  *
2065  * Emits the "mark_set" signal as notification of the mark's initial
2066  * placement.
2067  *
2068  * Return value: the new #GtkTextMark object
2069  **/
2070 GtkTextMark*
2071 gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
2072                              const gchar *mark_name,
2073                              const GtkTextIter *where,
2074                              gboolean left_gravity)
2075 {
2076   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2077
2078   return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
2079                                    left_gravity, FALSE);
2080 }
2081
2082 /**
2083  * gtk_text_buffer_move_mark:
2084  * @buffer: a #GtkTextBuffer
2085  * @mark: a #GtkTextMark
2086  * @where: new location for @mark in @buffer
2087  *
2088  * Moves @mark to the new location @where. Emits the "mark_set" signal
2089  * as notification of the move.
2090  **/
2091 void
2092 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
2093                            GtkTextMark *mark,
2094                            const GtkTextIter *where)
2095 {
2096   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2097   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2098   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2099
2100   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
2101 }
2102
2103 /**
2104  * gtk_text_buffer_get_iter_at_mark:
2105  * @buffer: a #GtkTextBuffer
2106  * @iter: iterator to initialize
2107  * @mark: a #GtkTextMark in @buffer
2108  *
2109  * Initializes @iter with the current position of @mark.
2110  **/
2111 void
2112 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
2113                                   GtkTextIter *iter,
2114                                   GtkTextMark *mark)
2115 {
2116   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2117   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2118   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2119
2120   _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
2121                                     iter,
2122                                     mark);
2123 }
2124
2125 /**
2126  * gtk_text_buffer_delete_mark:
2127  * @buffer: a #GtkTextBuffer
2128  * @mark: a #GtkTextMark in @buffer
2129  *
2130  * Deletes @mark, so that it's no longer located anywhere in the
2131  * buffer. Removes the reference the buffer holds to the mark, so if
2132  * you haven't called g_object_ref () on the mark, it will be freed. Even
2133  * if the mark isn't freed, most operations on @mark become
2134  * invalid. There is no way to undelete a
2135  * mark. gtk_text_mark_get_deleted () will return TRUE after this
2136  * function has been called on a mark; gtk_text_mark_get_deleted ()
2137  * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
2138  * signal will be emitted as notification after the mark is deleted.
2139  **/
2140 void
2141 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
2142                              GtkTextMark   *mark)
2143 {
2144   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2145   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2146   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2147
2148   g_object_ref (mark);
2149
2150   _gtk_text_btree_remove_mark (get_btree (buffer), mark);
2151
2152   /* See rationale above for MARK_SET on why we emit this after
2153    * removing the mark, rather than removing the mark in a default
2154    * handler.
2155    */
2156   g_signal_emit (buffer, signals[MARK_DELETED],
2157                  0,
2158                  mark);
2159
2160   g_object_unref (mark);
2161 }
2162
2163 /**
2164  * gtk_text_buffer_get_mark:
2165  * @buffer: a #GtkTextBuffer
2166  * @name: a mark name
2167  *
2168  * Returns the mark named @name in buffer @buffer, or NULL if no such
2169  * mark exists in the buffer.
2170  *
2171  * Return value: a #GtkTextMark, or NULL
2172  **/
2173 GtkTextMark*
2174 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
2175                           const gchar         *name)
2176 {
2177   GtkTextMark *mark;
2178
2179   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2180   g_return_val_if_fail (name != NULL, NULL);
2181
2182   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2183
2184   return mark;
2185 }
2186
2187
2188 /**
2189  * gtk_text_buffer_move_mark_by_name:
2190  * @buffer: a #GtkTextBuffer
2191  * @name: name of a mark
2192  * @where: new location for mark
2193  *
2194  * Moves the mark named @name (which must exist) to location @where.
2195  * See gtk_text_buffer_move_mark () for details.
2196  **/
2197 void
2198 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
2199                                    const gchar       *name,
2200                                    const GtkTextIter *where)
2201 {
2202   GtkTextMark *mark;
2203
2204   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2205   g_return_if_fail (name != NULL);
2206
2207   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2208
2209   if (mark == NULL)
2210     {
2211       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2212       return;
2213     }
2214
2215   gtk_text_buffer_move_mark (buffer, mark, where);
2216 }
2217
2218 /**
2219  * gtk_text_buffer_delete_mark_by_name:
2220  * @buffer: a #GtkTextBuffer
2221  * @name: name of a mark in @buffer
2222  *
2223  * Deletes the mark named @name; the mark must exist. See
2224  * gtk_text_buffer_delete_mark () for details.
2225  **/
2226 void
2227 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer     *buffer,
2228                                      const gchar       *name)
2229 {
2230   GtkTextMark *mark;
2231
2232   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2233   g_return_if_fail (name != NULL);
2234
2235   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2236
2237   if (mark == NULL)
2238     {
2239       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2240       return;
2241     }
2242
2243   gtk_text_buffer_delete_mark (buffer, mark);
2244 }
2245
2246 /**
2247  * gtk_text_buffer_get_insert:
2248  * @buffer: a #GtkTextBuffer
2249  *
2250  * Returns the mark that represents the cursor (insertion point).
2251  * Equivalent to calling gtk_text_buffer_get_mark () to get the mark
2252  * named "insert", but very slightly more efficient, and involves less
2253  * typing.
2254  *
2255  * Return value: insertion point mark
2256  **/
2257 GtkTextMark*
2258 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
2259 {
2260   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2261
2262   /* FIXME use struct member in btree */
2263   return gtk_text_buffer_get_mark (buffer, "insert");
2264 }
2265
2266 /**
2267  * gtk_text_buffer_get_selection_bound:
2268  * @buffer: a #GtkTextBuffer
2269  *
2270  * Returns the mark that represents the selection bound.  Equivalent
2271  * to calling gtk_text_buffer_get_mark () to get the mark named
2272  * "selection_bound", but very slightly more efficient, and involves
2273  * less typing.
2274  *
2275  * The currently-selected text in @buffer is the region between the
2276  * "selection_bound" and "insert" marks. If "selection_bound" and
2277  * "insert" are in the same place, then there is no current selection.
2278  * gtk_text_buffer_get_selection_bounds() is another convenient function
2279  * for handling the selection, if you just want to know whether there's a
2280  * selection and what its bounds are.
2281  *
2282  * Return value: selection bound mark
2283  **/
2284 GtkTextMark*
2285 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
2286 {
2287   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2288
2289   /* FIXME use struct member in btree */
2290   return gtk_text_buffer_get_mark (buffer, "selection_bound");
2291 }
2292
2293 /**
2294  * gtk_text_buffer_get_iter_at_child_anchor:
2295  * @buffer: a #GtkTextBuffer
2296  * @iter: an iterator to be initialized
2297  * @anchor: a child anchor that appears in @buffer
2298  *
2299  * Obtains the location of @anchor within @buffer.
2300  * 
2301  **/
2302 void
2303 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
2304                                           GtkTextIter        *iter,
2305                                           GtkTextChildAnchor *anchor)
2306 {
2307   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2308   g_return_if_fail (iter != NULL);
2309   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
2310   g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
2311   
2312   _gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
2313                                            iter,
2314                                            anchor);
2315 }
2316
2317 /**
2318  * gtk_text_buffer_place_cursor:
2319  * @buffer: a #GtkTextBuffer
2320  * @where: where to put the cursor
2321  *
2322  * This function moves the "insert" and "selection_bound" marks
2323  * simultaneously.  If you move them to the same place in two steps
2324  * with gtk_text_buffer_move_mark(), you will temporarily select a
2325  * region in between their old and new locations, which can be pretty
2326  * inefficient since the temporarily-selected region will force stuff
2327  * to be recalculated. This function moves them as a unit, which can
2328  * be optimized.
2329  **/
2330 void
2331 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
2332                               const GtkTextIter *where)
2333 {
2334   gtk_text_buffer_select_range (buffer, where, where);
2335 }
2336
2337
2338 /**
2339  * gtk_text_buffer_select_range:
2340  * @buffer: a #GtkTextBuffer
2341  * @ins: where to put the "insert" mark
2342  * @bound: where to put the "selection_bound" mark
2343  *
2344  * This function moves the "insert" and "selection_bound" marks
2345  * simultaneously.  If you move them in two steps
2346  * with gtk_text_buffer_move_mark(), you will temporarily select a
2347  * region in between their old and new locations, which can be pretty
2348  * inefficient since the temporarily-selected region will force stuff
2349  * to be recalculated. This function moves them as a unit, which can
2350  * be optimized.
2351  *
2352  * Since: 2.4
2353  **/
2354 void
2355 gtk_text_buffer_select_range (GtkTextBuffer     *buffer,
2356                               const GtkTextIter *ins,
2357                               const GtkTextIter *bound)
2358 {
2359   GtkTextIter real_ins;
2360   GtkTextIter real_bound;
2361
2362   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2363
2364   real_ins = *ins;
2365   real_bound = *bound;
2366
2367   _gtk_text_btree_select_range (get_btree (buffer), &real_ins, &real_bound);
2368   gtk_text_buffer_mark_set (buffer, &real_ins,
2369                             gtk_text_buffer_get_mark (buffer,
2370                                                       "insert"));
2371   gtk_text_buffer_mark_set (buffer, &real_bound,
2372                             gtk_text_buffer_get_mark (buffer,
2373                                                       "selection_bound"));
2374 }
2375
2376 /*
2377  * Tags
2378  */
2379
2380 /**
2381  * gtk_text_buffer_create_tag:
2382  * @buffer: a #GtkTextBuffer
2383  * @tag_name: name of the new tag, or %NULL
2384  * @first_property_name: name of first property to set, or %NULL
2385  * @Varargs: %NULL-terminated list of property names and values
2386  *
2387  *
2388  * Creates a tag and adds it to the tag table for @buffer.
2389  * Equivalent to calling gtk_text_tag_new () and then adding the
2390  * tag to the buffer's tag table. The returned tag is owned by
2391  * the buffer's tag table, so the ref count will be equal to one.
2392  *
2393  * If @tag_name is %NULL, the tag is anonymous.
2394  *
2395  * If @tag_name is non-%NULL, a tag called @tag_name must not already
2396  * exist in the tag table for this buffer.
2397  *
2398  * The @first_property_name argument and subsequent arguments are a list
2399  * of properties to set on the tag, as with g_object_set().
2400  *
2401  * Return value: a new tag
2402  **/
2403 GtkTextTag*
2404 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
2405                             const gchar   *tag_name,
2406                             const gchar   *first_property_name,
2407                             ...)
2408 {
2409   GtkTextTag *tag;
2410   va_list list;
2411   
2412   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2413
2414   tag = gtk_text_tag_new (tag_name);
2415
2416   gtk_text_tag_table_add (get_table (buffer), tag);
2417
2418   if (first_property_name)
2419     {
2420       va_start (list, first_property_name);
2421       g_object_set_valist (G_OBJECT (tag), first_property_name, list);
2422       va_end (list);
2423     }
2424   
2425   g_object_unref (tag);
2426
2427   return tag;
2428 }
2429
2430 static void
2431 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
2432                                 GtkTextTag *tag,
2433                                 const GtkTextIter *start,
2434                                 const GtkTextIter *end)
2435 {
2436   if (tag->table != buffer->tag_table)
2437     {
2438       g_warning ("Can only apply tags that are in the tag table for the buffer");
2439       return;
2440     }
2441   
2442   _gtk_text_btree_tag (start, end, tag, TRUE);
2443 }
2444
2445 static void
2446 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
2447                                  GtkTextTag *tag,
2448                                  const GtkTextIter *start,
2449                                  const GtkTextIter *end)
2450 {
2451   if (tag->table != buffer->tag_table)
2452     {
2453       g_warning ("Can only remove tags that are in the tag table for the buffer");
2454       return;
2455     }
2456   
2457   _gtk_text_btree_tag (start, end, tag, FALSE);
2458 }
2459
2460 static void
2461 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
2462 {
2463   gtk_text_buffer_set_modified (buffer, TRUE);
2464 }
2465
2466 static void
2467 gtk_text_buffer_real_mark_set (GtkTextBuffer *buffer,
2468                                const GtkTextIter *iter,
2469                                GtkTextMark *mark)
2470 {
2471   GtkTextMark *insert;
2472   
2473   insert = gtk_text_buffer_get_insert (buffer);
2474
2475   if (mark == insert || mark == gtk_text_buffer_get_selection_bound (buffer))
2476     {
2477       gboolean has_selection;
2478
2479       update_selection_clipboards (buffer);
2480     
2481       has_selection = gtk_text_buffer_get_selection_bounds (buffer,
2482                                                             NULL,
2483                                                             NULL);
2484
2485       if (has_selection != buffer->has_selection)
2486         {
2487           buffer->has_selection = has_selection;
2488           g_object_notify (G_OBJECT (buffer), "has-selection");
2489         }
2490     }
2491     
2492     if (mark == insert)
2493       g_object_notify (G_OBJECT (buffer), "cursor-position");
2494 }
2495
2496 static void
2497 gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,
2498                           GtkTextTag *tag,
2499                           gboolean apply,
2500                           const GtkTextIter *start,
2501                           const GtkTextIter *end)
2502 {
2503   GtkTextIter start_tmp = *start;
2504   GtkTextIter end_tmp = *end;
2505
2506   g_return_if_fail (tag != NULL);
2507
2508   gtk_text_iter_order (&start_tmp, &end_tmp);
2509
2510   if (apply)
2511     g_signal_emit (buffer, signals[APPLY_TAG],
2512                    0,
2513                    tag, &start_tmp, &end_tmp);
2514   else
2515     g_signal_emit (buffer, signals[REMOVE_TAG],
2516                    0,
2517                    tag, &start_tmp, &end_tmp);
2518 }
2519
2520
2521 /**
2522  * gtk_text_buffer_apply_tag:
2523  * @buffer: a #GtkTextBuffer
2524  * @tag: a #GtkTextTag
2525  * @start: one bound of range to be tagged
2526  * @end: other bound of range to be tagged
2527  *
2528  * Emits the "apply_tag" signal on @buffer. The default
2529  * handler for the signal applies @tag to the given range.
2530  * @start and @end do not have to be in order.
2531  * 
2532  **/
2533 void
2534 gtk_text_buffer_apply_tag (GtkTextBuffer *buffer,
2535                            GtkTextTag    *tag,
2536                            const GtkTextIter *start,
2537                            const GtkTextIter *end)
2538 {
2539   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2540   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2541   g_return_if_fail (start != NULL);
2542   g_return_if_fail (end != NULL);
2543   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2544   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2545   g_return_if_fail (tag->table == buffer->tag_table);
2546   
2547   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2548 }
2549
2550 /**
2551  * gtk_text_buffer_remove_tag:
2552  * @buffer: a #GtkTextBuffer
2553  * @tag: a #GtkTextTag
2554  * @start: one bound of range to be untagged
2555  * @end: other bound of range to be untagged
2556  *
2557  * Emits the "remove_tag" signal. The default handler for the signal
2558  * removes all occurrences of @tag from the given range. @start and
2559  * @end don't have to be in order.
2560  * 
2561  **/
2562 void
2563 gtk_text_buffer_remove_tag (GtkTextBuffer *buffer,
2564                             GtkTextTag    *tag,
2565                             const GtkTextIter *start,
2566                             const GtkTextIter *end)
2567
2568 {
2569   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2570   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2571   g_return_if_fail (start != NULL);
2572   g_return_if_fail (end != NULL);
2573   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2574   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2575   g_return_if_fail (tag->table == buffer->tag_table);
2576   
2577   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2578 }
2579
2580
2581 /**
2582  * gtk_text_buffer_apply_tag_by_name:
2583  * @buffer: a #GtkTextBuffer
2584  * @name: name of a named #GtkTextTag
2585  * @start: one bound of range to be tagged
2586  * @end: other bound of range to be tagged
2587  *
2588  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2589  * get a #GtkTextTag, then calls gtk_text_buffer_apply_tag().
2590  * 
2591  **/
2592 void
2593 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
2594                                    const gchar   *name,
2595                                    const GtkTextIter *start,
2596                                    const GtkTextIter *end)
2597 {
2598   GtkTextTag *tag;
2599
2600   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2601   g_return_if_fail (name != NULL);
2602   g_return_if_fail (start != NULL);
2603   g_return_if_fail (end != NULL);
2604   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2605   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2606
2607   tag = gtk_text_tag_table_lookup (get_table (buffer),
2608                                    name);
2609
2610   if (tag == NULL)
2611     {
2612       g_warning ("Unknown tag `%s'", name);
2613       return;
2614     }
2615
2616   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2617 }
2618
2619 /**
2620  * gtk_text_buffer_remove_tag_by_name:
2621  * @buffer: a #GtkTextBuffer
2622  * @name: name of a #GtkTextTag
2623  * @start: one bound of range to be untagged
2624  * @end: other bound of range to be untagged
2625  *
2626  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2627  * get a #GtkTextTag, then calls gtk_text_buffer_remove_tag().
2628  * 
2629  * 
2630  **/
2631 void
2632 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
2633                                     const gchar *name,
2634                                     const GtkTextIter *start,
2635                                     const GtkTextIter *end)
2636 {
2637   GtkTextTag *tag;
2638
2639   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2640   g_return_if_fail (name != NULL);
2641   g_return_if_fail (start != NULL);
2642   g_return_if_fail (end != NULL);
2643   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2644   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2645   
2646   tag = gtk_text_tag_table_lookup (get_table (buffer),
2647                                    name);
2648
2649   if (tag == NULL)
2650     {
2651       g_warning ("Unknown tag `%s'", name);
2652       return;
2653     }
2654
2655   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2656 }
2657
2658 static gint
2659 pointer_cmp (gconstpointer a,
2660              gconstpointer b)
2661 {
2662   if (a < b)
2663     return -1;
2664   else if (a > b)
2665     return 1;
2666   else
2667     return 0;
2668 }
2669
2670 /**
2671  * gtk_text_buffer_remove_all_tags:
2672  * @buffer: a #GtkTextBuffer
2673  * @start: one bound of range to be untagged
2674  * @end: other bound of range to be untagged
2675  * 
2676  * Removes all tags in the range between @start and @end.  Be careful
2677  * with this function; it could remove tags added in code unrelated to
2678  * the code you're currently writing. That is, using this function is
2679  * probably a bad idea if you have two or more unrelated code sections
2680  * that add tags.
2681  **/
2682 void
2683 gtk_text_buffer_remove_all_tags (GtkTextBuffer     *buffer,
2684                                  const GtkTextIter *start,
2685                                  const GtkTextIter *end)
2686 {
2687   GtkTextIter first, second, tmp;
2688   GSList *tags;
2689   GSList *tmp_list;
2690   GSList *prev, *next;
2691   GtkTextTag *tag;
2692   
2693   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2694   g_return_if_fail (start != NULL);
2695   g_return_if_fail (end != NULL);
2696   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2697   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2698   
2699   first = *start;
2700   second = *end;
2701
2702   gtk_text_iter_order (&first, &second);
2703
2704   /* Get all tags turned on at the start */
2705   tags = gtk_text_iter_get_tags (&first);
2706   
2707   /* Find any that are toggled on within the range */
2708   tmp = first;
2709   while (gtk_text_iter_forward_to_tag_toggle (&tmp, NULL))
2710     {
2711       GSList *toggled;
2712       GSList *tmp_list2;
2713
2714       if (gtk_text_iter_compare (&tmp, &second) >= 0)
2715         break; /* past the end of the range */
2716       
2717       toggled = gtk_text_iter_get_toggled_tags (&tmp, TRUE);
2718
2719       /* We could end up with a really big-ass list here.
2720        * Fix it someday.
2721        */
2722       tmp_list2 = toggled;
2723       while (tmp_list2 != NULL)
2724         {
2725           tags = g_slist_prepend (tags, tmp_list2->data);
2726
2727           tmp_list2 = g_slist_next (tmp_list2);
2728         }
2729
2730       g_slist_free (toggled);
2731     }
2732   
2733   /* Sort the list */
2734   tags = g_slist_sort (tags, pointer_cmp);
2735
2736   /* Strip duplicates */
2737   tag = NULL;
2738   prev = NULL;
2739   tmp_list = tags;
2740   while (tmp_list != NULL)
2741     {
2742       if (tag == tmp_list->data)
2743         {
2744           /* duplicate */
2745           next = tmp_list->next;
2746           if (prev)
2747             prev->next = next;
2748
2749           tmp_list->next = NULL;
2750
2751           g_slist_free (tmp_list);
2752
2753           tmp_list = next;
2754           /* prev is unchanged */
2755         }
2756       else
2757         {
2758           /* not a duplicate */
2759           tag = GTK_TEXT_TAG (tmp_list->data);
2760           prev = tmp_list;
2761           tmp_list = tmp_list->next;
2762         }
2763     }
2764
2765   g_slist_foreach (tags, (GFunc) g_object_ref, NULL);
2766   
2767   tmp_list = tags;
2768   while (tmp_list != NULL)
2769     {
2770       tag = GTK_TEXT_TAG (tmp_list->data);
2771
2772       gtk_text_buffer_remove_tag (buffer, tag, &first, &second);
2773       
2774       tmp_list = tmp_list->next;
2775     }
2776
2777   g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
2778   
2779   g_slist_free (tags);
2780 }
2781
2782
2783 /*
2784  * Obtain various iterators
2785  */
2786
2787 /**
2788  * gtk_text_buffer_get_iter_at_line_offset:
2789  * @buffer: a #GtkTextBuffer
2790  * @iter: iterator to initialize
2791  * @line_number: line number counting from 0
2792  * @char_offset: char offset from start of line
2793  *
2794  * Obtains an iterator pointing to @char_offset within the given
2795  * line. The @char_offset must exist, offsets off the end of the line
2796  * are not allowed. Note <emphasis>characters</emphasis>, not bytes;
2797  * UTF-8 may encode one character as multiple bytes.
2798  * 
2799  **/
2800 void
2801 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
2802                                          GtkTextIter        *iter,
2803                                          gint                line_number,
2804                                          gint                char_offset)
2805 {
2806   g_return_if_fail (iter != NULL);
2807   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2808
2809   _gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
2810                                          iter, line_number, char_offset);
2811 }
2812
2813 /**
2814  * gtk_text_buffer_get_iter_at_line_index:
2815  * @buffer: a #GtkTextBuffer 
2816  * @iter: iterator to initialize 
2817  * @line_number: line number counting from 0
2818  * @byte_index: byte index from start of line
2819  *
2820  * Obtains an iterator pointing to @byte_index within the given line.
2821  * @byte_index must be the start of a UTF-8 character, and must not be
2822  * beyond the end of the line.  Note <emphasis>bytes</emphasis>, not
2823  * characters; UTF-8 may encode one character as multiple bytes.
2824  * 
2825  **/
2826 void
2827 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
2828                                          GtkTextIter   *iter,
2829                                          gint           line_number,
2830                                          gint           byte_index)
2831 {
2832   g_return_if_fail (iter != NULL);
2833   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2834
2835   _gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
2836                                          iter, line_number, byte_index);
2837 }
2838
2839 /**
2840  * gtk_text_buffer_get_iter_at_line:
2841  * @buffer: a #GtkTextBuffer 
2842  * @iter: iterator to initialize
2843  * @line_number: line number counting from 0
2844  * 
2845  * Initializes @iter to the start of the given line.
2846  **/
2847 void
2848 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
2849                                      GtkTextIter        *iter,
2850                                      gint                line_number)
2851 {
2852   g_return_if_fail (iter != NULL);
2853   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2854
2855   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
2856 }
2857
2858 /**
2859  * gtk_text_buffer_get_iter_at_offset:
2860  * @buffer: a #GtkTextBuffer 
2861  * @iter: iterator to initialize
2862  * @char_offset: char offset from start of buffer, counting from 0, or -1
2863  *
2864  * Initializes @iter to a position @char_offset chars from the start
2865  * of the entire buffer. If @char_offset is -1 or greater than the number
2866  * of characters in the buffer, @iter is initialized to the end iterator,
2867  * the iterator one past the last valid character in the buffer.
2868  **/
2869 void
2870 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
2871                                             GtkTextIter        *iter,
2872                                             gint                char_offset)
2873 {
2874   g_return_if_fail (iter != NULL);
2875   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2876
2877   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
2878 }
2879
2880 /**
2881  * gtk_text_buffer_get_start_iter:
2882  * @buffer: a #GtkTextBuffer
2883  * @iter: iterator to initialize
2884  *
2885  * Initialized @iter with the first position in the text buffer. This
2886  * is the same as using gtk_text_buffer_get_iter_at_offset() to get
2887  * the iter at character offset 0.
2888  **/
2889 void
2890 gtk_text_buffer_get_start_iter (GtkTextBuffer *buffer,
2891                                 GtkTextIter   *iter)
2892 {
2893   g_return_if_fail (iter != NULL);
2894   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2895
2896   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, 0);
2897 }
2898
2899 /**
2900  * gtk_text_buffer_get_end_iter:
2901  * @buffer: a #GtkTextBuffer 
2902  * @iter: iterator to initialize
2903  *
2904  * Initializes @iter with the "end iterator," one past the last valid
2905  * character in the text buffer. If dereferenced with
2906  * gtk_text_iter_get_char(), the end iterator has a character value of
2907  * 0. The entire buffer lies in the range from the first position in
2908  * the buffer (call gtk_text_buffer_get_start_iter() to get
2909  * character position 0) to the end iterator.
2910  * 
2911  **/
2912 void
2913 gtk_text_buffer_get_end_iter         (GtkTextBuffer      *buffer,
2914                                        GtkTextIter        *iter)
2915 {
2916   g_return_if_fail (iter != NULL);
2917   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2918
2919   _gtk_text_btree_get_end_iter (get_btree (buffer), iter);
2920 }
2921
2922 /**
2923  * gtk_text_buffer_get_bounds:
2924  * @buffer: a #GtkTextBuffer 
2925  * @start: iterator to initialize with first position in the buffer
2926  * @end: iterator to initialize with the end iterator
2927  *
2928  * Retrieves the first and last iterators in the buffer, i.e. the
2929  * entire buffer lies within the range [@start,@end).
2930  * 
2931  **/
2932 void
2933 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
2934                             GtkTextIter   *start,
2935                             GtkTextIter   *end)
2936 {
2937   g_return_if_fail (start != NULL);
2938   g_return_if_fail (end != NULL);
2939   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2940
2941   _gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
2942   _gtk_text_btree_get_end_iter (get_btree (buffer), end);
2943 }
2944
2945 /*
2946  * Modified flag
2947  */
2948
2949 /**
2950  * gtk_text_buffer_get_modified:
2951  * @buffer: a #GtkTextBuffer 
2952  * 
2953  * Indicates whether the buffer has been modified since the last call
2954  * to gtk_text_buffer_set_modified() set the modification flag to
2955  * %FALSE. Used for example to enable a "save" function in a text
2956  * editor.
2957  * 
2958  * Return value: %TRUE if the buffer has been modified
2959  **/
2960 gboolean
2961 gtk_text_buffer_get_modified (GtkTextBuffer *buffer)
2962 {
2963   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2964
2965   return buffer->modified;
2966 }
2967
2968 /**
2969  * gtk_text_buffer_set_modified:
2970  * @buffer: a #GtkTextBuffer 
2971  * @setting: modification flag setting
2972  *
2973  * Used to keep track of whether the buffer has been modified since the
2974  * last time it was saved. Whenever the buffer is saved to disk, call
2975  * gtk_text_buffer_set_modified (@buffer, FALSE). When the buffer is modified,
2976  * it will automatically toggled on the modified bit again. When the modified
2977  * bit flips, the buffer emits a "modified_changed" signal.
2978  * 
2979  **/
2980 void
2981 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
2982                               gboolean             setting)
2983 {
2984   gboolean fixed_setting;
2985
2986   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2987
2988   fixed_setting = setting != FALSE;
2989
2990   if (buffer->modified == fixed_setting)
2991     return;
2992   else
2993     {
2994       buffer->modified = fixed_setting;
2995       g_signal_emit (buffer, signals[MODIFIED_CHANGED], 0);
2996     }
2997 }
2998
2999 /**
3000  * gtk_text_buffer_get_has_selection:
3001  * @buffer: a #GtkTextBuffer 
3002  * 
3003  * Indicates whether the buffer has some text currently selected.
3004  * 
3005  * Return value: %TRUE if the there is text selected
3006  *
3007  * Since: 2.10
3008  **/
3009 gboolean
3010 gtk_text_buffer_get_has_selection (GtkTextBuffer *buffer)
3011 {
3012   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3013
3014   return buffer->has_selection;
3015 }
3016
3017
3018 /*
3019  * Assorted other stuff
3020  */
3021
3022 /**
3023  * gtk_text_buffer_get_line_count:
3024  * @buffer: a #GtkTextBuffer 
3025  * 
3026  * Obtains the number of lines in the buffer. This value is cached, so
3027  * the function is very fast.
3028  * 
3029  * Return value: number of lines in the buffer
3030  **/
3031 gint
3032 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
3033 {
3034   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3035
3036   return _gtk_text_btree_line_count (get_btree (buffer));
3037 }
3038
3039 /**
3040  * gtk_text_buffer_get_char_count:
3041  * @buffer: a #GtkTextBuffer 
3042  * 
3043  * Gets the number of characters in the buffer; note that characters
3044  * and bytes are not the same, you can't e.g. expect the contents of
3045  * the buffer in string form to be this many bytes long. The character
3046  * count is cached, so this function is very fast.
3047  * 
3048  * Return value: number of characters in the buffer
3049  **/
3050 gint
3051 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
3052 {
3053   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3054
3055   return _gtk_text_btree_char_count (get_btree (buffer));
3056 }
3057
3058 /* Called when we lose the primary selection.
3059  */
3060 static void
3061 clipboard_clear_selection_cb (GtkClipboard *clipboard,
3062                               gpointer      data)
3063 {
3064   /* Move selection_bound to the insertion point */
3065   GtkTextIter insert;
3066   GtkTextIter selection_bound;
3067   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3068
3069   gtk_text_buffer_get_iter_at_mark (buffer, &insert,
3070                                     gtk_text_buffer_get_mark (buffer, "insert"));
3071   gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
3072                                     gtk_text_buffer_get_mark (buffer, "selection_bound"));
3073
3074   if (!gtk_text_iter_equal (&insert, &selection_bound))
3075     gtk_text_buffer_move_mark (buffer,
3076                                gtk_text_buffer_get_mark (buffer, "selection_bound"),
3077                                &insert);
3078 }
3079
3080 /* Called when we have the primary selection and someone else wants our
3081  * data in order to paste it.
3082  */
3083 static void
3084 clipboard_get_selection_cb (GtkClipboard     *clipboard,
3085                             GtkSelectionData *selection_data,
3086                             guint             info,
3087                             gpointer          data)
3088 {
3089   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3090   GtkTextIter start, end;
3091
3092   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3093     {
3094       if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3095         {
3096           /* Provide the address of the buffer; this will only be
3097            * used within-process
3098            */
3099           gtk_selection_data_set (selection_data,
3100                                   selection_data->target,
3101                                   8, /* bytes */
3102                                   (void*)&buffer,
3103                                   sizeof (buffer));
3104         }
3105       else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3106         {
3107           guint8 *str;
3108           gsize   len;
3109
3110           str = gtk_text_buffer_serialize (buffer, buffer,
3111                                            selection_data->target,
3112                                            &start, &end, &len);
3113
3114           gtk_selection_data_set (selection_data,
3115                                   selection_data->target,
3116                                   8, /* bytes */
3117                                   str, len);
3118           g_free (str);
3119         }
3120       else
3121         {
3122           gchar *str;
3123
3124           str = gtk_text_iter_get_visible_text (&start, &end);
3125           gtk_selection_data_set_text (selection_data, str, -1);
3126           g_free (str);
3127         }
3128     }
3129 }
3130
3131 static GtkTextBuffer *
3132 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
3133 {
3134   GtkTextBuffer *contents;
3135
3136   contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
3137
3138   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard-source"),
3139                      buffer);
3140   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
3141                      GINT_TO_POINTER (1));
3142
3143   /*  Ref the source buffer as long as the clipboard contents buffer
3144    *  exists, because it's needed for serializing the contents buffer.
3145    *  See http://bugzilla.gnome.org/show_bug.cgi?id=339195
3146    */
3147   g_object_ref (buffer);
3148   g_object_weak_ref (G_OBJECT (contents), (GWeakNotify) g_object_unref, buffer);
3149
3150   return contents;
3151 }
3152
3153 /* Provide cut/copied data */
3154 static void
3155 clipboard_get_contents_cb (GtkClipboard     *clipboard,
3156                            GtkSelectionData *selection_data,
3157                            guint             info,
3158                            gpointer          data)
3159 {
3160   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3161
3162   g_assert (contents); /* This should never be called unless we own the clipboard */
3163
3164   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3165     {
3166       /* Provide the address of the clipboard buffer; this will only
3167        * be used within-process. OK to supply a NULL value for contents.
3168        */
3169       gtk_selection_data_set (selection_data,
3170                               selection_data->target,
3171                               8, /* bytes */
3172                               (void*)&contents,
3173                               sizeof (contents));
3174     }
3175   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3176     {
3177       GtkTextBuffer *clipboard_source_buffer;
3178       GtkTextIter start, end;
3179       guint8 *str;
3180       gsize   len;
3181
3182       clipboard_source_buffer = g_object_get_data (G_OBJECT (contents),
3183                                                    "gtk-text-buffer-clipboard-source");
3184
3185       gtk_text_buffer_get_bounds (contents, &start, &end);
3186
3187       str = gtk_text_buffer_serialize (clipboard_source_buffer, contents,
3188                                        selection_data->target,
3189                                        &start, &end, &len);
3190
3191       gtk_selection_data_set (selection_data,
3192                               selection_data->target,
3193                               8, /* bytes */
3194                               str, len);
3195       g_free (str);
3196     }
3197   else
3198     {
3199       gchar *str;
3200       GtkTextIter start, end;
3201
3202       gtk_text_buffer_get_bounds (contents, &start, &end);
3203
3204       str = gtk_text_iter_get_visible_text (&start, &end);
3205       gtk_selection_data_set_text (selection_data, str, -1);
3206       g_free (str);
3207     }
3208 }
3209
3210 static void
3211 clipboard_clear_contents_cb (GtkClipboard *clipboard,
3212                              gpointer      data)
3213 {
3214   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3215
3216   g_object_unref (contents);
3217 }
3218
3219 static void
3220 get_paste_point (GtkTextBuffer *buffer,
3221                  GtkTextIter   *iter,
3222                  gboolean       clear_afterward)
3223 {
3224   GtkTextIter insert_point;
3225   GtkTextMark *paste_point_override;
3226
3227   paste_point_override = gtk_text_buffer_get_mark (buffer,
3228                                                    "gtk_paste_point_override");
3229
3230   if (paste_point_override != NULL)
3231     {
3232       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3233                                         paste_point_override);
3234       if (clear_afterward)
3235         gtk_text_buffer_delete_mark (buffer,
3236                                      gtk_text_buffer_get_mark (buffer,
3237                                                                "gtk_paste_point_override"));
3238     }
3239   else
3240     {
3241       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3242                                         gtk_text_buffer_get_mark (buffer,
3243                                                                   "insert"));
3244     }
3245
3246   *iter = insert_point;
3247 }
3248
3249 static void
3250 pre_paste_prep (ClipboardRequest *request_data,
3251                 GtkTextIter      *insert_point)
3252 {
3253   GtkTextBuffer *buffer = request_data->buffer;
3254   
3255   get_paste_point (buffer, insert_point, TRUE);
3256
3257   /* If we're going to replace the selection, we insert before it to
3258    * avoid messing it up, then we delete the selection after inserting.
3259    */
3260   if (request_data->replace_selection)
3261     {
3262       GtkTextIter start, end;
3263       
3264       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3265         *insert_point = start;
3266     }
3267 }
3268
3269 static void
3270 post_paste_cleanup (ClipboardRequest *request_data)
3271 {
3272   if (request_data->replace_selection)
3273     {
3274       GtkTextIter start, end;
3275       
3276       if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
3277                                                 &start, &end))
3278         {
3279           if (request_data->interactive)
3280             gtk_text_buffer_delete_interactive (request_data->buffer,
3281                                                 &start,
3282                                                 &end,
3283                                                 request_data->default_editable);
3284           else
3285             gtk_text_buffer_delete (request_data->buffer, &start, &end);
3286         }
3287     }
3288 }
3289
3290 static void
3291 free_clipboard_request (ClipboardRequest *request_data)
3292 {
3293   g_object_unref (request_data->buffer);
3294   g_free (request_data);
3295 }
3296
3297 /* Called when we request a paste and receive the text data
3298  */
3299 static void
3300 clipboard_text_received (GtkClipboard *clipboard,
3301                          const gchar  *str,
3302                          gpointer      data)
3303 {
3304   ClipboardRequest *request_data = data;
3305   GtkTextBuffer *buffer = request_data->buffer;
3306
3307   if (str)
3308     {
3309       GtkTextIter insert_point;
3310       
3311       if (request_data->interactive) 
3312         gtk_text_buffer_begin_user_action (buffer);
3313
3314       pre_paste_prep (request_data, &insert_point);
3315       
3316       if (request_data->interactive) 
3317         gtk_text_buffer_insert_interactive (buffer, &insert_point,
3318                                             str, -1, request_data->default_editable);
3319       else
3320         gtk_text_buffer_insert (buffer, &insert_point,
3321                                 str, -1);
3322
3323       post_paste_cleanup (request_data);
3324       
3325       if (request_data->interactive) 
3326         gtk_text_buffer_end_user_action (buffer);
3327     }
3328
3329   free_clipboard_request (request_data);
3330 }
3331
3332 static GtkTextBuffer*
3333 selection_data_get_buffer (GtkSelectionData *selection_data,
3334                            ClipboardRequest *request_data)
3335 {
3336   GdkWindow *owner;
3337   GtkTextBuffer *src_buffer = NULL;
3338
3339   /* If we can get the owner, the selection is in-process */
3340   owner = gdk_selection_owner_get_for_display (selection_data->display,
3341                                                selection_data->selection);
3342
3343   if (owner == NULL)
3344     return NULL;
3345   
3346   if (gdk_window_get_window_type (owner) == GDK_WINDOW_FOREIGN)
3347     return NULL;
3348  
3349   if (selection_data->type !=
3350       gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
3351     return NULL;
3352
3353   if (selection_data->length != sizeof (src_buffer))
3354     return NULL;
3355           
3356   memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
3357
3358   if (src_buffer == NULL)
3359     return NULL;
3360   
3361   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
3362
3363   if (gtk_text_buffer_get_tag_table (src_buffer) !=
3364       gtk_text_buffer_get_tag_table (request_data->buffer))
3365     return NULL;
3366   
3367   return src_buffer;
3368 }
3369
3370 #if 0
3371 /* These are pretty handy functions; maybe something like them
3372  * should be in the public API. Also, there are other places in this
3373  * file where they could be used.
3374  */
3375 static gpointer
3376 save_iter (const GtkTextIter *iter,
3377            gboolean           left_gravity)
3378 {
3379   return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
3380                                       NULL,
3381                                       iter,
3382                                       TRUE);
3383 }
3384
3385 static void
3386 restore_iter (const GtkTextIter *iter,
3387               gpointer           save_id)
3388 {
3389   gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
3390                                     (GtkTextIter*) iter,
3391                                     save_id);
3392   gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
3393                                save_id);
3394 }
3395 #endif
3396
3397 static void
3398 clipboard_rich_text_received (GtkClipboard *clipboard,
3399                               GdkAtom       format,
3400                               const guint8 *text,
3401                               gsize         length,
3402                               gpointer      data)
3403 {
3404   ClipboardRequest *request_data = data;
3405   GtkTextIter insert_point;
3406   gboolean retval = TRUE;
3407   GError *error = NULL;
3408
3409   if (text != NULL && length > 0)
3410     {
3411       pre_paste_prep (request_data, &insert_point);
3412
3413       if (request_data->interactive)
3414         gtk_text_buffer_begin_user_action (request_data->buffer);
3415
3416       if (!request_data->interactive ||
3417           gtk_text_iter_can_insert (&insert_point,
3418                                     request_data->default_editable))
3419         {
3420           retval = gtk_text_buffer_deserialize (request_data->buffer,
3421                                                 request_data->buffer,
3422                                                 format,
3423                                                 &insert_point,
3424                                                 text, length,
3425                                                 &error);
3426         }
3427
3428       if (!retval)
3429         {
3430           g_warning ("error pasting: %s\n", error->message);
3431           g_clear_error (&error);
3432         }
3433
3434       if (request_data->interactive)
3435         gtk_text_buffer_end_user_action (request_data->buffer);
3436
3437       if (retval)
3438         {
3439           post_paste_cleanup (request_data);
3440           return;
3441         }
3442     }
3443
3444   /* Request the text selection instead */
3445   gtk_clipboard_request_text (clipboard,
3446                               clipboard_text_received,
3447                               data);
3448 }
3449
3450 static void
3451 paste_from_buffer (ClipboardRequest    *request_data,
3452                    GtkTextBuffer       *src_buffer,
3453                    const GtkTextIter   *start,
3454                    const GtkTextIter   *end)
3455 {
3456   GtkTextIter insert_point;
3457   GtkTextBuffer *buffer = request_data->buffer;
3458   
3459   /* We're about to emit a bunch of signals, so be safe */
3460   g_object_ref (src_buffer);
3461   
3462   pre_paste_prep (request_data, &insert_point);
3463   
3464   if (request_data->interactive) 
3465     gtk_text_buffer_begin_user_action (buffer);
3466
3467   if (!gtk_text_iter_equal (start, end))
3468     {
3469       if (!request_data->interactive ||
3470           (gtk_text_iter_can_insert (&insert_point,
3471                                      request_data->default_editable)))
3472         gtk_text_buffer_real_insert_range (buffer,
3473                                            &insert_point,
3474                                            start,
3475                                            end,
3476                                            request_data->interactive);
3477     }
3478
3479   post_paste_cleanup (request_data);
3480       
3481   if (request_data->interactive) 
3482     gtk_text_buffer_end_user_action (buffer);
3483
3484   g_object_unref (src_buffer);
3485
3486   free_clipboard_request (request_data);
3487 }
3488
3489 static void
3490 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
3491                                      GtkSelectionData *selection_data,
3492                                      gpointer          data)
3493 {
3494   ClipboardRequest *request_data = data;
3495   GtkTextBuffer *src_buffer;
3496
3497   src_buffer = selection_data_get_buffer (selection_data, request_data); 
3498
3499   if (src_buffer)
3500     {
3501       GtkTextIter start, end;
3502
3503       if (g_object_get_data (G_OBJECT (src_buffer), "gtk-text-buffer-clipboard"))
3504         {
3505           gtk_text_buffer_get_bounds (src_buffer, &start, &end);
3506
3507           paste_from_buffer (request_data, src_buffer,
3508                              &start, &end);
3509         }
3510       else
3511         {
3512           if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
3513             paste_from_buffer (request_data, src_buffer,
3514                                &start, &end);
3515         }
3516     }
3517   else
3518     {
3519       if (gtk_clipboard_wait_is_rich_text_available (clipboard,
3520                                                      request_data->buffer))
3521         {
3522           /* Request rich text */
3523           gtk_clipboard_request_rich_text (clipboard,
3524                                            request_data->buffer,
3525                                            clipboard_rich_text_received,
3526                                            data);
3527         }
3528       else
3529         {
3530           /* Request the text selection instead */
3531           gtk_clipboard_request_text (clipboard,
3532                                       clipboard_text_received,
3533                                       data);
3534         }
3535     }
3536 }
3537
3538 typedef struct
3539 {
3540   GtkClipboard *clipboard;
3541   guint ref_count;
3542 } SelectionClipboard;
3543
3544 static void
3545 update_selection_clipboards (GtkTextBuffer *buffer)
3546 {
3547   GtkTextBufferPrivate *priv;
3548   GSList               *tmp_list = buffer->selection_clipboards;
3549
3550   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3551
3552   gtk_text_buffer_get_copy_target_list (buffer);
3553
3554   while (tmp_list)
3555     {
3556       GtkTextIter start;
3557       GtkTextIter end;
3558       
3559       SelectionClipboard *selection_clipboard = tmp_list->data;
3560       GtkClipboard *clipboard = selection_clipboard->clipboard;
3561
3562       /* Determine whether we have a selection and adjust X selection
3563        * accordingly.
3564        */
3565       if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3566         {
3567           if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
3568             gtk_clipboard_clear (clipboard);
3569         }
3570       else
3571         {
3572           /* Even if we already have the selection, we need to update our
3573            * timestamp.
3574            */
3575           if (!gtk_clipboard_set_with_owner (clipboard,
3576                                              priv->copy_target_entries,
3577                                              priv->n_copy_target_entries,
3578                                              clipboard_get_selection_cb,
3579                                              clipboard_clear_selection_cb,
3580                                              G_OBJECT (buffer)))
3581             clipboard_clear_selection_cb (clipboard, buffer);
3582         }
3583
3584       tmp_list = tmp_list->next;
3585     }
3586 }
3587
3588 static SelectionClipboard *
3589 find_selection_clipboard (GtkTextBuffer *buffer,
3590                           GtkClipboard  *clipboard)
3591 {
3592   GSList *tmp_list = buffer->selection_clipboards;
3593   while (tmp_list)
3594     {
3595       SelectionClipboard *selection_clipboard = tmp_list->data;
3596       if (selection_clipboard->clipboard == clipboard)
3597         return selection_clipboard;
3598       
3599       tmp_list = tmp_list->next;
3600     }
3601
3602   return NULL;
3603 }
3604
3605 /**
3606  * gtk_text_buffer_add_selection_clipboard:
3607  * @buffer: a #GtkTextBuffer
3608  * @clipboard: a #GtkClipboard
3609  * 
3610  * Adds @clipboard to the list of clipboards in which the selection contents
3611  * of @buffer are available. In most cases, @clipboard will be the #GtkClipboard
3612  * of type %GDK_SELECTION_PRIMARY for a view of @buffer.
3613  **/
3614 void
3615 gtk_text_buffer_add_selection_clipboard (GtkTextBuffer *buffer,
3616                                          GtkClipboard  *clipboard)
3617 {
3618   SelectionClipboard *selection_clipboard;
3619
3620   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3621   g_return_if_fail (clipboard != NULL);
3622
3623   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3624   if (selection_clipboard)
3625     {
3626       selection_clipboard->ref_count++;
3627     }
3628   else
3629     {
3630       selection_clipboard = g_new (SelectionClipboard, 1);
3631
3632       selection_clipboard->clipboard = clipboard;
3633       selection_clipboard->ref_count = 1;
3634
3635       buffer->selection_clipboards = g_slist_prepend (buffer->selection_clipboards, selection_clipboard);
3636     }
3637 }
3638
3639 /**
3640  * gtk_text_buffer_remove_selection_clipboard:
3641  * @buffer: a #GtkTextBuffer
3642  * @clipboard: a #GtkClipboard added to @buffer by gtk_text_buffer_add_selection_clipboard().
3643  * 
3644  * Removes a #GtkClipboard added with gtk_text_buffer_add_selection_clipboard()
3645  **/
3646 void 
3647 gtk_text_buffer_remove_selection_clipboard (GtkTextBuffer *buffer,
3648                                             GtkClipboard  *clipboard)
3649 {
3650   SelectionClipboard *selection_clipboard;
3651
3652   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3653   g_return_if_fail (clipboard != NULL);
3654
3655   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3656   g_return_if_fail (selection_clipboard != NULL);
3657
3658   selection_clipboard->ref_count--;
3659   if (selection_clipboard->ref_count == 0)
3660     {
3661       if (gtk_clipboard_get_owner (selection_clipboard->clipboard) == G_OBJECT (buffer))
3662         gtk_clipboard_clear (selection_clipboard->clipboard);
3663
3664       buffer->selection_clipboards = g_slist_remove (buffer->selection_clipboards,
3665                                                      selection_clipboard);
3666       
3667       g_free (selection_clipboard);
3668     }
3669 }
3670
3671 static void
3672 remove_all_selection_clipboards (GtkTextBuffer *buffer)
3673 {
3674   g_slist_foreach (buffer->selection_clipboards, (GFunc)g_free, NULL);
3675   g_slist_free (buffer->selection_clipboards);
3676   buffer->selection_clipboards = NULL;
3677 }
3678
3679 /**
3680  * gtk_text_buffer_paste_clipboard:
3681  * @buffer: a #GtkTextBuffer
3682  * @clipboard: the #GtkClipboard to paste from
3683  * @override_location: location to insert pasted text, or %NULL for at the cursor
3684  * @default_editable: whether the buffer is editable by default
3685  *
3686  * Pastes the contents of a clipboard at the insertion point, or at @override_location.
3687  * (Note: pasting is asynchronous, that is, we'll ask for the paste data and
3688  * return, and at some point later after the main loop runs, the paste
3689  * data will be inserted.)
3690  * 
3691  **/
3692 void
3693 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
3694                                  GtkClipboard  *clipboard,
3695                                  GtkTextIter   *override_location,
3696                                  gboolean       default_editable)
3697 {
3698   ClipboardRequest *data = g_new (ClipboardRequest, 1);
3699   GtkTextIter paste_point;
3700   GtkTextIter start, end;
3701
3702   if (override_location != NULL)
3703     gtk_text_buffer_create_mark (buffer,
3704                                  "gtk_paste_point_override",
3705                                  override_location, FALSE);
3706
3707   data->buffer = g_object_ref (buffer);
3708   data->interactive = TRUE;
3709   data->default_editable = default_editable;
3710
3711   /* When pasting with the cursor inside the selection area, you
3712    * replace the selection with the new text, otherwise, you
3713    * simply insert the new text at the point where the click
3714    * occured, unselecting any selected text. The replace_selection
3715    * flag toggles this behavior.
3716    */
3717   data->replace_selection = FALSE;
3718   
3719   get_paste_point (buffer, &paste_point, FALSE);
3720   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
3721       (gtk_text_iter_in_range (&paste_point, &start, &end) ||
3722        gtk_text_iter_equal (&paste_point, &end)))
3723     data->replace_selection = TRUE;
3724
3725   gtk_clipboard_request_contents (clipboard,
3726                                   gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
3727                                   clipboard_clipboard_buffer_received, data);
3728 }
3729
3730 /**
3731  * gtk_text_buffer_delete_selection:
3732  * @buffer: a #GtkTextBuffer 
3733  * @interactive: whether the deletion is caused by user interaction
3734  * @default_editable: whether the buffer is editable by default
3735  *
3736  * Deletes the range between the "insert" and "selection_bound" marks,
3737  * that is, the currently-selected text. If @interactive is %TRUE,
3738  * the editability of the selection will be considered (users can't delete
3739  * uneditable text).
3740  * 
3741  * Return value: whether there was a non-empty selection to delete
3742  **/
3743 gboolean
3744 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
3745                                   gboolean interactive,
3746                                   gboolean default_editable)
3747 {
3748   GtkTextIter start;
3749   GtkTextIter end;
3750
3751   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3752     {
3753       return FALSE; /* No selection */
3754     }
3755   else
3756     {
3757       if (interactive)
3758         {
3759           gtk_text_buffer_begin_user_action (buffer);
3760           gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
3761           gtk_text_buffer_end_user_action (buffer);
3762         }
3763       else
3764         gtk_text_buffer_delete (buffer, &start, &end);
3765
3766       return TRUE; /* We deleted stuff */
3767     }
3768 }
3769
3770 /**
3771  * gtk_text_buffer_backspace:
3772  * @buffer: a #GtkTextBuffer
3773  * @iter: a position in @buffer
3774  * @interactive: whether the deletion is caused by user interaction
3775  * @default_editable: whether the buffer is editable by default
3776  * 
3777  * Performs the appropriate action as if the user hit the delete
3778  * key with the cursor at the position specified by @iter. In the
3779  * normal case a single character will be deleted, but when
3780  * combining accents are involved, more than one character can
3781  * be deleted, and when precomposed character and accent combinations
3782  * are involved, less than one character will be deleted.
3783  * 
3784  * Because the buffer is modified, all outstanding iterators become 
3785  * invalid after calling this function; however, the @iter will be
3786  * re-initialized to point to the location where text was deleted. 
3787  *
3788  * Return value: %TRUE if the buffer was modified
3789
3790  * Since: 2.6
3791  **/
3792 gboolean
3793 gtk_text_buffer_backspace (GtkTextBuffer *buffer,
3794                            GtkTextIter   *iter,
3795                            gboolean       interactive,
3796                            gboolean       default_editable)
3797 {
3798   gchar *cluster_text;
3799   GtkTextIter start;
3800   GtkTextIter end;
3801   gboolean retval = FALSE;
3802   const PangoLogAttr *attrs;
3803   int offset;
3804   gboolean backspace_deletes_character;
3805
3806   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3807   g_return_val_if_fail (iter != NULL, FALSE);
3808
3809   start = *iter;
3810   end = *iter;
3811
3812   attrs = _gtk_text_buffer_get_line_log_attrs (buffer, &start, NULL);
3813
3814   /* For no good reason, attrs is NULL for the empty last line in
3815    * a buffer. Special case that here. (#156164)
3816    */
3817   if (attrs)
3818     {
3819       offset = gtk_text_iter_get_line_offset (&start);
3820       backspace_deletes_character = attrs[offset].backspace_deletes_character;
3821     }
3822   else
3823     backspace_deletes_character = FALSE;
3824
3825   gtk_text_iter_backward_cursor_position (&start);
3826
3827   if (gtk_text_iter_equal (&start, &end))
3828     return FALSE;
3829     
3830   cluster_text = gtk_text_iter_get_text (&start, &end);
3831
3832   if (interactive)
3833     gtk_text_buffer_begin_user_action (buffer);
3834   
3835   if (gtk_text_buffer_delete_interactive (buffer, &start, &end,
3836                                           default_editable))
3837     {
3838       if (backspace_deletes_character)
3839         {
3840           gchar *normalized_text = g_utf8_normalize (cluster_text,
3841                                                      strlen (cluster_text),
3842                                                      G_NORMALIZE_NFD);
3843           glong len = g_utf8_strlen (normalized_text, -1);
3844           
3845           if (len > 1)
3846             gtk_text_buffer_insert_interactive (buffer,
3847                                                 &start,
3848                                                 normalized_text,
3849                                                 g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
3850                                                 default_editable);
3851           
3852           g_free (normalized_text);
3853         }
3854
3855       retval = TRUE;
3856     }
3857   
3858   if (interactive)
3859     gtk_text_buffer_end_user_action (buffer);
3860   
3861   g_free (cluster_text);
3862
3863   /* Revalidate the users iter */
3864   *iter = start;
3865
3866   return retval;
3867 }
3868
3869 static void
3870 cut_or_copy (GtkTextBuffer *buffer,
3871              GtkClipboard  *clipboard,
3872              gboolean       delete_region_after,
3873              gboolean       interactive,
3874              gboolean       default_editable)
3875 {
3876   GtkTextBufferPrivate *priv;
3877
3878   /* We prefer to cut the selected region between selection_bound and
3879    * insertion point. If that region is empty, then we cut the region
3880    * between the "anchor" and the insertion point (this is for
3881    * C-space and M-w and other Emacs-style copy/yank keys). Note that
3882    * insert and selection_bound are guaranteed to exist, but the
3883    * anchor only exists sometimes.
3884    */
3885   GtkTextIter start;
3886   GtkTextIter end;
3887
3888   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3889
3890   gtk_text_buffer_get_copy_target_list (buffer);
3891
3892   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3893     {
3894       /* Let's try the anchor thing */
3895       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
3896
3897       if (anchor == NULL)
3898         return;
3899       else
3900         {
3901           gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
3902           gtk_text_iter_order (&start, &end);
3903         }
3904     }
3905
3906   if (!gtk_text_iter_equal (&start, &end))
3907     {
3908       GtkTextIter ins;
3909       GtkTextBuffer *contents;
3910
3911       contents = create_clipboard_contents_buffer (buffer);
3912
3913       gtk_text_buffer_get_iter_at_offset (contents, &ins, 0);
3914       
3915       gtk_text_buffer_insert_range (contents, &ins, &start, &end);
3916                                     
3917       if (!gtk_clipboard_set_with_data (clipboard,
3918                                         priv->copy_target_entries,
3919                                         priv->n_copy_target_entries,
3920                                         clipboard_get_contents_cb,
3921                                         clipboard_clear_contents_cb,
3922                                         contents))
3923         g_object_unref (contents);
3924       else
3925         gtk_clipboard_set_can_store (clipboard,
3926                                      priv->copy_target_entries + 1,
3927                                      priv->n_copy_target_entries - 1);
3928
3929       if (delete_region_after)
3930         {
3931           if (interactive)
3932             gtk_text_buffer_delete_interactive (buffer, &start, &end,
3933                                                 default_editable);
3934           else
3935             gtk_text_buffer_delete (buffer, &start, &end);
3936         }
3937     }
3938 }
3939
3940 /**
3941  * gtk_text_buffer_cut_clipboard:
3942  * @buffer: a #GtkTextBuffer
3943  * @clipboard: the #GtkClipboard object to cut to.
3944  * @default_editable: default editability of the buffer
3945  *
3946  * Copies the currently-selected text to a clipboard, then deletes
3947  * said text if it's editable.
3948  * 
3949  **/
3950 void
3951 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
3952                                GtkClipboard  *clipboard,
3953                                gboolean       default_editable)
3954 {
3955   gtk_text_buffer_begin_user_action (buffer);
3956   cut_or_copy (buffer, clipboard, TRUE, TRUE, default_editable);
3957   gtk_text_buffer_end_user_action (buffer);
3958 }
3959
3960 /**
3961  * gtk_text_buffer_copy_clipboard:
3962  * @buffer: a #GtkTextBuffer 
3963  * @clipboard: the #GtkClipboard object to copy to.
3964  *
3965  * Copies the currently-selected text to a clipboard.
3966  * 
3967  **/
3968 void
3969 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer,
3970                                 GtkClipboard  *clipboard)
3971 {
3972   gtk_text_buffer_begin_user_action (buffer);
3973   cut_or_copy (buffer, clipboard, FALSE, TRUE, TRUE);
3974   gtk_text_buffer_end_user_action (buffer);
3975 }
3976
3977
3978 /**
3979  * gtk_text_buffer_get_selection_bounds:
3980  * @buffer: a #GtkTextBuffer a #GtkTextBuffer
3981  * @start: iterator to initialize with selection start
3982  * @end: iterator to initialize with selection end
3983  *
3984  * Returns %TRUE if some text is selected; places the bounds
3985  * of the selection in @start and @end (if the selection has length 0,
3986  * then @start and @end are filled in with the same value).
3987  * @start and @end will be in ascending order. If @start and @end are
3988  * NULL, then they are not filled in, but the return value still indicates
3989  * whether text is selected.
3990  *
3991  * Return value: whether the selection has nonzero length
3992  **/
3993 gboolean
3994 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
3995                                         GtkTextIter        *start,
3996                                         GtkTextIter        *end)
3997 {
3998   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3999
4000   return _gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
4001 }
4002
4003 /**
4004  * gtk_text_buffer_begin_user_action:
4005  * @buffer: a #GtkTextBuffer
4006  * 
4007  * Called to indicate that the buffer operations between here and a
4008  * call to gtk_text_buffer_end_user_action() are part of a single
4009  * user-visible operation. The operations between
4010  * gtk_text_buffer_begin_user_action() and
4011  * gtk_text_buffer_end_user_action() can then be grouped when creating
4012  * an undo stack. #GtkTextBuffer maintains a count of calls to
4013  * gtk_text_buffer_begin_user_action() that have not been closed with
4014  * a call to gtk_text_buffer_end_user_action(), and emits the "begin_user_action"
4015  * and "end_user_action" signals only for the outermost pair of calls.
4016  * This allows you to build user actions from other user actions.
4017  *
4018  * The "interactive" buffer mutation functions, such as
4019  * gtk_text_buffer_insert_interactive(), automatically call begin/end
4020  * user action around the buffer operations they perform, so there's
4021  * no need to add extra calls if you user action consists solely of a
4022  * single call to one of those functions.
4023  **/
4024 void
4025 gtk_text_buffer_begin_user_action (GtkTextBuffer *buffer)
4026 {
4027   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4028
4029   buffer->user_action_count += 1;
4030   
4031   if (buffer->user_action_count == 1)
4032     {
4033       /* Outermost nested user action begin emits the signal */
4034       g_signal_emit (buffer, signals[BEGIN_USER_ACTION], 0);
4035     }
4036 }
4037
4038 /**
4039  * gtk_text_buffer_end_user_action:
4040  * @buffer: a #GtkTextBuffer
4041  * 
4042  * Should be paired with a call to gtk_text_buffer_begin_user_action().
4043  * See that function for a full explanation.
4044  **/
4045 void
4046 gtk_text_buffer_end_user_action (GtkTextBuffer *buffer)
4047 {
4048   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4049   g_return_if_fail (buffer->user_action_count > 0);
4050   
4051   buffer->user_action_count -= 1;
4052   
4053   if (buffer->user_action_count == 0)
4054     {
4055       /* Ended the outermost-nested user action end, so emit the signal */
4056       g_signal_emit (buffer, signals[END_USER_ACTION], 0);
4057     }
4058 }
4059
4060 static void
4061 gtk_text_buffer_free_target_lists (GtkTextBuffer *buffer)
4062 {
4063   GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4064
4065   if (priv->copy_target_list)
4066     {
4067       gtk_target_list_unref (priv->copy_target_list);
4068       priv->copy_target_list = NULL;
4069
4070       gtk_target_table_free (priv->copy_target_entries,
4071                              priv->n_copy_target_entries);
4072       priv->copy_target_entries = NULL;
4073       priv->n_copy_target_entries = 0;
4074     }
4075
4076   if (priv->paste_target_list)
4077     {
4078       gtk_target_list_unref (priv->paste_target_list);
4079       priv->paste_target_list = NULL;
4080
4081       gtk_target_table_free (priv->paste_target_entries,
4082                              priv->n_paste_target_entries);
4083       priv->paste_target_entries = NULL;
4084       priv->n_paste_target_entries = 0;
4085     }
4086 }
4087
4088 static GtkTargetList *
4089 gtk_text_buffer_get_target_list (GtkTextBuffer   *buffer,
4090                                  gboolean         deserializable,
4091                                  GtkTargetEntry **entries,
4092                                  gint            *n_entries)
4093 {
4094   GtkTargetList *target_list;
4095
4096   target_list = gtk_target_list_new (NULL, 0);
4097
4098   gtk_target_list_add (target_list,
4099                        gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
4100                        GTK_TARGET_SAME_APP,
4101                        GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS);
4102
4103   gtk_target_list_add_rich_text_targets (target_list,
4104                                          GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
4105                                          deserializable,
4106                                          buffer);
4107
4108   gtk_target_list_add_text_targets (target_list,
4109                                     GTK_TEXT_BUFFER_TARGET_INFO_TEXT);
4110
4111   *entries = gtk_target_table_new_from_list (target_list, n_entries);
4112
4113   return target_list;
4114 }
4115
4116 /**
4117  * gtk_text_buffer_get_copy_target_list:
4118  * @buffer: a #GtkTextBuffer
4119  *
4120  * This function returns the list of targets this text buffer can
4121  * provide for copying and as DND source. The targets in the list are
4122  * added with %info values from the #GtkTextBufferTargetInfo enum,
4123  * using gtk_target_list_add_rich_text_targets() and
4124  * gtk_target_list_add_text_targets()
4125  *
4126  * Return value: the #GtkTargetList
4127  *
4128  * Since: 2.10
4129  **/
4130 GtkTargetList *
4131 gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer)
4132 {
4133   GtkTextBufferPrivate *priv;
4134
4135   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4136
4137   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4138
4139   if (! priv->copy_target_list)
4140     priv->copy_target_list =
4141       gtk_text_buffer_get_target_list (buffer, FALSE,
4142                                        &priv->copy_target_entries,
4143                                        &priv->n_copy_target_entries);
4144
4145   return priv->copy_target_list;
4146 }
4147
4148 /**
4149  * gtk_text_buffer_get_paste_target_list:
4150  * @buffer: a #GtkTextBuffer
4151  *
4152  * This function returns the list of targets this text buffer supports
4153  * for pasting and as DND destination. The targets in the list are
4154  * added with %info values from the #GtkTextBufferTargetInfo enum,
4155  * using gtk_target_list_add_rich_text_targets() and
4156  * gtk_target_list_add_text_targets()
4157  *
4158  * Return value: the #GtkTargetList
4159  *
4160  * Since: 2.10
4161  **/
4162 GtkTargetList *
4163 gtk_text_buffer_get_paste_target_list (GtkTextBuffer *buffer)
4164 {
4165   GtkTextBufferPrivate *priv;
4166
4167   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4168
4169   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4170
4171   if (! priv->paste_target_list)
4172     priv->paste_target_list =
4173       gtk_text_buffer_get_target_list (buffer, TRUE,
4174                                        &priv->paste_target_entries,
4175                                        &priv->n_paste_target_entries);
4176
4177   return priv->paste_target_list;
4178 }
4179
4180 /*
4181  * Logical attribute cache
4182  */
4183
4184 #define ATTR_CACHE_SIZE 2
4185
4186 typedef struct _CacheEntry CacheEntry;
4187 struct _CacheEntry
4188 {
4189   gint line;
4190   gint char_len;
4191   PangoLogAttr *attrs;
4192 };
4193
4194
4195 struct _GtkTextLogAttrCache
4196 {
4197   gint chars_changed_stamp;
4198   CacheEntry entries[ATTR_CACHE_SIZE];
4199 };
4200
4201 static void
4202 free_log_attr_cache (GtkTextLogAttrCache *cache)
4203 {
4204   gint i = 0;
4205   while (i < ATTR_CACHE_SIZE)
4206     {
4207       g_free (cache->entries[i].attrs);
4208       ++i;
4209     }
4210   g_free (cache);
4211 }
4212
4213 static void
4214 clear_log_attr_cache (GtkTextLogAttrCache *cache)
4215 {
4216   gint i = 0;
4217   while (i < ATTR_CACHE_SIZE)
4218     {
4219       g_free (cache->entries[i].attrs);
4220       cache->entries[i].attrs = NULL;
4221       ++i;
4222     }
4223 }
4224
4225 static PangoLogAttr*
4226 compute_log_attrs (const GtkTextIter *iter,
4227                    gint              *char_lenp)
4228 {
4229   GtkTextIter start;
4230   GtkTextIter end;
4231   gchar *paragraph;
4232   gint char_len, byte_len;
4233   PangoLogAttr *attrs = NULL;
4234   
4235   start = *iter;
4236   end = *iter;
4237
4238   gtk_text_iter_set_line_offset (&start, 0);
4239   gtk_text_iter_forward_line (&end);
4240
4241   paragraph = gtk_text_iter_get_slice (&start, &end);
4242   char_len = g_utf8_strlen (paragraph, -1);
4243   byte_len = strlen (paragraph);
4244
4245   g_assert (char_len > 0);
4246
4247   if (char_lenp)
4248     *char_lenp = char_len;
4249   
4250   attrs = g_new (PangoLogAttr, char_len + 1);
4251
4252   /* FIXME we need to follow PangoLayout and allow different language
4253    * tags within the paragraph
4254    */
4255   pango_get_log_attrs (paragraph, byte_len, -1,
4256                        gtk_text_iter_get_language (&start),
4257                        attrs,
4258                        char_len + 1);
4259   
4260   g_free (paragraph);
4261
4262   return attrs;
4263 }
4264
4265 /* The return value from this is valid until you call this a second time.
4266  */
4267 const PangoLogAttr*
4268 _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer     *buffer,
4269                                      const GtkTextIter *anywhere_in_line,
4270                                      gint              *char_len)
4271 {
4272   gint line;
4273   GtkTextLogAttrCache *cache;
4274   gint i;
4275   
4276   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4277   g_return_val_if_fail (anywhere_in_line != NULL, NULL);
4278
4279   /* special-case for empty last line in buffer */
4280   if (gtk_text_iter_is_end (anywhere_in_line) &&
4281       gtk_text_iter_get_line_offset (anywhere_in_line) == 0)
4282     {
4283       if (char_len)
4284         *char_len = 0;
4285       return NULL;
4286     }
4287   
4288   /* FIXME we also need to recompute log attrs if the language tag at
4289    * the start of a paragraph changes
4290    */
4291   
4292   if (buffer->log_attr_cache == NULL)
4293     {
4294       buffer->log_attr_cache = g_new0 (GtkTextLogAttrCache, 1);
4295       buffer->log_attr_cache->chars_changed_stamp =
4296         _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer));
4297     }
4298   else if (buffer->log_attr_cache->chars_changed_stamp !=
4299            _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer)))
4300     {
4301       clear_log_attr_cache (buffer->log_attr_cache);
4302     }
4303   
4304   cache = buffer->log_attr_cache;
4305   line = gtk_text_iter_get_line (anywhere_in_line);
4306
4307   i = 0;
4308   while (i < ATTR_CACHE_SIZE)
4309     {
4310       if (cache->entries[i].attrs &&
4311           cache->entries[i].line == line)
4312         {
4313           if (char_len)
4314             *char_len = cache->entries[i].char_len;
4315           return cache->entries[i].attrs;
4316         }
4317       ++i;
4318     }
4319   
4320   /* Not in cache; open up the first cache entry */
4321   g_free (cache->entries[ATTR_CACHE_SIZE-1].attrs);
4322   
4323   g_memmove (cache->entries + 1, cache->entries,
4324              sizeof (CacheEntry) * (ATTR_CACHE_SIZE - 1));
4325
4326   cache->entries[0].line = line;
4327   cache->entries[0].attrs = compute_log_attrs (anywhere_in_line,
4328                                                &cache->entries[0].char_len);
4329
4330   if (char_len)
4331     *char_len = cache->entries[0].char_len;
4332   
4333   return cache->entries[0].attrs;
4334 }
4335
4336 void
4337 _gtk_text_buffer_notify_will_remove_tag (GtkTextBuffer *buffer,
4338                                          GtkTextTag    *tag)
4339 {
4340   /* This removes tag from the buffer, but DOESN'T emit the
4341    * remove_tag signal, because we can't afford to have user
4342    * code messing things up at this point; the tag MUST be removed
4343    * entirely.
4344    */
4345   if (buffer->btree)
4346     _gtk_text_btree_notify_will_remove_tag (buffer->btree, tag);
4347 }
4348
4349 /*
4350  * Debug spew
4351  */
4352
4353 void
4354 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
4355 {
4356   _gtk_text_btree_spew (get_btree (buffer));
4357 }
4358
4359 #define __GTK_TEXT_BUFFER_C__
4360 #include "gtkaliasdef.c"