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