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