]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
Remove g_convert (moved to glib) and now useless utf_to_latin1()
[~andy/gtk] / gtk / gtktextbuffer.c
1 /*  gtktextbuffer.c - the "model" in the MVC text widget architecture 
2  *  Copyright (c) 2000 Red Hat, Inc.
3  *  Developed by Havoc Pennington
4  */
5
6 #include <string.h>
7
8 #include "gtkclipboard.h"
9 #include "gtkinvisible.h"
10 #include "gtksignal.h"
11 #include "gtktextbuffer.h"
12 #include "gtktextbtree.h"
13 #include "gtktextiterprivate.h"
14 #include <string.h>
15
16 typedef struct _ClipboardRequest ClipboardRequest;
17
18 struct _ClipboardRequest
19 {
20   GtkTextBuffer *buffer;
21   gboolean interactive;
22   gboolean default_editable;
23   gboolean is_clipboard;
24 };
25
26 enum {
27   INSERT_TEXT,
28   DELETE_TEXT,
29   CHANGED,
30   MODIFIED_CHANGED,
31   MARK_SET,
32   MARK_DELETED,
33   APPLY_TAG,
34   REMOVE_TAG,
35   LAST_SIGNAL
36 };
37
38 enum {
39   ARG_0,
40   LAST_ARG
41 };
42
43 enum {
44   TARGET_STRING,
45   TARGET_TEXT,
46   TARGET_COMPOUND_TEXT,
47   TARGET_UTF8_STRING
48 };
49
50 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
51 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
52 static void gtk_text_buffer_destroy    (GtkObject          *object);
53 static void gtk_text_buffer_finalize   (GObject            *object);
54
55
56 static void gtk_text_buffer_update_primary_selection   (GtkTextBuffer     *buffer);
57 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
58                                                         GtkTextIter       *iter,
59                                                         const gchar       *text,
60                                                         gint               len,
61                                                         gboolean           interactive);
62 static void gtk_text_buffer_real_delete_text           (GtkTextBuffer     *buffer,
63                                                         GtkTextIter       *start,
64                                                         GtkTextIter       *end,
65                                                         gboolean           interactive);
66 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
67                                                         GtkTextTag        *tag,
68                                                         const GtkTextIter *start_char,
69                                                         const GtkTextIter *end_char);
70 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
71                                                         GtkTextTag        *tag,
72                                                         const GtkTextIter *start_char,
73                                                         const GtkTextIter *end_char);
74
75 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
76
77 void gtk_marshal_NONE__INT_POINTER_INT (GtkObject  *object,
78                                         GtkSignalFunc func,
79                                         gpointer func_data,
80                                         GtkArg  *args);
81
82 static GtkObjectClass *parent_class = NULL;
83 static guint signals[LAST_SIGNAL] = { 0 };
84
85 GtkType
86 gtk_text_buffer_get_type (void)
87 {
88   static GtkType our_type = 0;
89
90   if (our_type == 0)
91     {
92       static const GtkTypeInfo our_info =
93       {
94         "GtkTextBuffer",
95         sizeof (GtkTextBuffer),
96         sizeof (GtkTextBufferClass),
97         (GtkClassInitFunc) gtk_text_buffer_class_init,
98         (GtkObjectInitFunc) gtk_text_buffer_init,
99         /* reserved_1 */ NULL,
100         /* reserved_2 */ NULL,
101         (GtkClassInitFunc) NULL
102       };
103
104       our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
105     }
106
107   return our_type;
108 }
109
110 static void
111 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
112 {
113   GtkObjectClass *object_class = (GtkObjectClass*) klass;
114   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
115
116   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
117   
118   signals[INSERT_TEXT] =
119     gtk_signal_new ("insert_text",
120                     GTK_RUN_LAST,
121                     GTK_CLASS_TYPE (object_class),
122                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
123                     gtk_marshal_NONE__POINTER_POINTER_INT_INT,
124                     GTK_TYPE_NONE,
125                     4,
126                     GTK_TYPE_POINTER,
127                     GTK_TYPE_POINTER,
128                     GTK_TYPE_INT,
129                     GTK_TYPE_BOOL);
130
131   signals[DELETE_TEXT] =
132     gtk_signal_new ("delete_text",
133                     GTK_RUN_LAST,
134                     GTK_CLASS_TYPE (object_class),
135                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
136                     gtk_marshal_NONE__POINTER_POINTER_INT,
137                     GTK_TYPE_NONE,
138                     3,
139                     GTK_TYPE_POINTER,
140                     GTK_TYPE_POINTER,
141                     GTK_TYPE_BOOL);
142
143   signals[CHANGED] =
144     gtk_signal_new ("changed",
145                     GTK_RUN_LAST,
146                     GTK_CLASS_TYPE (object_class),
147                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
148                     gtk_marshal_NONE__NONE,
149                     GTK_TYPE_NONE,
150                     0);
151
152   signals[MODIFIED_CHANGED] =
153     gtk_signal_new ("modified_changed",
154                     GTK_RUN_LAST,
155                     GTK_CLASS_TYPE (object_class),
156                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
157                     gtk_marshal_NONE__NONE,
158                     GTK_TYPE_NONE,
159                     0);
160   
161   signals[MARK_SET] =
162     gtk_signal_new ("mark_set",
163                     GTK_RUN_LAST,
164                     GTK_CLASS_TYPE (object_class),
165                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
166                     gtk_marshal_NONE__POINTER_POINTER,
167                     GTK_TYPE_NONE,
168                     2,
169                     GTK_TYPE_POINTER,
170                     GTK_TYPE_POINTER);
171
172   signals[MARK_DELETED] =
173     gtk_signal_new ("mark_deleted",
174                     GTK_RUN_LAST,
175                     GTK_CLASS_TYPE (object_class),
176                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
177                     gtk_marshal_NONE__POINTER,
178                     GTK_TYPE_NONE,
179                     1,
180                     GTK_TYPE_POINTER);
181
182   signals[APPLY_TAG] =
183     gtk_signal_new ("apply_tag",
184                     GTK_RUN_LAST,
185                     GTK_CLASS_TYPE (object_class),
186                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
187                     gtk_marshal_NONE__POINTER_POINTER_POINTER,
188                     GTK_TYPE_NONE,
189                     3,
190                     GTK_TYPE_POINTER,
191                     GTK_TYPE_POINTER,
192                     GTK_TYPE_POINTER);
193     
194   signals[REMOVE_TAG] =
195     gtk_signal_new ("remove_tag",
196                     GTK_RUN_LAST,
197                     GTK_CLASS_TYPE (object_class),
198                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
199                     gtk_marshal_NONE__POINTER_POINTER_POINTER,
200                     GTK_TYPE_NONE,
201                     3,
202                     GTK_TYPE_POINTER,
203                     GTK_TYPE_POINTER,
204                     GTK_TYPE_POINTER);
205   
206   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
207
208   object_class->destroy = gtk_text_buffer_destroy;
209
210   gobject_class->finalize = gtk_text_buffer_finalize;
211
212   klass->insert_text = gtk_text_buffer_real_insert_text;
213   klass->delete_text = gtk_text_buffer_real_delete_text;
214   klass->apply_tag = gtk_text_buffer_real_apply_tag;
215   klass->remove_tag = gtk_text_buffer_real_remove_tag;
216 }
217
218
219 typedef gint (*GtkSignal_NONE__INT_POINTER_INT) (GtkObject  *object,
220                                                  gint pos,
221                                                  const gchar *text,
222                                                  gint len,
223                                                  gpointer user_data);
224
225 void 
226 gtk_marshal_NONE__INT_POINTER_INT (GtkObject  *object,
227                                    GtkSignalFunc func,
228                                    gpointer func_data,
229                                    GtkArg  *args)
230 {
231   GtkSignal_NONE__INT_POINTER_INT rfunc;
232
233   rfunc = (GtkSignal_NONE__INT_POINTER_INT) func;
234
235   (*rfunc) (object,
236             GTK_VALUE_INT (args[0]),
237             GTK_VALUE_POINTER (args[1]),
238             GTK_VALUE_INT (args[2]),
239             func_data);
240 }
241
242 void
243 gtk_text_buffer_init (GtkTextBuffer *buffer)
244 {
245 }
246
247 /**
248  * gtk_text_buffer_new:
249  * @table: a tag table, or NULL to create a new one
250  * 
251  * Creates a new text buffer.
252  * 
253  * Return value: a new text buffer
254  **/
255 GtkTextBuffer*
256 gtk_text_buffer_new (GtkTextTagTable *table)
257 {
258   GtkTextBuffer *text_buffer;
259   
260   text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
261
262   if (table)
263     {
264       text_buffer->tag_table = table;
265       
266       gtk_object_ref (GTK_OBJECT(text_buffer->tag_table));
267       gtk_object_sink (GTK_OBJECT(text_buffer->tag_table));
268     } 
269   
270   return text_buffer;
271 }
272
273 static void
274 gtk_text_buffer_destroy (GtkObject *object)
275 {
276   GtkTextBuffer *buffer;
277
278   buffer = GTK_TEXT_BUFFER (object);
279
280   if (buffer->tag_table)
281     {
282       gtk_object_unref(GTK_OBJECT(buffer->tag_table));
283       buffer->tag_table = NULL;
284     }
285
286   if (buffer->btree)
287     {
288       gtk_text_btree_unref(buffer->btree);
289       buffer->btree = NULL;
290     }
291   
292   (* parent_class->destroy) (object);
293 }
294
295 static void
296 gtk_text_buffer_finalize (GObject *object)
297 {
298   GtkTextBuffer *tkxt_buffer;
299
300   tkxt_buffer = GTK_TEXT_BUFFER (object);
301
302   G_OBJECT_CLASS (parent_class)->finalize (object);
303 }
304
305 static GtkTextTagTable*
306 get_table (GtkTextBuffer *buffer)
307 {
308   if (buffer->tag_table == NULL)
309     {
310       buffer->tag_table = gtk_text_tag_table_new ();
311
312       gtk_object_ref (GTK_OBJECT(buffer->tag_table));
313       gtk_object_sink (GTK_OBJECT(buffer->tag_table));
314     }
315
316   return buffer->tag_table;
317 }
318
319 static GtkTextBTree*
320 get_btree (GtkTextBuffer *buffer)
321 {
322   if (buffer->btree == NULL)
323     buffer->btree = gtk_text_btree_new(gtk_text_buffer_get_tag_table (buffer),
324                                        buffer);
325   
326   return buffer->btree;
327 }
328
329 GtkTextBTree*
330 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
331 {
332   return get_btree (buffer);
333 }
334
335 /**
336  * gtk_text_buffer_get_tag_table:
337  * @buffer: a #GtkTextBuffer
338  * 
339  * Get the #GtkTextTagTable associated with this buffer.
340  * 
341  * Return value: the buffer's tag table
342  **/
343 GtkTextTagTable*
344 gtk_text_buffer_get_tag_table (GtkTextBuffer  *buffer)
345 {
346   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
347
348   return get_table (buffer);
349 }
350
351 /*
352  * Insertion
353  */
354
355 static void
356 gtk_text_buffer_real_insert_text(GtkTextBuffer *buffer,
357                                  GtkTextIter *iter,
358                                  const gchar *text,
359                                  gint len,
360                                  gboolean interactive)
361 {
362   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
363   g_return_if_fail(iter != NULL);
364
365   gtk_text_btree_insert(iter, text, len);
366   
367   gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
368
369   gtk_text_buffer_set_modified(buffer, TRUE);
370 }
371
372 static void
373 gtk_text_buffer_emit_insert(GtkTextBuffer *buffer,
374                             GtkTextIter *iter,
375                             const gchar *text,
376                             gint len,
377                             gboolean interactive)
378 {
379   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
380   g_return_if_fail(iter != NULL);
381   g_return_if_fail(text != NULL);
382
383   if (len < 0)
384     len = strlen(text);
385   
386   if (len > 0)
387     {
388       gtk_signal_emit(GTK_OBJECT(buffer), signals[INSERT_TEXT],
389                       iter, text, len, interactive);
390     }
391 }
392
393 /**
394  * gtk_text_buffer_insert:
395  * @buffer: a #GtkTextBuffer
396  * @iter: a position in the buffer
397  * @text: UTF-8 format text to insert
398  * @len: length of text in bytes, or -1
399  * 
400  * Inserts @len bytes of @text at position @iter.  If @len is -1,
401  * @text must be nul-terminated and will be inserted in its
402  * entirety. Emits the "insert_text" signal; insertion actually occurs
403  * in the default handler for the signal. @iter is invalidated when
404  * insertion occurs (because the buffer contents change), but the
405  * default signal handler revalidates it to point to the end of the
406  * inserted text.
407  * 
408  **/
409 void
410 gtk_text_buffer_insert (GtkTextBuffer *buffer,
411                         GtkTextIter *iter,
412                         const gchar *text,
413                         gint len)
414 {
415   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
416   g_return_if_fail(iter != NULL);
417   g_return_if_fail(text != NULL);
418   
419   gtk_text_buffer_emit_insert(buffer, iter, text, len, FALSE);
420 }
421
422 /**
423  * gtk_text_buffer_insert_at_cursor:
424  * @buffer: a #GtkTextBuffer
425  * @text: some text in UTF-8 format
426  * @len: length of text, in bytes
427  * 
428  * Simply calls gtk_text_buffer_insert(), using the current
429  * cursor position as the insertion point.
430  **/
431 void
432 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
433                                   const gchar *text,
434                                   gint len)
435 {
436   GtkTextIter iter;
437
438   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
439   g_return_if_fail(text != NULL);
440
441   gtk_text_buffer_get_iter_at_mark(buffer, &iter,
442                                    gtk_text_buffer_get_mark (buffer,
443                                                              "insert"));
444
445   gtk_text_buffer_insert(buffer, &iter, text, len);
446 }
447
448 /**
449  * gtk_text_buffer_insert_interactive:
450  * @buffer: a #GtkTextBuffer
451  * @iter: a position in @buffer
452  * @text: some UTF-8 text
453  * @len: length of text in bytes, or -1
454  * @default_editable: default editability of buffer
455  * 
456  * Like gtk_text_buffer_insert(), but the insertion will not occur if
457  * @iter is at a non-editable location in the buffer.  Usually you
458  * want to prevent insertions at ineditable locations if the insertion
459  * results from a user action (is interactive).
460  * 
461  * Return value: whether text was actually inserted
462  **/
463 gboolean
464 gtk_text_buffer_insert_interactive(GtkTextBuffer *buffer,
465                                    GtkTextIter   *iter,
466                                    const gchar   *text,
467                                    gint           len,
468                                    gboolean       default_editable)
469 {
470   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
471   g_return_val_if_fail(text != NULL, FALSE);
472   
473   if (gtk_text_iter_editable (iter, default_editable))
474     {
475       gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
476       return TRUE;
477     }
478   else
479     return FALSE;
480 }
481
482 /**
483  * gtk_text_buffer_insert_interactive_at_cursor:
484  * @buffer: a #GtkTextBuffer
485  * @text: text in UTF-8 format
486  * @len: length of text in bytes, or -1
487  * @default_editable: default editability of buffer
488  * 
489  * Calls gtk_text_buffer_insert_interactive() at the cursor
490  * position.
491  * 
492  * Return value: whether text was actually inserted
493  **/
494 gboolean
495 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
496                                               const gchar   *text,
497                                               gint           len,
498                                               gboolean       default_editable)
499 {
500   GtkTextIter iter;
501
502   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
503   g_return_val_if_fail(text != NULL, FALSE);
504   
505   gtk_text_buffer_get_iter_at_mark(buffer, &iter,
506                                    gtk_text_buffer_get_mark (buffer,
507                                                              "insert"));
508
509   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
510                                              default_editable);
511 }
512
513 /*
514  * Deletion
515  */
516
517 static void
518 gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer,
519                                  GtkTextIter *start,
520                                  GtkTextIter *end,
521                                  gboolean interactive)
522 {
523   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
524   g_return_if_fail(start != NULL);
525   g_return_if_fail(end != NULL);
526   
527   gtk_text_btree_delete(start, end);
528
529   /* may have deleted the selection... */
530   gtk_text_buffer_update_primary_selection(buffer);
531   
532   gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
533   
534   gtk_text_buffer_set_modified(buffer, TRUE);
535 }
536
537 static void
538 gtk_text_buffer_emit_delete(GtkTextBuffer *buffer,
539                             GtkTextIter *start,
540                             GtkTextIter *end,
541                             gboolean interactive)
542 {
543   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
544   g_return_if_fail(start != NULL);
545   g_return_if_fail(end != NULL);
546
547   if (gtk_text_iter_equal(start, end))
548     return;
549
550   gtk_text_iter_reorder (start, end);
551
552   /* FIXME if the final newline is in the deletion range,
553    * shorten the range. (i.e. if end is the end iterator,
554    * move it backward by one)
555    */
556   
557   gtk_signal_emit(GTK_OBJECT(buffer),
558                   signals[DELETE_TEXT],
559                   start, end,
560                   interactive);
561 }
562
563 /**
564  * gtk_text_buffer_delete:
565  * @buffer: a #GtkTextBuffer
566  * @start: a position in @buffer
567  * @end: another position in @buffer
568  *
569  * Deletes text between @start and @end. The order of @start and @end
570  * is not actually relevant; gtk_text_buffer_delete() will reorder
571  * them. This function actually emits the "delete_text" signal, and
572  * the default handler of that signal deletes the text. Because the
573  * buffer is modified, all outstanding iterators become invalid after
574  * calling this function; however, the @start and @end will be
575  * re-initialized to point to the location where text was deleted.
576  *
577  * Note that the final newline in the buffer may not be deleted; a
578  * #GtkTextBuffer always contains at least one newline.  You can
579  * safely include the final newline in the range [@start,@end) but it
580  * won't be affected by the deletion.
581  * 
582  **/
583 void
584 gtk_text_buffer_delete (GtkTextBuffer *buffer,
585                         GtkTextIter *start,
586                         GtkTextIter *end)
587 {
588   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
589   g_return_if_fail(start != NULL);
590   g_return_if_fail(end != NULL);
591   
592   gtk_text_buffer_emit_delete(buffer, start, end, FALSE);
593 }
594
595 /**
596  * gtk_text_buffer_delete_interactive:
597  * @buffer: a #GtkTextBuffer
598  * @start_iter: start of range to delete
599  * @end_iter: end of range
600  * @default_editable: whether the buffer is editable by default 
601  * 
602  * Deletes all <emphasis>editable</emphasis> text in the given range.
603  * Calls gtk_text_buffer_delete() for each editable sub-range of
604  * [@start,@end).
605  * 
606  * Return value: whether some text was actually deleted
607  **/
608 gboolean
609 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
610                                     GtkTextIter   *start_iter,
611                                     GtkTextIter   *end_iter,
612                                     gboolean       default_editable)
613 {
614   GtkTextMark *end_mark;
615   GtkTextMark *start_mark;
616   GtkTextIter iter;
617   gboolean current_state;
618   gboolean deleted_stuff = FALSE;
619
620   /* Delete all editable text in the range start_iter, end_iter */
621   
622   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
623   g_return_val_if_fail (start_iter != NULL, FALSE);
624   g_return_val_if_fail (end_iter != NULL, FALSE);
625
626   gtk_text_iter_reorder (start_iter, end_iter);
627   
628   start_mark = gtk_text_buffer_create_mark (buffer, NULL, 
629                                             start_iter, TRUE);
630   end_mark = gtk_text_buffer_create_mark (buffer, NULL, 
631                                           end_iter, FALSE);
632   iter = *start_iter;
633   
634   current_state = gtk_text_iter_editable (&iter, default_editable);
635   
636   while (TRUE)
637     {
638       gboolean new_state;
639       gboolean done = FALSE;
640       GtkTextIter end;
641
642       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
643       
644       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
645       
646       if (gtk_text_iter_compare (&iter, &end) >= 0)
647         {
648           done = TRUE;
649           iter = end; /* clamp to the last boundary */
650         }
651
652       new_state = gtk_text_iter_editable (&iter, default_editable);
653
654       if (current_state == new_state)
655         {
656           if (done)
657             {
658               if (current_state)
659                 {
660                   /* We're ending an editable region. Delete said region. */
661                   GtkTextIter start;
662                   
663                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
664                   
665                   gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
666                   
667                   deleted_stuff = TRUE;
668                 }
669
670               break;
671             }
672           else
673             continue;
674         }
675
676       if (current_state && !new_state)
677         {
678           /* End of an editable region. Delete it. */
679           GtkTextIter start;
680           
681           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
682           
683           gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
684
685           current_state = FALSE;
686           deleted_stuff = TRUE;
687         }
688       else
689         {
690           /* We are at the start of an editable region. We won't be deleting
691            * the previous region. Move start mark to start of this region.
692            */
693
694           g_assert (!current_state && new_state);          
695           
696           gtk_text_buffer_move_mark (buffer, start_mark,
697                                      &iter);
698
699
700           current_state = TRUE;
701         }
702
703       if (done)
704         break;
705     }
706
707   
708   gtk_text_buffer_delete_mark (buffer, start_mark);
709   gtk_text_buffer_delete_mark (buffer, end_mark);
710   
711   return deleted_stuff;
712 }
713
714 /*
715  * Extracting textual buffer contents
716  */
717
718 /**
719  * gtk_text_buffer_get_text:
720  * @buffer: a #GtkTextBuffer
721  * @start: start of a range
722  * @end: end of a range
723  * @include_hidden_chars: whether to include invisible text
724  * 
725  * Returns the text in the range [@start,@end). Excludes undisplayed
726  * text (text marked with tags that set the invisibility attribute) if
727  * @include_hidden_chars is FALSE. Does not include characters
728  * representing embedded images, so byte and character indexes into
729  * the returned string do <emphasis>not</emphasis> correspond to byte
730  * and character indexes into the buffer. Contrast with
731  * gtk_text_buffer_get_slice().
732  * 
733  * Return value: an allocated UTF-8 string
734  **/
735 gchar*
736 gtk_text_buffer_get_text (GtkTextBuffer      *buffer,
737                           const GtkTextIter *start,
738                           const GtkTextIter *end,
739                           gboolean             include_hidden_chars)
740 {
741   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
742   g_return_val_if_fail(start != NULL, NULL);
743   g_return_val_if_fail(end != NULL, NULL);
744
745   if (include_hidden_chars)
746     return gtk_text_iter_get_text(start, end);
747   else
748     return gtk_text_iter_get_visible_text(start, end);
749 }
750
751 /**
752  * gtk_text_buffer_get_slice:
753  * @buffer: a #GtkTextBuffer
754  * @start: start of a range
755  * @end: end of a range
756  * @include_hidden_chars: whether to include invisible text 
757  *
758  * Returns the text in the range [@start,@end). Excludes undisplayed
759  * text (text marked with tags that set the invisibility attribute) if
760  * @include_hidden_chars is FALSE. The returned string includes a
761  * 0xFFFD character whenever the buffer contains
762  * embedded images, so byte and character indexes into
763  * the returned string <emphasis>do</emphasis> correspond to byte
764  * and character indexes into the buffer. Contrast with
765  * gtk_text_buffer_get_text().
766  * 
767  * Return value: an allocated UTF-8 string
768  **/
769 gchar*
770 gtk_text_buffer_get_slice (GtkTextBuffer      *buffer,
771                            const GtkTextIter *start,
772                            const GtkTextIter *end,
773                            gboolean             include_hidden_chars)
774 {
775   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
776   g_return_val_if_fail(start != NULL, NULL);
777   g_return_val_if_fail(end != NULL, NULL);
778
779   if (include_hidden_chars)
780     return gtk_text_iter_get_slice(start, end);
781   else
782     return gtk_text_iter_get_visible_slice(start, end);
783 }
784
785 /*
786  * Pixmaps
787  */
788
789 void
790 gtk_text_buffer_insert_pixmap         (GtkTextBuffer      *buffer,
791                                        GtkTextIter *iter,
792                                        GdkPixmap           *pixmap,
793                                        GdkBitmap           *mask)
794 {
795   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
796   g_return_if_fail(iter != NULL);
797   g_return_if_fail(pixmap != NULL);
798
799   gtk_text_btree_insert_pixmap(iter, pixmap, mask);
800
801   /* FIXME pixmap-specific signal like insert_text */
802   
803   gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
804   
805   gtk_text_buffer_set_modified(buffer, TRUE);
806 }
807
808 /*
809  * Mark manipulation
810  */
811
812 static void
813 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
814                           const GtkTextIter *location,
815                           GtkTextMark       *mark)
816 {
817   /* IMO this should NOT work like insert_text and delete_text,
818      where the real action happens in the default handler.
819
820      The reason is that the default handler would be _required_,
821      i.e. the whole widget would start breaking and segfaulting
822      if the default handler didn't get run. So you can't really
823      override the default handler or stop the emission; that is,
824      this signal is purely for notification, and not to allow users
825      to modify the default behavior. */
826   gtk_signal_emit(GTK_OBJECT(buffer),
827                   signals[MARK_SET],
828                   location,
829                   mark);
830
831 }
832
833 /**
834  * gtk_text_buffer_set_mark:
835  * @buffer:       a #GtkTextBuffer
836  * @mark_name:    name of the mark
837  * @iter:         location for the mark.
838  * @left_gravity: if the mark is created by this function, gravity for the new
839  *                mark.
840  * @should_exist: if %TRUE, warn if the mark does not exist, and return
841  *                immediately.
842  * 
843  * Move the mark to the given position, if not @should_exist, create the mark.
844  * 
845  * Return value: 
846  **/
847 static GtkTextMark*
848 gtk_text_buffer_set_mark(GtkTextBuffer *buffer,
849                          GtkTextMark *existing_mark,
850                          const gchar *mark_name,
851                          const GtkTextIter *iter,
852                          gboolean left_gravity,
853                          gboolean should_exist)
854 {
855   GtkTextIter location;
856   GtkTextMark *mark;
857   
858   mark = gtk_text_btree_set_mark(get_btree (buffer),
859                                  existing_mark,
860                                  mark_name,
861                                  left_gravity,
862                                  iter,
863                                  should_exist);
864
865   if (gtk_text_btree_mark_is_insert(get_btree (buffer), mark) ||
866       gtk_text_btree_mark_is_selection_bound(get_btree (buffer), mark))
867     {
868       gtk_text_buffer_update_primary_selection(buffer);
869     }
870   
871   gtk_text_btree_get_iter_at_mark(get_btree (buffer),
872                                   &location,
873                                   mark);
874   
875   gtk_text_buffer_mark_set (buffer, &location, mark);
876
877   return (GtkTextMark*)mark;
878 }
879
880 /**
881  * gtk_text_buffer_create_mark:
882  * @buffer: a #GtkTextBuffer
883  * @mark_name: name for mark, or %NULL
884  * @where: location to place mark
885  * @left_gravity: whether the mark has left gravity
886  * 
887  * Creates a mark at position @where. If @mark_name is %NULL, the mark
888  * is anonymous; otherwise, the mark can be retrieved by name using
889  * gtk_text_buffer_get_mark(). If a mark has left gravity, and text is
890  * inserted at the mark's current location, the mark will be moved to
891  * the left of the newly-inserted text. If the mark has right gravity
892  * (@left_gravity = %FALSE), the mark will end up on the right of
893  * newly-inserted text. The standard left-to-right cursor is a mark
894  * with right gravity (when you type, the cursor stays on the right
895  * side of the text you're typing).
896  *
897  * The caller of this function does <emphasis>not</emphasis> own a reference
898  * to the returned #GtkTextMark, so you can ignore the return value
899  * if you like.
900  * 
901  * Return value: the new #GtkTextMark object
902  **/
903 GtkTextMark*
904 gtk_text_buffer_create_mark(GtkTextBuffer *buffer,
905                             const gchar *mark_name,
906                             const GtkTextIter *where,
907                             gboolean left_gravity)
908 {
909   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
910   
911   return gtk_text_buffer_set_mark(buffer, NULL, mark_name, where,
912                                   left_gravity, FALSE);
913 }
914
915 /**
916  * gtk_text_buffer_move_mark:
917  * @buffer: 
918  * @mark: 
919  * @where: 
920  * 
921  * 
922  **/
923 void
924 gtk_text_buffer_move_mark(GtkTextBuffer *buffer,
925                           GtkTextMark *mark,
926                           const GtkTextIter *where)
927 {
928   g_return_if_fail (mark != NULL);
929   g_return_if_fail (!gtk_text_mark_deleted (mark));
930   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
931   
932   gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE);
933 }
934
935 void
936 gtk_text_buffer_get_iter_at_mark(GtkTextBuffer *buffer,
937                                  GtkTextIter *iter,
938                                  GtkTextMark *mark)
939 {
940   g_return_if_fail (mark != NULL);
941   g_return_if_fail (!gtk_text_mark_deleted (mark));
942   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
943
944   gtk_text_btree_get_iter_at_mark(get_btree (buffer),
945                                   iter,
946                                   mark);
947 }
948
949 void
950 gtk_text_buffer_delete_mark(GtkTextBuffer *buffer,
951                             GtkTextMark *mark)
952 {
953   g_return_if_fail (mark != NULL);
954   g_return_if_fail (!gtk_text_mark_deleted (mark));
955   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
956
957   gtk_text_btree_remove_mark (get_btree (buffer), mark);
958
959   /* See rationale above for MARK_SET on why we emit this after
960      removing the mark, rather than removing the mark in a default
961      handler. */
962   gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_DELETED],
963                   mark);
964 }
965
966 GtkTextMark*
967 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
968                           const gchar         *name)
969 {
970   GtkTextMark *mark;
971
972   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
973   g_return_val_if_fail(name != NULL, NULL);
974   
975   mark = gtk_text_btree_get_mark_by_name(get_btree (buffer), name);
976
977   return mark;
978 }
979
980 /**
981  * gtk_text_buffer_place_cursor:
982  * @buffer: a #GtkTextBuffer 
983  * @where: where to put the cursor
984  * 
985  * This function moves the "insert" and "selection_bound" marks
986  * simultaneously.  If you move them to the same place in two steps
987  * with gtk_text_buffer_move_mark(), you will temporarily select a
988  * region in between their old and new locations, which marks part of
989  * the buffer invalid and can be inefficient. This function moves
990  * them as a unit, which can be optimized.
991  **/
992 void
993 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
994                               const GtkTextIter *where)
995 {
996   GtkTextIter real;
997   
998   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
999
1000   real = *where;
1001   
1002   if (gtk_text_iter_is_last (&real))
1003     gtk_text_iter_prev_char (&real);
1004   
1005   gtk_text_btree_place_cursor(get_btree (buffer), &real);
1006   gtk_text_buffer_mark_set (buffer, &real,
1007                             gtk_text_buffer_get_mark (buffer,
1008                                                       "insert"));
1009   gtk_text_buffer_mark_set (buffer, &real,
1010                             gtk_text_buffer_get_mark (buffer,
1011                                                       "selection_bound"));
1012 }
1013
1014 /*
1015  * Tags
1016  */
1017
1018 /**
1019  * gtk_text_buffer_create_tag:
1020  * @buffer: a #GtkTextBuffer
1021  * @tag_name: name of the new tag, or %NULL
1022  * 
1023  * Creates a tag and adds it to the tag table for @buffer.
1024  * Equivalent to calling gtk_text_tag_new() and then adding the
1025  * tag to the buffer's tag table. The returned tag has its refcount
1026  * incremented, as if you'd called gtk_text_tag_new().
1027  *
1028  * If @tag_name is %NULL, the tag is anonymous.
1029  * 
1030  * Return value: a new tag
1031  **/
1032 GtkTextTag*
1033 gtk_text_buffer_create_tag(GtkTextBuffer *buffer,
1034                            const gchar *tag_name)
1035 {
1036   GtkTextTag *tag;
1037   
1038   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
1039   
1040   tag = gtk_text_tag_new(tag_name);
1041
1042   gtk_text_tag_table_add(get_table (buffer), tag);
1043
1044   return tag;
1045 }
1046
1047 static void
1048 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1049                                 GtkTextTag *tag,
1050                                 const GtkTextIter *start,
1051                                 const GtkTextIter *end)
1052 {
1053   gtk_text_btree_tag(start, end, tag, TRUE);
1054 }
1055
1056 static void
1057 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1058                                  GtkTextTag *tag,
1059                                  const GtkTextIter *start,
1060                                  const GtkTextIter *end)
1061 {
1062   gtk_text_btree_tag(start, end, tag, FALSE);
1063 }
1064
1065
1066 static void
1067 gtk_text_buffer_emit_tag(GtkTextBuffer *buffer,
1068                          GtkTextTag *tag,
1069                          gboolean apply,
1070                          const GtkTextIter *start,
1071                          const GtkTextIter *end)
1072 {
1073   g_return_if_fail(tag != NULL);
1074
1075   if (apply)
1076     gtk_signal_emit(GTK_OBJECT(buffer), signals[APPLY_TAG],
1077                     tag, start, end);
1078   else
1079     gtk_signal_emit(GTK_OBJECT(buffer), signals[REMOVE_TAG],
1080                     tag, start, end);
1081 }
1082
1083
1084 void
1085 gtk_text_buffer_apply_tag(GtkTextBuffer *buffer,
1086                           GtkTextTag    *tag,
1087                           const GtkTextIter *start,
1088                           const GtkTextIter *end)
1089 {
1090   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1091   g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1092   g_return_if_fail(start != NULL);
1093   g_return_if_fail(end != NULL);  
1094
1095   gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1096 }
1097
1098 void
1099 gtk_text_buffer_remove_tag(GtkTextBuffer *buffer,
1100                            GtkTextTag    *tag,
1101                            const GtkTextIter *start,
1102                            const GtkTextIter *end)
1103
1104 {
1105   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1106   g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1107   g_return_if_fail(start != NULL);
1108   g_return_if_fail(end != NULL);
1109
1110   gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1111 }
1112
1113
1114 void
1115 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1116                                    const gchar *name,
1117                                    const GtkTextIter *start,
1118                                    const GtkTextIter *end)
1119 {
1120   GtkTextTag *tag;
1121   
1122   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1123   g_return_if_fail(name != NULL);
1124   g_return_if_fail(start != NULL);
1125   g_return_if_fail(end != NULL);
1126   
1127   tag = gtk_text_tag_table_lookup(get_table (buffer),
1128                                   name);
1129
1130   if (tag == NULL)
1131     {
1132       g_warning("Unknown tag `%s'", name);
1133       return;
1134     }
1135
1136   gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1137 }
1138
1139 void
1140 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1141                                     const gchar *name,
1142                                     const GtkTextIter *start,
1143                                     const GtkTextIter *end)
1144 {
1145   GtkTextTag *tag;
1146   
1147   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1148   g_return_if_fail(name != NULL);
1149   g_return_if_fail(start != NULL);
1150   g_return_if_fail(end != NULL);
1151
1152   tag = gtk_text_tag_table_lookup(get_table (buffer),
1153                                   name);
1154
1155   if (tag == NULL)
1156     {
1157       g_warning("Unknown tag `%s'", name);
1158       return;
1159     }
1160   
1161   gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1162 }
1163
1164
1165 /*
1166  * Obtain various iterators
1167  */
1168
1169 void
1170 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
1171                                          GtkTextIter        *iter,
1172                                          gint                line_number,
1173                                          gint                char_offset)
1174 {  
1175   g_return_if_fail(iter != NULL);
1176   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1177
1178   gtk_text_btree_get_iter_at_line_char(get_btree (buffer),
1179                                        iter, line_number, char_offset);
1180 }
1181
1182 void
1183 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
1184                                      GtkTextIter        *iter,
1185                                      gint                line_number)
1186 {
1187   g_return_if_fail(iter != NULL);
1188   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1189
1190   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1191 }
1192
1193 void
1194 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
1195                                             GtkTextIter        *iter,
1196                                             gint                char_offset)
1197 {
1198   g_return_if_fail(iter != NULL);
1199   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1200
1201   gtk_text_btree_get_iter_at_char(get_btree (buffer), iter, char_offset);
1202 }
1203
1204 void
1205 gtk_text_buffer_get_last_iter         (GtkTextBuffer      *buffer,
1206                                        GtkTextIter        *iter)
1207 {  
1208   g_return_if_fail(iter != NULL);
1209   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1210
1211   gtk_text_btree_get_last_iter(get_btree (buffer), iter);
1212 }
1213
1214 void
1215 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1216                             GtkTextIter   *start,
1217                             GtkTextIter   *end)
1218 {
1219   g_return_if_fail(start != NULL);
1220   g_return_if_fail(end != NULL);
1221   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1222
1223   gtk_text_btree_get_iter_at_char(get_btree (buffer), start, 0);
1224   gtk_text_btree_get_last_iter(get_btree (buffer), end);
1225 }
1226
1227 /*
1228  * Modified flag
1229  */
1230
1231 gboolean
1232 gtk_text_buffer_modified (GtkTextBuffer      *buffer)
1233 {
1234   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
1235   
1236   return buffer->modified;
1237 }
1238
1239 void
1240 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
1241                               gboolean             setting)
1242 {
1243   gboolean fixed_setting;
1244   
1245   g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1246
1247   fixed_setting = setting != FALSE;
1248   
1249   if (buffer->modified == fixed_setting)
1250     return;
1251   else
1252     {
1253       buffer->modified = fixed_setting;
1254       gtk_signal_emit(GTK_OBJECT(buffer), signals[MODIFIED_CHANGED]);
1255     }
1256 }
1257
1258
1259 /*
1260  * Assorted other stuff
1261  */
1262
1263 gint
1264 gtk_text_buffer_get_line_count(GtkTextBuffer *buffer)
1265 {
1266   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1267   
1268   return gtk_text_btree_line_count(get_btree (buffer));
1269 }
1270
1271 gint
1272 gtk_text_buffer_get_char_count(GtkTextBuffer *buffer)
1273 {
1274   g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1275
1276   return gtk_text_btree_char_count(get_btree (buffer));
1277 }
1278
1279 GSList*
1280 gtk_text_buffer_get_tags               (GtkTextBuffer      *buffer,
1281                                         const GtkTextIter  *iter)
1282 {
1283   GSList *retval = NULL;
1284   GtkTextTag** tags;
1285   gint count = 0;
1286   
1287   tags = gtk_text_btree_get_tags(iter, &count);
1288
1289   if (count > 0)
1290     {
1291       gint i;
1292
1293       gtk_text_tag_array_sort(tags, count);
1294       
1295       i = 0;
1296       while (i < count)
1297         {
1298           retval = g_slist_prepend(retval, tags[i]);
1299           ++i;
1300         }
1301
1302       retval = g_slist_reverse(retval);
1303     }
1304
1305   if (tags)
1306     g_free(tags);
1307
1308   return retval;
1309 }
1310
1311 /* Called when we lose the primary selection.
1312  */
1313 static void
1314 clipboard_clear_cb (GtkClipboard *clipboard,
1315                     gpointer      data)
1316 {
1317   /* Move selection_bound to the insertion point */
1318   GtkTextIter insert;
1319   GtkTextIter selection_bound;
1320   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
1321   
1322   gtk_text_buffer_get_iter_at_mark(buffer, &insert,
1323                                    gtk_text_buffer_get_mark (buffer, "insert"));
1324   gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound,
1325                                    gtk_text_buffer_get_mark (buffer, "selection_bound"));
1326   
1327   if (!gtk_text_iter_equal(&insert, &selection_bound))
1328     gtk_text_buffer_move_mark(buffer,
1329                               gtk_text_buffer_get_mark (buffer, "selection_bound"),
1330                               &insert);
1331 }
1332
1333 /* Called when we have the primary selection and someone else wants our
1334  * data in order to paste it.
1335  */
1336 static void
1337 clipboard_get_cb (GtkClipboard     *clipboard,
1338                   GtkSelectionData *selection_data,
1339                   guint             info,
1340                   gpointer          data)
1341 {
1342   GtkTextBuffer *buffer = GTK_TEXT_BUFFER(data);
1343   gchar *str;
1344   GtkTextIter start, end;
1345   
1346   if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1347     {
1348       /* Extract the selected text */
1349       str = gtk_text_iter_get_visible_text(&start, &end);
1350       gtk_selection_data_set_text (selection_data, str);
1351       g_free (str);
1352     }
1353 }
1354
1355 /* Called when we request a paste and receive the data
1356  */
1357 static void
1358 clipboard_received (GtkClipboard *clipboard,
1359                     const gchar  *str,
1360                     gpointer      data)
1361 {
1362   ClipboardRequest *request_data = data;
1363   GtkTextBuffer *buffer = request_data->buffer;
1364
1365   if (str)
1366     {
1367       gboolean reselect;
1368       GtkTextIter insert_point;
1369       GtkTextMark *paste_point_override;
1370
1371       paste_point_override = gtk_text_buffer_get_mark (buffer,
1372                                                        "__paste_point_override");
1373       
1374       if (paste_point_override != NULL)
1375         {
1376           gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1377                                            paste_point_override);
1378           gtk_text_buffer_delete_mark(buffer,
1379                                       gtk_text_buffer_get_mark (buffer,
1380                                                                 "__paste_point_override"));
1381         }
1382       else
1383         {
1384           gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1385                                            gtk_text_buffer_get_mark (buffer,
1386                                                                      "insert"));
1387         }
1388       
1389       reselect = FALSE;
1390
1391       /* FIXME ALL OF THIS - I think that the "best method" is that when pasting
1392        * with the cursor inside the selection area, you replace the selection
1393        * with the new text, otherwise, you simply insert the new text at
1394        * the point where the click occured, unselecting any selected text.
1395        *
1396        * This probably is best implemented as a "replace_selection" flag in
1397        * ClipboardRequest.
1398        */
1399 #if 0      
1400       if ((TRUE/* Text is selected FIXME */) && 
1401           (!buffer->have_selection || request_data->is_clipboard))
1402         {
1403           reselect = TRUE;
1404           
1405           if (buffer->have_selection)
1406             {
1407               /* FIXME Delete currently-selected chars but don't give up X
1408                  selection since we'll use the newly-pasted stuff as
1409                  a new X selection */
1410               
1411             }
1412           else
1413             ; /* FIXME Delete selected chars and give up X selection */
1414         }
1415 #endif
1416       
1417       
1418       if (request_data->interactive)
1419         gtk_text_buffer_insert_interactive (buffer, &insert_point,
1420                                             str, -1, request_data->default_editable);
1421       else
1422         gtk_text_buffer_insert (buffer, &insert_point,
1423                                 str, -1);
1424       
1425       if (reselect)
1426         ; /* FIXME Select the region of text we just inserted */
1427     }
1428
1429   g_object_unref (G_OBJECT (buffer));
1430   g_free (request_data);
1431 }
1432
1433 static void
1434 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
1435 {
1436   static const GtkTargetEntry targets[] = {
1437     { "STRING", 0, TARGET_STRING },
1438     { "TEXT",   0, TARGET_TEXT }, 
1439     { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
1440     { "UTF8_STRING", 0, TARGET_UTF8_STRING }
1441   };
1442
1443   GtkTextIter start;
1444   GtkTextIter end;
1445
1446   GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
1447
1448   /* Determine whether we have a selection and adjust X selection
1449    * accordingly.
1450    */
1451   
1452   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1453     {
1454       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
1455         gtk_clipboard_clear (clipboard);
1456     }
1457   else
1458     {
1459       /* Even if we already have the selection, we need to update our
1460        * timestamp.
1461        */
1462       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
1463                                          clipboard_get_cb, clipboard_clear_cb, G_OBJECT (buffer)))
1464         clipboard_clear_cb (clipboard, buffer);
1465     }
1466 }
1467
1468 static void
1469 paste (GtkTextBuffer *buffer, 
1470        gboolean is_clipboard,
1471        gboolean interactive,
1472        gboolean default_editable)
1473 {
1474   ClipboardRequest *data = g_new (ClipboardRequest, 1);
1475
1476   data->buffer = buffer;
1477   g_object_ref (G_OBJECT (buffer));
1478   data->interactive = interactive;
1479   data->default_editable = default_editable;
1480
1481   gtk_clipboard_request_text (gtk_clipboard_get (is_clipboard ? GDK_NONE : GDK_SELECTION_PRIMARY),
1482                               clipboard_received, data);
1483 }
1484
1485 void
1486 gtk_text_buffer_paste_primary (GtkTextBuffer *buffer,
1487                                GtkTextIter   *override_location,
1488                                gboolean       default_editable)
1489 {
1490   if (override_location != NULL)
1491     gtk_text_buffer_create_mark(buffer,
1492                                 "__paste_point_override",
1493                                 override_location, FALSE);
1494   
1495   paste (buffer, FALSE, TRUE, default_editable);
1496 }
1497
1498 void
1499 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
1500                                  gboolean       default_editable)
1501 {
1502   paste (buffer, TRUE, TRUE, default_editable);
1503 }
1504
1505 gboolean
1506 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
1507                                   gboolean interactive,
1508                                   gboolean default_editable)
1509 {
1510   GtkTextIter start;
1511   GtkTextIter end;
1512   
1513   if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1514     {
1515       return FALSE; /* No selection */
1516     }
1517   else
1518     {
1519       if (interactive)
1520         gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
1521       else
1522         gtk_text_buffer_delete (buffer, &start, &end);
1523
1524       return TRUE; /* We deleted stuff */
1525     }
1526 }
1527
1528 static void
1529 cut_or_copy(GtkTextBuffer *buffer,
1530             gboolean delete_region_after,
1531             gboolean interactive,
1532             gboolean default_editable)
1533 {
1534   /* We prefer to cut the selected region between selection_bound and
1535      insertion point. If that region is empty, then we cut the region
1536      between the "anchor" and the insertion point (this is for C-space
1537      and M-w and other Emacs-style copy/yank keys). Note that insert
1538      and selection_bound are guaranteed to exist, but the anchor only
1539      exists sometimes. */
1540   GtkTextIter start;
1541   GtkTextIter end;
1542
1543   if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1544     {
1545       /* Let's try the anchor thing */
1546       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
1547       
1548       if (anchor == NULL)
1549         return;
1550       else
1551         {
1552           gtk_text_buffer_get_iter_at_mark(buffer, &end, anchor);
1553           gtk_text_iter_reorder(&start, &end);
1554         }
1555     }
1556
1557   if (!gtk_text_iter_equal(&start, &end))
1558     {
1559       GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
1560       gchar *text;
1561       
1562       text = gtk_text_iter_get_visible_text (&start, &end);
1563       gtk_clipboard_set_text (clipboard, text, -1);
1564       g_free (text);
1565       
1566       if (delete_region_after)
1567         {
1568           if (interactive)
1569             gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
1570           else
1571             gtk_text_buffer_delete (buffer, &start, &end);
1572         }
1573     }
1574 }
1575
1576 void
1577 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
1578                                gboolean       default_editable)
1579 {
1580   cut_or_copy (buffer, TRUE, TRUE, default_editable);
1581 }
1582
1583 void
1584 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
1585 {
1586   cut_or_copy (buffer, FALSE, TRUE, TRUE);
1587 }
1588
1589
1590 gboolean
1591 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
1592                                         GtkTextIter        *start,
1593                                         GtkTextIter        *end)
1594 {
1595   g_return_val_if_fail (buffer != NULL, FALSE);
1596   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1597
1598   return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
1599 }
1600
1601
1602 /*
1603  * Debug spew
1604  */
1605
1606 void
1607 gtk_text_buffer_spew(GtkTextBuffer *buffer)
1608 {
1609   gtk_text_btree_spew(get_btree (buffer));
1610 }
1611