]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
Merge branch 'master' into toolpalette
[~andy/gtk] / gtk / gtktextbuffer.c
1 /* GTK - The GIMP Toolkit
2  * gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
3  *                 Copyright (C) 2004 Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26  */
27
28 #include "config.h"
29 #include <string.h>
30 #include <stdarg.h>
31
32 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
33 #include "gtkclipboard.h"
34 #include "gtkdnd.h"
35 #include "gtkinvisible.h"
36 #include "gtkmarshalers.h"
37 #include "gtktextbuffer.h"
38 #include "gtktextbufferrichtext.h"
39 #include "gtktextbtree.h"
40 #include "gtktextiterprivate.h"
41 #include "gtkprivate.h"
42 #include "gtkintl.h"
43 #include "gtkalias.h"
44
45
46 #define GTK_TEXT_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_BUFFER, GtkTextBufferPrivate))
47
48 typedef struct _GtkTextBufferPrivate GtkTextBufferPrivate;
49
50 struct _GtkTextBufferPrivate
51 {
52   GtkTargetList  *copy_target_list;
53   GtkTargetEntry *copy_target_entries;
54   gint            n_copy_target_entries;
55
56   GtkTargetList  *paste_target_list;
57   GtkTargetEntry *paste_target_entries;
58   gint            n_paste_target_entries;
59 };
60
61
62 typedef struct _ClipboardRequest ClipboardRequest;
63
64 struct _ClipboardRequest
65 {
66   GtkTextBuffer *buffer;
67   gboolean interactive;
68   gboolean default_editable;
69   gboolean is_clipboard;
70   gboolean replace_selection;
71 };
72
73 enum {
74   INSERT_TEXT,
75   INSERT_PIXBUF,
76   INSERT_CHILD_ANCHOR,
77   DELETE_RANGE,
78   CHANGED,
79   MODIFIED_CHANGED,
80   MARK_SET,
81   MARK_DELETED,
82   APPLY_TAG,
83   REMOVE_TAG,
84   BEGIN_USER_ACTION,
85   END_USER_ACTION,
86   PASTE_DONE,
87   LAST_SIGNAL
88 };
89
90 enum {
91   PROP_0,
92
93   /* Construct */
94   PROP_TAG_TABLE,
95
96   /* Normal */
97   PROP_TEXT,
98   PROP_HAS_SELECTION,
99   PROP_CURSOR_POSITION,
100   PROP_COPY_TARGET_LIST,
101   PROP_PASTE_TARGET_LIST
102 };
103
104 static void gtk_text_buffer_finalize   (GObject            *object);
105
106 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
107                                                         GtkTextIter       *iter,
108                                                         const gchar       *text,
109                                                         gint               len);
110 static void gtk_text_buffer_real_insert_pixbuf         (GtkTextBuffer     *buffer,
111                                                         GtkTextIter       *iter,
112                                                         GdkPixbuf         *pixbuf);
113 static void gtk_text_buffer_real_insert_anchor         (GtkTextBuffer     *buffer,
114                                                         GtkTextIter       *iter,
115                                                         GtkTextChildAnchor *anchor);
116 static void gtk_text_buffer_real_delete_range          (GtkTextBuffer     *buffer,
117                                                         GtkTextIter       *start,
118                                                         GtkTextIter       *end);
119 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
120                                                         GtkTextTag        *tag,
121                                                         const GtkTextIter *start_char,
122                                                         const GtkTextIter *end_char);
123 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
124                                                         GtkTextTag        *tag,
125                                                         const GtkTextIter *start_char,
126                                                         const GtkTextIter *end_char);
127 static void gtk_text_buffer_real_changed               (GtkTextBuffer     *buffer);
128 static void gtk_text_buffer_real_mark_set              (GtkTextBuffer     *buffer,
129                                                         const GtkTextIter *iter,
130                                                         GtkTextMark       *mark);
131
132 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
133 static void          free_log_attr_cache (GtkTextLogAttrCache *cache);
134
135 static void remove_all_selection_clipboards       (GtkTextBuffer *buffer);
136 static void update_selection_clipboards           (GtkTextBuffer *buffer);
137
138 static GtkTextBuffer *create_clipboard_contents_buffer (GtkTextBuffer *buffer);
139
140 static void gtk_text_buffer_free_target_lists     (GtkTextBuffer *buffer);
141
142 static guint signals[LAST_SIGNAL] = { 0 };
143
144 static void gtk_text_buffer_set_property (GObject         *object,
145                                           guint            prop_id,
146                                           const GValue    *value,
147                                           GParamSpec      *pspec);
148 static void gtk_text_buffer_get_property (GObject         *object,
149                                           guint            prop_id,
150                                           GValue          *value,
151                                           GParamSpec      *pspec);
152 static void gtk_text_buffer_notify       (GObject         *object,
153                                           GParamSpec      *pspec);
154
155 G_DEFINE_TYPE (GtkTextBuffer, gtk_text_buffer, G_TYPE_OBJECT)
156
157 static void
158 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
159 {
160   GObjectClass *object_class = G_OBJECT_CLASS (klass);
161
162   object_class->finalize = gtk_text_buffer_finalize;
163   object_class->set_property = gtk_text_buffer_set_property;
164   object_class->get_property = gtk_text_buffer_get_property;
165   object_class->notify       = gtk_text_buffer_notify;
166  
167   klass->insert_text = gtk_text_buffer_real_insert_text;
168   klass->insert_pixbuf = gtk_text_buffer_real_insert_pixbuf;
169   klass->insert_child_anchor = gtk_text_buffer_real_insert_anchor;
170   klass->delete_range = gtk_text_buffer_real_delete_range;
171   klass->apply_tag = gtk_text_buffer_real_apply_tag;
172   klass->remove_tag = gtk_text_buffer_real_remove_tag;
173   klass->changed = gtk_text_buffer_real_changed;
174   klass->mark_set = gtk_text_buffer_real_mark_set;
175
176   /* Construct */
177   g_object_class_install_property (object_class,
178                                    PROP_TAG_TABLE,
179                                    g_param_spec_object ("tag-table",
180                                                         P_("Tag Table"),
181                                                         P_("Text Tag Table"),
182                                                         GTK_TYPE_TEXT_TAG_TABLE,
183                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
184
185   /* Normal properties*/
186   
187   /**
188    * GtkTextBuffer:text:
189    *
190    * The text content of the buffer. Without child widgets and images,
191    * see gtk_text_buffer_get_text() for more information.
192    *
193    * Since: 2.8
194    */
195   g_object_class_install_property (object_class,
196                                    PROP_TEXT,
197                                    g_param_spec_string ("text",
198                                                         P_("Text"),
199                                                         P_("Current text of the buffer"),
200                                                         "",
201                                                         GTK_PARAM_READWRITE));
202
203   /**
204    * GtkTextBuffer:has-selection:
205    *
206    * Whether the buffer has some text currently selected.
207    *
208    * Since: 2.10
209    */
210   g_object_class_install_property (object_class,
211                                    PROP_HAS_SELECTION,
212                                    g_param_spec_boolean ("has-selection",
213                                                          P_("Has selection"),
214                                                          P_("Whether the buffer has some text currently selected"),
215                                                          FALSE,
216                                                          GTK_PARAM_READABLE));
217
218   /**
219    * GtkTextBuffer:cursor-position:
220    *
221    * The position of the insert mark (as offset from the beginning 
222    * of the buffer). It is useful for getting notified when the 
223    * cursor moves.
224    *
225    * Since: 2.10
226    */
227   g_object_class_install_property (object_class,
228                                    PROP_CURSOR_POSITION,
229                                    g_param_spec_int ("cursor-position",
230                                                      P_("Cursor position"),
231                                                      P_("The position of the insert mark (as offset from the beginning of the buffer)"),
232                                                      0, G_MAXINT, 0,
233                                                      GTK_PARAM_READABLE));
234
235   /**
236    * GtkTextBuffer:copy-target-list:
237    *
238    * The list of targets this buffer supports for clipboard copying
239    * and as DND source.
240    *
241    * Since: 2.10
242    */
243   g_object_class_install_property (object_class,
244                                    PROP_COPY_TARGET_LIST,
245                                    g_param_spec_boxed ("copy-target-list",
246                                                        P_("Copy target list"),
247                                                        P_("The list of targets this buffer supports for clipboard copying and DND source"),
248                                                        GTK_TYPE_TARGET_LIST,
249                                                        GTK_PARAM_READABLE));
250
251   /**
252    * GtkTextBuffer:paste-target-list:
253    *
254    * The list of targets this buffer supports for clipboard pasting
255    * and as DND destination.
256    *
257    * Since: 2.10
258    */
259   g_object_class_install_property (object_class,
260                                    PROP_PASTE_TARGET_LIST,
261                                    g_param_spec_boxed ("paste-target-list",
262                                                        P_("Paste target list"),
263                                                        P_("The list of targets this buffer supports for clipboard pasting and DND destination"),
264                                                        GTK_TYPE_TARGET_LIST,
265                                                        GTK_PARAM_READABLE));
266
267   /**
268    * GtkTextBuffer::insert-text:
269    * @textbuffer: the object which received the signal
270    * @location: position to insert @text in @textbuffer
271    * @text: the UTF-8 text to be inserted
272    * @len: length of the inserted text in bytes
273    * 
274    * The ::insert-text signal is emitted to insert text in a #GtkTextBuffer.
275    * Insertion actually occurs in the default handler.  
276    * 
277    * Note that if your handler runs before the default handler it must not 
278    * invalidate the @location iter (or has to revalidate it). 
279    * The default signal handler revalidates it to point to the end of the 
280    * inserted text.
281    * 
282    * See also: 
283    * gtk_text_buffer_insert(), 
284    * gtk_text_buffer_insert_range().
285    */
286   signals[INSERT_TEXT] =
287     g_signal_new (I_("insert-text"),
288                   G_OBJECT_CLASS_TYPE (object_class),
289                   G_SIGNAL_RUN_LAST,
290                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_text),
291                   NULL, NULL,
292                   _gtk_marshal_VOID__BOXED_STRING_INT,
293                   G_TYPE_NONE,
294                   3,
295                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
296                   G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
297                   G_TYPE_INT);
298
299   /**
300    * GtkTextBuffer::insert-pixbuf:
301    * @textbuffer: the object which received the signal
302    * @location: position to insert @pixbuf in @textbuffer
303    * @pixbuf: the #GdkPixbuf to be inserted
304    * 
305    * The ::insert-pixbuf signal is emitted to insert a #GdkPixbuf 
306    * in a #GtkTextBuffer. Insertion actually occurs in the default handler.
307    * 
308    * Note that if your handler runs before the default handler it must not 
309    * invalidate the @location iter (or has to revalidate it). 
310    * The default signal handler revalidates it to be placed after the 
311    * inserted @pixbuf.
312    * 
313    * See also: gtk_text_buffer_insert_pixbuf().
314    */
315   signals[INSERT_PIXBUF] =
316     g_signal_new (I_("insert-pixbuf"),
317                   G_OBJECT_CLASS_TYPE (object_class),
318                   G_SIGNAL_RUN_LAST,
319                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_pixbuf),
320                   NULL, NULL,
321                   _gtk_marshal_VOID__BOXED_OBJECT,
322                   G_TYPE_NONE,
323                   2,
324                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
325                   GDK_TYPE_PIXBUF);
326
327
328   /**
329    * GtkTextBuffer::insert-child-anchor:
330    * @textbuffer: the object which received the signal
331    * @location: position to insert @anchor in @textbuffer
332    * @anchor: the #GtkTextChildAnchor to be inserted
333    * 
334    * The ::insert-child-anchor signal is emitted to insert a
335    * #GtkTextChildAnchor in a #GtkTextBuffer.
336    * Insertion actually occurs in the default handler.
337    * 
338    * Note that if your handler runs before the default handler it must
339    * not invalidate the @location iter (or has to revalidate it). 
340    * The default signal handler revalidates it to be placed after the 
341    * inserted @anchor.
342    * 
343    * See also: gtk_text_buffer_insert_child_anchor().
344    */
345   signals[INSERT_CHILD_ANCHOR] =
346     g_signal_new (I_("insert-child-anchor"),
347                   G_OBJECT_CLASS_TYPE (object_class),
348                   G_SIGNAL_RUN_LAST,
349                   G_STRUCT_OFFSET (GtkTextBufferClass, insert_child_anchor),
350                   NULL, NULL,
351                   _gtk_marshal_VOID__BOXED_OBJECT,
352                   G_TYPE_NONE,
353                   2,
354                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
355                   GTK_TYPE_TEXT_CHILD_ANCHOR);
356   
357   /**
358    * GtkTextBuffer::delete-range:
359    * @textbuffer: the object which received the signal
360    * @start: the start of the range to be deleted
361    * @end: the end of the range to be deleted
362    * 
363    * The ::delete-range signal is emitted to delete a range 
364    * from a #GtkTextBuffer. 
365    * 
366    * Note that if your handler runs before the default handler it must not 
367    * invalidate the @start and @end iters (or has to revalidate them). 
368    * The default signal handler revalidates the @start and @end iters to 
369    * both point point to the location where text was deleted. Handlers
370    * which run after the default handler (see g_signal_connect_after())
371    * do not have access to the deleted text.
372    * 
373    * See also: gtk_text_buffer_delete().
374    */
375   signals[DELETE_RANGE] =
376     g_signal_new (I_("delete-range"),
377                   G_OBJECT_CLASS_TYPE (object_class),
378                   G_SIGNAL_RUN_LAST,
379                   G_STRUCT_OFFSET (GtkTextBufferClass, delete_range),
380                   NULL, NULL,
381                   _gtk_marshal_VOID__BOXED_BOXED,
382                   G_TYPE_NONE,
383                   2,
384                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
385                   GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
386
387   /**
388    * GtkTextBuffer::changed:
389    * @textbuffer: the object which received the signal
390    * 
391    * The ::changed signal is emitted when the content of a #GtkTextBuffer 
392    * has changed.
393    */
394   signals[CHANGED] =
395     g_signal_new (I_("changed"),
396                   G_OBJECT_CLASS_TYPE (object_class),
397                   G_SIGNAL_RUN_LAST,                   
398                   G_STRUCT_OFFSET (GtkTextBufferClass, changed),
399                   NULL, NULL,
400                   _gtk_marshal_VOID__VOID,
401                   G_TYPE_NONE,
402                   0);
403
404   /**
405    * GtkTextBuffer::modified-changed:
406    * @textbuffer: the object which received the signal
407    * 
408    * The ::modified-changed signal is emitted when the modified bit of a 
409    * #GtkTextBuffer flips.
410    * 
411    * See also:
412    * gtk_text_buffer_set_modified().
413    */
414   signals[MODIFIED_CHANGED] =
415     g_signal_new (I_("modified-changed"),
416                   G_OBJECT_CLASS_TYPE (object_class),
417                   G_SIGNAL_RUN_LAST,
418                   G_STRUCT_OFFSET (GtkTextBufferClass, modified_changed),
419                   NULL, NULL,
420                   _gtk_marshal_VOID__VOID,
421                   G_TYPE_NONE,
422                   0);
423
424   /**
425    * GtkTextBuffer::mark-set:
426    * @textbuffer: the object which received the signal
427    * @location: The location of @mark in @textbuffer
428    * @mark: The mark that is set
429    * 
430    * The ::mark-set signal is emitted as notification
431    * after a #GtkTextMark is set.
432    * 
433    * See also: 
434    * gtk_text_buffer_create_mark(),
435    * gtk_text_buffer_move_mark().
436    */
437   signals[MARK_SET] =
438     g_signal_new (I_("mark-set"),
439                   G_OBJECT_CLASS_TYPE (object_class),
440                   G_SIGNAL_RUN_LAST,                   
441                   G_STRUCT_OFFSET (GtkTextBufferClass, mark_set),
442                   NULL, NULL,
443                   _gtk_marshal_VOID__BOXED_OBJECT,
444                   G_TYPE_NONE,
445                   2,
446                   GTK_TYPE_TEXT_ITER,
447                   GTK_TYPE_TEXT_MARK);
448
449   /**
450    * GtkTextBuffer::mark-deleted:
451    * @textbuffer: the object which received the signal
452    * @mark: The mark that was deleted
453    * 
454    * The ::mark-deleted signal is emitted as notification
455    * after a #GtkTextMark is deleted. 
456    * 
457    * See also:
458    * gtk_text_buffer_delete_mark().
459    */
460   signals[MARK_DELETED] =
461     g_signal_new (I_("mark-deleted"),
462                   G_OBJECT_CLASS_TYPE (object_class),
463                   G_SIGNAL_RUN_LAST,                   
464                   G_STRUCT_OFFSET (GtkTextBufferClass, mark_deleted),
465                   NULL, NULL,
466                   _gtk_marshal_VOID__OBJECT,
467                   G_TYPE_NONE,
468                   1,
469                   GTK_TYPE_TEXT_MARK);
470
471    /**
472    * GtkTextBuffer::apply-tag:
473    * @textbuffer: the object which received the signal
474    * @tag: the applied tag
475    * @start: the start of the range the tag is applied to
476    * @end: the end of the range the tag is applied to
477    * 
478    * The ::apply-tag signal is emitted to apply a tag to a
479    * range of text in a #GtkTextBuffer. 
480    * Applying actually occurs in the default handler.
481    * 
482    * Note that if your handler runs before the default handler it must not 
483    * invalidate the @start and @end iters (or has to revalidate them). 
484    * 
485    * See also: 
486    * gtk_text_buffer_apply_tag(),
487    * gtk_text_buffer_insert_with_tags(),
488    * gtk_text_buffer_insert_range().
489    */ 
490   signals[APPLY_TAG] =
491     g_signal_new (I_("apply-tag"),
492                   G_OBJECT_CLASS_TYPE (object_class),
493                   G_SIGNAL_RUN_LAST,
494                   G_STRUCT_OFFSET (GtkTextBufferClass, apply_tag),
495                   NULL, NULL,
496                   _gtk_marshal_VOID__OBJECT_BOXED_BOXED,
497                   G_TYPE_NONE,
498                   3,
499                   GTK_TYPE_TEXT_TAG,
500                   GTK_TYPE_TEXT_ITER,
501                   GTK_TYPE_TEXT_ITER);
502
503
504    /**
505    * GtkTextBuffer::remove-tag:
506    * @textbuffer: the object which received the signal
507    * @tag: the tag to be removed
508    * @start: the start of the range the tag is removed from
509    * @end: the end of the range the tag is removed from
510    * 
511    * The ::remove-tag signal is emitted to remove all occurrences of @tag from
512    * a range of text in a #GtkTextBuffer. 
513    * Removal actually occurs in the default handler.
514    * 
515    * Note that if your handler runs before the default handler it must not 
516    * invalidate the @start and @end iters (or has to revalidate them). 
517    * 
518    * See also: 
519    * gtk_text_buffer_remove_tag(). 
520    */ 
521   signals[REMOVE_TAG] =
522     g_signal_new (I_("remove-tag"),
523                   G_OBJECT_CLASS_TYPE (object_class),
524                   G_SIGNAL_RUN_LAST,
525                   G_STRUCT_OFFSET (GtkTextBufferClass, remove_tag),
526                   NULL, NULL,
527                   _gtk_marshal_VOID__OBJECT_BOXED_BOXED,
528                   G_TYPE_NONE,
529                   3,
530                   GTK_TYPE_TEXT_TAG,
531                   GTK_TYPE_TEXT_ITER,
532                   GTK_TYPE_TEXT_ITER);
533
534    /**
535    * GtkTextBuffer::begin-user-action:
536    * @textbuffer: the object which received the signal
537    * 
538    * The ::begin-user-action signal is emitted at the beginning of a single
539    * user-visible operation on a #GtkTextBuffer.
540    * 
541    * See also: 
542    * gtk_text_buffer_begin_user_action(),
543    * gtk_text_buffer_insert_interactive(),
544    * gtk_text_buffer_insert_range_interactive(),
545    * gtk_text_buffer_delete_interactive(),
546    * gtk_text_buffer_backspace(),
547    * gtk_text_buffer_delete_selection().
548    */ 
549   signals[BEGIN_USER_ACTION] =
550     g_signal_new (I_("begin-user-action"),
551                   G_OBJECT_CLASS_TYPE (object_class),
552                   G_SIGNAL_RUN_LAST,                   
553                   G_STRUCT_OFFSET (GtkTextBufferClass, begin_user_action),
554                   NULL, NULL,
555                   _gtk_marshal_VOID__VOID,
556                   G_TYPE_NONE,
557                   0);
558
559    /**
560    * GtkTextBuffer::end-user-action:
561    * @textbuffer: the object which received the signal
562    * 
563    * The ::end-user-action signal is emitted at the end of a single
564    * user-visible operation on the #GtkTextBuffer.
565    * 
566    * See also: 
567    * gtk_text_buffer_end_user_action(),
568    * gtk_text_buffer_insert_interactive(),
569    * gtk_text_buffer_insert_range_interactive(),
570    * gtk_text_buffer_delete_interactive(),
571    * gtk_text_buffer_backspace(),
572    * gtk_text_buffer_delete_selection(),
573    * gtk_text_buffer_backspace().
574    */ 
575   signals[END_USER_ACTION] =
576     g_signal_new (I_("end-user-action"),
577                   G_OBJECT_CLASS_TYPE (object_class),
578                   G_SIGNAL_RUN_LAST,                   
579                   G_STRUCT_OFFSET (GtkTextBufferClass, end_user_action),
580                   NULL, NULL,
581                   _gtk_marshal_VOID__VOID,
582                   G_TYPE_NONE,
583                   0);
584
585    /**
586    * GtkTextBuffer::paste-done:
587    * @textbuffer: the object which received the signal
588    * 
589    * The paste-done signal is emitted after paste operation has been completed.
590    * This is useful to properly scroll the view to the end of the pasted text.
591    * See gtk_text_buffer_paste_clipboard() for more details.
592    * 
593    * Since: 2.16
594    */ 
595   signals[PASTE_DONE] =
596     g_signal_new (I_("paste-done"),
597                   G_OBJECT_CLASS_TYPE (object_class),
598                   G_SIGNAL_RUN_LAST,
599                   G_STRUCT_OFFSET (GtkTextBufferClass, paste_done),
600                   NULL, NULL,
601                   _gtk_marshal_VOID__OBJECT,
602                   G_TYPE_NONE,
603                   1,
604                   GTK_TYPE_CLIPBOARD);
605
606   g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
607 }
608
609 static void
610 gtk_text_buffer_init (GtkTextBuffer *buffer)
611 {
612   buffer->clipboard_contents_buffers = NULL;
613   buffer->tag_table = NULL;
614
615   /* allow copying of arbiatray stuff in the internal rich text format */
616   gtk_text_buffer_register_serialize_tagset (buffer, NULL);
617 }
618
619 static void
620 set_table (GtkTextBuffer *buffer, GtkTextTagTable *table)
621 {
622   g_return_if_fail (buffer->tag_table == NULL);
623
624   if (table)
625     {
626       buffer->tag_table = table;
627       g_object_ref (buffer->tag_table);
628       _gtk_text_tag_table_add_buffer (table, buffer);
629     }
630 }
631
632 static GtkTextTagTable*
633 get_table (GtkTextBuffer *buffer)
634 {
635   if (buffer->tag_table == NULL)
636     {
637       buffer->tag_table = gtk_text_tag_table_new ();
638       _gtk_text_tag_table_add_buffer (buffer->tag_table, buffer);
639     }
640
641   return buffer->tag_table;
642 }
643
644 static void
645 gtk_text_buffer_set_property (GObject         *object,
646                               guint            prop_id,
647                               const GValue    *value,
648                               GParamSpec      *pspec)
649 {
650   GtkTextBuffer *text_buffer;
651
652   text_buffer = GTK_TEXT_BUFFER (object);
653
654   switch (prop_id)
655     {
656     case PROP_TAG_TABLE:
657       set_table (text_buffer, g_value_get_object (value));
658       break;
659
660     case PROP_TEXT:
661       gtk_text_buffer_set_text (text_buffer,
662                                 g_value_get_string (value), -1);
663       break;
664
665     default:
666       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667       break;
668     }
669 }
670
671 static void
672 gtk_text_buffer_get_property (GObject         *object,
673                               guint            prop_id,
674                               GValue          *value,
675                               GParamSpec      *pspec)
676 {
677   GtkTextBuffer *text_buffer;
678   GtkTextIter iter;
679
680   text_buffer = GTK_TEXT_BUFFER (object);
681
682   switch (prop_id)
683     {
684     case PROP_TAG_TABLE:
685       g_value_set_object (value, get_table (text_buffer));
686       break;
687
688     case PROP_TEXT:
689       {
690         GtkTextIter start, end;
691
692         gtk_text_buffer_get_start_iter (text_buffer, &start);
693         gtk_text_buffer_get_end_iter (text_buffer, &end);
694
695         g_value_take_string (value,
696                             gtk_text_buffer_get_text (text_buffer,
697                                                       &start, &end, FALSE));
698         break;
699       }
700
701     case PROP_HAS_SELECTION:
702       g_value_set_boolean (value, text_buffer->has_selection);
703       break;
704
705     case PROP_CURSOR_POSITION:
706       gtk_text_buffer_get_iter_at_mark (text_buffer, &iter, 
707                                         gtk_text_buffer_get_insert (text_buffer));
708       g_value_set_int (value, gtk_text_iter_get_offset (&iter));
709       break;
710
711     case PROP_COPY_TARGET_LIST:
712       g_value_set_boxed (value, gtk_text_buffer_get_copy_target_list (text_buffer));
713       break;
714
715     case PROP_PASTE_TARGET_LIST:
716       g_value_set_boxed (value, gtk_text_buffer_get_paste_target_list (text_buffer));
717       break;
718
719     default:
720       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
721       break;
722     }
723 }
724
725 static void
726 gtk_text_buffer_notify (GObject    *object,
727                         GParamSpec *pspec)
728 {
729   if (!strcmp (pspec->name, "copy-target-list") ||
730       !strcmp (pspec->name, "paste-target-list"))
731     {
732       gtk_text_buffer_free_target_lists (GTK_TEXT_BUFFER (object));
733     }
734 }
735
736 /**
737  * gtk_text_buffer_new:
738  * @table: a tag table, or %NULL to create a new one
739  *
740  * Creates a new text buffer.
741  *
742  * Return value: a new text buffer
743  **/
744 GtkTextBuffer*
745 gtk_text_buffer_new (GtkTextTagTable *table)
746 {
747   GtkTextBuffer *text_buffer;
748
749   text_buffer = g_object_new (GTK_TYPE_TEXT_BUFFER, "tag-table", table, NULL);
750
751   return text_buffer;
752 }
753
754 static void
755 gtk_text_buffer_finalize (GObject *object)
756 {
757   GtkTextBuffer *buffer;
758
759   buffer = GTK_TEXT_BUFFER (object);
760
761   remove_all_selection_clipboards (buffer);
762
763   if (buffer->tag_table)
764     {
765       _gtk_text_tag_table_remove_buffer (buffer->tag_table, buffer);
766       g_object_unref (buffer->tag_table);
767       buffer->tag_table = NULL;
768     }
769
770   if (buffer->btree)
771     {
772       _gtk_text_btree_unref (buffer->btree);
773       buffer->btree = NULL;
774     }
775
776   if (buffer->log_attr_cache)
777     free_log_attr_cache (buffer->log_attr_cache);
778
779   buffer->log_attr_cache = NULL;
780
781   gtk_text_buffer_free_target_lists (buffer);
782
783   G_OBJECT_CLASS (gtk_text_buffer_parent_class)->finalize (object);
784 }
785
786 static GtkTextBTree*
787 get_btree (GtkTextBuffer *buffer)
788 {
789   if (buffer->btree == NULL)
790     buffer->btree = _gtk_text_btree_new (gtk_text_buffer_get_tag_table (buffer),
791                                          buffer);
792
793   return buffer->btree;
794 }
795
796 GtkTextBTree*
797 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
798 {
799   return get_btree (buffer);
800 }
801
802 /**
803  * gtk_text_buffer_get_tag_table:
804  * @buffer: a #GtkTextBuffer
805  *
806  * Get the #GtkTextTagTable associated with this buffer.
807  *
808  * Return value: the buffer's tag table
809  **/
810 GtkTextTagTable*
811 gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer)
812 {
813   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
814
815   return get_table (buffer);
816 }
817
818 /**
819  * gtk_text_buffer_set_text:
820  * @buffer: a #GtkTextBuffer
821  * @text: UTF-8 text to insert
822  * @len: length of @text in bytes
823  *
824  * Deletes current contents of @buffer, and inserts @text instead. If
825  * @len is -1, @text must be nul-terminated. @text must be valid UTF-8.
826  **/
827 void
828 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
829                           const gchar   *text,
830                           gint           len)
831 {
832   GtkTextIter start, end;
833
834   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
835   g_return_if_fail (text != NULL);
836
837   if (len < 0)
838     len = strlen (text);
839
840   gtk_text_buffer_get_bounds (buffer, &start, &end);
841
842   gtk_text_buffer_delete (buffer, &start, &end);
843
844   if (len > 0)
845     {
846       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
847       gtk_text_buffer_insert (buffer, &start, text, len);
848     }
849   
850   g_object_notify (G_OBJECT (buffer), "text");
851 }
852
853  
854
855 /*
856  * Insertion
857  */
858
859 static void
860 gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
861                                   GtkTextIter   *iter,
862                                   const gchar   *text,
863                                   gint           len)
864 {
865   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
866   g_return_if_fail (iter != NULL);
867   
868   _gtk_text_btree_insert (iter, text, len);
869
870   g_signal_emit (buffer, signals[CHANGED], 0);
871   g_object_notify (G_OBJECT (buffer), "cursor-position");
872 }
873
874 static void
875 gtk_text_buffer_emit_insert (GtkTextBuffer *buffer,
876                              GtkTextIter   *iter,
877                              const gchar   *text,
878                              gint           len)
879 {
880   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
881   g_return_if_fail (iter != NULL);
882   g_return_if_fail (text != NULL);
883
884   if (len < 0)
885     len = strlen (text);
886
887   g_return_if_fail (g_utf8_validate (text, len, NULL));
888   
889   if (len > 0)
890     {
891       g_signal_emit (buffer, signals[INSERT_TEXT], 0,
892                      iter, text, len);
893     }
894 }
895
896 /**
897  * gtk_text_buffer_insert:
898  * @buffer: a #GtkTextBuffer
899  * @iter: a position in the buffer
900  * @text: UTF-8 format text to insert
901  * @len: length of text in bytes, or -1
902  *
903  * Inserts @len bytes of @text at position @iter.  If @len is -1,
904  * @text must be nul-terminated and will be inserted in its
905  * entirety. Emits the "insert-text" signal; insertion actually occurs
906  * in the default handler for the signal. @iter is invalidated when
907  * insertion occurs (because the buffer contents change), but the
908  * default signal handler revalidates it to point to the end of the
909  * inserted text.
910  **/
911 void
912 gtk_text_buffer_insert (GtkTextBuffer *buffer,
913                         GtkTextIter   *iter,
914                         const gchar   *text,
915                         gint           len)
916 {
917   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
918   g_return_if_fail (iter != NULL);
919   g_return_if_fail (text != NULL);
920   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
921   
922   gtk_text_buffer_emit_insert (buffer, iter, text, len);
923 }
924
925 /**
926  * gtk_text_buffer_insert_at_cursor:
927  * @buffer: a #GtkTextBuffer
928  * @text: some text in UTF-8 format
929  * @len: length of text, in bytes
930  *
931  * Simply calls gtk_text_buffer_insert(), using the current
932  * cursor position as the insertion point.
933  **/
934 void
935 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
936                                   const gchar   *text,
937                                   gint           len)
938 {
939   GtkTextIter iter;
940
941   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
942   g_return_if_fail (text != NULL);
943
944   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
945                                     gtk_text_buffer_get_insert (buffer));
946
947   gtk_text_buffer_insert (buffer, &iter, text, len);
948 }
949
950 /**
951  * gtk_text_buffer_insert_interactive:
952  * @buffer: a #GtkTextBuffer
953  * @iter: a position in @buffer
954  * @text: some UTF-8 text
955  * @len: length of text in bytes, or -1
956  * @default_editable: default editability of buffer
957  *
958  * Like gtk_text_buffer_insert(), but the insertion will not occur if
959  * @iter is at a non-editable location in the buffer. Usually you
960  * want to prevent insertions at ineditable locations if the insertion
961  * results from a user action (is interactive).
962  *
963  * @default_editable indicates the editability of text that doesn't
964  * have a tag affecting editability applied to it. Typically the
965  * result of gtk_text_view_get_editable() is appropriate here.
966  *
967  * Return value: whether text was actually inserted
968  **/
969 gboolean
970 gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer,
971                                     GtkTextIter   *iter,
972                                     const gchar   *text,
973                                     gint           len,
974                                     gboolean       default_editable)
975 {
976   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
977   g_return_val_if_fail (text != NULL, FALSE);
978   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, FALSE);
979
980   if (gtk_text_iter_can_insert (iter, default_editable))
981     {
982       gtk_text_buffer_begin_user_action (buffer);
983       gtk_text_buffer_emit_insert (buffer, iter, text, len);
984       gtk_text_buffer_end_user_action (buffer);
985       return TRUE;
986     }
987   else
988     return FALSE;
989 }
990
991 /**
992  * gtk_text_buffer_insert_interactive_at_cursor:
993  * @buffer: a #GtkTextBuffer
994  * @text: text in UTF-8 format
995  * @len: length of text in bytes, or -1
996  * @default_editable: default editability of buffer
997  *
998  * Calls gtk_text_buffer_insert_interactive() at the cursor
999  * position.
1000  *
1001  * @default_editable indicates the editability of text that doesn't
1002  * have a tag affecting editability applied to it. Typically the
1003  * result of gtk_text_view_get_editable() is appropriate here.
1004  * 
1005  * Return value: whether text was actually inserted
1006  **/
1007 gboolean
1008 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
1009                                               const gchar   *text,
1010                                               gint           len,
1011                                               gboolean       default_editable)
1012 {
1013   GtkTextIter iter;
1014
1015   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1016   g_return_val_if_fail (text != NULL, FALSE);
1017
1018   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
1019                                     gtk_text_buffer_get_insert (buffer));
1020
1021   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
1022                                              default_editable);
1023 }
1024
1025 static gboolean
1026 possibly_not_text (gunichar ch,
1027                    gpointer user_data)
1028 {
1029   return ch == GTK_TEXT_UNKNOWN_CHAR;
1030 }
1031
1032 static void
1033 insert_text_range (GtkTextBuffer     *buffer,
1034                    GtkTextIter       *iter,
1035                    const GtkTextIter *orig_start,
1036                    const GtkTextIter *orig_end,
1037                    gboolean           interactive)
1038 {
1039   gchar *text;
1040
1041   text = gtk_text_iter_get_text (orig_start, orig_end);
1042
1043   gtk_text_buffer_emit_insert (buffer, iter, text, -1);
1044
1045   g_free (text);
1046 }
1047
1048 typedef struct _Range Range;
1049 struct _Range
1050 {
1051   GtkTextBuffer *buffer;
1052   GtkTextMark *start_mark;
1053   GtkTextMark *end_mark;
1054   GtkTextMark *whole_end_mark;
1055   GtkTextIter *range_start;
1056   GtkTextIter *range_end;
1057   GtkTextIter *whole_end;
1058 };
1059
1060 static Range*
1061 save_range (GtkTextIter *range_start,
1062             GtkTextIter *range_end,
1063             GtkTextIter *whole_end)
1064 {
1065   Range *r;
1066
1067   r = g_new (Range, 1);
1068
1069   r->buffer = gtk_text_iter_get_buffer (range_start);
1070   g_object_ref (r->buffer);
1071   
1072   r->start_mark = 
1073     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1074                                  NULL,
1075                                  range_start,
1076                                  FALSE);
1077   r->end_mark = 
1078     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1079                                  NULL,
1080                                  range_end,
1081                                  TRUE);
1082
1083   r->whole_end_mark = 
1084     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
1085                                  NULL,
1086                                  whole_end,
1087                                  TRUE);
1088
1089   r->range_start = range_start;
1090   r->range_end = range_end;
1091   r->whole_end = whole_end;
1092
1093   return r;
1094 }
1095
1096 static void
1097 restore_range (Range *r)
1098 {
1099   gtk_text_buffer_get_iter_at_mark (r->buffer,
1100                                     r->range_start,
1101                                     r->start_mark);
1102       
1103   gtk_text_buffer_get_iter_at_mark (r->buffer,
1104                                     r->range_end,
1105                                     r->end_mark);
1106       
1107   gtk_text_buffer_get_iter_at_mark (r->buffer,
1108                                     r->whole_end,
1109                                     r->whole_end_mark);  
1110   
1111   gtk_text_buffer_delete_mark (r->buffer, r->start_mark);
1112   gtk_text_buffer_delete_mark (r->buffer, r->end_mark);
1113   gtk_text_buffer_delete_mark (r->buffer, r->whole_end_mark);
1114
1115   /* Due to the gravities on the marks, the ordering could have
1116    * gotten mangled; we switch to an empty range in that
1117    * case
1118    */
1119   
1120   if (gtk_text_iter_compare (r->range_start, r->range_end) > 0)
1121     *r->range_start = *r->range_end;
1122
1123   if (gtk_text_iter_compare (r->range_end, r->whole_end) > 0)
1124     *r->range_end = *r->whole_end;
1125   
1126   g_object_unref (r->buffer);
1127   g_free (r); 
1128 }
1129
1130 static void
1131 insert_range_untagged (GtkTextBuffer     *buffer,
1132                        GtkTextIter       *iter,
1133                        const GtkTextIter *orig_start,
1134                        const GtkTextIter *orig_end,
1135                        gboolean           interactive)
1136 {
1137   GtkTextIter range_start;
1138   GtkTextIter range_end;
1139   GtkTextIter start, end;
1140   Range *r;
1141   
1142   if (gtk_text_iter_equal (orig_start, orig_end))
1143     return;
1144
1145   start = *orig_start;
1146   end = *orig_end;
1147   
1148   range_start = start;
1149   range_end = start;
1150   
1151   while (TRUE)
1152     {
1153       if (gtk_text_iter_equal (&range_start, &range_end))
1154         {
1155           /* Figure out how to move forward */
1156
1157           g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1158           
1159           if (gtk_text_iter_equal (&range_end, &end))
1160             {
1161               /* nothing left to do */
1162               break;
1163             }
1164           else if (gtk_text_iter_get_char (&range_end) == GTK_TEXT_UNKNOWN_CHAR)
1165             {
1166               GdkPixbuf *pixbuf = NULL;
1167               GtkTextChildAnchor *anchor = NULL;
1168               pixbuf = gtk_text_iter_get_pixbuf (&range_end);
1169               anchor = gtk_text_iter_get_child_anchor (&range_end);
1170
1171               if (pixbuf)
1172                 {
1173                   r = save_range (&range_start,
1174                                   &range_end,
1175                                   &end);
1176
1177                   gtk_text_buffer_insert_pixbuf (buffer,
1178                                                  iter,
1179                                                  pixbuf);
1180
1181                   restore_range (r);
1182                   r = NULL;
1183                   
1184                   gtk_text_iter_forward_char (&range_end);
1185                   
1186                   range_start = range_end;
1187                 }
1188               else if (anchor)
1189                 {
1190                   /* Just skip anchors */
1191
1192                   gtk_text_iter_forward_char (&range_end);
1193                   range_start = range_end;
1194                 }
1195               else
1196                 {
1197                   /* The GTK_TEXT_UNKNOWN_CHAR was in a text segment, so
1198                    * keep going. 
1199                    */
1200                   gtk_text_iter_forward_find_char (&range_end,
1201                                                    possibly_not_text, NULL,
1202                                                    &end);
1203                   
1204                   g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1205                 }
1206             }
1207           else
1208             {
1209               /* Text segment starts here, so forward search to
1210                * find its possible endpoint
1211                */
1212               gtk_text_iter_forward_find_char (&range_end,
1213                                                possibly_not_text, NULL,
1214                                                &end);
1215               
1216               g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
1217             }
1218         }
1219       else
1220         {
1221           r = save_range (&range_start,
1222                           &range_end,
1223                           &end);
1224           
1225           insert_text_range (buffer,
1226                              iter,
1227                              &range_start,
1228                              &range_end,
1229                              interactive);
1230
1231           restore_range (r);
1232           r = NULL;
1233           
1234           range_start = range_end;
1235         }
1236     }
1237 }
1238
1239 static void
1240 insert_range_not_inside_self (GtkTextBuffer     *buffer,
1241                               GtkTextIter       *iter,
1242                               const GtkTextIter *orig_start,
1243                               const GtkTextIter *orig_end,
1244                               gboolean           interactive)
1245 {
1246   /* Find each range of uniformly-tagged text, insert it,
1247    * then apply the tags.
1248    */
1249   GtkTextIter start = *orig_start;
1250   GtkTextIter end = *orig_end;
1251   GtkTextIter range_start;
1252   GtkTextIter range_end;
1253   
1254   if (gtk_text_iter_equal (orig_start, orig_end))
1255     return;
1256   
1257   gtk_text_iter_order (&start, &end);
1258
1259   range_start = start;
1260   range_end = start;  
1261   
1262   while (TRUE)
1263     {
1264       gint start_offset;
1265       GtkTextIter start_iter;
1266       GSList *tags;
1267       GSList *tmp_list;
1268       Range *r;
1269       
1270       if (gtk_text_iter_equal (&range_start, &end))
1271         break; /* All done */
1272
1273       g_assert (gtk_text_iter_compare (&range_start, &end) < 0);
1274       
1275       gtk_text_iter_forward_to_tag_toggle (&range_end, NULL);
1276
1277       g_assert (!gtk_text_iter_equal (&range_start, &range_end));
1278
1279       /* Clamp to the end iterator */
1280       if (gtk_text_iter_compare (&range_end, &end) > 0)
1281         range_end = end;
1282       
1283       /* We have a range with unique tags; insert it, and
1284        * apply all tags.
1285        */
1286       start_offset = gtk_text_iter_get_offset (iter);
1287
1288       r = save_range (&range_start, &range_end, &end);
1289       
1290       insert_range_untagged (buffer, iter, &range_start, &range_end, interactive);
1291
1292       restore_range (r);
1293       r = NULL;
1294       
1295       gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
1296       
1297       tags = gtk_text_iter_get_tags (&range_start);
1298       tmp_list = tags;
1299       while (tmp_list != NULL)
1300         {
1301           gtk_text_buffer_apply_tag (buffer,
1302                                      tmp_list->data,
1303                                      &start_iter,
1304                                      iter);
1305           
1306           tmp_list = g_slist_next (tmp_list);
1307         }
1308       g_slist_free (tags);
1309
1310       range_start = range_end;
1311     }
1312 }
1313
1314 static void
1315 gtk_text_buffer_real_insert_range (GtkTextBuffer     *buffer,
1316                                    GtkTextIter       *iter,
1317                                    const GtkTextIter *orig_start,
1318                                    const GtkTextIter *orig_end,
1319                                    gboolean           interactive)
1320 {
1321   GtkTextBuffer *src_buffer;
1322   
1323   /* Find each range of uniformly-tagged text, insert it,
1324    * then apply the tags.
1325    */  
1326   if (gtk_text_iter_equal (orig_start, orig_end))
1327     return;
1328
1329   if (interactive)
1330     gtk_text_buffer_begin_user_action (buffer);
1331   
1332   src_buffer = gtk_text_iter_get_buffer (orig_start);
1333   
1334   if (gtk_text_iter_get_buffer (iter) != src_buffer ||
1335       !gtk_text_iter_in_range (iter, orig_start, orig_end))
1336     {
1337       insert_range_not_inside_self (buffer, iter, orig_start, orig_end, interactive);
1338     }
1339   else
1340     {
1341       /* If you insert a range into itself, it could loop infinitely
1342        * because the region being copied keeps growing as we insert. So
1343        * we have to separately copy the range before and after
1344        * the insertion point.
1345        */
1346       GtkTextIter start = *orig_start;
1347       GtkTextIter end = *orig_end;
1348       GtkTextIter range_start;
1349       GtkTextIter range_end;
1350       Range *first_half;
1351       Range *second_half;
1352
1353       gtk_text_iter_order (&start, &end);
1354       
1355       range_start = start;
1356       range_end = *iter;
1357       first_half = save_range (&range_start, &range_end, &end);
1358
1359       range_start = *iter;
1360       range_end = end;
1361       second_half = save_range (&range_start, &range_end, &end);
1362
1363       restore_range (first_half);
1364       insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive);
1365
1366       restore_range (second_half);
1367       insert_range_not_inside_self (buffer, iter, &range_start, &range_end, interactive);
1368     }
1369   
1370   if (interactive)
1371     gtk_text_buffer_end_user_action (buffer);
1372 }
1373
1374 /**
1375  * gtk_text_buffer_insert_range:
1376  * @buffer: a #GtkTextBuffer
1377  * @iter: a position in @buffer
1378  * @start: a position in a #GtkTextBuffer
1379  * @end: another position in the same buffer as @start
1380  *
1381  * Copies text, tags, and pixbufs between @start and @end (the order
1382  * of @start and @end doesn't matter) and inserts the copy at @iter.
1383  * Used instead of simply getting/inserting text because it preserves
1384  * images and tags. If @start and @end are in a different buffer from
1385  * @buffer, the two buffers must share the same tag table.
1386  *
1387  * Implemented via emissions of the insert_text and apply_tag signals,
1388  * so expect those.
1389  **/
1390 void
1391 gtk_text_buffer_insert_range (GtkTextBuffer     *buffer,
1392                               GtkTextIter       *iter,
1393                               const GtkTextIter *start,
1394                               const GtkTextIter *end)
1395 {
1396   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1397   g_return_if_fail (iter != NULL);
1398   g_return_if_fail (start != NULL);
1399   g_return_if_fail (end != NULL);
1400   g_return_if_fail (gtk_text_iter_get_buffer (start) ==
1401                     gtk_text_iter_get_buffer (end));
1402   g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
1403                     buffer->tag_table);  
1404   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1405   
1406   gtk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE);
1407 }
1408
1409 /**
1410  * gtk_text_buffer_insert_range_interactive:
1411  * @buffer: a #GtkTextBuffer
1412  * @iter: a position in @buffer
1413  * @start: a position in a #GtkTextBuffer
1414  * @end: another position in the same buffer as @start
1415  * @default_editable: default editability of the buffer
1416  *
1417  * Same as gtk_text_buffer_insert_range(), but does nothing if the
1418  * insertion point isn't editable. The @default_editable parameter
1419  * indicates whether the text is editable at @iter if no tags
1420  * enclosing @iter affect editability. Typically the result of
1421  * gtk_text_view_get_editable() is appropriate here.
1422  *
1423  * Returns: whether an insertion was possible at @iter
1424  **/
1425 gboolean
1426 gtk_text_buffer_insert_range_interactive (GtkTextBuffer     *buffer,
1427                                           GtkTextIter       *iter,
1428                                           const GtkTextIter *start,
1429                                           const GtkTextIter *end,
1430                                           gboolean           default_editable)
1431 {
1432   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1433   g_return_val_if_fail (iter != NULL, FALSE);
1434   g_return_val_if_fail (start != NULL, FALSE);
1435   g_return_val_if_fail (end != NULL, FALSE);
1436   g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
1437                         gtk_text_iter_get_buffer (end), FALSE);
1438   g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
1439                         buffer->tag_table, FALSE);
1440
1441   if (gtk_text_iter_can_insert (iter, default_editable))
1442     {
1443       gtk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE);
1444       return TRUE;
1445     }
1446   else
1447     return FALSE;
1448 }
1449
1450 /**
1451  * gtk_text_buffer_insert_with_tags:
1452  * @buffer: a #GtkTextBuffer
1453  * @iter: an iterator in @buffer
1454  * @text: UTF-8 text
1455  * @len: length of @text, or -1
1456  * @first_tag: first tag to apply to @text
1457  * @Varargs: NULL-terminated list of tags to apply
1458  *
1459  * Inserts @text into @buffer at @iter, applying the list of tags to
1460  * the newly-inserted text. The last tag specified must be NULL to
1461  * terminate the list. Equivalent to calling gtk_text_buffer_insert(),
1462  * then gtk_text_buffer_apply_tag() on the inserted text;
1463  * gtk_text_buffer_insert_with_tags() is just a convenience function.
1464  **/
1465 void
1466 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
1467                                   GtkTextIter   *iter,
1468                                   const gchar   *text,
1469                                   gint           len,
1470                                   GtkTextTag    *first_tag,
1471                                   ...)
1472 {
1473   gint start_offset;
1474   GtkTextIter start;
1475   va_list args;
1476   GtkTextTag *tag;
1477
1478   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1479   g_return_if_fail (iter != NULL);
1480   g_return_if_fail (text != NULL);
1481   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1482   
1483   start_offset = gtk_text_iter_get_offset (iter);
1484
1485   gtk_text_buffer_insert (buffer, iter, text, len);
1486
1487   if (first_tag == NULL)
1488     return;
1489
1490   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1491
1492   va_start (args, first_tag);
1493   tag = first_tag;
1494   while (tag)
1495     {
1496       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1497
1498       tag = va_arg (args, GtkTextTag*);
1499     }
1500
1501   va_end (args);
1502 }
1503
1504 /**
1505  * gtk_text_buffer_insert_with_tags_by_name:
1506  * @buffer: a #GtkTextBuffer
1507  * @iter: position in @buffer
1508  * @text: UTF-8 text
1509  * @len: length of @text, or -1
1510  * @first_tag_name: name of a tag to apply to @text
1511  * @Varargs: more tag names
1512  *
1513  * Same as gtk_text_buffer_insert_with_tags(), but allows you
1514  * to pass in tag names instead of tag objects.
1515  **/
1516 void
1517 gtk_text_buffer_insert_with_tags_by_name  (GtkTextBuffer *buffer,
1518                                            GtkTextIter   *iter,
1519                                            const gchar   *text,
1520                                            gint           len,
1521                                            const gchar   *first_tag_name,
1522                                            ...)
1523 {
1524   gint start_offset;
1525   GtkTextIter start;
1526   va_list args;
1527   const gchar *tag_name;
1528
1529   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1530   g_return_if_fail (iter != NULL);
1531   g_return_if_fail (text != NULL);
1532   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1533   
1534   start_offset = gtk_text_iter_get_offset (iter);
1535
1536   gtk_text_buffer_insert (buffer, iter, text, len);
1537
1538   if (first_tag_name == NULL)
1539     return;
1540
1541   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1542
1543   va_start (args, first_tag_name);
1544   tag_name = first_tag_name;
1545   while (tag_name)
1546     {
1547       GtkTextTag *tag;
1548
1549       tag = gtk_text_tag_table_lookup (buffer->tag_table,
1550                                        tag_name);
1551
1552       if (tag == NULL)
1553         {
1554           g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
1555           va_end (args);
1556           return;
1557         }
1558
1559       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1560
1561       tag_name = va_arg (args, const gchar*);
1562     }
1563
1564   va_end (args);
1565 }
1566
1567
1568 /*
1569  * Deletion
1570  */
1571
1572 static void
1573 gtk_text_buffer_real_delete_range (GtkTextBuffer *buffer,
1574                                    GtkTextIter   *start,
1575                                    GtkTextIter   *end)
1576 {
1577   gboolean has_selection;
1578
1579   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1580   g_return_if_fail (start != NULL);
1581   g_return_if_fail (end != NULL);
1582
1583   _gtk_text_btree_delete (start, end);
1584
1585   /* may have deleted the selection... */
1586   update_selection_clipboards (buffer);
1587
1588   has_selection = gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
1589   if (has_selection != buffer->has_selection)
1590     {
1591       buffer->has_selection = has_selection;
1592       g_object_notify (G_OBJECT (buffer), "has-selection");
1593     }
1594
1595   g_signal_emit (buffer, signals[CHANGED], 0);
1596   g_object_notify (G_OBJECT (buffer), "cursor-position");
1597 }
1598
1599 static void
1600 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
1601                              GtkTextIter *start,
1602                              GtkTextIter *end)
1603 {
1604   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1605   g_return_if_fail (start != NULL);
1606   g_return_if_fail (end != NULL);
1607
1608   if (gtk_text_iter_equal (start, end))
1609     return;
1610
1611   gtk_text_iter_order (start, end);
1612
1613   g_signal_emit (buffer,
1614                  signals[DELETE_RANGE],
1615                  0,
1616                  start, end);
1617 }
1618
1619 /**
1620  * gtk_text_buffer_delete:
1621  * @buffer: a #GtkTextBuffer
1622  * @start: a position in @buffer
1623  * @end: another position in @buffer
1624  *
1625  * Deletes text between @start and @end. The order of @start and @end
1626  * is not actually relevant; gtk_text_buffer_delete() will reorder
1627  * them. This function actually emits the "delete-range" signal, and
1628  * the default handler of that signal deletes the text. Because the
1629  * buffer is modified, all outstanding iterators become invalid after
1630  * calling this function; however, the @start and @end will be
1631  * re-initialized to point to the location where text was deleted.
1632  **/
1633 void
1634 gtk_text_buffer_delete (GtkTextBuffer *buffer,
1635                         GtkTextIter   *start,
1636                         GtkTextIter   *end)
1637 {
1638   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1639   g_return_if_fail (start != NULL);
1640   g_return_if_fail (end != NULL);
1641   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
1642   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
1643   
1644   gtk_text_buffer_emit_delete (buffer, start, end);
1645 }
1646
1647 /**
1648  * gtk_text_buffer_delete_interactive:
1649  * @buffer: a #GtkTextBuffer
1650  * @start_iter: start of range to delete
1651  * @end_iter: end of range
1652  * @default_editable: whether the buffer is editable by default
1653  *
1654  * Deletes all <emphasis>editable</emphasis> text in the given range.
1655  * Calls gtk_text_buffer_delete() for each editable sub-range of
1656  * [@start,@end). @start and @end are revalidated to point to
1657  * the location of the last deleted range, or left untouched if
1658  * no text was deleted.
1659  *
1660  * Return value: whether some text was actually deleted
1661  **/
1662 gboolean
1663 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
1664                                     GtkTextIter   *start_iter,
1665                                     GtkTextIter   *end_iter,
1666                                     gboolean       default_editable)
1667 {
1668   GtkTextMark *end_mark;
1669   GtkTextMark *start_mark;
1670   GtkTextIter iter;
1671   gboolean current_state;
1672   gboolean deleted_stuff = FALSE;
1673
1674   /* Delete all editable text in the range start_iter, end_iter */
1675
1676   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1677   g_return_val_if_fail (start_iter != NULL, FALSE);
1678   g_return_val_if_fail (end_iter != NULL, FALSE);
1679   g_return_val_if_fail (gtk_text_iter_get_buffer (start_iter) == buffer, FALSE);
1680   g_return_val_if_fail (gtk_text_iter_get_buffer (end_iter) == buffer, FALSE);
1681
1682   
1683   gtk_text_buffer_begin_user_action (buffer);
1684   
1685   gtk_text_iter_order (start_iter, end_iter);
1686
1687   start_mark = gtk_text_buffer_create_mark (buffer, NULL,
1688                                             start_iter, TRUE);
1689   end_mark = gtk_text_buffer_create_mark (buffer, NULL,
1690                                           end_iter, FALSE);
1691
1692   gtk_text_buffer_get_iter_at_mark (buffer, &iter, start_mark);
1693
1694   current_state = gtk_text_iter_editable (&iter, default_editable);
1695
1696   while (TRUE)
1697     {
1698       gboolean new_state;
1699       gboolean done = FALSE;
1700       GtkTextIter end;
1701
1702       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
1703
1704       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
1705
1706       if (gtk_text_iter_compare (&iter, &end) >= 0)
1707         {
1708           done = TRUE;
1709           iter = end; /* clamp to the last boundary */
1710         }
1711
1712       new_state = gtk_text_iter_editable (&iter, default_editable);
1713
1714       if (current_state == new_state)
1715         {
1716           if (done)
1717             {
1718               if (current_state)
1719                 {
1720                   /* We're ending an editable region. Delete said region. */
1721                   GtkTextIter start;
1722
1723                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1724
1725                   gtk_text_buffer_emit_delete (buffer, &start, &iter);
1726
1727                   deleted_stuff = TRUE;
1728
1729                   /* revalidate user's iterators. */
1730                   *start_iter = start;
1731                   *end_iter = iter;
1732                 }
1733
1734               break;
1735             }
1736           else
1737             continue;
1738         }
1739
1740       if (current_state && !new_state)
1741         {
1742           /* End of an editable region. Delete it. */
1743           GtkTextIter start;
1744
1745           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1746
1747           gtk_text_buffer_emit_delete (buffer, &start, &iter);
1748
1749           /* It's more robust to ask for the state again then to assume that
1750            * we're on the next not-editable segment. We don't know what the
1751            * ::delete-range handler did.... maybe it deleted the following
1752            * not-editable segment because it was associated with the editable
1753            * segment.
1754            */
1755           current_state = gtk_text_iter_editable (&iter, default_editable);
1756           deleted_stuff = TRUE;
1757
1758           /* revalidate user's iterators. */
1759           *start_iter = start;
1760           *end_iter = iter;
1761         }
1762       else
1763         {
1764           /* We are at the start of an editable region. We won't be deleting
1765            * the previous region. Move start mark to start of this region.
1766            */
1767
1768           g_assert (!current_state && new_state);
1769
1770           gtk_text_buffer_move_mark (buffer, start_mark, &iter);
1771
1772           current_state = TRUE;
1773         }
1774
1775       if (done)
1776         break;
1777     }
1778
1779   gtk_text_buffer_delete_mark (buffer, start_mark);
1780   gtk_text_buffer_delete_mark (buffer, end_mark);
1781
1782   gtk_text_buffer_end_user_action (buffer);
1783   
1784   return deleted_stuff;
1785 }
1786
1787 /*
1788  * Extracting textual buffer contents
1789  */
1790
1791 /**
1792  * gtk_text_buffer_get_text:
1793  * @buffer: a #GtkTextBuffer
1794  * @start: start of a range
1795  * @end: end of a range
1796  * @include_hidden_chars: whether to include invisible text
1797  *
1798  * Returns the text in the range [@start,@end). Excludes undisplayed
1799  * text (text marked with tags that set the invisibility attribute) if
1800  * @include_hidden_chars is %FALSE. Does not include characters
1801  * representing embedded images, so byte and character indexes into
1802  * the returned string do <emphasis>not</emphasis> correspond to byte
1803  * and character indexes into the buffer. Contrast with
1804  * gtk_text_buffer_get_slice().
1805  *
1806  * Return value: an allocated UTF-8 string
1807  **/
1808 gchar*
1809 gtk_text_buffer_get_text (GtkTextBuffer     *buffer,
1810                           const GtkTextIter *start,
1811                           const GtkTextIter *end,
1812                           gboolean           include_hidden_chars)
1813 {
1814   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1815   g_return_val_if_fail (start != NULL, NULL);
1816   g_return_val_if_fail (end != NULL, NULL);
1817   g_return_val_if_fail (gtk_text_iter_get_buffer (start) == buffer, NULL);
1818   g_return_val_if_fail (gtk_text_iter_get_buffer (end) == buffer, NULL);
1819   
1820   if (include_hidden_chars)
1821     return gtk_text_iter_get_text (start, end);
1822   else
1823     return gtk_text_iter_get_visible_text (start, end);
1824 }
1825
1826 /**
1827  * gtk_text_buffer_get_slice:
1828  * @buffer: a #GtkTextBuffer
1829  * @start: start of a range
1830  * @end: end of a range
1831  * @include_hidden_chars: whether to include invisible text
1832  *
1833  * Returns the text in the range [@start,@end). Excludes undisplayed
1834  * text (text marked with tags that set the invisibility attribute) if
1835  * @include_hidden_chars is %FALSE. The returned string includes a
1836  * 0xFFFC character whenever the buffer contains
1837  * embedded images, so byte and character indexes into
1838  * the returned string <emphasis>do</emphasis> correspond to byte
1839  * and character indexes into the buffer. Contrast with
1840  * gtk_text_buffer_get_text(). Note that 0xFFFC can occur in normal
1841  * text as well, so it is not a reliable indicator that a pixbuf or
1842  * widget is in the buffer.
1843  *
1844  * Return value: an allocated UTF-8 string
1845  **/
1846 gchar*
1847 gtk_text_buffer_get_slice (GtkTextBuffer     *buffer,
1848                            const GtkTextIter *start,
1849                            const GtkTextIter *end,
1850                            gboolean           include_hidden_chars)
1851 {
1852   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1853   g_return_val_if_fail (start != NULL, NULL);
1854   g_return_val_if_fail (end != NULL, NULL);
1855   g_return_val_if_fail (gtk_text_iter_get_buffer (start) == buffer, NULL);
1856   g_return_val_if_fail (gtk_text_iter_get_buffer (end) == buffer, NULL);
1857   
1858   if (include_hidden_chars)
1859     return gtk_text_iter_get_slice (start, end);
1860   else
1861     return gtk_text_iter_get_visible_slice (start, end);
1862 }
1863
1864 /*
1865  * Pixbufs
1866  */
1867
1868 static void
1869 gtk_text_buffer_real_insert_pixbuf (GtkTextBuffer *buffer,
1870                                     GtkTextIter   *iter,
1871                                     GdkPixbuf     *pixbuf)
1872
1873   _gtk_text_btree_insert_pixbuf (iter, pixbuf);
1874
1875   g_signal_emit (buffer, signals[CHANGED], 0);
1876 }
1877
1878 /**
1879  * gtk_text_buffer_insert_pixbuf:
1880  * @buffer: a #GtkTextBuffer
1881  * @iter: location to insert the pixbuf
1882  * @pixbuf: a #GdkPixbuf
1883  *
1884  * Inserts an image into the text buffer at @iter. The image will be
1885  * counted as one character in character counts, and when obtaining
1886  * the buffer contents as a string, will be represented by the Unicode
1887  * "object replacement character" 0xFFFC. Note that the "slice"
1888  * variants for obtaining portions of the buffer as a string include
1889  * this character for pixbufs, but the "text" variants do
1890  * not. e.g. see gtk_text_buffer_get_slice() and
1891  * gtk_text_buffer_get_text().
1892  **/
1893 void
1894 gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer,
1895                                GtkTextIter   *iter,
1896                                GdkPixbuf     *pixbuf)
1897 {
1898   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1899   g_return_if_fail (iter != NULL);
1900   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1901   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1902   
1903   g_signal_emit (buffer, signals[INSERT_PIXBUF], 0,
1904                  iter, pixbuf);
1905 }
1906
1907 /*
1908  * Child anchor
1909  */
1910
1911
1912 static void
1913 gtk_text_buffer_real_insert_anchor (GtkTextBuffer      *buffer,
1914                                     GtkTextIter        *iter,
1915                                     GtkTextChildAnchor *anchor)
1916 {
1917   _gtk_text_btree_insert_child_anchor (iter, anchor);
1918
1919   g_signal_emit (buffer, signals[CHANGED], 0);
1920 }
1921
1922 /**
1923  * gtk_text_buffer_insert_child_anchor:
1924  * @buffer: a #GtkTextBuffer
1925  * @iter: location to insert the anchor
1926  * @anchor: a #GtkTextChildAnchor
1927  *
1928  * Inserts a child widget anchor into the text buffer at @iter. The
1929  * anchor will be counted as one character in character counts, and
1930  * when obtaining the buffer contents as a string, will be represented
1931  * by the Unicode "object replacement character" 0xFFFC. Note that the
1932  * "slice" variants for obtaining portions of the buffer as a string
1933  * include this character for child anchors, but the "text" variants do
1934  * not. E.g. see gtk_text_buffer_get_slice() and
1935  * gtk_text_buffer_get_text(). Consider
1936  * gtk_text_buffer_create_child_anchor() as a more convenient
1937  * alternative to this function. The buffer will add a reference to
1938  * the anchor, so you can unref it after insertion.
1939  **/
1940 void
1941 gtk_text_buffer_insert_child_anchor (GtkTextBuffer      *buffer,
1942                                      GtkTextIter        *iter,
1943                                      GtkTextChildAnchor *anchor)
1944 {
1945   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1946   g_return_if_fail (iter != NULL);
1947   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
1948   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
1949   
1950   g_signal_emit (buffer, signals[INSERT_CHILD_ANCHOR], 0,
1951                  iter, anchor);
1952 }
1953
1954 /**
1955  * gtk_text_buffer_create_child_anchor:
1956  * @buffer: a #GtkTextBuffer
1957  * @iter: location in the buffer
1958  * 
1959  * This is a convenience function which simply creates a child anchor
1960  * with gtk_text_child_anchor_new() and inserts it into the buffer
1961  * with gtk_text_buffer_insert_child_anchor(). The new anchor is
1962  * owned by the buffer; no reference count is returned to
1963  * the caller of gtk_text_buffer_create_child_anchor().
1964  * 
1965  * Return value: the created child anchor
1966  **/
1967 GtkTextChildAnchor*
1968 gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
1969                                      GtkTextIter   *iter)
1970 {
1971   GtkTextChildAnchor *anchor;
1972   
1973   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1974   g_return_val_if_fail (iter != NULL, NULL);
1975   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, NULL);
1976   
1977   anchor = gtk_text_child_anchor_new ();
1978
1979   gtk_text_buffer_insert_child_anchor (buffer, iter, anchor);
1980
1981   g_object_unref (anchor);
1982
1983   return anchor;
1984 }
1985
1986 /*
1987  * Mark manipulation
1988  */
1989
1990 static void
1991 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
1992                           const GtkTextIter *location,
1993                           GtkTextMark       *mark)
1994 {
1995   /* IMO this should NOT work like insert_text and delete_range,
1996    * where the real action happens in the default handler.
1997    * 
1998    * The reason is that the default handler would be _required_,
1999    * i.e. the whole widget would start breaking and segfaulting if the
2000    * default handler didn't get run. So you can't really override the
2001    * default handler or stop the emission; that is, this signal is
2002    * purely for notification, and not to allow users to modify the
2003    * default behavior.
2004    */
2005
2006   g_object_ref (mark);
2007
2008   g_signal_emit (buffer,
2009                  signals[MARK_SET],
2010                  0,
2011                  location,
2012                  mark);
2013
2014   g_object_unref (mark);
2015 }
2016
2017 /**
2018  * gtk_text_buffer_set_mark:
2019  * @buffer:       a #GtkTextBuffer
2020  * @mark_name:    name of the mark
2021  * @iter:         location for the mark
2022  * @left_gravity: if the mark is created by this function, gravity for 
2023  *                the new mark
2024  * @should_exist: if %TRUE, warn if the mark does not exist, and return
2025  *                immediately
2026  *
2027  * Move the mark to the given position, if not @should_exist, 
2028  * create the mark.
2029  *
2030  * Return value: mark
2031  **/
2032 static GtkTextMark*
2033 gtk_text_buffer_set_mark (GtkTextBuffer     *buffer,
2034                           GtkTextMark       *existing_mark,
2035                           const gchar       *mark_name,
2036                           const GtkTextIter *iter,
2037                           gboolean           left_gravity,
2038                           gboolean           should_exist)
2039 {
2040   GtkTextIter location;
2041   GtkTextMark *mark;
2042
2043   g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == buffer, NULL);
2044   
2045   mark = _gtk_text_btree_set_mark (get_btree (buffer),
2046                                    existing_mark,
2047                                    mark_name,
2048                                    left_gravity,
2049                                    iter,
2050                                    should_exist);
2051   
2052   _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
2053                                    &location,
2054                                    mark);
2055
2056   gtk_text_buffer_mark_set (buffer, &location, mark);
2057
2058   return mark;
2059 }
2060
2061 /**
2062  * gtk_text_buffer_create_mark:
2063  * @buffer: a #GtkTextBuffer
2064  * @mark_name: name for mark, or %NULL
2065  * @where: location to place mark
2066  * @left_gravity: whether the mark has left gravity
2067  *
2068  * Creates a mark at position @where. If @mark_name is %NULL, the mark
2069  * is anonymous; otherwise, the mark can be retrieved by name using
2070  * gtk_text_buffer_get_mark(). If a mark has left gravity, and text is
2071  * inserted at the mark's current location, the mark will be moved to
2072  * the left of the newly-inserted text. If the mark has right gravity
2073  * (@left_gravity = %FALSE), the mark will end up on the right of
2074  * newly-inserted text. The standard left-to-right cursor is a mark
2075  * with right gravity (when you type, the cursor stays on the right
2076  * side of the text you're typing).
2077  *
2078  * The caller of this function does <emphasis>not</emphasis> own a 
2079  * reference to the returned #GtkTextMark, so you can ignore the 
2080  * return value if you like. Marks are owned by the buffer and go 
2081  * away when the buffer does.
2082  *
2083  * Emits the "mark-set" signal as notification of the mark's initial
2084  * placement.
2085  *
2086  * Return value: the new #GtkTextMark object
2087  **/
2088 GtkTextMark*
2089 gtk_text_buffer_create_mark (GtkTextBuffer     *buffer,
2090                              const gchar       *mark_name,
2091                              const GtkTextIter *where,
2092                              gboolean           left_gravity)
2093 {
2094   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2095
2096   return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
2097                                    left_gravity, FALSE);
2098 }
2099
2100 /**
2101  * gtk_text_buffer_add_mark:
2102  * @buffer: a #GtkTextBuffer
2103  * @mark: the mark to add
2104  * @where: location to place mark
2105  *
2106  * Adds the mark at position @where. The mark must not be added to
2107  * another buffer, and if its name is not %NULL then there must not
2108  * be another mark in the buffer with the same name.
2109  *
2110  * Emits the "mark-set" signal as notification of the mark's initial
2111  * placement.
2112  *
2113  * Since: 2.12
2114  **/
2115 void
2116 gtk_text_buffer_add_mark (GtkTextBuffer     *buffer,
2117                           GtkTextMark       *mark,
2118                           const GtkTextIter *where)
2119 {
2120   const gchar *name;
2121
2122   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2123   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2124   g_return_if_fail (where != NULL);
2125   g_return_if_fail (gtk_text_mark_get_buffer (mark) == NULL);
2126
2127   name = gtk_text_mark_get_name (mark);
2128
2129   if (name != NULL && gtk_text_buffer_get_mark (buffer, name) != NULL)
2130     {
2131       g_critical ("Mark %s already exists in the buffer", name);
2132       return;
2133     }
2134
2135   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, FALSE);
2136 }
2137
2138 /**
2139  * gtk_text_buffer_move_mark:
2140  * @buffer: a #GtkTextBuffer
2141  * @mark: a #GtkTextMark
2142  * @where: new location for @mark in @buffer
2143  *
2144  * Moves @mark to the new location @where. Emits the "mark-set" signal
2145  * as notification of the move.
2146  **/
2147 void
2148 gtk_text_buffer_move_mark (GtkTextBuffer     *buffer,
2149                            GtkTextMark       *mark,
2150                            const GtkTextIter *where)
2151 {
2152   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2153   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2154   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2155
2156   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
2157 }
2158
2159 /**
2160  * gtk_text_buffer_get_iter_at_mark:
2161  * @buffer: a #GtkTextBuffer
2162  * @iter: iterator to initialize
2163  * @mark: a #GtkTextMark in @buffer
2164  *
2165  * Initializes @iter with the current position of @mark.
2166  **/
2167 void
2168 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
2169                                   GtkTextIter   *iter,
2170                                   GtkTextMark   *mark)
2171 {
2172   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2173   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2174   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2175
2176   _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
2177                                     iter,
2178                                     mark);
2179 }
2180
2181 /**
2182  * gtk_text_buffer_delete_mark:
2183  * @buffer: a #GtkTextBuffer
2184  * @mark: a #GtkTextMark in @buffer
2185  *
2186  * Deletes @mark, so that it's no longer located anywhere in the
2187  * buffer. Removes the reference the buffer holds to the mark, so if
2188  * you haven't called g_object_ref() on the mark, it will be freed. Even
2189  * if the mark isn't freed, most operations on @mark become
2190  * invalid, until it gets added to a buffer again with 
2191  * gtk_text_buffer_add_mark(). Use gtk_text_mark_get_deleted() to  
2192  * find out if a mark has been removed from its buffer.
2193  * The "mark-deleted" signal will be emitted as notification after 
2194  * the mark is deleted.
2195  **/
2196 void
2197 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
2198                              GtkTextMark   *mark)
2199 {
2200   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2201   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
2202   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2203
2204   g_object_ref (mark);
2205
2206   _gtk_text_btree_remove_mark (get_btree (buffer), mark);
2207
2208   /* See rationale above for MARK_SET on why we emit this after
2209    * removing the mark, rather than removing the mark in a default
2210    * handler.
2211    */
2212   g_signal_emit (buffer, signals[MARK_DELETED],
2213                  0,
2214                  mark);
2215
2216   g_object_unref (mark);
2217 }
2218
2219 /**
2220  * gtk_text_buffer_get_mark:
2221  * @buffer: a #GtkTextBuffer
2222  * @name: a mark name
2223  *
2224  * Returns the mark named @name in buffer @buffer, or %NULL if no such
2225  * mark exists in the buffer.
2226  *
2227  * Return value: a #GtkTextMark, or %NULL
2228  **/
2229 GtkTextMark*
2230 gtk_text_buffer_get_mark (GtkTextBuffer *buffer,
2231                           const gchar   *name)
2232 {
2233   GtkTextMark *mark;
2234
2235   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2236   g_return_val_if_fail (name != NULL, NULL);
2237
2238   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2239
2240   return mark;
2241 }
2242
2243 /**
2244  * gtk_text_buffer_move_mark_by_name:
2245  * @buffer: a #GtkTextBuffer
2246  * @name: name of a mark
2247  * @where: new location for mark
2248  *
2249  * Moves the mark named @name (which must exist) to location @where.
2250  * See gtk_text_buffer_move_mark() for details.
2251  **/
2252 void
2253 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
2254                                    const gchar       *name,
2255                                    const GtkTextIter *where)
2256 {
2257   GtkTextMark *mark;
2258
2259   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2260   g_return_if_fail (name != NULL);
2261
2262   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2263
2264   if (mark == NULL)
2265     {
2266       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2267       return;
2268     }
2269
2270   gtk_text_buffer_move_mark (buffer, mark, where);
2271 }
2272
2273 /**
2274  * gtk_text_buffer_delete_mark_by_name:
2275  * @buffer: a #GtkTextBuffer
2276  * @name: name of a mark in @buffer
2277  *
2278  * Deletes the mark named @name; the mark must exist. See
2279  * gtk_text_buffer_delete_mark() for details.
2280  **/
2281 void
2282 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer *buffer,
2283                                      const gchar   *name)
2284 {
2285   GtkTextMark *mark;
2286
2287   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2288   g_return_if_fail (name != NULL);
2289
2290   mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
2291
2292   if (mark == NULL)
2293     {
2294       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
2295       return;
2296     }
2297
2298   gtk_text_buffer_delete_mark (buffer, mark);
2299 }
2300
2301 /**
2302  * gtk_text_buffer_get_insert:
2303  * @buffer: a #GtkTextBuffer
2304  *
2305  * Returns the mark that represents the cursor (insertion point).
2306  * Equivalent to calling gtk_text_buffer_get_mark() to get the mark
2307  * named "insert", but very slightly more efficient, and involves less
2308  * typing.
2309  *
2310  * Return value: insertion point mark
2311  **/
2312 GtkTextMark*
2313 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
2314 {
2315   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2316
2317   return _gtk_text_btree_get_insert (get_btree (buffer));
2318 }
2319
2320 /**
2321  * gtk_text_buffer_get_selection_bound:
2322  * @buffer: a #GtkTextBuffer
2323  *
2324  * Returns the mark that represents the selection bound.  Equivalent
2325  * to calling gtk_text_buffer_get_mark() to get the mark named
2326  * "selection_bound", but very slightly more efficient, and involves
2327  * less typing.
2328  *
2329  * The currently-selected text in @buffer is the region between the
2330  * "selection_bound" and "insert" marks. If "selection_bound" and
2331  * "insert" are in the same place, then there is no current selection.
2332  * gtk_text_buffer_get_selection_bounds() is another convenient function
2333  * for handling the selection, if you just want to know whether there's a
2334  * selection and what its bounds are.
2335  *
2336  * Return value: selection bound mark
2337  **/
2338 GtkTextMark*
2339 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
2340 {
2341   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2342
2343   return _gtk_text_btree_get_selection_bound (get_btree (buffer));
2344 }
2345
2346 /**
2347  * gtk_text_buffer_get_iter_at_child_anchor:
2348  * @buffer: a #GtkTextBuffer
2349  * @iter: an iterator to be initialized
2350  * @anchor: a child anchor that appears in @buffer
2351  *
2352  * Obtains the location of @anchor within @buffer.
2353  **/
2354 void
2355 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
2356                                           GtkTextIter        *iter,
2357                                           GtkTextChildAnchor *anchor)
2358 {
2359   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2360   g_return_if_fail (iter != NULL);
2361   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
2362   g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
2363   
2364   _gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
2365                                            iter,
2366                                            anchor);
2367 }
2368
2369 /**
2370  * gtk_text_buffer_place_cursor:
2371  * @buffer: a #GtkTextBuffer
2372  * @where: where to put the cursor
2373  *
2374  * This function moves the "insert" and "selection_bound" marks
2375  * simultaneously.  If you move them to the same place in two steps
2376  * with gtk_text_buffer_move_mark(), you will temporarily select a
2377  * region in between their old and new locations, which can be pretty
2378  * inefficient since the temporarily-selected region will force stuff
2379  * to be recalculated. This function moves them as a unit, which can
2380  * be optimized.
2381  **/
2382 void
2383 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
2384                               const GtkTextIter *where)
2385 {
2386   gtk_text_buffer_select_range (buffer, where, where);
2387 }
2388
2389 /**
2390  * gtk_text_buffer_select_range:
2391  * @buffer: a #GtkTextBuffer
2392  * @ins: where to put the "insert" mark
2393  * @bound: where to put the "selection_bound" mark
2394  *
2395  * This function moves the "insert" and "selection_bound" marks
2396  * simultaneously.  If you move them in two steps
2397  * with gtk_text_buffer_move_mark(), you will temporarily select a
2398  * region in between their old and new locations, which can be pretty
2399  * inefficient since the temporarily-selected region will force stuff
2400  * to be recalculated. This function moves them as a unit, which can
2401  * be optimized.
2402  *
2403  * Since: 2.4
2404  **/
2405 void
2406 gtk_text_buffer_select_range (GtkTextBuffer     *buffer,
2407                               const GtkTextIter *ins,
2408                               const GtkTextIter *bound)
2409 {
2410   GtkTextIter real_ins;
2411   GtkTextIter real_bound;
2412
2413   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2414
2415   real_ins = *ins;
2416   real_bound = *bound;
2417
2418   _gtk_text_btree_select_range (get_btree (buffer), &real_ins, &real_bound);
2419   gtk_text_buffer_mark_set (buffer, &real_ins,
2420                             gtk_text_buffer_get_insert (buffer));
2421   gtk_text_buffer_mark_set (buffer, &real_bound,
2422                             gtk_text_buffer_get_selection_bound (buffer));
2423 }
2424
2425 /*
2426  * Tags
2427  */
2428
2429 /**
2430  * gtk_text_buffer_create_tag:
2431  * @buffer: a #GtkTextBuffer
2432  * @tag_name: name of the new tag, or %NULL
2433  * @first_property_name: name of first property to set, or %NULL
2434  * @Varargs: %NULL-terminated list of property names and values
2435  *
2436  *
2437  * Creates a tag and adds it to the tag table for @buffer.
2438  * Equivalent to calling gtk_text_tag_new() and then adding the
2439  * tag to the buffer's tag table. The returned tag is owned by
2440  * the buffer's tag table, so the ref count will be equal to one.
2441  *
2442  * If @tag_name is %NULL, the tag is anonymous.
2443  *
2444  * If @tag_name is non-%NULL, a tag called @tag_name must not already
2445  * exist in the tag table for this buffer.
2446  *
2447  * The @first_property_name argument and subsequent arguments are a list
2448  * of properties to set on the tag, as with g_object_set().
2449  *
2450  * Return value: a new tag
2451  **/
2452 GtkTextTag*
2453 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
2454                             const gchar   *tag_name,
2455                             const gchar   *first_property_name,
2456                             ...)
2457 {
2458   GtkTextTag *tag;
2459   va_list list;
2460   
2461   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2462
2463   tag = gtk_text_tag_new (tag_name);
2464
2465   gtk_text_tag_table_add (get_table (buffer), tag);
2466
2467   if (first_property_name)
2468     {
2469       va_start (list, first_property_name);
2470       g_object_set_valist (G_OBJECT (tag), first_property_name, list);
2471       va_end (list);
2472     }
2473   
2474   g_object_unref (tag);
2475
2476   return tag;
2477 }
2478
2479 static void
2480 gtk_text_buffer_real_apply_tag (GtkTextBuffer     *buffer,
2481                                 GtkTextTag        *tag,
2482                                 const GtkTextIter *start,
2483                                 const GtkTextIter *end)
2484 {
2485   if (tag->table != buffer->tag_table)
2486     {
2487       g_warning ("Can only apply tags that are in the tag table for the buffer");
2488       return;
2489     }
2490   
2491   _gtk_text_btree_tag (start, end, tag, TRUE);
2492 }
2493
2494 static void
2495 gtk_text_buffer_real_remove_tag (GtkTextBuffer     *buffer,
2496                                  GtkTextTag        *tag,
2497                                  const GtkTextIter *start,
2498                                  const GtkTextIter *end)
2499 {
2500   if (tag->table != buffer->tag_table)
2501     {
2502       g_warning ("Can only remove tags that are in the tag table for the buffer");
2503       return;
2504     }
2505   
2506   _gtk_text_btree_tag (start, end, tag, FALSE);
2507 }
2508
2509 static void
2510 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
2511 {
2512   gtk_text_buffer_set_modified (buffer, TRUE);
2513 }
2514
2515 static void
2516 gtk_text_buffer_real_mark_set (GtkTextBuffer     *buffer,
2517                                const GtkTextIter *iter,
2518                                GtkTextMark       *mark)
2519 {
2520   GtkTextMark *insert;
2521   
2522   insert = gtk_text_buffer_get_insert (buffer);
2523
2524   if (mark == insert || mark == gtk_text_buffer_get_selection_bound (buffer))
2525     {
2526       gboolean has_selection;
2527
2528       update_selection_clipboards (buffer);
2529     
2530       has_selection = gtk_text_buffer_get_selection_bounds (buffer,
2531                                                             NULL,
2532                                                             NULL);
2533
2534       if (has_selection != buffer->has_selection)
2535         {
2536           buffer->has_selection = has_selection;
2537           g_object_notify (G_OBJECT (buffer), "has-selection");
2538         }
2539     }
2540     
2541     if (mark == insert)
2542       g_object_notify (G_OBJECT (buffer), "cursor-position");
2543 }
2544
2545 static void
2546 gtk_text_buffer_emit_tag (GtkTextBuffer     *buffer,
2547                           GtkTextTag        *tag,
2548                           gboolean           apply,
2549                           const GtkTextIter *start,
2550                           const GtkTextIter *end)
2551 {
2552   GtkTextIter start_tmp = *start;
2553   GtkTextIter end_tmp = *end;
2554
2555   g_return_if_fail (tag != NULL);
2556
2557   gtk_text_iter_order (&start_tmp, &end_tmp);
2558
2559   if (apply)
2560     g_signal_emit (buffer, signals[APPLY_TAG],
2561                    0,
2562                    tag, &start_tmp, &end_tmp);
2563   else
2564     g_signal_emit (buffer, signals[REMOVE_TAG],
2565                    0,
2566                    tag, &start_tmp, &end_tmp);
2567 }
2568
2569 /**
2570  * gtk_text_buffer_apply_tag:
2571  * @buffer: a #GtkTextBuffer
2572  * @tag: a #GtkTextTag
2573  * @start: one bound of range to be tagged
2574  * @end: other bound of range to be tagged
2575  *
2576  * Emits the "apply-tag" signal on @buffer. The default
2577  * handler for the signal applies @tag to the given range.
2578  * @start and @end do not have to be in order.
2579  **/
2580 void
2581 gtk_text_buffer_apply_tag (GtkTextBuffer     *buffer,
2582                            GtkTextTag        *tag,
2583                            const GtkTextIter *start,
2584                            const GtkTextIter *end)
2585 {
2586   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2587   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2588   g_return_if_fail (start != NULL);
2589   g_return_if_fail (end != NULL);
2590   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2591   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2592   g_return_if_fail (tag->table == buffer->tag_table);
2593   
2594   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2595 }
2596
2597 /**
2598  * gtk_text_buffer_remove_tag:
2599  * @buffer: a #GtkTextBuffer
2600  * @tag: a #GtkTextTag
2601  * @start: one bound of range to be untagged
2602  * @end: other bound of range to be untagged
2603  *
2604  * Emits the "remove-tag" signal. The default handler for the signal
2605  * removes all occurrences of @tag from the given range. @start and
2606  * @end don't have to be in order.
2607  **/
2608 void
2609 gtk_text_buffer_remove_tag (GtkTextBuffer     *buffer,
2610                             GtkTextTag        *tag,
2611                             const GtkTextIter *start,
2612                             const GtkTextIter *end)
2613
2614 {
2615   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2616   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
2617   g_return_if_fail (start != NULL);
2618   g_return_if_fail (end != NULL);
2619   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2620   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2621   g_return_if_fail (tag->table == buffer->tag_table);
2622   
2623   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2624 }
2625
2626 /**
2627  * gtk_text_buffer_apply_tag_by_name:
2628  * @buffer: a #GtkTextBuffer
2629  * @name: name of a named #GtkTextTag
2630  * @start: one bound of range to be tagged
2631  * @end: other bound of range to be tagged
2632  *
2633  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2634  * get a #GtkTextTag, then calls gtk_text_buffer_apply_tag().
2635  **/
2636 void
2637 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer     *buffer,
2638                                    const gchar       *name,
2639                                    const GtkTextIter *start,
2640                                    const GtkTextIter *end)
2641 {
2642   GtkTextTag *tag;
2643
2644   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2645   g_return_if_fail (name != NULL);
2646   g_return_if_fail (start != NULL);
2647   g_return_if_fail (end != NULL);
2648   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2649   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2650
2651   tag = gtk_text_tag_table_lookup (get_table (buffer),
2652                                    name);
2653
2654   if (tag == NULL)
2655     {
2656       g_warning ("Unknown tag `%s'", name);
2657       return;
2658     }
2659
2660   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
2661 }
2662
2663 /**
2664  * gtk_text_buffer_remove_tag_by_name:
2665  * @buffer: a #GtkTextBuffer
2666  * @name: name of a #GtkTextTag
2667  * @start: one bound of range to be untagged
2668  * @end: other bound of range to be untagged
2669  *
2670  * Calls gtk_text_tag_table_lookup() on the buffer's tag table to
2671  * get a #GtkTextTag, then calls gtk_text_buffer_remove_tag().
2672  **/
2673 void
2674 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer     *buffer,
2675                                     const gchar       *name,
2676                                     const GtkTextIter *start,
2677                                     const GtkTextIter *end)
2678 {
2679   GtkTextTag *tag;
2680
2681   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2682   g_return_if_fail (name != NULL);
2683   g_return_if_fail (start != NULL);
2684   g_return_if_fail (end != NULL);
2685   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2686   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2687   
2688   tag = gtk_text_tag_table_lookup (get_table (buffer),
2689                                    name);
2690
2691   if (tag == NULL)
2692     {
2693       g_warning ("Unknown tag `%s'", name);
2694       return;
2695     }
2696
2697   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
2698 }
2699
2700 static gint
2701 pointer_cmp (gconstpointer a,
2702              gconstpointer b)
2703 {
2704   if (a < b)
2705     return -1;
2706   else if (a > b)
2707     return 1;
2708   else
2709     return 0;
2710 }
2711
2712 /**
2713  * gtk_text_buffer_remove_all_tags:
2714  * @buffer: a #GtkTextBuffer
2715  * @start: one bound of range to be untagged
2716  * @end: other bound of range to be untagged
2717  * 
2718  * Removes all tags in the range between @start and @end.  Be careful
2719  * with this function; it could remove tags added in code unrelated to
2720  * the code you're currently writing. That is, using this function is
2721  * probably a bad idea if you have two or more unrelated code sections
2722  * that add tags.
2723  **/
2724 void
2725 gtk_text_buffer_remove_all_tags (GtkTextBuffer     *buffer,
2726                                  const GtkTextIter *start,
2727                                  const GtkTextIter *end)
2728 {
2729   GtkTextIter first, second, tmp;
2730   GSList *tags;
2731   GSList *tmp_list;
2732   GSList *prev, *next;
2733   GtkTextTag *tag;
2734   
2735   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2736   g_return_if_fail (start != NULL);
2737   g_return_if_fail (end != NULL);
2738   g_return_if_fail (gtk_text_iter_get_buffer (start) == buffer);
2739   g_return_if_fail (gtk_text_iter_get_buffer (end) == buffer);
2740   
2741   first = *start;
2742   second = *end;
2743
2744   gtk_text_iter_order (&first, &second);
2745
2746   /* Get all tags turned on at the start */
2747   tags = gtk_text_iter_get_tags (&first);
2748   
2749   /* Find any that are toggled on within the range */
2750   tmp = first;
2751   while (gtk_text_iter_forward_to_tag_toggle (&tmp, NULL))
2752     {
2753       GSList *toggled;
2754       GSList *tmp_list2;
2755
2756       if (gtk_text_iter_compare (&tmp, &second) >= 0)
2757         break; /* past the end of the range */
2758       
2759       toggled = gtk_text_iter_get_toggled_tags (&tmp, TRUE);
2760
2761       /* We could end up with a really big-ass list here.
2762        * Fix it someday.
2763        */
2764       tmp_list2 = toggled;
2765       while (tmp_list2 != NULL)
2766         {
2767           tags = g_slist_prepend (tags, tmp_list2->data);
2768
2769           tmp_list2 = g_slist_next (tmp_list2);
2770         }
2771
2772       g_slist_free (toggled);
2773     }
2774   
2775   /* Sort the list */
2776   tags = g_slist_sort (tags, pointer_cmp);
2777
2778   /* Strip duplicates */
2779   tag = NULL;
2780   prev = NULL;
2781   tmp_list = tags;
2782   while (tmp_list != NULL)
2783     {
2784       if (tag == tmp_list->data)
2785         {
2786           /* duplicate */
2787           next = tmp_list->next;
2788           if (prev)
2789             prev->next = next;
2790
2791           tmp_list->next = NULL;
2792
2793           g_slist_free (tmp_list);
2794
2795           tmp_list = next;
2796           /* prev is unchanged */
2797         }
2798       else
2799         {
2800           /* not a duplicate */
2801           tag = GTK_TEXT_TAG (tmp_list->data);
2802           prev = tmp_list;
2803           tmp_list = tmp_list->next;
2804         }
2805     }
2806
2807   g_slist_foreach (tags, (GFunc) g_object_ref, NULL);
2808   
2809   tmp_list = tags;
2810   while (tmp_list != NULL)
2811     {
2812       tag = GTK_TEXT_TAG (tmp_list->data);
2813
2814       gtk_text_buffer_remove_tag (buffer, tag, &first, &second);
2815       
2816       tmp_list = tmp_list->next;
2817     }
2818
2819   g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
2820   
2821   g_slist_free (tags);
2822 }
2823
2824
2825 /*
2826  * Obtain various iterators
2827  */
2828
2829 /**
2830  * gtk_text_buffer_get_iter_at_line_offset:
2831  * @buffer: a #GtkTextBuffer
2832  * @iter: iterator to initialize
2833  * @line_number: line number counting from 0
2834  * @char_offset: char offset from start of line
2835  *
2836  * Obtains an iterator pointing to @char_offset within the given
2837  * line. The @char_offset must exist, offsets off the end of the line
2838  * are not allowed. Note <emphasis>characters</emphasis>, not bytes;
2839  * UTF-8 may encode one character as multiple bytes.
2840  **/
2841 void
2842 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
2843                                          GtkTextIter   *iter,
2844                                          gint           line_number,
2845                                          gint           char_offset)
2846 {
2847   g_return_if_fail (iter != NULL);
2848   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2849
2850   _gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
2851                                          iter, line_number, char_offset);
2852 }
2853
2854 /**
2855  * gtk_text_buffer_get_iter_at_line_index:
2856  * @buffer: a #GtkTextBuffer 
2857  * @iter: iterator to initialize 
2858  * @line_number: line number counting from 0
2859  * @byte_index: byte index from start of line
2860  *
2861  * Obtains an iterator pointing to @byte_index within the given line.
2862  * @byte_index must be the start of a UTF-8 character, and must not be
2863  * beyond the end of the line.  Note <emphasis>bytes</emphasis>, not
2864  * characters; UTF-8 may encode one character as multiple bytes.
2865  **/
2866 void
2867 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
2868                                          GtkTextIter   *iter,
2869                                          gint           line_number,
2870                                          gint           byte_index)
2871 {
2872   g_return_if_fail (iter != NULL);
2873   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2874
2875   _gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
2876                                          iter, line_number, byte_index);
2877 }
2878
2879 /**
2880  * gtk_text_buffer_get_iter_at_line:
2881  * @buffer: a #GtkTextBuffer 
2882  * @iter: iterator to initialize
2883  * @line_number: line number counting from 0
2884  * 
2885  * Initializes @iter to the start of the given line.
2886  **/
2887 void
2888 gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer,
2889                                   GtkTextIter   *iter,
2890                                   gint           line_number)
2891 {
2892   g_return_if_fail (iter != NULL);
2893   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2894
2895   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
2896 }
2897
2898 /**
2899  * gtk_text_buffer_get_iter_at_offset:
2900  * @buffer: a #GtkTextBuffer 
2901  * @iter: iterator to initialize
2902  * @char_offset: char offset from start of buffer, counting from 0, or -1
2903  *
2904  * Initializes @iter to a position @char_offset chars from the start
2905  * of the entire buffer. If @char_offset is -1 or greater than the number
2906  * of characters in the buffer, @iter is initialized to the end iterator,
2907  * the iterator one past the last valid character in the buffer.
2908  **/
2909 void
2910 gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buffer,
2911                                     GtkTextIter   *iter,
2912                                     gint           char_offset)
2913 {
2914   g_return_if_fail (iter != NULL);
2915   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2916
2917   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
2918 }
2919
2920 /**
2921  * gtk_text_buffer_get_start_iter:
2922  * @buffer: a #GtkTextBuffer
2923  * @iter: iterator to initialize
2924  *
2925  * Initialized @iter with the first position in the text buffer. This
2926  * is the same as using gtk_text_buffer_get_iter_at_offset() to get
2927  * the iter at character offset 0.
2928  **/
2929 void
2930 gtk_text_buffer_get_start_iter (GtkTextBuffer *buffer,
2931                                 GtkTextIter   *iter)
2932 {
2933   g_return_if_fail (iter != NULL);
2934   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2935
2936   _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, 0);
2937 }
2938
2939 /**
2940  * gtk_text_buffer_get_end_iter:
2941  * @buffer: a #GtkTextBuffer 
2942  * @iter: iterator to initialize
2943  *
2944  * Initializes @iter with the "end iterator," one past the last valid
2945  * character in the text buffer. If dereferenced with
2946  * gtk_text_iter_get_char(), the end iterator has a character value of
2947  * 0. The entire buffer lies in the range from the first position in
2948  * the buffer (call gtk_text_buffer_get_start_iter() to get
2949  * character position 0) to the end iterator.
2950  **/
2951 void
2952 gtk_text_buffer_get_end_iter (GtkTextBuffer *buffer,
2953                               GtkTextIter   *iter)
2954 {
2955   g_return_if_fail (iter != NULL);
2956   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2957
2958   _gtk_text_btree_get_end_iter (get_btree (buffer), iter);
2959 }
2960
2961 /**
2962  * gtk_text_buffer_get_bounds:
2963  * @buffer: a #GtkTextBuffer 
2964  * @start: iterator to initialize with first position in the buffer
2965  * @end: iterator to initialize with the end iterator
2966  *
2967  * Retrieves the first and last iterators in the buffer, i.e. the
2968  * entire buffer lies within the range [@start,@end).
2969  **/
2970 void
2971 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
2972                             GtkTextIter   *start,
2973                             GtkTextIter   *end)
2974 {
2975   g_return_if_fail (start != NULL);
2976   g_return_if_fail (end != NULL);
2977   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2978
2979   _gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
2980   _gtk_text_btree_get_end_iter (get_btree (buffer), end);
2981 }
2982
2983 /*
2984  * Modified flag
2985  */
2986
2987 /**
2988  * gtk_text_buffer_get_modified:
2989  * @buffer: a #GtkTextBuffer 
2990  * 
2991  * Indicates whether the buffer has been modified since the last call
2992  * to gtk_text_buffer_set_modified() set the modification flag to
2993  * %FALSE. Used for example to enable a "save" function in a text
2994  * editor.
2995  * 
2996  * Return value: %TRUE if the buffer has been modified
2997  **/
2998 gboolean
2999 gtk_text_buffer_get_modified (GtkTextBuffer *buffer)
3000 {
3001   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3002
3003   return buffer->modified;
3004 }
3005
3006 /**
3007  * gtk_text_buffer_set_modified:
3008  * @buffer: a #GtkTextBuffer 
3009  * @setting: modification flag setting
3010  *
3011  * Used to keep track of whether the buffer has been modified since the
3012  * last time it was saved. Whenever the buffer is saved to disk, call
3013  * gtk_text_buffer_set_modified (@buffer, FALSE). When the buffer is modified,
3014  * it will automatically toggled on the modified bit again. When the modified
3015  * bit flips, the buffer emits a "modified-changed" signal.
3016  **/
3017 void
3018 gtk_text_buffer_set_modified (GtkTextBuffer *buffer,
3019                               gboolean       setting)
3020 {
3021   gboolean fixed_setting;
3022
3023   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3024
3025   fixed_setting = setting != FALSE;
3026
3027   if (buffer->modified == fixed_setting)
3028     return;
3029   else
3030     {
3031       buffer->modified = fixed_setting;
3032       g_signal_emit (buffer, signals[MODIFIED_CHANGED], 0);
3033     }
3034 }
3035
3036 /**
3037  * gtk_text_buffer_get_has_selection:
3038  * @buffer: a #GtkTextBuffer 
3039  * 
3040  * Indicates whether the buffer has some text currently selected.
3041  * 
3042  * Return value: %TRUE if the there is text selected
3043  *
3044  * Since: 2.10
3045  **/
3046 gboolean
3047 gtk_text_buffer_get_has_selection (GtkTextBuffer *buffer)
3048 {
3049   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3050
3051   return buffer->has_selection;
3052 }
3053
3054
3055 /*
3056  * Assorted other stuff
3057  */
3058
3059 /**
3060  * gtk_text_buffer_get_line_count:
3061  * @buffer: a #GtkTextBuffer 
3062  * 
3063  * Obtains the number of lines in the buffer. This value is cached, so
3064  * the function is very fast.
3065  * 
3066  * Return value: number of lines in the buffer
3067  **/
3068 gint
3069 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
3070 {
3071   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3072
3073   return _gtk_text_btree_line_count (get_btree (buffer));
3074 }
3075
3076 /**
3077  * gtk_text_buffer_get_char_count:
3078  * @buffer: a #GtkTextBuffer 
3079  * 
3080  * Gets the number of characters in the buffer; note that characters
3081  * and bytes are not the same, you can't e.g. expect the contents of
3082  * the buffer in string form to be this many bytes long. The character
3083  * count is cached, so this function is very fast.
3084  * 
3085  * Return value: number of characters in the buffer
3086  **/
3087 gint
3088 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
3089 {
3090   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
3091
3092   return _gtk_text_btree_char_count (get_btree (buffer));
3093 }
3094
3095 /* Called when we lose the primary selection.
3096  */
3097 static void
3098 clipboard_clear_selection_cb (GtkClipboard *clipboard,
3099                               gpointer      data)
3100 {
3101   /* Move selection_bound to the insertion point */
3102   GtkTextIter insert;
3103   GtkTextIter selection_bound;
3104   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3105
3106   gtk_text_buffer_get_iter_at_mark (buffer, &insert,
3107                                     gtk_text_buffer_get_insert (buffer));
3108   gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
3109                                     gtk_text_buffer_get_selection_bound (buffer));
3110
3111   if (!gtk_text_iter_equal (&insert, &selection_bound))
3112     gtk_text_buffer_move_mark (buffer,
3113                                gtk_text_buffer_get_selection_bound (buffer),
3114                                &insert);
3115 }
3116
3117 /* Called when we have the primary selection and someone else wants our
3118  * data in order to paste it.
3119  */
3120 static void
3121 clipboard_get_selection_cb (GtkClipboard     *clipboard,
3122                             GtkSelectionData *selection_data,
3123                             guint             info,
3124                             gpointer          data)
3125 {
3126   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
3127   GtkTextIter start, end;
3128
3129   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3130     {
3131       if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3132         {
3133           /* Provide the address of the buffer; this will only be
3134            * used within-process
3135            */
3136           gtk_selection_data_set (selection_data,
3137                                   selection_data->target,
3138                                   8, /* bytes */
3139                                   (void*)&buffer,
3140                                   sizeof (buffer));
3141         }
3142       else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3143         {
3144           guint8 *str;
3145           gsize   len;
3146
3147           str = gtk_text_buffer_serialize (buffer, buffer,
3148                                            selection_data->target,
3149                                            &start, &end, &len);
3150
3151           gtk_selection_data_set (selection_data,
3152                                   selection_data->target,
3153                                   8, /* bytes */
3154                                   str, len);
3155           g_free (str);
3156         }
3157       else
3158         {
3159           gchar *str;
3160
3161           str = gtk_text_iter_get_visible_text (&start, &end);
3162           gtk_selection_data_set_text (selection_data, str, -1);
3163           g_free (str);
3164         }
3165     }
3166 }
3167
3168 static GtkTextBuffer *
3169 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
3170 {
3171   GtkTextBuffer *contents;
3172
3173   contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
3174
3175   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard-source"),
3176                      buffer);
3177   g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
3178                      GINT_TO_POINTER (1));
3179
3180   /*  Ref the source buffer as long as the clipboard contents buffer
3181    *  exists, because it's needed for serializing the contents buffer.
3182    *  See http://bugzilla.gnome.org/show_bug.cgi?id=339195
3183    */
3184   g_object_ref (buffer);
3185   g_object_weak_ref (G_OBJECT (contents), (GWeakNotify) g_object_unref, buffer);
3186
3187   return contents;
3188 }
3189
3190 /* Provide cut/copied data */
3191 static void
3192 clipboard_get_contents_cb (GtkClipboard     *clipboard,
3193                            GtkSelectionData *selection_data,
3194                            guint             info,
3195                            gpointer          data)
3196 {
3197   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3198
3199   g_assert (contents); /* This should never be called unless we own the clipboard */
3200
3201   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
3202     {
3203       /* Provide the address of the clipboard buffer; this will only
3204        * be used within-process. OK to supply a NULL value for contents.
3205        */
3206       gtk_selection_data_set (selection_data,
3207                               selection_data->target,
3208                               8, /* bytes */
3209                               (void*)&contents,
3210                               sizeof (contents));
3211     }
3212   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
3213     {
3214       GtkTextBuffer *clipboard_source_buffer;
3215       GtkTextIter start, end;
3216       guint8 *str;
3217       gsize   len;
3218
3219       clipboard_source_buffer = g_object_get_data (G_OBJECT (contents),
3220                                                    "gtk-text-buffer-clipboard-source");
3221
3222       gtk_text_buffer_get_bounds (contents, &start, &end);
3223
3224       str = gtk_text_buffer_serialize (clipboard_source_buffer, contents,
3225                                        selection_data->target,
3226                                        &start, &end, &len);
3227
3228       gtk_selection_data_set (selection_data,
3229                               selection_data->target,
3230                               8, /* bytes */
3231                               str, len);
3232       g_free (str);
3233     }
3234   else
3235     {
3236       gchar *str;
3237       GtkTextIter start, end;
3238
3239       gtk_text_buffer_get_bounds (contents, &start, &end);
3240
3241       str = gtk_text_iter_get_visible_text (&start, &end);
3242       gtk_selection_data_set_text (selection_data, str, -1);
3243       g_free (str);
3244     }
3245 }
3246
3247 static void
3248 clipboard_clear_contents_cb (GtkClipboard *clipboard,
3249                              gpointer      data)
3250 {
3251   GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
3252
3253   g_object_unref (contents);
3254 }
3255
3256 static void
3257 get_paste_point (GtkTextBuffer *buffer,
3258                  GtkTextIter   *iter,
3259                  gboolean       clear_afterward)
3260 {
3261   GtkTextIter insert_point;
3262   GtkTextMark *paste_point_override;
3263
3264   paste_point_override = gtk_text_buffer_get_mark (buffer,
3265                                                    "gtk_paste_point_override");
3266
3267   if (paste_point_override != NULL)
3268     {
3269       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3270                                         paste_point_override);
3271       if (clear_afterward)
3272         gtk_text_buffer_delete_mark (buffer,
3273                                      gtk_text_buffer_get_mark (buffer,
3274                                                                "gtk_paste_point_override"));
3275     }
3276   else
3277     {
3278       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
3279                                         gtk_text_buffer_get_insert (buffer));
3280     }
3281
3282   *iter = insert_point;
3283 }
3284
3285 static void
3286 pre_paste_prep (ClipboardRequest *request_data,
3287                 GtkTextIter      *insert_point)
3288 {
3289   GtkTextBuffer *buffer = request_data->buffer;
3290   
3291   get_paste_point (buffer, insert_point, TRUE);
3292
3293   /* If we're going to replace the selection, we insert before it to
3294    * avoid messing it up, then we delete the selection after inserting.
3295    */
3296   if (request_data->replace_selection)
3297     {
3298       GtkTextIter start, end;
3299       
3300       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3301         *insert_point = start;
3302     }
3303 }
3304
3305 static void
3306 post_paste_cleanup (ClipboardRequest *request_data)
3307 {
3308   if (request_data->replace_selection)
3309     {
3310       GtkTextIter start, end;
3311       
3312       if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
3313                                                 &start, &end))
3314         {
3315           if (request_data->interactive)
3316             gtk_text_buffer_delete_interactive (request_data->buffer,
3317                                                 &start,
3318                                                 &end,
3319                                                 request_data->default_editable);
3320           else
3321             gtk_text_buffer_delete (request_data->buffer, &start, &end);
3322         }
3323     }
3324 }
3325
3326 static void
3327 emit_paste_done (GtkTextBuffer *buffer,
3328                  GtkClipboard  *clipboard)
3329 {
3330   g_signal_emit (buffer, signals[PASTE_DONE], 0, clipboard);
3331 }
3332
3333 static void
3334 free_clipboard_request (ClipboardRequest *request_data)
3335 {
3336   g_object_unref (request_data->buffer);
3337   g_free (request_data);
3338 }
3339
3340 /* Called when we request a paste and receive the text data
3341  */
3342 static void
3343 clipboard_text_received (GtkClipboard *clipboard,
3344                          const gchar  *str,
3345                          gpointer      data)
3346 {
3347   ClipboardRequest *request_data = data;
3348   GtkTextBuffer *buffer = request_data->buffer;
3349
3350   if (str)
3351     {
3352       GtkTextIter insert_point;
3353       
3354       if (request_data->interactive) 
3355         gtk_text_buffer_begin_user_action (buffer);
3356
3357       pre_paste_prep (request_data, &insert_point);
3358       
3359       if (request_data->interactive) 
3360         gtk_text_buffer_insert_interactive (buffer, &insert_point,
3361                                             str, -1, request_data->default_editable);
3362       else
3363         gtk_text_buffer_insert (buffer, &insert_point,
3364                                 str, -1);
3365
3366       post_paste_cleanup (request_data);
3367       
3368       if (request_data->interactive) 
3369         gtk_text_buffer_end_user_action (buffer);
3370
3371       emit_paste_done (buffer, clipboard);
3372     }
3373
3374   free_clipboard_request (request_data);
3375 }
3376
3377 static GtkTextBuffer*
3378 selection_data_get_buffer (GtkSelectionData *selection_data,
3379                            ClipboardRequest *request_data)
3380 {
3381   GdkWindow *owner;
3382   GtkTextBuffer *src_buffer = NULL;
3383
3384   /* If we can get the owner, the selection is in-process */
3385   owner = gdk_selection_owner_get_for_display (selection_data->display,
3386                                                selection_data->selection);
3387
3388   if (owner == NULL)
3389     return NULL;
3390   
3391   if (gdk_window_get_window_type (owner) == GDK_WINDOW_FOREIGN)
3392     return NULL;
3393  
3394   if (selection_data->type !=
3395       gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
3396     return NULL;
3397
3398   if (selection_data->length != sizeof (src_buffer))
3399     return NULL;
3400           
3401   memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
3402
3403   if (src_buffer == NULL)
3404     return NULL;
3405   
3406   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
3407
3408   if (gtk_text_buffer_get_tag_table (src_buffer) !=
3409       gtk_text_buffer_get_tag_table (request_data->buffer))
3410     return NULL;
3411   
3412   return src_buffer;
3413 }
3414
3415 #if 0
3416 /* These are pretty handy functions; maybe something like them
3417  * should be in the public API. Also, there are other places in this
3418  * file where they could be used.
3419  */
3420 static gpointer
3421 save_iter (const GtkTextIter *iter,
3422            gboolean           left_gravity)
3423 {
3424   return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
3425                                       NULL,
3426                                       iter,
3427                                       TRUE);
3428 }
3429
3430 static void
3431 restore_iter (const GtkTextIter *iter,
3432               gpointer           save_id)
3433 {
3434   gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
3435                                     (GtkTextIter*) iter,
3436                                     save_id);
3437   gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
3438                                save_id);
3439 }
3440 #endif
3441
3442 static void
3443 clipboard_rich_text_received (GtkClipboard *clipboard,
3444                               GdkAtom       format,
3445                               const guint8 *text,
3446                               gsize         length,
3447                               gpointer      data)
3448 {
3449   ClipboardRequest *request_data = data;
3450   GtkTextIter insert_point;
3451   gboolean retval = TRUE;
3452   GError *error = NULL;
3453
3454   if (text != NULL && length > 0)
3455     {
3456       pre_paste_prep (request_data, &insert_point);
3457
3458       if (request_data->interactive)
3459         gtk_text_buffer_begin_user_action (request_data->buffer);
3460
3461       if (!request_data->interactive ||
3462           gtk_text_iter_can_insert (&insert_point,
3463                                     request_data->default_editable))
3464         {
3465           retval = gtk_text_buffer_deserialize (request_data->buffer,
3466                                                 request_data->buffer,
3467                                                 format,
3468                                                 &insert_point,
3469                                                 text, length,
3470                                                 &error);
3471         }
3472
3473       if (!retval)
3474         {
3475           g_warning ("error pasting: %s\n", error->message);
3476           g_clear_error (&error);
3477         }
3478
3479       if (request_data->interactive)
3480         gtk_text_buffer_end_user_action (request_data->buffer);
3481
3482       emit_paste_done (request_data->buffer, clipboard);
3483
3484       if (retval)
3485         {
3486           post_paste_cleanup (request_data);
3487           return;
3488         }
3489     }
3490
3491   /* Request the text selection instead */
3492   gtk_clipboard_request_text (clipboard,
3493                               clipboard_text_received,
3494                               data);
3495 }
3496
3497 static void
3498 paste_from_buffer (GtkClipboard      *clipboard,
3499                    ClipboardRequest  *request_data,
3500                    GtkTextBuffer     *src_buffer,
3501                    const GtkTextIter *start,
3502                    const GtkTextIter *end)
3503 {
3504   GtkTextIter insert_point;
3505   GtkTextBuffer *buffer = request_data->buffer;
3506   
3507   /* We're about to emit a bunch of signals, so be safe */
3508   g_object_ref (src_buffer);
3509   
3510   pre_paste_prep (request_data, &insert_point);
3511   
3512   if (request_data->interactive) 
3513     gtk_text_buffer_begin_user_action (buffer);
3514
3515   if (!gtk_text_iter_equal (start, end))
3516     {
3517       if (!request_data->interactive ||
3518           (gtk_text_iter_can_insert (&insert_point,
3519                                      request_data->default_editable)))
3520         gtk_text_buffer_real_insert_range (buffer,
3521                                            &insert_point,
3522                                            start,
3523                                            end,
3524                                            request_data->interactive);
3525     }
3526
3527   post_paste_cleanup (request_data);
3528       
3529   if (request_data->interactive) 
3530     gtk_text_buffer_end_user_action (buffer);
3531
3532   emit_paste_done (buffer, clipboard);
3533
3534   g_object_unref (src_buffer);
3535
3536   free_clipboard_request (request_data);
3537 }
3538
3539 static void
3540 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
3541                                      GtkSelectionData *selection_data,
3542                                      gpointer          data)
3543 {
3544   ClipboardRequest *request_data = data;
3545   GtkTextBuffer *src_buffer;
3546
3547   src_buffer = selection_data_get_buffer (selection_data, request_data); 
3548
3549   if (src_buffer)
3550     {
3551       GtkTextIter start, end;
3552
3553       if (g_object_get_data (G_OBJECT (src_buffer), "gtk-text-buffer-clipboard"))
3554         {
3555           gtk_text_buffer_get_bounds (src_buffer, &start, &end);
3556
3557           paste_from_buffer (clipboard, request_data, src_buffer,
3558                              &start, &end);
3559         }
3560       else
3561         {
3562           if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
3563             paste_from_buffer (clipboard, request_data, src_buffer,
3564                                &start, &end);
3565         }
3566     }
3567   else
3568     {
3569       if (gtk_clipboard_wait_is_rich_text_available (clipboard,
3570                                                      request_data->buffer))
3571         {
3572           /* Request rich text */
3573           gtk_clipboard_request_rich_text (clipboard,
3574                                            request_data->buffer,
3575                                            clipboard_rich_text_received,
3576                                            data);
3577         }
3578       else
3579         {
3580           /* Request the text selection instead */
3581           gtk_clipboard_request_text (clipboard,
3582                                       clipboard_text_received,
3583                                       data);
3584         }
3585     }
3586 }
3587
3588 typedef struct
3589 {
3590   GtkClipboard *clipboard;
3591   guint ref_count;
3592 } SelectionClipboard;
3593
3594 static void
3595 update_selection_clipboards (GtkTextBuffer *buffer)
3596 {
3597   GtkTextBufferPrivate *priv;
3598   GSList               *tmp_list = buffer->selection_clipboards;
3599
3600   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3601
3602   gtk_text_buffer_get_copy_target_list (buffer);
3603
3604   while (tmp_list)
3605     {
3606       GtkTextIter start;
3607       GtkTextIter end;
3608       
3609       SelectionClipboard *selection_clipboard = tmp_list->data;
3610       GtkClipboard *clipboard = selection_clipboard->clipboard;
3611
3612       /* Determine whether we have a selection and adjust X selection
3613        * accordingly.
3614        */
3615       if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3616         {
3617           if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
3618             gtk_clipboard_clear (clipboard);
3619         }
3620       else
3621         {
3622           /* Even if we already have the selection, we need to update our
3623            * timestamp.
3624            */
3625           if (!gtk_clipboard_set_with_owner (clipboard,
3626                                              priv->copy_target_entries,
3627                                              priv->n_copy_target_entries,
3628                                              clipboard_get_selection_cb,
3629                                              clipboard_clear_selection_cb,
3630                                              G_OBJECT (buffer)))
3631             clipboard_clear_selection_cb (clipboard, buffer);
3632         }
3633
3634       tmp_list = tmp_list->next;
3635     }
3636 }
3637
3638 static SelectionClipboard *
3639 find_selection_clipboard (GtkTextBuffer *buffer,
3640                           GtkClipboard  *clipboard)
3641 {
3642   GSList *tmp_list = buffer->selection_clipboards;
3643   while (tmp_list)
3644     {
3645       SelectionClipboard *selection_clipboard = tmp_list->data;
3646       if (selection_clipboard->clipboard == clipboard)
3647         return selection_clipboard;
3648       
3649       tmp_list = tmp_list->next;
3650     }
3651
3652   return NULL;
3653 }
3654
3655 /**
3656  * gtk_text_buffer_add_selection_clipboard:
3657  * @buffer: a #GtkTextBuffer
3658  * @clipboard: a #GtkClipboard
3659  * 
3660  * Adds @clipboard to the list of clipboards in which the selection 
3661  * contents of @buffer are available. In most cases, @clipboard will be 
3662  * the #GtkClipboard of type %GDK_SELECTION_PRIMARY for a view of @buffer.
3663  **/
3664 void
3665 gtk_text_buffer_add_selection_clipboard (GtkTextBuffer *buffer,
3666                                          GtkClipboard  *clipboard)
3667 {
3668   SelectionClipboard *selection_clipboard;
3669
3670   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3671   g_return_if_fail (clipboard != NULL);
3672
3673   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3674   if (selection_clipboard)
3675     {
3676       selection_clipboard->ref_count++;
3677     }
3678   else
3679     {
3680       selection_clipboard = g_new (SelectionClipboard, 1);
3681
3682       selection_clipboard->clipboard = clipboard;
3683       selection_clipboard->ref_count = 1;
3684
3685       buffer->selection_clipboards = g_slist_prepend (buffer->selection_clipboards, selection_clipboard);
3686     }
3687 }
3688
3689 /**
3690  * gtk_text_buffer_remove_selection_clipboard:
3691  * @buffer: a #GtkTextBuffer
3692  * @clipboard: a #GtkClipboard added to @buffer by 
3693  *             gtk_text_buffer_add_selection_clipboard()
3694  * 
3695  * Removes a #GtkClipboard added with 
3696  * gtk_text_buffer_add_selection_clipboard().
3697  **/
3698 void 
3699 gtk_text_buffer_remove_selection_clipboard (GtkTextBuffer *buffer,
3700                                             GtkClipboard  *clipboard)
3701 {
3702   SelectionClipboard *selection_clipboard;
3703
3704   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
3705   g_return_if_fail (clipboard != NULL);
3706
3707   selection_clipboard = find_selection_clipboard (buffer, clipboard);
3708   g_return_if_fail (selection_clipboard != NULL);
3709
3710   selection_clipboard->ref_count--;
3711   if (selection_clipboard->ref_count == 0)
3712     {
3713       if (gtk_clipboard_get_owner (selection_clipboard->clipboard) == G_OBJECT (buffer))
3714         gtk_clipboard_clear (selection_clipboard->clipboard);
3715
3716       buffer->selection_clipboards = g_slist_remove (buffer->selection_clipboards,
3717                                                      selection_clipboard);
3718       
3719       g_free (selection_clipboard);
3720     }
3721 }
3722
3723 static void
3724 remove_all_selection_clipboards (GtkTextBuffer *buffer)
3725 {
3726   g_slist_foreach (buffer->selection_clipboards, (GFunc)g_free, NULL);
3727   g_slist_free (buffer->selection_clipboards);
3728   buffer->selection_clipboards = NULL;
3729 }
3730
3731 /**
3732  * gtk_text_buffer_paste_clipboard:
3733  * @buffer: a #GtkTextBuffer
3734  * @clipboard: the #GtkClipboard to paste from
3735  * @override_location: location to insert pasted text, or %NULL for 
3736  *                     at the cursor
3737  * @default_editable: whether the buffer is editable by default
3738  *
3739  * Pastes the contents of a clipboard at the insertion point, or at 
3740  * @override_location. (Note: pasting is asynchronous, that is, we'll 
3741  * ask for the paste data and return, and at some point later after 
3742  * the main loop runs, the paste data will be inserted.)
3743  **/
3744 void
3745 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
3746                                  GtkClipboard  *clipboard,
3747                                  GtkTextIter   *override_location,
3748                                  gboolean       default_editable)
3749 {
3750   ClipboardRequest *data = g_new (ClipboardRequest, 1);
3751   GtkTextIter paste_point;
3752   GtkTextIter start, end;
3753
3754   if (override_location != NULL)
3755     gtk_text_buffer_create_mark (buffer,
3756                                  "gtk_paste_point_override",
3757                                  override_location, FALSE);
3758
3759   data->buffer = g_object_ref (buffer);
3760   data->interactive = TRUE;
3761   data->default_editable = default_editable;
3762
3763   /* When pasting with the cursor inside the selection area, you
3764    * replace the selection with the new text, otherwise, you
3765    * simply insert the new text at the point where the click
3766    * occured, unselecting any selected text. The replace_selection
3767    * flag toggles this behavior.
3768    */
3769   data->replace_selection = FALSE;
3770   
3771   get_paste_point (buffer, &paste_point, FALSE);
3772   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
3773       (gtk_text_iter_in_range (&paste_point, &start, &end) ||
3774        gtk_text_iter_equal (&paste_point, &end)))
3775     data->replace_selection = TRUE;
3776
3777   gtk_clipboard_request_contents (clipboard,
3778                                   gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
3779                                   clipboard_clipboard_buffer_received, data);
3780 }
3781
3782 /**
3783  * gtk_text_buffer_delete_selection:
3784  * @buffer: a #GtkTextBuffer 
3785  * @interactive: whether the deletion is caused by user interaction
3786  * @default_editable: whether the buffer is editable by default
3787  *
3788  * Deletes the range between the "insert" and "selection_bound" marks,
3789  * that is, the currently-selected text. If @interactive is %TRUE,
3790  * the editability of the selection will be considered (users can't delete
3791  * uneditable text).
3792  * 
3793  * Return value: whether there was a non-empty selection to delete
3794  **/
3795 gboolean
3796 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
3797                                   gboolean interactive,
3798                                   gboolean default_editable)
3799 {
3800   GtkTextIter start;
3801   GtkTextIter end;
3802
3803   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3804     {
3805       return FALSE; /* No selection */
3806     }
3807   else
3808     {
3809       if (interactive)
3810         gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
3811       else
3812         gtk_text_buffer_delete (buffer, &start, &end);
3813
3814       return TRUE; /* We deleted stuff */
3815     }
3816 }
3817
3818 /**
3819  * gtk_text_buffer_backspace:
3820  * @buffer: a #GtkTextBuffer
3821  * @iter: a position in @buffer
3822  * @interactive: whether the deletion is caused by user interaction
3823  * @default_editable: whether the buffer is editable by default
3824  * 
3825  * Performs the appropriate action as if the user hit the delete
3826  * key with the cursor at the position specified by @iter. In the
3827  * normal case a single character will be deleted, but when
3828  * combining accents are involved, more than one character can
3829  * be deleted, and when precomposed character and accent combinations
3830  * are involved, less than one character will be deleted.
3831  * 
3832  * Because the buffer is modified, all outstanding iterators become 
3833  * invalid after calling this function; however, the @iter will be
3834  * re-initialized to point to the location where text was deleted. 
3835  *
3836  * Return value: %TRUE if the buffer was modified
3837  *
3838  * Since: 2.6
3839  **/
3840 gboolean
3841 gtk_text_buffer_backspace (GtkTextBuffer *buffer,
3842                            GtkTextIter   *iter,
3843                            gboolean       interactive,
3844                            gboolean       default_editable)
3845 {
3846   gchar *cluster_text;
3847   GtkTextIter start;
3848   GtkTextIter end;
3849   gboolean retval = FALSE;
3850   const PangoLogAttr *attrs;
3851   int offset;
3852   gboolean backspace_deletes_character;
3853
3854   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
3855   g_return_val_if_fail (iter != NULL, FALSE);
3856
3857   start = *iter;
3858   end = *iter;
3859
3860   attrs = _gtk_text_buffer_get_line_log_attrs (buffer, &start, NULL);
3861
3862   /* For no good reason, attrs is NULL for the empty last line in
3863    * a buffer. Special case that here. (#156164)
3864    */
3865   if (attrs)
3866     {
3867       offset = gtk_text_iter_get_line_offset (&start);
3868       backspace_deletes_character = attrs[offset].backspace_deletes_character;
3869     }
3870   else
3871     backspace_deletes_character = FALSE;
3872
3873   gtk_text_iter_backward_cursor_position (&start);
3874
3875   if (gtk_text_iter_equal (&start, &end))
3876     return FALSE;
3877     
3878   cluster_text = gtk_text_iter_get_text (&start, &end);
3879
3880   if (interactive)
3881     gtk_text_buffer_begin_user_action (buffer);
3882   
3883   if (gtk_text_buffer_delete_interactive (buffer, &start, &end,
3884                                           default_editable))
3885     {
3886       /* special case \r\n, since we never want to reinsert \r */
3887       if (backspace_deletes_character && strcmp ("\r\n", cluster_text))
3888         {
3889           gchar *normalized_text = g_utf8_normalize (cluster_text,
3890                                                      strlen (cluster_text),
3891                                                      G_NORMALIZE_NFD);
3892           glong len = g_utf8_strlen (normalized_text, -1);
3893
3894           if (len > 1)
3895             gtk_text_buffer_insert_interactive (buffer,
3896                                                 &start,
3897                                                 normalized_text,
3898                                                 g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
3899                                                 default_editable);
3900           
3901           g_free (normalized_text);
3902         }
3903
3904       retval = TRUE;
3905     }
3906   
3907   if (interactive)
3908     gtk_text_buffer_end_user_action (buffer);
3909   
3910   g_free (cluster_text);
3911
3912   /* Revalidate the users iter */
3913   *iter = start;
3914
3915   return retval;
3916 }
3917
3918 static void
3919 cut_or_copy (GtkTextBuffer *buffer,
3920              GtkClipboard  *clipboard,
3921              gboolean       delete_region_after,
3922              gboolean       interactive,
3923              gboolean       default_editable)
3924 {
3925   GtkTextBufferPrivate *priv;
3926
3927   /* We prefer to cut the selected region between selection_bound and
3928    * insertion point. If that region is empty, then we cut the region
3929    * between the "anchor" and the insertion point (this is for
3930    * C-space and M-w and other Emacs-style copy/yank keys). Note that
3931    * insert and selection_bound are guaranteed to exist, but the
3932    * anchor only exists sometimes.
3933    */
3934   GtkTextIter start;
3935   GtkTextIter end;
3936
3937   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
3938
3939   gtk_text_buffer_get_copy_target_list (buffer);
3940
3941   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
3942     {
3943       /* Let's try the anchor thing */
3944       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
3945
3946       if (anchor == NULL)
3947         return;
3948       else
3949         {
3950           gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
3951           gtk_text_iter_order (&start, &end);
3952         }
3953     }
3954
3955   if (!gtk_text_iter_equal (&start, &end))
3956     {
3957       GtkTextIter ins;
3958       GtkTextBuffer *contents;
3959
3960       contents = create_clipboard_contents_buffer (buffer);
3961
3962       gtk_text_buffer_get_iter_at_offset (contents, &ins, 0);
3963       
3964       gtk_text_buffer_insert_range (contents, &ins, &start, &end);
3965                                     
3966       if (!gtk_clipboard_set_with_data (clipboard,
3967                                         priv->copy_target_entries,
3968                                         priv->n_copy_target_entries,
3969                                         clipboard_get_contents_cb,
3970                                         clipboard_clear_contents_cb,
3971                                         contents))
3972         g_object_unref (contents);
3973       else
3974         gtk_clipboard_set_can_store (clipboard,
3975                                      priv->copy_target_entries + 1,
3976                                      priv->n_copy_target_entries - 1);
3977
3978       if (delete_region_after)
3979         {
3980           if (interactive)
3981             gtk_text_buffer_delete_interactive (buffer, &start, &end,
3982                                                 default_editable);
3983           else
3984             gtk_text_buffer_delete (buffer, &start, &end);
3985         }
3986     }
3987 }
3988
3989 /**
3990  * gtk_text_buffer_cut_clipboard:
3991  * @buffer: a #GtkTextBuffer
3992  * @clipboard: the #GtkClipboard object to cut to
3993  * @default_editable: default editability of the buffer
3994  *
3995  * Copies the currently-selected text to a clipboard, then deletes
3996  * said text if it's editable.
3997  **/
3998 void
3999 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
4000                                GtkClipboard  *clipboard,
4001                                gboolean       default_editable)
4002 {
4003   gtk_text_buffer_begin_user_action (buffer);
4004   cut_or_copy (buffer, clipboard, TRUE, TRUE, default_editable);
4005   gtk_text_buffer_end_user_action (buffer);
4006 }
4007
4008 /**
4009  * gtk_text_buffer_copy_clipboard:
4010  * @buffer: a #GtkTextBuffer 
4011  * @clipboard: the #GtkClipboard object to copy to
4012  *
4013  * Copies the currently-selected text to a clipboard.
4014  **/
4015 void
4016 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer,
4017                                 GtkClipboard  *clipboard)
4018 {
4019   gtk_text_buffer_begin_user_action (buffer);
4020   cut_or_copy (buffer, clipboard, FALSE, TRUE, TRUE);
4021   gtk_text_buffer_end_user_action (buffer);
4022 }
4023
4024 /**
4025  * gtk_text_buffer_get_selection_bounds:
4026  * @buffer: a #GtkTextBuffer a #GtkTextBuffer
4027  * @start: iterator to initialize with selection start
4028  * @end: iterator to initialize with selection end
4029  *
4030  * Returns %TRUE if some text is selected; places the bounds
4031  * of the selection in @start and @end (if the selection has length 0,
4032  * then @start and @end are filled in with the same value).
4033  * @start and @end will be in ascending order. If @start and @end are
4034  * NULL, then they are not filled in, but the return value still indicates
4035  * whether text is selected.
4036  *
4037  * Return value: whether the selection has nonzero length
4038  **/
4039 gboolean
4040 gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer,
4041                                       GtkTextIter   *start,
4042                                       GtkTextIter   *end)
4043 {
4044   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
4045
4046   return _gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
4047 }
4048
4049 /**
4050  * gtk_text_buffer_begin_user_action:
4051  * @buffer: a #GtkTextBuffer
4052  * 
4053  * Called to indicate that the buffer operations between here and a
4054  * call to gtk_text_buffer_end_user_action() are part of a single
4055  * user-visible operation. The operations between
4056  * gtk_text_buffer_begin_user_action() and
4057  * gtk_text_buffer_end_user_action() can then be grouped when creating
4058  * an undo stack. #GtkTextBuffer maintains a count of calls to
4059  * gtk_text_buffer_begin_user_action() that have not been closed with
4060  * a call to gtk_text_buffer_end_user_action(), and emits the 
4061  * "begin-user-action" and "end-user-action" signals only for the 
4062  * outermost pair of calls. This allows you to build user actions 
4063  * from other user actions.
4064  *
4065  * The "interactive" buffer mutation functions, such as
4066  * gtk_text_buffer_insert_interactive(), automatically call begin/end
4067  * user action around the buffer operations they perform, so there's
4068  * no need to add extra calls if you user action consists solely of a
4069  * single call to one of those functions.
4070  **/
4071 void
4072 gtk_text_buffer_begin_user_action (GtkTextBuffer *buffer)
4073 {
4074   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4075
4076   buffer->user_action_count += 1;
4077   
4078   if (buffer->user_action_count == 1)
4079     {
4080       /* Outermost nested user action begin emits the signal */
4081       g_signal_emit (buffer, signals[BEGIN_USER_ACTION], 0);
4082     }
4083 }
4084
4085 /**
4086  * gtk_text_buffer_end_user_action:
4087  * @buffer: a #GtkTextBuffer
4088  * 
4089  * Should be paired with a call to gtk_text_buffer_begin_user_action().
4090  * See that function for a full explanation.
4091  **/
4092 void
4093 gtk_text_buffer_end_user_action (GtkTextBuffer *buffer)
4094 {
4095   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
4096   g_return_if_fail (buffer->user_action_count > 0);
4097   
4098   buffer->user_action_count -= 1;
4099   
4100   if (buffer->user_action_count == 0)
4101     {
4102       /* Ended the outermost-nested user action end, so emit the signal */
4103       g_signal_emit (buffer, signals[END_USER_ACTION], 0);
4104     }
4105 }
4106
4107 static void
4108 gtk_text_buffer_free_target_lists (GtkTextBuffer *buffer)
4109 {
4110   GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4111
4112   if (priv->copy_target_list)
4113     {
4114       gtk_target_list_unref (priv->copy_target_list);
4115       priv->copy_target_list = NULL;
4116
4117       gtk_target_table_free (priv->copy_target_entries,
4118                              priv->n_copy_target_entries);
4119       priv->copy_target_entries = NULL;
4120       priv->n_copy_target_entries = 0;
4121     }
4122
4123   if (priv->paste_target_list)
4124     {
4125       gtk_target_list_unref (priv->paste_target_list);
4126       priv->paste_target_list = NULL;
4127
4128       gtk_target_table_free (priv->paste_target_entries,
4129                              priv->n_paste_target_entries);
4130       priv->paste_target_entries = NULL;
4131       priv->n_paste_target_entries = 0;
4132     }
4133 }
4134
4135 static GtkTargetList *
4136 gtk_text_buffer_get_target_list (GtkTextBuffer   *buffer,
4137                                  gboolean         deserializable,
4138                                  GtkTargetEntry **entries,
4139                                  gint            *n_entries)
4140 {
4141   GtkTargetList *target_list;
4142
4143   target_list = gtk_target_list_new (NULL, 0);
4144
4145   gtk_target_list_add (target_list,
4146                        gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
4147                        GTK_TARGET_SAME_APP,
4148                        GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS);
4149
4150   gtk_target_list_add_rich_text_targets (target_list,
4151                                          GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
4152                                          deserializable,
4153                                          buffer);
4154
4155   gtk_target_list_add_text_targets (target_list,
4156                                     GTK_TEXT_BUFFER_TARGET_INFO_TEXT);
4157
4158   *entries = gtk_target_table_new_from_list (target_list, n_entries);
4159
4160   return target_list;
4161 }
4162
4163 /**
4164  * gtk_text_buffer_get_copy_target_list:
4165  * @buffer: a #GtkTextBuffer
4166  *
4167  * This function returns the list of targets this text buffer can
4168  * provide for copying and as DND source. The targets in the list are
4169  * added with %info values from the #GtkTextBufferTargetInfo enum,
4170  * using gtk_target_list_add_rich_text_targets() and
4171  * gtk_target_list_add_text_targets().
4172  *
4173  * Return value: the #GtkTargetList
4174  *
4175  * Since: 2.10
4176  **/
4177 GtkTargetList *
4178 gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer)
4179 {
4180   GtkTextBufferPrivate *priv;
4181
4182   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4183
4184   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4185
4186   if (! priv->copy_target_list)
4187     priv->copy_target_list =
4188       gtk_text_buffer_get_target_list (buffer, FALSE,
4189                                        &priv->copy_target_entries,
4190                                        &priv->n_copy_target_entries);
4191
4192   return priv->copy_target_list;
4193 }
4194
4195 /**
4196  * gtk_text_buffer_get_paste_target_list:
4197  * @buffer: a #GtkTextBuffer
4198  *
4199  * This function returns the list of targets this text buffer supports
4200  * for pasting and as DND destination. The targets in the list are
4201  * added with %info values from the #GtkTextBufferTargetInfo enum,
4202  * using gtk_target_list_add_rich_text_targets() and
4203  * gtk_target_list_add_text_targets().
4204  *
4205  * Return value: the #GtkTargetList
4206  *
4207  * Since: 2.10
4208  **/
4209 GtkTargetList *
4210 gtk_text_buffer_get_paste_target_list (GtkTextBuffer *buffer)
4211 {
4212   GtkTextBufferPrivate *priv;
4213
4214   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4215
4216   priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
4217
4218   if (! priv->paste_target_list)
4219     priv->paste_target_list =
4220       gtk_text_buffer_get_target_list (buffer, TRUE,
4221                                        &priv->paste_target_entries,
4222                                        &priv->n_paste_target_entries);
4223
4224   return priv->paste_target_list;
4225 }
4226
4227 /*
4228  * Logical attribute cache
4229  */
4230
4231 #define ATTR_CACHE_SIZE 2
4232
4233 typedef struct _CacheEntry CacheEntry;
4234 struct _CacheEntry
4235 {
4236   gint line;
4237   gint char_len;
4238   PangoLogAttr *attrs;
4239 };
4240
4241 struct _GtkTextLogAttrCache
4242 {
4243   gint chars_changed_stamp;
4244   CacheEntry entries[ATTR_CACHE_SIZE];
4245 };
4246
4247 static void
4248 free_log_attr_cache (GtkTextLogAttrCache *cache)
4249 {
4250   gint i = 0;
4251   while (i < ATTR_CACHE_SIZE)
4252     {
4253       g_free (cache->entries[i].attrs);
4254       ++i;
4255     }
4256   g_free (cache);
4257 }
4258
4259 static void
4260 clear_log_attr_cache (GtkTextLogAttrCache *cache)
4261 {
4262   gint i = 0;
4263   while (i < ATTR_CACHE_SIZE)
4264     {
4265       g_free (cache->entries[i].attrs);
4266       cache->entries[i].attrs = NULL;
4267       ++i;
4268     }
4269 }
4270
4271 static PangoLogAttr*
4272 compute_log_attrs (const GtkTextIter *iter,
4273                    gint              *char_lenp)
4274 {
4275   GtkTextIter start;
4276   GtkTextIter end;
4277   gchar *paragraph;
4278   gint char_len, byte_len;
4279   PangoLogAttr *attrs = NULL;
4280   
4281   start = *iter;
4282   end = *iter;
4283
4284   gtk_text_iter_set_line_offset (&start, 0);
4285   gtk_text_iter_forward_line (&end);
4286
4287   paragraph = gtk_text_iter_get_slice (&start, &end);
4288   char_len = g_utf8_strlen (paragraph, -1);
4289   byte_len = strlen (paragraph);
4290
4291   g_assert (char_len > 0);
4292
4293   if (char_lenp)
4294     *char_lenp = char_len;
4295   
4296   attrs = g_new (PangoLogAttr, char_len + 1);
4297
4298   /* FIXME we need to follow PangoLayout and allow different language
4299    * tags within the paragraph
4300    */
4301   pango_get_log_attrs (paragraph, byte_len, -1,
4302                        gtk_text_iter_get_language (&start),
4303                        attrs,
4304                        char_len + 1);
4305   
4306   g_free (paragraph);
4307
4308   return attrs;
4309 }
4310
4311 /* The return value from this is valid until you call this a second time.
4312  */
4313 const PangoLogAttr*
4314 _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer     *buffer,
4315                                      const GtkTextIter *anywhere_in_line,
4316                                      gint              *char_len)
4317 {
4318   gint line;
4319   GtkTextLogAttrCache *cache;
4320   gint i;
4321   
4322   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
4323   g_return_val_if_fail (anywhere_in_line != NULL, NULL);
4324
4325   /* special-case for empty last line in buffer */
4326   if (gtk_text_iter_is_end (anywhere_in_line) &&
4327       gtk_text_iter_get_line_offset (anywhere_in_line) == 0)
4328     {
4329       if (char_len)
4330         *char_len = 0;
4331       return NULL;
4332     }
4333   
4334   /* FIXME we also need to recompute log attrs if the language tag at
4335    * the start of a paragraph changes
4336    */
4337   
4338   if (buffer->log_attr_cache == NULL)
4339     {
4340       buffer->log_attr_cache = g_new0 (GtkTextLogAttrCache, 1);
4341       buffer->log_attr_cache->chars_changed_stamp =
4342         _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer));
4343     }
4344   else if (buffer->log_attr_cache->chars_changed_stamp !=
4345            _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer)))
4346     {
4347       clear_log_attr_cache (buffer->log_attr_cache);
4348     }
4349   
4350   cache = buffer->log_attr_cache;
4351   line = gtk_text_iter_get_line (anywhere_in_line);
4352
4353   i = 0;
4354   while (i < ATTR_CACHE_SIZE)
4355     {
4356       if (cache->entries[i].attrs &&
4357           cache->entries[i].line == line)
4358         {
4359           if (char_len)
4360             *char_len = cache->entries[i].char_len;
4361           return cache->entries[i].attrs;
4362         }
4363       ++i;
4364     }
4365   
4366   /* Not in cache; open up the first cache entry */
4367   g_free (cache->entries[ATTR_CACHE_SIZE-1].attrs);
4368   
4369   g_memmove (cache->entries + 1, cache->entries,
4370              sizeof (CacheEntry) * (ATTR_CACHE_SIZE - 1));
4371
4372   cache->entries[0].line = line;
4373   cache->entries[0].attrs = compute_log_attrs (anywhere_in_line,
4374                                                &cache->entries[0].char_len);
4375
4376   if (char_len)
4377     *char_len = cache->entries[0].char_len;
4378   
4379   return cache->entries[0].attrs;
4380 }
4381
4382 void
4383 _gtk_text_buffer_notify_will_remove_tag (GtkTextBuffer *buffer,
4384                                          GtkTextTag    *tag)
4385 {
4386   /* This removes tag from the buffer, but DOESN'T emit the
4387    * remove-tag signal, because we can't afford to have user
4388    * code messing things up at this point; the tag MUST be removed
4389    * entirely.
4390    */
4391   if (buffer->btree)
4392     _gtk_text_btree_notify_will_remove_tag (buffer->btree, tag);
4393 }
4394
4395 /*
4396  * Debug spew
4397  */
4398
4399 void
4400 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
4401 {
4402   _gtk_text_btree_spew (get_btree (buffer));
4403 }
4404
4405 #define __GTK_TEXT_BUFFER_C__
4406 #include "gtkaliasdef.c"