]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
urg, removed implementation of gtk_marshal_VOID__INT_INT_INT_INT. if
[~andy/gtk] / gtk / gtktextbuffer.c
1 /* GTK - The GIMP Toolkit
2  * gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27
28 #include <string.h>
29
30 #include "gtkclipboard.h"
31 #include "gtkinvisible.h"
32 #include "gtksignal.h"
33 #include "gtktextbuffer.h"
34 #include "gtktextbtree.h"
35 #include "gtktextiterprivate.h"
36 #include <string.h>
37
38 typedef struct _ClipboardRequest ClipboardRequest;
39
40 struct _ClipboardRequest
41 {
42   GtkTextBuffer *buffer;
43   gboolean interactive;
44   gboolean default_editable;
45   gboolean is_clipboard;
46 };
47
48 enum {
49   INSERT_TEXT,
50   DELETE_TEXT,
51   CHANGED,
52   MODIFIED_CHANGED,
53   MARK_SET,
54   MARK_DELETED,
55   APPLY_TAG,
56   REMOVE_TAG,
57   LAST_SIGNAL
58 };
59
60 enum {
61   ARG_0,
62   LAST_ARG
63 };
64
65 enum {
66   TARGET_STRING,
67   TARGET_TEXT,
68   TARGET_COMPOUND_TEXT,
69   TARGET_UTF8_STRING
70 };
71
72 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
73 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
74 static void gtk_text_buffer_destroy    (GtkObject          *object);
75 static void gtk_text_buffer_finalize   (GObject            *object);
76
77
78 static void gtk_text_buffer_update_primary_selection   (GtkTextBuffer     *buffer);
79 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
80                                                         GtkTextIter       *iter,
81                                                         const gchar       *text,
82                                                         gint               len,
83                                                         gboolean           interactive);
84 static void gtk_text_buffer_real_delete_text           (GtkTextBuffer     *buffer,
85                                                         GtkTextIter       *start,
86                                                         GtkTextIter       *end,
87                                                         gboolean           interactive);
88 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
89                                                         GtkTextTag        *tag,
90                                                         const GtkTextIter *start_char,
91                                                         const GtkTextIter *end_char);
92 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
93                                                         GtkTextTag        *tag,
94                                                         const GtkTextIter *start_char,
95                                                         const GtkTextIter *end_char);
96
97 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
98
99 static GtkObjectClass *parent_class = NULL;
100 static guint signals[LAST_SIGNAL] = { 0 };
101
102 GtkType
103 gtk_text_buffer_get_type (void)
104 {
105   static GtkType our_type = 0;
106
107   if (our_type == 0)
108     {
109       static const GtkTypeInfo our_info =
110       {
111         "GtkTextBuffer",
112         sizeof (GtkTextBuffer),
113         sizeof (GtkTextBufferClass),
114         (GtkClassInitFunc) gtk_text_buffer_class_init,
115         (GtkObjectInitFunc) gtk_text_buffer_init,
116         /* reserved_1 */ NULL,
117         /* reserved_2 */ NULL,
118         (GtkClassInitFunc) NULL
119       };
120
121       our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
122     }
123
124   return our_type;
125 }
126
127 static void
128 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
129 {
130   GtkObjectClass *object_class = (GtkObjectClass*) klass;
131   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
132
133   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
134   
135   signals[INSERT_TEXT] =
136     gtk_signal_new ("insert_text",
137                     GTK_RUN_LAST,
138                     GTK_CLASS_TYPE (object_class),
139                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
140                     gtk_marshal_VOID__POINTER_POINTER_INT_INT,
141                     GTK_TYPE_NONE,
142                     4,
143                     GTK_TYPE_POINTER,
144                     GTK_TYPE_POINTER,
145                     GTK_TYPE_INT,
146                     GTK_TYPE_BOOL);
147
148   signals[DELETE_TEXT] =
149     gtk_signal_new ("delete_text",
150                     GTK_RUN_LAST,
151                     GTK_CLASS_TYPE (object_class),
152                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
153                     gtk_marshal_VOID__POINTER_POINTER_INT,
154                     GTK_TYPE_NONE,
155                     3,
156                     GTK_TYPE_POINTER,
157                     GTK_TYPE_POINTER,
158                     GTK_TYPE_BOOL);
159
160   signals[CHANGED] =
161     gtk_signal_new ("changed",
162                     GTK_RUN_LAST,
163                     GTK_CLASS_TYPE (object_class),
164                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
165                     gtk_marshal_VOID__VOID,
166                     GTK_TYPE_NONE,
167                     0);
168
169   signals[MODIFIED_CHANGED] =
170     gtk_signal_new ("modified_changed",
171                     GTK_RUN_LAST,
172                     GTK_CLASS_TYPE (object_class),
173                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
174                     gtk_marshal_VOID__VOID,
175                     GTK_TYPE_NONE,
176                     0);
177   
178   signals[MARK_SET] =
179     gtk_signal_new ("mark_set",
180                     GTK_RUN_LAST,
181                     GTK_CLASS_TYPE (object_class),
182                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
183                     gtk_marshal_VOID__POINTER_POINTER,
184                     GTK_TYPE_NONE,
185                     2,
186                     GTK_TYPE_POINTER,
187                     GTK_TYPE_POINTER);
188
189   signals[MARK_DELETED] =
190     gtk_signal_new ("mark_deleted",
191                     GTK_RUN_LAST,
192                     GTK_CLASS_TYPE (object_class),
193                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
194                     gtk_marshal_VOID__POINTER,
195                     GTK_TYPE_NONE,
196                     1,
197                     GTK_TYPE_POINTER);
198
199   signals[APPLY_TAG] =
200     gtk_signal_new ("apply_tag",
201                     GTK_RUN_LAST,
202                     GTK_CLASS_TYPE (object_class),
203                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
204                     gtk_marshal_VOID__POINTER_POINTER_POINTER,
205                     GTK_TYPE_NONE,
206                     3,
207                     GTK_TYPE_POINTER,
208                     GTK_TYPE_POINTER,
209                     GTK_TYPE_POINTER);
210     
211   signals[REMOVE_TAG] =
212     gtk_signal_new ("remove_tag",
213                     GTK_RUN_LAST,
214                     GTK_CLASS_TYPE (object_class),
215                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
216                     gtk_marshal_VOID__POINTER_POINTER_POINTER,
217                     GTK_TYPE_NONE,
218                     3,
219                     GTK_TYPE_POINTER,
220                     GTK_TYPE_POINTER,
221                     GTK_TYPE_POINTER);
222   
223   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
224
225   object_class->destroy = gtk_text_buffer_destroy;
226
227   gobject_class->finalize = gtk_text_buffer_finalize;
228
229   klass->insert_text = gtk_text_buffer_real_insert_text;
230   klass->delete_text = gtk_text_buffer_real_delete_text;
231   klass->apply_tag = gtk_text_buffer_real_apply_tag;
232   klass->remove_tag = gtk_text_buffer_real_remove_tag;
233 }
234
235 void
236 gtk_text_buffer_init (GtkTextBuffer *buffer)
237 {
238 }
239
240 /**
241  * gtk_text_buffer_new:
242  * @table: a tag table, or NULL to create a new one
243  * 
244  * Creates a new text buffer.
245  * 
246  * Return value: a new text buffer
247  **/
248 GtkTextBuffer*
249 gtk_text_buffer_new (GtkTextTagTable *table)
250 {
251   GtkTextBuffer *text_buffer;
252   
253   text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
254
255   if (table)
256     {
257       text_buffer->tag_table = table;
258       
259       gtk_object_ref (GTK_OBJECT(text_buffer->tag_table));
260       gtk_object_sink (GTK_OBJECT(text_buffer->tag_table));
261     } 
262   
263   return text_buffer;
264 }
265
266 static void
267 gtk_text_buffer_destroy (GtkObject *object)
268 {
269   GtkTextBuffer *buffer;
270
271   buffer = GTK_TEXT_BUFFER (object);
272
273   if (buffer->tag_table)
274     {
275       gtk_object_unref(GTK_OBJECT(buffer->tag_table));
276       buffer->tag_table = NULL;
277     }
278
279   if (buffer->btree)
280     {
281       gtk_text_btree_unref(buffer->btree);
282       buffer->btree = NULL;
283     }
284   
285   (* parent_class->destroy) (object);
286 }
287
288 static void
289 gtk_text_buffer_finalize (GObject *object)
290 {
291   GtkTextBuffer *tkxt_buffer;
292
293   tkxt_buffer = GTK_TEXT_BUFFER (object);
294
295   G_OBJECT_CLASS (parent_class)->finalize (object);
296 }
297
298 static GtkTextTagTable*
299 get_table (GtkTextBuffer *buffer)
300 {
301   if (buffer->tag_table == NULL)
302     {
303       buffer->tag_table = gtk_text_tag_table_new ();
304
305       gtk_object_ref (GTK_OBJECT(buffer->tag_table));
306       gtk_object_sink (GTK_OBJECT(buffer->tag_table));
307     }
308
309   return buffer->tag_table;
310 }
311
312 static GtkTextBTree*
313 get_btree (GtkTextBuffer *buffer)
314 {
315   if (buffer->btree == NULL)
316     buffer->btree = gtk_text_btree_new(gtk_text_buffer_get_tag_table (buffer),
317                                        buffer);
318   
319   return buffer->btree;
320 }
321
322 GtkTextBTree*
323 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
324 {
325   return get_btree (buffer);
326 }
327
328 /**
329  * gtk_text_buffer_get_tag_table:
330  * @buffer: a #GtkTextBuffer
331  * 
332  * Get the #GtkTextTagTable associated with this buffer.
333  * 
334  * Return value: the buffer's tag table
335  **/
336 GtkTextTagTable*
337 gtk_text_buffer_get_tag_table (GtkTextBuffer  *buffer)
338 {
339   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
340
341   return get_table (buffer);
342 }
343
344 /**
345  * gtk_text_buffer_set_text:
346  * @buffer: a #GtkTextBuffer
347  * @text: UTF-8 text to insert
348  * @len: length of @text in bytes
349  * 
350  * Deletes current contents of @buffer, and inserts @text instead.  If
351  * @text doesn't end with a newline, a newline is added;
352  * #GtkTextBuffer contents must always end with a newline. If @text
353  * ends with a newline, the new buffer contents will be exactly
354  * @text. If @len is -1, @text must be nul-terminated.
355  **/
356 void
357 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
358                           const gchar   *text,
359                           gint           len)
360 {
361   GtkTextIter start, end;
362   
363   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
364   g_return_if_fail (text != NULL);
365
366   if (len < 0)
367     len = strlen (text);
368
369   /* Chop newline, since the buffer will already have one
370    * in it.
371    */
372   if (len > 0 && text[len-1] == '\n')
373     len -= 1;
374
375   gtk_text_buffer_get_bounds (buffer, &start, &end);
376   
377   gtk_text_buffer_delete (buffer, &start, &end);
378
379   if (len > 0)
380     {
381       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
382       gtk_text_buffer_insert (buffer, &start, text, len);
383     }
384 }
385
386 /*
387  * Insertion
388  */
389
390 static void
391 gtk_text_buffer_real_insert_text(GtkTextBuffer *buffer,
392                                  GtkTextIter *iter,
393                                  const gchar *text,
394                                  gint len,
395                                  gboolean interactive)
396 {
397   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
398   g_return_if_fail(iter != NULL);
399
400   gtk_text_btree_insert(iter, text, len);
401   
402   gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
403
404   gtk_text_buffer_set_modified(buffer, TRUE);
405 }
406
407 static void
408 gtk_text_buffer_emit_insert(GtkTextBuffer *buffer,
409                             GtkTextIter *iter,
410                             const gchar *text,
411                             gint len,
412                             gboolean interactive)
413 {
414   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
415   g_return_if_fail(iter != NULL);
416   g_return_if_fail(text != NULL);
417
418   if (len < 0)
419     len = strlen(text);
420   
421   if (len > 0)
422     {
423       gtk_signal_emit(GTK_OBJECT(buffer), signals[INSERT_TEXT],
424                       iter, text, len, interactive);
425     }
426 }
427
428 /**
429  * gtk_text_buffer_insert:
430  * @buffer: a #GtkTextBuffer
431  * @iter: a position in the buffer
432  * @text: UTF-8 format text to insert
433  * @len: length of text in bytes, or -1
434  * 
435  * Inserts @len bytes of @text at position @iter.  If @len is -1,
436  * @text must be nul-terminated and will be inserted in its
437  * entirety. Emits the "insert_text" signal; insertion actually occurs
438  * in the default handler for the signal. @iter is invalidated when
439  * insertion occurs (because the buffer contents change), but the
440  * default signal handler revalidates it to point to the end of the
441  * inserted text.
442  * 
443  **/
444 void
445 gtk_text_buffer_insert (GtkTextBuffer *buffer,
446                         GtkTextIter *iter,
447                         const gchar *text,
448                         gint len)
449 {
450   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
451   g_return_if_fail(iter != NULL);
452   g_return_if_fail(text != NULL);
453   
454   gtk_text_buffer_emit_insert(buffer, iter, text, len, FALSE);
455 }
456
457 /**
458  * gtk_text_buffer_insert_at_cursor:
459  * @buffer: a #GtkTextBuffer
460  * @text: some text in UTF-8 format
461  * @len: length of text, in bytes
462  * 
463  * Simply calls gtk_text_buffer_insert(), using the current
464  * cursor position as the insertion point.
465  **/
466 void
467 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
468                                   const gchar *text,
469                                   gint len)
470 {
471   GtkTextIter iter;
472
473   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
474   g_return_if_fail(text != NULL);
475
476   gtk_text_buffer_get_iter_at_mark(buffer, &iter,
477                                    gtk_text_buffer_get_mark (buffer,
478                                                              "insert"));
479
480   gtk_text_buffer_insert(buffer, &iter, text, len);
481 }
482
483 /**
484  * gtk_text_buffer_insert_interactive:
485  * @buffer: a #GtkTextBuffer
486  * @iter: a position in @buffer
487  * @text: some UTF-8 text
488  * @len: length of text in bytes, or -1
489  * @default_editable: default editability of buffer
490  * 
491  * Like gtk_text_buffer_insert(), but the insertion will not occur if
492  * @iter is at a non-editable location in the buffer.  Usually you
493  * want to prevent insertions at ineditable locations if the insertion
494  * results from a user action (is interactive).
495  * 
496  * Return value: whether text was actually inserted
497  **/
498 gboolean
499 gtk_text_buffer_insert_interactive(GtkTextBuffer *buffer,
500                                    GtkTextIter   *iter,
501                                    const gchar   *text,
502                                    gint           len,
503                                    gboolean       default_editable)
504 {
505   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
506   g_return_val_if_fail(text != NULL, FALSE);
507   
508   if (gtk_text_iter_editable (iter, default_editable))
509     {
510       gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
511       return TRUE;
512     }
513   else
514     return FALSE;
515 }
516
517 /**
518  * gtk_text_buffer_insert_interactive_at_cursor:
519  * @buffer: a #GtkTextBuffer
520  * @text: text in UTF-8 format
521  * @len: length of text in bytes, or -1
522  * @default_editable: default editability of buffer
523  * 
524  * Calls gtk_text_buffer_insert_interactive() at the cursor
525  * position.
526  * 
527  * Return value: whether text was actually inserted
528  **/
529 gboolean
530 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
531                                               const gchar   *text,
532                                               gint           len,
533                                               gboolean       default_editable)
534 {
535   GtkTextIter iter;
536
537   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
538   g_return_val_if_fail(text != NULL, FALSE);
539   
540   gtk_text_buffer_get_iter_at_mark(buffer, &iter,
541                                    gtk_text_buffer_get_mark (buffer,
542                                                              "insert"));
543
544   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
545                                              default_editable);
546 }
547
548
549 /**
550  * gtk_text_buffer_insert_range:
551  * @buffer: a #GtkTextBuffer
552  * @iter: a position in @buffer
553  * @start: a position in a #GtkTextBuffer
554  * @end: another position in the same buffer as @start
555  *
556  * Copies text, tags, and pixbufs between @start and @end (the order
557  * of @start and @end doesn't matter) and inserts the copy at @iter.
558  * Used instead of simply getting/inserting text because it preserves
559  * images and tags. If @start and @end are in a different buffer
560  * from @buffer, the two buffers must share the same tag table.
561  *
562  * Implemented via multiple emissions of the insert_text and
563  * apply_tag signals, so expect those.
564  **/
565 void
566 gtk_text_buffer_insert_range (GtkTextBuffer     *buffer,
567                               GtkTextIter       *iter,
568                               const GtkTextIter *start,
569                               const GtkTextIter *end)
570 {
571   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
572   g_return_if_fail (iter != NULL);
573   g_return_if_fail (start != NULL);
574   g_return_if_fail (end != NULL);
575   g_return_if_fail (gtk_text_iter_get_buffer (start) !=
576                     gtk_text_iter_get_buffer (end));
577   g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table !=
578                     buffer->tag_table);
579
580   /* FIXME */
581 }
582
583 gboolean
584 gtk_text_buffer_insert_range_interactive (GtkTextBuffer     *buffer,
585                                           GtkTextIter       *iter,
586                                           const GtkTextIter *start,
587                                           const GtkTextIter *end,
588                                           gboolean           default_editable)
589 {
590   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
591   g_return_val_if_fail (iter != NULL, FALSE);
592   g_return_val_if_fail (start != NULL, FALSE);
593   g_return_val_if_fail (end != NULL, FALSE);
594   g_return_val_if_fail (gtk_text_iter_get_buffer (start) !=
595                         gtk_text_iter_get_buffer (end), FALSE);
596   g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table !=
597                         buffer->tag_table, FALSE);
598
599
600   /* FIXME */
601   
602   return FALSE;
603 }
604
605 /**
606  * gtk_text_buffer_insert_with_tags:
607  * @buffer: a #GtkTextBuffer
608  * @iter: an iterator in @buffer
609  * @text: UTF-8 text
610  * @len: length of @text, or -1 
611  * @first_tag: first tag to apply to @text
612  * @Varargs: NULL-terminated list of tags to apply 
613  * 
614  * Inserts @text into @buffer at @iter, applying the list of tags to
615  * the newly-inserted text. The last tag specified must be NULL to
616  * terminate the list. Equivalent to calling gtk_text_buffer_insert(),
617  * then gtk_text_buffer_apply_tag() on the inserted text;
618  * gtk_text_buffer_insert_with_tags() is just a convenience function.
619  **/
620 void
621 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
622                                   GtkTextIter   *iter,
623                                   const gchar   *text,
624                                   gint           len,
625                                   GtkTextTag    *first_tag,
626                                   ...)
627 {
628   gint start_offset;
629   GtkTextIter start;
630   va_list args;
631   GtkTextTag *tag;
632   
633   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
634   g_return_if_fail (iter != NULL);
635   g_return_if_fail (text != NULL);
636
637   start_offset = gtk_text_iter_get_offset (iter);
638   
639   gtk_text_buffer_insert (buffer, iter, text, len);
640
641   if (first_tag == NULL)
642     return;
643   
644   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
645   
646   va_start (args, first_tag);
647   tag = first_tag;
648   while (tag)
649     {
650       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
651
652       tag = va_arg (args, GtkTextTag*);
653     }
654
655   va_end (args);
656 }
657
658 /**
659  * gtk_text_buffer_insert_with_tags_by_name:
660  * @buffer: a #GtkTextBuffer
661  * @iter: position in @buffer
662  * @text: UTF-8 text
663  * @len: length of @text, or -1
664  * @first_tag_name: name of a tag to apply to @text
665  * @Varargs: more tag names
666  * 
667  * Same as gtk_text_buffer_insert_with_tags(), but allows you
668  * to pass in tag names instead of tag objects.
669  **/
670 void
671 gtk_text_buffer_insert_with_tags_by_name  (GtkTextBuffer *buffer,
672                                            GtkTextIter   *iter,
673                                            const gchar   *text,
674                                            gint           len,
675                                            const gchar   *first_tag_name,
676                                            ...)
677 {
678   gint start_offset;
679   GtkTextIter start;
680   va_list args;
681   const gchar *tag_name;
682   
683   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
684   g_return_if_fail (iter != NULL);
685   g_return_if_fail (text != NULL);
686
687   start_offset = gtk_text_iter_get_offset (iter);
688   
689   gtk_text_buffer_insert (buffer, iter, text, len);
690
691   if (first_tag_name == NULL)
692     return;
693   
694   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
695   
696   va_start (args, first_tag_name);
697   tag_name = first_tag_name;
698   while (tag_name)
699     {
700       GtkTextTag *tag;
701
702       tag = gtk_text_tag_table_lookup (buffer->tag_table,
703                                        tag_name);
704
705       if (tag == NULL)
706         {
707           g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
708           return;
709         }
710       
711       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
712
713       tag_name = va_arg (args, const gchar*);
714     }
715
716   va_end (args);
717 }
718
719
720 /*
721  * Deletion
722  */
723
724 static void
725 gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer,
726                                  GtkTextIter *start,
727                                  GtkTextIter *end,
728                                  gboolean interactive)
729 {
730   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
731   g_return_if_fail(start != NULL);
732   g_return_if_fail(end != NULL);
733   
734   gtk_text_btree_delete(start, end);
735
736   /* may have deleted the selection... */
737   gtk_text_buffer_update_primary_selection(buffer);
738   
739   gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
740   
741   gtk_text_buffer_set_modified(buffer, TRUE);
742 }
743
744 static void
745 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
746                              GtkTextIter *start,
747                              GtkTextIter *end,
748                              gboolean interactive)
749 {
750   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
751   g_return_if_fail(start != NULL);
752   g_return_if_fail(end != NULL);
753
754   if (gtk_text_iter_equal(start, end))
755     return;
756
757   gtk_text_iter_reorder (start, end);
758
759   /* Somewhat annoyingly, if you try to delete the final newline
760    * the BTree will put it back; which means you can't deduce the
761    * final contents of the buffer purely by monitoring insert/delete
762    * signals on the buffer. But if you delete the final newline, any
763    * tags on the newline will go away, oddly. See comment in
764    * gtktextbtree.c. This is all sort of annoying, but really hard
765    * to fix.
766    */
767   gtk_signal_emit(GTK_OBJECT(buffer),
768                   signals[DELETE_TEXT],
769                   start, end,
770                   interactive);
771 }
772
773 /**
774  * gtk_text_buffer_delete:
775  * @buffer: a #GtkTextBuffer
776  * @start: a position in @buffer
777  * @end: another position in @buffer
778  *
779  * Deletes text between @start and @end. The order of @start and @end
780  * is not actually relevant; gtk_text_buffer_delete() will reorder
781  * them. This function actually emits the "delete_text" signal, and
782  * the default handler of that signal deletes the text. Because the
783  * buffer is modified, all outstanding iterators become invalid after
784  * calling this function; however, the @start and @end will be
785  * re-initialized to point to the location where text was deleted.
786  *
787  * Note that the final newline in the buffer may not be deleted; a
788  * #GtkTextBuffer always contains at least one newline.  You can
789  * safely include the final newline in the range [@start,@end) but it
790  * won't be affected by the deletion.
791  * 
792  **/
793 void
794 gtk_text_buffer_delete (GtkTextBuffer *buffer,
795                         GtkTextIter   *start,
796                         GtkTextIter   *end)
797 {
798   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
799   g_return_if_fail(start != NULL);
800   g_return_if_fail(end != NULL);
801   
802   gtk_text_buffer_emit_delete(buffer, start, end, FALSE);
803 }
804
805 /**
806  * gtk_text_buffer_delete_interactive:
807  * @buffer: a #GtkTextBuffer
808  * @start_iter: start of range to delete
809  * @end_iter: end of range
810  * @default_editable: whether the buffer is editable by default 
811  * 
812  * Deletes all <emphasis>editable</emphasis> text in the given range.
813  * Calls gtk_text_buffer_delete() for each editable sub-range of
814  * [@start,@end). @start and @end are revalidated to point to
815  * the location of the last deleted range, or left untouched if
816  * no text was deleted.
817  * 
818  * Return value: whether some text was actually deleted
819  **/
820 gboolean
821 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
822                                     GtkTextIter   *start_iter,
823                                     GtkTextIter   *end_iter,
824                                     gboolean       default_editable)
825 {
826   GtkTextMark *end_mark;
827   GtkTextMark *start_mark;
828   GtkTextIter iter;
829   gboolean current_state;
830   gboolean deleted_stuff = FALSE;
831
832   /* Delete all editable text in the range start_iter, end_iter */
833   
834   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
835   g_return_val_if_fail (start_iter != NULL, FALSE);
836   g_return_val_if_fail (end_iter != NULL, FALSE);
837
838   gtk_text_iter_reorder (start_iter, end_iter);
839   
840   start_mark = gtk_text_buffer_create_mark (buffer, NULL, 
841                                             start_iter, TRUE);
842   end_mark = gtk_text_buffer_create_mark (buffer, NULL, 
843                                           end_iter, FALSE);
844   iter = *start_iter;
845   
846   current_state = gtk_text_iter_editable (&iter, default_editable);
847   
848   while (TRUE)
849     {
850       gboolean new_state;
851       gboolean done = FALSE;
852       GtkTextIter end;
853
854       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
855       
856       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
857       
858       if (gtk_text_iter_compare (&iter, &end) >= 0)
859         {
860           done = TRUE;
861           iter = end; /* clamp to the last boundary */
862         }
863
864       new_state = gtk_text_iter_editable (&iter, default_editable);
865
866       if (current_state == new_state)
867         {
868           if (done)
869             {
870               if (current_state)
871                 {
872                   /* We're ending an editable region. Delete said region. */
873                   GtkTextIter start;
874                   
875                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
876                   
877                   gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
878                   
879                   deleted_stuff = TRUE;
880
881                   /* revalidate user's iterators. */
882                   *start_iter = start;
883                   *end_iter = iter;
884                 }
885
886               break;
887             }
888           else
889             continue;
890         }
891
892       if (current_state && !new_state)
893         {
894           /* End of an editable region. Delete it. */
895           GtkTextIter start;
896           
897           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
898           
899           gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
900
901           current_state = FALSE;
902           deleted_stuff = TRUE;
903
904           /* revalidate user's iterators. */
905           *start_iter = start;
906           *end_iter = iter;
907         }
908       else
909         {
910           /* We are at the start of an editable region. We won't be deleting
911            * the previous region. Move start mark to start of this region.
912            */
913
914           g_assert (!current_state && new_state);          
915           
916           gtk_text_buffer_move_mark (buffer, start_mark,
917                                      &iter);
918
919
920           current_state = TRUE;
921         }
922
923       if (done)
924         break;
925     }
926
927   
928   gtk_text_buffer_delete_mark (buffer, start_mark);
929   gtk_text_buffer_delete_mark (buffer, end_mark);
930   
931   return deleted_stuff;
932 }
933
934 /*
935  * Extracting textual buffer contents
936  */
937
938 /**
939  * gtk_text_buffer_get_text:
940  * @buffer: a #GtkTextBuffer
941  * @start: start of a range
942  * @end: end of a range
943  * @include_hidden_chars: whether to include invisible text
944  * 
945  * Returns the text in the range [@start,@end). Excludes undisplayed
946  * text (text marked with tags that set the invisibility attribute) if
947  * @include_hidden_chars is FALSE. Does not include characters
948  * representing embedded images, so byte and character indexes into
949  * the returned string do <emphasis>not</emphasis> correspond to byte
950  * and character indexes into the buffer. Contrast with
951  * gtk_text_buffer_get_slice().
952  * 
953  * Return value: an allocated UTF-8 string
954  **/
955 gchar*
956 gtk_text_buffer_get_text (GtkTextBuffer      *buffer,
957                           const GtkTextIter *start,
958                           const GtkTextIter *end,
959                           gboolean             include_hidden_chars)
960 {
961   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
962   g_return_val_if_fail(start != NULL, NULL);
963   g_return_val_if_fail(end != NULL, NULL);
964
965   if (include_hidden_chars)
966     return gtk_text_iter_get_text(start, end);
967   else
968     return gtk_text_iter_get_visible_text(start, end);
969 }
970
971 /**
972  * gtk_text_buffer_get_slice:
973  * @buffer: a #GtkTextBuffer
974  * @start: start of a range
975  * @end: end of a range
976  * @include_hidden_chars: whether to include invisible text 
977  *
978  * Returns the text in the range [@start,@end). Excludes undisplayed
979  * text (text marked with tags that set the invisibility attribute) if
980  * @include_hidden_chars is FALSE. The returned string includes a
981  * 0xFFFD character whenever the buffer contains
982  * embedded images, so byte and character indexes into
983  * the returned string <emphasis>do</emphasis> correspond to byte
984  * and character indexes into the buffer. Contrast with
985  * gtk_text_buffer_get_text().
986  * 
987  * Return value: an allocated UTF-8 string
988  **/
989 gchar*
990 gtk_text_buffer_get_slice (GtkTextBuffer      *buffer,
991                            const GtkTextIter *start,
992                            const GtkTextIter *end,
993                            gboolean             include_hidden_chars)
994 {
995   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
996   g_return_val_if_fail(start != NULL, NULL);
997   g_return_val_if_fail(end != NULL, NULL);
998
999   if (include_hidden_chars)
1000     return gtk_text_iter_get_slice(start, end);
1001   else
1002     return gtk_text_iter_get_visible_slice(start, end);
1003 }
1004
1005 /*
1006  * Pixmaps
1007  */
1008
1009 void
1010 gtk_text_buffer_insert_pixbuf         (GtkTextBuffer      *buffer,
1011                                        GtkTextIter        *iter,
1012                                        GdkPixbuf          *pixbuf)
1013 {
1014   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1015   g_return_if_fail (iter != NULL);
1016   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1017   
1018   gtk_text_btree_insert_pixbuf (iter, pixbuf);
1019
1020   /* FIXME pixbuf-specific signal like insert_text */
1021   
1022   gtk_signal_emit (GTK_OBJECT(buffer), signals[CHANGED]);
1023   
1024   gtk_text_buffer_set_modified (buffer, TRUE);
1025 }
1026
1027 /*
1028  * Mark manipulation
1029  */
1030
1031 static void
1032 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
1033                           const GtkTextIter *location,
1034                           GtkTextMark       *mark)
1035 {
1036   /* IMO this should NOT work like insert_text and delete_text,
1037      where the real action happens in the default handler.
1038
1039      The reason is that the default handler would be _required_,
1040      i.e. the whole widget would start breaking and segfaulting
1041      if the default handler didn't get run. So you can't really
1042      override the default handler or stop the emission; that is,
1043      this signal is purely for notification, and not to allow users
1044      to modify the default behavior. */
1045
1046   g_object_ref (G_OBJECT (mark));
1047   
1048   gtk_signal_emit(GTK_OBJECT(buffer),
1049                   signals[MARK_SET],
1050                   location,
1051                   mark);
1052
1053   g_object_unref (G_OBJECT (mark));
1054 }
1055
1056 /**
1057  * gtk_text_buffer_set_mark:
1058  * @buffer:       a #GtkTextBuffer
1059  * @mark_name:    name of the mark
1060  * @iter:         location for the mark.
1061  * @left_gravity: if the mark is created by this function, gravity for the new
1062  *                mark.
1063  * @should_exist: if %TRUE, warn if the mark does not exist, and return
1064  *                immediately.
1065  * 
1066  * Move the mark to the given position, if not @should_exist, create the mark.
1067  * 
1068  * Return value: mark
1069  **/
1070 static GtkTextMark*
1071 gtk_text_buffer_set_mark (GtkTextBuffer *buffer,
1072                           GtkTextMark *existing_mark,
1073                           const gchar *mark_name,
1074                           const GtkTextIter *iter,
1075                           gboolean left_gravity,
1076                           gboolean should_exist)
1077 {
1078   GtkTextIter location;
1079   GtkTextMark *mark;
1080   
1081   mark = gtk_text_btree_set_mark (get_btree (buffer),
1082                                   existing_mark,
1083                                   mark_name,
1084                                   left_gravity,
1085                                   iter,
1086                                   should_exist);
1087
1088   if (gtk_text_btree_mark_is_insert(get_btree (buffer), mark) ||
1089       gtk_text_btree_mark_is_selection_bound (get_btree (buffer), mark))
1090     {
1091       gtk_text_buffer_update_primary_selection (buffer);
1092     }
1093   
1094   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1095                                    &location,
1096                                    mark);
1097   
1098   gtk_text_buffer_mark_set (buffer, &location, mark);
1099
1100   return mark;
1101 }
1102
1103 /**
1104  * gtk_text_buffer_create_mark:
1105  * @buffer: a #GtkTextBuffer
1106  * @mark_name: name for mark, or %NULL
1107  * @where: location to place mark
1108  * @left_gravity: whether the mark has left gravity
1109  * 
1110  * Creates a mark at position @where. If @mark_name is %NULL, the mark
1111  * is anonymous; otherwise, the mark can be retrieved by name using
1112  * gtk_text_buffer_get_mark(). If a mark has left gravity, and text is
1113  * inserted at the mark's current location, the mark will be moved to
1114  * the left of the newly-inserted text. If the mark has right gravity
1115  * (@left_gravity = %FALSE), the mark will end up on the right of
1116  * newly-inserted text. The standard left-to-right cursor is a mark
1117  * with right gravity (when you type, the cursor stays on the right
1118  * side of the text you're typing).
1119  *
1120  * The caller of this function does <emphasis>not</emphasis> own a reference
1121  * to the returned #GtkTextMark, so you can ignore the return value
1122  * if you like. Marks are owned by the buffer and go away when the
1123  * buffer does.
1124  *
1125  * Emits the "mark_set" signal as notification of the mark's initial
1126  * placement.
1127  * 
1128  * Return value: the new #GtkTextMark object
1129  **/
1130 GtkTextMark*
1131 gtk_text_buffer_create_mark(GtkTextBuffer *buffer,
1132                             const gchar *mark_name,
1133                             const GtkTextIter *where,
1134                             gboolean left_gravity)
1135 {
1136   g_return_val_if_fail (GTK_IS_TEXT_BUFFER(buffer), NULL);
1137   
1138   return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
1139                                    left_gravity, FALSE);
1140 }
1141
1142 /**
1143  * gtk_text_buffer_move_mark:
1144  * @buffer: a #GtkTextBuffer
1145  * @mark: a #GtkTextMark
1146  * @where: new location for @mark in @buffer
1147  * 
1148  * Moves @mark to the new location @where. Emits the "mark_set" signal
1149  * as notification of the move.
1150  **/
1151 void
1152 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
1153                            GtkTextMark *mark,
1154                            const GtkTextIter *where)
1155 {
1156   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1157   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1158   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1159   
1160   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
1161 }
1162
1163 /**
1164  * gtk_text_buffer_get_iter_at_mark:
1165  * @buffer: a #GtkTextBuffer
1166  * @iter: iterator to initialize
1167  * @mark: a #GtkTextMark in @buffer
1168  * 
1169  * Initializes @iter with the current position of @mark.
1170  **/
1171 void
1172 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
1173                                   GtkTextIter *iter,
1174                                   GtkTextMark *mark)
1175 {
1176   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1177   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1178   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1179
1180   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1181                                    iter,
1182                                    mark);
1183 }
1184
1185 /**
1186  * gtk_text_buffer_delete_mark:
1187  * @buffer: a #GtkTextBuffer
1188  * @mark: a #GtkTextMark in @buffer 
1189  * 
1190  * Deletes @mark, so that it's no longer located anywhere in the
1191  * buffer. Removes the reference the buffer holds to the mark, so if
1192  * you haven't called g_object_ref() on the mark, it will be freed. Even
1193  * if the mark isn't freed, most operations on @mark become
1194  * invalid. There is no way to undelete a
1195  * mark. gtk_text_mark_get_deleted() will return TRUE after this
1196  * function has been called on a mark; gtk_text_mark_get_deleted()
1197  * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
1198  * signal will be emitted as notification after the mark is deleted.
1199  **/
1200 void
1201 gtk_text_buffer_delete_mark(GtkTextBuffer *buffer,
1202                             GtkTextMark   *mark)
1203 {
1204   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1205   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1206   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1207   
1208   g_object_ref (G_OBJECT (mark));
1209   
1210   gtk_text_btree_remove_mark (get_btree (buffer), mark);
1211
1212   /* See rationale above for MARK_SET on why we emit this after
1213    * removing the mark, rather than removing the mark in a default
1214    * handler.
1215    */
1216   gtk_signal_emit (GTK_OBJECT(buffer), signals[MARK_DELETED],
1217                    mark);
1218
1219   g_object_unref (G_OBJECT (mark));
1220 }
1221
1222 /**
1223  * gtk_text_buffer_get_mark:
1224  * @buffer: a #GtkTextBuffer
1225  * @name: a mark name
1226  * 
1227  * Returns the mark named @name in buffer @buffer, or NULL if no such
1228  * mark exists in the buffer.
1229  * 
1230  * Return value: a #GtkTextMark, or NULL
1231  **/
1232 GtkTextMark*
1233 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
1234                           const gchar         *name)
1235 {
1236   GtkTextMark *mark;
1237
1238   g_return_val_if_fail (GTK_IS_TEXT_BUFFER(buffer), NULL);
1239   g_return_val_if_fail (name != NULL, NULL);
1240   
1241   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1242
1243   return mark;
1244 }
1245
1246
1247 /**
1248  * gtk_text_buffer_move_mark_by_name:
1249  * @buffer: a #GtkTextBuffer 
1250  * @name: name of a mark
1251  * @where: new location for mark
1252  * 
1253  * Moves the mark named @name (which must exist) to location @where.
1254  * See gtk_text_buffer_move_mark() for details.
1255  **/
1256 void
1257 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
1258                                    const gchar       *name,
1259                                    const GtkTextIter *where)
1260 {
1261   GtkTextMark *mark;
1262
1263   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1264   g_return_if_fail (name != NULL);
1265   
1266   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);  
1267
1268   if (mark == NULL)
1269     {
1270       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1271       return;
1272     }
1273   
1274   gtk_text_buffer_move_mark (buffer, mark, where);
1275 }
1276
1277 /**
1278  * gtk_text_buffer_delete_mark_by_name:
1279  * @buffer: a #GtkTextBuffer
1280  * @name: name of a mark in @buffer
1281  * 
1282  * Deletes the mark named @name; the mark must exist. See
1283  * gtk_text_buffer_delete_mark() for details.
1284  **/
1285 void
1286 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer     *buffer,
1287                                      const gchar       *name)
1288 {
1289   GtkTextMark *mark;
1290
1291   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1292   g_return_if_fail (name != NULL);
1293   
1294   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);  
1295
1296   if (mark == NULL)
1297     {
1298       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1299       return;
1300     }
1301   
1302   gtk_text_buffer_delete_mark (buffer, mark);
1303 }
1304
1305 /**
1306  * gtk_text_buffer_get_insert:
1307  * @buffer: a #GtkTextBuffer
1308  * 
1309  * Returns the mark that represents the cursor (insertion point).
1310  * Equivalent to calling gtk_text_buffer_get_mark() to get the mark
1311  * name "insert," but very slightly more efficient, and involves less
1312  * typing.
1313  * 
1314  * Return value: insertion point mark
1315  **/
1316 GtkTextMark*
1317 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
1318 {
1319   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
1320
1321   /* FIXME use struct member in btree */
1322   return gtk_text_buffer_get_mark (buffer, "insert");
1323 }
1324
1325 /**
1326  * gtk_text_buffer_get_selection_bound:
1327  * @buffer: a #GtkTextBuffer
1328  * 
1329  * Returns the mark that represents the selection bound.  Equivalent
1330  * to calling gtk_text_buffer_get_mark() to get the mark name
1331  * "selection_bound," but very slightly more efficient, and involves
1332  * less typing.
1333  *
1334  * The currently-selected text in @buffer is the region between the
1335  * "selection_bound" and "insert" marks. If "selection_bound" and
1336  * "insert" are in the same place, then there is no current selection.
1337  * gtk_text_buffer_get_selection_bounds() is another convenient function
1338  * for handling the selection, if you just want to know whether there's a
1339  * selection and what its bounds are.
1340  * 
1341  * Return value: selection bound mark
1342  **/
1343 GtkTextMark*
1344 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
1345 {
1346   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
1347
1348   /* FIXME use struct member in btree */
1349   return gtk_text_buffer_get_mark (buffer, "selection_bound");
1350 }
1351
1352
1353 GtkTextChildAnchor*
1354 gtk_text_buffer_create_child_anchor (GtkTextBuffer      *buffer,
1355                                      const GtkTextIter  *where)
1356 {
1357   /* FIXME: Implement? */
1358
1359   return NULL;
1360 }
1361
1362 void
1363 gtk_text_buffer_move_child_anchor (GtkTextBuffer      *buffer,
1364                                    GtkTextChildAnchor *anchor,
1365                                    GtkTextIter        *where)
1366 {
1367   
1368   
1369 }
1370
1371 void
1372 gtk_text_buffer_delete_child_anchor (GtkTextBuffer      *buffer,
1373                                      GtkTextChildAnchor *anchor)
1374 {
1375
1376
1377
1378 }
1379
1380 void
1381 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
1382                                           GtkTextIter        *iter,
1383                                           GtkTextChildAnchor *anchor)
1384 {
1385   
1386
1387 }
1388
1389 /**
1390  * gtk_text_buffer_place_cursor:
1391  * @buffer: a #GtkTextBuffer 
1392  * @where: where to put the cursor
1393  * 
1394  * This function moves the "insert" and "selection_bound" marks
1395  * simultaneously.  If you move them to the same place in two steps
1396  * with gtk_text_buffer_move_mark(), you will temporarily select a
1397  * region in between their old and new locations, which can be pretty
1398  * inefficient since the temporarily-selected region will force stuff
1399  * to be recalculated. This function moves them as a unit, which can
1400  * be optimized.
1401  **/
1402 void
1403 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
1404                               const GtkTextIter *where)
1405 {
1406   GtkTextIter real;
1407   
1408   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1409
1410   real = *where;
1411   
1412   if (gtk_text_iter_is_last (&real))
1413     gtk_text_iter_prev_char (&real);
1414   
1415   gtk_text_btree_place_cursor (get_btree (buffer), &real);
1416   gtk_text_buffer_mark_set (buffer, &real,
1417                             gtk_text_buffer_get_mark (buffer,
1418                                                       "insert"));
1419   gtk_text_buffer_mark_set (buffer, &real,
1420                             gtk_text_buffer_get_mark (buffer,
1421                                                       "selection_bound"));
1422 }
1423
1424 /*
1425  * Tags
1426  */
1427
1428 /**
1429  * gtk_text_buffer_create_tag:
1430  * @buffer: a #GtkTextBuffer
1431  * @tag_name: name of the new tag, or %NULL
1432  * 
1433  * Creates a tag and adds it to the tag table for @buffer.
1434  * Equivalent to calling gtk_text_tag_new() and then adding the
1435  * tag to the buffer's tag table. The returned tag has its refcount
1436  * incremented, as if you'd called gtk_text_tag_new().
1437  *
1438  * If @tag_name is %NULL, the tag is anonymous.
1439  * 
1440  * Return value: a new tag
1441  **/
1442 GtkTextTag*
1443 gtk_text_buffer_create_tag(GtkTextBuffer *buffer,
1444                            const gchar *tag_name)
1445 {
1446   GtkTextTag *tag;
1447   
1448   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
1449   
1450   tag = gtk_text_tag_new(tag_name);
1451
1452   gtk_text_tag_table_add(get_table (buffer), tag);
1453
1454   return tag;
1455 }
1456
1457 static void
1458 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1459                                 GtkTextTag *tag,
1460                                 const GtkTextIter *start,
1461                                 const GtkTextIter *end)
1462 {
1463   gtk_text_btree_tag (start, end, tag, TRUE);
1464 }
1465
1466 static void
1467 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1468                                  GtkTextTag *tag,
1469                                  const GtkTextIter *start,
1470                                  const GtkTextIter *end)
1471 {
1472   gtk_text_btree_tag (start, end, tag, FALSE);
1473 }
1474
1475
1476 static void
1477 gtk_text_buffer_emit_tag(GtkTextBuffer *buffer,
1478                          GtkTextTag *tag,
1479                          gboolean apply,
1480                          const GtkTextIter *start,
1481                          const GtkTextIter *end)
1482 {
1483   GtkTextIter start_tmp = *start;
1484   GtkTextIter end_tmp = *end;
1485   
1486   g_return_if_fail(tag != NULL);
1487   
1488   gtk_text_iter_reorder (&start_tmp, &end_tmp);
1489   
1490   if (apply)
1491     gtk_signal_emit (GTK_OBJECT(buffer), signals[APPLY_TAG],
1492                      tag, &start_tmp, &end_tmp);
1493   else
1494     gtk_signal_emit (GTK_OBJECT(buffer), signals[REMOVE_TAG],
1495                      tag, &start_tmp, &end_tmp);
1496 }
1497
1498
1499 void
1500 gtk_text_buffer_apply_tag(GtkTextBuffer *buffer,
1501                           GtkTextTag    *tag,
1502                           const GtkTextIter *start,
1503                           const GtkTextIter *end)
1504 {
1505   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1506   g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1507   g_return_if_fail(start != NULL);
1508   g_return_if_fail(end != NULL);  
1509
1510   gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1511 }
1512
1513 void
1514 gtk_text_buffer_remove_tag(GtkTextBuffer *buffer,
1515                            GtkTextTag    *tag,
1516                            const GtkTextIter *start,
1517                            const GtkTextIter *end)
1518
1519 {
1520   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1521   g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1522   g_return_if_fail(start != NULL);
1523   g_return_if_fail(end != NULL);
1524
1525   gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1526 }
1527
1528
1529 void
1530 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1531                                    const gchar *name,
1532                                    const GtkTextIter *start,
1533                                    const GtkTextIter *end)
1534 {
1535   GtkTextTag *tag;
1536   
1537   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1538   g_return_if_fail(name != NULL);
1539   g_return_if_fail(start != NULL);
1540   g_return_if_fail(end != NULL);
1541   
1542   tag = gtk_text_tag_table_lookup(get_table (buffer),
1543                                   name);
1544
1545   if (tag == NULL)
1546     {
1547       g_warning("Unknown tag `%s'", name);
1548       return;
1549     }
1550
1551   gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1552 }
1553
1554 void
1555 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1556                                     const gchar *name,
1557                                     const GtkTextIter *start,
1558                                     const GtkTextIter *end)
1559 {
1560   GtkTextTag *tag;
1561   
1562   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1563   g_return_if_fail(name != NULL);
1564   g_return_if_fail(start != NULL);
1565   g_return_if_fail(end != NULL);
1566
1567   tag = gtk_text_tag_table_lookup(get_table (buffer),
1568                                   name);
1569
1570   if (tag == NULL)
1571     {
1572       g_warning("Unknown tag `%s'", name);
1573       return;
1574     }
1575   
1576   gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1577 }
1578
1579
1580 /*
1581  * Obtain various iterators
1582  */
1583
1584 void
1585 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
1586                                          GtkTextIter        *iter,
1587                                          gint                line_number,
1588                                          gint                char_offset)
1589 {  
1590   g_return_if_fail (iter != NULL);
1591   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1592
1593   gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
1594                                         iter, line_number, char_offset);
1595 }
1596
1597 void
1598 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
1599                                          GtkTextIter   *iter,
1600                                          gint           line_number,
1601                                          gint           byte_index)
1602 {
1603   g_return_if_fail (iter != NULL);
1604   g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer));
1605
1606   gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
1607                                         iter, line_number, byte_index);
1608 }
1609
1610 void
1611 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
1612                                      GtkTextIter        *iter,
1613                                      gint                line_number)
1614 {
1615   g_return_if_fail(iter != NULL);
1616   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1617
1618   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1619 }
1620
1621 void
1622 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
1623                                             GtkTextIter        *iter,
1624                                             gint                char_offset)
1625 {
1626   g_return_if_fail(iter != NULL);
1627   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1628
1629   gtk_text_btree_get_iter_at_char(get_btree (buffer), iter, char_offset);
1630 }
1631
1632 void
1633 gtk_text_buffer_get_last_iter         (GtkTextBuffer      *buffer,
1634                                        GtkTextIter        *iter)
1635 {  
1636   g_return_if_fail(iter != NULL);
1637   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1638
1639   gtk_text_btree_get_last_iter(get_btree (buffer), iter);
1640 }
1641
1642 void
1643 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1644                             GtkTextIter   *start,
1645                             GtkTextIter   *end)
1646 {
1647   g_return_if_fail(start != NULL);
1648   g_return_if_fail(end != NULL);
1649   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1650
1651   gtk_text_btree_get_iter_at_char(get_btree (buffer), start, 0);
1652   gtk_text_btree_get_last_iter(get_btree (buffer), end);
1653 }
1654
1655 /*
1656  * Modified flag
1657  */
1658
1659 gboolean
1660 gtk_text_buffer_modified (GtkTextBuffer      *buffer)
1661 {
1662   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
1663   
1664   return buffer->modified;
1665 }
1666
1667 void
1668 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
1669                               gboolean             setting)
1670 {
1671   gboolean fixed_setting;
1672   
1673   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1674
1675   fixed_setting = setting != FALSE;
1676   
1677   if (buffer->modified == fixed_setting)
1678     return;
1679   else
1680     {
1681       buffer->modified = fixed_setting;
1682       gtk_signal_emit(GTK_OBJECT(buffer), signals[MODIFIED_CHANGED]);
1683     }
1684 }
1685
1686
1687 /*
1688  * Assorted other stuff
1689  */
1690
1691 gint
1692 gtk_text_buffer_get_line_count(GtkTextBuffer *buffer)
1693 {
1694   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1695   
1696   return gtk_text_btree_line_count(get_btree (buffer));
1697 }
1698
1699 gint
1700 gtk_text_buffer_get_char_count(GtkTextBuffer *buffer)
1701 {
1702   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1703
1704   return gtk_text_btree_char_count(get_btree (buffer));
1705 }
1706
1707 GSList*
1708 gtk_text_buffer_get_tags               (GtkTextBuffer      *buffer,
1709                                         const GtkTextIter  *iter)
1710 {
1711   GSList *retval = NULL;
1712   GtkTextTag** tags;
1713   gint count = 0;
1714   
1715   tags = gtk_text_btree_get_tags(iter, &count);
1716
1717   if (count > 0)
1718     {
1719       gint i;
1720
1721       gtk_text_tag_array_sort(tags, count);
1722       
1723       i = 0;
1724       while (i < count)
1725         {
1726           retval = g_slist_prepend(retval, tags[i]);
1727           ++i;
1728         }
1729
1730       retval = g_slist_reverse(retval);
1731     }
1732
1733   if (tags)
1734     g_free(tags);
1735
1736   return retval;
1737 }
1738
1739 /* Called when we lose the primary selection.
1740  */
1741 static void
1742 clipboard_clear_cb (GtkClipboard *clipboard,
1743                     gpointer      data)
1744 {
1745   /* Move selection_bound to the insertion point */
1746   GtkTextIter insert;
1747   GtkTextIter selection_bound;
1748   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
1749   
1750   gtk_text_buffer_get_iter_at_mark(buffer, &insert,
1751                                    gtk_text_buffer_get_mark (buffer, "insert"));
1752   gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound,
1753                                    gtk_text_buffer_get_mark (buffer, "selection_bound"));
1754   
1755   if (!gtk_text_iter_equal(&insert, &selection_bound))
1756     gtk_text_buffer_move_mark(buffer,
1757                               gtk_text_buffer_get_mark (buffer, "selection_bound"),
1758                               &insert);
1759 }
1760
1761 /* Called when we have the primary selection and someone else wants our
1762  * data in order to paste it.
1763  */
1764 static void
1765 clipboard_get_cb (GtkClipboard     *clipboard,
1766                   GtkSelectionData *selection_data,
1767                   guint             info,
1768                   gpointer          data)
1769 {
1770   GtkTextBuffer *buffer = GTK_TEXT_BUFFER(data);
1771   gchar *str;
1772   GtkTextIter start, end;
1773   
1774   if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1775     {
1776       /* Extract the selected text */
1777       str = gtk_text_iter_get_visible_text(&start, &end);
1778       gtk_selection_data_set_text (selection_data, str);
1779       g_free (str);
1780     }
1781 }
1782
1783 /* Called when we request a paste and receive the data
1784  */
1785 static void
1786 clipboard_received (GtkClipboard *clipboard,
1787                     const gchar  *str,
1788                     gpointer      data)
1789 {
1790   ClipboardRequest *request_data = data;
1791   GtkTextBuffer *buffer = request_data->buffer;
1792
1793   if (str)
1794     {
1795       gboolean reselect;
1796       GtkTextIter insert_point;
1797       GtkTextMark *paste_point_override;
1798
1799       paste_point_override = gtk_text_buffer_get_mark (buffer,
1800                                                        "gtk_paste_point_override");
1801       
1802       if (paste_point_override != NULL)
1803         {
1804           gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1805                                            paste_point_override);
1806           gtk_text_buffer_delete_mark(buffer,
1807                                       gtk_text_buffer_get_mark (buffer,
1808                                                                 "gtk_paste_point_override"));
1809         }
1810       else
1811         {
1812           gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1813                                            gtk_text_buffer_get_mark (buffer,
1814                                                                      "insert"));
1815         }
1816       
1817       reselect = FALSE;
1818
1819       /* FIXME ALL OF THIS - I think that the "best method" is that when pasting
1820        * with the cursor inside the selection area, you replace the selection
1821        * with the new text, otherwise, you simply insert the new text at
1822        * the point where the click occured, unselecting any selected text.
1823        *
1824        * This probably is best implemented as a "replace_selection" flag in
1825        * ClipboardRequest.
1826        */
1827 #if 0      
1828       if ((TRUE/* Text is selected FIXME */) && 
1829           (!buffer->have_selection || request_data->is_clipboard))
1830         {
1831           reselect = TRUE;
1832           
1833           if (buffer->have_selection)
1834             {
1835               /* FIXME Delete currently-selected chars but don't give up X
1836                  selection since we'll use the newly-pasted stuff as
1837                  a new X selection */
1838               
1839             }
1840           else
1841             ; /* FIXME Delete selected chars and give up X selection */
1842         }
1843 #endif      
1844
1845       if (request_data->interactive)
1846         gtk_text_buffer_insert_interactive (buffer, &insert_point,
1847                                             str, -1, request_data->default_editable);
1848       else
1849         gtk_text_buffer_insert (buffer, &insert_point,
1850                                 str, -1);
1851       
1852       if (reselect)
1853         ; /* FIXME Select the region of text we just inserted */
1854     }
1855
1856   g_object_unref (G_OBJECT (buffer));
1857   g_free (request_data);
1858 }
1859
1860 static void
1861 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
1862 {
1863   static const GtkTargetEntry targets[] = {
1864     { "STRING", 0, TARGET_STRING },
1865     { "TEXT",   0, TARGET_TEXT }, 
1866     { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
1867     { "UTF8_STRING", 0, TARGET_UTF8_STRING }
1868   };
1869
1870   GtkTextIter start;
1871   GtkTextIter end;
1872
1873   GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
1874
1875   /* Determine whether we have a selection and adjust X selection
1876    * accordingly.
1877    */
1878   
1879   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1880     {
1881       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
1882         gtk_clipboard_clear (clipboard);
1883     }
1884   else
1885     {
1886       /* Even if we already have the selection, we need to update our
1887        * timestamp.
1888        */
1889       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
1890                                          clipboard_get_cb, clipboard_clear_cb, G_OBJECT (buffer)))
1891         clipboard_clear_cb (clipboard, buffer);
1892     }
1893 }
1894
1895 static void
1896 paste (GtkTextBuffer *buffer, 
1897        gboolean is_clipboard,
1898        gboolean interactive,
1899        gboolean default_editable)
1900 {
1901   ClipboardRequest *data = g_new (ClipboardRequest, 1);
1902
1903   data->buffer = buffer;
1904   g_object_ref (G_OBJECT (buffer));
1905   data->interactive = interactive;
1906   data->default_editable = default_editable;
1907
1908   gtk_clipboard_request_text (gtk_clipboard_get (is_clipboard ? GDK_NONE : GDK_SELECTION_PRIMARY),
1909                               clipboard_received, data);
1910 }
1911
1912 void
1913 gtk_text_buffer_paste_primary (GtkTextBuffer *buffer,
1914                                GtkTextIter   *override_location,
1915                                gboolean       default_editable)
1916 {
1917   if (override_location != NULL)
1918     gtk_text_buffer_create_mark(buffer,
1919                                 "gtk_paste_point_override",
1920                                 override_location, FALSE);
1921   
1922   paste (buffer, FALSE, TRUE, default_editable);
1923 }
1924
1925 void
1926 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
1927                                  gboolean       default_editable)
1928 {
1929   paste (buffer, TRUE, TRUE, default_editable);
1930 }
1931
1932 gboolean
1933 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
1934                                   gboolean interactive,
1935                                   gboolean default_editable)
1936 {
1937   GtkTextIter start;
1938   GtkTextIter end;
1939   
1940   if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1941     {
1942       return FALSE; /* No selection */
1943     }
1944   else
1945     {
1946       if (interactive)
1947         gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
1948       else
1949         gtk_text_buffer_delete (buffer, &start, &end);
1950
1951       return TRUE; /* We deleted stuff */
1952     }
1953 }
1954
1955 static void
1956 cut_or_copy(GtkTextBuffer *buffer,
1957             gboolean delete_region_after,
1958             gboolean interactive,
1959             gboolean default_editable)
1960 {
1961   /* We prefer to cut the selected region between selection_bound and
1962      insertion point. If that region is empty, then we cut the region
1963      between the "anchor" and the insertion point (this is for C-space
1964      and M-w and other Emacs-style copy/yank keys). Note that insert
1965      and selection_bound are guaranteed to exist, but the anchor only
1966      exists sometimes. */
1967   GtkTextIter start;
1968   GtkTextIter end;
1969
1970   if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1971     {
1972       /* Let's try the anchor thing */
1973       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
1974       
1975       if (anchor == NULL)
1976         return;
1977       else
1978         {
1979           gtk_text_buffer_get_iter_at_mark(buffer, &end, anchor);
1980           gtk_text_iter_reorder(&start, &end);
1981         }
1982     }
1983
1984   if (!gtk_text_iter_equal(&start, &end))
1985     {
1986       GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
1987       gchar *text;
1988       
1989       text = gtk_text_iter_get_visible_text (&start, &end);
1990       gtk_clipboard_set_text (clipboard, text, -1);
1991       g_free (text);
1992       
1993       if (delete_region_after)
1994         {
1995           if (interactive)
1996             gtk_text_buffer_delete_interactive (buffer, &start, &end,
1997                                                 default_editable);
1998           else
1999             gtk_text_buffer_delete (buffer, &start, &end);
2000         }
2001     }
2002 }
2003
2004 void
2005 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
2006                                gboolean       default_editable)
2007 {
2008   cut_or_copy (buffer, TRUE, TRUE, default_editable);
2009 }
2010
2011 void
2012 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
2013 {
2014   cut_or_copy (buffer, FALSE, TRUE, TRUE);
2015 }
2016
2017
2018 /**
2019  * gtk_text_buffer_get_selection_bounds:
2020  * @buffer: a #GtkTextBuffer
2021  * @start: iterator to initialize with selection start
2022  * @end: iterator to initialize with selection end
2023  * 
2024  * Returns %TRUE if some text is selected; places the bounds
2025  * of the selection in @start and @end (if the selection has length 0,
2026  * then @start and @end are filled in with the same value).
2027  * @start and @end will be in ascending order. If @start and @end are
2028  * NULL, then they are not filled in, but the return value still indicates
2029  * whether text is selected.
2030  * 
2031  * Return value: whether the selection has nonzero length
2032  **/
2033 gboolean
2034 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
2035                                         GtkTextIter        *start,
2036                                         GtkTextIter        *end)
2037 {
2038   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2039
2040   return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
2041 }
2042
2043
2044 /*
2045  * Debug spew
2046  */
2047
2048 void
2049 _gtk_text_buffer_spew(GtkTextBuffer *buffer)
2050 {
2051   gtk_text_btree_spew(get_btree (buffer));
2052 }
2053
2054
2055
2056
2057