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