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