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