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