]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbuffer.c
Half-ass somewhat fix this function, so that scrolling to the insertion
[~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   gboolean replace_selection;
47 };
48
49 enum {
50   INSERT_TEXT,
51   DELETE_TEXT,
52   CHANGED,
53   MODIFIED_CHANGED,
54   MARK_SET,
55   MARK_DELETED,
56   APPLY_TAG,
57   REMOVE_TAG,
58   LAST_SIGNAL
59 };
60
61 enum {
62   ARG_0,
63   LAST_ARG
64 };
65
66 enum {
67   TARGET_STRING,
68   TARGET_TEXT,
69   TARGET_COMPOUND_TEXT,
70   TARGET_UTF8_STRING,
71   TARGET_TEXT_BUFFER_CONTENTS
72 };
73
74 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
75 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
76 static void gtk_text_buffer_finalize   (GObject            *object);
77
78
79 static void gtk_text_buffer_update_primary_selection   (GtkTextBuffer     *buffer);
80 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
81                                                         GtkTextIter       *iter,
82                                                         const gchar       *text,
83                                                         gint               len,
84                                                         gboolean           interactive);
85 static void gtk_text_buffer_real_delete_text           (GtkTextBuffer     *buffer,
86                                                         GtkTextIter       *start,
87                                                         GtkTextIter       *end,
88                                                         gboolean           interactive);
89 static void gtk_text_buffer_real_apply_tag             (GtkTextBuffer     *buffer,
90                                                         GtkTextTag        *tag,
91                                                         const GtkTextIter *start_char,
92                                                         const GtkTextIter *end_char);
93 static void gtk_text_buffer_real_remove_tag            (GtkTextBuffer     *buffer,
94                                                         GtkTextTag        *tag,
95                                                         const GtkTextIter *start_char,
96                                                         const GtkTextIter *end_char);
97 static void gtk_text_buffer_real_changed               (GtkTextBuffer     *buffer);
98
99 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
100
101 static GtkObjectClass *parent_class = NULL;
102 static guint signals[LAST_SIGNAL] = { 0 };
103
104 GtkType
105 gtk_text_buffer_get_type (void)
106 {
107   static GtkType our_type = 0;
108
109   if (our_type == 0)
110     {
111       static const GtkTypeInfo our_info =
112       {
113         "GtkTextBuffer",
114         sizeof (GtkTextBuffer),
115         sizeof (GtkTextBufferClass),
116         (GtkClassInitFunc) gtk_text_buffer_class_init,
117         (GtkObjectInitFunc) gtk_text_buffer_init,
118         /* reserved_1 */ NULL,
119         /* reserved_2 */ NULL,
120         (GtkClassInitFunc) NULL
121       };
122
123       our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
124     }
125
126   return our_type;
127 }
128
129 static void
130 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
131 {
132   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
133   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
134
135   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
136
137   signals[INSERT_TEXT] =
138     gtk_signal_new ("insert_text",
139                     GTK_RUN_LAST,
140                     GTK_CLASS_TYPE (object_class),
141                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
142                     gtk_marshal_VOID__BOXED_BOXED_INT_BOOLEAN,
143                     GTK_TYPE_NONE,
144                     4,
145                     GTK_TYPE_TEXT_ITER,
146                     GTK_TYPE_TEXT_ITER,
147                     GTK_TYPE_INT,
148                     GTK_TYPE_BOOL);
149
150   signals[DELETE_TEXT] =
151     gtk_signal_new ("delete_text",
152                     GTK_RUN_LAST,
153                     GTK_CLASS_TYPE (object_class),
154                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
155                     gtk_marshal_VOID__BOXED_BOXED_BOOLEAN,
156                     GTK_TYPE_NONE,
157                     3,
158                     GTK_TYPE_TEXT_ITER,
159                     GTK_TYPE_TEXT_ITER,
160                     GTK_TYPE_BOOL);
161
162   signals[CHANGED] =
163     gtk_signal_new ("changed",
164                     GTK_RUN_LAST,
165                     GTK_CLASS_TYPE (object_class),
166                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
167                     gtk_marshal_VOID__VOID,
168                     GTK_TYPE_NONE,
169                     0);
170
171   signals[MODIFIED_CHANGED] =
172     gtk_signal_new ("modified_changed",
173                     GTK_RUN_LAST,
174                     GTK_CLASS_TYPE (object_class),
175                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
176                     gtk_marshal_VOID__VOID,
177                     GTK_TYPE_NONE,
178                     0);
179
180   signals[MARK_SET] =
181     gtk_signal_new ("mark_set",
182                     GTK_RUN_LAST,
183                     GTK_CLASS_TYPE (object_class),
184                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
185                     gtk_marshal_VOID__BOXED_OBJECT,
186                     GTK_TYPE_NONE,
187                     2,
188                     GTK_TYPE_TEXT_ITER,
189                     G_TYPE_OBJECT);
190
191   signals[MARK_DELETED] =
192     gtk_signal_new ("mark_deleted",
193                     GTK_RUN_LAST,
194                     GTK_CLASS_TYPE (object_class),
195                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
196                     gtk_marshal_VOID__OBJECT,
197                     GTK_TYPE_NONE,
198                     1,
199                     G_TYPE_OBJECT);
200
201   signals[APPLY_TAG] =
202     gtk_signal_new ("apply_tag",
203                     GTK_RUN_LAST,
204                     GTK_CLASS_TYPE (object_class),
205                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
206                     gtk_marshal_VOID__OBJECT_BOXED_BOXED,
207                     GTK_TYPE_NONE,
208                     3,
209                     G_TYPE_OBJECT,
210                     GTK_TYPE_TEXT_ITER,
211                     GTK_TYPE_TEXT_ITER);
212
213   signals[REMOVE_TAG] =
214     gtk_signal_new ("remove_tag",
215                     GTK_RUN_LAST,
216                     GTK_CLASS_TYPE (object_class),
217                     GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
218                     gtk_marshal_VOID__OBJECT_BOXED_BOXED,
219                     GTK_TYPE_NONE,
220                     3,
221                     G_TYPE_OBJECT,
222                     GTK_TYPE_TEXT_ITER,
223                     GTK_TYPE_TEXT_ITER);
224
225   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
226
227   gobject_class->finalize = gtk_text_buffer_finalize;
228
229   klass->insert_text = gtk_text_buffer_real_insert_text;
230   klass->delete_text = gtk_text_buffer_real_delete_text;
231   klass->apply_tag = gtk_text_buffer_real_apply_tag;
232   klass->remove_tag = gtk_text_buffer_real_remove_tag;
233   klass->changed = gtk_text_buffer_real_changed;
234 }
235
236 void
237 gtk_text_buffer_init (GtkTextBuffer *buffer)
238 {
239   buffer->clipboard_contents = NULL;
240 }
241
242 /**
243  * gtk_text_buffer_new:
244  * @table: a tag table, or NULL to create a new one
245  *
246  * Creates a new text buffer.
247  *
248  * Return value: a new text buffer
249  **/
250 GtkTextBuffer*
251 gtk_text_buffer_new (GtkTextTagTable *table)
252 {
253   GtkTextBuffer *text_buffer;
254
255   text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
256
257   if (table)
258     {
259       text_buffer->tag_table = table;
260
261       gtk_object_ref (GTK_OBJECT (text_buffer->tag_table));
262       gtk_object_sink (GTK_OBJECT (text_buffer->tag_table));
263     }
264
265   return text_buffer;
266 }
267
268 static void
269 gtk_text_buffer_finalize (GObject *object)
270 {
271   GtkTextBuffer *buffer;
272
273   buffer = GTK_TEXT_BUFFER (object);
274
275   if (buffer->clipboard_contents)
276     {
277       g_object_unref (G_OBJECT (buffer->clipboard_contents));
278       buffer->clipboard_contents = NULL;
279     }
280   
281   if (buffer->tag_table)
282     {
283       gtk_object_unref (GTK_OBJECT (buffer->tag_table));
284       buffer->tag_table = NULL;
285     }
286
287   if (buffer->btree)
288     {
289       gtk_text_btree_unref (buffer->btree);
290       buffer->btree = NULL;
291     }
292   
293   G_OBJECT_CLASS (parent_class)->finalize (object);
294 }
295
296 static GtkTextTagTable*
297 get_table (GtkTextBuffer *buffer)
298 {
299   if (buffer->tag_table == NULL)
300     {
301       buffer->tag_table = gtk_text_tag_table_new ();
302
303       gtk_object_ref (GTK_OBJECT (buffer->tag_table));
304       gtk_object_sink (GTK_OBJECT (buffer->tag_table));
305     }
306
307   return buffer->tag_table;
308 }
309
310 static GtkTextBTree*
311 get_btree (GtkTextBuffer *buffer)
312 {
313   if (buffer->btree == NULL)
314     buffer->btree = gtk_text_btree_new (gtk_text_buffer_get_tag_table (buffer),
315                                         buffer);
316
317   return buffer->btree;
318 }
319
320 GtkTextBTree*
321 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
322 {
323   return get_btree (buffer);
324 }
325
326 /**
327  * gtk_text_buffer_get_tag_table:
328  * @buffer: a #GtkTextBuffer
329  *
330  * Get the #GtkTextTagTable associated with this buffer.
331  *
332  * Return value: the buffer's tag table
333  **/
334 GtkTextTagTable*
335 gtk_text_buffer_get_tag_table (GtkTextBuffer  *buffer)
336 {
337   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
338
339   return get_table (buffer);
340 }
341
342 /**
343  * gtk_text_buffer_set_text:
344  * @buffer: a #GtkTextBuffer
345  * @text: UTF-8 text to insert
346  * @len: length of @text in bytes
347  *
348  * Deletes current contents of @buffer, and inserts @text instead.  If
349  * @text doesn't end with a newline, a newline is added;
350  * #GtkTextBuffer contents must always end with a newline. If @text
351  * ends with a newline, the new buffer contents will be exactly
352  * @text. If @len is -1, @text must be nul-terminated.
353  **/
354 void
355 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
356                           const gchar   *text,
357                           gint           len)
358 {
359   GtkTextIter start, end;
360
361   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
362   g_return_if_fail (text != NULL);
363
364   if (len < 0)
365     len = strlen (text);
366
367   /* Chop newline, since the buffer will already have one
368    * in it.
369    */
370   if (len > 0 && text[len-1] == '\n')
371     len -= 1;
372
373   gtk_text_buffer_get_bounds (buffer, &start, &end);
374
375   gtk_text_buffer_delete (buffer, &start, &end);
376
377   if (len > 0)
378     {
379       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
380       gtk_text_buffer_insert (buffer, &start, text, len);
381     }
382 }
383
384 /*
385  * Insertion
386  */
387
388 static void
389
390 gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
391                                   GtkTextIter *iter,
392                                   const gchar *text,
393                                   gint len,
394                                   gboolean interactive)
395 {
396   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
397   g_return_if_fail (iter != NULL);
398
399   gtk_text_btree_insert (iter, text, len);
400
401   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
402 }
403
404 static void
405 gtk_text_buffer_emit_insert (GtkTextBuffer *buffer,
406                              GtkTextIter *iter,
407                              const gchar *text,
408                              gint len,
409                              gboolean interactive)
410 {
411   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
412   g_return_if_fail (iter != NULL);
413   g_return_if_fail (text != NULL);
414
415   if (len < 0)
416     len = strlen (text);
417
418   if (len > 0)
419     {
420       gtk_signal_emit (GTK_OBJECT (buffer), signals[INSERT_TEXT],
421                        iter, text, len, interactive);
422     }
423 }
424
425 /**
426  * gtk_text_buffer_insert:
427  * @buffer: a #GtkTextBuffer
428  * @iter: a position in the buffer
429  * @text: UTF-8 format text to insert
430  * @len: length of text in bytes, or -1
431  *
432  * Inserts @len bytes of @text at position @iter.  If @len is -1,
433  * @text must be nul-terminated and will be inserted in its
434  * entirety. Emits the "insert_text" signal; insertion actually occurs
435  * in the default handler for the signal. @iter is invalidated when
436  * insertion occurs (because the buffer contents change), but the
437  * default signal handler revalidates it to point to the end of the
438  * inserted text.
439  *
440  **/
441 void
442 gtk_text_buffer_insert (GtkTextBuffer *buffer,
443                         GtkTextIter *iter,
444                         const gchar *text,
445                         gint len)
446 {
447   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
448   g_return_if_fail (iter != NULL);
449   g_return_if_fail (text != NULL);
450
451   gtk_text_buffer_emit_insert (buffer, iter, text, len, FALSE);
452 }
453
454 /**
455  * gtk_text_buffer_insert_at_cursor:
456  * @buffer: a #GtkTextBuffer
457  * @text: some text in UTF-8 format
458  * @len: length of text, in bytes
459  *
460  * Simply calls gtk_text_buffer_insert (), using the current
461  * cursor position as the insertion point.
462  **/
463 void
464 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
465                                   const gchar *text,
466                                   gint len)
467 {
468   GtkTextIter iter;
469
470   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
471   g_return_if_fail (text != NULL);
472
473   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
474                                     gtk_text_buffer_get_mark (buffer,
475                                                               "insert"));
476
477   gtk_text_buffer_insert (buffer, &iter, text, len);
478 }
479
480 /**
481  * gtk_text_buffer_insert_interactive:
482  * @buffer: a #GtkTextBuffer
483  * @iter: a position in @buffer
484  * @text: some UTF-8 text
485  * @len: length of text in bytes, or -1
486  * @default_editable: default editability of buffer
487  *
488  * Like gtk_text_buffer_insert (), but the insertion will not occur if
489  * @iter is at a non-editable location in the buffer.  Usually you
490  * want to prevent insertions at ineditable locations if the insertion
491  * results from a user action (is interactive).
492  *
493  * @default_editable indicates the editability of text that doesn't
494  * have a tag affecting editability applied to it. Typically the
495  * result of gtk_text_view_get_editable() is appropriate here.
496  *
497  * Return value: whether text was actually inserted
498  **/
499 gboolean
500 gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer,
501                                     GtkTextIter   *iter,
502                                     const gchar   *text,
503                                     gint           len,
504                                     gboolean       default_editable)
505 {
506   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
507   g_return_val_if_fail (text != NULL, FALSE);
508
509   if (gtk_text_iter_editable (iter, default_editable))
510     {
511       gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
512       return TRUE;
513     }
514   else
515     return FALSE;
516 }
517
518 /**
519  * gtk_text_buffer_insert_interactive_at_cursor:
520  * @buffer: a #GtkTextBuffer
521  * @text: text in UTF-8 format
522  * @len: length of text in bytes, or -1
523  * @default_editable: default editability of buffer
524  *
525  * Calls gtk_text_buffer_insert_interactive () at the cursor
526  * position.
527  *
528  * @default_editable indicates the editability of text that doesn't
529  * have a tag affecting editability applied to it. Typically the
530  * result of gtk_text_view_get_editable() is appropriate here.
531  * 
532  * Return value: whether text was actually inserted
533  **/
534 gboolean
535 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
536                                               const gchar   *text,
537                                               gint           len,
538                                               gboolean       default_editable)
539 {
540   GtkTextIter iter;
541
542   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
543   g_return_val_if_fail (text != NULL, FALSE);
544
545   gtk_text_buffer_get_iter_at_mark (buffer, &iter,
546                                     gtk_text_buffer_get_mark (buffer,
547                                                               "insert"));
548
549   return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
550                                              default_editable);
551 }
552
553 static gboolean
554 possibly_not_text (gunichar ch,
555                    gpointer user_data)
556 {
557   return ch == 0xFFFD;
558 }
559
560 static void
561 insert_text_range (GtkTextBuffer     *buffer,
562                    GtkTextIter       *iter,
563                    const GtkTextIter *orig_start,
564                    const GtkTextIter *orig_end,
565                    gboolean           interactive)
566 {
567   gchar *text;
568
569   text = gtk_text_iter_get_text (orig_start, orig_end);
570
571   gtk_text_buffer_emit_insert (buffer, iter, text, -1, interactive);
572
573   g_free (text);
574 }
575
576 typedef struct _Range Range;
577 struct _Range
578 {
579   GtkTextBuffer *buffer;
580   GtkTextMark *start_mark;
581   GtkTextMark *end_mark;
582   GtkTextMark *whole_end_mark;
583   GtkTextIter *range_start;
584   GtkTextIter *range_end;
585   GtkTextIter *whole_end;
586 };
587
588 static Range*
589 save_range (GtkTextIter *range_start,
590             GtkTextIter *range_end,
591             GtkTextIter *whole_end)
592 {
593   Range *r;
594
595   r = g_new (Range, 1);
596
597   r->buffer = gtk_text_iter_get_buffer (range_start);
598   g_object_ref (G_OBJECT (r->buffer));
599   
600   r->start_mark = 
601     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
602                                  NULL,
603                                  range_start,
604                                  TRUE);
605   r->end_mark = 
606     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
607                                  NULL,
608                                  range_end,
609                                  FALSE);
610
611   r->whole_end_mark = 
612     gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
613                                  NULL,
614                                  whole_end,
615                                  FALSE);
616
617   r->range_start = range_start;
618   r->range_end = range_end;
619   r->whole_end = whole_end;
620
621   return r;
622 }
623
624 static void
625 restore_range (Range *r)
626 {
627   gtk_text_buffer_get_iter_at_mark (r->buffer,
628                                     r->range_start,
629                                     r->start_mark);
630       
631   gtk_text_buffer_get_iter_at_mark (r->buffer,
632                                     r->range_end,
633                                     r->end_mark);
634       
635   gtk_text_buffer_get_iter_at_mark (r->buffer,
636                                     r->whole_end,
637                                     r->whole_end_mark);
638       
639   gtk_text_buffer_delete_mark (r->buffer, r->start_mark);
640   gtk_text_buffer_delete_mark (r->buffer, r->end_mark);
641   gtk_text_buffer_delete_mark (r->buffer, r->whole_end_mark);
642
643   g_object_unref (G_OBJECT (r->buffer));
644   g_free (r); 
645 }
646
647 static void
648 insert_range_untagged (GtkTextBuffer     *buffer,
649                        GtkTextIter       *iter,
650                        const GtkTextIter *orig_start,
651                        const GtkTextIter *orig_end,
652                        gboolean           interactive)
653 {
654   GtkTextIter range_start;
655   GtkTextIter range_end;
656   GtkTextIter start, end;
657   GtkTextBuffer *src_buffer;
658   Range *r;
659   
660   if (gtk_text_iter_equal (orig_start, orig_end))
661     return;
662
663   start = *orig_start;
664   end = *orig_end;
665   
666   src_buffer = gtk_text_iter_get_buffer (&start);
667   
668   range_start = start;
669   range_end = start;
670   
671   while (TRUE)
672     {
673       if (gtk_text_iter_equal (&range_start, &range_end))
674         {
675           /* Figure out how to move forward */
676
677           g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
678           
679           if (gtk_text_iter_equal (&range_end, &end))
680             {
681               /* nothing left to do */
682               break;
683             }
684           else if (gtk_text_iter_get_char (&range_end) == 0xFFFD)
685             {
686               GdkPixbuf *pixbuf = NULL;
687               GtkTextChildAnchor *anchor = NULL;
688               pixbuf = gtk_text_iter_get_pixbuf (&range_end);
689               anchor = gtk_text_iter_get_child_anchor (&range_end);
690
691               if (pixbuf)
692                 {
693                   r = save_range (&range_start,
694                                   &range_end,
695                                   &end);
696
697                   gtk_text_buffer_insert_pixbuf (buffer,
698                                                  iter,
699                                                  pixbuf);
700
701                   restore_range (r);
702                   r = NULL;
703                   
704                   gtk_text_iter_next_char (&range_end);
705                   
706                   range_start = range_end;
707                 }
708               else if (anchor)
709                 {
710                   /* Just skip anchors */
711
712                   gtk_text_iter_next_char (&range_end);
713                   range_start = range_end;
714                 }
715               else
716                 {
717                   /* The 0xFFFD was in a text segment, so
718                    * keep going. 
719                    */
720                   gtk_text_iter_forward_find_char (&range_end,
721                                                    possibly_not_text, NULL,
722                                                    &end);
723                   
724                   g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
725                 }
726             }
727           else
728             {
729               /* Text segment starts here, so forward search to
730                * find its possible endpoint
731                */
732               gtk_text_iter_forward_find_char (&range_end,
733                                                possibly_not_text, NULL,
734                                                &end);
735               
736               g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
737             }
738         }
739       else
740         {
741           r = save_range (&range_start,
742                           &range_end,
743                           &end);
744           
745           insert_text_range (buffer,
746                              iter,
747                              &range_start,
748                              &range_end,
749                              interactive);
750
751           restore_range (r);
752           r = NULL;
753           
754           range_start = range_end;
755         }
756     }
757 }
758
759 static void
760 gtk_text_buffer_real_insert_range (GtkTextBuffer     *buffer,
761                                    GtkTextIter       *iter,
762                                    const GtkTextIter *orig_start,
763                                    const GtkTextIter *orig_end,
764                                    gboolean           interactive)
765 {
766   /* Find each range of uniformly-tagged text, insert it,
767    * then apply the tags.
768    */
769   GtkTextIter start = *orig_start;
770   GtkTextIter end = *orig_end;
771   GtkTextIter range_start;
772   GtkTextIter range_end;
773   GtkTextBuffer *src_buffer;
774   Range *r;
775   
776   if (gtk_text_iter_equal (orig_start, orig_end))
777     return;
778
779   src_buffer = gtk_text_iter_get_buffer (orig_start);
780   
781   gtk_text_iter_reorder (&start, &end);
782
783   range_start = start;
784   range_end = start;
785
786   while (TRUE)
787     {
788       gint start_offset;
789       GtkTextIter start_iter;
790       GSList *tags;
791       GSList *tmp_list;
792       
793       if (gtk_text_iter_equal (&range_start, &end))
794         break; /* All done */
795
796       g_assert (gtk_text_iter_compare (&range_start, &end) < 0);
797       
798       gtk_text_iter_forward_to_tag_toggle (&range_end, NULL);
799
800       g_assert (!gtk_text_iter_equal (&range_start, &range_end));
801
802       /* Clamp to the end iterator */
803       if (gtk_text_iter_compare (&range_end, &end) > 0)
804         range_end = end;
805       
806       /* We have a range with unique tags; insert it, and
807        * apply all tags.
808        */
809       start_offset = gtk_text_iter_get_offset (iter);
810
811       r = save_range (&range_start, &range_end, &end);
812       
813       insert_range_untagged (buffer, iter, &range_start, &range_end, interactive);
814
815       restore_range (r);
816       r = NULL;
817       
818       gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
819       
820       tags = gtk_text_iter_get_tags (&range_start);
821       tmp_list = tags;
822       while (tmp_list != NULL)
823         {
824           gtk_text_buffer_apply_tag (buffer,
825                                      tmp_list->data,
826                                      &start_iter,
827                                      iter);
828           
829           tmp_list = g_slist_next (tmp_list);
830         }
831       g_slist_free (tags);
832
833       range_start = range_end;
834     }
835 }
836
837 /**
838  * gtk_text_buffer_insert_range:
839  * @buffer: a #GtkTextBuffer
840  * @iter: a position in @buffer
841  * @start: a position in a #GtkTextBuffer
842  * @end: another position in the same buffer as @start
843  *
844  * Copies text, tags, and pixbufs between @start and @end (the order
845  * of @start and @end doesn't matter) and inserts the copy at @iter.
846  * Used instead of simply getting/inserting text because it preserves
847  * images and tags. If @start and @end are in a different buffer from
848  * @buffer, the two buffers must share the same tag table.
849  *
850  * Implemented via emissions of the insert_text and apply_tag signals,
851  * so expect those.
852  **/
853 void
854 gtk_text_buffer_insert_range (GtkTextBuffer     *buffer,
855                               GtkTextIter       *iter,
856                               const GtkTextIter *start,
857                               const GtkTextIter *end)
858 {
859   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
860   g_return_if_fail (iter != NULL);
861   g_return_if_fail (start != NULL);
862   g_return_if_fail (end != NULL);
863   g_return_if_fail (gtk_text_iter_get_buffer (start) ==
864                     gtk_text_iter_get_buffer (end));
865   g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
866                     buffer->tag_table);  
867
868   gtk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE);
869 }
870
871 /**
872  * gtk_text_buffer_insert_range_interactive:
873  * @buffer: a #GtkTextBuffer
874  * @iter: a position in @buffer
875  * @start: a position in a #GtkTextBuffer
876  * @end: another position in the same buffer as @start
877  * @default_editable: default editability of the buffer
878  *
879  * Same as gtk_text_buffer_insert_range(), but does nothing if the
880  * insertion point isn't editable. The @default_editable parameter
881  * indicates whether the text is editable at @iter if no tags
882  * enclosing @iter affect editability. Typically the result of
883  * gtk_text_view_get_editable() is appropriate here.
884  *
885  * Returns: whether an insertion was possible at @iter
886  **/
887 gboolean
888 gtk_text_buffer_insert_range_interactive (GtkTextBuffer     *buffer,
889                                           GtkTextIter       *iter,
890                                           const GtkTextIter *start,
891                                           const GtkTextIter *end,
892                                           gboolean           default_editable)
893 {
894   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
895   g_return_val_if_fail (iter != NULL, FALSE);
896   g_return_val_if_fail (start != NULL, FALSE);
897   g_return_val_if_fail (end != NULL, FALSE);
898   g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
899                         gtk_text_iter_get_buffer (end), FALSE);
900   g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
901                         buffer->tag_table, FALSE);
902
903
904   if (gtk_text_iter_editable (iter, default_editable))
905     {
906       gtk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE);
907       return TRUE;
908     }
909   else
910     return FALSE;
911 }
912
913 /**
914  * gtk_text_buffer_insert_with_tags:
915  * @buffer: a #GtkTextBuffer
916  * @iter: an iterator in @buffer
917  * @text: UTF-8 text
918  * @len: length of @text, or -1
919  * @first_tag: first tag to apply to @text
920  * @Varargs: NULL-terminated list of tags to apply
921  *
922  * Inserts @text into @buffer at @iter, applying the list of tags to
923  * the newly-inserted text. The last tag specified must be NULL to
924  * terminate the list. Equivalent to calling gtk_text_buffer_insert (),
925  * then gtk_text_buffer_apply_tag () on the inserted text;
926  * gtk_text_buffer_insert_with_tags () is just a convenience function.
927  **/
928 void
929 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
930                                   GtkTextIter   *iter,
931                                   const gchar   *text,
932                                   gint           len,
933                                   GtkTextTag    *first_tag,
934                                   ...)
935 {
936   gint start_offset;
937   GtkTextIter start;
938   va_list args;
939   GtkTextTag *tag;
940
941   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
942   g_return_if_fail (iter != NULL);
943   g_return_if_fail (text != NULL);
944
945   start_offset = gtk_text_iter_get_offset (iter);
946
947   gtk_text_buffer_insert (buffer, iter, text, len);
948
949   if (first_tag == NULL)
950     return;
951
952   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
953
954   va_start (args, first_tag);
955   tag = first_tag;
956   while (tag)
957     {
958       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
959
960       tag = va_arg (args, GtkTextTag*);
961     }
962
963   va_end (args);
964 }
965
966 /**
967  * gtk_text_buffer_insert_with_tags_by_name:
968  * @buffer: a #GtkTextBuffer
969  * @iter: position in @buffer
970  * @text: UTF-8 text
971  * @len: length of @text, or -1
972  * @first_tag_name: name of a tag to apply to @text
973  * @Varargs: more tag names
974  *
975  * Same as gtk_text_buffer_insert_with_tags (), but allows you
976  * to pass in tag names instead of tag objects.
977  **/
978 void
979 gtk_text_buffer_insert_with_tags_by_name  (GtkTextBuffer *buffer,
980                                            GtkTextIter   *iter,
981                                            const gchar   *text,
982                                            gint           len,
983                                            const gchar   *first_tag_name,
984                                            ...)
985 {
986   gint start_offset;
987   GtkTextIter start;
988   va_list args;
989   const gchar *tag_name;
990
991   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
992   g_return_if_fail (iter != NULL);
993   g_return_if_fail (text != NULL);
994
995   start_offset = gtk_text_iter_get_offset (iter);
996
997   gtk_text_buffer_insert (buffer, iter, text, len);
998
999   if (first_tag_name == NULL)
1000     return;
1001
1002   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1003
1004   va_start (args, first_tag_name);
1005   tag_name = first_tag_name;
1006   while (tag_name)
1007     {
1008       GtkTextTag *tag;
1009
1010       tag = gtk_text_tag_table_lookup (buffer->tag_table,
1011                                        tag_name);
1012
1013       if (tag == NULL)
1014         {
1015           g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
1016           return;
1017         }
1018
1019       gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1020
1021       tag_name = va_arg (args, const gchar*);
1022     }
1023
1024   va_end (args);
1025 }
1026
1027
1028 /*
1029  * Deletion
1030  */
1031
1032 static void
1033 gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
1034                                   GtkTextIter *start,
1035                                   GtkTextIter *end,
1036                                   gboolean interactive)
1037 {
1038   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1039   g_return_if_fail (start != NULL);
1040   g_return_if_fail (end != NULL);
1041
1042   gtk_text_btree_delete (start, end);
1043
1044   /* may have deleted the selection... */
1045   gtk_text_buffer_update_primary_selection (buffer);
1046
1047   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1048 }
1049
1050 static void
1051 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
1052                              GtkTextIter *start,
1053                              GtkTextIter *end,
1054                              gboolean interactive)
1055 {
1056   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1057   g_return_if_fail (start != NULL);
1058   g_return_if_fail (end != NULL);
1059
1060   if (gtk_text_iter_equal (start, end))
1061     return;
1062
1063   gtk_text_iter_reorder (start, end);
1064
1065   /* Somewhat annoyingly, if you try to delete the final newline
1066    * the BTree will put it back; which means you can't deduce the
1067    * final contents of the buffer purely by monitoring insert/delete
1068    * signals on the buffer. But if you delete the final newline, any
1069    * tags on the newline will go away, oddly. See comment in
1070    * gtktextbtree.c. This is all sort of annoying, but really hard
1071    * to fix.
1072    */
1073   gtk_signal_emit (GTK_OBJECT (buffer),
1074                    signals[DELETE_TEXT],
1075                    start, end,
1076                    interactive);
1077 }
1078
1079 /**
1080  * gtk_text_buffer_delete:
1081  * @buffer: a #GtkTextBuffer
1082  * @start: a position in @buffer
1083  * @end: another position in @buffer
1084  *
1085  * Deletes text between @start and @end. The order of @start and @end
1086  * is not actually relevant; gtk_text_buffer_delete () will reorder
1087  * them. This function actually emits the "delete_text" signal, and
1088  * the default handler of that signal deletes the text. Because the
1089  * buffer is modified, all outstanding iterators become invalid after
1090  * calling this function; however, the @start and @end will be
1091  * re-initialized to point to the location where text was deleted.
1092  *
1093  * Note that the final newline in the buffer may not be deleted; a
1094  * #GtkTextBuffer always contains at least one newline.  You can
1095  * safely include the final newline in the range [@start,@end) but it
1096  * won't be affected by the deletion.
1097  *
1098  **/
1099 void
1100 gtk_text_buffer_delete (GtkTextBuffer *buffer,
1101                         GtkTextIter   *start,
1102                         GtkTextIter   *end)
1103 {
1104   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1105   g_return_if_fail (start != NULL);
1106   g_return_if_fail (end != NULL);
1107
1108   gtk_text_buffer_emit_delete (buffer, start, end, FALSE);
1109 }
1110
1111 /**
1112  * gtk_text_buffer_delete_interactive:
1113  * @buffer: a #GtkTextBuffer
1114  * @start_iter: start of range to delete
1115  * @end_iter: end of range
1116  * @default_editable: whether the buffer is editable by default
1117  *
1118  * Deletes all <emphasis>editable</emphasis> text in the given range.
1119  * Calls gtk_text_buffer_delete () for each editable sub-range of
1120  * [@start,@end). @start and @end are revalidated to point to
1121  * the location of the last deleted range, or left untouched if
1122  * no text was deleted.
1123  *
1124  * Return value: whether some text was actually deleted
1125  **/
1126 gboolean
1127 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
1128                                     GtkTextIter   *start_iter,
1129                                     GtkTextIter   *end_iter,
1130                                     gboolean       default_editable)
1131 {
1132   GtkTextMark *end_mark;
1133   GtkTextMark *start_mark;
1134   GtkTextIter iter;
1135   gboolean current_state;
1136   gboolean deleted_stuff = FALSE;
1137
1138   /* Delete all editable text in the range start_iter, end_iter */
1139
1140   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1141   g_return_val_if_fail (start_iter != NULL, FALSE);
1142   g_return_val_if_fail (end_iter != NULL, FALSE);
1143
1144   gtk_text_iter_reorder (start_iter, end_iter);
1145
1146   start_mark = gtk_text_buffer_create_mark (buffer, NULL,
1147                                             start_iter, TRUE);
1148   end_mark = gtk_text_buffer_create_mark (buffer, NULL,
1149                                           end_iter, FALSE);
1150   iter = *start_iter;
1151
1152   current_state = gtk_text_iter_editable (&iter, default_editable);
1153
1154   while (TRUE)
1155     {
1156       gboolean new_state;
1157       gboolean done = FALSE;
1158       GtkTextIter end;
1159
1160       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
1161
1162       gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
1163
1164       if (gtk_text_iter_compare (&iter, &end) >= 0)
1165         {
1166           done = TRUE;
1167           iter = end; /* clamp to the last boundary */
1168         }
1169
1170       new_state = gtk_text_iter_editable (&iter, default_editable);
1171
1172       if (current_state == new_state)
1173         {
1174           if (done)
1175             {
1176               if (current_state)
1177                 {
1178                   /* We're ending an editable region. Delete said region. */
1179                   GtkTextIter start;
1180
1181                   gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1182
1183                   gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1184
1185                   deleted_stuff = TRUE;
1186
1187                   /* revalidate user's iterators. */
1188                   *start_iter = start;
1189                   *end_iter = iter;
1190                 }
1191
1192               break;
1193             }
1194           else
1195             continue;
1196         }
1197
1198       if (current_state && !new_state)
1199         {
1200           /* End of an editable region. Delete it. */
1201           GtkTextIter start;
1202
1203           gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1204
1205           gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1206
1207           current_state = FALSE;
1208           deleted_stuff = TRUE;
1209
1210           /* revalidate user's iterators. */
1211           *start_iter = start;
1212           *end_iter = iter;
1213         }
1214       else
1215         {
1216           /* We are at the start of an editable region. We won't be deleting
1217            * the previous region. Move start mark to start of this region.
1218            */
1219
1220           g_assert (!current_state && new_state);
1221
1222           gtk_text_buffer_move_mark (buffer, start_mark,
1223                                      &iter);
1224
1225
1226           current_state = TRUE;
1227         }
1228
1229       if (done)
1230         break;
1231     }
1232
1233
1234   gtk_text_buffer_delete_mark (buffer, start_mark);
1235   gtk_text_buffer_delete_mark (buffer, end_mark);
1236
1237   return deleted_stuff;
1238 }
1239
1240 /*
1241  * Extracting textual buffer contents
1242  */
1243
1244 /**
1245  * gtk_text_buffer_get_text:
1246  * @buffer: a #GtkTextBuffer
1247  * @start: start of a range
1248  * @end: end of a range
1249  * @include_hidden_chars: whether to include invisible text
1250  *
1251  * Returns the text in the range [@start,@end). Excludes undisplayed
1252  * text (text marked with tags that set the invisibility attribute) if
1253  * @include_hidden_chars is FALSE. Does not include characters
1254  * representing embedded images, so byte and character indexes into
1255  * the returned string do <emphasis>not</emphasis> correspond to byte
1256  * and character indexes into the buffer. Contrast with
1257  * gtk_text_buffer_get_slice ().
1258  *
1259  * Return value: an allocated UTF-8 string
1260  **/
1261 gchar*
1262 gtk_text_buffer_get_text (GtkTextBuffer      *buffer,
1263                           const GtkTextIter *start,
1264                           const GtkTextIter *end,
1265                           gboolean             include_hidden_chars)
1266 {
1267   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1268   g_return_val_if_fail (start != NULL, NULL);
1269   g_return_val_if_fail (end != NULL, NULL);
1270
1271   if (include_hidden_chars)
1272     return gtk_text_iter_get_text (start, end);
1273   else
1274     return gtk_text_iter_get_visible_text (start, end);
1275 }
1276
1277 /**
1278  * gtk_text_buffer_get_slice:
1279  * @buffer: a #GtkTextBuffer
1280  * @start: start of a range
1281  * @end: end of a range
1282  * @include_hidden_chars: whether to include invisible text
1283  *
1284  * Returns the text in the range [@start,@end). Excludes undisplayed
1285  * text (text marked with tags that set the invisibility attribute) if
1286  * @include_hidden_chars is FALSE. The returned string includes a
1287  * 0xFFFD character whenever the buffer contains
1288  * embedded images, so byte and character indexes into
1289  * the returned string <emphasis>do</emphasis> correspond to byte
1290  * and character indexes into the buffer. Contrast with
1291  * gtk_text_buffer_get_text (). Note that 0xFFFD can occur in normal
1292  * text as well, so it is not a reliable indicator that a pixbuf or
1293  * widget is in the buffer.
1294  *
1295  * Return value: an allocated UTF-8 string
1296  **/
1297 gchar*
1298 gtk_text_buffer_get_slice (GtkTextBuffer      *buffer,
1299                            const GtkTextIter *start,
1300                            const GtkTextIter *end,
1301                            gboolean             include_hidden_chars)
1302 {
1303   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1304   g_return_val_if_fail (start != NULL, NULL);
1305   g_return_val_if_fail (end != NULL, NULL);
1306
1307   if (include_hidden_chars)
1308     return gtk_text_iter_get_slice (start, end);
1309   else
1310     return gtk_text_iter_get_visible_slice (start, end);
1311 }
1312
1313 /*
1314  * Pixmaps
1315  */
1316
1317 void
1318 gtk_text_buffer_insert_pixbuf         (GtkTextBuffer      *buffer,
1319                                        GtkTextIter        *iter,
1320                                        GdkPixbuf          *pixbuf)
1321 {
1322   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1323   g_return_if_fail (iter != NULL);
1324   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1325
1326   gtk_text_btree_insert_pixbuf (iter, pixbuf);
1327
1328   /* FIXME pixbuf-specific signal like insert_text */
1329
1330   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1331 }
1332
1333 /*
1334  * Child anchor
1335  */
1336
1337 GtkTextChildAnchor*
1338 gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
1339                                      GtkTextIter   *iter)
1340 {
1341   GtkTextChildAnchor *anchor;
1342   
1343   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1344   g_return_val_if_fail (iter != NULL, NULL);
1345
1346   anchor = gtk_text_btree_create_child_anchor (iter);
1347
1348   /* FIXME child-anchor-specific signal */
1349   
1350   gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1351
1352   return anchor;
1353 }
1354
1355
1356 /*
1357  * Mark manipulation
1358  */
1359
1360 static void
1361 gtk_text_buffer_mark_set (GtkTextBuffer     *buffer,
1362                           const GtkTextIter *location,
1363                           GtkTextMark       *mark)
1364 {
1365   /* IMO this should NOT work like insert_text and delete_text,
1366      where the real action happens in the default handler.
1367
1368      The reason is that the default handler would be _required_,
1369      i.e. the whole widget would start breaking and segfaulting
1370      if the default handler didn't get run. So you can't really
1371      override the default handler or stop the emission; that is,
1372      this signal is purely for notification, and not to allow users
1373      to modify the default behavior. */
1374
1375   g_object_ref (G_OBJECT (mark));
1376
1377   gtk_signal_emit (GTK_OBJECT (buffer),
1378                    signals[MARK_SET],
1379                    location,
1380                    mark);
1381
1382   g_object_unref (G_OBJECT (mark));
1383 }
1384
1385 /**
1386  * gtk_text_buffer_set_mark:
1387  * @buffer:       a #GtkTextBuffer
1388  * @mark_name:    name of the mark
1389  * @iter:         location for the mark.
1390  * @left_gravity: if the mark is created by this function, gravity for the new
1391  *                mark.
1392  * @should_exist: if %TRUE, warn if the mark does not exist, and return
1393  *                immediately.
1394  *
1395  * Move the mark to the given position, if not @should_exist, create the mark.
1396  *
1397  * Return value: mark
1398  **/
1399 static GtkTextMark*
1400 gtk_text_buffer_set_mark (GtkTextBuffer *buffer,
1401                           GtkTextMark *existing_mark,
1402                           const gchar *mark_name,
1403                           const GtkTextIter *iter,
1404                           gboolean left_gravity,
1405                           gboolean should_exist)
1406 {
1407   GtkTextIter location;
1408   GtkTextMark *mark;
1409
1410   mark = gtk_text_btree_set_mark (get_btree (buffer),
1411                                   existing_mark,
1412                                   mark_name,
1413                                   left_gravity,
1414                                   iter,
1415                                   should_exist);
1416
1417   if (gtk_text_btree_mark_is_insert (get_btree (buffer), mark) ||
1418       gtk_text_btree_mark_is_selection_bound (get_btree (buffer), mark))
1419     {
1420       gtk_text_buffer_update_primary_selection (buffer);
1421     }
1422
1423   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1424                                    &location,
1425                                    mark);
1426
1427   gtk_text_buffer_mark_set (buffer, &location, mark);
1428
1429   return mark;
1430 }
1431
1432 /**
1433  * gtk_text_buffer_create_mark:
1434  * @buffer: a #GtkTextBuffer
1435  * @mark_name: name for mark, or %NULL
1436  * @where: location to place mark
1437  * @left_gravity: whether the mark has left gravity
1438  *
1439  * Creates a mark at position @where. If @mark_name is %NULL, the mark
1440  * is anonymous; otherwise, the mark can be retrieved by name using
1441  * gtk_text_buffer_get_mark (). If a mark has left gravity, and text is
1442  * inserted at the mark's current location, the mark will be moved to
1443  * the left of the newly-inserted text. If the mark has right gravity
1444  * (@left_gravity = %FALSE), the mark will end up on the right of
1445  * newly-inserted text. The standard left-to-right cursor is a mark
1446  * with right gravity (when you type, the cursor stays on the right
1447  * side of the text you're typing).
1448  *
1449  * The caller of this function does <emphasis>not</emphasis> own a reference
1450  * to the returned #GtkTextMark, so you can ignore the return value
1451  * if you like. Marks are owned by the buffer and go away when the
1452  * buffer does.
1453  *
1454  * Emits the "mark_set" signal as notification of the mark's initial
1455  * placement.
1456  *
1457  * Return value: the new #GtkTextMark object
1458  **/
1459 GtkTextMark*
1460 gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
1461                              const gchar *mark_name,
1462                              const GtkTextIter *where,
1463                              gboolean left_gravity)
1464 {
1465   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1466
1467   return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
1468                                    left_gravity, FALSE);
1469 }
1470
1471 /**
1472  * gtk_text_buffer_move_mark:
1473  * @buffer: a #GtkTextBuffer
1474  * @mark: a #GtkTextMark
1475  * @where: new location for @mark in @buffer
1476  *
1477  * Moves @mark to the new location @where. Emits the "mark_set" signal
1478  * as notification of the move.
1479  **/
1480 void
1481 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
1482                            GtkTextMark *mark,
1483                            const GtkTextIter *where)
1484 {
1485   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1486   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1487   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1488
1489   gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
1490 }
1491
1492 /**
1493  * gtk_text_buffer_get_iter_at_mark:
1494  * @buffer: a #GtkTextBuffer
1495  * @iter: iterator to initialize
1496  * @mark: a #GtkTextMark in @buffer
1497  *
1498  * Initializes @iter with the current position of @mark.
1499  **/
1500 void
1501 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
1502                                   GtkTextIter *iter,
1503                                   GtkTextMark *mark)
1504 {
1505   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1506   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1507   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1508
1509   gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1510                                    iter,
1511                                    mark);
1512 }
1513
1514 /**
1515  * gtk_text_buffer_delete_mark:
1516  * @buffer: a #GtkTextBuffer
1517  * @mark: a #GtkTextMark in @buffer
1518  *
1519  * Deletes @mark, so that it's no longer located anywhere in the
1520  * buffer. Removes the reference the buffer holds to the mark, so if
1521  * you haven't called g_object_ref () on the mark, it will be freed. Even
1522  * if the mark isn't freed, most operations on @mark become
1523  * invalid. There is no way to undelete a
1524  * mark. gtk_text_mark_get_deleted () will return TRUE after this
1525  * function has been called on a mark; gtk_text_mark_get_deleted ()
1526  * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
1527  * signal will be emitted as notification after the mark is deleted.
1528  **/
1529 void
1530 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
1531                              GtkTextMark   *mark)
1532 {
1533   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1534   g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1535   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1536
1537   g_object_ref (G_OBJECT (mark));
1538
1539   gtk_text_btree_remove_mark (get_btree (buffer), mark);
1540
1541   /* See rationale above for MARK_SET on why we emit this after
1542    * removing the mark, rather than removing the mark in a default
1543    * handler.
1544    */
1545   gtk_signal_emit (GTK_OBJECT (buffer), signals[MARK_DELETED],
1546                    mark);
1547
1548   g_object_unref (G_OBJECT (mark));
1549 }
1550
1551 /**
1552  * gtk_text_buffer_get_mark:
1553  * @buffer: a #GtkTextBuffer
1554  * @name: a mark name
1555  *
1556  * Returns the mark named @name in buffer @buffer, or NULL if no such
1557  * mark exists in the buffer.
1558  *
1559  * Return value: a #GtkTextMark, or NULL
1560  **/
1561 GtkTextMark*
1562 gtk_text_buffer_get_mark (GtkTextBuffer      *buffer,
1563                           const gchar         *name)
1564 {
1565   GtkTextMark *mark;
1566
1567   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1568   g_return_val_if_fail (name != NULL, NULL);
1569
1570   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1571
1572   return mark;
1573 }
1574
1575
1576 /**
1577  * gtk_text_buffer_move_mark_by_name:
1578  * @buffer: a #GtkTextBuffer
1579  * @name: name of a mark
1580  * @where: new location for mark
1581  *
1582  * Moves the mark named @name (which must exist) to location @where.
1583  * See gtk_text_buffer_move_mark () for details.
1584  **/
1585 void
1586 gtk_text_buffer_move_mark_by_name (GtkTextBuffer     *buffer,
1587                                    const gchar       *name,
1588                                    const GtkTextIter *where)
1589 {
1590   GtkTextMark *mark;
1591
1592   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1593   g_return_if_fail (name != NULL);
1594
1595   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1596
1597   if (mark == NULL)
1598     {
1599       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1600       return;
1601     }
1602
1603   gtk_text_buffer_move_mark (buffer, mark, where);
1604 }
1605
1606 /**
1607  * gtk_text_buffer_delete_mark_by_name:
1608  * @buffer: a #GtkTextBuffer
1609  * @name: name of a mark in @buffer
1610  *
1611  * Deletes the mark named @name; the mark must exist. See
1612  * gtk_text_buffer_delete_mark () for details.
1613  **/
1614 void
1615 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer     *buffer,
1616                                      const gchar       *name)
1617 {
1618   GtkTextMark *mark;
1619
1620   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1621   g_return_if_fail (name != NULL);
1622
1623   mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1624
1625   if (mark == NULL)
1626     {
1627       g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1628       return;
1629     }
1630
1631   gtk_text_buffer_delete_mark (buffer, mark);
1632 }
1633
1634 /**
1635  * gtk_text_buffer_get_insert:
1636  * @buffer: a #GtkTextBuffer
1637  *
1638  * Returns the mark that represents the cursor (insertion point).
1639  * Equivalent to calling gtk_text_buffer_get_mark () to get the mark
1640  * name "insert," but very slightly more efficient, and involves less
1641  * typing.
1642  *
1643  * Return value: insertion point mark
1644  **/
1645 GtkTextMark*
1646 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
1647 {
1648   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1649
1650   /* FIXME use struct member in btree */
1651   return gtk_text_buffer_get_mark (buffer, "insert");
1652 }
1653
1654 /**
1655  * gtk_text_buffer_get_selection_bound:
1656  * @buffer: a #GtkTextBuffer
1657  *
1658  * Returns the mark that represents the selection bound.  Equivalent
1659  * to calling gtk_text_buffer_get_mark () to get the mark name
1660  * "selection_bound," but very slightly more efficient, and involves
1661  * less typing.
1662  *
1663  * The currently-selected text in @buffer is the region between the
1664  * "selection_bound" and "insert" marks. If "selection_bound" and
1665  * "insert" are in the same place, then there is no current selection.
1666  * gtk_text_buffer_get_selection_bounds () is another convenient function
1667  * for handling the selection, if you just want to know whether there's a
1668  * selection and what its bounds are.
1669  *
1670  * Return value: selection bound mark
1671  **/
1672 GtkTextMark*
1673 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
1674 {
1675   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1676
1677   /* FIXME use struct member in btree */
1678   return gtk_text_buffer_get_mark (buffer, "selection_bound");
1679 }
1680
1681 void
1682 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer      *buffer,
1683                                           GtkTextIter        *iter,
1684                                           GtkTextChildAnchor *anchor)
1685 {
1686   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1687   g_return_if_fail (iter != NULL);
1688   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
1689   g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
1690   
1691   gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
1692                                            iter,
1693                                            anchor);
1694 }
1695
1696 /**
1697  * gtk_text_buffer_place_cursor:
1698  * @buffer: a #GtkTextBuffer
1699  * @where: where to put the cursor
1700  *
1701  * This function moves the "insert" and "selection_bound" marks
1702  * simultaneously.  If you move them to the same place in two steps
1703  * with gtk_text_buffer_move_mark (), you will temporarily select a
1704  * region in between their old and new locations, which can be pretty
1705  * inefficient since the temporarily-selected region will force stuff
1706  * to be recalculated. This function moves them as a unit, which can
1707  * be optimized.
1708  **/
1709 void
1710 gtk_text_buffer_place_cursor (GtkTextBuffer     *buffer,
1711                               const GtkTextIter *where)
1712 {
1713   GtkTextIter real;
1714
1715   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1716
1717   real = *where;
1718
1719   if (gtk_text_iter_is_last (&real))
1720     gtk_text_iter_prev_char (&real);
1721
1722   gtk_text_btree_place_cursor (get_btree (buffer), &real);
1723   gtk_text_buffer_mark_set (buffer, &real,
1724                             gtk_text_buffer_get_mark (buffer,
1725                                                       "insert"));
1726   gtk_text_buffer_mark_set (buffer, &real,
1727                             gtk_text_buffer_get_mark (buffer,
1728                                                       "selection_bound"));
1729 }
1730
1731 /*
1732  * Tags
1733  */
1734
1735 /**
1736  * gtk_text_buffer_create_tag:
1737  * @buffer: a #GtkTextBuffer
1738  * @tag_name: name of the new tag, or %NULL
1739  *
1740  * Creates a tag and adds it to the tag table for @buffer.
1741  * Equivalent to calling gtk_text_tag_new () and then adding the
1742  * tag to the buffer's tag table. The returned tag has its refcount
1743  * incremented, as if you'd called gtk_text_tag_new ().
1744  *
1745  * If @tag_name is %NULL, the tag is anonymous.
1746  *
1747  * Return value: a new tag
1748  **/
1749 GtkTextTag*
1750 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
1751                             const gchar *tag_name)
1752 {
1753   GtkTextTag *tag;
1754
1755   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1756
1757   tag = gtk_text_tag_new (tag_name);
1758
1759   gtk_text_tag_table_add (get_table (buffer), tag);
1760
1761   return tag;
1762 }
1763
1764 static void
1765 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1766                                 GtkTextTag *tag,
1767                                 const GtkTextIter *start,
1768                                 const GtkTextIter *end)
1769 {
1770   gtk_text_btree_tag (start, end, tag, TRUE);
1771 }
1772
1773 static void
1774 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1775                                  GtkTextTag *tag,
1776                                  const GtkTextIter *start,
1777                                  const GtkTextIter *end)
1778 {
1779   gtk_text_btree_tag (start, end, tag, FALSE);
1780 }
1781
1782 static void
1783 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
1784 {
1785   gtk_text_buffer_set_modified (buffer, TRUE);
1786 }
1787
1788 static void
1789 gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,
1790                           GtkTextTag *tag,
1791                           gboolean apply,
1792                           const GtkTextIter *start,
1793                           const GtkTextIter *end)
1794 {
1795   GtkTextIter start_tmp = *start;
1796   GtkTextIter end_tmp = *end;
1797
1798   g_return_if_fail (tag != NULL);
1799
1800   gtk_text_iter_reorder (&start_tmp, &end_tmp);
1801
1802   if (apply)
1803     gtk_signal_emit (GTK_OBJECT (buffer), signals[APPLY_TAG],
1804                      tag, &start_tmp, &end_tmp);
1805   else
1806     gtk_signal_emit (GTK_OBJECT (buffer), signals[REMOVE_TAG],
1807                      tag, &start_tmp, &end_tmp);
1808 }
1809
1810
1811 void
1812 gtk_text_buffer_apply_tag (GtkTextBuffer *buffer,
1813                            GtkTextTag    *tag,
1814                            const GtkTextIter *start,
1815                            const GtkTextIter *end)
1816 {
1817   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1818   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1819   g_return_if_fail (start != NULL);
1820   g_return_if_fail (end != NULL);
1821
1822   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1823 }
1824
1825 void
1826 gtk_text_buffer_remove_tag (GtkTextBuffer *buffer,
1827                             GtkTextTag    *tag,
1828                             const GtkTextIter *start,
1829                             const GtkTextIter *end)
1830
1831 {
1832   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1833   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1834   g_return_if_fail (start != NULL);
1835   g_return_if_fail (end != NULL);
1836
1837   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1838 }
1839
1840
1841 void
1842 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1843                                    const gchar *name,
1844                                    const GtkTextIter *start,
1845                                    const GtkTextIter *end)
1846 {
1847   GtkTextTag *tag;
1848
1849   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1850   g_return_if_fail (name != NULL);
1851   g_return_if_fail (start != NULL);
1852   g_return_if_fail (end != NULL);
1853
1854   tag = gtk_text_tag_table_lookup (get_table (buffer),
1855                                    name);
1856
1857   if (tag == NULL)
1858     {
1859       g_warning ("Unknown tag `%s'", name);
1860       return;
1861     }
1862
1863   gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1864 }
1865
1866 void
1867 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1868                                     const gchar *name,
1869                                     const GtkTextIter *start,
1870                                     const GtkTextIter *end)
1871 {
1872   GtkTextTag *tag;
1873
1874   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1875   g_return_if_fail (name != NULL);
1876   g_return_if_fail (start != NULL);
1877   g_return_if_fail (end != NULL);
1878
1879   tag = gtk_text_tag_table_lookup (get_table (buffer),
1880                                    name);
1881
1882   if (tag == NULL)
1883     {
1884       g_warning ("Unknown tag `%s'", name);
1885       return;
1886     }
1887
1888   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1889 }
1890
1891
1892 /*
1893  * Obtain various iterators
1894  */
1895
1896 void
1897 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer      *buffer,
1898                                          GtkTextIter        *iter,
1899                                          gint                line_number,
1900                                          gint                char_offset)
1901 {
1902   g_return_if_fail (iter != NULL);
1903   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1904
1905   gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
1906                                         iter, line_number, char_offset);
1907 }
1908
1909 void
1910 gtk_text_buffer_get_iter_at_line_index  (GtkTextBuffer *buffer,
1911                                          GtkTextIter   *iter,
1912                                          gint           line_number,
1913                                          gint           byte_index)
1914 {
1915   g_return_if_fail (iter != NULL);
1916   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1917
1918   gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
1919                                         iter, line_number, byte_index);
1920 }
1921
1922 void
1923 gtk_text_buffer_get_iter_at_line    (GtkTextBuffer      *buffer,
1924                                      GtkTextIter        *iter,
1925                                      gint                line_number)
1926 {
1927   g_return_if_fail (iter != NULL);
1928   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1929
1930   gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1931 }
1932
1933 void
1934 gtk_text_buffer_get_iter_at_offset         (GtkTextBuffer      *buffer,
1935                                             GtkTextIter        *iter,
1936                                             gint                char_offset)
1937 {
1938   g_return_if_fail (iter != NULL);
1939   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1940
1941   gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
1942 }
1943
1944 void
1945 gtk_text_buffer_get_last_iter         (GtkTextBuffer      *buffer,
1946                                        GtkTextIter        *iter)
1947 {
1948   g_return_if_fail (iter != NULL);
1949   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1950
1951   gtk_text_btree_get_last_iter (get_btree (buffer), iter);
1952 }
1953
1954 void
1955 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1956                             GtkTextIter   *start,
1957                             GtkTextIter   *end)
1958 {
1959   g_return_if_fail (start != NULL);
1960   g_return_if_fail (end != NULL);
1961   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1962
1963   gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
1964   gtk_text_btree_get_last_iter (get_btree (buffer), end);
1965 }
1966
1967 /*
1968  * Modified flag
1969  */
1970
1971 gboolean
1972 gtk_text_buffer_modified (GtkTextBuffer      *buffer)
1973 {
1974   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1975
1976   return buffer->modified;
1977 }
1978
1979 void
1980 gtk_text_buffer_set_modified (GtkTextBuffer      *buffer,
1981                               gboolean             setting)
1982 {
1983   gboolean fixed_setting;
1984
1985   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1986
1987   fixed_setting = setting != FALSE;
1988
1989   if (buffer->modified == fixed_setting)
1990     return;
1991   else
1992     {
1993       buffer->modified = fixed_setting;
1994       gtk_signal_emit (GTK_OBJECT (buffer), signals[MODIFIED_CHANGED]);
1995     }
1996 }
1997
1998
1999 /*
2000  * Assorted other stuff
2001  */
2002
2003 gint
2004 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
2005 {
2006   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2007
2008   return gtk_text_btree_line_count (get_btree (buffer));
2009 }
2010
2011 gint
2012 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
2013 {
2014   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2015
2016   return gtk_text_btree_char_count (get_btree (buffer));
2017 }
2018
2019 /* Called when we lose the primary selection.
2020  */
2021 static void
2022 clipboard_clear_selection_cb (GtkClipboard *clipboard,
2023                               gpointer      data)
2024 {
2025   /* Move selection_bound to the insertion point */
2026   GtkTextIter insert;
2027   GtkTextIter selection_bound;
2028   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2029
2030   gtk_text_buffer_get_iter_at_mark (buffer, &insert,
2031                                     gtk_text_buffer_get_mark (buffer, "insert"));
2032   gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
2033                                     gtk_text_buffer_get_mark (buffer, "selection_bound"));
2034
2035   if (!gtk_text_iter_equal (&insert, &selection_bound))
2036     gtk_text_buffer_move_mark (buffer,
2037                                gtk_text_buffer_get_mark (buffer, "selection_bound"),
2038                                &insert);
2039 }
2040
2041 /* Called when we have the primary selection and someone else wants our
2042  * data in order to paste it.
2043  */
2044 static void
2045 clipboard_get_selection_cb (GtkClipboard     *clipboard,
2046                             GtkSelectionData *selection_data,
2047                             guint             info,
2048                             gpointer          data)
2049 {
2050   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2051   GtkTextIter start, end;
2052
2053   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2054     {
2055       if (selection_data->target ==
2056           gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2057         {
2058           /* Provide the address of the buffer; this will only be
2059            * used within-process
2060            */
2061           gtk_selection_data_set (selection_data,
2062                                   gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2063                                   8, /* bytes */
2064                                   (void*)&buffer,
2065                                   sizeof (buffer));
2066         }
2067       else
2068         {
2069           gchar *str;
2070           
2071           str = gtk_text_iter_get_visible_text (&start, &end);
2072           gtk_selection_data_set_text (selection_data, str);
2073           g_free (str);
2074         }
2075     }
2076 }
2077
2078 /* Provide cut/copied data */
2079 static void
2080 clipboard_get_contents_cb (GtkClipboard     *clipboard,
2081                            GtkSelectionData *selection_data,
2082                            guint             info,
2083                            gpointer          data)
2084 {
2085   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2086   GtkTextBuffer *contents = buffer->clipboard_contents;
2087
2088   if (selection_data->target ==
2089       gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2090     {
2091       /* Provide the address of the clipboard buffer; this will only
2092        * be used within-process. OK to supply a NULL value for contents.
2093        */
2094       gtk_selection_data_set (selection_data,
2095                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2096                               8, /* bytes */
2097                               (void*)&contents,
2098                               sizeof (contents));
2099     }
2100   else
2101     {
2102       /* Just provide text from the clipboard buffer */
2103       if (buffer->clipboard_contents)
2104         {
2105           gchar *str;
2106           GtkTextIter start, end;
2107           
2108           gtk_text_buffer_get_bounds (contents, &start, &end);
2109           /* strip off the trailing newline, it isn't part of the text that was cut */
2110           gtk_text_iter_prev_char (&end);
2111           
2112           str = gtk_text_iter_get_visible_text (&start, &end);
2113           gtk_selection_data_set_text (selection_data, str);
2114           g_free (str);
2115         }
2116       else
2117         {
2118           gtk_selection_data_set_text (selection_data, "");
2119           return;
2120         }
2121     }
2122 }
2123
2124 static void
2125 clipboard_clear_contents_cb (GtkClipboard *clipboard,
2126                              gpointer      data)
2127 {
2128   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2129
2130   if (buffer->clipboard_contents)
2131     {
2132       g_object_unref (G_OBJECT (buffer->clipboard_contents));
2133       buffer->clipboard_contents = NULL;
2134     }  
2135 }
2136
2137 static void
2138 get_paste_point (GtkTextBuffer *buffer,
2139                  GtkTextIter   *iter,
2140                  gboolean       clear_afterward)
2141 {
2142   GtkTextIter insert_point;
2143   GtkTextMark *paste_point_override;
2144
2145   paste_point_override = gtk_text_buffer_get_mark (buffer,
2146                                                    "gtk_paste_point_override");
2147
2148   if (paste_point_override != NULL)
2149     {
2150       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2151                                         paste_point_override);
2152       if (clear_afterward)
2153         gtk_text_buffer_delete_mark (buffer,
2154                                      gtk_text_buffer_get_mark (buffer,
2155                                                                "gtk_paste_point_override"));
2156     }
2157   else
2158     {
2159       gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2160                                         gtk_text_buffer_get_mark (buffer,
2161                                                                   "insert"));
2162     }
2163
2164   *iter = insert_point;
2165 }
2166
2167 static void
2168 pre_paste_prep (ClipboardRequest *request_data,
2169                 GtkTextIter      *insert_point)
2170 {
2171   GtkTextBuffer *buffer = request_data->buffer;
2172
2173   if (request_data->replace_selection)
2174     {
2175       GtkTextIter start, end;
2176       
2177       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2178         {
2179           if (request_data->interactive)
2180             gtk_text_buffer_delete_interactive (buffer,
2181                                                 &start,
2182                                                 &end,
2183                                                 request_data->default_editable);
2184           else
2185             gtk_text_buffer_delete (buffer, &start, &end);
2186         }
2187     }
2188       
2189   get_paste_point (buffer, insert_point, TRUE);
2190 }
2191
2192 /* Called when we request a paste and receive the text data
2193  */
2194 static void
2195 clipboard_text_received (GtkClipboard *clipboard,
2196                          const gchar  *str,
2197                          gpointer      data)
2198 {
2199   ClipboardRequest *request_data = data;
2200   GtkTextBuffer *buffer = request_data->buffer;
2201
2202   if (str)
2203     {
2204       GtkTextIter insert_point;
2205
2206       pre_paste_prep (request_data, &insert_point);
2207       
2208       if (request_data->interactive)
2209         gtk_text_buffer_insert_interactive (buffer, &insert_point,
2210                                             str, -1, request_data->default_editable);
2211       else
2212         gtk_text_buffer_insert (buffer, &insert_point,
2213                                 str, -1);
2214     }
2215
2216   g_object_unref (G_OBJECT (buffer));
2217   g_free (request_data);
2218 }
2219
2220 static GtkTextBuffer*
2221 selection_data_get_buffer (GtkSelectionData *selection_data,
2222                            ClipboardRequest *request_data)
2223 {
2224   GdkWindow *owner;
2225   GtkTextBuffer *src_buffer = NULL;
2226
2227   /* If we can get the owner, the selection is in-process */
2228   owner = gdk_selection_owner_get (selection_data->selection);
2229
2230   if (owner == NULL)
2231     return NULL;
2232   
2233   if (selection_data->type != gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2234     return NULL;
2235
2236   if (selection_data->length != sizeof (src_buffer))
2237     return NULL;
2238           
2239   memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
2240
2241   if (src_buffer == NULL)
2242     return NULL;
2243   
2244   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
2245
2246   if (gtk_text_buffer_get_tag_table (src_buffer) !=
2247       gtk_text_buffer_get_tag_table (request_data->buffer))
2248     return NULL;
2249   
2250   return src_buffer;
2251 }
2252
2253 static void
2254 paste_from_buffer (ClipboardRequest    *request_data,
2255                    GtkTextBuffer       *src_buffer,
2256                    const GtkTextIter   *start,
2257                    const GtkTextIter   *end)
2258 {
2259   GtkTextIter insert_point;
2260   
2261   /* We're about to emit a bunch of signals, so be safe */
2262   g_object_ref (G_OBJECT (src_buffer));
2263   
2264   pre_paste_prep (request_data, &insert_point);
2265   
2266   if (!gtk_text_iter_equal (start, end))
2267     {
2268       gtk_text_buffer_real_insert_range (request_data->buffer,
2269                                          &insert_point,
2270                                          start,
2271                                          end,
2272                                          request_data->interactive);
2273     }
2274       
2275   g_object_unref (G_OBJECT (src_buffer));
2276 }
2277
2278 static void
2279 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
2280                                      GtkSelectionData *selection_data,
2281                                      gpointer          data)
2282 {
2283   ClipboardRequest *request_data = data;
2284   GtkTextBuffer *src_buffer;
2285   
2286   src_buffer = selection_data_get_buffer (selection_data, request_data); 
2287
2288   if (src_buffer)
2289     {
2290       GtkTextIter start, end;
2291
2292       gtk_text_buffer_get_bounds (src_buffer, &start, &end);
2293       /* There's an extra newline on clipboard_contents */
2294       gtk_text_iter_prev_char (&end);
2295       
2296       paste_from_buffer (request_data, src_buffer,
2297                          &start, &end);
2298     }
2299   else
2300     {
2301       /* Request the text selection instead */
2302       gtk_clipboard_request_text (clipboard,
2303                                   clipboard_text_received,
2304                                   data);
2305     }
2306 }
2307
2308 static void
2309 clipboard_selection_buffer_received (GtkClipboard     *clipboard,
2310                                      GtkSelectionData *selection_data,
2311                                      gpointer          data)
2312 {
2313   ClipboardRequest *request_data = data;
2314   GtkTextBuffer *src_buffer;
2315   
2316   src_buffer = selection_data_get_buffer (selection_data, request_data); 
2317
2318   if (src_buffer)
2319     {
2320       GtkTextIter start, end;
2321
2322       if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
2323         paste_from_buffer (request_data, src_buffer,
2324                            &start, &end);
2325     }
2326   else
2327     {
2328       /* Request the text selection instead */
2329       gtk_clipboard_request_text (clipboard,
2330                                   clipboard_text_received,
2331                                   data);
2332     }
2333 }
2334
2335 static const GtkTargetEntry targets[] = {
2336   { "STRING", 0, TARGET_STRING },
2337   { "TEXT",   0, TARGET_TEXT },
2338   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
2339   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
2340   { "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
2341 };
2342
2343 static void
2344 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
2345 {
2346   GtkTextIter start;
2347   GtkTextIter end;
2348
2349   GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
2350
2351   /* Determine whether we have a selection and adjust X selection
2352    * accordingly.
2353    */
2354
2355   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2356     {
2357       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
2358         gtk_clipboard_clear (clipboard);
2359     }
2360   else
2361     {
2362       /* Even if we already have the selection, we need to update our
2363        * timestamp.
2364        */
2365       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2366                                          clipboard_get_selection_cb,
2367                                          clipboard_clear_selection_cb,
2368                                          G_OBJECT (buffer)))
2369         clipboard_clear_selection_cb (clipboard, buffer);
2370     }
2371 }
2372
2373 static void
2374 paste (GtkTextBuffer *buffer,
2375        gboolean       is_clipboard,
2376        gboolean       interactive,
2377        gboolean       default_editable)
2378 {
2379   ClipboardRequest *data = g_new (ClipboardRequest, 1);
2380   GtkTextIter paste_point;
2381   GtkTextIter start, end;
2382   
2383   data->buffer = buffer;
2384   g_object_ref (G_OBJECT (buffer));
2385   data->interactive = interactive;
2386   data->default_editable = default_editable;
2387
2388   /* When pasting with the cursor inside the selection area, you
2389    * replace the selection with the new text, otherwise, you
2390    * simply insert the new text at the point where the click
2391    * occured, unselecting any selected text. The replace_selection
2392    * flag toggles this behavior. FIXME set the flag based on something.
2393    */
2394   data->replace_selection = FALSE;
2395   
2396   get_paste_point (buffer, &paste_point, FALSE);
2397   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
2398       gtk_text_iter_in_range (&paste_point, &start, &end))
2399     data->replace_selection = TRUE;
2400
2401   if (is_clipboard)
2402     gtk_clipboard_request_contents (gtk_clipboard_get (GDK_NONE),
2403                                     
2404                                     gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2405                                     clipboard_clipboard_buffer_received, data);
2406   else
2407     gtk_clipboard_request_contents (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
2408                                     
2409                                     gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2410                                     clipboard_selection_buffer_received, data);    
2411 }
2412
2413 void
2414 gtk_text_buffer_paste_primary (GtkTextBuffer       *buffer,
2415                                const GtkTextIter   *override_location,
2416                                gboolean             default_editable)
2417 {
2418   if (override_location != NULL)
2419     gtk_text_buffer_create_mark (buffer,
2420                                  "gtk_paste_point_override",
2421                                  override_location, FALSE);
2422
2423   paste (buffer, FALSE, TRUE, default_editable);
2424 }
2425
2426 void
2427 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
2428                                  gboolean       default_editable)
2429 {
2430   paste (buffer, TRUE, TRUE, default_editable);
2431 }
2432
2433 gboolean
2434 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
2435                                   gboolean interactive,
2436                                   gboolean default_editable)
2437 {
2438   GtkTextIter start;
2439   GtkTextIter end;
2440
2441   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2442     {
2443       return FALSE; /* No selection */
2444     }
2445   else
2446     {
2447       if (interactive)
2448         gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
2449       else
2450         gtk_text_buffer_delete (buffer, &start, &end);
2451
2452       return TRUE; /* We deleted stuff */
2453     }
2454 }
2455
2456 static void
2457 cut_or_copy (GtkTextBuffer *buffer,
2458              gboolean delete_region_after,
2459              gboolean interactive,
2460              gboolean default_editable)
2461 {
2462   /* We prefer to cut the selected region between selection_bound and
2463    * insertion point. If that region is empty, then we cut the region
2464    * between the "anchor" and the insertion point (this is for
2465    * C-space and M-w and other Emacs-style copy/yank keys). Note that
2466    * insert and selection_bound are guaranteed to exist, but the
2467    * anchor only exists sometimes.
2468    */
2469   GtkTextIter start;
2470   GtkTextIter end;
2471
2472   if (buffer->clipboard_contents)
2473     {
2474       g_object_unref (G_OBJECT (buffer->clipboard_contents));
2475       buffer->clipboard_contents = NULL;
2476     }
2477   
2478   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2479     {
2480       /* Let's try the anchor thing */
2481       GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
2482
2483       if (anchor == NULL)
2484         return;
2485       else
2486         {
2487           gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
2488           gtk_text_iter_reorder (&start, &end);
2489         }
2490     }
2491
2492   if (!gtk_text_iter_equal (&start, &end))
2493     {
2494       GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
2495       GtkTextIter ins;
2496       
2497       buffer->clipboard_contents =
2498         gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
2499
2500       gtk_text_buffer_get_iter_at_offset (buffer->clipboard_contents,
2501                                           &ins, 0);
2502       
2503       gtk_text_buffer_insert_range (buffer->clipboard_contents,
2504                                     &ins,
2505                                     &start,
2506                                     &end);
2507                                     
2508       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2509                                          clipboard_get_contents_cb,
2510                                          clipboard_clear_contents_cb,
2511                                          G_OBJECT (buffer)))
2512         clipboard_clear_contents_cb (clipboard, buffer);      
2513
2514       if (delete_region_after)
2515         {
2516           if (interactive)
2517             gtk_text_buffer_delete_interactive (buffer, &start, &end,
2518                                                 default_editable);
2519           else
2520             gtk_text_buffer_delete (buffer, &start, &end);
2521         }
2522     }
2523 }
2524
2525 void
2526 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
2527                                gboolean       default_editable)
2528 {
2529   cut_or_copy (buffer, TRUE, TRUE, default_editable);
2530 }
2531
2532 void
2533 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
2534 {
2535   cut_or_copy (buffer, FALSE, TRUE, TRUE);
2536 }
2537
2538
2539 /**
2540  * gtk_text_buffer_get_selection_bounds:
2541  * @buffer: a #GtkTextBuffer
2542  * @start: iterator to initialize with selection start
2543  * @end: iterator to initialize with selection end
2544  *
2545  * Returns %TRUE if some text is selected; places the bounds
2546  * of the selection in @start and @end (if the selection has length 0,
2547  * then @start and @end are filled in with the same value).
2548  * @start and @end will be in ascending order. If @start and @end are
2549  * NULL, then they are not filled in, but the return value still indicates
2550  * whether text is selected.
2551  *
2552  * Return value: whether the selection has nonzero length
2553  **/
2554 gboolean
2555 gtk_text_buffer_get_selection_bounds   (GtkTextBuffer      *buffer,
2556                                         GtkTextIter        *start,
2557                                         GtkTextIter        *end)
2558 {
2559   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2560
2561   return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
2562 }
2563
2564
2565 /*
2566  * Debug spew
2567  */
2568
2569 void
2570 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
2571 {
2572   gtk_text_btree_spew (get_btree (buffer));
2573 }
2574
2575
2576
2577
2578