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