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