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