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