]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
Handle chopping off \r\n and 0x2029 in addition to \n before passing to
[~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 <string.h>
29
30 #include "gtkclipboard.h"
31 #include "gtkinvisible.h"
32 #include "gtksignal.h"
33 #include "gtktextbuffer.h"
34 #include "gtktextbtree.h"
35 #include "gtktextiterprivate.h"
36 #include <string.h>
37
38 typedef struct _ClipboardRequest ClipboardRequest;
39
40 struct _ClipboardRequest
41 {
42   GtkTextBuffer *buffer;
43   gboolean interactive;
44   gboolean default_editable;
45   gboolean is_clipboard;
46   gboolean replace_selection;
47 };
48
49 enum {
50   INSERT_TEXT,
51   DELETE_TEXT,
52   CHANGED,
53   MODIFIED_CHANGED,
54   MARK_SET,
55   MARK_DELETED,
56   APPLY_TAG,
57   REMOVE_TAG,
58   LAST_SIGNAL
59 };
60
61 enum {
62   ARG_0,
63   LAST_ARG
64 };
65
66 enum {
67   TARGET_STRING,
68   TARGET_TEXT,
69   TARGET_COMPOUND_TEXT,
70   TARGET_UTF8_STRING,
71   TARGET_TEXT_BUFFER_CONTENTS
72 };
73
74 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
75 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
76 static void gtk_text_buffer_finalize   (GObject            *object);
77
78
79 static void gtk_text_buffer_update_primary_selection   (GtkTextBuffer     *buffer);
80 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
81                                                         GtkTextIter       *iter,
82                                                         const gchar       *text,
83                                                         gint               len,
84                                                         gboolean           interactive);
85 static void gtk_text_buffer_real_delete_text           (GtkTextBuffer     *buffer,
86                                                         GtkTextIter       *start,
87                                                         GtkTextIter       *end,
88                                                         gboolean           interactive);
89 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
90                                                         GtkTextTag        *tag,
91                                                         const GtkTextIter *start_char,
92                                                         const GtkTextIter *end_char);
93 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
94                                                         GtkTextTag        *tag,
95                                                         const GtkTextIter *start_char,
96                                                         const GtkTextIter *end_char);
97 static void gtk_text_buffer_real_changed               (GtkTextBuffer     *buffer);
98
99 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
100 static void          free_log_attr_cache (GtkTextLogAttrCache *cache);
101
102 static GtkObjectClass *parent_class = NULL;
103 static guint signals[LAST_SIGNAL] = { 0 };
104
105 GtkType
106 gtk_text_buffer_get_type (void)
107 {
108   static GtkType our_type = 0;
109
110   if (our_type == 0)
111     {
112       static const GtkTypeInfo our_info =
113       {
114         "GtkTextBuffer",
115         sizeof (GtkTextBuffer),
116         sizeof (GtkTextBufferClass),
117         (GtkClassInitFunc) gtk_text_buffer_class_init,
118         (GtkObjectInitFunc) gtk_text_buffer_init,
119         /* reserved_1 */ NULL,
120         /* reserved_2 */ NULL,
121         (GtkClassInitFunc) NULL
122       };
123
124       our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
125     }
126
127   return our_type;
128 }
129
130 static void
131 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
132 {
133   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
134   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
135
136   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
137
138   signals[INSERT_TEXT] =
139     gtk_signal_new ("insert_text",
140                     GTK_RUN_LAST,
141                     GTK_CLASS_TYPE (object_class),
142                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
143                     gtk_marshal_VOID__BOXED_BOXED_INT_BOOLEAN,
144                     GTK_TYPE_NONE,
145                     4,
146                     GTK_TYPE_TEXT_ITER,
147                     GTK_TYPE_TEXT_ITER,
148                     GTK_TYPE_INT,
149                     GTK_TYPE_BOOL);
150
151   signals[DELETE_TEXT] =
152     gtk_signal_new ("delete_text",
153                     GTK_RUN_LAST,
154                     GTK_CLASS_TYPE (object_class),
155                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
156                     gtk_marshal_VOID__BOXED_BOXED_BOOLEAN,
157                     GTK_TYPE_NONE,
158                     3,
159                     GTK_TYPE_TEXT_ITER,
160                     GTK_TYPE_TEXT_ITER,
161                     GTK_TYPE_BOOL);
162
163   signals[CHANGED] =
164     gtk_signal_new ("changed",
165                     GTK_RUN_LAST,
166                     GTK_CLASS_TYPE (object_class),
167                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
168                     gtk_marshal_VOID__VOID,
169                     GTK_TYPE_NONE,
170                     0);
171
172   signals[MODIFIED_CHANGED] =
173     gtk_signal_new ("modified_changed",
174                     GTK_RUN_LAST,
175                     GTK_CLASS_TYPE (object_class),
176                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
177                     gtk_marshal_VOID__VOID,
178                     GTK_TYPE_NONE,
179                     0);
180
181   signals[MARK_SET] =
182     gtk_signal_new ("mark_set",
183                     GTK_RUN_LAST,
184                     GTK_CLASS_TYPE (object_class),
185                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
186                     gtk_marshal_VOID__BOXED_OBJECT,
187                     GTK_TYPE_NONE,
188                     2,
189                     GTK_TYPE_TEXT_ITER,
190                     G_TYPE_OBJECT);
191
192   signals[MARK_DELETED] =
193     gtk_signal_new ("mark_deleted",
194                     GTK_RUN_LAST,
195                     GTK_CLASS_TYPE (object_class),
196                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
197                     gtk_marshal_VOID__OBJECT,
198                     GTK_TYPE_NONE,
199                     1,
200                     G_TYPE_OBJECT);
201
202   signals[APPLY_TAG] =
203     gtk_signal_new ("apply_tag",
204                     GTK_RUN_LAST,
205                     GTK_CLASS_TYPE (object_class),
206                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
207                     gtk_marshal_VOID__OBJECT_BOXED_BOXED,
208                     GTK_TYPE_NONE,
209                     3,
210                     G_TYPE_OBJECT,
211                     GTK_TYPE_TEXT_ITER,
212                     GTK_TYPE_TEXT_ITER);
213
214   signals[REMOVE_TAG] =
215     gtk_signal_new ("remove_tag",
216                     GTK_RUN_LAST,
217                     GTK_CLASS_TYPE (object_class),
218                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
219                     gtk_marshal_VOID__OBJECT_BOXED_BOXED,
220                     GTK_TYPE_NONE,
221                     3,
222                     G_TYPE_OBJECT,
223                     GTK_TYPE_TEXT_ITER,
224                     GTK_TYPE_TEXT_ITER);
225
226   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
227
228   gobject_class->finalize = gtk_text_buffer_finalize;
229
230   klass->insert_text = gtk_text_buffer_real_insert_text;
231   klass->delete_text = gtk_text_buffer_real_delete_text;
232   klass->apply_tag = gtk_text_buffer_real_apply_tag;
233   klass->remove_tag = gtk_text_buffer_real_remove_tag;
234   klass->changed = gtk_text_buffer_real_changed;
235 }
236
237 void
238 gtk_text_buffer_init (GtkTextBuffer *buffer)
239 {
240   buffer->clipboard_contents = NULL;
241 }
242
243 /**
244  * gtk_text_buffer_new:
245  * @table: a tag table, or NULL to create a new one
246  *
247  * Creates a new text buffer.
248  *
249  * Return value: a new text buffer
250  **/
251 GtkTextBuffer*
252 gtk_text_buffer_new (GtkTextTagTable *table)
253 {
254   GtkTextBuffer *text_buffer;
255
256   text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
257
258   if (table)
259     {
260       text_buffer->tag_table = table;
261
262       gtk_object_ref (GTK_OBJECT (text_buffer->tag_table));
263       gtk_object_sink (GTK_OBJECT (text_buffer->tag_table));
264     }
265
266   gtk_object_ref (GTK_OBJECT (text_buffer));
267   gtk_object_sink (GTK_OBJECT (text_buffer));
268   
269   return text_buffer;
270 }
271
272 static void
273 gtk_text_buffer_finalize (GObject *object)
274 {
275   GtkTextBuffer *buffer;
276
277   buffer = GTK_TEXT_BUFFER (object);
278
279   if (buffer->clipboard_contents)
280     {
281       g_object_unref (G_OBJECT (buffer->clipboard_contents));
282       buffer->clipboard_contents = NULL;
283     }
284   
285   if (buffer->tag_table)
286     {
287       gtk_object_unref (GTK_OBJECT (buffer->tag_table));
288       buffer->tag_table = NULL;
289     }
290
291   if (buffer->btree)
292     {
293       gtk_text_btree_unref (buffer->btree);
294       buffer->btree = NULL;
295     }
296
297   if (buffer->log_attr_cache)
298     free_log_attr_cache (buffer->log_attr_cache);
299
300   buffer->log_attr_cache = NULL;
301   
302   G_OBJECT_CLASS (parent_class)->finalize (object);
303 }
304
305 static GtkTextTagTable*
306 get_table (GtkTextBuffer *buffer)
307 {
308   if (buffer->tag_table == NULL)
309     {
310       buffer->tag_table = gtk_text_tag_table_new ();
311
312       gtk_object_ref (GTK_OBJECT (buffer->tag_table));
313       gtk_object_sink (GTK_OBJECT (buffer->tag_table));
314     }
315
316   return buffer->tag_table;
317 }
318
319 static GtkTextBTree*
320 get_btree (GtkTextBuffer *buffer)
321 {
322   if (buffer->btree == NULL)
323     buffer->btree = gtk_text_btree_new (gtk_text_buffer_get_tag_table (buffer),
324                                         buffer);
325
326   return buffer->btree;
327 }
328
329 GtkTextBTree*
330 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
331 {
332   return get_btree (buffer);
333 }
334
335 /**
336  * gtk_text_buffer_get_tag_table:
337  * @buffer: a #GtkTextBuffer
338  *
339  * Get the #GtkTextTagTable associated with this buffer.
340  *
341  * Return value: the buffer's tag table
342  **/
343 GtkTextTagTable*
344 gtk_text_buffer_get_tag_table (GtkTextBuffer  *buffer)
345 {
346   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
347
348   return get_table (buffer);
349 }
350
351 /**
352  * gtk_text_buffer_set_text:
353  * @buffer: a #GtkTextBuffer
354  * @text: UTF-8 text to insert
355  * @len: length of @text in bytes
356  *
357  * Deletes current contents of @buffer, and inserts @text instead.  If
358  * @text doesn't end with a newline, a newline is added;
359  * #GtkTextBuffer contents must always end with a newline. If @text
360  * ends with a newline, the new buffer contents will be exactly
361  * @text. If @len is -1, @text must be nul-terminated.
362  **/
363 void
364 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
365                           const gchar   *text,
366                           gint           len)
367 {
368   GtkTextIter start, end;
369
370   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
371   g_return_if_fail (text != NULL);
372
373   if (len < 0)
374     len = strlen (text);
375
376   /* Chop newline, since the buffer will already have one
377    * in it.
378    */
379   if (len > 0 && text[len-1] == '\n')
380     len -= 1;
381
382   gtk_text_buffer_get_bounds (buffer, &start, &end);
383
384   gtk_text_buffer_delete (buffer, &start, &end);
385
386   if (len > 0)
387     {
388       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
389       gtk_text_buffer_insert (buffer, &start, text, len);
390     }
391 }
392
393 /*
394  * Insertion
395  */
396
397 static void
398
399 gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
400                                   GtkTextIter *iter,
401                                   const gchar *text,
402                                   gint len,
403                                   gboolean interactive)
404 {
405   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
406   g_return_if_fail (iter != NULL);
407
408   gtk_text_btree_insert (iter, text, len);
409
410   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
411 }
412
413 static void
414 gtk_text_buffer_emit_insert (GtkTextBuffer *buffer,
415                              GtkTextIter *iter,
416                              const gchar *text,
417                              gint len,
418                              gboolean interactive)
419 {
420   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
421   g_return_if_fail (iter != NULL);
422   g_return_if_fail (text != NULL);
423
424   if (len < 0)
425     len = strlen (text);
426
427   if (len > 0)
428     {
429       gtk_signal_emit (GTK_OBJECT (buffer), signals[INSERT_TEXT],
430                        iter, text, len, interactive);
431     }
432 }
433
434 /**
435  * gtk_text_buffer_insert:
436  * @buffer: a #GtkTextBuffer
437  * @iter: a position in the buffer
438  * @text: UTF-8 format text to insert
439  * @len: length of text in bytes, or -1
440  *
441  * Inserts @len bytes of @text at position @iter.  If @len is -1,
442  * @text must be nul-terminated and will be inserted in its
443  * entirety. Emits the "insert_text" signal; insertion actually occurs
444  * in the default handler for the signal. @iter is invalidated when
445  * insertion occurs (because the buffer contents change), but the
446  * default signal handler revalidates it to point to the end of the
447  * inserted text.
448  *
449  **/
450 void
451 gtk_text_buffer_insert (GtkTextBuffer *buffer,
452                         GtkTextIter *iter,
453                         const gchar *text,
454                         gint len)
455 {
456   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
457   g_return_if_fail (iter != NULL);
458   g_return_if_fail (text != NULL);
459
460   gtk_text_buffer_emit_insert (buffer, iter, text, len, FALSE);
461 }
462
463 /**
464  * gtk_text_buffer_insert_at_cursor:
465  * @buffer: a #GtkTextBuffer
466  * @text: some text in UTF-8 format
467  * @len: length of text, in bytes
468  *
469  * Simply calls gtk_text_buffer_insert (), using the current
470  * cursor position as the insertion point.
471  **/
472 void
473 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
474                                   const gchar *text,
475                                   gint len)
476 {
477   GtkTextIter iter;
478
479   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
480   g_return_if_fail (text != NULL);
481
482   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
483                                     gtk_text_buffer_get_mark (buffer,
484                                                               "insert"));
485
486   gtk_text_buffer_insert (buffer, &iter, text, len);
487 }
488
489 /**
490  * gtk_text_buffer_insert_interactive:
491  * @buffer: a #GtkTextBuffer
492  * @iter: a position in @buffer
493  * @text: some UTF-8 text
494  * @len: length of text in bytes, or -1
495  * @default_editable: default editability of buffer
496  *
497  * Like gtk_text_buffer_insert (), but the insertion will not occur if
498  * @iter is at a non-editable location in the buffer.  Usually you
499  * want to prevent insertions at ineditable locations if the insertion
500  * results from a user action (is interactive).
501  *
502  * @default_editable indicates the editability of text that doesn't
503  * have a tag affecting editability applied to it. Typically the
504  * result of gtk_text_view_get_editable() is appropriate here.
505  *
506  * Return value: whether text was actually inserted
507  **/
508 gboolean
509 gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer,
510                                     GtkTextIter   *iter,
511                                     const gchar   *text,
512                                     gint           len,
513                                     gboolean       default_editable)
514 {
515   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
516   g_return_val_if_fail (text != NULL, FALSE);
517
518   if (gtk_text_iter_editable (iter, default_editable))
519     {
520       gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
521       return TRUE;
522     }
523   else
524     return FALSE;
525 }
526
527 /**
528  * gtk_text_buffer_insert_interactive_at_cursor:
529  * @buffer: a #GtkTextBuffer
530  * @text: text in UTF-8 format
531  * @len: length of text in bytes, or -1
532  * @default_editable: default editability of buffer
533  *
534  * Calls gtk_text_buffer_insert_interactive () at the cursor
535  * position.
536  *
537  * @default_editable indicates the editability of text that doesn't
538  * have a tag affecting editability applied to it. Typically the
539  * result of gtk_text_view_get_editable() is appropriate here.
540  * 
541  * Return value: whether text was actually inserted
542  **/
543 gboolean
544 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
545                                               const gchar   *text,
546                                               gint           len,
547                                               gboolean       default_editable)
548 {
549   GtkTextIter iter;
550
551   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
552   g_return_val_if_fail (text != NULL, FALSE);
553
554   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
555                                     gtk_text_buffer_get_mark (buffer,
556                                                               "insert"));
557
558   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
559                                              default_editable);
560 }
561
562 static gboolean
563 possibly_not_text (gunichar ch,
564                    gpointer user_data)
565 {
566   return ch == GTK_TEXT_UNKNOWN_CHAR;
567 }
568
569 static void
570 insert_text_range (GtkTextBuffer     *buffer,
571                    GtkTextIter       *iter,
572                    const GtkTextIter *orig_start,
573                    const GtkTextIter *orig_end,
574                    gboolean           interactive)
575 {
576   gchar *text;
577
578   text = gtk_text_iter_get_text (orig_start, orig_end);
579
580   gtk_text_buffer_emit_insert (buffer, iter, text, -1, interactive);
581
582   g_free (text);
583 }
584
585 typedef struct _Range Range;
586 struct _Range
587 {
588   GtkTextBuffer *buffer;
589   GtkTextMark *start_mark;
590   GtkTextMark *end_mark;
591   GtkTextMark *whole_end_mark;
592   GtkTextIter *range_start;
593   GtkTextIter *range_end;
594   GtkTextIter *whole_end;
595 };
596
597 static Range*
598 save_range (GtkTextIter *range_start,
599             GtkTextIter *range_end,
600             GtkTextIter *whole_end)
601 {
602   Range *r;
603
604   r = g_new (Range, 1);
605
606   r->buffer = gtk_text_iter_get_buffer (range_start);
607   g_object_ref (G_OBJECT (r->buffer));
608   
609   r->start_mark = 
610     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
611                                  NULL,
612                                  range_start,
613                                  TRUE);
614   r->end_mark = 
615     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
616                                  NULL,
617                                  range_end,
618                                  FALSE);
619
620   r->whole_end_mark = 
621     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
622                                  NULL,
623                                  whole_end,
624                                  FALSE);
625
626   r->range_start = range_start;
627   r->range_end = range_end;
628   r->whole_end = whole_end;
629
630   return r;
631 }
632
633 static void
634 restore_range (Range *r)
635 {
636   gtk_text_buffer_get_iter_at_mark (r->buffer,
637                                     r->range_start,
638                                     r->start_mark);
639       
640   gtk_text_buffer_get_iter_at_mark (r->buffer,
641                                     r->range_end,
642                                     r->end_mark);
643       
644   gtk_text_buffer_get_iter_at_mark (r->buffer,
645                                     r->whole_end,
646                                     r->whole_end_mark);
647       
648   gtk_text_buffer_delete_mark (r->buffer, r->start_mark);
649   gtk_text_buffer_delete_mark (r->buffer, r->end_mark);
650   gtk_text_buffer_delete_mark (r->buffer, r->whole_end_mark);
651
652   g_object_unref (G_OBJECT (r->buffer));
653   g_free (r); 
654 }
655
656 static void
657 insert_range_untagged (GtkTextBuffer     *buffer,
658                        GtkTextIter       *iter,
659                        const GtkTextIter *orig_start,
660                        const GtkTextIter *orig_end,
661                        gboolean           interactive)
662 {
663   GtkTextIter range_start;
664   GtkTextIter range_end;
665   GtkTextIter start, end;
666   GtkTextBuffer *src_buffer;
667   Range *r;
668   
669   if (gtk_text_iter_equal (orig_start, orig_end))
670     return;
671
672   start = *orig_start;
673   end = *orig_end;
674   
675   src_buffer = gtk_text_iter_get_buffer (&start);
676   
677   range_start = start;
678   range_end = start;
679   
680   while (TRUE)
681     {
682       if (gtk_text_iter_equal (&range_start, &range_end))
683         {
684           /* Figure out how to move forward */
685
686           g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
687           
688           if (gtk_text_iter_equal (&range_end, &end))
689             {
690               /* nothing left to do */
691               break;
692             }
693           else if (gtk_text_iter_get_char (&range_end) == GTK_TEXT_UNKNOWN_CHAR)
694             {
695               GdkPixbuf *pixbuf = NULL;
696               GtkTextChildAnchor *anchor = NULL;
697               pixbuf = gtk_text_iter_get_pixbuf (&range_end);
698               anchor = gtk_text_iter_get_child_anchor (&range_end);
699
700               if (pixbuf)
701                 {
702                   r = save_range (&range_start,
703                                   &range_end,
704                                   &end);
705
706                   gtk_text_buffer_insert_pixbuf (buffer,
707                                                  iter,
708                                                  pixbuf);
709
710                   restore_range (r);
711                   r = NULL;
712                   
713                   gtk_text_iter_forward_char (&range_end);
714                   
715                   range_start = range_end;
716                 }
717               else if (anchor)
718                 {
719                   /* Just skip anchors */
720
721                   gtk_text_iter_forward_char (&range_end);
722                   range_start = range_end;
723                 }
724               else
725                 {
726                   /* The GTK_TEXT_UNKNOWN_CHAR was in a text segment, so
727                    * keep going. 
728                    */
729                   gtk_text_iter_forward_find_char (&range_end,
730                                                    possibly_not_text, NULL,
731                                                    &end);
732                   
733                   g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
734                 }
735             }
736           else
737             {
738               /* Text segment starts here, so forward search to
739                * find its possible endpoint
740                */
741               gtk_text_iter_forward_find_char (&range_end,
742                                                possibly_not_text, NULL,
743                                                &end);
744               
745               g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
746             }
747         }
748       else
749         {
750           r = save_range (&range_start,
751                           &range_end,
752                           &end);
753           
754           insert_text_range (buffer,
755                              iter,
756                              &range_start,
757                              &range_end,
758                              interactive);
759
760           restore_range (r);
761           r = NULL;
762           
763           range_start = range_end;
764         }
765     }
766 }
767
768 static void
769 gtk_text_buffer_real_insert_range (GtkTextBuffer     *buffer,
770                                    GtkTextIter       *iter,
771                                    const GtkTextIter *orig_start,
772                                    const GtkTextIter *orig_end,
773                                    gboolean           interactive)
774 {
775   /* Find each range of uniformly-tagged text, insert it,
776    * then apply the tags.
777    */
778   GtkTextIter start = *orig_start;
779   GtkTextIter end = *orig_end;
780   GtkTextIter range_start;
781   GtkTextIter range_end;
782   GtkTextBuffer *src_buffer;
783   Range *r;
784   
785   if (gtk_text_iter_equal (orig_start, orig_end))
786     return;
787
788   src_buffer = gtk_text_iter_get_buffer (orig_start);
789   
790   gtk_text_iter_reorder (&start, &end);
791
792   range_start = start;
793   range_end = start;
794
795   while (TRUE)
796     {
797       gint start_offset;
798       GtkTextIter start_iter;
799       GSList *tags;
800       GSList *tmp_list;
801       
802       if (gtk_text_iter_equal (&range_start, &end))
803         break; /* All done */
804
805       g_assert (gtk_text_iter_compare (&range_start, &end) < 0);
806       
807       gtk_text_iter_forward_to_tag_toggle (&range_end, NULL);
808
809       g_assert (!gtk_text_iter_equal (&range_start, &range_end));
810
811       /* Clamp to the end iterator */
812       if (gtk_text_iter_compare (&range_end, &end) > 0)
813         range_end = end;
814       
815       /* We have a range with unique tags; insert it, and
816        * apply all tags.
817        */
818       start_offset = gtk_text_iter_get_offset (iter);
819
820       r = save_range (&range_start, &range_end, &end);
821       
822       insert_range_untagged (buffer, iter, &range_start, &range_end, interactive);
823
824       restore_range (r);
825       r = NULL;
826       
827       gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
828       
829       tags = gtk_text_iter_get_tags (&range_start);
830       tmp_list = tags;
831       while (tmp_list != NULL)
832         {
833           gtk_text_buffer_apply_tag (buffer,
834                                      tmp_list->data,
835                                      &start_iter,
836                                      iter);
837           
838           tmp_list = g_slist_next (tmp_list);
839         }
840       g_slist_free (tags);
841
842       range_start = range_end;
843     }
844 }
845
846 /**
847  * gtk_text_buffer_insert_range:
848  * @buffer: a #GtkTextBuffer
849  * @iter: a position in @buffer
850  * @start: a position in a #GtkTextBuffer
851  * @end: another position in the same buffer as @start
852  *
853  * Copies text, tags, and pixbufs between @start and @end (the order
854  * of @start and @end doesn't matter) and inserts the copy at @iter.
855  * Used instead of simply getting/inserting text because it preserves
856  * images and tags. If @start and @end are in a different buffer from
857  * @buffer, the two buffers must share the same tag table.
858  *
859  * Implemented via emissions of the insert_text and apply_tag signals,
860  * so expect those.
861  **/
862 void
863 gtk_text_buffer_insert_range (GtkTextBuffer     *buffer,
864                               GtkTextIter       *iter,
865                               const GtkTextIter *start,
866                               const GtkTextIter *end)
867 {
868   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
869   g_return_if_fail (iter != NULL);
870   g_return_if_fail (start != NULL);
871   g_return_if_fail (end != NULL);
872   g_return_if_fail (gtk_text_iter_get_buffer (start) ==
873                     gtk_text_iter_get_buffer (end));
874   g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
875                     buffer->tag_table);  
876
877   gtk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE);
878 }
879
880 /**
881  * gtk_text_buffer_insert_range_interactive:
882  * @buffer: a #GtkTextBuffer
883  * @iter: a position in @buffer
884  * @start: a position in a #GtkTextBuffer
885  * @end: another position in the same buffer as @start
886  * @default_editable: default editability of the buffer
887  *
888  * Same as gtk_text_buffer_insert_range(), but does nothing if the
889  * insertion point isn't editable. The @default_editable parameter
890  * indicates whether the text is editable at @iter if no tags
891  * enclosing @iter affect editability. Typically the result of
892  * gtk_text_view_get_editable() is appropriate here.
893  *
894  * Returns: whether an insertion was possible at @iter
895  **/
896 gboolean
897 gtk_text_buffer_insert_range_interactive (GtkTextBuffer     *buffer,
898                                           GtkTextIter       *iter,
899                                           const GtkTextIter *start,
900                                           const GtkTextIter *end,
901                                           gboolean           default_editable)
902 {
903   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
904   g_return_val_if_fail (iter != NULL, FALSE);
905   g_return_val_if_fail (start != NULL, FALSE);
906   g_return_val_if_fail (end != NULL, FALSE);
907   g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
908                         gtk_text_iter_get_buffer (end), FALSE);
909   g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
910                         buffer->tag_table, FALSE);
911
912
913   if (gtk_text_iter_editable (iter, default_editable))
914     {
915       gtk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE);
916       return TRUE;
917     }
918   else
919     return FALSE;
920 }
921
922 /**
923  * gtk_text_buffer_insert_with_tags:
924  * @buffer: a #GtkTextBuffer
925  * @iter: an iterator in @buffer
926  * @text: UTF-8 text
927  * @len: length of @text, or -1
928  * @first_tag: first tag to apply to @text
929  * @Varargs: NULL-terminated list of tags to apply
930  *
931  * Inserts @text into @buffer at @iter, applying the list of tags to
932  * the newly-inserted text. The last tag specified must be NULL to
933  * terminate the list. Equivalent to calling gtk_text_buffer_insert (),
934  * then gtk_text_buffer_apply_tag () on the inserted text;
935  * gtk_text_buffer_insert_with_tags () is just a convenience function.
936  **/
937 void
938 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
939                                   GtkTextIter   *iter,
940                                   const gchar   *text,
941                                   gint           len,
942                                   GtkTextTag    *first_tag,
943                                   ...)
944 {
945   gint start_offset;
946   GtkTextIter start;
947   va_list args;
948   GtkTextTag *tag;
949
950   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
951   g_return_if_fail (iter != NULL);
952   g_return_if_fail (text != NULL);
953
954   start_offset = gtk_text_iter_get_offset (iter);
955
956   gtk_text_buffer_insert (buffer, iter, text, len);
957
958   if (first_tag == NULL)
959     return;
960
961   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
962
963   va_start (args, first_tag);
964   tag = first_tag;
965   while (tag)
966     {
967       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
968
969       tag = va_arg (args, GtkTextTag*);
970     }
971
972   va_end (args);
973 }
974
975 /**
976  * gtk_text_buffer_insert_with_tags_by_name:
977  * @buffer: a #GtkTextBuffer
978  * @iter: position in @buffer
979  * @text: UTF-8 text
980  * @len: length of @text, or -1
981  * @first_tag_name: name of a tag to apply to @text
982  * @Varargs: more tag names
983  *
984  * Same as gtk_text_buffer_insert_with_tags (), but allows you
985  * to pass in tag names instead of tag objects.
986  **/
987 void
988 gtk_text_buffer_insert_with_tags_by_name  (GtkTextBuffer *buffer,
989                                            GtkTextIter   *iter,
990                                            const gchar   *text,
991                                            gint           len,
992                                            const gchar   *first_tag_name,
993                                            ...)
994 {
995   gint start_offset;
996   GtkTextIter start;
997   va_list args;
998   const gchar *tag_name;
999
1000   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1001   g_return_if_fail (iter != NULL);
1002   g_return_if_fail (text != NULL);
1003
1004   start_offset = gtk_text_iter_get_offset (iter);
1005
1006   gtk_text_buffer_insert (buffer, iter, text, len);
1007
1008   if (first_tag_name == NULL)
1009     return;
1010
1011   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1012
1013   va_start (args, first_tag_name);
1014   tag_name = first_tag_name;
1015   while (tag_name)
1016     {
1017       GtkTextTag *tag;
1018
1019       tag = gtk_text_tag_table_lookup (buffer->tag_table,
1020                                        tag_name);
1021
1022       if (tag == NULL)
1023         {
1024           g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
1025           return;
1026         }
1027
1028       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1029
1030       tag_name = va_arg (args, const gchar*);
1031     }
1032
1033   va_end (args);
1034 }
1035
1036
1037 /*
1038  * Deletion
1039  */
1040
1041 static void
1042 gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
1043                                   GtkTextIter *start,
1044                                   GtkTextIter *end,
1045                                   gboolean interactive)
1046 {
1047   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1048   g_return_if_fail (start != NULL);
1049   g_return_if_fail (end != NULL);
1050
1051   gtk_text_btree_delete (start, end);
1052
1053   /* may have deleted the selection... */
1054   gtk_text_buffer_update_primary_selection (buffer);
1055
1056   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1057 }
1058
1059 static void
1060 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
1061                              GtkTextIter *start,
1062                              GtkTextIter *end,
1063                              gboolean interactive)
1064 {
1065   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1066   g_return_if_fail (start != NULL);
1067   g_return_if_fail (end != NULL);
1068
1069   if (gtk_text_iter_equal (start, end))
1070     return;
1071
1072   gtk_text_iter_reorder (start, end);
1073
1074   /* Somewhat annoyingly, if you try to delete the final newline
1075    * the BTree will put it back; which means you can't deduce the
1076    * final contents of the buffer purely by monitoring insert/delete
1077    * signals on the buffer. But if you delete the final newline, any
1078    * tags on the newline will go away, oddly. See comment in
1079    * gtktextbtree.c. This is all sort of annoying, but really hard
1080    * to fix.
1081    */
1082   gtk_signal_emit (GTK_OBJECT (buffer),
1083                    signals[DELETE_TEXT],
1084                    start, end,
1085                    interactive);
1086 }
1087
1088 /**
1089  * gtk_text_buffer_delete:
1090  * @buffer: a #GtkTextBuffer
1091  * @start: a position in @buffer
1092  * @end: another position in @buffer
1093  *
1094  * Deletes text between @start and @end. The order of @start and @end
1095  * is not actually relevant; gtk_text_buffer_delete () will reorder
1096  * them. This function actually emits the "delete_text" signal, and
1097  * the default handler of that signal deletes the text. Because the
1098  * buffer is modified, all outstanding iterators become invalid after
1099  * calling this function; however, the @start and @end will be
1100  * re-initialized to point to the location where text was deleted.
1101  *
1102  * Note that the final newline in the buffer may not be deleted; a
1103  * #GtkTextBuffer always contains at least one newline.  You can
1104  * safely include the final newline in the range [@start,@end) but it
1105  * won't be affected by the deletion.
1106  *
1107  **/
1108 void
1109 gtk_text_buffer_delete (GtkTextBuffer *buffer,
1110                         GtkTextIter   *start,
1111                         GtkTextIter   *end)
1112 {
1113   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1114   g_return_if_fail (start != NULL);
1115   g_return_if_fail (end != NULL);
1116
1117   gtk_text_buffer_emit_delete (buffer, start, end, FALSE);
1118 }
1119
1120 /**
1121  * gtk_text_buffer_delete_interactive:
1122  * @buffer: a #GtkTextBuffer
1123  * @start_iter: start of range to delete
1124  * @end_iter: end of range
1125  * @default_editable: whether the buffer is editable by default
1126  *
1127  * Deletes all <emphasis>editable</emphasis> text in the given range.
1128  * Calls gtk_text_buffer_delete () for each editable sub-range of
1129  * [@start,@end). @start and @end are revalidated to point to
1130  * the location of the last deleted range, or left untouched if
1131  * no text was deleted.
1132  *
1133  * Return value: whether some text was actually deleted
1134  **/
1135 gboolean
1136 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
1137                                     GtkTextIter   *start_iter,
1138                                     GtkTextIter   *end_iter,
1139                                     gboolean       default_editable)
1140 {
1141   GtkTextMark *end_mark;
1142   GtkTextMark *start_mark;
1143   GtkTextIter iter;
1144   gboolean current_state;
1145   gboolean deleted_stuff = FALSE;
1146
1147   /* Delete all editable text in the range start_iter, end_iter */
1148
1149   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1150   g_return_val_if_fail (start_iter != NULL, FALSE);
1151   g_return_val_if_fail (end_iter != NULL, FALSE);
1152
1153   gtk_text_iter_reorder (start_iter, end_iter);
1154
1155   start_mark = gtk_text_buffer_create_mark (buffer, NULL,
1156                                             start_iter, TRUE);
1157   end_mark = gtk_text_buffer_create_mark (buffer, NULL,
1158                                           end_iter, FALSE);
1159   iter = *start_iter;
1160
1161   current_state = gtk_text_iter_editable (&iter, default_editable);
1162
1163   while (TRUE)
1164     {
1165       gboolean new_state;
1166       gboolean done = FALSE;
1167       GtkTextIter end;
1168
1169       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
1170
1171       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
1172
1173       if (gtk_text_iter_compare (&iter, &end) >= 0)
1174         {
1175           done = TRUE;
1176           iter = end; /* clamp to the last boundary */
1177         }
1178
1179       new_state = gtk_text_iter_editable (&iter, default_editable);
1180
1181       if (current_state == new_state)
1182         {
1183           if (done)
1184             {
1185               if (current_state)
1186                 {
1187                   /* We're ending an editable region. Delete said region. */
1188                   GtkTextIter start;
1189
1190                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1191
1192                   gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1193
1194                   deleted_stuff = TRUE;
1195
1196                   /* revalidate user's iterators. */
1197                   *start_iter = start;
1198                   *end_iter = iter;
1199                 }
1200
1201               break;
1202             }
1203           else
1204             continue;
1205         }
1206
1207       if (current_state && !new_state)
1208         {
1209           /* End of an editable region. Delete it. */
1210           GtkTextIter start;
1211
1212           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1213
1214           gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1215
1216           current_state = FALSE;
1217           deleted_stuff = TRUE;
1218
1219           /* revalidate user's iterators. */
1220           *start_iter = start;
1221           *end_iter = iter;
1222         }
1223       else
1224         {
1225           /* We are at the start of an editable region. We won't be deleting
1226            * the previous region. Move start mark to start of this region.
1227            */
1228
1229           g_assert (!current_state && new_state);
1230
1231           gtk_text_buffer_move_mark (buffer, start_mark,
1232                                      &iter);
1233
1234
1235           current_state = TRUE;
1236         }
1237
1238       if (done)
1239         break;
1240     }
1241
1242
1243   gtk_text_buffer_delete_mark (buffer, start_mark);
1244   gtk_text_buffer_delete_mark (buffer, end_mark);
1245
1246   return deleted_stuff;
1247 }
1248
1249 /*
1250  * Extracting textual buffer contents
1251  */
1252
1253 /**
1254  * gtk_text_buffer_get_text:
1255  * @buffer: a #GtkTextBuffer
1256  * @start: start of a range
1257  * @end: end of a range
1258  * @include_hidden_chars: whether to include invisible text
1259  *
1260  * Returns the text in the range [@start,@end). Excludes undisplayed
1261  * text (text marked with tags that set the invisibility attribute) if
1262  * @include_hidden_chars is FALSE. Does not include characters
1263  * representing embedded images, so byte and character indexes into
1264  * the returned string do <emphasis>not</emphasis> correspond to byte
1265  * and character indexes into the buffer. Contrast with
1266  * gtk_text_buffer_get_slice ().
1267  *
1268  * Return value: an allocated UTF-8 string
1269  **/
1270 gchar*
1271 gtk_text_buffer_get_text (GtkTextBuffer      *buffer,
1272                           const GtkTextIter *start,
1273                           const GtkTextIter *end,
1274                           gboolean             include_hidden_chars)
1275 {
1276   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1277   g_return_val_if_fail (start != NULL, NULL);
1278   g_return_val_if_fail (end != NULL, NULL);
1279
1280   if (include_hidden_chars)
1281     return gtk_text_iter_get_text (start, end);
1282   else
1283     return gtk_text_iter_get_visible_text (start, end);
1284 }
1285
1286 /**
1287  * gtk_text_buffer_get_slice:
1288  * @buffer: a #GtkTextBuffer
1289  * @start: start of a range
1290  * @end: end of a range
1291  * @include_hidden_chars: whether to include invisible text
1292  *
1293  * Returns the text in the range [@start,@end). Excludes undisplayed
1294  * text (text marked with tags that set the invisibility attribute) if
1295  * @include_hidden_chars is FALSE. The returned string includes a
1296  * 0xFFFC character whenever the buffer contains
1297  * embedded images, so byte and character indexes into
1298  * the returned string <emphasis>do</emphasis> correspond to byte
1299  * and character indexes into the buffer. Contrast with
1300  * gtk_text_buffer_get_text (). Note that 0xFFFC can occur in normal
1301  * text as well, so it is not a reliable indicator that a pixbuf or
1302  * widget is in the buffer.
1303  *
1304  * Return value: an allocated UTF-8 string
1305  **/
1306 gchar*
1307 gtk_text_buffer_get_slice (GtkTextBuffer      *buffer,
1308                            const GtkTextIter *start,
1309                            const GtkTextIter *end,
1310                            gboolean             include_hidden_chars)
1311 {
1312   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1313   g_return_val_if_fail (start != NULL, NULL);
1314   g_return_val_if_fail (end != NULL, NULL);
1315
1316   if (include_hidden_chars)
1317     return gtk_text_iter_get_slice (start, end);
1318   else
1319     return gtk_text_iter_get_visible_slice (start, end);
1320 }
1321
1322 /*
1323  * Pixmaps
1324  */
1325
1326 void
1327 gtk_text_buffer_insert_pixbuf         (GtkTextBuffer      *buffer,
1328                                        GtkTextIter        *iter,
1329                                        GdkPixbuf          *pixbuf)
1330 {
1331   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1332   g_return_if_fail (iter != NULL);
1333   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1334
1335   gtk_text_btree_insert_pixbuf (iter, pixbuf);
1336
1337   /* FIXME pixbuf-specific signal like insert_text */
1338
1339   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1340 }
1341
1342 /*
1343  * Child anchor
1344  */
1345
1346 GtkTextChildAnchor*
1347 gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
1348                                      GtkTextIter   *iter)
1349 {
1350   GtkTextChildAnchor *anchor;
1351   
1352   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1353   g_return_val_if_fail (iter != NULL, NULL);
1354
1355   anchor = gtk_text_btree_create_child_anchor (iter);
1356
1357   /* FIXME child-anchor-specific signal */
1358   
1359   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1360
1361   return anchor;
1362 }
1363
1364
1365 /*
1366  * Mark manipulation
1367  */
1368
1369 static void
1370 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
1371                           const GtkTextIter *location,
1372                           GtkTextMark       *mark)
1373 {
1374   /* IMO this should NOT work like insert_text and delete_text,
1375      where the real action happens in the default handler.
1376
1377      The reason is that the default handler would be _required_,
1378      i.e. the whole widget would start breaking and segfaulting
1379      if the default handler didn't get run. So you can't really
1380      override the default handler or stop the emission; that is,
1381      this signal is purely for notification, and not to allow users
1382      to modify the default behavior. */
1383
1384   g_object_ref (G_OBJECT (mark));
1385
1386   gtk_signal_emit (GTK_OBJECT (buffer),
1387                    signals[MARK_SET],
1388                    location,
1389                    mark);
1390
1391   g_object_unref (G_OBJECT (mark));
1392 }
1393
1394 /**
1395  * gtk_text_buffer_set_mark:
1396  * @buffer:       a #GtkTextBuffer
1397  * @mark_name:    name of the mark
1398  * @iter:         location for the mark.
1399  * @left_gravity: if the mark is created by this function, gravity for the new
1400  *                mark.
1401  * @should_exist: if %TRUE, warn if the mark does not exist, and return
1402  *                immediately.
1403  *
1404  * Move the mark to the given position, if not @should_exist, create the mark.
1405  *
1406  * Return value: mark
1407  **/
1408 static GtkTextMark*
1409 gtk_text_buffer_set_mark (GtkTextBuffer *buffer,
1410                           GtkTextMark *existing_mark,
1411                           const gchar *mark_name,
1412                           const GtkTextIter *iter,
1413                           gboolean left_gravity,
1414                           gboolean should_exist)
1415 {
1416   GtkTextIter location;
1417   GtkTextMark *mark;
1418
1419   mark = gtk_text_btree_set_mark (get_btree (buffer),
1420                                   existing_mark,
1421                                   mark_name,
1422                                   left_gravity,
1423                                   iter,
1424                                   should_exist);
1425
1426   if (gtk_text_btree_mark_is_insert (get_btree (buffer), mark) ||
1427       gtk_text_btree_mark_is_selection_bound (get_btree (buffer), mark))
1428     {
1429       gtk_text_buffer_update_primary_selection (buffer);
1430     }
1431
1432   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1433                                    &location,
1434                                    mark);
1435
1436   gtk_text_buffer_mark_set (buffer, &location, mark);
1437
1438   return mark;
1439 }
1440
1441 /**
1442  * gtk_text_buffer_create_mark:
1443  * @buffer: a #GtkTextBuffer
1444  * @mark_name: name for mark, or %NULL
1445  * @where: location to place mark
1446  * @left_gravity: whether the mark has left gravity
1447  *
1448  * Creates a mark at position @where. If @mark_name is %NULL, the mark
1449  * is anonymous; otherwise, the mark can be retrieved by name using
1450  * gtk_text_buffer_get_mark (). If a mark has left gravity, and text is
1451  * inserted at the mark's current location, the mark will be moved to
1452  * the left of the newly-inserted text. If the mark has right gravity
1453  * (@left_gravity = %FALSE), the mark will end up on the right of
1454  * newly-inserted text. The standard left-to-right cursor is a mark
1455  * with right gravity (when you type, the cursor stays on the right
1456  * side of the text you're typing).
1457  *
1458  * The caller of this function does <emphasis>not</emphasis> own a reference
1459  * to the returned #GtkTextMark, so you can ignore the return value
1460  * if you like. Marks are owned by the buffer and go away when the
1461  * buffer does.
1462  *
1463  * Emits the "mark_set" signal as notification of the mark's initial
1464  * placement.
1465  *
1466  * Return value: the new #GtkTextMark object
1467  **/
1468 GtkTextMark*
1469 gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
1470                              const gchar *mark_name,
1471                              const GtkTextIter *where,
1472                              gboolean left_gravity)
1473 {
1474   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1475
1476   return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
1477                                    left_gravity, FALSE);
1478 }
1479
1480 /**
1481  * gtk_text_buffer_move_mark:
1482  * @buffer: a #GtkTextBuffer
1483  * @mark: a #GtkTextMark
1484  * @where: new location for @mark in @buffer
1485  *
1486  * Moves @mark to the new location @where. Emits the "mark_set" signal
1487  * as notification of the move.
1488  **/
1489 void
1490 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
1491                            GtkTextMark *mark,
1492                            const GtkTextIter *where)
1493 {
1494   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1495   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1496   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1497
1498   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
1499 }
1500
1501 /**
1502  * gtk_text_buffer_get_iter_at_mark:
1503  * @buffer: a #GtkTextBuffer
1504  * @iter: iterator to initialize
1505  * @mark: a #GtkTextMark in @buffer
1506  *
1507  * Initializes @iter with the current position of @mark.
1508  **/
1509 void
1510 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
1511                                   GtkTextIter *iter,
1512                                   GtkTextMark *mark)
1513 {
1514   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1515   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1516   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1517
1518   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1519                                    iter,
1520                                    mark);
1521 }
1522
1523 /**
1524  * gtk_text_buffer_delete_mark:
1525  * @buffer: a #GtkTextBuffer
1526  * @mark: a #GtkTextMark in @buffer
1527  *
1528  * Deletes @mark, so that it's no longer located anywhere in the
1529  * buffer. Removes the reference the buffer holds to the mark, so if
1530  * you haven't called g_object_ref () on the mark, it will be freed. Even
1531  * if the mark isn't freed, most operations on @mark become
1532  * invalid. There is no way to undelete a
1533  * mark. gtk_text_mark_get_deleted () will return TRUE after this
1534  * function has been called on a mark; gtk_text_mark_get_deleted ()
1535  * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
1536  * signal will be emitted as notification after the mark is deleted.
1537  **/
1538 void
1539 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
1540                              GtkTextMark   *mark)
1541 {
1542   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1543   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1544   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1545
1546   g_object_ref (G_OBJECT (mark));
1547
1548   gtk_text_btree_remove_mark (get_btree (buffer), mark);
1549
1550   /* See rationale above for MARK_SET on why we emit this after
1551    * removing the mark, rather than removing the mark in a default
1552    * handler.
1553    */
1554   gtk_signal_emit (GTK_OBJECT (buffer), signals[MARK_DELETED],
1555                    mark);
1556
1557   g_object_unref (G_OBJECT (mark));
1558 }
1559
1560 /**
1561  * gtk_text_buffer_get_mark:
1562  * @buffer: a #GtkTextBuffer
1563  * @name: a mark name
1564  *
1565  * Returns the mark named @name in buffer @buffer, or NULL if no such
1566  * mark exists in the buffer.
1567  *
1568  * Return value: a #GtkTextMark, or NULL
1569  **/
1570 GtkTextMark*
1571 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
1572                           const gchar         *name)
1573 {
1574   GtkTextMark *mark;
1575
1576   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1577   g_return_val_if_fail (name != NULL, NULL);
1578
1579   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1580
1581   return mark;
1582 }
1583
1584
1585 /**
1586  * gtk_text_buffer_move_mark_by_name:
1587  * @buffer: a #GtkTextBuffer
1588  * @name: name of a mark
1589  * @where: new location for mark
1590  *
1591  * Moves the mark named @name (which must exist) to location @where.
1592  * See gtk_text_buffer_move_mark () for details.
1593  **/
1594 void
1595 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
1596                                    const gchar       *name,
1597                                    const GtkTextIter *where)
1598 {
1599   GtkTextMark *mark;
1600
1601   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1602   g_return_if_fail (name != NULL);
1603
1604   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1605
1606   if (mark == NULL)
1607     {
1608       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1609       return;
1610     }
1611
1612   gtk_text_buffer_move_mark (buffer, mark, where);
1613 }
1614
1615 /**
1616  * gtk_text_buffer_delete_mark_by_name:
1617  * @buffer: a #GtkTextBuffer
1618  * @name: name of a mark in @buffer
1619  *
1620  * Deletes the mark named @name; the mark must exist. See
1621  * gtk_text_buffer_delete_mark () for details.
1622  **/
1623 void
1624 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer     *buffer,
1625                                      const gchar       *name)
1626 {
1627   GtkTextMark *mark;
1628
1629   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1630   g_return_if_fail (name != NULL);
1631
1632   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1633
1634   if (mark == NULL)
1635     {
1636       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1637       return;
1638     }
1639
1640   gtk_text_buffer_delete_mark (buffer, mark);
1641 }
1642
1643 /**
1644  * gtk_text_buffer_get_insert:
1645  * @buffer: a #GtkTextBuffer
1646  *
1647  * Returns the mark that represents the cursor (insertion point).
1648  * Equivalent to calling gtk_text_buffer_get_mark () to get the mark
1649  * name "insert," but very slightly more efficient, and involves less
1650  * typing.
1651  *
1652  * Return value: insertion point mark
1653  **/
1654 GtkTextMark*
1655 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
1656 {
1657   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1658
1659   /* FIXME use struct member in btree */
1660   return gtk_text_buffer_get_mark (buffer, "insert");
1661 }
1662
1663 /**
1664  * gtk_text_buffer_get_selection_bound:
1665  * @buffer: a #GtkTextBuffer
1666  *
1667  * Returns the mark that represents the selection bound.  Equivalent
1668  * to calling gtk_text_buffer_get_mark () to get the mark name
1669  * "selection_bound," but very slightly more efficient, and involves
1670  * less typing.
1671  *
1672  * The currently-selected text in @buffer is the region between the
1673  * "selection_bound" and "insert" marks. If "selection_bound" and
1674  * "insert" are in the same place, then there is no current selection.
1675  * gtk_text_buffer_get_selection_bounds () is another convenient function
1676  * for handling the selection, if you just want to know whether there's a
1677  * selection and what its bounds are.
1678  *
1679  * Return value: selection bound mark
1680  **/
1681 GtkTextMark*
1682 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
1683 {
1684   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1685
1686   /* FIXME use struct member in btree */
1687   return gtk_text_buffer_get_mark (buffer, "selection_bound");
1688 }
1689
1690 void
1691 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
1692                                           GtkTextIter        *iter,
1693                                           GtkTextChildAnchor *anchor)
1694 {
1695   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1696   g_return_if_fail (iter != NULL);
1697   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
1698   g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
1699   
1700   gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
1701                                            iter,
1702                                            anchor);
1703 }
1704
1705 /**
1706  * gtk_text_buffer_place_cursor:
1707  * @buffer: a #GtkTextBuffer
1708  * @where: where to put the cursor
1709  *
1710  * This function moves the "insert" and "selection_bound" marks
1711  * simultaneously.  If you move them to the same place in two steps
1712  * with gtk_text_buffer_move_mark (), you will temporarily select a
1713  * region in between their old and new locations, which can be pretty
1714  * inefficient since the temporarily-selected region will force stuff
1715  * to be recalculated. This function moves them as a unit, which can
1716  * be optimized.
1717  **/
1718 void
1719 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
1720                               const GtkTextIter *where)
1721 {
1722   GtkTextIter real;
1723
1724   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1725
1726   real = *where;
1727
1728   if (gtk_text_iter_is_last (&real))
1729     gtk_text_iter_backward_char (&real);
1730
1731   gtk_text_btree_place_cursor (get_btree (buffer), &real);
1732   gtk_text_buffer_mark_set (buffer, &real,
1733                             gtk_text_buffer_get_mark (buffer,
1734                                                       "insert"));
1735   gtk_text_buffer_mark_set (buffer, &real,
1736                             gtk_text_buffer_get_mark (buffer,
1737                                                       "selection_bound"));
1738 }
1739
1740 /*
1741  * Tags
1742  */
1743
1744 /**
1745  * gtk_text_buffer_create_tag:
1746  * @buffer: a #GtkTextBuffer
1747  * @tag_name: name of the new tag, or %NULL
1748  *
1749  * Creates a tag and adds it to the tag table for @buffer.
1750  * Equivalent to calling gtk_text_tag_new () and then adding the
1751  * tag to the buffer's tag table. The returned tag has its refcount
1752  * incremented, as if you'd called gtk_text_tag_new ().
1753  *
1754  * If @tag_name is %NULL, the tag is anonymous.
1755  *
1756  * Return value: a new tag
1757  **/
1758 GtkTextTag*
1759 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
1760                             const gchar *tag_name)
1761 {
1762   GtkTextTag *tag;
1763
1764   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1765
1766   tag = gtk_text_tag_new (tag_name);
1767
1768   gtk_text_tag_table_add (get_table (buffer), tag);
1769
1770   return tag;
1771 }
1772
1773 static void
1774 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1775                                 GtkTextTag *tag,
1776                                 const GtkTextIter *start,
1777                                 const GtkTextIter *end)
1778 {
1779   gtk_text_btree_tag (start, end, tag, TRUE);
1780 }
1781
1782 static void
1783 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1784                                  GtkTextTag *tag,
1785                                  const GtkTextIter *start,
1786                                  const GtkTextIter *end)
1787 {
1788   gtk_text_btree_tag (start, end, tag, FALSE);
1789 }
1790
1791 static void
1792 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
1793 {
1794   gtk_text_buffer_set_modified (buffer, TRUE);
1795 }
1796
1797 static void
1798 gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,
1799                           GtkTextTag *tag,
1800                           gboolean apply,
1801                           const GtkTextIter *start,
1802                           const GtkTextIter *end)
1803 {
1804   GtkTextIter start_tmp = *start;
1805   GtkTextIter end_tmp = *end;
1806
1807   g_return_if_fail (tag != NULL);
1808
1809   gtk_text_iter_reorder (&start_tmp, &end_tmp);
1810
1811   if (apply)
1812     gtk_signal_emit (GTK_OBJECT (buffer), signals[APPLY_TAG],
1813                      tag, &start_tmp, &end_tmp);
1814   else
1815     gtk_signal_emit (GTK_OBJECT (buffer), signals[REMOVE_TAG],
1816                      tag, &start_tmp, &end_tmp);
1817 }
1818
1819
1820 void
1821 gtk_text_buffer_apply_tag (GtkTextBuffer *buffer,
1822                            GtkTextTag    *tag,
1823                            const GtkTextIter *start,
1824                            const GtkTextIter *end)
1825 {
1826   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1827   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1828   g_return_if_fail (start != NULL);
1829   g_return_if_fail (end != NULL);
1830
1831   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1832 }
1833
1834 void
1835 gtk_text_buffer_remove_tag (GtkTextBuffer *buffer,
1836                             GtkTextTag    *tag,
1837                             const GtkTextIter *start,
1838                             const GtkTextIter *end)
1839
1840 {
1841   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1842   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1843   g_return_if_fail (start != NULL);
1844   g_return_if_fail (end != NULL);
1845
1846   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1847 }
1848
1849
1850 void
1851 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1852                                    const gchar *name,
1853                                    const GtkTextIter *start,
1854                                    const GtkTextIter *end)
1855 {
1856   GtkTextTag *tag;
1857
1858   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1859   g_return_if_fail (name != NULL);
1860   g_return_if_fail (start != NULL);
1861   g_return_if_fail (end != NULL);
1862
1863   tag = gtk_text_tag_table_lookup (get_table (buffer),
1864                                    name);
1865
1866   if (tag == NULL)
1867     {
1868       g_warning ("Unknown tag `%s'", name);
1869       return;
1870     }
1871
1872   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1873 }
1874
1875 void
1876 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1877                                     const gchar *name,
1878                                     const GtkTextIter *start,
1879                                     const GtkTextIter *end)
1880 {
1881   GtkTextTag *tag;
1882
1883   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1884   g_return_if_fail (name != NULL);
1885   g_return_if_fail (start != NULL);
1886   g_return_if_fail (end != NULL);
1887
1888   tag = gtk_text_tag_table_lookup (get_table (buffer),
1889                                    name);
1890
1891   if (tag == NULL)
1892     {
1893       g_warning ("Unknown tag `%s'", name);
1894       return;
1895     }
1896
1897   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1898 }
1899
1900
1901 /*
1902  * Obtain various iterators
1903  */
1904
1905 void
1906 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
1907                                          GtkTextIter        *iter,
1908                                          gint                line_number,
1909                                          gint                char_offset)
1910 {
1911   g_return_if_fail (iter != NULL);
1912   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1913
1914   gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
1915                                         iter, line_number, char_offset);
1916 }
1917
1918 void
1919 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
1920                                          GtkTextIter   *iter,
1921                                          gint           line_number,
1922                                          gint           byte_index)
1923 {
1924   g_return_if_fail (iter != NULL);
1925   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1926
1927   gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
1928                                         iter, line_number, byte_index);
1929 }
1930
1931 void
1932 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
1933                                      GtkTextIter        *iter,
1934                                      gint                line_number)
1935 {
1936   g_return_if_fail (iter != NULL);
1937   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1938
1939   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1940 }
1941
1942 void
1943 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
1944                                             GtkTextIter        *iter,
1945                                             gint                char_offset)
1946 {
1947   g_return_if_fail (iter != NULL);
1948   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1949
1950   gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
1951 }
1952
1953 void
1954 gtk_text_buffer_get_last_iter         (GtkTextBuffer      *buffer,
1955                                        GtkTextIter        *iter)
1956 {
1957   g_return_if_fail (iter != NULL);
1958   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1959
1960   gtk_text_btree_get_last_iter (get_btree (buffer), iter);
1961 }
1962
1963 void
1964 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1965                             GtkTextIter   *start,
1966                             GtkTextIter   *end)
1967 {
1968   g_return_if_fail (start != NULL);
1969   g_return_if_fail (end != NULL);
1970   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1971
1972   gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
1973   gtk_text_btree_get_last_iter (get_btree (buffer), end);
1974 }
1975
1976 /*
1977  * Modified flag
1978  */
1979
1980 gboolean
1981 gtk_text_buffer_modified (GtkTextBuffer      *buffer)
1982 {
1983   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1984
1985   return buffer->modified;
1986 }
1987
1988 void
1989 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
1990                               gboolean             setting)
1991 {
1992   gboolean fixed_setting;
1993
1994   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1995
1996   fixed_setting = setting != FALSE;
1997
1998   if (buffer->modified == fixed_setting)
1999     return;
2000   else
2001     {
2002       buffer->modified = fixed_setting;
2003       gtk_signal_emit (GTK_OBJECT (buffer), signals[MODIFIED_CHANGED]);
2004     }
2005 }
2006
2007
2008 /*
2009  * Assorted other stuff
2010  */
2011
2012 gint
2013 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
2014 {
2015   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2016
2017   return gtk_text_btree_line_count (get_btree (buffer));
2018 }
2019
2020 gint
2021 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
2022 {
2023   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2024
2025   return gtk_text_btree_char_count (get_btree (buffer));
2026 }
2027
2028 /* Called when we lose the primary selection.
2029  */
2030 static void
2031 clipboard_clear_selection_cb (GtkClipboard *clipboard,
2032                               gpointer      data)
2033 {
2034   /* Move selection_bound to the insertion point */
2035   GtkTextIter insert;
2036   GtkTextIter selection_bound;
2037   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2038
2039   gtk_text_buffer_get_iter_at_mark (buffer, &insert,
2040                                     gtk_text_buffer_get_mark (buffer, "insert"));
2041   gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
2042                                     gtk_text_buffer_get_mark (buffer, "selection_bound"));
2043
2044   if (!gtk_text_iter_equal (&insert, &selection_bound))
2045     gtk_text_buffer_move_mark (buffer,
2046                                gtk_text_buffer_get_mark (buffer, "selection_bound"),
2047                                &insert);
2048 }
2049
2050 /* Called when we have the primary selection and someone else wants our
2051  * data in order to paste it.
2052  */
2053 static void
2054 clipboard_get_selection_cb (GtkClipboard     *clipboard,
2055                             GtkSelectionData *selection_data,
2056                             guint             info,
2057                             gpointer          data)
2058 {
2059   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2060   GtkTextIter start, end;
2061
2062   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2063     {
2064       if (selection_data->target ==
2065           gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2066         {
2067           /* Provide the address of the buffer; this will only be
2068            * used within-process
2069            */
2070           gtk_selection_data_set (selection_data,
2071                                   gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2072                                   8, /* bytes */
2073                                   (void*)&buffer,
2074                                   sizeof (buffer));
2075         }
2076       else
2077         {
2078           gchar *str;
2079           
2080           str = gtk_text_iter_get_visible_text (&start, &end);
2081           gtk_selection_data_set_text (selection_data, str);
2082           g_free (str);
2083         }
2084     }
2085 }
2086
2087 /* Provide cut/copied data */
2088 static void
2089 clipboard_get_contents_cb (GtkClipboard     *clipboard,
2090                            GtkSelectionData *selection_data,
2091                            guint             info,
2092                            gpointer          data)
2093 {
2094   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2095   GtkTextBuffer *contents = buffer->clipboard_contents;
2096
2097   if (selection_data->target ==
2098       gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2099     {
2100       /* Provide the address of the clipboard buffer; this will only
2101        * be used within-process. OK to supply a NULL value for contents.
2102        */
2103       gtk_selection_data_set (selection_data,
2104                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2105                               8, /* bytes */
2106                               (void*)&contents,
2107                               sizeof (contents));
2108     }
2109   else
2110     {
2111       /* Just provide text from the clipboard buffer */
2112       if (buffer->clipboard_contents)
2113         {
2114           gchar *str;
2115           GtkTextIter start, end;
2116           
2117           gtk_text_buffer_get_bounds (contents, &start, &end);
2118           /* strip off the trailing newline, it isn't part of the text that was cut */
2119           gtk_text_iter_backward_char (&end);
2120           
2121           str = gtk_text_iter_get_visible_text (&start, &end);
2122           gtk_selection_data_set_text (selection_data, str);
2123           g_free (str);
2124         }
2125       else
2126         {
2127           gtk_selection_data_set_text (selection_data, "");
2128           return;
2129         }
2130     }
2131 }
2132
2133 static void
2134 clipboard_clear_contents_cb (GtkClipboard *clipboard,
2135                              gpointer      data)
2136 {
2137   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2138
2139   if (buffer->clipboard_contents)
2140     {
2141       g_object_unref (G_OBJECT (buffer->clipboard_contents));
2142       buffer->clipboard_contents = NULL;
2143     }  
2144 }
2145
2146 static void
2147 get_paste_point (GtkTextBuffer *buffer,
2148                  GtkTextIter   *iter,
2149                  gboolean       clear_afterward)
2150 {
2151   GtkTextIter insert_point;
2152   GtkTextMark *paste_point_override;
2153
2154   paste_point_override = gtk_text_buffer_get_mark (buffer,
2155                                                    "gtk_paste_point_override");
2156
2157   if (paste_point_override != NULL)
2158     {
2159       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2160                                         paste_point_override);
2161       if (clear_afterward)
2162         gtk_text_buffer_delete_mark (buffer,
2163                                      gtk_text_buffer_get_mark (buffer,
2164                                                                "gtk_paste_point_override"));
2165     }
2166   else
2167     {
2168       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2169                                         gtk_text_buffer_get_mark (buffer,
2170                                                                   "insert"));
2171     }
2172
2173   *iter = insert_point;
2174 }
2175
2176 static void
2177 pre_paste_prep (ClipboardRequest *request_data,
2178                 GtkTextIter      *insert_point)
2179 {
2180   GtkTextBuffer *buffer = request_data->buffer;
2181   
2182   get_paste_point (buffer, insert_point, TRUE);
2183
2184   /* If we're going to replace the selection, we insert before it to
2185    * avoid messing it up, then we delete the selection after inserting.
2186    */
2187   if (request_data->replace_selection)
2188     {
2189       GtkTextIter start, end;
2190       
2191       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2192         *insert_point = start;
2193     }
2194 }
2195
2196 static void
2197 post_paste_cleanup (ClipboardRequest *request_data)
2198 {
2199   if (request_data->replace_selection)
2200     {
2201       GtkTextIter start, end;
2202       
2203       if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
2204                                                 &start, &end))
2205         {
2206           if (request_data->interactive)
2207             gtk_text_buffer_delete_interactive (request_data->buffer,
2208                                                 &start,
2209                                                 &end,
2210                                                 request_data->default_editable);
2211           else
2212             gtk_text_buffer_delete (request_data->buffer, &start, &end);
2213         }
2214     }
2215 }
2216
2217 /* Called when we request a paste and receive the text data
2218  */
2219 static void
2220 clipboard_text_received (GtkClipboard *clipboard,
2221                          const gchar  *str,
2222                          gpointer      data)
2223 {
2224   ClipboardRequest *request_data = data;
2225   GtkTextBuffer *buffer = request_data->buffer;
2226
2227   if (str)
2228     {
2229       GtkTextIter insert_point;
2230
2231       pre_paste_prep (request_data, &insert_point);
2232       
2233       if (request_data->interactive)
2234         gtk_text_buffer_insert_interactive (buffer, &insert_point,
2235                                             str, -1, request_data->default_editable);
2236       else
2237         gtk_text_buffer_insert (buffer, &insert_point,
2238                                 str, -1);
2239
2240       post_paste_cleanup (request_data);
2241     }
2242
2243   g_object_unref (G_OBJECT (buffer));
2244   g_free (request_data);
2245 }
2246
2247 static GtkTextBuffer*
2248 selection_data_get_buffer (GtkSelectionData *selection_data,
2249                            ClipboardRequest *request_data)
2250 {
2251   GdkWindow *owner;
2252   GtkTextBuffer *src_buffer = NULL;
2253
2254   /* If we can get the owner, the selection is in-process */
2255   owner = gdk_selection_owner_get (selection_data->selection);
2256
2257   if (owner == NULL)
2258     return NULL;
2259   
2260   if (selection_data->type != gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2261     return NULL;
2262
2263   if (selection_data->length != sizeof (src_buffer))
2264     return NULL;
2265           
2266   memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
2267
2268   if (src_buffer == NULL)
2269     return NULL;
2270   
2271   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
2272
2273   if (gtk_text_buffer_get_tag_table (src_buffer) !=
2274       gtk_text_buffer_get_tag_table (request_data->buffer))
2275     return NULL;
2276   
2277   return src_buffer;
2278 }
2279
2280 #if 0
2281 /* These are pretty handy functions; maybe something like them
2282  * should be in the public API. Also, there are other places in this
2283  * file where they could be used.
2284  */
2285 static gpointer
2286 save_iter (const GtkTextIter *iter,
2287            gboolean           left_gravity)
2288 {
2289   return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
2290                                       NULL,
2291                                       iter,
2292                                       TRUE);
2293 }
2294
2295 static void
2296 restore_iter (const GtkTextIter *iter,
2297               gpointer           save_id)
2298 {
2299   gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
2300                                     (GtkTextIter*) iter,
2301                                     save_id);
2302   gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
2303                                save_id);
2304 }
2305 #endif
2306
2307 static void
2308 paste_from_buffer (ClipboardRequest    *request_data,
2309                    GtkTextBuffer       *src_buffer,
2310                    const GtkTextIter   *start,
2311                    const GtkTextIter   *end)
2312 {
2313   GtkTextIter insert_point;
2314   
2315   /* We're about to emit a bunch of signals, so be safe */
2316   g_object_ref (G_OBJECT (src_buffer));
2317   
2318   pre_paste_prep (request_data, &insert_point);
2319   
2320   if (!gtk_text_iter_equal (start, end))
2321     {
2322       gtk_text_buffer_real_insert_range (request_data->buffer,
2323                                          &insert_point,
2324                                          start,
2325                                          end,
2326                                          request_data->interactive);
2327     }
2328
2329   post_paste_cleanup (request_data);
2330       
2331   g_object_unref (G_OBJECT (src_buffer));
2332 }
2333
2334 static void
2335 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
2336                                      GtkSelectionData *selection_data,
2337                                      gpointer          data)
2338 {
2339   ClipboardRequest *request_data = data;
2340   GtkTextBuffer *src_buffer;
2341   
2342   src_buffer = selection_data_get_buffer (selection_data, request_data); 
2343
2344   if (src_buffer)
2345     {
2346       GtkTextIter start, end;
2347
2348       gtk_text_buffer_get_bounds (src_buffer, &start, &end);
2349       /* There's an extra newline on clipboard_contents */
2350       gtk_text_iter_backward_char (&end);
2351       
2352       paste_from_buffer (request_data, src_buffer,
2353                          &start, &end);
2354     }
2355   else
2356     {
2357       /* Request the text selection instead */
2358       gtk_clipboard_request_text (clipboard,
2359                                   clipboard_text_received,
2360                                   data);
2361     }
2362 }
2363
2364 static void
2365 clipboard_selection_buffer_received (GtkClipboard     *clipboard,
2366                                      GtkSelectionData *selection_data,
2367                                      gpointer          data)
2368 {
2369   ClipboardRequest *request_data = data;
2370   GtkTextBuffer *src_buffer;
2371   
2372   src_buffer = selection_data_get_buffer (selection_data, request_data); 
2373
2374   if (src_buffer)
2375     {
2376       GtkTextIter start, end;
2377
2378       if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
2379         paste_from_buffer (request_data, src_buffer,
2380                            &start, &end);
2381     }
2382   else
2383     {
2384       /* Request the text selection instead */
2385       gtk_clipboard_request_text (clipboard,
2386                                   clipboard_text_received,
2387                                   data);
2388     }
2389 }
2390
2391 static const GtkTargetEntry targets[] = {
2392   { "STRING", 0, TARGET_STRING },
2393   { "TEXT",   0, TARGET_TEXT },
2394   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
2395   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
2396   { "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
2397 };
2398
2399 static void
2400 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
2401 {
2402   GtkTextIter start;
2403   GtkTextIter end;
2404
2405   GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
2406
2407   /* Determine whether we have a selection and adjust X selection
2408    * accordingly.
2409    */
2410
2411   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2412     {
2413       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
2414         gtk_clipboard_clear (clipboard);
2415     }
2416   else
2417     {
2418       /* Even if we already have the selection, we need to update our
2419        * timestamp.
2420        */
2421       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2422                                          clipboard_get_selection_cb,
2423                                          clipboard_clear_selection_cb,
2424                                          G_OBJECT (buffer)))
2425         clipboard_clear_selection_cb (clipboard, buffer);
2426     }
2427 }
2428
2429 static void
2430 paste (GtkTextBuffer *buffer,
2431        gboolean       is_clipboard,
2432        gboolean       interactive,
2433        gboolean       default_editable)
2434 {
2435   ClipboardRequest *data = g_new (ClipboardRequest, 1);
2436   GtkTextIter paste_point;
2437   GtkTextIter start, end;
2438   
2439   data->buffer = buffer;
2440   g_object_ref (G_OBJECT (buffer));
2441   data->interactive = interactive;
2442   data->default_editable = default_editable;
2443
2444   /* When pasting with the cursor inside the selection area, you
2445    * replace the selection with the new text, otherwise, you
2446    * simply insert the new text at the point where the click
2447    * occured, unselecting any selected text. The replace_selection
2448    * flag toggles this behavior.
2449    */
2450   data->replace_selection = FALSE;
2451   
2452   get_paste_point (buffer, &paste_point, FALSE);
2453   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
2454       (gtk_text_iter_in_range (&paste_point, &start, &end) ||
2455        gtk_text_iter_equal (&paste_point, &end)))
2456     data->replace_selection = TRUE;
2457
2458   if (is_clipboard)
2459     gtk_clipboard_request_contents (gtk_clipboard_get (GDK_NONE),
2460                                     
2461                                     gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2462                                     clipboard_clipboard_buffer_received, data);
2463   else
2464     gtk_clipboard_request_contents (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
2465                                     
2466                                     gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2467                                     clipboard_selection_buffer_received, data);    
2468 }
2469
2470 void
2471 gtk_text_buffer_paste_primary (GtkTextBuffer       *buffer,
2472                                const GtkTextIter   *override_location,
2473                                gboolean             default_editable)
2474 {
2475   if (override_location != NULL)
2476     gtk_text_buffer_create_mark (buffer,
2477                                  "gtk_paste_point_override",
2478                                  override_location, FALSE);
2479
2480   paste (buffer, FALSE, TRUE, default_editable);
2481 }
2482
2483 void
2484 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
2485                                  gboolean       default_editable)
2486 {
2487   paste (buffer, TRUE, TRUE, default_editable);
2488 }
2489
2490 gboolean
2491 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
2492                                   gboolean interactive,
2493                                   gboolean default_editable)
2494 {
2495   GtkTextIter start;
2496   GtkTextIter end;
2497
2498   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2499     {
2500       return FALSE; /* No selection */
2501     }
2502   else
2503     {
2504       if (interactive)
2505         gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
2506       else
2507         gtk_text_buffer_delete (buffer, &start, &end);
2508
2509       return TRUE; /* We deleted stuff */
2510     }
2511 }
2512
2513 static void
2514 cut_or_copy (GtkTextBuffer *buffer,
2515              gboolean delete_region_after,
2516              gboolean interactive,
2517              gboolean default_editable)
2518 {
2519   /* We prefer to cut the selected region between selection_bound and
2520    * insertion point. If that region is empty, then we cut the region
2521    * between the "anchor" and the insertion point (this is for
2522    * C-space and M-w and other Emacs-style copy/yank keys). Note that
2523    * insert and selection_bound are guaranteed to exist, but the
2524    * anchor only exists sometimes.
2525    */
2526   GtkTextIter start;
2527   GtkTextIter end;
2528
2529   if (buffer->clipboard_contents)
2530     {
2531       g_object_unref (G_OBJECT (buffer->clipboard_contents));
2532       buffer->clipboard_contents = NULL;
2533     }
2534   
2535   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2536     {
2537       /* Let's try the anchor thing */
2538       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
2539
2540       if (anchor == NULL)
2541         return;
2542       else
2543         {
2544           gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
2545           gtk_text_iter_reorder (&start, &end);
2546         }
2547     }
2548
2549   if (!gtk_text_iter_equal (&start, &end))
2550     {
2551       GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
2552       GtkTextIter ins;
2553       
2554       buffer->clipboard_contents =
2555         gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
2556
2557       gtk_text_buffer_get_iter_at_offset (buffer->clipboard_contents,
2558                                           &ins, 0);
2559       
2560       gtk_text_buffer_insert_range (buffer->clipboard_contents,
2561                                     &ins,
2562                                     &start,
2563                                     &end);
2564                                     
2565       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2566                                          clipboard_get_contents_cb,
2567                                          clipboard_clear_contents_cb,
2568                                          G_OBJECT (buffer)))
2569         clipboard_clear_contents_cb (clipboard, buffer);      
2570
2571       if (delete_region_after)
2572         {
2573           if (interactive)
2574             gtk_text_buffer_delete_interactive (buffer, &start, &end,
2575                                                 default_editable);
2576           else
2577             gtk_text_buffer_delete (buffer, &start, &end);
2578         }
2579     }
2580 }
2581
2582 void
2583 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
2584                                gboolean       default_editable)
2585 {
2586   cut_or_copy (buffer, TRUE, TRUE, default_editable);
2587 }
2588
2589 void
2590 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
2591 {
2592   cut_or_copy (buffer, FALSE, TRUE, TRUE);
2593 }
2594
2595
2596 /**
2597  * gtk_text_buffer_get_selection_bounds:
2598  * @buffer: a #GtkTextBuffer
2599  * @start: iterator to initialize with selection start
2600  * @end: iterator to initialize with selection end
2601  *
2602  * Returns %TRUE if some text is selected; places the bounds
2603  * of the selection in @start and @end (if the selection has length 0,
2604  * then @start and @end are filled in with the same value).
2605  * @start and @end will be in ascending order. If @start and @end are
2606  * NULL, then they are not filled in, but the return value still indicates
2607  * whether text is selected.
2608  *
2609  * Return value: whether the selection has nonzero length
2610  **/
2611 gboolean
2612 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
2613                                         GtkTextIter        *start,
2614                                         GtkTextIter        *end)
2615 {
2616   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2617
2618   return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
2619 }
2620
2621 /*
2622  * Logical attribute cache
2623  */
2624
2625 #define ATTR_CACHE_SIZE 2
2626
2627 typedef struct _CacheEntry CacheEntry;
2628 struct _CacheEntry
2629 {
2630   gint line;
2631   gint char_len;
2632   PangoLogAttr *attrs;
2633 };
2634
2635
2636 struct _GtkTextLogAttrCache
2637 {
2638   gint chars_changed_stamp;
2639   CacheEntry entries[ATTR_CACHE_SIZE];
2640 };
2641
2642 static void
2643 free_log_attr_cache (GtkTextLogAttrCache *cache)
2644 {
2645   gint i = 0;
2646   while (i < ATTR_CACHE_SIZE)
2647     {
2648       g_free (cache->entries[i].attrs);
2649       ++i;
2650     }
2651   g_free (cache);
2652 }
2653
2654 static void
2655 clear_log_attr_cache (GtkTextLogAttrCache *cache)
2656 {
2657   gint i = 0;
2658   while (i < ATTR_CACHE_SIZE)
2659     {
2660       g_free (cache->entries[i].attrs);
2661       cache->entries[i].attrs = NULL;
2662       ++i;
2663     }
2664 }
2665
2666 static PangoLogAttr*
2667 compute_log_attrs (const GtkTextIter *iter,
2668                    gint              *char_lenp)
2669 {
2670   GtkTextIter start;
2671   GtkTextIter end;
2672   gchar *paragraph;
2673   gint char_len, byte_len;
2674   PangoLogAttr *attrs = NULL;
2675   gchar *lang;
2676   
2677   start = *iter;
2678   end = *iter;
2679
2680   gtk_text_iter_set_line_offset (&start, 0);
2681   gtk_text_iter_forward_line (&end);
2682
2683   paragraph = gtk_text_iter_get_slice (&start, &end);
2684   char_len = g_utf8_strlen (paragraph, -1);
2685   byte_len = strlen (paragraph);
2686
2687   g_assert (char_len > 0);
2688
2689   if (char_lenp)
2690     *char_lenp = char_len;
2691   
2692   attrs = g_new (PangoLogAttr, char_len);
2693   
2694   lang = gtk_text_iter_get_language (&start);
2695   
2696   pango_get_log_attrs (paragraph, byte_len, -1,
2697                        lang,
2698                        attrs);
2699   
2700   g_free (lang);
2701
2702   g_free (paragraph);
2703
2704   return attrs;
2705 }
2706
2707 /* The return value from this is valid until you call this a second time.
2708  */
2709 const PangoLogAttr*
2710 _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer     *buffer,
2711                                      const GtkTextIter *anywhere_in_line,
2712                                      gint              *char_len)
2713 {
2714   gint line;
2715   GtkTextLogAttrCache *cache;
2716   gint i;
2717   
2718   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2719   g_return_val_if_fail (anywhere_in_line != NULL, NULL);
2720   g_return_val_if_fail (!gtk_text_iter_is_last (anywhere_in_line), NULL);
2721
2722   /* FIXME we also need to recompute log attrs if the language tag at
2723    * the start of a paragraph changes
2724    */
2725   
2726   if (buffer->log_attr_cache == NULL)
2727     {
2728       buffer->log_attr_cache = g_new0 (GtkTextLogAttrCache, 1);
2729       buffer->log_attr_cache->chars_changed_stamp =
2730         gtk_text_btree_get_chars_changed_stamp (get_btree (buffer));
2731     }
2732   else if (buffer->log_attr_cache->chars_changed_stamp !=
2733            gtk_text_btree_get_chars_changed_stamp (get_btree (buffer)))
2734     {
2735       clear_log_attr_cache (buffer->log_attr_cache);
2736     }
2737   
2738   cache = buffer->log_attr_cache;
2739   line = gtk_text_iter_get_line (anywhere_in_line);
2740
2741   i = 0;
2742   while (i < ATTR_CACHE_SIZE)
2743     {
2744       if (cache->entries[i].attrs &&
2745           cache->entries[i].line == line)
2746         {
2747           if (char_len)
2748             *char_len = cache->entries[i].char_len;
2749           return cache->entries[i].attrs;
2750         }
2751       ++i;
2752     }
2753   
2754   /* Not in cache; open up the first cache entry */
2755   if (cache->entries[ATTR_CACHE_SIZE-1].attrs)
2756     g_free (cache->entries[ATTR_CACHE_SIZE-1].attrs);
2757   
2758   g_memmove (cache->entries + 1, cache->entries,
2759              sizeof (CacheEntry) * (ATTR_CACHE_SIZE - 1));
2760
2761   cache->entries[0].line = line;
2762   cache->entries[0].attrs = compute_log_attrs (anywhere_in_line,
2763                                                &cache->entries[0].char_len);
2764
2765   if (char_len)
2766     *char_len = cache->entries[0].char_len;
2767   
2768   return cache->entries[0].attrs;
2769 }
2770
2771 /*
2772  * Debug spew
2773  */
2774
2775 void
2776 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
2777 {
2778   gtk_text_btree_spew (get_btree (buffer));
2779 }
2780
2781
2782
2783
2784