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