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