]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
68364b60b17e42b1e837016c88d5f6ec89a661eb
[~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_add_mark:
2084  * @buffer: a #GtkTextBuffer
2085  * @mark: the mark to add
2086  * @where: location to place mark
2087  *
2088  * Adds the mark at position @where. The mark must not be added to
2089  * another buffer, and if its name is not %NULL then there must not
2090  * be another mark in the buffer with the same name.
2091  *
2092  * Emits the "mark_set" signal as notification of the mark's initial
2093  * placement.
2094  *
2095  * Since: 2.12
2096  **/
2097 void
2098 gtk_text_buffer_add_mark (GtkTextBuffer     *buffer,
2099                           GtkTextMark       *mark,
2100                           const GtkTextIter *where)
2101 {
2102   const gchar *name;
2103
2104   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2105   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2106   g_return_if_fail (where != NULL);
2107   g_return_if_fail (gtk_text_mark_get_buffer (mark) == NULL);
2108
2109   name = gtk_text_mark_get_name (mark);
2110
2111   if (name != NULL && gtk_text_buffer_get_mark (buffer, name) != NULL)
2112     {
2113       g_critical ("Mark %s already exists in the buffer", name);
2114       return;
2115     }
2116
2117   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, FALSE);
2118 }
2119
2120 /**
2121  * gtk_text_buffer_move_mark:
2122  * @buffer: a #GtkTextBuffer
2123  * @mark: a #GtkTextMark
2124  * @where: new location for @mark in @buffer
2125  *
2126  * Moves @mark to the new location @where. Emits the "mark_set" signal
2127  * as notification of the move.
2128  **/
2129 void
2130 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
2131                            GtkTextMark *mark,
2132                            const GtkTextIter *where)
2133 {
2134   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2135   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2136   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2137
2138   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
2139 }
2140
2141 /**
2142  * gtk_text_buffer_get_iter_at_mark:
2143  * @buffer: a #GtkTextBuffer
2144  * @iter: iterator to initialize
2145  * @mark: a #GtkTextMark in @buffer
2146  *
2147  * Initializes @iter with the current position of @mark.
2148  **/
2149 void
2150 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
2151                                   GtkTextIter *iter,
2152                                   GtkTextMark *mark)
2153 {
2154   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2155   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2156   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2157
2158   _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
2159                                     iter,
2160                                     mark);
2161 }
2162
2163 /**
2164  * gtk_text_buffer_delete_mark:
2165  * @buffer: a #GtkTextBuffer
2166  * @mark: a #GtkTextMark in @buffer
2167  *
2168  * Deletes @mark, so that it's no longer located anywhere in the
2169  * buffer. Removes the reference the buffer holds to the mark, so if
2170  * you haven't called g_object_ref() on the mark, it will be freed. Even
2171  * if the mark isn't freed, most operations on @mark become
2172  * invalid, until it gets added to a buffer again with 
2173  * gtk_text_buffer_add_mark(). Use gtk_text_mark_get_deleted() to  
2174  * find out if a mark has been removed from its buffer.
2175  * The "mark_deleted" signal will be emitted as notification after 
2176  * the mark is deleted.
2177  **/
2178 void
2179 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
2180                              GtkTextMark   *mark)
2181 {
2182   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2183   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2184   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2185
2186   g_object_ref (mark);
2187
2188   _gtk_text_btree_remove_mark (get_btree (buffer), mark);
2189
2190   /* See rationale above for MARK_SET on why we emit this after
2191    * removing the mark, rather than removing the mark in a default
2192    * handler.
2193    */
2194   g_signal_emit (buffer, signals[MARK_DELETED],
2195                  0,
2196                  mark);
2197
2198   g_object_unref (mark);
2199 }
2200
2201 /**
2202  * gtk_text_buffer_get_mark:
2203  * @buffer: a #GtkTextBuffer
2204  * @name: a mark name
2205  *
2206  * Returns the mark named @name in buffer @buffer, or NULL if no such
2207  * mark exists in the buffer.
2208  *
2209  * Return value: a #GtkTextMark, or NULL
2210  **/
2211 GtkTextMark*
2212 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
2213                           const gchar         *name)
2214 {
2215   GtkTextMark *mark;
2216
2217   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2218   g_return_val_if_fail (name != NULL, NULL);
2219
2220   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2221
2222   return mark;
2223 }
2224
2225
2226 /**
2227  * gtk_text_buffer_move_mark_by_name:
2228  * @buffer: a #GtkTextBuffer
2229  * @name: name of a mark
2230  * @where: new location for mark
2231  *
2232  * Moves the mark named @name (which must exist) to location @where.
2233  * See gtk_text_buffer_move_mark () for details.
2234  **/
2235 void
2236 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
2237                                    const gchar       *name,
2238                                    const GtkTextIter *where)
2239 {
2240   GtkTextMark *mark;
2241
2242   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2243   g_return_if_fail (name != NULL);
2244
2245   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2246
2247   if (mark == NULL)
2248     {
2249       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2250       return;
2251     }
2252
2253   gtk_text_buffer_move_mark (buffer, mark, where);
2254 }
2255
2256 /**
2257  * gtk_text_buffer_delete_mark_by_name:
2258  * @buffer: a #GtkTextBuffer
2259  * @name: name of a mark in @buffer
2260  *
2261  * Deletes the mark named @name; the mark must exist. See
2262  * gtk_text_buffer_delete_mark () for details.
2263  **/
2264 void
2265 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer     *buffer,
2266                                      const gchar       *name)
2267 {
2268   GtkTextMark *mark;
2269
2270   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2271   g_return_if_fail (name != NULL);
2272
2273   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2274
2275   if (mark == NULL)
2276     {
2277       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2278       return;
2279     }
2280
2281   gtk_text_buffer_delete_mark (buffer, mark);
2282 }
2283
2284 /**
2285  * gtk_text_buffer_get_insert:
2286  * @buffer: a #GtkTextBuffer
2287  *
2288  * Returns the mark that represents the cursor (insertion point).
2289  * Equivalent to calling gtk_text_buffer_get_mark () to get the mark
2290  * named "insert", but very slightly more efficient, and involves less
2291  * typing.
2292  *
2293  * Return value: insertion point mark
2294  **/
2295 GtkTextMark*
2296 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
2297 {
2298   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2299
2300   /* FIXME use struct member in btree */
2301   return gtk_text_buffer_get_mark (buffer, "insert");
2302 }
2303
2304 /**
2305  * gtk_text_buffer_get_selection_bound:
2306  * @buffer: a #GtkTextBuffer
2307  *
2308  * Returns the mark that represents the selection bound.  Equivalent
2309  * to calling gtk_text_buffer_get_mark () to get the mark named
2310  * "selection_bound", but very slightly more efficient, and involves
2311  * less typing.
2312  *
2313  * The currently-selected text in @buffer is the region between the
2314  * "selection_bound" and "insert" marks. If "selection_bound" and
2315  * "insert" are in the same place, then there is no current selection.
2316  * gtk_text_buffer_get_selection_bounds() is another convenient function
2317  * for handling the selection, if you just want to know whether there's a
2318  * selection and what its bounds are.
2319  *
2320  * Return value: selection bound mark
2321  **/
2322 GtkTextMark*
2323 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
2324 {
2325   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2326
2327   /* FIXME use struct member in btree */
2328   return gtk_text_buffer_get_mark (buffer, "selection_bound");
2329 }
2330
2331 /**
2332  * gtk_text_buffer_get_iter_at_child_anchor:
2333  * @buffer: a #GtkTextBuffer
2334  * @iter: an iterator to be initialized
2335  * @anchor: a child anchor that appears in @buffer
2336  *
2337  * Obtains the location of @anchor within @buffer.
2338  * 
2339  **/
2340 void
2341 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
2342                                           GtkTextIter        *iter,
2343                                           GtkTextChildAnchor *anchor)
2344 {
2345   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2346   g_return_if_fail (iter != NULL);
2347   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
2348   g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
2349   
2350   _gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
2351                                            iter,
2352                                            anchor);
2353 }
2354
2355 /**
2356  * gtk_text_buffer_place_cursor:
2357  * @buffer: a #GtkTextBuffer
2358  * @where: where to put the cursor
2359  *
2360  * This function moves the "insert" and "selection_bound" marks
2361  * simultaneously.  If you move them to the same place in two steps
2362  * with gtk_text_buffer_move_mark(), you will temporarily select a
2363  * region in between their old and new locations, which can be pretty
2364  * inefficient since the temporarily-selected region will force stuff
2365  * to be recalculated. This function moves them as a unit, which can
2366  * be optimized.
2367  **/
2368 void
2369 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
2370                               const GtkTextIter *where)
2371 {
2372   gtk_text_buffer_select_range (buffer, where, where);
2373 }
2374
2375
2376 /**
2377  * gtk_text_buffer_select_range:
2378  * @buffer: a #GtkTextBuffer
2379  * @ins: where to put the "insert" mark
2380  * @bound: where to put the "selection_bound" mark
2381  *
2382  * This function moves the "insert" and "selection_bound" marks
2383  * simultaneously.  If you move them in two steps
2384  * with gtk_text_buffer_move_mark(), you will temporarily select a
2385  * region in between their old and new locations, which can be pretty
2386  * inefficient since the temporarily-selected region will force stuff
2387  * to be recalculated. This function moves them as a unit, which can
2388  * be optimized.
2389  *
2390  * Since: 2.4
2391  **/
2392 void
2393 gtk_text_buffer_select_range (GtkTextBuffer     *buffer,
2394                               const GtkTextIter *ins,
2395                               const GtkTextIter *bound)
2396 {
2397   GtkTextIter real_ins;
2398   GtkTextIter real_bound;
2399
2400   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2401
2402   real_ins = *ins;
2403   real_bound = *bound;
2404
2405   _gtk_text_btree_select_range (get_btree (buffer), &real_ins, &real_bound);
2406   gtk_text_buffer_mark_set (buffer, &real_ins,
2407                             gtk_text_buffer_get_mark (buffer,
2408                                                       "insert"));
2409   gtk_text_buffer_mark_set (buffer, &real_bound,
2410                             gtk_text_buffer_get_mark (buffer,
2411                                                       "selection_bound"));
2412 }
2413
2414 /*
2415  * Tags
2416  */
2417
2418 /**
2419  * gtk_text_buffer_create_tag:
2420  * @buffer: a #GtkTextBuffer
2421  * @tag_name: name of the new tag, or %NULL
2422  * @first_property_name: name of first property to set, or %NULL
2423  * @Varargs: %NULL-terminated list of property names and values
2424  *
2425  *
2426  * Creates a tag and adds it to the tag table for @buffer.
2427  * Equivalent to calling gtk_text_tag_new () and then adding the
2428  * tag to the buffer's tag table. The returned tag is owned by
2429  * the buffer's tag table, so the ref count will be equal to one.
2430  *
2431  * If @tag_name is %NULL, the tag is anonymous.
2432  *
2433  * If @tag_name is non-%NULL, a tag called @tag_name must not already
2434  * exist in the tag table for this buffer.
2435  *
2436  * The @first_property_name argument and subsequent arguments are a list
2437  * of properties to set on the tag, as with g_object_set().
2438  *
2439  * Return value: a new tag
2440  **/
2441 GtkTextTag*
2442 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
2443                             const gchar   *tag_name,
2444                             const gchar   *first_property_name,
2445                             ...)
2446 {
2447   GtkTextTag *tag;
2448   va_list list;
2449   
2450   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2451
2452   tag = gtk_text_tag_new (tag_name);
2453
2454   gtk_text_tag_table_add (get_table (buffer), tag);
2455
2456   if (first_property_name)
2457     {
2458       va_start (list, first_property_name);
2459       g_object_set_valist (G_OBJECT (tag), first_property_name, list);
2460       va_end (list);
2461     }
2462   
2463   g_object_unref (tag);
2464
2465   return tag;
2466 }
2467
2468 static void
2469 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
2470                                 GtkTextTag *tag,
2471                                 const GtkTextIter *start,
2472                                 const GtkTextIter *end)
2473 {
2474   if (tag->table != buffer->tag_table)
2475     {
2476       g_warning ("Can only apply tags that are in the tag table for the buffer");
2477       return;
2478     }
2479   
2480   _gtk_text_btree_tag (start, end, tag, TRUE);
2481 }
2482
2483 static void
2484 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
2485                                  GtkTextTag *tag,
2486                                  const GtkTextIter *start,
2487                                  const GtkTextIter *end)
2488 {
2489   if (tag->table != buffer->tag_table)
2490     {
2491       g_warning ("Can only remove tags that are in the tag table for the buffer");
2492       return;
2493     }
2494   
2495   _gtk_text_btree_tag (start, end, tag, FALSE);
2496 }
2497
2498 static void
2499 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
2500 {
2501   gtk_text_buffer_set_modified (buffer, TRUE);
2502 }
2503
2504 static void
2505 gtk_text_buffer_real_mark_set (GtkTextBuffer *buffer,
2506                                const GtkTextIter *iter,
2507                                GtkTextMark *mark)
2508 {
2509   GtkTextMark *insert;
2510   
2511   insert = gtk_text_buffer_get_insert (buffer);
2512
2513   if (mark == insert || mark == gtk_text_buffer_get_selection_bound (buffer))
2514     {
2515       gboolean has_selection;
2516
2517       update_selection_clipboards (buffer);
2518     
2519       has_selection = gtk_text_buffer_get_selection_bounds (buffer,
2520                                                             NULL,
2521                                                             NULL);
2522
2523       if (has_selection != buffer->has_selection)
2524         {
2525           buffer->has_selection = has_selection;
2526           g_object_notify (G_OBJECT (buffer), "has-selection");
2527         }
2528     }
2529     
2530     if (mark == insert)
2531       g_object_notify (G_OBJECT (buffer), "cursor-position");
2532 }
2533
2534 static void
2535 gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,
2536                           GtkTextTag *tag,
2537                           gboolean apply,
2538                           const GtkTextIter *start,
2539                           const GtkTextIter *end)
2540 {
2541   GtkTextIter start_tmp = *start;
2542   GtkTextIter end_tmp = *end;
2543
2544   g_return_if_fail (tag != NULL);
2545
2546   gtk_text_iter_order (&start_tmp, &end_tmp);
2547
2548   if (apply)
2549     g_signal_emit (buffer, signals[APPLY_TAG],
2550                    0,
2551                    tag, &start_tmp, &end_tmp);
2552   else
2553     g_signal_emit (buffer, signals[REMOVE_TAG],
2554                    0,
2555                    tag, &start_tmp, &end_tmp);
2556 }
2557
2558
2559 /**
2560  * gtk_text_buffer_apply_tag:
2561  * @buffer: a #GtkTextBuffer
2562  * @tag: a #GtkTextTag
2563  * @start: one bound of range to be tagged
2564  * @end: other bound of range to be tagged
2565  *
2566  * Emits the "apply_tag" signal on @buffer. The default
2567  * handler for the signal applies @tag to the given range.
2568  * @start and @end do not have to be in order.
2569  * 
2570  **/
2571 void
2572 gtk_text_buffer_apply_tag (GtkTextBuffer *buffer,
2573                            GtkTextTag    *tag,
2574                            const GtkTextIter *start,
2575                            const GtkTextIter *end)
2576 {
2577   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2578   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2579   g_return_if_fail (start != NULL);
2580   g_return_if_fail (end != NULL);
2581   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2582   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2583   g_return_if_fail (tag->table == buffer->tag_table);
2584   
2585   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2586 }
2587
2588 /**
2589  * gtk_text_buffer_remove_tag:
2590  * @buffer: a #GtkTextBuffer
2591  * @tag: a #GtkTextTag
2592  * @start: one bound of range to be untagged
2593  * @end: other bound of range to be untagged
2594  *
2595  * Emits the "remove_tag" signal. The default handler for the signal
2596  * removes all occurrences of @tag from the given range. @start and
2597  * @end don't have to be in order.
2598  * 
2599  **/
2600 void
2601 gtk_text_buffer_remove_tag (GtkTextBuffer *buffer,
2602                             GtkTextTag    *tag,
2603                             const GtkTextIter *start,
2604                             const GtkTextIter *end)
2605
2606 {
2607   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2608   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2609   g_return_if_fail (start != NULL);
2610   g_return_if_fail (end != NULL);
2611   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2612   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2613   g_return_if_fail (tag->table == buffer->tag_table);
2614   
2615   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2616 }
2617
2618
2619 /**
2620  * gtk_text_buffer_apply_tag_by_name:
2621  * @buffer: a #GtkTextBuffer
2622  * @name: name of a named #GtkTextTag
2623  * @start: one bound of range to be tagged
2624  * @end: other bound of range to be tagged
2625  *
2626  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2627  * get a #GtkTextTag, then calls gtk_text_buffer_apply_tag().
2628  * 
2629  **/
2630 void
2631 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
2632                                    const gchar   *name,
2633                                    const GtkTextIter *start,
2634                                    const GtkTextIter *end)
2635 {
2636   GtkTextTag *tag;
2637
2638   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2639   g_return_if_fail (name != NULL);
2640   g_return_if_fail (start != NULL);
2641   g_return_if_fail (end != NULL);
2642   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2643   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2644
2645   tag = gtk_text_tag_table_lookup (get_table (buffer),
2646                                    name);
2647
2648   if (tag == NULL)
2649     {
2650       g_warning ("Unknown tag `%s'", name);
2651       return;
2652     }
2653
2654   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2655 }
2656
2657 /**
2658  * gtk_text_buffer_remove_tag_by_name:
2659  * @buffer: a #GtkTextBuffer
2660  * @name: name of a #GtkTextTag
2661  * @start: one bound of range to be untagged
2662  * @end: other bound of range to be untagged
2663  *
2664  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2665  * get a #GtkTextTag, then calls gtk_text_buffer_remove_tag().
2666  * 
2667  * 
2668  **/
2669 void
2670 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
2671                                     const gchar *name,
2672                                     const GtkTextIter *start,
2673                                     const GtkTextIter *end)
2674 {
2675   GtkTextTag *tag;
2676
2677   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2678   g_return_if_fail (name != NULL);
2679   g_return_if_fail (start != NULL);
2680   g_return_if_fail (end != NULL);
2681   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2682   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2683   
2684   tag = gtk_text_tag_table_lookup (get_table (buffer),
2685                                    name);
2686
2687   if (tag == NULL)
2688     {
2689       g_warning ("Unknown tag `%s'", name);
2690       return;
2691     }
2692
2693   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2694 }
2695
2696 static gint
2697 pointer_cmp (gconstpointer a,
2698              gconstpointer b)
2699 {
2700   if (a < b)
2701     return -1;
2702   else if (a > b)
2703     return 1;
2704   else
2705     return 0;
2706 }
2707
2708 /**
2709  * gtk_text_buffer_remove_all_tags:
2710  * @buffer: a #GtkTextBuffer
2711  * @start: one bound of range to be untagged
2712  * @end: other bound of range to be untagged
2713  * 
2714  * Removes all tags in the range between @start and @end.  Be careful
2715  * with this function; it could remove tags added in code unrelated to
2716  * the code you're currently writing. That is, using this function is
2717  * probably a bad idea if you have two or more unrelated code sections
2718  * that add tags.
2719  **/
2720 void
2721 gtk_text_buffer_remove_all_tags (GtkTextBuffer     *buffer,
2722                                  const GtkTextIter *start,
2723                                  const GtkTextIter *end)
2724 {
2725   GtkTextIter first, second, tmp;
2726   GSList *tags;
2727   GSList *tmp_list;
2728   GSList *prev, *next;
2729   GtkTextTag *tag;
2730   
2731   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2732   g_return_if_fail (start != NULL);
2733   g_return_if_fail (end != NULL);
2734   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2735   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2736   
2737   first = *start;
2738   second = *end;
2739
2740   gtk_text_iter_order (&first, &second);
2741
2742   /* Get all tags turned on at the start */
2743   tags = gtk_text_iter_get_tags (&first);
2744   
2745   /* Find any that are toggled on within the range */
2746   tmp = first;
2747   while (gtk_text_iter_forward_to_tag_toggle (&tmp, NULL))
2748     {
2749       GSList *toggled;
2750       GSList *tmp_list2;
2751
2752       if (gtk_text_iter_compare (&tmp, &second) >= 0)
2753         break; /* past the end of the range */
2754       
2755       toggled = gtk_text_iter_get_toggled_tags (&tmp, TRUE);
2756
2757       /* We could end up with a really big-ass list here.
2758        * Fix it someday.
2759        */
2760       tmp_list2 = toggled;
2761       while (tmp_list2 != NULL)
2762         {
2763           tags = g_slist_prepend (tags, tmp_list2->data);
2764
2765           tmp_list2 = g_slist_next (tmp_list2);
2766         }
2767
2768       g_slist_free (toggled);
2769     }
2770   
2771   /* Sort the list */
2772   tags = g_slist_sort (tags, pointer_cmp);
2773
2774   /* Strip duplicates */
2775   tag = NULL;
2776   prev = NULL;
2777   tmp_list = tags;
2778   while (tmp_list != NULL)
2779     {
2780       if (tag == tmp_list->data)
2781         {
2782           /* duplicate */
2783           next = tmp_list->next;
2784           if (prev)
2785             prev->next = next;
2786
2787           tmp_list->next = NULL;
2788
2789           g_slist_free (tmp_list);
2790
2791           tmp_list = next;
2792           /* prev is unchanged */
2793         }
2794       else
2795         {
2796           /* not a duplicate */
2797           tag = GTK_TEXT_TAG (tmp_list->data);
2798           prev = tmp_list;
2799           tmp_list = tmp_list->next;
2800         }
2801     }
2802
2803   g_slist_foreach (tags, (GFunc) g_object_ref, NULL);
2804   
2805   tmp_list = tags;
2806   while (tmp_list != NULL)
2807     {
2808       tag = GTK_TEXT_TAG (tmp_list->data);
2809
2810       gtk_text_buffer_remove_tag (buffer, tag, &first, &second);
2811       
2812       tmp_list = tmp_list->next;
2813     }
2814
2815   g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
2816   
2817   g_slist_free (tags);
2818 }
2819
2820
2821 /*
2822  * Obtain various iterators
2823  */
2824
2825 /**
2826  * gtk_text_buffer_get_iter_at_line_offset:
2827  * @buffer: a #GtkTextBuffer
2828  * @iter: iterator to initialize
2829  * @line_number: line number counting from 0
2830  * @char_offset: char offset from start of line
2831  *
2832  * Obtains an iterator pointing to @char_offset within the given
2833  * line. The @char_offset must exist, offsets off the end of the line
2834  * are not allowed. Note <emphasis>characters</emphasis>, not bytes;
2835  * UTF-8 may encode one character as multiple bytes.
2836  * 
2837  **/
2838 void
2839 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
2840                                          GtkTextIter        *iter,
2841                                          gint                line_number,
2842                                          gint                char_offset)
2843 {
2844   g_return_if_fail (iter != NULL);
2845   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2846
2847   _gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
2848                                          iter, line_number, char_offset);
2849 }
2850
2851 /**
2852  * gtk_text_buffer_get_iter_at_line_index:
2853  * @buffer: a #GtkTextBuffer 
2854  * @iter: iterator to initialize 
2855  * @line_number: line number counting from 0
2856  * @byte_index: byte index from start of line
2857  *
2858  * Obtains an iterator pointing to @byte_index within the given line.
2859  * @byte_index must be the start of a UTF-8 character, and must not be
2860  * beyond the end of the line.  Note <emphasis>bytes</emphasis>, not
2861  * characters; UTF-8 may encode one character as multiple bytes.
2862  * 
2863  **/
2864 void
2865 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
2866                                          GtkTextIter   *iter,
2867                                          gint           line_number,
2868                                          gint           byte_index)
2869 {
2870   g_return_if_fail (iter != NULL);
2871   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2872
2873   _gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
2874                                          iter, line_number, byte_index);
2875 }
2876
2877 /**
2878  * gtk_text_buffer_get_iter_at_line:
2879  * @buffer: a #GtkTextBuffer 
2880  * @iter: iterator to initialize
2881  * @line_number: line number counting from 0
2882  * 
2883  * Initializes @iter to the start of the given line.
2884  **/
2885 void
2886 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
2887                                      GtkTextIter        *iter,
2888                                      gint                line_number)
2889 {
2890   g_return_if_fail (iter != NULL);
2891   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2892
2893   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
2894 }
2895
2896 /**
2897  * gtk_text_buffer_get_iter_at_offset:
2898  * @buffer: a #GtkTextBuffer 
2899  * @iter: iterator to initialize
2900  * @char_offset: char offset from start of buffer, counting from 0, or -1
2901  *
2902  * Initializes @iter to a position @char_offset chars from the start
2903  * of the entire buffer. If @char_offset is -1 or greater than the number
2904  * of characters in the buffer, @iter is initialized to the end iterator,
2905  * the iterator one past the last valid character in the buffer.
2906  **/
2907 void
2908 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
2909                                             GtkTextIter        *iter,
2910                                             gint                char_offset)
2911 {
2912   g_return_if_fail (iter != NULL);
2913   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2914
2915   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
2916 }
2917
2918 /**
2919  * gtk_text_buffer_get_start_iter:
2920  * @buffer: a #GtkTextBuffer
2921  * @iter: iterator to initialize
2922  *
2923  * Initialized @iter with the first position in the text buffer. This
2924  * is the same as using gtk_text_buffer_get_iter_at_offset() to get
2925  * the iter at character offset 0.
2926  **/
2927 void
2928 gtk_text_buffer_get_start_iter (GtkTextBuffer *buffer,
2929                                 GtkTextIter   *iter)
2930 {
2931   g_return_if_fail (iter != NULL);
2932   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2933
2934   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, 0);
2935 }
2936
2937 /**
2938  * gtk_text_buffer_get_end_iter:
2939  * @buffer: a #GtkTextBuffer 
2940  * @iter: iterator to initialize
2941  *
2942  * Initializes @iter with the "end iterator," one past the last valid
2943  * character in the text buffer. If dereferenced with
2944  * gtk_text_iter_get_char(), the end iterator has a character value of
2945  * 0. The entire buffer lies in the range from the first position in
2946  * the buffer (call gtk_text_buffer_get_start_iter() to get
2947  * character position 0) to the end iterator.
2948  * 
2949  **/
2950 void
2951 gtk_text_buffer_get_end_iter         (GtkTextBuffer      *buffer,
2952                                        GtkTextIter        *iter)
2953 {
2954   g_return_if_fail (iter != NULL);
2955   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2956
2957   _gtk_text_btree_get_end_iter (get_btree (buffer), iter);
2958 }
2959
2960 /**
2961  * gtk_text_buffer_get_bounds:
2962  * @buffer: a #GtkTextBuffer 
2963  * @start: iterator to initialize with first position in the buffer
2964  * @end: iterator to initialize with the end iterator
2965  *
2966  * Retrieves the first and last iterators in the buffer, i.e. the
2967  * entire buffer lies within the range [@start,@end).
2968  * 
2969  **/
2970 void
2971 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
2972                             GtkTextIter   *start,
2973                             GtkTextIter   *end)
2974 {
2975   g_return_if_fail (start != NULL);
2976   g_return_if_fail (end != NULL);
2977   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2978
2979   _gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
2980   _gtk_text_btree_get_end_iter (get_btree (buffer), end);
2981 }
2982
2983 /*
2984  * Modified flag
2985  */
2986
2987 /**
2988  * gtk_text_buffer_get_modified:
2989  * @buffer: a #GtkTextBuffer 
2990  * 
2991  * Indicates whether the buffer has been modified since the last call
2992  * to gtk_text_buffer_set_modified() set the modification flag to
2993  * %FALSE. Used for example to enable a "save" function in a text
2994  * editor.
2995  * 
2996  * Return value: %TRUE if the buffer has been modified
2997  **/
2998 gboolean
2999 gtk_text_buffer_get_modified (GtkTextBuffer *buffer)
3000 {
3001   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3002
3003   return buffer->modified;
3004 }
3005
3006 /**
3007  * gtk_text_buffer_set_modified:
3008  * @buffer: a #GtkTextBuffer 
3009  * @setting: modification flag setting
3010  *
3011  * Used to keep track of whether the buffer has been modified since the
3012  * last time it was saved. Whenever the buffer is saved to disk, call
3013  * gtk_text_buffer_set_modified (@buffer, FALSE). When the buffer is modified,
3014  * it will automatically toggled on the modified bit again. When the modified
3015  * bit flips, the buffer emits a "modified_changed" signal.
3016  * 
3017  **/
3018 void
3019 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
3020                               gboolean             setting)
3021 {
3022   gboolean fixed_setting;
3023
3024   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3025
3026   fixed_setting = setting != FALSE;
3027
3028   if (buffer->modified == fixed_setting)
3029     return;
3030   else
3031     {
3032       buffer->modified = fixed_setting;
3033       g_signal_emit (buffer, signals[MODIFIED_CHANGED], 0);
3034     }
3035 }
3036
3037 /**
3038  * gtk_text_buffer_get_has_selection:
3039  * @buffer: a #GtkTextBuffer 
3040  * 
3041  * Indicates whether the buffer has some text currently selected.
3042  * 
3043  * Return value: %TRUE if the there is text selected
3044  *
3045  * Since: 2.10
3046  **/
3047 gboolean
3048 gtk_text_buffer_get_has_selection (GtkTextBuffer *buffer)
3049 {
3050   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3051
3052   return buffer->has_selection;
3053 }
3054
3055
3056 /*
3057  * Assorted other stuff
3058  */
3059
3060 /**
3061  * gtk_text_buffer_get_line_count:
3062  * @buffer: a #GtkTextBuffer 
3063  * 
3064  * Obtains the number of lines in the buffer. This value is cached, so
3065  * the function is very fast.
3066  * 
3067  * Return value: number of lines in the buffer
3068  **/
3069 gint
3070 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
3071 {
3072   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3073
3074   return _gtk_text_btree_line_count (get_btree (buffer));
3075 }
3076
3077 /**
3078  * gtk_text_buffer_get_char_count:
3079  * @buffer: a #GtkTextBuffer 
3080  * 
3081  * Gets the number of characters in the buffer; note that characters
3082  * and bytes are not the same, you can't e.g. expect the contents of
3083  * the buffer in string form to be this many bytes long. The character
3084  * count is cached, so this function is very fast.
3085  * 
3086  * Return value: number of characters in the buffer
3087  **/
3088 gint
3089 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
3090 {
3091   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3092
3093   return _gtk_text_btree_char_count (get_btree (buffer));
3094 }
3095
3096 /* Called when we lose the primary selection.
3097  */
3098 static void
3099 clipboard_clear_selection_cb (GtkClipboard *clipboard,
3100                               gpointer      data)
3101 {
3102   /* Move selection_bound to the insertion point */
3103   GtkTextIter insert;
3104   GtkTextIter selection_bound;
3105   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3106
3107   gtk_text_buffer_get_iter_at_mark (buffer, &insert,
3108                                     gtk_text_buffer_get_mark (buffer, "insert"));
3109   gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
3110                                     gtk_text_buffer_get_mark (buffer, "selection_bound"));
3111
3112   if (!gtk_text_iter_equal (&insert, &selection_bound))
3113     gtk_text_buffer_move_mark (buffer,
3114                                gtk_text_buffer_get_mark (buffer, "selection_bound"),
3115                                &insert);
3116 }
3117
3118 /* Called when we have the primary selection and someone else wants our
3119  * data in order to paste it.
3120  */
3121 static void
3122 clipboard_get_selection_cb (GtkClipboard     *clipboard,
3123                             GtkSelectionData *selection_data,
3124                             guint             info,
3125                             gpointer          data)
3126 {
3127   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3128   GtkTextIter start, end;
3129
3130   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3131     {
3132       if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3133         {
3134           /* Provide the address of the buffer; this will only be
3135            * used within-process
3136            */
3137           gtk_selection_data_set (selection_data,
3138                                   selection_data->target,
3139                                   8, /* bytes */
3140                                   (void*)&buffer,
3141                                   sizeof (buffer));
3142         }
3143       else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3144         {
3145           guint8 *str;
3146           gsize   len;
3147
3148           str = gtk_text_buffer_serialize (buffer, buffer,
3149                                            selection_data->target,
3150                                            &start, &end, &len);
3151
3152           gtk_selection_data_set (selection_data,
3153                                   selection_data->target,
3154                                   8, /* bytes */
3155                                   str, len);
3156           g_free (str);
3157         }
3158       else
3159         {
3160           gchar *str;
3161
3162           str = gtk_text_iter_get_visible_text (&start, &end);
3163           gtk_selection_data_set_text (selection_data, str, -1);
3164           g_free (str);
3165         }
3166     }
3167 }
3168
3169 static GtkTextBuffer *
3170 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
3171 {
3172   GtkTextBuffer *contents;
3173
3174   contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
3175
3176   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard-source"),
3177                      buffer);
3178   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
3179                      GINT_TO_POINTER (1));
3180
3181   /*  Ref the source buffer as long as the clipboard contents buffer
3182    *  exists, because it's needed for serializing the contents buffer.
3183    *  See http://bugzilla.gnome.org/show_bug.cgi?id=339195
3184    */
3185   g_object_ref (buffer);
3186   g_object_weak_ref (G_OBJECT (contents), (GWeakNotify) g_object_unref, buffer);
3187
3188   return contents;
3189 }
3190
3191 /* Provide cut/copied data */
3192 static void
3193 clipboard_get_contents_cb (GtkClipboard     *clipboard,
3194                            GtkSelectionData *selection_data,
3195                            guint             info,
3196                            gpointer          data)
3197 {
3198   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3199
3200   g_assert (contents); /* This should never be called unless we own the clipboard */
3201
3202   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3203     {
3204       /* Provide the address of the clipboard buffer; this will only
3205        * be used within-process. OK to supply a NULL value for contents.
3206        */
3207       gtk_selection_data_set (selection_data,
3208                               selection_data->target,
3209                               8, /* bytes */
3210                               (void*)&contents,
3211                               sizeof (contents));
3212     }
3213   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3214     {
3215       GtkTextBuffer *clipboard_source_buffer;
3216       GtkTextIter start, end;
3217       guint8 *str;
3218       gsize   len;
3219
3220       clipboard_source_buffer = g_object_get_data (G_OBJECT (contents),
3221                                                    "gtk-text-buffer-clipboard-source");
3222
3223       gtk_text_buffer_get_bounds (contents, &start, &end);
3224
3225       str = gtk_text_buffer_serialize (clipboard_source_buffer, contents,
3226                                        selection_data->target,
3227                                        &start, &end, &len);
3228
3229       gtk_selection_data_set (selection_data,
3230                               selection_data->target,
3231                               8, /* bytes */
3232                               str, len);
3233       g_free (str);
3234     }
3235   else
3236     {
3237       gchar *str;
3238       GtkTextIter start, end;
3239
3240       gtk_text_buffer_get_bounds (contents, &start, &end);
3241
3242       str = gtk_text_iter_get_visible_text (&start, &end);
3243       gtk_selection_data_set_text (selection_data, str, -1);
3244       g_free (str);
3245     }
3246 }
3247
3248 static void
3249 clipboard_clear_contents_cb (GtkClipboard *clipboard,
3250                              gpointer      data)
3251 {
3252   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3253
3254   g_object_unref (contents);
3255 }
3256
3257 static void
3258 get_paste_point (GtkTextBuffer *buffer,
3259                  GtkTextIter   *iter,
3260                  gboolean       clear_afterward)
3261 {
3262   GtkTextIter insert_point;
3263   GtkTextMark *paste_point_override;
3264
3265   paste_point_override = gtk_text_buffer_get_mark (buffer,
3266                                                    "gtk_paste_point_override");
3267
3268   if (paste_point_override != NULL)
3269     {
3270       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3271                                         paste_point_override);
3272       if (clear_afterward)
3273         gtk_text_buffer_delete_mark (buffer,
3274                                      gtk_text_buffer_get_mark (buffer,
3275                                                                "gtk_paste_point_override"));
3276     }
3277   else
3278     {
3279       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3280                                         gtk_text_buffer_get_mark (buffer,
3281                                                                   "insert"));
3282     }
3283
3284   *iter = insert_point;
3285 }
3286
3287 static void
3288 pre_paste_prep (ClipboardRequest *request_data,
3289                 GtkTextIter      *insert_point)
3290 {
3291   GtkTextBuffer *buffer = request_data->buffer;
3292   
3293   get_paste_point (buffer, insert_point, TRUE);
3294
3295   /* If we're going to replace the selection, we insert before it to
3296    * avoid messing it up, then we delete the selection after inserting.
3297    */
3298   if (request_data->replace_selection)
3299     {
3300       GtkTextIter start, end;
3301       
3302       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3303         *insert_point = start;
3304     }
3305 }
3306
3307 static void
3308 post_paste_cleanup (ClipboardRequest *request_data)
3309 {
3310   if (request_data->replace_selection)
3311     {
3312       GtkTextIter start, end;
3313       
3314       if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
3315                                                 &start, &end))
3316         {
3317           if (request_data->interactive)
3318             gtk_text_buffer_delete_interactive (request_data->buffer,
3319                                                 &start,
3320                                                 &end,
3321                                                 request_data->default_editable);
3322           else
3323             gtk_text_buffer_delete (request_data->buffer, &start, &end);
3324         }
3325     }
3326 }
3327
3328 static void
3329 free_clipboard_request (ClipboardRequest *request_data)
3330 {
3331   g_object_unref (request_data->buffer);
3332   g_free (request_data);
3333 }
3334
3335 /* Called when we request a paste and receive the text data
3336  */
3337 static void
3338 clipboard_text_received (GtkClipboard *clipboard,
3339                          const gchar  *str,
3340                          gpointer      data)
3341 {
3342   ClipboardRequest *request_data = data;
3343   GtkTextBuffer *buffer = request_data->buffer;
3344
3345   if (str)
3346     {
3347       GtkTextIter insert_point;
3348       
3349       if (request_data->interactive) 
3350         gtk_text_buffer_begin_user_action (buffer);
3351
3352       pre_paste_prep (request_data, &insert_point);
3353       
3354       if (request_data->interactive) 
3355         gtk_text_buffer_insert_interactive (buffer, &insert_point,
3356                                             str, -1, request_data->default_editable);
3357       else
3358         gtk_text_buffer_insert (buffer, &insert_point,
3359                                 str, -1);
3360
3361       post_paste_cleanup (request_data);
3362       
3363       if (request_data->interactive) 
3364         gtk_text_buffer_end_user_action (buffer);
3365     }
3366
3367   free_clipboard_request (request_data);
3368 }
3369
3370 static GtkTextBuffer*
3371 selection_data_get_buffer (GtkSelectionData *selection_data,
3372                            ClipboardRequest *request_data)
3373 {
3374   GdkWindow *owner;
3375   GtkTextBuffer *src_buffer = NULL;
3376
3377   /* If we can get the owner, the selection is in-process */
3378   owner = gdk_selection_owner_get_for_display (selection_data->display,
3379                                                selection_data->selection);
3380
3381   if (owner == NULL)
3382     return NULL;
3383   
3384   if (gdk_window_get_window_type (owner) == GDK_WINDOW_FOREIGN)
3385     return NULL;
3386  
3387   if (selection_data->type !=
3388       gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
3389     return NULL;
3390
3391   if (selection_data->length != sizeof (src_buffer))
3392     return NULL;
3393           
3394   memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
3395
3396   if (src_buffer == NULL)
3397     return NULL;
3398   
3399   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
3400
3401   if (gtk_text_buffer_get_tag_table (src_buffer) !=
3402       gtk_text_buffer_get_tag_table (request_data->buffer))
3403     return NULL;
3404   
3405   return src_buffer;
3406 }
3407
3408 #if 0
3409 /* These are pretty handy functions; maybe something like them
3410  * should be in the public API. Also, there are other places in this
3411  * file where they could be used.
3412  */
3413 static gpointer
3414 save_iter (const GtkTextIter *iter,
3415            gboolean           left_gravity)
3416 {
3417   return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
3418                                       NULL,
3419                                       iter,
3420                                       TRUE);
3421 }
3422
3423 static void
3424 restore_iter (const GtkTextIter *iter,
3425               gpointer           save_id)
3426 {
3427   gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
3428                                     (GtkTextIter*) iter,
3429                                     save_id);
3430   gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
3431                                save_id);
3432 }
3433 #endif
3434
3435 static void
3436 clipboard_rich_text_received (GtkClipboard *clipboard,
3437                               GdkAtom       format,
3438                               const guint8 *text,
3439                               gsize         length,
3440                               gpointer      data)
3441 {
3442   ClipboardRequest *request_data = data;
3443   GtkTextIter insert_point;
3444   gboolean retval = TRUE;
3445   GError *error = NULL;
3446
3447   if (text != NULL && length > 0)
3448     {
3449       pre_paste_prep (request_data, &insert_point);
3450
3451       if (request_data->interactive)
3452         gtk_text_buffer_begin_user_action (request_data->buffer);
3453
3454       if (!request_data->interactive ||
3455           gtk_text_iter_can_insert (&insert_point,
3456                                     request_data->default_editable))
3457         {
3458           retval = gtk_text_buffer_deserialize (request_data->buffer,
3459                                                 request_data->buffer,
3460                                                 format,
3461                                                 &insert_point,
3462                                                 text, length,
3463                                                 &error);
3464         }
3465
3466       if (!retval)
3467         {
3468           g_warning ("error pasting: %s\n", error->message);
3469           g_clear_error (&error);
3470         }
3471
3472       if (request_data->interactive)
3473         gtk_text_buffer_end_user_action (request_data->buffer);
3474
3475       if (retval)
3476         {
3477           post_paste_cleanup (request_data);
3478           return;
3479         }
3480     }
3481
3482   /* Request the text selection instead */
3483   gtk_clipboard_request_text (clipboard,
3484                               clipboard_text_received,
3485                               data);
3486 }
3487
3488 static void
3489 paste_from_buffer (ClipboardRequest    *request_data,
3490                    GtkTextBuffer       *src_buffer,
3491                    const GtkTextIter   *start,
3492                    const GtkTextIter   *end)
3493 {
3494   GtkTextIter insert_point;
3495   GtkTextBuffer *buffer = request_data->buffer;
3496   
3497   /* We're about to emit a bunch of signals, so be safe */
3498   g_object_ref (src_buffer);
3499   
3500   pre_paste_prep (request_data, &insert_point);
3501   
3502   if (request_data->interactive) 
3503     gtk_text_buffer_begin_user_action (buffer);
3504
3505   if (!gtk_text_iter_equal (start, end))
3506     {
3507       if (!request_data->interactive ||
3508           (gtk_text_iter_can_insert (&insert_point,
3509                                      request_data->default_editable)))
3510         gtk_text_buffer_real_insert_range (buffer,
3511                                            &insert_point,
3512                                            start,
3513                                            end,
3514                                            request_data->interactive);
3515     }
3516
3517   post_paste_cleanup (request_data);
3518       
3519   if (request_data->interactive) 
3520     gtk_text_buffer_end_user_action (buffer);
3521
3522   g_object_unref (src_buffer);
3523
3524   free_clipboard_request (request_data);
3525 }
3526
3527 static void
3528 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
3529                                      GtkSelectionData *selection_data,
3530                                      gpointer          data)
3531 {
3532   ClipboardRequest *request_data = data;
3533   GtkTextBuffer *src_buffer;
3534
3535   src_buffer = selection_data_get_buffer (selection_data, request_data); 
3536
3537   if (src_buffer)
3538     {
3539       GtkTextIter start, end;
3540
3541       if (g_object_get_data (G_OBJECT (src_buffer), "gtk-text-buffer-clipboard"))
3542         {
3543           gtk_text_buffer_get_bounds (src_buffer, &start, &end);
3544
3545           paste_from_buffer (request_data, src_buffer,
3546                              &start, &end);
3547         }
3548       else
3549         {
3550           if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
3551             paste_from_buffer (request_data, src_buffer,
3552                                &start, &end);
3553         }
3554     }
3555   else
3556     {
3557       if (gtk_clipboard_wait_is_rich_text_available (clipboard,
3558                                                      request_data->buffer))
3559         {
3560           /* Request rich text */
3561           gtk_clipboard_request_rich_text (clipboard,
3562                                            request_data->buffer,
3563                                            clipboard_rich_text_received,
3564                                            data);
3565         }
3566       else
3567         {
3568           /* Request the text selection instead */
3569           gtk_clipboard_request_text (clipboard,
3570                                       clipboard_text_received,
3571                                       data);
3572         }
3573     }
3574 }
3575
3576 typedef struct
3577 {
3578   GtkClipboard *clipboard;
3579   guint ref_count;
3580 } SelectionClipboard;
3581
3582 static void
3583 update_selection_clipboards (GtkTextBuffer *buffer)
3584 {
3585   GtkTextBufferPrivate *priv;
3586   GSList               *tmp_list = buffer->selection_clipboards;
3587
3588   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3589
3590   gtk_text_buffer_get_copy_target_list (buffer);
3591
3592   while (tmp_list)
3593     {
3594       GtkTextIter start;
3595       GtkTextIter end;
3596       
3597       SelectionClipboard *selection_clipboard = tmp_list->data;
3598       GtkClipboard *clipboard = selection_clipboard->clipboard;
3599
3600       /* Determine whether we have a selection and adjust X selection
3601        * accordingly.
3602        */
3603       if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3604         {
3605           if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
3606             gtk_clipboard_clear (clipboard);
3607         }
3608       else
3609         {
3610           /* Even if we already have the selection, we need to update our
3611            * timestamp.
3612            */
3613           if (!gtk_clipboard_set_with_owner (clipboard,
3614                                              priv->copy_target_entries,
3615                                              priv->n_copy_target_entries,
3616                                              clipboard_get_selection_cb,
3617                                              clipboard_clear_selection_cb,
3618                                              G_OBJECT (buffer)))
3619             clipboard_clear_selection_cb (clipboard, buffer);
3620         }
3621
3622       tmp_list = tmp_list->next;
3623     }
3624 }
3625
3626 static SelectionClipboard *
3627 find_selection_clipboard (GtkTextBuffer *buffer,
3628                           GtkClipboard  *clipboard)
3629 {
3630   GSList *tmp_list = buffer->selection_clipboards;
3631   while (tmp_list)
3632     {
3633       SelectionClipboard *selection_clipboard = tmp_list->data;
3634       if (selection_clipboard->clipboard == clipboard)
3635         return selection_clipboard;
3636       
3637       tmp_list = tmp_list->next;
3638     }
3639
3640   return NULL;
3641 }
3642
3643 /**
3644  * gtk_text_buffer_add_selection_clipboard:
3645  * @buffer: a #GtkTextBuffer
3646  * @clipboard: a #GtkClipboard
3647  * 
3648  * Adds @clipboard to the list of clipboards in which the selection contents
3649  * of @buffer are available. In most cases, @clipboard will be the #GtkClipboard
3650  * of type %GDK_SELECTION_PRIMARY for a view of @buffer.
3651  **/
3652 void
3653 gtk_text_buffer_add_selection_clipboard (GtkTextBuffer *buffer,
3654                                          GtkClipboard  *clipboard)
3655 {
3656   SelectionClipboard *selection_clipboard;
3657
3658   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3659   g_return_if_fail (clipboard != NULL);
3660
3661   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3662   if (selection_clipboard)
3663     {
3664       selection_clipboard->ref_count++;
3665     }
3666   else
3667     {
3668       selection_clipboard = g_new (SelectionClipboard, 1);
3669
3670       selection_clipboard->clipboard = clipboard;
3671       selection_clipboard->ref_count = 1;
3672
3673       buffer->selection_clipboards = g_slist_prepend (buffer->selection_clipboards, selection_clipboard);
3674     }
3675 }
3676
3677 /**
3678  * gtk_text_buffer_remove_selection_clipboard:
3679  * @buffer: a #GtkTextBuffer
3680  * @clipboard: a #GtkClipboard added to @buffer by gtk_text_buffer_add_selection_clipboard().
3681  * 
3682  * Removes a #GtkClipboard added with gtk_text_buffer_add_selection_clipboard()
3683  **/
3684 void 
3685 gtk_text_buffer_remove_selection_clipboard (GtkTextBuffer *buffer,
3686                                             GtkClipboard  *clipboard)
3687 {
3688   SelectionClipboard *selection_clipboard;
3689
3690   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3691   g_return_if_fail (clipboard != NULL);
3692
3693   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3694   g_return_if_fail (selection_clipboard != NULL);
3695
3696   selection_clipboard->ref_count--;
3697   if (selection_clipboard->ref_count == 0)
3698     {
3699       if (gtk_clipboard_get_owner (selection_clipboard->clipboard) == G_OBJECT (buffer))
3700         gtk_clipboard_clear (selection_clipboard->clipboard);
3701
3702       buffer->selection_clipboards = g_slist_remove (buffer->selection_clipboards,
3703                                                      selection_clipboard);
3704       
3705       g_free (selection_clipboard);
3706     }
3707 }
3708
3709 static void
3710 remove_all_selection_clipboards (GtkTextBuffer *buffer)
3711 {
3712   g_slist_foreach (buffer->selection_clipboards, (GFunc)g_free, NULL);
3713   g_slist_free (buffer->selection_clipboards);
3714   buffer->selection_clipboards = NULL;
3715 }
3716
3717 /**
3718  * gtk_text_buffer_paste_clipboard:
3719  * @buffer: a #GtkTextBuffer
3720  * @clipboard: the #GtkClipboard to paste from
3721  * @override_location: location to insert pasted text, or %NULL for at the cursor
3722  * @default_editable: whether the buffer is editable by default
3723  *
3724  * Pastes the contents of a clipboard at the insertion point, or at @override_location.
3725  * (Note: pasting is asynchronous, that is, we'll ask for the paste data and
3726  * return, and at some point later after the main loop runs, the paste
3727  * data will be inserted.)
3728  * 
3729  **/
3730 void
3731 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
3732                                  GtkClipboard  *clipboard,
3733                                  GtkTextIter   *override_location,
3734                                  gboolean       default_editable)
3735 {
3736   ClipboardRequest *data = g_new (ClipboardRequest, 1);
3737   GtkTextIter paste_point;
3738   GtkTextIter start, end;
3739
3740   if (override_location != NULL)
3741     gtk_text_buffer_create_mark (buffer,
3742                                  "gtk_paste_point_override",
3743                                  override_location, FALSE);
3744
3745   data->buffer = g_object_ref (buffer);
3746   data->interactive = TRUE;
3747   data->default_editable = default_editable;
3748
3749   /* When pasting with the cursor inside the selection area, you
3750    * replace the selection with the new text, otherwise, you
3751    * simply insert the new text at the point where the click
3752    * occured, unselecting any selected text. The replace_selection
3753    * flag toggles this behavior.
3754    */
3755   data->replace_selection = FALSE;
3756   
3757   get_paste_point (buffer, &paste_point, FALSE);
3758   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
3759       (gtk_text_iter_in_range (&paste_point, &start, &end) ||
3760        gtk_text_iter_equal (&paste_point, &end)))
3761     data->replace_selection = TRUE;
3762
3763   gtk_clipboard_request_contents (clipboard,
3764                                   gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
3765                                   clipboard_clipboard_buffer_received, data);
3766 }
3767
3768 /**
3769  * gtk_text_buffer_delete_selection:
3770  * @buffer: a #GtkTextBuffer 
3771  * @interactive: whether the deletion is caused by user interaction
3772  * @default_editable: whether the buffer is editable by default
3773  *
3774  * Deletes the range between the "insert" and "selection_bound" marks,
3775  * that is, the currently-selected text. If @interactive is %TRUE,
3776  * the editability of the selection will be considered (users can't delete
3777  * uneditable text).
3778  * 
3779  * Return value: whether there was a non-empty selection to delete
3780  **/
3781 gboolean
3782 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
3783                                   gboolean interactive,
3784                                   gboolean default_editable)
3785 {
3786   GtkTextIter start;
3787   GtkTextIter end;
3788
3789   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3790     {
3791       return FALSE; /* No selection */
3792     }
3793   else
3794     {
3795       if (interactive)
3796         {
3797           gtk_text_buffer_begin_user_action (buffer);
3798           gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
3799           gtk_text_buffer_end_user_action (buffer);
3800         }
3801       else
3802         gtk_text_buffer_delete (buffer, &start, &end);
3803
3804       return TRUE; /* We deleted stuff */
3805     }
3806 }
3807
3808 /**
3809  * gtk_text_buffer_backspace:
3810  * @buffer: a #GtkTextBuffer
3811  * @iter: a position in @buffer
3812  * @interactive: whether the deletion is caused by user interaction
3813  * @default_editable: whether the buffer is editable by default
3814  * 
3815  * Performs the appropriate action as if the user hit the delete
3816  * key with the cursor at the position specified by @iter. In the
3817  * normal case a single character will be deleted, but when
3818  * combining accents are involved, more than one character can
3819  * be deleted, and when precomposed character and accent combinations
3820  * are involved, less than one character will be deleted.
3821  * 
3822  * Because the buffer is modified, all outstanding iterators become 
3823  * invalid after calling this function; however, the @iter will be
3824  * re-initialized to point to the location where text was deleted. 
3825  *
3826  * Return value: %TRUE if the buffer was modified
3827
3828  * Since: 2.6
3829  **/
3830 gboolean
3831 gtk_text_buffer_backspace (GtkTextBuffer *buffer,
3832                            GtkTextIter   *iter,
3833                            gboolean       interactive,
3834                            gboolean       default_editable)
3835 {
3836   gchar *cluster_text;
3837   GtkTextIter start;
3838   GtkTextIter end;
3839   gboolean retval = FALSE;
3840   const PangoLogAttr *attrs;
3841   int offset;
3842   gboolean backspace_deletes_character;
3843
3844   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3845   g_return_val_if_fail (iter != NULL, FALSE);
3846
3847   start = *iter;
3848   end = *iter;
3849
3850   attrs = _gtk_text_buffer_get_line_log_attrs (buffer, &start, NULL);
3851
3852   /* For no good reason, attrs is NULL for the empty last line in
3853    * a buffer. Special case that here. (#156164)
3854    */
3855   if (attrs)
3856     {
3857       offset = gtk_text_iter_get_line_offset (&start);
3858       backspace_deletes_character = attrs[offset].backspace_deletes_character;
3859     }
3860   else
3861     backspace_deletes_character = FALSE;
3862
3863   gtk_text_iter_backward_cursor_position (&start);
3864
3865   if (gtk_text_iter_equal (&start, &end))
3866     return FALSE;
3867     
3868   cluster_text = gtk_text_iter_get_text (&start, &end);
3869
3870   if (interactive)
3871     gtk_text_buffer_begin_user_action (buffer);
3872   
3873   if (gtk_text_buffer_delete_interactive (buffer, &start, &end,
3874                                           default_editable))
3875     {
3876       if (backspace_deletes_character)
3877         {
3878           gchar *normalized_text = g_utf8_normalize (cluster_text,
3879                                                      strlen (cluster_text),
3880                                                      G_NORMALIZE_NFD);
3881           glong len = g_utf8_strlen (normalized_text, -1);
3882           
3883           if (len > 1)
3884             gtk_text_buffer_insert_interactive (buffer,
3885                                                 &start,
3886                                                 normalized_text,
3887                                                 g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
3888                                                 default_editable);
3889           
3890           g_free (normalized_text);
3891         }
3892
3893       retval = TRUE;
3894     }
3895   
3896   if (interactive)
3897     gtk_text_buffer_end_user_action (buffer);
3898   
3899   g_free (cluster_text);
3900
3901   /* Revalidate the users iter */
3902   *iter = start;
3903
3904   return retval;
3905 }
3906
3907 static void
3908 cut_or_copy (GtkTextBuffer *buffer,
3909              GtkClipboard  *clipboard,
3910              gboolean       delete_region_after,
3911              gboolean       interactive,
3912              gboolean       default_editable)
3913 {
3914   GtkTextBufferPrivate *priv;
3915
3916   /* We prefer to cut the selected region between selection_bound and
3917    * insertion point. If that region is empty, then we cut the region
3918    * between the "anchor" and the insertion point (this is for
3919    * C-space and M-w and other Emacs-style copy/yank keys). Note that
3920    * insert and selection_bound are guaranteed to exist, but the
3921    * anchor only exists sometimes.
3922    */
3923   GtkTextIter start;
3924   GtkTextIter end;
3925
3926   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3927
3928   gtk_text_buffer_get_copy_target_list (buffer);
3929
3930   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3931     {
3932       /* Let's try the anchor thing */
3933       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
3934
3935       if (anchor == NULL)
3936         return;
3937       else
3938         {
3939           gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
3940           gtk_text_iter_order (&start, &end);
3941         }
3942     }
3943
3944   if (!gtk_text_iter_equal (&start, &end))
3945     {
3946       GtkTextIter ins;
3947       GtkTextBuffer *contents;
3948
3949       contents = create_clipboard_contents_buffer (buffer);
3950
3951       gtk_text_buffer_get_iter_at_offset (contents, &ins, 0);
3952       
3953       gtk_text_buffer_insert_range (contents, &ins, &start, &end);
3954                                     
3955       if (!gtk_clipboard_set_with_data (clipboard,
3956                                         priv->copy_target_entries,
3957                                         priv->n_copy_target_entries,
3958                                         clipboard_get_contents_cb,
3959                                         clipboard_clear_contents_cb,
3960                                         contents))
3961         g_object_unref (contents);
3962       else
3963         gtk_clipboard_set_can_store (clipboard,
3964                                      priv->copy_target_entries + 1,
3965                                      priv->n_copy_target_entries - 1);
3966
3967       if (delete_region_after)
3968         {
3969           if (interactive)
3970             gtk_text_buffer_delete_interactive (buffer, &start, &end,
3971                                                 default_editable);
3972           else
3973             gtk_text_buffer_delete (buffer, &start, &end);
3974         }
3975     }
3976 }
3977
3978 /**
3979  * gtk_text_buffer_cut_clipboard:
3980  * @buffer: a #GtkTextBuffer
3981  * @clipboard: the #GtkClipboard object to cut to.
3982  * @default_editable: default editability of the buffer
3983  *
3984  * Copies the currently-selected text to a clipboard, then deletes
3985  * said text if it's editable.
3986  * 
3987  **/
3988 void
3989 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
3990                                GtkClipboard  *clipboard,
3991                                gboolean       default_editable)
3992 {
3993   gtk_text_buffer_begin_user_action (buffer);
3994   cut_or_copy (buffer, clipboard, TRUE, TRUE, default_editable);
3995   gtk_text_buffer_end_user_action (buffer);
3996 }
3997
3998 /**
3999  * gtk_text_buffer_copy_clipboard:
4000  * @buffer: a #GtkTextBuffer 
4001  * @clipboard: the #GtkClipboard object to copy to.
4002  *
4003  * Copies the currently-selected text to a clipboard.
4004  * 
4005  **/
4006 void
4007 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer,
4008                                 GtkClipboard  *clipboard)
4009 {
4010   gtk_text_buffer_begin_user_action (buffer);
4011   cut_or_copy (buffer, clipboard, FALSE, TRUE, TRUE);
4012   gtk_text_buffer_end_user_action (buffer);
4013 }
4014
4015
4016 /**
4017  * gtk_text_buffer_get_selection_bounds:
4018  * @buffer: a #GtkTextBuffer a #GtkTextBuffer
4019  * @start: iterator to initialize with selection start
4020  * @end: iterator to initialize with selection end
4021  *
4022  * Returns %TRUE if some text is selected; places the bounds
4023  * of the selection in @start and @end (if the selection has length 0,
4024  * then @start and @end are filled in with the same value).
4025  * @start and @end will be in ascending order. If @start and @end are
4026  * NULL, then they are not filled in, but the return value still indicates
4027  * whether text is selected.
4028  *
4029  * Return value: whether the selection has nonzero length
4030  **/
4031 gboolean
4032 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
4033                                         GtkTextIter        *start,
4034                                         GtkTextIter        *end)
4035 {
4036   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
4037
4038   return _gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
4039 }
4040
4041 /**
4042  * gtk_text_buffer_begin_user_action:
4043  * @buffer: a #GtkTextBuffer
4044  * 
4045  * Called to indicate that the buffer operations between here and a
4046  * call to gtk_text_buffer_end_user_action() are part of a single
4047  * user-visible operation. The operations between
4048  * gtk_text_buffer_begin_user_action() and
4049  * gtk_text_buffer_end_user_action() can then be grouped when creating
4050  * an undo stack. #GtkTextBuffer maintains a count of calls to
4051  * gtk_text_buffer_begin_user_action() that have not been closed with
4052  * a call to gtk_text_buffer_end_user_action(), and emits the "begin_user_action"
4053  * and "end_user_action" signals only for the outermost pair of calls.
4054  * This allows you to build user actions from other user actions.
4055  *
4056  * The "interactive" buffer mutation functions, such as
4057  * gtk_text_buffer_insert_interactive(), automatically call begin/end
4058  * user action around the buffer operations they perform, so there's
4059  * no need to add extra calls if you user action consists solely of a
4060  * single call to one of those functions.
4061  **/
4062 void
4063 gtk_text_buffer_begin_user_action (GtkTextBuffer *buffer)
4064 {
4065   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4066
4067   buffer->user_action_count += 1;
4068   
4069   if (buffer->user_action_count == 1)
4070     {
4071       /* Outermost nested user action begin emits the signal */
4072       g_signal_emit (buffer, signals[BEGIN_USER_ACTION], 0);
4073     }
4074 }
4075
4076 /**
4077  * gtk_text_buffer_end_user_action:
4078  * @buffer: a #GtkTextBuffer
4079  * 
4080  * Should be paired with a call to gtk_text_buffer_begin_user_action().
4081  * See that function for a full explanation.
4082  **/
4083 void
4084 gtk_text_buffer_end_user_action (GtkTextBuffer *buffer)
4085 {
4086   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4087   g_return_if_fail (buffer->user_action_count > 0);
4088   
4089   buffer->user_action_count -= 1;
4090   
4091   if (buffer->user_action_count == 0)
4092     {
4093       /* Ended the outermost-nested user action end, so emit the signal */
4094       g_signal_emit (buffer, signals[END_USER_ACTION], 0);
4095     }
4096 }
4097
4098 static void
4099 gtk_text_buffer_free_target_lists (GtkTextBuffer *buffer)
4100 {
4101   GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4102
4103   if (priv->copy_target_list)
4104     {
4105       gtk_target_list_unref (priv->copy_target_list);
4106       priv->copy_target_list = NULL;
4107
4108       gtk_target_table_free (priv->copy_target_entries,
4109                              priv->n_copy_target_entries);
4110       priv->copy_target_entries = NULL;
4111       priv->n_copy_target_entries = 0;
4112     }
4113
4114   if (priv->paste_target_list)
4115     {
4116       gtk_target_list_unref (priv->paste_target_list);
4117       priv->paste_target_list = NULL;
4118
4119       gtk_target_table_free (priv->paste_target_entries,
4120                              priv->n_paste_target_entries);
4121       priv->paste_target_entries = NULL;
4122       priv->n_paste_target_entries = 0;
4123     }
4124 }
4125
4126 static GtkTargetList *
4127 gtk_text_buffer_get_target_list (GtkTextBuffer   *buffer,
4128                                  gboolean         deserializable,
4129                                  GtkTargetEntry **entries,
4130                                  gint            *n_entries)
4131 {
4132   GtkTargetList *target_list;
4133
4134   target_list = gtk_target_list_new (NULL, 0);
4135
4136   gtk_target_list_add (target_list,
4137                        gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
4138                        GTK_TARGET_SAME_APP,
4139                        GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS);
4140
4141   gtk_target_list_add_rich_text_targets (target_list,
4142                                          GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
4143                                          deserializable,
4144                                          buffer);
4145
4146   gtk_target_list_add_text_targets (target_list,
4147                                     GTK_TEXT_BUFFER_TARGET_INFO_TEXT);
4148
4149   *entries = gtk_target_table_new_from_list (target_list, n_entries);
4150
4151   return target_list;
4152 }
4153
4154 /**
4155  * gtk_text_buffer_get_copy_target_list:
4156  * @buffer: a #GtkTextBuffer
4157  *
4158  * This function returns the list of targets this text buffer can
4159  * provide for copying and as DND source. The targets in the list are
4160  * added with %info values from the #GtkTextBufferTargetInfo enum,
4161  * using gtk_target_list_add_rich_text_targets() and
4162  * gtk_target_list_add_text_targets()
4163  *
4164  * Return value: the #GtkTargetList
4165  *
4166  * Since: 2.10
4167  **/
4168 GtkTargetList *
4169 gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer)
4170 {
4171   GtkTextBufferPrivate *priv;
4172
4173   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4174
4175   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4176
4177   if (! priv->copy_target_list)
4178     priv->copy_target_list =
4179       gtk_text_buffer_get_target_list (buffer, FALSE,
4180                                        &priv->copy_target_entries,
4181                                        &priv->n_copy_target_entries);
4182
4183   return priv->copy_target_list;
4184 }
4185
4186 /**
4187  * gtk_text_buffer_get_paste_target_list:
4188  * @buffer: a #GtkTextBuffer
4189  *
4190  * This function returns the list of targets this text buffer supports
4191  * for pasting and as DND destination. The targets in the list are
4192  * added with %info values from the #GtkTextBufferTargetInfo enum,
4193  * using gtk_target_list_add_rich_text_targets() and
4194  * gtk_target_list_add_text_targets()
4195  *
4196  * Return value: the #GtkTargetList
4197  *
4198  * Since: 2.10
4199  **/
4200 GtkTargetList *
4201 gtk_text_buffer_get_paste_target_list (GtkTextBuffer *buffer)
4202 {
4203   GtkTextBufferPrivate *priv;
4204
4205   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4206
4207   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4208
4209   if (! priv->paste_target_list)
4210     priv->paste_target_list =
4211       gtk_text_buffer_get_target_list (buffer, TRUE,
4212                                        &priv->paste_target_entries,
4213                                        &priv->n_paste_target_entries);
4214
4215   return priv->paste_target_list;
4216 }
4217
4218 /*
4219  * Logical attribute cache
4220  */
4221
4222 #define ATTR_CACHE_SIZE 2
4223
4224 typedef struct _CacheEntry CacheEntry;
4225 struct _CacheEntry
4226 {
4227   gint line;
4228   gint char_len;
4229   PangoLogAttr *attrs;
4230 };
4231
4232
4233 struct _GtkTextLogAttrCache
4234 {
4235   gint chars_changed_stamp;
4236   CacheEntry entries[ATTR_CACHE_SIZE];
4237 };
4238
4239 static void
4240 free_log_attr_cache (GtkTextLogAttrCache *cache)
4241 {
4242   gint i = 0;
4243   while (i < ATTR_CACHE_SIZE)
4244     {
4245       g_free (cache->entries[i].attrs);
4246       ++i;
4247     }
4248   g_free (cache);
4249 }
4250
4251 static void
4252 clear_log_attr_cache (GtkTextLogAttrCache *cache)
4253 {
4254   gint i = 0;
4255   while (i < ATTR_CACHE_SIZE)
4256     {
4257       g_free (cache->entries[i].attrs);
4258       cache->entries[i].attrs = NULL;
4259       ++i;
4260     }
4261 }
4262
4263 static PangoLogAttr*
4264 compute_log_attrs (const GtkTextIter *iter,
4265                    gint              *char_lenp)
4266 {
4267   GtkTextIter start;
4268   GtkTextIter end;
4269   gchar *paragraph;
4270   gint char_len, byte_len;
4271   PangoLogAttr *attrs = NULL;
4272   
4273   start = *iter;
4274   end = *iter;
4275
4276   gtk_text_iter_set_line_offset (&start, 0);
4277   gtk_text_iter_forward_line (&end);
4278
4279   paragraph = gtk_text_iter_get_slice (&start, &end);
4280   char_len = g_utf8_strlen (paragraph, -1);
4281   byte_len = strlen (paragraph);
4282
4283   g_assert (char_len > 0);
4284
4285   if (char_lenp)
4286     *char_lenp = char_len;
4287   
4288   attrs = g_new (PangoLogAttr, char_len + 1);
4289
4290   /* FIXME we need to follow PangoLayout and allow different language
4291    * tags within the paragraph
4292    */
4293   pango_get_log_attrs (paragraph, byte_len, -1,
4294                        gtk_text_iter_get_language (&start),
4295                        attrs,
4296                        char_len + 1);
4297   
4298   g_free (paragraph);
4299
4300   return attrs;
4301 }
4302
4303 /* The return value from this is valid until you call this a second time.
4304  */
4305 const PangoLogAttr*
4306 _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer     *buffer,
4307                                      const GtkTextIter *anywhere_in_line,
4308                                      gint              *char_len)
4309 {
4310   gint line;
4311   GtkTextLogAttrCache *cache;
4312   gint i;
4313   
4314   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4315   g_return_val_if_fail (anywhere_in_line != NULL, NULL);
4316
4317   /* special-case for empty last line in buffer */
4318   if (gtk_text_iter_is_end (anywhere_in_line) &&
4319       gtk_text_iter_get_line_offset (anywhere_in_line) == 0)
4320     {
4321       if (char_len)
4322         *char_len = 0;
4323       return NULL;
4324     }
4325   
4326   /* FIXME we also need to recompute log attrs if the language tag at
4327    * the start of a paragraph changes
4328    */
4329   
4330   if (buffer->log_attr_cache == NULL)
4331     {
4332       buffer->log_attr_cache = g_new0 (GtkTextLogAttrCache, 1);
4333       buffer->log_attr_cache->chars_changed_stamp =
4334         _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer));
4335     }
4336   else if (buffer->log_attr_cache->chars_changed_stamp !=
4337            _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer)))
4338     {
4339       clear_log_attr_cache (buffer->log_attr_cache);
4340     }
4341   
4342   cache = buffer->log_attr_cache;
4343   line = gtk_text_iter_get_line (anywhere_in_line);
4344
4345   i = 0;
4346   while (i < ATTR_CACHE_SIZE)
4347     {
4348       if (cache->entries[i].attrs &&
4349           cache->entries[i].line == line)
4350         {
4351           if (char_len)
4352             *char_len = cache->entries[i].char_len;
4353           return cache->entries[i].attrs;
4354         }
4355       ++i;
4356     }
4357   
4358   /* Not in cache; open up the first cache entry */
4359   g_free (cache->entries[ATTR_CACHE_SIZE-1].attrs);
4360   
4361   g_memmove (cache->entries + 1, cache->entries,
4362              sizeof (CacheEntry) * (ATTR_CACHE_SIZE - 1));
4363
4364   cache->entries[0].line = line;
4365   cache->entries[0].attrs = compute_log_attrs (anywhere_in_line,
4366                                                &cache->entries[0].char_len);
4367
4368   if (char_len)
4369     *char_len = cache->entries[0].char_len;
4370   
4371   return cache->entries[0].attrs;
4372 }
4373
4374 void
4375 _gtk_text_buffer_notify_will_remove_tag (GtkTextBuffer *buffer,
4376                                          GtkTextTag    *tag)
4377 {
4378   /* This removes tag from the buffer, but DOESN'T emit the
4379    * remove_tag signal, because we can't afford to have user
4380    * code messing things up at this point; the tag MUST be removed
4381    * entirely.
4382    */
4383   if (buffer->btree)
4384     _gtk_text_btree_notify_will_remove_tag (buffer->btree, tag);
4385 }
4386
4387 /*
4388  * Debug spew
4389  */
4390
4391 void
4392 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
4393 {
4394   _gtk_text_btree_spew (get_btree (buffer));
4395 }
4396
4397 #define __GTK_TEXT_BUFFER_C__
4398 #include "gtkaliasdef.c"