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