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