]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
move README.linux-fb in here
[~andy/gtk] / gtk / gtktextview.c
1 /* GTK - The GIMP Toolkit
2  * gtktextview.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 #include <string.h>
28
29 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
30 #include "gtkbindings.h"
31 #include "gtkdnd.h"
32 #include "gtkimagemenuitem.h"
33 #include "gtkintl.h"
34 #include "gtkmain.h"
35 #include "gtkmarshalers.h"
36 #include "gtkmenu.h"
37 #include "gtkmenuitem.h"
38 #include "gtkseparatormenuitem.h"
39 #include "gtksettings.h"
40 #include "gtksignal.h"
41 #include "gtkstock.h"
42 #include "gtktextdisplay.h"
43 #include "gtktextview.h"
44 #include "gtkimmulticontext.h"
45 #include "gdk/gdkkeysyms.h"
46 #include "gtktextutil.h"
47 #include <string.h>
48
49 /* How scrolling, validation, exposes, etc. work.
50  *
51  * The expose_event handler has the invariant that the onscreen lines
52  * have been validated.
53  *
54  * There are two ways that onscreen lines can become invalid. The first
55  * is to change which lines are onscreen. This happens when the value
56  * of a scroll adjustment changes. So the code path begins in
57  * gtk_text_view_value_changed() and goes like this:
58  *   - gdk_window_scroll() to reflect the new adjustment value
59  *   - validate the lines that were moved onscreen
60  *   - gdk_window_process_updates() to handle the exposes immediately
61  *
62  * The second way is that you get the "invalidated" signal from the layout,
63  * indicating that lines have become invalid. This code path begins in
64  * invalidated_handler() and goes like this:
65  *   - install high-priority idle which does the rest of the steps
66  *   - if a scroll is pending from scroll_to_mark(), do the scroll,
67  *     jumping to the gtk_text_view_value_changed() code path
68  *   - otherwise, validate the onscreen lines
69  *   - DO NOT process updates
70  *
71  * In both cases, validating the onscreen lines can trigger a scroll
72  * due to maintaining the first_para on the top of the screen.
73  * If validation triggers a scroll, we jump to the top of the code path
74  * for value_changed, and bail out of the current code path.
75  *
76  * Also, in size_allocate, if we invalidate some lines from changing
77  * the layout width, we need to go ahead and run the high-priority idle,
78  * because GTK sends exposes right after doing the size allocates without
79  * returning to the main loop. This is also why the high-priority idle
80  * is at a higher priority than resizing.
81  *
82  */
83
84 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
85 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
86
87 #if 0
88 #define DEBUG_VALIDATION_AND_SCROLLING
89 #endif
90
91 #ifdef DEBUG_VALIDATION_AND_SCROLLING
92 #define DV(x) (x)
93 #else
94 #define DV(x)
95 #endif
96
97 struct _GtkTextPendingScroll
98 {
99   GtkTextMark   *mark;
100   gdouble        within_margin;
101   gboolean       use_align;
102   gdouble        xalign;
103   gdouble        yalign;
104 };
105   
106 enum
107 {
108   SET_SCROLL_ADJUSTMENTS,
109   POPULATE_POPUP,
110   MOVE_CURSOR,
111   SET_ANCHOR,
112   INSERT_AT_CURSOR,
113   DELETE_FROM_CURSOR,
114   CUT_CLIPBOARD,
115   COPY_CLIPBOARD,
116   PASTE_CLIPBOARD,
117   TOGGLE_OVERWRITE,
118   LAST_SIGNAL
119 };
120
121 enum
122 {
123   PROP_0,
124   PROP_PIXELS_ABOVE_LINES,
125   PROP_PIXELS_BELOW_LINES,
126   PROP_PIXELS_INSIDE_WRAP,
127   PROP_EDITABLE,
128   PROP_WRAP_MODE,
129   PROP_JUSTIFICATION,
130   PROP_LEFT_MARGIN,
131   PROP_RIGHT_MARGIN,
132   PROP_INDENT,
133   PROP_TABS,
134   PROP_CURSOR_VISIBLE,
135   LAST_PROP
136 };
137
138 static void gtk_text_view_init                 (GtkTextView      *text_view);
139 static void gtk_text_view_class_init           (GtkTextViewClass *klass);
140 static void gtk_text_view_destroy              (GtkObject        *object);
141 static void gtk_text_view_finalize             (GObject          *object);
142 static void gtk_text_view_set_property         (GObject         *object,
143                                                 guint            prop_id,
144                                                 const GValue    *value,
145                                                 GParamSpec      *pspec);
146 static void gtk_text_view_get_property         (GObject         *object,
147                                                 guint            prop_id,
148                                                 GValue          *value,
149                                                 GParamSpec      *pspec);
150 static void gtk_text_view_size_request         (GtkWidget        *widget,
151                                                 GtkRequisition   *requisition);
152 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
153                                                 GtkAllocation    *allocation);
154 static void gtk_text_view_realize              (GtkWidget        *widget);
155 static void gtk_text_view_unrealize            (GtkWidget        *widget);
156 static void gtk_text_view_style_set            (GtkWidget        *widget,
157                                                 GtkStyle         *previous_style);
158 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
159                                                 GtkTextDirection  previous_direction);
160 static gint gtk_text_view_event                (GtkWidget        *widget,
161                                                 GdkEvent         *event);
162 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
163                                                 GdkEventKey      *event);
164 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
165                                                 GdkEventKey      *event);
166 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
167                                                 GdkEventButton   *event);
168 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
169                                                 GdkEventButton   *event);
170 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
171                                                 GdkEventFocus    *event);
172 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
173                                                 GdkEventFocus    *event);
174 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
175                                                 GdkEventMotion   *event);
176 static gint gtk_text_view_expose_event         (GtkWidget        *widget,
177                                                 GdkEventExpose   *expose);
178 static void gtk_text_view_draw_focus           (GtkWidget        *widget);
179 static void gtk_text_view_grab_focus           (GtkWidget        *widget);
180
181 /* Source side drag signals */
182 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
183                                             GdkDragContext   *context);
184 static void gtk_text_view_drag_end         (GtkWidget        *widget,
185                                             GdkDragContext   *context);
186 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
187                                             GdkDragContext   *context,
188                                             GtkSelectionData *selection_data,
189                                             guint             info,
190                                             guint             time);
191 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
192                                             GdkDragContext   *context);
193
194 /* Target side drag signals */
195 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
196                                                   GdkDragContext   *context,
197                                                   guint             time);
198 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
199                                                   GdkDragContext   *context,
200                                                   gint              x,
201                                                   gint              y,
202                                                   guint             time);
203 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
204                                                   GdkDragContext   *context,
205                                                   gint              x,
206                                                   gint              y,
207                                                   guint             time);
208 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
209                                                   GdkDragContext   *context,
210                                                   gint              x,
211                                                   gint              y,
212                                                   GtkSelectionData *selection_data,
213                                                   guint             info,
214                                                   guint             time);
215
216 static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
217                                                   GtkAdjustment *hadj,
218                                                   GtkAdjustment *vadj);
219 static void gtk_text_view_popup_menu             (GtkWidget     *widget);
220
221 static void gtk_text_view_move_cursor      (GtkTextView           *text_view,
222                                             GtkMovementStep        step,
223                                             gint                   count,
224                                             gboolean               extend_selection);
225 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
226 static void gtk_text_view_scroll_pages     (GtkTextView           *text_view,
227                                             gint                   count);
228 static void gtk_text_view_insert_at_cursor (GtkTextView           *text_view,
229                                             const gchar           *str);
230 static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
231                                               GtkDeleteType          type,
232                                               gint                   count);
233 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
234 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
235 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
236 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
237 static void gtk_text_view_unselect         (GtkTextView           *text_view);
238
239 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
240 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
241                                                      GtkTextIter        *iter);
242 static void     gtk_text_view_update_layout_width       (GtkTextView        *text_view);
243 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
244                                                          GtkTextAttributes *values,
245                                                          GtkStyle           *style);
246 static void     gtk_text_view_ensure_layout          (GtkTextView        *text_view);
247 static void     gtk_text_view_destroy_layout         (GtkTextView        *text_view);
248 static void     gtk_text_view_check_keymap_direction (GtkTextView        *text_view);
249 static void     gtk_text_view_reset_im_context       (GtkTextView        *text_view);
250 static void     gtk_text_view_start_selection_drag   (GtkTextView        *text_view,
251                                                       const GtkTextIter  *iter,
252                                                       GdkEventButton     *event);
253 static gboolean gtk_text_view_end_selection_drag     (GtkTextView        *text_view,
254                                                       GdkEventButton     *event);
255 static void     gtk_text_view_start_selection_dnd    (GtkTextView        *text_view,
256                                                       const GtkTextIter  *iter,
257                                                       GdkEventMotion     *event);
258 static void     gtk_text_view_check_cursor_blink     (GtkTextView        *text_view);
259 static void     gtk_text_view_pend_cursor_blink      (GtkTextView        *text_view);
260 static void     gtk_text_view_stop_cursor_blink      (GtkTextView        *text_view);
261
262 static void     gtk_text_view_value_changed                (GtkAdjustment *adj,
263                                                             GtkTextView   *view);
264 static void     gtk_text_view_commit_handler               (GtkIMContext  *context,
265                                                             const gchar   *str,
266                                                             GtkTextView   *text_view);
267 static void     gtk_text_view_commit_text                  (GtkTextView   *text_view,
268                                                             const gchar   *text);
269 static void     gtk_text_view_preedit_changed_handler      (GtkIMContext  *context,
270                                                             GtkTextView   *text_view);
271 static gboolean gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
272                                                             GtkTextView   *text_view);
273 static gboolean gtk_text_view_delete_surrounding_handler   (GtkIMContext  *context,
274                                                             gint           offset,
275                                                             gint           n_chars,
276                                                             GtkTextView   *text_view);
277
278 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
279                                                   const GtkTextIter *location,
280                                                   GtkTextMark       *mark,
281                                                   gpointer           data);
282 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
283                                                   gint              *x,
284                                                   gint              *y);
285 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
286                                                   gint               x,
287                                                   gint               y);
288
289 static GtkAdjustment* get_hadjustment            (GtkTextView       *text_view);
290 static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
291
292 static void gtk_text_view_do_popup               (GtkTextView       *text_view,
293                                                   GdkEventButton    *event);
294
295 static void gtk_text_view_queue_scroll           (GtkTextView   *text_view,
296                                                   GtkTextMark   *mark,
297                                                   gdouble        within_margin,
298                                                   gboolean       use_align,
299                                                   gdouble        xalign,
300                                                   gdouble        yalign);
301
302 static gboolean gtk_text_view_flush_scroll       (GtkTextView *text_view);
303 static void     gtk_text_view_update_adjustments (GtkTextView *text_view);
304 static void     gtk_text_view_invalidate         (GtkTextView *text_view);
305
306 static void gtk_text_view_update_im_spot_location (GtkTextView *text_view);
307
308 /* Container methods */
309 static void gtk_text_view_add    (GtkContainer *container,
310                                   GtkWidget    *child);
311 static void gtk_text_view_remove (GtkContainer *container,
312                                   GtkWidget    *child);
313 static void gtk_text_view_forall (GtkContainer *container,
314                                   gboolean      include_internals,
315                                   GtkCallback   callback,
316                                   gpointer      callback_data);
317
318 /* FIXME probably need the focus methods. */
319
320 typedef struct _GtkTextViewChild GtkTextViewChild;
321
322 struct _GtkTextViewChild
323 {
324   GtkWidget *widget;
325
326   GtkTextChildAnchor *anchor;
327
328   gint from_top_of_line;
329   gint from_left_of_buffer;
330   
331   /* These are ignored if anchor != NULL */
332   GtkTextWindowType type;
333   gint x;
334   gint y;
335 };
336
337 static GtkTextViewChild* text_view_child_new_anchored      (GtkWidget          *child,
338                                                             GtkTextChildAnchor *anchor,
339                                                             GtkTextLayout      *layout);
340 static GtkTextViewChild* text_view_child_new_window        (GtkWidget          *child,
341                                                             GtkTextWindowType   type,
342                                                             gint                x,
343                                                             gint                y);
344 static void              text_view_child_free              (GtkTextViewChild   *child);
345 static void              text_view_child_set_parent_window (GtkTextView        *text_view,
346                                                             GtkTextViewChild   *child);
347
348 struct _GtkTextWindow
349 {
350   GtkTextWindowType type;
351   GtkWidget *widget;
352   GdkWindow *window;
353   GdkWindow *bin_window;
354   GtkRequisition requisition;
355   GdkRectangle allocation;
356 };
357
358 static GtkTextWindow *text_window_new             (GtkTextWindowType  type,
359                                                    GtkWidget         *widget,
360                                                    gint               width_request,
361                                                    gint               height_request);
362 static void           text_window_free            (GtkTextWindow     *win);
363 static void           text_window_realize         (GtkTextWindow     *win,
364                                                    GdkWindow         *parent);
365 static void           text_window_unrealize       (GtkTextWindow     *win);
366 static void           text_window_size_allocate   (GtkTextWindow     *win,
367                                                    GdkRectangle      *rect);
368 static void           text_window_scroll          (GtkTextWindow     *win,
369                                                    gint               dx,
370                                                    gint               dy);
371 static void           text_window_invalidate_rect (GtkTextWindow     *win,
372                                                    GdkRectangle      *rect);
373
374 static gint           text_window_get_width       (GtkTextWindow     *win);
375 static gint           text_window_get_height      (GtkTextWindow     *win);
376 static void           text_window_get_allocation  (GtkTextWindow     *win,
377                                                    GdkRectangle      *rect);
378
379
380 enum
381 {
382   TARGET_STRING,
383   TARGET_TEXT,
384   TARGET_COMPOUND_TEXT,
385   TARGET_UTF8_STRING,
386   TARGET_TEXT_BUFFER_CONTENTS
387 };
388
389 static GtkTargetEntry target_table[] = {
390   { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP,
391     TARGET_TEXT_BUFFER_CONTENTS },
392   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
393   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
394   { "TEXT", 0, TARGET_TEXT },
395   { "text/plain", 0, TARGET_STRING },
396   { "STRING",     0, TARGET_STRING }
397 };
398
399 static GtkContainerClass *parent_class = NULL;
400 static guint signals[LAST_SIGNAL] = { 0 };
401
402 GtkType
403 gtk_text_view_get_type (void)
404 {
405   static GtkType our_type = 0;
406
407   if (our_type == 0)
408     {
409       static const GtkTypeInfo our_info =
410       {
411         "GtkTextView",
412         sizeof (GtkTextView),
413         sizeof (GtkTextViewClass),
414         (GtkClassInitFunc) gtk_text_view_class_init,
415         (GtkObjectInitFunc) gtk_text_view_init,
416         /* reserved_1 */ NULL,
417         /* reserved_2 */ NULL,
418         (GtkClassInitFunc) NULL
419       };
420
421       our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
422     }
423
424   return our_type;
425 }
426
427 static void
428 add_move_binding (GtkBindingSet  *binding_set,
429                   guint           keyval,
430                   guint           modmask,
431                   GtkMovementStep step,
432                   gint            count)
433 {
434   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
435
436   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
437                                 "move_cursor", 3,
438                                 GTK_TYPE_ENUM, step,
439                                 GTK_TYPE_INT, count,
440                                 GTK_TYPE_BOOL, FALSE);
441
442   /* Selection-extending version */
443   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
444                                 "move_cursor", 3,
445                                 GTK_TYPE_ENUM, step,
446                                 GTK_TYPE_INT, count,
447                                 GTK_TYPE_BOOL, TRUE);
448 }
449
450 static void
451 gtk_text_view_class_init (GtkTextViewClass *klass)
452 {
453   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
454   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
455   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
456   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
457   GtkBindingSet *binding_set;
458
459   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
460
461   /* Default handlers and virtual methods
462    */
463   gobject_class->set_property = gtk_text_view_set_property;
464   gobject_class->get_property = gtk_text_view_get_property;
465
466   object_class->destroy = gtk_text_view_destroy;
467   gobject_class->finalize = gtk_text_view_finalize;
468
469   widget_class->realize = gtk_text_view_realize;
470   widget_class->unrealize = gtk_text_view_unrealize;
471   widget_class->style_set = gtk_text_view_style_set;
472   widget_class->direction_changed = gtk_text_view_direction_changed;
473   widget_class->size_request = gtk_text_view_size_request;
474   widget_class->size_allocate = gtk_text_view_size_allocate;
475   widget_class->event = gtk_text_view_event;
476   widget_class->key_press_event = gtk_text_view_key_press_event;
477   widget_class->key_release_event = gtk_text_view_key_release_event;
478   widget_class->button_press_event = gtk_text_view_button_press_event;
479   widget_class->button_release_event = gtk_text_view_button_release_event;
480   widget_class->focus_in_event = gtk_text_view_focus_in_event;
481   widget_class->focus_out_event = gtk_text_view_focus_out_event;
482   widget_class->motion_notify_event = gtk_text_view_motion_event;
483   widget_class->expose_event = gtk_text_view_expose_event;
484   widget_class->grab_focus = gtk_text_view_grab_focus;
485   
486   widget_class->drag_begin = gtk_text_view_drag_begin;
487   widget_class->drag_end = gtk_text_view_drag_end;
488   widget_class->drag_data_get = gtk_text_view_drag_data_get;
489   widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
490
491   widget_class->drag_leave = gtk_text_view_drag_leave;
492   widget_class->drag_motion = gtk_text_view_drag_motion;
493   widget_class->drag_drop = gtk_text_view_drag_drop;
494   widget_class->drag_data_received = gtk_text_view_drag_data_received;
495
496   widget_class->popup_menu = gtk_text_view_popup_menu;
497   
498   container_class->add = gtk_text_view_add;
499   container_class->remove = gtk_text_view_remove;
500   container_class->forall = gtk_text_view_forall;
501
502   klass->move_cursor = gtk_text_view_move_cursor;
503   klass->set_anchor = gtk_text_view_set_anchor;
504   klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
505   klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
506   klass->cut_clipboard = gtk_text_view_cut_clipboard;
507   klass->copy_clipboard = gtk_text_view_copy_clipboard;
508   klass->paste_clipboard = gtk_text_view_paste_clipboard;
509   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
510   klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
511
512   /*
513    * Properties
514    */
515  
516   g_object_class_install_property (gobject_class,
517                                    PROP_PIXELS_ABOVE_LINES,
518                                    g_param_spec_int ("pixels_above_lines",
519                                                      _("Pixels Above Lines"),
520                                                      _("Pixels of blank space above paragraphs"),
521                                                      0,
522                                                      G_MAXINT,
523                                                      0,
524                                                      G_PARAM_READWRITE));
525  
526   g_object_class_install_property (gobject_class,
527                                    PROP_PIXELS_BELOW_LINES,
528                                    g_param_spec_int ("pixels_below_lines",
529                                                      _("Pixels Below Lines"),
530                                                      _("Pixels of blank space below paragraphs"),
531                                                      0,
532                                                      G_MAXINT,
533                                                      0,
534                                                      G_PARAM_READWRITE));
535  
536   g_object_class_install_property (gobject_class,
537                                    PROP_PIXELS_INSIDE_WRAP,
538                                    g_param_spec_int ("pixels_inside_wrap",
539                                                      _("Pixels Inside Wrap"),
540                                                      _("Pixels of blank space between wrapped lines in a paragraph"),
541                                                      0,
542                                                      G_MAXINT,
543                                                      0,
544                                                      G_PARAM_READWRITE));
545
546   g_object_class_install_property (gobject_class,
547                                    PROP_EDITABLE,
548                                    g_param_spec_boolean ("editable",
549                                                          _("Editable"),
550                                                          _("Whether the text can be modified by the user"),
551                                                          TRUE,
552                                                          G_PARAM_READWRITE));
553
554   g_object_class_install_property (gobject_class,
555                                    PROP_WRAP_MODE,
556                                    g_param_spec_enum ("wrap_mode",
557                                                       _("Wrap Mode"),
558                                                       _("Whether to wrap lines never, at word boundaries, or at character boundaries"),
559                                                       GTK_TYPE_WRAP_MODE,
560                                                       GTK_WRAP_NONE,
561                                                       G_PARAM_READWRITE));
562  
563   g_object_class_install_property (gobject_class,
564                                    PROP_JUSTIFICATION,
565                                    g_param_spec_enum ("justification",
566                                                       _("Justification"),
567                                                       _("Left, right, or center justification"),
568                                                       GTK_TYPE_JUSTIFICATION,
569                                                       GTK_JUSTIFY_LEFT,
570                                                       G_PARAM_READWRITE));
571  
572   g_object_class_install_property (gobject_class,
573                                    PROP_LEFT_MARGIN,
574                                    g_param_spec_int ("left_margin",
575                                                      _("Left Margin"),
576                                                      _("Width of the left margin in pixels"),
577                                                      0,
578                                                      G_MAXINT,
579                                                      0,
580                                                      G_PARAM_READWRITE));
581
582   g_object_class_install_property (gobject_class,
583                                    PROP_RIGHT_MARGIN,
584                                    g_param_spec_int ("right_margin",
585                                                      _("Right Margin"),
586                                                      _("Width of the right margin in pixels"),
587                                                      0,
588                                                      G_MAXINT,
589                                                      0,
590                                                      G_PARAM_READWRITE));
591
592   g_object_class_install_property (gobject_class,
593                                    PROP_INDENT,
594                                    g_param_spec_int ("indent",
595                                                      _("Indent"),
596                                                      _("Amount to indent the paragraph, in pixels"),
597                                                      0,
598                                                      G_MAXINT,
599                                                      0,
600                                                      G_PARAM_READWRITE));
601
602   g_object_class_install_property (gobject_class,
603                                    PROP_TABS,
604                                    g_param_spec_boxed ("tabs",
605                                                        _("Tabs"),
606                                                        _("Custom tabs for this text"),
607                                                        PANGO_TYPE_TAB_ARRAY,
608                                                        G_PARAM_READWRITE));
609
610   g_object_class_install_property (gobject_class,
611                                    PROP_CURSOR_VISIBLE,
612                                    g_param_spec_boolean ("cursor_visible",
613                                                          _("Cursor Visible"),
614                                                          _("If the insertion cursor is shown"),
615                                                          TRUE,
616                                                          G_PARAM_READWRITE));
617
618   
619   /*
620    * Style properties
621    */
622
623   gtk_widget_class_install_style_property (widget_class,
624                                            g_param_spec_boxed ("cursor_color",
625                                                                _("Cursor color"),
626                                                                _("Color with which to draw insertion cursor"),
627                                                                GDK_TYPE_COLOR,
628                                                                G_PARAM_READABLE));
629
630
631   /*
632    * Signals
633    */
634
635   signals[MOVE_CURSOR] =
636     gtk_signal_new ("move_cursor",
637                     GTK_RUN_LAST | GTK_RUN_ACTION,
638                     GTK_CLASS_TYPE (object_class),
639                     GTK_SIGNAL_OFFSET (GtkTextViewClass, move_cursor),
640                     _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
641                     GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
642
643   signals[SET_ANCHOR] =
644     gtk_signal_new ("set_anchor",
645                     GTK_RUN_LAST | GTK_RUN_ACTION,
646                     GTK_CLASS_TYPE (object_class),
647                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
648                     _gtk_marshal_VOID__VOID,
649                     GTK_TYPE_NONE, 0);
650
651   signals[INSERT_AT_CURSOR] =
652     gtk_signal_new ("insert_at_cursor",
653                     GTK_RUN_LAST | GTK_RUN_ACTION,
654                     GTK_CLASS_TYPE (object_class),
655                     GTK_SIGNAL_OFFSET (GtkTextViewClass, insert_at_cursor),
656                     _gtk_marshal_VOID__STRING,
657                     GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
658
659   signals[DELETE_FROM_CURSOR] =
660     gtk_signal_new ("delete_from_cursor",
661                     GTK_RUN_LAST | GTK_RUN_ACTION,
662                     GTK_CLASS_TYPE (object_class),
663                     GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_from_cursor),
664                     _gtk_marshal_VOID__ENUM_INT,
665                     GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
666
667   signals[CUT_CLIPBOARD] =
668     gtk_signal_new ("cut_clipboard",
669                     GTK_RUN_LAST | GTK_RUN_ACTION,
670                     GTK_CLASS_TYPE (object_class),
671                     GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_clipboard),
672                     _gtk_marshal_VOID__VOID,
673                     GTK_TYPE_NONE, 0);
674
675   signals[COPY_CLIPBOARD] =
676     gtk_signal_new ("copy_clipboard",
677                     GTK_RUN_LAST | GTK_RUN_ACTION,
678                     GTK_CLASS_TYPE (object_class),
679                     GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_clipboard),
680                     _gtk_marshal_VOID__VOID,
681                     GTK_TYPE_NONE, 0);
682
683   signals[PASTE_CLIPBOARD] =
684     gtk_signal_new ("paste_clipboard",
685                     GTK_RUN_LAST | GTK_RUN_ACTION,
686                     GTK_CLASS_TYPE (object_class),
687                     GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_clipboard),
688                     _gtk_marshal_VOID__VOID,
689                     GTK_TYPE_NONE, 0);
690
691   signals[TOGGLE_OVERWRITE] =
692     gtk_signal_new ("toggle_overwrite",
693                     GTK_RUN_LAST | GTK_RUN_ACTION,
694                     GTK_CLASS_TYPE (object_class),
695                     GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
696                     _gtk_marshal_VOID__VOID,
697                     GTK_TYPE_NONE, 0);
698
699   signals[SET_SCROLL_ADJUSTMENTS] =
700     gtk_signal_new ("set_scroll_adjustments",
701                     GTK_RUN_LAST,
702                     GTK_CLASS_TYPE (object_class),
703                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
704                     _gtk_marshal_VOID__OBJECT_OBJECT,
705                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
706   widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
707
708   signals[POPULATE_POPUP] =
709     gtk_signal_new ("populate_popup",
710                     GTK_RUN_LAST,
711                     GTK_CLASS_TYPE (object_class),
712                     GTK_SIGNAL_OFFSET (GtkTextViewClass, populate_popup),
713                     _gtk_marshal_VOID__OBJECT,
714                     GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
715   
716   /*
717    * Key bindings
718    */
719
720   binding_set = gtk_binding_set_by_class (klass);
721
722   /* Moving the insertion point */
723   add_move_binding (binding_set, GDK_Right, 0,
724                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
725
726   add_move_binding (binding_set, GDK_KP_Right, 0,
727                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
728   
729   add_move_binding (binding_set, GDK_Left, 0,
730                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
731
732   add_move_binding (binding_set, GDK_KP_Left, 0,
733                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
734   
735   add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
736                     GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
737
738   add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
739                     GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
740
741   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
742                     GTK_MOVEMENT_WORDS, 1);
743
744   add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
745                     GTK_MOVEMENT_WORDS, 1);
746   
747   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
748                     GTK_MOVEMENT_WORDS, -1);
749
750   add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
751                     GTK_MOVEMENT_WORDS, 1);
752   
753   /* Eventually we want to move by display lines, not paragraphs */
754   add_move_binding (binding_set, GDK_Up, 0,
755                     GTK_MOVEMENT_DISPLAY_LINES, -1);
756
757   add_move_binding (binding_set, GDK_KP_Up, 0,
758                     GTK_MOVEMENT_DISPLAY_LINES, -1);
759   
760   add_move_binding (binding_set, GDK_Down, 0,
761                     GTK_MOVEMENT_DISPLAY_LINES, 1);
762
763   add_move_binding (binding_set, GDK_KP_Down, 0,
764                     GTK_MOVEMENT_DISPLAY_LINES, 1);
765   
766   add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
767                     GTK_MOVEMENT_DISPLAY_LINES, -1);
768
769   add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
770                     GTK_MOVEMENT_DISPLAY_LINES, 1);
771
772   add_move_binding (binding_set, GDK_Up, GDK_CONTROL_MASK,
773                     GTK_MOVEMENT_PARAGRAPHS, -1);
774
775   add_move_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK,
776                     GTK_MOVEMENT_PARAGRAPHS, -1);
777   
778   add_move_binding (binding_set, GDK_Down, GDK_CONTROL_MASK,
779                     GTK_MOVEMENT_PARAGRAPHS, 1);
780
781   add_move_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
782                     GTK_MOVEMENT_PARAGRAPHS, 1);
783   
784   add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
785                     GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
786
787   add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
788                     GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
789
790   add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
791                     GTK_MOVEMENT_WORDS, 1);
792
793   add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
794                     GTK_MOVEMENT_WORDS, -1);
795
796   add_move_binding (binding_set, GDK_Home, 0,
797                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
798
799   add_move_binding (binding_set, GDK_KP_Home, 0,
800                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
801   
802   add_move_binding (binding_set, GDK_End, 0,
803                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
804
805   add_move_binding (binding_set, GDK_KP_End, 0,
806                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
807   
808   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
809                     GTK_MOVEMENT_BUFFER_ENDS, -1);
810
811   add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
812                     GTK_MOVEMENT_BUFFER_ENDS, -1);
813   
814   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
815                     GTK_MOVEMENT_BUFFER_ENDS, 1);
816
817   add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
818                     GTK_MOVEMENT_BUFFER_ENDS, 1);
819   
820   add_move_binding (binding_set, GDK_Page_Up, 0,
821                     GTK_MOVEMENT_PAGES, -1);
822
823   add_move_binding (binding_set, GDK_KP_Page_Up, 0,
824                     GTK_MOVEMENT_PAGES, -1);
825   
826   add_move_binding (binding_set, GDK_Page_Down, 0,
827                     GTK_MOVEMENT_PAGES, 1);
828
829   add_move_binding (binding_set, GDK_KP_Page_Down, 0,
830                     GTK_MOVEMENT_PAGES, 1);
831   
832   /* Setting the cut/paste/copy anchor */
833   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
834                                 "set_anchor", 0);
835   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK,
836                                 "set_anchor", 0);
837   
838   /* Deleting text */
839   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
840                                 "delete_from_cursor", 2,
841                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
842                                 GTK_TYPE_INT, 1);
843
844   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
845                                 "delete_from_cursor", 2,
846                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
847                                 GTK_TYPE_INT, 1);
848   
849   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
850                                 "delete_from_cursor", 2,
851                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
852                                 GTK_TYPE_INT, 1);
853
854   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
855                                 "delete_from_cursor", 2,
856                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
857                                 GTK_TYPE_INT, -1);
858
859   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
860                                 "delete_from_cursor", 2,
861                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
862                                 GTK_TYPE_INT, 1);
863
864   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
865                                 "delete_from_cursor", 2,
866                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
867                                 GTK_TYPE_INT, 1);
868   
869   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
870                                 "delete_from_cursor", 2,
871                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
872                                 GTK_TYPE_INT, 1);
873
874   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
875                                 "delete_from_cursor", 2,
876                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
877                                 GTK_TYPE_INT, -1);
878
879   gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
880                                 "delete_from_cursor", 2,
881                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
882                                 GTK_TYPE_INT, 1);
883
884   gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
885                                 "delete_from_cursor", 2,
886                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
887                                 GTK_TYPE_INT, 1);
888
889   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
890                                 "delete_from_cursor", 2,
891                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
892                                 GTK_TYPE_INT, 1);
893   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_MOD1_MASK,
894                                 "delete_from_cursor", 2,
895                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
896                                 GTK_TYPE_INT, 1);
897   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
898                                 "insert_at_cursor", 1,
899                                 GTK_TYPE_STRING, " ");
900   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_MOD1_MASK,
901                                 "insert_at_cursor", 1,
902                                 GTK_TYPE_STRING, " ");
903   
904   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
905                                 "delete_from_cursor", 2,
906                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
907                                 GTK_TYPE_INT, 1);
908
909   /* Cut/copy/paste */
910
911   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
912                                 "cut_clipboard", 0);
913
914   gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
915                                 "cut_clipboard", 0);
916
917   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
918                                 "copy_clipboard", 0);
919
920   gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
921                                 "paste_clipboard", 0);
922
923   gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
924                                 "paste_clipboard", 0);
925
926   /* Overwrite */
927   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
928                                 "toggle_overwrite", 0);
929   gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
930                                 "toggle_overwrite", 0);
931 }
932
933 static void
934 gtk_text_view_init (GtkTextView *text_view)
935 {
936   GtkWidget *widget;
937
938   widget = GTK_WIDGET (text_view);
939
940   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
941
942   /* Set up default style */
943   text_view->wrap_mode = GTK_WRAP_NONE;
944   text_view->pixels_above_lines = 0;
945   text_view->pixels_below_lines = 0;
946   text_view->pixels_inside_wrap = 0;
947   text_view->justify = GTK_JUSTIFY_LEFT;
948   text_view->left_margin = 0;
949   text_view->right_margin = 0;
950   text_view->indent = 0;
951   text_view->tabs = NULL;
952   text_view->editable = TRUE;
953
954   gtk_drag_dest_set (widget,
955                      0,
956                      target_table, G_N_ELEMENTS (target_table),
957                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
958
959   text_view->virtual_cursor_x = -1;
960   text_view->virtual_cursor_y = -1;
961
962   /* This object is completely private. No external entity can gain a reference
963    * to it; so we create it here and destroy it in finalize ().
964    */
965   text_view->im_context = gtk_im_multicontext_new ();
966
967   g_signal_connect (G_OBJECT (text_view->im_context), "commit",
968                     G_CALLBACK (gtk_text_view_commit_handler), text_view);
969   g_signal_connect (G_OBJECT (text_view->im_context), "preedit_changed",
970                     G_CALLBACK (gtk_text_view_preedit_changed_handler), text_view);
971   g_signal_connect (G_OBJECT (text_view->im_context), "retrieve_surrounding",
972                     G_CALLBACK (gtk_text_view_retrieve_surrounding_handler), text_view);
973   g_signal_connect (G_OBJECT (text_view->im_context), "delete_surrounding",
974                     G_CALLBACK (gtk_text_view_delete_surrounding_handler), text_view);
975
976   text_view->cursor_visible = TRUE;
977
978   text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
979                                             widget, 200, 200);
980
981   text_view->drag_start_x = -1;
982   text_view->drag_start_y = -1;
983
984   text_view->pending_place_cursor_button = 0;
985
986   /* We handle all our own redrawing */
987   gtk_widget_set_redraw_on_allocate (widget, FALSE);
988 }
989
990 /**
991  * gtk_text_view_new:
992  *
993  * Creates a new #GtkTextView. If you don't call gtk_text_view_set_buffer()
994  * before using the text view, an empty default buffer will be created
995  * for you. Get the buffer with gtk_text_view_get_buffer(). If you want
996  * to specify your own buffer, consider gtk_text_view_new_with_buffer().
997  *
998  * Return value: a new #GtkTextView
999  **/
1000 GtkWidget*
1001 gtk_text_view_new (void)
1002 {
1003   return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
1004 }
1005
1006 /**
1007  * gtk_text_view_new_with_buffer:
1008  * @buffer: a #GtkTextBuffer
1009  *
1010  * Creates a new #GtkTextView widget displaying the buffer
1011  * @buffer. One buffer can be shared among many widgets.
1012  * @buffer may be NULL to create a default buffer, in which case
1013  * this function is equivalent to gtk_text_view_new(). The
1014  * text view adds its own reference count to the buffer; it does not
1015  * take over an existing reference.
1016  *
1017  * Return value: a new #GtkTextView.
1018  **/
1019 GtkWidget*
1020 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
1021 {
1022   GtkTextView *text_view;
1023
1024   text_view = (GtkTextView*)gtk_text_view_new ();
1025
1026   gtk_text_view_set_buffer (text_view, buffer);
1027
1028   return GTK_WIDGET (text_view);
1029 }
1030
1031 /**
1032  * gtk_text_view_set_buffer:
1033  * @text_view: a #GtkTextView
1034  * @buffer: a #GtkTextBuffer
1035  *
1036  * Sets @buffer as the buffer being displayed by @text_view. The previous
1037  * buffer displayed by the text view is unreferenced, and a reference is
1038  * added to @buffer. If you owned a reference to @buffer before passing it
1039  * to this function, you must remove that reference yourself; #GtkTextView
1040  * will not "adopt" it.
1041  *
1042  **/
1043 void
1044 gtk_text_view_set_buffer (GtkTextView   *text_view,
1045                           GtkTextBuffer *buffer)
1046 {
1047   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1048   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
1049
1050   if (text_view->buffer == buffer)
1051     return;
1052
1053   if (text_view->buffer != NULL)
1054     {
1055       /* Destroy all anchored children */
1056       GSList *tmp_list;
1057       GSList *copy;
1058
1059       copy = g_slist_copy (text_view->children);
1060       tmp_list = copy;
1061       while (tmp_list != NULL)
1062         {
1063           GtkTextViewChild *vc = tmp_list->data;
1064
1065           if (vc->anchor)
1066             {
1067               gtk_widget_destroy (vc->widget);
1068               /* vc may now be invalid! */
1069             }
1070
1071           tmp_list = g_slist_next (tmp_list);
1072         }
1073
1074       g_slist_free (copy);
1075
1076       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->buffer),
1077                                             gtk_text_view_mark_set_handler, text_view);
1078       g_object_unref (G_OBJECT (text_view->buffer));
1079       text_view->dnd_mark = NULL;
1080
1081       if (GTK_WIDGET_REALIZED (text_view))
1082         gtk_text_buffer_remove_selection_clipboard (text_view->buffer,
1083                                                     gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1084     }
1085
1086   text_view->buffer = buffer;
1087
1088   if (buffer != NULL)
1089     {
1090       GtkTextIter start;
1091
1092       g_object_ref (G_OBJECT (buffer));
1093
1094       if (text_view->layout)
1095         gtk_text_layout_set_buffer (text_view->layout, buffer);
1096
1097       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
1098
1099       text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
1100                                                          "gtk_drag_target",
1101                                                          &start, FALSE);
1102
1103       text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
1104                                                                 NULL,
1105                                                                 &start, TRUE);
1106
1107       text_view->first_para_pixels = 0;
1108
1109       g_signal_connect (G_OBJECT (text_view->buffer), "mark_set",
1110                         G_CALLBACK (gtk_text_view_mark_set_handler), text_view);
1111
1112       if (GTK_WIDGET_REALIZED (text_view))
1113         gtk_text_buffer_add_selection_clipboard (text_view->buffer,
1114                                                  gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1115     }
1116   
1117   if (GTK_WIDGET_VISIBLE (text_view))
1118     gtk_widget_queue_draw (GTK_WIDGET (text_view));
1119   
1120   gtk_text_view_invalidate (text_view);
1121 }
1122
1123 static GtkTextBuffer*
1124 get_buffer (GtkTextView *text_view)
1125 {
1126   if (text_view->buffer == NULL)
1127     {
1128       GtkTextBuffer *b;
1129       b = gtk_text_buffer_new (NULL);
1130       gtk_text_view_set_buffer (text_view, b);
1131       g_object_unref (G_OBJECT (b));
1132     }
1133
1134   return text_view->buffer;
1135 }
1136
1137 /**
1138  * gtk_text_view_get_buffer:
1139  * @text_view: a #GtkTextView
1140  *
1141  * Returns the #GtkTextBuffer being displayed by this text view.
1142  * The reference count on the buffer is not incremented; the caller
1143  * of this function won't own a new reference.
1144  *
1145  * Return value: a #GtkTextBuffer
1146  **/
1147 GtkTextBuffer*
1148 gtk_text_view_get_buffer (GtkTextView *text_view)
1149 {
1150   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
1151
1152   return get_buffer (text_view);
1153 }
1154
1155 /**
1156  * gtk_text_view_get_iter_at_location:
1157  * @text_view: a #GtkTextView
1158  * @iter: a #GtkTextIter
1159  * @x: x position, in buffer coordinates
1160  * @y: y position, in buffer coordinates
1161  *
1162  * Retrieves the iterator at buffer coordinates @x and @y. Buffer
1163  * coordinates are coordinates for the entire buffer, not just the
1164  * currently-displayed portion.  If you have coordinates from an
1165  * event, you have to convert those to buffer coordinates with
1166  * gtk_text_view_window_to_buffer_coords().
1167  *
1168  **/
1169 void
1170 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
1171                                     GtkTextIter *iter,
1172                                     gint         x,
1173                                     gint         y)
1174 {
1175   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1176   g_return_if_fail (iter != NULL);
1177   g_return_if_fail (text_view->layout != NULL);
1178
1179   gtk_text_layout_get_iter_at_pixel (text_view->layout,
1180                                      iter,
1181                                      x,
1182                                      y);
1183 }
1184
1185 /**
1186  * gtk_text_view_get_iter_location:
1187  * @text_view: a #GtkTextView
1188  * @iter: a #GtkTextIter
1189  * @location: bounds of the character at @iter
1190  *
1191  * Gets a rectangle which roughly contains the character at @iter.
1192  * The rectangle position is in buffer coordinates; use
1193  * gtk_text_view_buffer_to_window_coords() to convert these
1194  * coordinates to coordinates for one of the windows in the text view.
1195  *
1196  **/
1197 void
1198 gtk_text_view_get_iter_location (GtkTextView       *text_view,
1199                                  const GtkTextIter *iter,
1200                                  GdkRectangle      *location)
1201 {
1202   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1203   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1204
1205   gtk_text_layout_get_iter_location (text_view->layout, iter, location);
1206 }
1207
1208 /**
1209  * gtk_text_view_get_line_yrange:
1210  * @text_view: a #GtkTextView
1211  * @iter: a #GtkTextIter
1212  * @y: return location for a y coordinate
1213  * @height: return location for a height
1214  *
1215  * Gets the y coordinate of the top of the line containing @iter,
1216  * and the height of the line. The coordinate is a buffer coordinate;
1217  * convert to window coordinates with gtk_text_view_buffer_to_window_coords().
1218  *
1219  **/
1220 void
1221 gtk_text_view_get_line_yrange (GtkTextView       *text_view,
1222                                const GtkTextIter *iter,
1223                                gint              *y,
1224                                gint              *height)
1225 {
1226   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1227   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1228
1229   gtk_text_layout_get_line_yrange (text_view->layout,
1230                                    iter,
1231                                    y,
1232                                    height);
1233 }
1234
1235 /**
1236  * gtk_text_view_get_line_at_y:
1237  * @text_view: a #GtkTextView
1238  * @target_iter: a #GtkTextIter
1239  * @y: a y coordinate
1240  * @line_top: return location for top coordinate of the line
1241  *
1242  * Gets the #GtkTextIter at the start of the line containing
1243  * the coordinate @y. @y is in buffer coordinates, convert from
1244  * window coordinates with gtk_text_view_window_to_buffer_coords().
1245  * If non-%NULL, @line_top will be filled with the coordinate of the top
1246  * edge of the line.
1247  **/
1248 void
1249 gtk_text_view_get_line_at_y (GtkTextView *text_view,
1250                              GtkTextIter *target_iter,
1251                              gint         y,
1252                              gint        *line_top)
1253 {
1254   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1255
1256   gtk_text_layout_get_line_at_y (text_view->layout,
1257                                  target_iter,
1258                                  y,
1259                                  line_top);
1260 }
1261
1262 static gboolean
1263 set_adjustment_clamped (GtkAdjustment *adj, gdouble val)
1264 {
1265   DV (g_print ("  Setting adj to raw value %g\n", val));
1266   
1267   /* We don't really want to clamp to upper; we want to clamp to
1268      upper - page_size which is the highest value the scrollbar
1269      will let us reach. */
1270   if (val > (adj->upper - adj->page_size))
1271     val = adj->upper - adj->page_size;
1272
1273   if (val < adj->lower)
1274     val = adj->lower;
1275
1276   if (val != adj->value)
1277     {
1278       DV (g_print ("  Setting adj to clamped value %g\n", val));
1279       gtk_adjustment_set_value (adj, val);
1280       return TRUE;
1281     }
1282   else
1283     return FALSE;
1284 }
1285
1286 /**
1287  * gtk_text_view_scroll_to_iter:
1288  * @text_view: a #GtkTextView
1289  * @iter: a #GtkTextIter
1290  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1291  * @use_align: whether to use alignment arguments (if %FALSE, just get the mark onscreen)
1292  * @xalign: horizontal alignment of mark within visible area.
1293  * @yalign: vertical alignment of mark within visible area
1294  *
1295  * Scrolls @text_view so that @iter is on the screen in the position
1296  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1297  * left or top, 1.0 indicates right or bottom, 0.5 means center. If @use_align
1298  * is %FALSE, the text scrolls the minimal distance to get the mark onscreen,
1299  * possibly not scrolling at all. The effective screen for purposes
1300  * of this function is reduced by a margin of size @within_margin.
1301  * NOTE: This function uses the currently-computed height of the
1302  * lines in the text buffer. Note that line heights are computed
1303  * in an idle handler; so this function may not have the desired effect
1304  * if it's called before the height computations. To avoid oddness,
1305  * consider using gtk_text_view_scroll_to_mark() which saves a point
1306  * to be scrolled to after line validation.
1307  *
1308  * Return value: %TRUE if scrolling occurred
1309  **/
1310 gboolean
1311 gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
1312                               GtkTextIter   *iter,
1313                               gdouble        within_margin,
1314                               gboolean       use_align,
1315                               gdouble        xalign,
1316                               gdouble        yalign)
1317 {
1318   GdkRectangle rect;
1319   GdkRectangle screen;
1320   gint screen_bottom;
1321   gint screen_right;
1322   gint scroll_dest;
1323   GtkWidget *widget;
1324   gboolean retval = FALSE;
1325   gint scroll_inc;
1326   gint screen_xoffset, screen_yoffset;
1327   gint current_x_scroll, current_y_scroll;
1328
1329   /* FIXME why don't we do the validate-at-scroll-destination thing
1330    * from flush_scroll in this function? I think it wasn't done before
1331    * because changed_handler was screwed up, but I could be wrong.
1332    */
1333   
1334   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1335   g_return_val_if_fail (iter != NULL, FALSE);
1336   g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE);
1337   g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE);
1338   g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE);
1339   
1340   widget = GTK_WIDGET (text_view);
1341
1342   DV(g_print(G_STRLOC"\n"));
1343   
1344   gtk_text_layout_get_iter_location (text_view->layout,
1345                                      iter,
1346                                      &rect);
1347
1348   DV (g_print (" target rect %d,%d  %d x %d\n", rect.x, rect.y, rect.width, rect.height));
1349   
1350   current_x_scroll = text_view->xoffset;
1351   current_y_scroll = text_view->yoffset;
1352
1353   screen.x = current_x_scroll;
1354   screen.y = current_y_scroll;
1355   screen.width = SCREEN_WIDTH (widget);
1356   screen.height = SCREEN_HEIGHT (widget);
1357   
1358   screen_xoffset = screen.width * within_margin;
1359   screen_yoffset = screen.height * within_margin;
1360   
1361   screen.x += screen_xoffset;
1362   screen.y += screen_yoffset;
1363   screen.width -= screen_xoffset * 2;
1364   screen.height -= screen_yoffset * 2;
1365
1366   /* paranoia check */
1367   if (screen.width < 1)
1368     screen.width = 1;
1369   if (screen.height < 1)
1370     screen.height = 1;
1371   
1372   screen_right = screen.x + screen.width;
1373   screen_bottom = screen.y + screen.height;
1374   
1375   /* The alignment affects the point in the target character that we
1376    * choose to align. If we're doing right/bottom alignment, we align
1377    * the right/bottom edge of the character the mark is at; if we're
1378    * doing left/top we align the left/top edge of the character; if
1379    * we're doing center alignment we align the center of the
1380    * character.
1381    */
1382   
1383   /* Vertical scroll */
1384
1385   scroll_inc = 0;
1386   scroll_dest = current_y_scroll;
1387   
1388   if (use_align)
1389     {      
1390       scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
1391       
1392       /* if scroll_dest < screen.y, we move a negative increment (up),
1393        * else a positive increment (down)
1394        */
1395       scroll_inc = scroll_dest - screen.y + screen_yoffset;
1396     }
1397   else
1398     {
1399       /* move minimum to get onscreen */
1400       if (rect.y < screen.y)
1401         {
1402           scroll_dest = rect.y;
1403           scroll_inc = scroll_dest - screen.y - screen_yoffset;
1404         }
1405       else if ((rect.y + rect.height) > screen_bottom)
1406         {
1407           scroll_dest = rect.y + rect.height;
1408           scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
1409         }
1410     }  
1411   
1412   if (scroll_inc != 0)
1413     {
1414       retval = set_adjustment_clamped (get_vadjustment (text_view),
1415                                        current_y_scroll + scroll_inc);
1416
1417       DV (g_print (" vert increment %d\n", scroll_inc));
1418     }
1419
1420   /* Horizontal scroll */
1421   
1422   scroll_inc = 0;
1423   scroll_dest = current_x_scroll;
1424   
1425   if (use_align)
1426     {      
1427       scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
1428
1429       /* if scroll_dest < screen.y, we move a negative increment (left),
1430        * else a positive increment (right)
1431        */
1432       scroll_inc = scroll_dest - screen.x + screen_xoffset;
1433     }
1434   else
1435     {
1436       /* move minimum to get onscreen */
1437       if (rect.x < screen.x)
1438         {
1439           scroll_dest = rect.x;
1440           scroll_inc = scroll_dest - screen.x - screen_xoffset;
1441         }
1442       else if ((rect.x + rect.width) > screen_right)
1443         {
1444           scroll_dest = rect.x + rect.width;
1445           scroll_inc = scroll_dest - screen_right + screen_xoffset;
1446         }
1447     }
1448   
1449   if (scroll_inc != 0)
1450     {
1451       retval = set_adjustment_clamped (get_hadjustment (text_view),
1452                                        current_x_scroll + scroll_inc);
1453
1454       DV (g_print (" horiz increment %d\n", scroll_inc));
1455     }
1456   
1457   if (retval)
1458     DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
1459   else
1460     DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
1461   
1462   return retval;
1463 }
1464
1465 static void
1466 free_pending_scroll (GtkTextPendingScroll *scroll)
1467 {
1468   if (!gtk_text_mark_get_deleted (scroll->mark))
1469     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (scroll->mark),
1470                                  scroll->mark);
1471   g_object_unref (G_OBJECT (scroll->mark));
1472   g_free (scroll);
1473 }
1474
1475 static void
1476 gtk_text_view_queue_scroll (GtkTextView   *text_view,
1477                             GtkTextMark   *mark,
1478                             gdouble        within_margin,
1479                             gboolean       use_align,
1480                             gdouble        xalign,
1481                             gdouble        yalign)
1482 {
1483   GtkTextIter iter;
1484   GtkTextPendingScroll *scroll;
1485
1486   DV(g_print(G_STRLOC"\n"));
1487   
1488   scroll = g_new (GtkTextPendingScroll, 1);
1489
1490   scroll->within_margin = within_margin;
1491   scroll->use_align = use_align;
1492   scroll->xalign = xalign;
1493   scroll->yalign = yalign;
1494   
1495   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1496
1497   scroll->mark = gtk_text_buffer_create_mark (get_buffer (text_view),
1498                                               NULL,
1499                                               &iter,
1500                                               gtk_text_mark_get_left_gravity (mark));
1501
1502   g_object_ref (G_OBJECT (scroll->mark));
1503   
1504   if (text_view->pending_scroll)
1505     free_pending_scroll (text_view->pending_scroll);
1506
1507   text_view->pending_scroll = scroll;
1508 }
1509
1510 static gboolean
1511 gtk_text_view_flush_scroll (GtkTextView *text_view)
1512 {
1513   GtkTextIter iter;
1514   GtkTextPendingScroll *scroll;
1515   gboolean retval;
1516   
1517   DV(g_print(G_STRLOC"\n"));
1518   
1519   if (text_view->pending_scroll == NULL)
1520     return FALSE;
1521
1522   scroll = text_view->pending_scroll;
1523
1524   /* avoid recursion */
1525   text_view->pending_scroll = NULL;
1526   
1527   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, scroll->mark);
1528
1529   /* Validate arbitrary area around the scroll destination, so the adjustment
1530    * can meaningfully point into that area
1531    */
1532   DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
1533   gtk_text_layout_validate_yrange (text_view->layout, &iter, -300, 300);
1534   
1535   DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
1536
1537   /* Ensure we have updated width/height */
1538   gtk_text_view_update_adjustments (text_view);
1539   
1540   retval = gtk_text_view_scroll_to_iter (text_view,
1541                                          &iter,
1542                                          scroll->within_margin,
1543                                          scroll->use_align,
1544                                          scroll->xalign,
1545                                          scroll->yalign);
1546   
1547   free_pending_scroll (scroll);
1548
1549   return retval;
1550 }
1551
1552 static void
1553 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gdouble upper)
1554 {  
1555   if (upper != adj->upper)
1556     {
1557       gdouble min = MAX (0.0, upper - adj->page_size);
1558       gboolean value_changed = FALSE;
1559
1560       adj->upper = upper;
1561
1562       if (adj->value > min)
1563         {
1564           adj->value = min;
1565           value_changed = TRUE;
1566         }
1567
1568       gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
1569       DV(g_print(">Changed adj upper to %g ("G_STRLOC")\n", upper));
1570       
1571       if (value_changed)
1572         {
1573           DV(g_print(">Changed adj value because upper decreased ("G_STRLOC")\n"));
1574           gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
1575         }
1576     }
1577 }
1578
1579 static void
1580 gtk_text_view_update_adjustments (GtkTextView *text_view)
1581 {
1582   gint width = 0, height = 0;
1583
1584   DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
1585
1586   if (text_view->layout)
1587     gtk_text_layout_get_size (text_view->layout, &width, &height);
1588
1589   if (text_view->width != width || text_view->height != height)
1590     {
1591       text_view->width = width;
1592       text_view->height = height;
1593
1594       gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
1595                                           MAX (SCREEN_WIDTH (text_view), width));
1596       gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
1597                                           MAX (SCREEN_HEIGHT (text_view), height));
1598       
1599       /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
1600
1601       /* Set up the step sizes; we'll say that a page is
1602          our allocation minus one step, and a step is
1603          1/10 of our allocation. */
1604       text_view->hadjustment->step_increment =
1605         SCREEN_WIDTH (text_view) / 10.0;
1606       text_view->hadjustment->page_increment =
1607         SCREEN_WIDTH (text_view) * 0.9;
1608       
1609       text_view->vadjustment->step_increment =
1610         SCREEN_HEIGHT (text_view) / 10.0;
1611       text_view->vadjustment->page_increment =
1612         SCREEN_HEIGHT (text_view) * 0.9;
1613
1614       gtk_signal_emit_by_name (GTK_OBJECT (get_hadjustment (text_view)), "changed");
1615       gtk_signal_emit_by_name (GTK_OBJECT (get_hadjustment (text_view)), "changed");
1616     }
1617 }
1618
1619 static void
1620 gtk_text_view_update_layout_width (GtkTextView *text_view)
1621 {
1622   DV(g_print(">Updating layout width ("G_STRLOC")\n"));
1623   
1624   gtk_text_view_ensure_layout (text_view);
1625
1626   gtk_text_layout_set_screen_width (text_view->layout,
1627                                     SCREEN_WIDTH (text_view));
1628 }
1629
1630 static void
1631 gtk_text_view_update_im_spot_location (GtkTextView *text_view)
1632 {
1633   GdkRectangle area;
1634   gint cursor_x_pos, cursor_y_pos;
1635
1636   if (text_view->layout == NULL)
1637     return;
1638   
1639   gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
1640
1641   area.x = cursor_x_pos;
1642   area.y = cursor_y_pos;
1643   area.width = area.height = 0;
1644
1645   gtk_im_context_set_cursor_location (text_view->im_context, &area);
1646 }
1647
1648 /**
1649  * gtk_text_view_scroll_to_mark:
1650  * @text_view: a #GtkTextView
1651  * @mark: a #GtkTextMark
1652  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1653  * @use_align: whether to use alignment arguments (if %FALSE, just get the mark onscreen)
1654  * @xalign: horizontal alignment of mark within visible area.
1655  * @yalign: vertical alignment of mark within visible area
1656  *
1657  * Scrolls @text_view so that @mark is on the screen in the position
1658  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1659  * left or top, 1.0 indicates right or bottom, 0.5 means center. If @use_align
1660  * is %FALSE, the text scrolls the minimal distance to get the mark onscreen,
1661  * possibly not scrolling at all. The effective screen for purposes
1662  * of this function is reduced by a margin of size @within_margin.
1663  *
1664  **/
1665 void
1666 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
1667                               GtkTextMark *mark,
1668                               gdouble      within_margin,
1669                               gboolean     use_align,
1670                               gdouble      xalign,
1671                               gdouble      yalign)
1672 {  
1673   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1674   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1675   g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5);
1676   g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
1677   g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
1678
1679   gtk_text_view_queue_scroll (text_view, mark,
1680                               within_margin,
1681                               use_align,
1682                               xalign,
1683                               yalign);
1684
1685   /* If no validation is pending, we need to go ahead and force an
1686    * immediate scroll.
1687    */
1688   if (text_view->layout &&
1689       gtk_text_layout_is_valid (text_view->layout))
1690     gtk_text_view_flush_scroll (text_view);
1691 }
1692
1693 /**
1694  * gtk_text_view_scroll_mark_onscreen:
1695  * @text_view: a #GtkTextView
1696  * @mark: a mark in the buffer for @text_view
1697  * 
1698  * Scrolls @text_view the minimum distance such that @mark is contained
1699  * within the visible area of the widget.
1700  * 
1701  **/
1702 void
1703 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
1704                                     GtkTextMark *mark)
1705 {
1706   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1707   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1708
1709   gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
1710 }
1711
1712 static gboolean
1713 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
1714 {
1715   GdkRectangle visible_rect;
1716   gtk_text_view_get_visible_rect (text_view, &visible_rect);
1717
1718   return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
1719                                                visible_rect.y,
1720                                                visible_rect.y + visible_rect.height);
1721 }
1722
1723 /**
1724  * gtk_text_view_move_mark_onscreen:
1725  * @text_view: a #GtkTextView
1726  * @mark: a #GtkTextMark
1727  *
1728  * Moves a mark within the buffer so that it's
1729  * located within the currently-visible text area.
1730  *
1731  * Return value: %TRUE if the mark moved (wasn't already onscreen)
1732  **/
1733 gboolean
1734 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
1735                                   GtkTextMark *mark)
1736 {
1737   GtkTextIter iter;
1738
1739   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1740   g_return_val_if_fail (mark != NULL, FALSE);
1741
1742   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1743
1744   if (clamp_iter_onscreen (text_view, &iter))
1745     {
1746       gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
1747       return TRUE;
1748     }
1749   else
1750     return FALSE;
1751 }
1752
1753 /**
1754  * gtk_text_view_get_visible_rect:
1755  * @text_view: a #GtkTextView
1756  * @visible_rect: rectangle to fill
1757  *
1758  * Fills @visible_rect with the currently-visible
1759  * region of the buffer, in buffer coordinates. Convert to window coordinates
1760  * with gtk_text_view_buffer_to_window_coords().
1761  **/
1762 void
1763 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
1764                                 GdkRectangle *visible_rect)
1765 {
1766   GtkWidget *widget;
1767
1768   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1769
1770   widget = GTK_WIDGET (text_view);
1771
1772   if (visible_rect)
1773     {
1774       visible_rect->x = text_view->xoffset;
1775       visible_rect->y = text_view->yoffset;
1776       visible_rect->width = SCREEN_WIDTH (widget);
1777       visible_rect->height = SCREEN_HEIGHT (widget);
1778
1779       DV(g_print(" visible rect: %d,%d %d x %d\n",
1780                  visible_rect->x,
1781                  visible_rect->y,
1782                  visible_rect->width,
1783                  visible_rect->height));
1784     }
1785 }
1786
1787 /**
1788  * gtk_text_view_set_wrap_mode:
1789  * @text_view: a #GtkTextView
1790  * @wrap_mode: a #GtkWrapMode
1791  *
1792  * Sets the line wrapping for the view.
1793  **/
1794 void
1795 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
1796                              GtkWrapMode  wrap_mode)
1797 {
1798   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1799
1800   if (text_view->wrap_mode != wrap_mode)
1801     {
1802       text_view->wrap_mode = wrap_mode;
1803
1804       if (text_view->layout)
1805         {
1806           text_view->layout->default_style->wrap_mode = wrap_mode;
1807           gtk_text_layout_default_style_changed (text_view->layout);
1808         }
1809     }
1810
1811   g_object_notify (G_OBJECT (text_view), "wrap_mode");
1812 }
1813
1814 /**
1815  * gtk_text_view_get_wrap_mode:
1816  * @text_view: a #GtkTextView
1817  *
1818  * Gets the line wrapping for the view.
1819  *
1820  * Return value: the line wrap setting
1821  **/
1822 GtkWrapMode
1823 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
1824 {
1825   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAP_NONE);
1826
1827   return text_view->wrap_mode;
1828 }
1829
1830 /**
1831  * gtk_text_view_set_editable:
1832  * @text_view: a #GtkTextView
1833  * @setting: whether it's editable
1834  *
1835  * Sets the default editability of the #GtkTextView. You can override
1836  * this default setting with tags in the buffer, using the "editable"
1837  * attribute of tags.
1838  **/
1839 void
1840 gtk_text_view_set_editable (GtkTextView *text_view,
1841                             gboolean     setting)
1842 {
1843   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1844
1845   if (text_view->editable != setting)
1846     {
1847       text_view->editable = setting;
1848
1849       if (text_view->layout)
1850         {
1851           text_view->layout->default_style->editable = text_view->editable;
1852           gtk_text_layout_default_style_changed (text_view->layout);
1853         }
1854     }
1855
1856   g_object_notify (G_OBJECT (text_view), "editable");
1857 }
1858
1859 /**
1860  * gtk_text_view_get_editable:
1861  * @text_view: a #GtkTextView
1862  *
1863  * Returns the default editability of the #GtkTextView. Tags in the
1864  * buffer may override this setting for some ranges of text.
1865  *
1866  * Return value: whether text is editable by default
1867  **/
1868 gboolean
1869 gtk_text_view_get_editable (GtkTextView *text_view)
1870 {
1871   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1872
1873   return text_view->editable;
1874 }
1875
1876 /**
1877  * gtk_text_view_set_pixels_above_lines:
1878  * @text_view: a #GtkTextView
1879  * @pixels_above_lines: pixels above paragraphs
1880  * 
1881  * Sets the default number of blank pixels above paragraphs in @text_view.
1882  * Tags in the buffer for @text_view may override the defaults.
1883  * 
1884  **/
1885 void
1886 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
1887                                       gint         pixels_above_lines)
1888 {
1889   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1890
1891   if (text_view->pixels_above_lines != pixels_above_lines)
1892     {
1893       text_view->pixels_above_lines = pixels_above_lines;
1894
1895       if (text_view->layout)
1896         {
1897           text_view->layout->default_style->pixels_above_lines = pixels_above_lines;
1898           gtk_text_layout_default_style_changed (text_view->layout);
1899         }
1900     }
1901
1902   g_object_notify (G_OBJECT (text_view), "pixels_above_lines");
1903 }
1904
1905 /**
1906  * gtk_text_view_get_pixels_above_lines:
1907  * @text_view: a #GtkTextView
1908  * 
1909  * Gets the default number of pixels to put above paragraphs.
1910  * 
1911  * Return value: default number of pixels above paragraphs
1912  **/
1913 gint
1914 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
1915 {
1916   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1917
1918   return text_view->pixels_above_lines;
1919 }
1920
1921 /**
1922  * gtk_text_view_set_pixels_below_lines:
1923  * @text_view: a #GtkTextView
1924  * @pixels_below_lines: pixels below paragraphs 
1925  *
1926  * Sets the default number of pixels of blank space
1927  * to put below paragraphs in @text_view. May be overridden
1928  * by tags applied to @text_view's buffer. 
1929  * 
1930  **/
1931 void
1932 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
1933                                       gint         pixels_below_lines)
1934 {
1935   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1936
1937   if (text_view->pixels_below_lines != pixels_below_lines)
1938     {
1939       text_view->pixels_below_lines = pixels_below_lines;
1940
1941       if (text_view->layout)
1942         {
1943           text_view->layout->default_style->pixels_below_lines = pixels_below_lines;
1944           gtk_text_layout_default_style_changed (text_view->layout);
1945         }
1946     }
1947
1948   g_object_notify (G_OBJECT (text_view), "pixels_below_lines");
1949 }
1950
1951 /**
1952  * gtk_text_view_get_pixels_below_lines:
1953  * @text_view: a #GtkTextView
1954  * 
1955  * Gets the value set by gtk_text_view_set_pixels_below_lines().
1956  * 
1957  * Return value: default number of blank pixels below paragraphs
1958  **/
1959 gint
1960 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
1961 {
1962   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1963
1964   return text_view->pixels_below_lines;
1965 }
1966
1967 /**
1968  * gtk_text_view_set_pixels_inside_wrap:
1969  * @text_view: a #GtkTextView
1970  * @pixels_inside_wrap: default number of pixels between wrapped lines
1971  *
1972  * Sets the default number of pixels of blank space to leave between
1973  * display/wrapped lines within a paragraph. May be overridden by
1974  * tags in @text_view's buffer.
1975  * 
1976  **/
1977 void
1978 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
1979                                       gint         pixels_inside_wrap)
1980 {
1981   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1982
1983   if (text_view->pixels_inside_wrap != pixels_inside_wrap)
1984     {
1985       text_view->pixels_inside_wrap = pixels_inside_wrap;
1986
1987       if (text_view->layout)
1988         {
1989           text_view->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
1990           gtk_text_layout_default_style_changed (text_view->layout);
1991         }
1992     }
1993   g_object_notify (G_OBJECT (text_view), "pixels_inside_wrap");
1994 }
1995
1996 /**
1997  * gtk_text_view_get_pixels_inside_wrap:
1998  * @text_view: a #GtkTextView
1999  * 
2000  * Gets the value set by gtk_text_view_set_pixels_inside_wrap().
2001  * 
2002  * Return value: default number of pixels of blank space between wrapped lines
2003  **/
2004 gint
2005 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
2006 {
2007   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2008
2009   return text_view->pixels_inside_wrap;
2010 }
2011
2012 /**
2013  * gtk_text_view_set_justification:
2014  * @text_view: a #GtkTextView
2015  * @justification: justification
2016  *
2017  * Sets the default justification of text in @text_view.
2018  * Tags in the view's buffer may override the default.
2019  * 
2020  **/
2021 void
2022 gtk_text_view_set_justification (GtkTextView     *text_view,
2023                                  GtkJustification justification)
2024 {
2025   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2026
2027   if (text_view->justify != justification)
2028     {
2029       text_view->justify = justification;
2030
2031       if (text_view->layout)
2032         {
2033           text_view->layout->default_style->justification = justification;
2034           gtk_text_layout_default_style_changed (text_view->layout);
2035         }
2036     }
2037
2038   g_object_notify (G_OBJECT (text_view), "justification");
2039 }
2040
2041 /**
2042  * gtk_text_view_get_justification:
2043  * @text_view: a #GtkTextView
2044  * 
2045  * Gets the default justification of paragraphs in @text_view.
2046  * Tags in the buffer may override the default.
2047  * 
2048  * Return value: default justification
2049  **/
2050 GtkJustification
2051 gtk_text_view_get_justification (GtkTextView *text_view)
2052 {
2053   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
2054
2055   return text_view->justify;
2056 }
2057
2058 /**
2059  * gtk_text_view_set_left_margin:
2060  * @text_view: a #GtkTextView
2061  * @left_margin: left margin in pixels
2062  * 
2063  * Sets the default left margin for text in @text_view.
2064  * Tags in the buffer may override the default.
2065  * 
2066  **/
2067 void
2068 gtk_text_view_set_left_margin (GtkTextView *text_view,
2069                                gint         left_margin)
2070 {
2071   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2072
2073   if (text_view->left_margin != left_margin)
2074     {
2075       text_view->left_margin = left_margin;
2076
2077       if (text_view->layout)
2078         {
2079           text_view->layout->default_style->left_margin = left_margin;
2080           gtk_text_layout_default_style_changed (text_view->layout);
2081         }
2082     }
2083
2084   g_object_notify (G_OBJECT (text_view), "left_margin");
2085 }
2086
2087 /**
2088  * gtk_text_view_get_left_margin:
2089  * @text_view: a #GtkTextView
2090  * 
2091  * Gets the default left margin size of paragraphs in the @text_view.
2092  * Tags in the buffer may override the default.
2093  * 
2094  * Return value: left margin in pixels
2095  **/
2096 gint
2097 gtk_text_view_get_left_margin (GtkTextView *text_view)
2098 {
2099   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2100
2101   return text_view->left_margin;
2102 }
2103
2104 /**
2105  * gtk_text_view_set_right_margin:
2106  * @text_view: a #GtkTextView
2107  * @right_margin: right margin in pixels
2108  *
2109  * Sets the default right margin for text in the text view.
2110  * Tags in the buffer may override the default.
2111  * 
2112  **/
2113 void
2114 gtk_text_view_set_right_margin (GtkTextView *text_view,
2115                                 gint         right_margin)
2116 {
2117   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2118
2119   if (text_view->right_margin != right_margin)
2120     {
2121       text_view->right_margin = right_margin;
2122
2123       if (text_view->layout)
2124         {
2125           text_view->layout->default_style->right_margin = right_margin;
2126           gtk_text_layout_default_style_changed (text_view->layout);
2127         }
2128     }
2129
2130   g_object_notify (G_OBJECT (text_view), "right_margin");
2131 }
2132
2133 /**
2134  * gtk_text_view_get_right_margin:
2135  * @text_view: a #GtkTextView
2136  * 
2137  * Gets the default right margin for text in @text_view. Tags
2138  * in the buffer may override the default.
2139  * 
2140  * Return value: right margin in pixels
2141  **/
2142 gint
2143 gtk_text_view_get_right_margin (GtkTextView *text_view)
2144 {
2145   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2146
2147   return text_view->right_margin;
2148 }
2149
2150 /**
2151  * gtk_text_view_set_indent:
2152  * @text_view: a #GtkTextView
2153  * @indent: indentation in pixels
2154  *
2155  * Sets the default indentation for paragraphs in @text_view.
2156  * Tags in the buffer may override the default.
2157  * 
2158  **/
2159 void
2160 gtk_text_view_set_indent (GtkTextView *text_view,
2161                           gint         indent)
2162 {
2163   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2164
2165   if (text_view->indent != indent)
2166     {
2167       text_view->indent = indent;
2168
2169       if (text_view->layout)
2170         {
2171           text_view->layout->default_style->indent = indent;
2172           gtk_text_layout_default_style_changed (text_view->layout);
2173         }
2174     }
2175   g_object_notify (G_OBJECT (text_view), "indent");
2176 }
2177
2178 /**
2179  * gtk_text_view_get_indent:
2180  * @text_view: a #GtkTextView
2181  * 
2182  * Gets the default indentation of paragraphs in @text_view.
2183  * Tags in the view's buffer may override the default.
2184  * The indentation may be negative.
2185  * 
2186  * Return value: number of pixels of indentation
2187  **/
2188 gint
2189 gtk_text_view_get_indent (GtkTextView *text_view)
2190 {
2191   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2192
2193   return text_view->indent;
2194 }
2195
2196 /**
2197  * gtk_text_view_set_tabs:
2198  * @text_view: a #GtkTextView
2199  * @tabs: tabs as a #PangoTabArray
2200  *
2201  * Sets the default tab stops for paragraphs in @text_view.
2202  * Tags in the buffer may override the default.
2203  * 
2204  **/
2205 void
2206 gtk_text_view_set_tabs (GtkTextView   *text_view,
2207                         PangoTabArray *tabs)
2208 {
2209   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2210
2211   if (text_view->tabs)
2212     pango_tab_array_free (text_view->tabs);
2213
2214   text_view->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
2215
2216   if (text_view->layout)
2217     {
2218       /* some unkosher futzing in internal struct details... */
2219       if (text_view->layout->default_style->tabs)
2220         pango_tab_array_free (text_view->layout->default_style->tabs);
2221
2222       text_view->layout->default_style->tabs =
2223         text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
2224
2225       gtk_text_layout_default_style_changed (text_view->layout);
2226     }
2227
2228   g_object_notify (G_OBJECT (text_view), "tabs");
2229 }
2230
2231 /**
2232  * gtk_text_view_get_tabs:
2233  * @text_view: a #GtkTextView
2234  * 
2235  * Gets the default tabs for @text_view. Tags in the buffer may
2236  * override the defaults. The returned array will be %NULL if
2237  * "standard" (8-space) tabs are used. Free the return value
2238  * with pango_tab_array_free().
2239  * 
2240  * Return value: copy of default tab array, or %NULL if "standard" tabs are used; must be freed with pango_tab_array_free().
2241  **/
2242 PangoTabArray*
2243 gtk_text_view_get_tabs (GtkTextView *text_view)
2244 {
2245   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
2246
2247   return text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
2248 }
2249
2250 /**
2251  * gtk_text_view_set_cursor_visible:
2252  * @text_view: a #GtkTextView
2253  * @setting: whether to show the insertion cursor
2254  *
2255  * Toggles whether the insertion point is displayed. A buffer with no editable
2256  * text probably shouldn't have a visible cursor, so you may want to turn
2257  * the cursor off.
2258  **/
2259 void
2260 gtk_text_view_set_cursor_visible    (GtkTextView   *text_view,
2261                                      gboolean       setting)
2262 {
2263   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2264
2265   setting = (setting != FALSE);
2266
2267   if (text_view->cursor_visible != setting)
2268     {
2269       text_view->cursor_visible = setting;
2270
2271       if (GTK_WIDGET_HAS_FOCUS (text_view))
2272         {
2273           if (text_view->layout)
2274             {
2275               gtk_text_layout_set_cursor_visible (text_view->layout, setting);
2276               gtk_text_view_check_cursor_blink (text_view);
2277             }
2278         }
2279     }
2280
2281   g_object_notify (G_OBJECT (text_view), "cursor_visible");
2282 }
2283
2284 /**
2285  * gtk_text_view_get_cursor_visible:
2286  * @text_view: a #GtkTextView
2287  *
2288  * Find out whether the cursor is being displayed.
2289  *
2290  * Return value: whether the insertion mark is visible
2291  **/
2292 gboolean
2293 gtk_text_view_get_cursor_visible    (GtkTextView   *text_view)
2294 {
2295   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2296
2297   return text_view->cursor_visible;
2298 }
2299
2300
2301 /**
2302  * gtk_text_view_place_cursor_onscreen:
2303  * @text_view: a #GtkTextView
2304  *
2305  * Moves the cursor to the currently visible region of the
2306  * buffer, it it isn't there already.
2307  *
2308  * Return value: TRUE if the cursor had to be moved.
2309  **/
2310 gboolean
2311 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
2312 {
2313   GtkTextIter insert;
2314
2315   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2316
2317   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2318                                     gtk_text_buffer_get_mark (get_buffer (text_view),
2319                                                               "insert"));
2320
2321   if (clamp_iter_onscreen (text_view, &insert))
2322     {
2323       gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
2324       return TRUE;
2325     }
2326   else
2327     return FALSE;
2328 }
2329
2330 static void
2331 gtk_text_view_remove_validate_idles (GtkTextView *text_view)
2332 {
2333   if (text_view->first_validate_idle != 0)
2334     {
2335       g_source_remove (text_view->first_validate_idle);
2336       text_view->first_validate_idle = 0;
2337     }
2338
2339   if (text_view->incremental_validate_idle != 0)
2340     {
2341       g_source_remove (text_view->incremental_validate_idle);
2342       text_view->incremental_validate_idle = 0;
2343     }
2344 }
2345
2346 static void
2347 gtk_text_view_destroy (GtkObject *object)
2348 {
2349   GtkTextView *text_view;
2350   GtkTextLayout *layout;
2351   
2352   text_view = GTK_TEXT_VIEW (object);
2353
2354   layout = text_view->layout;
2355   
2356   gtk_text_view_remove_validate_idles (text_view);
2357   gtk_text_view_set_buffer (text_view, NULL);
2358   gtk_text_view_destroy_layout (text_view);
2359
2360   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2361 }
2362
2363 static void
2364 gtk_text_view_finalize (GObject *object)
2365 {
2366   GtkTextView *text_view;
2367
2368   text_view = GTK_TEXT_VIEW (object);
2369
2370   g_return_if_fail (text_view->buffer == NULL);
2371
2372   gtk_text_view_destroy_layout (text_view);
2373   gtk_text_view_set_buffer (text_view, NULL);
2374   
2375   if (text_view->pending_scroll)
2376     {
2377       free_pending_scroll (text_view->pending_scroll);
2378       text_view->pending_scroll = NULL;
2379     }
2380   
2381   if (text_view->hadjustment)
2382     g_object_unref (G_OBJECT (text_view->hadjustment));
2383   if (text_view->vadjustment)
2384     g_object_unref (G_OBJECT (text_view->vadjustment));
2385
2386   text_window_free (text_view->text_window);
2387
2388   if (text_view->left_window)
2389     text_window_free (text_view->left_window);
2390
2391   if (text_view->top_window)
2392     text_window_free (text_view->top_window);
2393
2394   if (text_view->right_window)
2395     text_window_free (text_view->right_window);
2396
2397   if (text_view->bottom_window)
2398     text_window_free (text_view->bottom_window);
2399
2400   g_object_unref (G_OBJECT (text_view->im_context));
2401
2402   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
2403 }
2404
2405 static void
2406 gtk_text_view_set_property (GObject         *object,
2407                             guint            prop_id,
2408                             const GValue    *value,
2409                             GParamSpec      *pspec)
2410 {
2411   GtkTextView *text_view;
2412
2413   text_view = GTK_TEXT_VIEW (object);
2414
2415   switch (prop_id)
2416     {
2417     case PROP_PIXELS_ABOVE_LINES:
2418       gtk_text_view_set_pixels_above_lines (text_view, g_value_get_int (value));
2419       break;
2420
2421     case PROP_PIXELS_BELOW_LINES:
2422       gtk_text_view_set_pixels_below_lines (text_view, g_value_get_int (value));
2423       break;
2424
2425     case PROP_PIXELS_INSIDE_WRAP:
2426       gtk_text_view_set_pixels_inside_wrap (text_view, g_value_get_int (value));
2427       break;
2428
2429     case PROP_EDITABLE:
2430       gtk_text_view_set_editable (text_view, g_value_get_boolean (value));
2431       break;
2432
2433     case PROP_WRAP_MODE:
2434       gtk_text_view_set_wrap_mode (text_view, g_value_get_enum (value));
2435       break;
2436       
2437     case PROP_JUSTIFICATION:
2438       gtk_text_view_set_justification (text_view, g_value_get_enum (value));
2439       break;
2440
2441     case PROP_LEFT_MARGIN:
2442       gtk_text_view_set_left_margin (text_view, g_value_get_int (value));
2443       break;
2444
2445     case PROP_RIGHT_MARGIN:
2446       gtk_text_view_set_right_margin (text_view, g_value_get_int (value));
2447       break;
2448
2449     case PROP_INDENT:
2450       gtk_text_view_set_indent (text_view, g_value_get_int (value));
2451       break;
2452
2453     case PROP_TABS:
2454       gtk_text_view_set_tabs (text_view, g_value_get_object (value));
2455       break;
2456
2457     case PROP_CURSOR_VISIBLE:
2458       gtk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
2459       break;
2460
2461     default:
2462       g_assert_not_reached ();
2463       break;
2464     }
2465 }
2466
2467 static void
2468 gtk_text_view_get_property (GObject         *object,
2469                             guint            prop_id,
2470                             GValue          *value,
2471                             GParamSpec      *pspec)
2472 {
2473   GtkTextView *text_view;
2474
2475   text_view = GTK_TEXT_VIEW (object);
2476
2477   switch (prop_id)
2478     {
2479     case PROP_PIXELS_ABOVE_LINES:
2480       g_value_set_int (value, text_view->pixels_above_lines);
2481       break;
2482
2483     case PROP_PIXELS_BELOW_LINES:
2484       g_value_set_int (value, text_view->pixels_below_lines);
2485       break;
2486
2487     case PROP_PIXELS_INSIDE_WRAP:
2488       g_value_set_int (value, text_view->pixels_inside_wrap);
2489       break;
2490
2491     case PROP_EDITABLE:
2492       g_value_set_boolean (value, text_view->editable);
2493       break;
2494       
2495     case PROP_WRAP_MODE:
2496       g_value_set_enum (value, text_view->wrap_mode);
2497       break;
2498
2499     case PROP_JUSTIFICATION:
2500       g_value_set_enum (value, text_view->justify);
2501       break;
2502
2503     case PROP_LEFT_MARGIN:
2504       g_value_set_int (value, text_view->left_margin);
2505       break;
2506
2507     case PROP_RIGHT_MARGIN:
2508       g_value_set_int (value, text_view->right_margin);
2509       break;
2510
2511     case PROP_INDENT:
2512       g_value_set_int (value, text_view->indent);
2513       break;
2514
2515     case PROP_TABS:
2516       g_value_set_object (value, gtk_text_view_get_tabs (text_view));
2517       break;
2518
2519     case PROP_CURSOR_VISIBLE:
2520       g_value_set_boolean (value, text_view->cursor_visible);
2521       break;
2522
2523     default:
2524       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2525       break;
2526     }
2527 }
2528
2529 static void
2530 gtk_text_view_size_request (GtkWidget      *widget,
2531                             GtkRequisition *requisition)
2532 {
2533   GtkTextView *text_view;
2534   GSList *tmp_list;
2535   gint focus_edge_width;
2536   gint focus_width;
2537   gboolean interior_focus;
2538   
2539   text_view = GTK_TEXT_VIEW (widget);
2540
2541   gtk_widget_style_get (widget,
2542                         "interior_focus", &interior_focus,
2543                         "focus_line_width", &focus_width,
2544                         NULL);
2545
2546   if (interior_focus)
2547     focus_edge_width = 0;
2548   else
2549     focus_edge_width = focus_width;
2550
2551   if (text_view->layout)
2552     {
2553       text_view->text_window->requisition.width = text_view->layout->width;
2554       text_view->text_window->requisition.height = text_view->layout->height;
2555     }
2556   else
2557     {
2558       text_view->text_window->requisition.width = 0;
2559       text_view->text_window->requisition.height = 0;
2560     }
2561   
2562   requisition->width = text_view->text_window->requisition.width + focus_edge_width * 2;
2563   requisition->height = text_view->text_window->requisition.height + focus_edge_width * 2;
2564
2565   if (text_view->left_window)
2566     requisition->width += text_view->left_window->requisition.width;
2567
2568   if (text_view->right_window)
2569     requisition->width += text_view->right_window->requisition.width;
2570
2571   if (text_view->top_window)
2572     requisition->height += text_view->top_window->requisition.height;
2573
2574   if (text_view->bottom_window)
2575     requisition->height += text_view->bottom_window->requisition.height;
2576
2577   requisition->width += GTK_CONTAINER (text_view)->border_width * 2;
2578   requisition->height += GTK_CONTAINER (text_view)->border_width * 2;
2579   
2580   tmp_list = text_view->children;
2581   while (tmp_list != NULL)
2582     {
2583       GtkTextViewChild *child = tmp_list->data;
2584
2585       if (child->anchor)
2586         {
2587           GtkRequisition child_req;
2588           GtkRequisition old_req;
2589
2590           gtk_widget_get_child_requisition (child->widget, &old_req);
2591           
2592           gtk_widget_size_request (child->widget, &child_req);
2593
2594           gtk_widget_get_child_requisition (child->widget, &child_req);
2595
2596           /* Invalidate layout lines if required */
2597           if (text_view->layout &&
2598               (old_req.width != child_req.width ||
2599                old_req.height != child_req.height))
2600             gtk_text_child_anchor_queue_resize (child->anchor,
2601                                                 text_view->layout);
2602         }
2603       else
2604         {
2605           GtkRequisition child_req;
2606           
2607           gtk_widget_size_request (child->widget, &child_req);
2608         }
2609
2610       tmp_list = g_slist_next (tmp_list);
2611     }
2612 }
2613
2614 static void
2615 gtk_text_view_compute_child_allocation (GtkTextView      *text_view,
2616                                         GtkTextViewChild *vc,
2617                                         GtkAllocation    *allocation)
2618 {
2619   gint buffer_y;
2620   GtkTextIter iter;
2621   GtkRequisition req;
2622   
2623   gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2624                                             &iter,
2625                                             vc->anchor);
2626
2627   gtk_text_layout_get_line_yrange (text_view->layout, &iter,
2628                                    &buffer_y, NULL);
2629
2630   buffer_y += vc->from_top_of_line;
2631
2632   allocation->x = vc->from_left_of_buffer - text_view->xoffset;
2633   allocation->y = buffer_y - text_view->yoffset;
2634
2635   gtk_widget_get_child_requisition (vc->widget, &req);
2636   allocation->width = req.width;
2637   allocation->height = req.height;
2638 }
2639
2640 static void
2641 gtk_text_view_update_child_allocation (GtkTextView      *text_view,
2642                                        GtkTextViewChild *vc)
2643 {
2644   GtkAllocation allocation;
2645
2646   gtk_text_view_compute_child_allocation (text_view, vc, &allocation);
2647   
2648   gtk_widget_size_allocate (vc->widget, &allocation);
2649
2650 #if 0
2651   g_print ("allocation for %p allocated to %d,%d yoffset = %d\n",
2652            vc->widget,
2653            vc->widget->allocation.x,
2654            vc->widget->allocation.y,
2655            text_view->yoffset);
2656 #endif
2657 }
2658
2659 static void
2660 gtk_text_view_child_allocated (GtkTextLayout *layout,
2661                                GtkWidget     *child,
2662                                gint           x,
2663                                gint           y,
2664                                gpointer       data)
2665 {
2666   GtkTextViewChild *vc = NULL;
2667   GtkTextView *text_view = data;
2668   
2669   /* x,y is the position of the child from the top of the line, and
2670    * from the left of the buffer. We have to translate that into text
2671    * window coordinates, then size_allocate the child.
2672    */
2673
2674   vc = g_object_get_data (G_OBJECT (child),
2675                           "gtk-text-view-child");
2676
2677   g_assert (vc != NULL);
2678
2679   DV (g_print ("child allocated at %d,%d\n", x, y));
2680   
2681   vc->from_left_of_buffer = x;
2682   vc->from_top_of_line = y;
2683
2684   gtk_text_view_update_child_allocation (text_view, vc);
2685 }
2686
2687 static void
2688 gtk_text_view_allocate_children (GtkTextView *text_view)
2689 {
2690   GSList *tmp_list;
2691
2692   DV(g_print(G_STRLOC"\n"));
2693   
2694   tmp_list = text_view->children;
2695   while (tmp_list != NULL)
2696     {
2697       GtkTextViewChild *child = tmp_list->data;
2698
2699       if (child->anchor)
2700         {
2701           /* We need to force-validate the regions containing
2702            * children.
2703            */
2704           GtkTextIter child_loc;
2705           gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2706                                                     &child_loc,
2707                                                     child->anchor);
2708
2709           gtk_text_layout_validate_yrange (text_view->layout,
2710                                            &child_loc,
2711                                            0, 1);
2712         }
2713       else
2714         {
2715           GtkAllocation allocation;          
2716           GtkRequisition child_req;
2717              
2718           g_assert (child != NULL);
2719           
2720           allocation.x = child->x;
2721           allocation.y = child->y;
2722
2723           gtk_widget_get_child_requisition (child->widget, &child_req);
2724           
2725           allocation.width = child_req.width;
2726           allocation.height = child_req.height;
2727           
2728           gtk_widget_size_allocate (child->widget, &allocation);          
2729         }
2730
2731       tmp_list = g_slist_next (tmp_list);
2732     }
2733 }
2734
2735 static void
2736 gtk_text_view_size_allocate (GtkWidget *widget,
2737                              GtkAllocation *allocation)
2738 {
2739   GtkTextView *text_view;
2740   GtkTextIter first_para;
2741   gint y;
2742   GtkAdjustment *vadj;
2743   gboolean yoffset_changed = FALSE;
2744   gint width, height;
2745   GdkRectangle text_rect;
2746   GdkRectangle left_rect;
2747   GdkRectangle right_rect;
2748   GdkRectangle top_rect;
2749   GdkRectangle bottom_rect;
2750   gint focus_edge_width;
2751   gint focus_width;
2752   gboolean interior_focus;
2753   gboolean size_changed;
2754   
2755   text_view = GTK_TEXT_VIEW (widget);
2756
2757   DV(g_print(G_STRLOC"\n"));
2758
2759   size_changed =
2760     widget->allocation.width != allocation->width ||
2761     widget->allocation.height != allocation->height;
2762   
2763   widget->allocation = *allocation;
2764
2765   if (GTK_WIDGET_REALIZED (widget))
2766     {
2767       gdk_window_move_resize (widget->window,
2768                               allocation->x, allocation->y,
2769                               allocation->width, allocation->height);
2770     }
2771
2772   /* distribute width/height among child windows. Ensure all
2773    * windows get at least a 1x1 allocation.
2774    */
2775
2776   gtk_widget_style_get (widget,
2777                         "interior_focus", &interior_focus,
2778                         "focus_line_width", &focus_width,
2779                         NULL);
2780
2781   if (interior_focus)
2782     focus_edge_width = 0;
2783   else
2784     focus_edge_width = focus_width;
2785   
2786   width = allocation->width - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
2787
2788   if (text_view->left_window)
2789     left_rect.width = text_view->left_window->requisition.width;
2790   else
2791     left_rect.width = 0;
2792
2793   width -= left_rect.width;
2794
2795   if (text_view->right_window)
2796     right_rect.width = text_view->right_window->requisition.width;
2797   else
2798     right_rect.width = 0;
2799
2800   width -= right_rect.width;
2801
2802   text_rect.width = MAX (1, width);
2803
2804   top_rect.width = text_rect.width;
2805   bottom_rect.width = text_rect.width;
2806
2807
2808   height = allocation->height - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
2809
2810   if (text_view->top_window)
2811     top_rect.height = text_view->top_window->requisition.height;
2812   else
2813     top_rect.height = 0;
2814
2815   height -= top_rect.height;
2816
2817   if (text_view->bottom_window)
2818     bottom_rect.height = text_view->bottom_window->requisition.height;
2819   else
2820     bottom_rect.height = 0;
2821
2822   height -= bottom_rect.height;
2823
2824   text_rect.height = MAX (1, height);
2825
2826   left_rect.height = text_rect.height;
2827   right_rect.height = text_rect.height;
2828
2829   /* Origins */
2830   left_rect.x = focus_edge_width + GTK_CONTAINER (text_view)->border_width;
2831   top_rect.y = focus_edge_width + GTK_CONTAINER (text_view)->border_width;
2832
2833   text_rect.x = left_rect.x + left_rect.width;
2834   text_rect.y = top_rect.y + top_rect.height;
2835
2836   left_rect.y = text_rect.y;
2837   right_rect.y = text_rect.y;
2838
2839   top_rect.x = text_rect.x;
2840   bottom_rect.x = text_rect.x;
2841
2842   right_rect.x = text_rect.x + text_rect.width;
2843   bottom_rect.y = text_rect.y + text_rect.height;
2844
2845   text_window_size_allocate (text_view->text_window,
2846                              &text_rect);
2847
2848   if (text_view->left_window)
2849     text_window_size_allocate (text_view->left_window,
2850                                &left_rect);
2851
2852   if (text_view->right_window)
2853     text_window_size_allocate (text_view->right_window,
2854                                &right_rect);
2855
2856   if (text_view->top_window)
2857     text_window_size_allocate (text_view->top_window,
2858                                &top_rect);
2859
2860   if (text_view->bottom_window)
2861     text_window_size_allocate (text_view->bottom_window,
2862                                &bottom_rect);
2863
2864   gtk_text_view_update_layout_width (text_view);
2865   
2866   /* Note that this will do some layout validation */
2867   gtk_text_view_allocate_children (text_view);
2868
2869   /* Now adjust the value of the adjustment to keep the cursor at the
2870    * same place in the buffer
2871    */
2872   gtk_text_view_get_first_para_iter (text_view, &first_para);
2873   gtk_text_layout_get_line_yrange (text_view->layout, &first_para, &y, NULL);
2874
2875   y += text_view->first_para_pixels;
2876
2877   /* Ensure h/v adj exist */
2878   get_hadjustment (text_view);
2879   get_vadjustment (text_view);
2880
2881   vadj = text_view->vadjustment;
2882   if (y > vadj->upper - vadj->page_size)
2883     y = MAX (0, vadj->upper - vadj->page_size);
2884
2885   if (y != text_view->yoffset)
2886     {
2887       vadj->value = text_view->yoffset = y;
2888       yoffset_changed = TRUE;
2889     }
2890
2891   text_view->hadjustment->page_size = SCREEN_WIDTH (text_view);
2892   text_view->hadjustment->page_increment = SCREEN_WIDTH (text_view) / 2;
2893   text_view->hadjustment->lower = 0;
2894   text_view->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
2895                                        text_view->width);
2896   gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
2897
2898   text_view->vadjustment->page_size = SCREEN_HEIGHT (text_view);
2899   text_view->vadjustment->page_increment = SCREEN_HEIGHT (text_view) / 2;
2900   text_view->vadjustment->lower = 0;
2901   text_view->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
2902                                        text_view->height);
2903   gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
2904
2905   if (yoffset_changed)
2906     gtk_adjustment_value_changed (vadj);
2907
2908   if (text_view->first_validate_idle != 0)
2909     {
2910       /* The GTK resize loop processes all the pending exposes right
2911        * after doing the resize stuff, so the idle sizer won't have a
2912        * chance to run. So we do the work here. 
2913        */
2914
2915       g_source_remove (text_view->first_validate_idle);
2916       text_view->first_validate_idle = 0;
2917       
2918       if (!gtk_text_view_flush_scroll (text_view))
2919         gtk_text_view_validate_onscreen (text_view);
2920     }
2921
2922   /* widget->window doesn't get auto-redrawn as the layout is computed, so has to
2923    * be invalidated
2924    */
2925   if (size_changed && GTK_WIDGET_REALIZED (widget))
2926     gdk_window_invalidate_rect (widget->window, NULL, FALSE);
2927 }
2928
2929 static void
2930 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
2931                                    GtkTextIter *iter)
2932 {
2933   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
2934                                     text_view->first_para_mark);
2935 }
2936
2937 static void
2938 gtk_text_view_validate_onscreen (GtkTextView *text_view)
2939 {
2940   GtkWidget *widget = GTK_WIDGET (text_view);
2941   
2942   DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
2943   
2944   if (SCREEN_HEIGHT (widget) > 0)
2945     {
2946       GtkTextIter first_para;
2947
2948       /* Be sure we've validated the stuff onscreen; if we
2949        * scrolled, these calls won't have any effect, because
2950        * they were called in the recursive validate_onscreen
2951        */
2952       gtk_text_view_get_first_para_iter (text_view, &first_para);
2953
2954       gtk_text_layout_validate_yrange (text_view->layout,
2955                                        &first_para,
2956                                        0,
2957                                        text_view->first_para_pixels +
2958                                        SCREEN_HEIGHT (widget));
2959     }
2960
2961   text_view->onscreen_validated = TRUE;
2962
2963   DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
2964   
2965   /* This can have the odd side effect of triggering a scroll, which should
2966    * flip "onscreen_validated" back to FALSE, but should also get us
2967    * back into this function to turn it on again.
2968    */
2969   gtk_text_view_update_adjustments (text_view);
2970
2971   g_assert (text_view->onscreen_validated);
2972 }
2973
2974 static gboolean
2975 first_validate_callback (gpointer data)
2976 {
2977   GtkTextView *text_view = data;
2978
2979   GDK_THREADS_ENTER ();
2980   
2981   /* Note that some of this code is duplicated at the end of size_allocate,
2982    * keep in sync with that.
2983    */
2984   
2985   DV(g_print(G_STRLOC"\n"));
2986
2987   /* Do this first, which means that if an "invalidate"
2988    * occurs during any of this process, a new first_validate_callback
2989    * will be installed, and we'll start again.
2990    */
2991   text_view->first_validate_idle = 0;
2992   
2993   /* be sure we have up-to-date screen size set on the
2994    * layout.
2995    */
2996   gtk_text_view_update_layout_width (text_view);
2997
2998   /* Bail out if we invalidated stuff; scrolling right away will just
2999    * confuse the issue.
3000    */
3001   if (text_view->first_validate_idle != 0)
3002     {
3003       DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
3004     }
3005   else
3006     {
3007       /* scroll to any marks, if that's pending. This can
3008        * jump us to the validation codepath used for scrolling
3009        * onscreen, if so we bail out.
3010        */
3011       if (!gtk_text_view_flush_scroll (text_view))
3012         gtk_text_view_validate_onscreen (text_view);
3013       
3014       DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
3015       
3016       g_assert (text_view->onscreen_validated);
3017       
3018     }
3019   
3020   GDK_THREADS_LEAVE ();
3021   
3022   return FALSE;
3023 }
3024
3025 static gboolean
3026 incremental_validate_callback (gpointer data)
3027 {
3028   GtkTextView *text_view = data;
3029   gboolean result = TRUE;
3030
3031   GDK_THREADS_ENTER ();
3032   
3033   DV(g_print(G_STRLOC"\n"));
3034   
3035   gtk_text_layout_validate (text_view->layout, 2000);
3036
3037   gtk_text_view_update_adjustments (text_view);
3038   
3039   if (gtk_text_layout_is_valid (text_view->layout))
3040     {
3041       text_view->incremental_validate_idle = 0;
3042       result = FALSE;
3043     }
3044
3045   GDK_THREADS_LEAVE ();
3046
3047   return result;
3048 }
3049
3050 static void
3051 gtk_text_view_invalidate (GtkTextView *text_view)
3052 {
3053   text_view->onscreen_validated = FALSE;
3054   
3055   DV(g_print(">Invalidate, onscreen_validated = FALSE ("G_STRLOC")\n"));
3056   
3057   if (!text_view->first_validate_idle)
3058     {
3059       text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
3060       DV (g_print (G_STRLOC": adding first validate idle %d\n",
3061                    text_view->first_validate_idle));
3062     }
3063       
3064   if (!text_view->incremental_validate_idle)
3065     {
3066       text_view->incremental_validate_idle = g_idle_add_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
3067       DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
3068                    text_view->incremental_validate_idle));
3069     }
3070 }
3071
3072 static void
3073 invalidated_handler (GtkTextLayout *layout,
3074                      gpointer       data)
3075 {
3076   GtkTextView *text_view;
3077
3078   text_view = GTK_TEXT_VIEW (data);
3079
3080   gtk_text_view_invalidate (text_view);
3081 }
3082
3083 static void
3084 changed_handler (GtkTextLayout     *layout,
3085                  gint               start_y,
3086                  gint               old_height,
3087                  gint               new_height,
3088                  gpointer           data)
3089 {
3090   GtkTextView *text_view;
3091   GtkWidget *widget;
3092   GdkRectangle visible_rect;
3093   GdkRectangle redraw_rect;
3094   
3095   text_view = GTK_TEXT_VIEW (data);
3096   widget = GTK_WIDGET (data);
3097   
3098   DV(g_print(">Lines Validated ("G_STRLOC")\n"));
3099
3100   if (GTK_WIDGET_REALIZED (text_view))
3101     {      
3102       gtk_text_view_get_visible_rect (text_view, &visible_rect);
3103
3104       redraw_rect.x = visible_rect.x;
3105       redraw_rect.width = visible_rect.width;
3106       redraw_rect.y = start_y;
3107
3108       if (old_height == new_height)
3109         redraw_rect.height = old_height;
3110       else
3111         redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
3112
3113       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
3114         {
3115           /* text_window_invalidate_rect() takes buffer coordinates */
3116           text_window_invalidate_rect (text_view->text_window,
3117                                        &redraw_rect);
3118
3119           DV(g_print(" invalidated rect: %d,%d %d x %d\n",
3120                      redraw_rect.x,
3121                      redraw_rect.y,
3122                      redraw_rect.width,
3123                      redraw_rect.height));
3124           
3125           if (text_view->left_window)
3126             text_window_invalidate_rect (text_view->left_window,
3127                                          &redraw_rect);
3128           if (text_view->right_window)
3129             text_window_invalidate_rect (text_view->right_window,
3130                                          &redraw_rect);
3131           if (text_view->top_window)
3132             text_window_invalidate_rect (text_view->top_window,
3133                                          &redraw_rect);
3134           if (text_view->bottom_window)
3135             text_window_invalidate_rect (text_view->bottom_window,
3136                                          &redraw_rect);
3137
3138           gtk_text_view_update_im_spot_location (text_view);
3139         }
3140     }
3141   
3142   if (old_height != new_height)
3143     {
3144       gboolean yoffset_changed = FALSE;
3145       GSList *tmp_list;
3146       int new_first_para_top;
3147       int old_first_para_top;
3148       GtkTextIter first;
3149       
3150       /* If the bottom of the old area was above the top of the
3151        * screen, we need to scroll to keep the current top of the
3152        * screen in place.  Remember that first_para_pixels is the
3153        * position of the top of the screen in coordinates relative to
3154        * the first paragraph onscreen.
3155        *
3156        * In short we are adding the height delta of the portion of the
3157        * changed region above first_para_mark to text_view->yoffset.
3158        */
3159       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &first,
3160                                         text_view->first_para_mark);
3161
3162       gtk_text_layout_get_line_yrange (layout, &first, &new_first_para_top, NULL);
3163
3164       old_first_para_top = text_view->yoffset - text_view->first_para_pixels;
3165
3166       if (new_first_para_top != old_first_para_top)
3167         {
3168           text_view->yoffset += new_first_para_top - old_first_para_top;
3169           
3170           get_vadjustment (text_view)->value = text_view->yoffset;
3171           yoffset_changed = TRUE;
3172         }
3173
3174       if (yoffset_changed)
3175         gtk_adjustment_value_changed (get_vadjustment (text_view));
3176
3177       /* FIXME be smarter about which anchored widgets we update */
3178
3179       tmp_list = text_view->children;
3180       while (tmp_list != NULL)
3181         {
3182           GtkTextViewChild *child = tmp_list->data;
3183
3184           if (child->anchor)
3185             gtk_text_view_update_child_allocation (text_view, child);
3186
3187           tmp_list = g_slist_next (tmp_list);
3188         }
3189     }
3190
3191   {
3192     GtkRequisition old_req;
3193     GtkRequisition new_req;
3194
3195     old_req = widget->requisition;
3196
3197     /* Use this instead of gtk_widget_size_request wrapper
3198      * to avoid the optimization which just returns widget->requisition
3199      * if a resize hasn't been queued.
3200      */
3201     GTK_WIDGET_GET_CLASS (widget)->size_request (widget, &new_req);
3202
3203     if (old_req.width != new_req.width ||
3204         old_req.height != new_req.height)
3205       gtk_widget_queue_resize (widget);
3206   }
3207 }
3208
3209 static void
3210 gtk_text_view_realize_cursor_gc (GtkTextView *text_view)
3211 {
3212   GdkColor *cursor_color;
3213   GdkColor red = { 0, 0xffff, 0x0000, 0x0000 };
3214   
3215   if (text_view->cursor_gc)
3216     gdk_gc_unref (text_view->cursor_gc);
3217
3218   gtk_widget_style_get (GTK_WIDGET (text_view), "cursor_color", &cursor_color, NULL);
3219
3220   if (!cursor_color)
3221     cursor_color = &red;
3222
3223   text_view->cursor_gc = gdk_gc_new (text_view->text_window->bin_window);
3224   gdk_gc_set_rgb_fg_color (text_view->cursor_gc, cursor_color);
3225 }
3226
3227 static void
3228 gtk_text_view_realize (GtkWidget *widget)
3229 {
3230   GtkTextView *text_view;
3231   GdkWindowAttr attributes;
3232   gint attributes_mask;
3233   GSList *tmp_list;
3234   
3235   text_view = GTK_TEXT_VIEW (widget);
3236   GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
3237
3238   attributes.window_type = GDK_WINDOW_CHILD;
3239   attributes.x = widget->allocation.x;
3240   attributes.y = widget->allocation.y;
3241   attributes.width = widget->allocation.width;
3242   attributes.height = widget->allocation.height;
3243   attributes.wclass = GDK_INPUT_OUTPUT;
3244   attributes.visual = gtk_widget_get_visual (widget);
3245   attributes.colormap = gtk_widget_get_colormap (widget);
3246   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
3247
3248   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3249
3250   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
3251                                    &attributes, attributes_mask);
3252   gdk_window_set_user_data (widget->window, widget);
3253
3254   /* must come before text_window_realize calls */
3255   widget->style = gtk_style_attach (widget->style, widget->window);
3256
3257   gdk_window_set_background (widget->window,
3258                              &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3259
3260   text_window_realize (text_view->text_window, widget->window);
3261
3262   if (text_view->left_window)
3263     text_window_realize (text_view->left_window,
3264                          widget->window);
3265
3266   if (text_view->top_window)
3267     text_window_realize (text_view->top_window,
3268                          widget->window);
3269
3270   if (text_view->right_window)
3271     text_window_realize (text_view->right_window,
3272                          widget->window);
3273
3274   if (text_view->bottom_window)
3275     text_window_realize (text_view->bottom_window,
3276                          widget->window);
3277
3278   gtk_text_view_realize_cursor_gc (text_view);
3279
3280   gtk_text_view_ensure_layout (text_view);
3281
3282   if (text_view->buffer)
3283     gtk_text_buffer_add_selection_clipboard (text_view->buffer,
3284                                              gtk_clipboard_get (GDK_SELECTION_PRIMARY));
3285
3286   tmp_list = text_view->children;
3287   while (tmp_list != NULL)
3288     {
3289       GtkTextViewChild *vc = tmp_list->data;
3290       
3291       text_view_child_set_parent_window (text_view, vc);
3292       
3293       tmp_list = tmp_list->next;
3294     }
3295 }
3296
3297 static void
3298 gtk_text_view_unrealize (GtkWidget *widget)
3299 {
3300   GtkTextView *text_view;
3301   
3302   text_view = GTK_TEXT_VIEW (widget);
3303
3304   if (text_view->buffer)
3305     gtk_text_buffer_remove_selection_clipboard (text_view->buffer,
3306                                                 gtk_clipboard_get (GDK_SELECTION_PRIMARY));
3307
3308   if (text_view->cursor_gc)
3309     {
3310       gdk_gc_unref (text_view->cursor_gc);
3311       text_view->cursor_gc = NULL;
3312     }
3313
3314   gtk_text_view_remove_validate_idles (text_view);
3315
3316   if (text_view->popup_menu)
3317     {
3318       gtk_widget_destroy (text_view->popup_menu);
3319       text_view->popup_menu = NULL;
3320     }
3321
3322   text_window_unrealize (text_view->text_window);
3323
3324   if (text_view->left_window)
3325     text_window_unrealize (text_view->left_window);
3326
3327   if (text_view->top_window)
3328     text_window_unrealize (text_view->top_window);
3329
3330   if (text_view->right_window)
3331     text_window_unrealize (text_view->right_window);
3332
3333   if (text_view->bottom_window)
3334     text_window_unrealize (text_view->bottom_window);
3335
3336   gtk_text_view_destroy_layout (text_view);
3337   
3338   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
3339 }
3340
3341 static void
3342 gtk_text_view_style_set (GtkWidget *widget,
3343                          GtkStyle  *previous_style)
3344 {
3345   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3346
3347   if (GTK_WIDGET_REALIZED (widget))
3348     {
3349       gdk_window_set_background (widget->window,
3350                                  &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3351
3352       gdk_window_set_background (text_view->text_window->bin_window,
3353                                  &widget->style->base[GTK_WIDGET_STATE (widget)]);
3354
3355       if (text_view->left_window)
3356         gdk_window_set_background (text_view->left_window->bin_window,
3357                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3358       if (text_view->right_window)
3359         gdk_window_set_background (text_view->right_window->bin_window,
3360                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3361
3362       if (text_view->top_window)
3363         gdk_window_set_background (text_view->top_window->bin_window,
3364                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3365
3366       if (text_view->bottom_window)
3367         gdk_window_set_background (text_view->bottom_window->bin_window,
3368                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3369       
3370       gtk_text_view_realize_cursor_gc (text_view);
3371     }
3372
3373   if (text_view->layout && previous_style)
3374     {
3375       gtk_text_view_set_attributes_from_style (text_view,
3376                                                text_view->layout->default_style,
3377                                                widget->style);
3378       gtk_text_layout_default_style_changed (text_view->layout);
3379     }
3380 }
3381
3382 static void
3383 gtk_text_view_direction_changed (GtkWidget        *widget,
3384                                  GtkTextDirection  previous_direction)
3385 {
3386   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3387
3388   if (text_view->layout)
3389     {
3390       text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
3391       gtk_text_layout_default_style_changed (text_view->layout);
3392     }
3393 }
3394
3395 /*
3396  * Events
3397  */
3398
3399 static gboolean
3400 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
3401 {
3402   if (event)
3403     switch (event->type)
3404       {
3405       case GDK_MOTION_NOTIFY:
3406         *x = event->motion.x;
3407         *y = event->motion.y;
3408         return TRUE;
3409         break;
3410
3411       case GDK_BUTTON_PRESS:
3412       case GDK_2BUTTON_PRESS:
3413       case GDK_3BUTTON_PRESS:
3414       case GDK_BUTTON_RELEASE:
3415         *x = event->button.x;
3416         *y = event->button.y;
3417         return TRUE;
3418         break;
3419
3420       case GDK_KEY_PRESS:
3421       case GDK_KEY_RELEASE:
3422       case GDK_ENTER_NOTIFY:
3423       case GDK_LEAVE_NOTIFY:
3424       case GDK_PROPERTY_NOTIFY:
3425       case GDK_SELECTION_CLEAR:
3426       case GDK_SELECTION_REQUEST:
3427       case GDK_SELECTION_NOTIFY:
3428       case GDK_PROXIMITY_IN:
3429       case GDK_PROXIMITY_OUT:
3430       case GDK_DRAG_ENTER:
3431       case GDK_DRAG_LEAVE:
3432       case GDK_DRAG_MOTION:
3433       case GDK_DRAG_STATUS:
3434       case GDK_DROP_START:
3435       case GDK_DROP_FINISHED:
3436       default:
3437         return FALSE;
3438         break;
3439       }
3440
3441   return FALSE;
3442 }
3443
3444 static gint
3445 emit_event_on_tags (GtkWidget   *widget,
3446                     GdkEvent    *event,
3447                     GtkTextIter *iter)
3448 {
3449   GSList *tags;
3450   GSList *tmp;
3451   gboolean retval = FALSE;
3452   GtkTextView *text_view;
3453
3454   text_view = GTK_TEXT_VIEW (widget);
3455
3456   tags = gtk_text_iter_get_tags (iter);
3457
3458   tmp = tags;
3459   while (tmp != NULL)
3460     {
3461       GtkTextTag *tag = tmp->data;
3462
3463       if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
3464         {
3465           retval = TRUE;
3466           break;
3467         }
3468
3469       tmp = g_slist_next (tmp);
3470     }
3471
3472   g_slist_free (tags);
3473
3474   return retval;
3475 }
3476
3477 static gint
3478 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
3479 {
3480   GtkTextView *text_view;
3481   gint x = 0, y = 0;
3482
3483   text_view = GTK_TEXT_VIEW (widget);
3484
3485   if (text_view->layout == NULL ||
3486       get_buffer (text_view) == NULL)
3487     return FALSE;
3488
3489   if (event->any.window != text_view->text_window->bin_window)
3490     return FALSE;
3491
3492   if (get_event_coordinates (event, &x, &y))
3493     {
3494       GtkTextIter iter;
3495
3496       x += text_view->xoffset;
3497       y += text_view->yoffset;
3498
3499       /* FIXME this is slow and we do it twice per event.
3500        * My favorite solution is to have GtkTextLayout cache
3501        * the last couple lookups.
3502        */
3503       gtk_text_layout_get_iter_at_pixel (text_view->layout,
3504                                          &iter,
3505                                          x, y);
3506
3507       return emit_event_on_tags (widget, event, &iter);
3508     }
3509   else if (event->type == GDK_KEY_PRESS ||
3510            event->type == GDK_KEY_RELEASE)
3511     {
3512       GtkTextMark *insert;
3513       GtkTextIter iter;
3514
3515       insert = gtk_text_buffer_get_mark (get_buffer (text_view),
3516                                          "insert");
3517
3518       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
3519
3520       return emit_event_on_tags (widget, event, &iter);
3521     }
3522   else
3523     return FALSE;
3524 }
3525
3526 static gint
3527 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
3528 {
3529   gboolean retval = FALSE;
3530   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3531   GtkTextMark *insert;
3532   GtkTextIter iter;
3533   
3534   if (text_view->layout == NULL ||
3535       get_buffer (text_view) == NULL)
3536     return FALSE;
3537
3538   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
3539   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
3540   if (gtk_text_iter_can_insert (&iter, text_view->editable) &&
3541       gtk_im_context_filter_keypress (text_view->im_context, event))
3542     {
3543       text_view->need_im_reset = TRUE;
3544       retval = TRUE;
3545     }
3546   else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
3547            GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
3548     retval = TRUE;
3549   else if (event->keyval == GDK_Return ||
3550            event->keyval == GDK_KP_Enter)
3551     {
3552       gtk_text_view_commit_text (text_view, "\n");
3553       retval = TRUE;
3554     }
3555   /* Pass through Tab as literal tab, unless Control is held down */
3556   else if ((event->keyval == GDK_Tab ||
3557             event->keyval == GDK_KP_Tab ||
3558             event->keyval == GDK_ISO_Left_Tab) &&
3559            !(event->state & GDK_CONTROL_MASK))
3560     {
3561       gtk_text_view_commit_text (text_view, "\t");
3562       retval = TRUE;
3563     }
3564   else
3565     retval = FALSE;
3566
3567   gtk_text_view_pend_cursor_blink (text_view);
3568
3569   return retval;
3570 }
3571
3572 static gint
3573 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
3574 {
3575   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3576   GtkTextMark *insert;
3577   GtkTextIter iter;
3578
3579   if (text_view->layout == NULL || get_buffer (text_view) == NULL)
3580     return FALSE;
3581       
3582   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
3583   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
3584   if (gtk_text_iter_can_insert (&iter, text_view->editable) &&
3585       gtk_im_context_filter_keypress (text_view->im_context, event))
3586     {
3587       text_view->need_im_reset = TRUE;
3588       return TRUE;
3589     }
3590   else
3591     return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
3592 }
3593
3594 static gint
3595 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
3596 {
3597   GtkTextView *text_view;
3598
3599   text_view = GTK_TEXT_VIEW (widget);
3600
3601   text_view->disable_scroll_on_focus = TRUE;
3602   gtk_widget_grab_focus (widget);
3603   text_view->disable_scroll_on_focus = FALSE;
3604
3605   if (event->window != text_view->text_window->bin_window)
3606     {
3607       /* Remove selection if any. */
3608       gtk_text_view_unselect (text_view);
3609       return FALSE;
3610     }
3611
3612 #if 0
3613   /* debug hack */
3614   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
3615     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
3616   else if (event->button == 3)
3617     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
3618 #endif
3619
3620   if (event->type == GDK_BUTTON_PRESS)
3621     {
3622       gtk_text_view_reset_im_context (text_view);
3623
3624       if (event->button == 1)
3625         {
3626           /* If we're in the selection, start a drag copy/move of the
3627            * selection; otherwise, start creating a new selection.
3628            */
3629           GtkTextIter iter;
3630           GtkTextIter start, end;
3631
3632           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3633                                              &iter,
3634                                              event->x + text_view->xoffset,
3635                                              event->y + text_view->yoffset);
3636
3637           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
3638                                                     &start, &end) &&
3639               gtk_text_iter_in_range (&iter, &start, &end))
3640             {
3641               text_view->drag_start_x = event->x;
3642               text_view->drag_start_y = event->y;
3643               text_view->pending_place_cursor_button = event->button;
3644             }
3645           else
3646             {
3647               gtk_text_view_start_selection_drag (text_view, &iter, event);
3648             }
3649
3650           return TRUE;
3651         }
3652       else if (event->button == 2)
3653         {
3654           GtkTextIter iter;
3655
3656           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3657                                              &iter,
3658                                              event->x + text_view->xoffset,
3659                                              event->y + text_view->yoffset);
3660
3661           gtk_text_buffer_paste_clipboard (get_buffer (text_view),
3662                                            gtk_clipboard_get (GDK_SELECTION_PRIMARY),
3663                                            &iter,
3664                                            text_view->editable);
3665           return TRUE;
3666         }
3667       else if (event->button == 3)
3668         {
3669           gtk_text_view_do_popup (text_view, event);
3670         }
3671     }
3672   else if ((event->type == GDK_2BUTTON_PRESS ||
3673             event->type == GDK_3BUTTON_PRESS) &&
3674            event->button == 1)
3675     {
3676       GtkTextIter start, end;      
3677       
3678       /* End the selection drag, otherwise we'd clear the new
3679        * word/line selection on button release
3680        */
3681       gtk_text_view_end_selection_drag (text_view, event);
3682
3683       gtk_text_layout_get_iter_at_pixel (text_view->layout,
3684                                          &start,
3685                                          event->x + text_view->xoffset,
3686                                          event->y + text_view->yoffset); 
3687
3688       end = start;
3689       
3690       if (event->type == GDK_2BUTTON_PRESS)
3691         {
3692           if (gtk_text_iter_inside_word (&start))
3693             {
3694               if (!gtk_text_iter_starts_word (&start))
3695                 gtk_text_iter_backward_word_start (&start);
3696               
3697               if (!gtk_text_iter_ends_word (&end))
3698                 gtk_text_iter_forward_word_end (&end);
3699             }
3700         }
3701       else if (event->type == GDK_3BUTTON_PRESS)
3702         {
3703           if (gtk_text_view_starts_display_line (text_view, &start))
3704             {
3705               /* If on a display line boundary, we assume the user
3706                * clicked off the end of a line and we therefore select
3707                * the line before the boundary.
3708                */
3709               gtk_text_view_backward_display_line_start (text_view, &start);
3710             }
3711           else
3712             {
3713               /* start isn't on the start of a line, so we move it to the
3714                * start, and move end to the end unless it's already there.
3715                */
3716               gtk_text_view_backward_display_line_start (text_view, &start);
3717
3718               if (!gtk_text_view_starts_display_line (text_view, &end))
3719                 gtk_text_view_forward_display_line_end (text_view, &end);
3720             }
3721         }
3722
3723       if (event->state & GDK_SHIFT_MASK)
3724         {
3725           /* Take union of old and new selection */
3726           GtkTextIter old_start, old_end;
3727           
3728           gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
3729                                                 &old_start, &old_end);
3730
3731           gtk_text_iter_order (&start, &old_start);
3732           gtk_text_iter_order (&old_end, &end);
3733
3734           /* Now start is the first of the starts, and end is the
3735            * last of the ends
3736            */
3737         }
3738       
3739       gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
3740                                          "selection_bound",
3741                                          &start);
3742       gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
3743                                          "insert",
3744                                          &end);
3745
3746       text_view->just_selected_element = TRUE;
3747       
3748       return TRUE;
3749     }
3750   
3751   return FALSE;
3752 }
3753
3754 static gint
3755 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
3756 {
3757   GtkTextView *text_view;
3758
3759   text_view = GTK_TEXT_VIEW (widget);
3760
3761   if (event->window != text_view->text_window->bin_window)
3762     return FALSE;
3763
3764   if (event->button == 1)
3765     {
3766       if (text_view->drag_start_x >= 0)
3767         {
3768           text_view->drag_start_x = -1;
3769           text_view->drag_start_y = -1;
3770         }
3771
3772       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
3773         return TRUE;
3774       else if (text_view->just_selected_element)
3775         {
3776           text_view->just_selected_element = FALSE;
3777           return FALSE;
3778         }
3779       else if (text_view->pending_place_cursor_button == event->button)
3780         {
3781           GtkTextIter iter;
3782
3783           /* Unselect everything; we clicked inside selection, but
3784            * didn't move by the drag threshold, so just clear selection
3785            * and place cursor.
3786            */
3787           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3788                                              &iter,
3789                                              event->x + text_view->xoffset,
3790                                              event->y + text_view->yoffset);
3791
3792           gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
3793
3794           text_view->pending_place_cursor_button = 0;
3795           
3796           return FALSE;
3797         }
3798     }
3799
3800   return FALSE;
3801 }
3802
3803 static void
3804 keymap_direction_changed (GdkKeymap   *keymap,
3805                           GtkTextView *text_view)
3806 {
3807   gtk_text_view_check_keymap_direction (text_view);
3808 }
3809
3810 static gint
3811 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
3812 {
3813   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3814
3815   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3816   gtk_widget_queue_draw (widget);
3817
3818   DV(g_print (G_STRLOC": focus_in_event\n"));
3819   
3820   if (text_view->cursor_visible && text_view->layout)
3821     {
3822       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3823       gtk_text_view_check_cursor_blink (text_view);
3824     }
3825
3826   g_signal_connect (gdk_keymap_get_default (),
3827                     "direction_changed",
3828                     G_CALLBACK (keymap_direction_changed), text_view);
3829   gtk_text_view_check_keymap_direction (text_view);
3830   
3831   text_view->need_im_reset = TRUE;
3832   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
3833
3834   return FALSE;
3835 }
3836
3837 static gint
3838 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
3839 {
3840   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3841
3842   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3843   gtk_widget_queue_draw (widget);
3844
3845   DV(g_print (G_STRLOC": focus_out_event\n"));
3846   
3847   if (text_view->cursor_visible && text_view->layout)
3848     {
3849       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
3850       gtk_text_view_check_cursor_blink (text_view);
3851     }
3852
3853   g_signal_handlers_disconnect_by_func (gdk_keymap_get_default (),
3854                                         keymap_direction_changed,
3855                                         text_view);
3856
3857   text_view->need_im_reset = TRUE;
3858   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
3859
3860   return FALSE;
3861 }
3862
3863 static gint
3864 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
3865 {
3866   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3867
3868   if (event->window == text_view->text_window->bin_window &&
3869       text_view->drag_start_x >= 0)
3870     {
3871       gint x, y;
3872
3873       gdk_window_get_pointer (text_view->text_window->bin_window,
3874                               &x, &y, NULL);
3875
3876       if (gtk_drag_check_threshold (widget,
3877                                     text_view->drag_start_x, 
3878                                     text_view->drag_start_y,
3879                                     x, y))
3880         {
3881           GtkTextIter iter;
3882           gint buffer_x, buffer_y;
3883
3884           gtk_text_view_window_to_buffer_coords (text_view,
3885                                                  GTK_TEXT_WINDOW_TEXT,
3886                                                  text_view->drag_start_x,
3887                                                  text_view->drag_start_y,
3888                                                  &buffer_x,
3889                                                  &buffer_y);
3890
3891           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3892                                              &iter,
3893                                              buffer_x, buffer_y);
3894
3895           gtk_text_view_start_selection_dnd (text_view, &iter, event);
3896           return TRUE;
3897         }
3898     }
3899
3900   return FALSE;
3901 }
3902
3903 static void
3904 gtk_text_view_paint (GtkWidget      *widget,
3905                      GdkRectangle   *area,
3906                      GdkEventExpose *event)
3907 {
3908   GtkTextView *text_view;
3909   GList *child_exposes;
3910   GList *tmp_list;
3911   
3912   text_view = GTK_TEXT_VIEW (widget);
3913
3914   g_return_if_fail (text_view->layout != NULL);
3915   g_return_if_fail (text_view->xoffset >= 0);
3916   g_return_if_fail (text_view->yoffset >= 0);
3917   
3918   DV (g_print (G_STRLOC": first_validate_idle: %d\n",
3919                text_view->first_validate_idle));
3920   
3921   if (!text_view->onscreen_validated)
3922     {
3923       g_warning (G_STRLOC ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen - this is a known bug, no need to report.");
3924       G_BREAKPOINT ();
3925     }
3926   
3927 #if 0
3928   printf ("painting %d,%d  %d x %d\n",
3929           area->x, area->y,
3930           area->width, area->height);
3931 #endif
3932
3933   child_exposes = NULL;
3934   gtk_text_layout_draw (text_view->layout,
3935                         widget,
3936                         text_view->text_window->bin_window,
3937                         text_view->cursor_gc,
3938                         text_view->xoffset,
3939                         text_view->yoffset,
3940                         area->x, area->y,
3941                         area->width, area->height,
3942                         &child_exposes);
3943
3944   tmp_list = child_exposes;
3945   while (tmp_list != NULL)
3946     {
3947       GtkWidget *child = tmp_list->data;
3948       
3949       gtk_container_propagate_expose (GTK_CONTAINER (text_view),
3950                                       child,
3951                                       event);
3952
3953       g_object_unref (G_OBJECT (child));
3954       
3955       tmp_list = tmp_list->next;
3956     }
3957
3958   g_list_free (child_exposes);
3959 }
3960
3961 static gint
3962 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
3963 {  
3964   if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
3965                                                  GTK_TEXT_WINDOW_TEXT))
3966     {
3967       DV(g_print (">Exposed ("G_STRLOC")\n"));
3968       gtk_text_view_paint (widget, &event->area, event);
3969     }
3970
3971   if (event->window == widget->window)
3972     gtk_text_view_draw_focus (widget);
3973
3974   return FALSE;
3975 }
3976
3977 static void
3978 gtk_text_view_draw_focus (GtkWidget *widget)
3979 {
3980   gboolean interior_focus;
3981
3982   /* We clear the focus if we are in interior focus mode. */
3983   gtk_widget_style_get (widget,
3984                         "interior_focus", &interior_focus,
3985                         NULL);
3986   
3987   if (GTK_WIDGET_DRAWABLE (widget))
3988     {
3989       if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
3990         {          
3991           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
3992                            NULL, widget, "textview",
3993                            0, 0,
3994                            widget->allocation.width,
3995                            widget->allocation.height);
3996         }
3997       else
3998         {
3999           gdk_window_clear (widget->window);
4000         }
4001     }
4002 }
4003
4004 static void
4005 gtk_text_view_grab_focus (GtkWidget *widget)
4006 {
4007   GtkTextView *text_view;
4008
4009   text_view = GTK_TEXT_VIEW (widget);
4010   
4011   GTK_WIDGET_CLASS (parent_class)->grab_focus (widget);
4012
4013   if (!text_view->disable_scroll_on_focus)
4014     gtk_text_view_scroll_mark_onscreen (text_view,
4015                                         gtk_text_buffer_get_mark (get_buffer (text_view),
4016                                                                   "insert"));
4017 }
4018
4019 /*
4020  * Container
4021  */
4022
4023 static void
4024 gtk_text_view_add (GtkContainer *container,
4025                    GtkWidget    *child)
4026 {
4027   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4028   g_return_if_fail (GTK_IS_WIDGET (child));
4029
4030   /* This is pretty random. */
4031   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
4032                                      child,
4033                                      GTK_TEXT_WINDOW_WIDGET,
4034                                      0, 0);
4035 }
4036
4037 static void
4038 gtk_text_view_remove (GtkContainer *container,
4039                       GtkWidget    *child)
4040 {
4041   GSList *iter;
4042   GtkTextView *text_view;
4043   GtkTextViewChild *vc;
4044
4045   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4046   g_return_if_fail (GTK_IS_WIDGET (child));
4047   g_return_if_fail (child->parent == (GtkWidget*) container);
4048
4049   text_view = GTK_TEXT_VIEW (container);
4050
4051   vc = NULL;
4052   iter = text_view->children;
4053
4054   while (iter != NULL)
4055     {
4056       vc = iter->data;
4057
4058       if (vc->widget == child)
4059         break;
4060
4061       iter = g_slist_next (iter);
4062     }
4063
4064   g_assert (iter != NULL); /* be sure we had the child in the list */
4065
4066   text_view->children = g_slist_remove (text_view->children, vc);
4067
4068   gtk_widget_unparent (vc->widget);
4069
4070   text_view_child_free (vc);
4071 }
4072
4073 static void
4074 gtk_text_view_forall (GtkContainer *container,
4075                       gboolean      include_internals,
4076                       GtkCallback   callback,
4077                       gpointer      callback_data)
4078 {
4079   GSList *iter;
4080   GtkTextView *text_view;
4081   GSList *copy;
4082
4083   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4084   g_return_if_fail (callback != NULL);
4085
4086   text_view = GTK_TEXT_VIEW (container);
4087
4088   copy = g_slist_copy (text_view->children);
4089   iter = copy;
4090
4091   while (iter != NULL)
4092     {
4093       GtkTextViewChild *vc = iter->data;
4094
4095       (* callback) (vc->widget, callback_data);
4096
4097       iter = g_slist_next (iter);
4098     }
4099
4100   g_slist_free (copy);
4101 }
4102
4103 #define CURSOR_ON_MULTIPLIER 0.66
4104 #define CURSOR_OFF_MULTIPLIER 0.34
4105 #define CURSOR_PEND_MULTIPLIER 1.0
4106
4107 static gboolean
4108 cursor_blinks (GtkTextView *text_view)
4109 {
4110   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4111   gboolean blink;
4112
4113 #ifdef DEBUG_VALIDATION_AND_SCROLLING
4114   return FALSE;
4115 #endif
4116   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
4117     return FALSE;
4118   
4119   g_object_get (G_OBJECT (settings), "gtk-cursor-blink", &blink, NULL);
4120   return blink;
4121 }
4122
4123 static gint
4124 get_cursor_time (GtkTextView *text_view)
4125 {
4126   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4127   gint time;
4128
4129   g_object_get (G_OBJECT (settings), "gtk-cursor-blink-time", &time, NULL);
4130
4131   return time;
4132 }
4133
4134 /*
4135  * Blink!
4136  */
4137
4138 static gint
4139 blink_cb (gpointer data)
4140 {
4141   GtkTextView *text_view;
4142   gboolean visible;
4143
4144   GDK_THREADS_ENTER ();
4145
4146   text_view = GTK_TEXT_VIEW (data);
4147   
4148   g_assert (text_view->layout);
4149   g_assert (GTK_WIDGET_HAS_FOCUS (text_view));
4150   g_assert (text_view->cursor_visible);
4151
4152   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
4153
4154   if (visible)
4155     text_view->blink_timeout = gtk_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
4156                                                 blink_cb,
4157                                                 text_view);
4158   else
4159     text_view->blink_timeout = gtk_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER,
4160                                                 blink_cb,
4161                                                 text_view);
4162   
4163   gtk_text_layout_set_cursor_visible (text_view->layout,
4164                                       !visible);
4165
4166   GDK_THREADS_LEAVE ();
4167
4168   /* Remove ourselves */
4169   return FALSE;
4170 }
4171
4172
4173 static void
4174 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
4175 {
4176   if (text_view->blink_timeout)  
4177     { 
4178       gtk_timeout_remove (text_view->blink_timeout);
4179       text_view->blink_timeout = 0;
4180     }
4181 }
4182
4183 static void
4184 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
4185 {
4186   if (text_view->layout != NULL &&
4187       text_view->cursor_visible &&
4188       GTK_WIDGET_HAS_FOCUS (text_view))
4189     {
4190       if (cursor_blinks (text_view))
4191         {
4192           if (text_view->blink_timeout == 0)
4193             {
4194               gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4195               
4196               text_view->blink_timeout = gtk_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
4197                                                           blink_cb,
4198                                                           text_view);
4199             }
4200         }
4201       else
4202         gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);   
4203     }
4204   else
4205     {
4206       gtk_text_view_stop_cursor_blink (text_view);
4207     }
4208 }
4209
4210 static void
4211 gtk_text_view_pend_cursor_blink(GtkTextView *text_view)
4212 {
4213   if (text_view->layout != NULL &&
4214       text_view->cursor_visible &&
4215       GTK_WIDGET_HAS_FOCUS (text_view) &&
4216       cursor_blinks (text_view))
4217     {
4218       if (text_view->blink_timeout != 0)
4219         {
4220           gtk_timeout_remove (text_view->blink_timeout);
4221           text_view->blink_timeout = 0;
4222         }
4223       
4224       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4225       
4226       text_view->blink_timeout = gtk_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER,
4227                                                   blink_cb,
4228                                                   text_view);
4229     }
4230 }
4231
4232
4233 /*
4234  * Key binding handlers
4235  */
4236
4237 static void
4238 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
4239                                   GtkTextIter *newplace,
4240                                   gint         count)
4241 {
4242   while (count < 0)
4243     {
4244       gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
4245       count++;
4246     }
4247
4248   while (count > 0)
4249     {
4250       gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
4251       count--;
4252     }
4253 }
4254
4255 static void
4256 gtk_text_view_move_cursor (GtkTextView     *text_view,
4257                            GtkMovementStep  step,
4258                            gint             count,
4259                            gboolean         extend_selection)
4260 {
4261   GtkTextIter insert;
4262   GtkTextIter newplace;
4263
4264   gint cursor_x_pos = 0;
4265
4266   gtk_text_view_reset_im_context (text_view);
4267
4268   if (step == GTK_MOVEMENT_PAGES)
4269     {
4270       gtk_text_view_scroll_pages (text_view, count);
4271       gtk_text_view_pend_cursor_blink (text_view);
4272       return;
4273     }
4274
4275   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4276                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4277                                                               "insert"));
4278   newplace = insert;
4279
4280   if (step == GTK_MOVEMENT_DISPLAY_LINES)
4281     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
4282
4283   switch (step)
4284     {
4285     case GTK_MOVEMENT_LOGICAL_POSITIONS:
4286       gtk_text_iter_forward_cursor_positions (&newplace, count);
4287       break;
4288
4289     case GTK_MOVEMENT_VISUAL_POSITIONS:
4290       gtk_text_layout_move_iter_visually (text_view->layout,
4291                                           &newplace, count);
4292       break;
4293
4294     case GTK_MOVEMENT_WORDS:
4295       if (count < 0)
4296         gtk_text_iter_backward_word_starts (&newplace, -count);
4297       else if (count > 0)
4298         gtk_text_iter_forward_word_ends (&newplace, count);
4299       break;
4300
4301     case GTK_MOVEMENT_DISPLAY_LINES:
4302       gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
4303       gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
4304       break;
4305
4306     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4307       if (count > 1)
4308         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
4309       else if (count < -1)
4310         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
4311
4312       if (count != 0)
4313         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
4314       break;
4315
4316     case GTK_MOVEMENT_PARAGRAPHS:
4317       gtk_text_iter_forward_lines (&newplace, count);
4318       gtk_text_iter_set_line_offset (&newplace, 0);
4319       break;
4320
4321     case GTK_MOVEMENT_PARAGRAPH_ENDS:
4322       if (count > 0)
4323         {
4324           if (!gtk_text_iter_ends_line (&newplace))
4325             gtk_text_iter_forward_to_line_end (&newplace);
4326         }
4327       else if (count < 0)
4328         {
4329           gtk_text_iter_set_line_offset (&newplace, 0);
4330         }
4331       break;
4332
4333     case GTK_MOVEMENT_BUFFER_ENDS:
4334       if (count > 0)
4335         gtk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
4336       else if (count < 0)
4337         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
4338       break;
4339
4340     default:
4341       break;
4342     }
4343
4344   if (!gtk_text_iter_equal (&insert, &newplace))
4345     {
4346       if (extend_selection)
4347         gtk_text_buffer_move_mark (get_buffer (text_view),
4348                                    gtk_text_buffer_get_mark (get_buffer (text_view),
4349                                                              "insert"),
4350                                    &newplace);
4351       else
4352         gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
4353
4354       DV(g_print (G_STRLOC": scrolling onscreen\n"));
4355       gtk_text_view_scroll_mark_onscreen (text_view,
4356                                           gtk_text_buffer_get_mark (get_buffer (text_view),
4357                                                                     "insert"));
4358
4359       if (step == GTK_MOVEMENT_DISPLAY_LINES)
4360         {
4361           gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
4362         }
4363     }
4364
4365   gtk_text_view_pend_cursor_blink (text_view);
4366 }
4367
4368 static void
4369 gtk_text_view_set_anchor (GtkTextView *text_view)
4370 {
4371   GtkTextIter insert;
4372
4373   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4374                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4375                                                               "insert"));
4376
4377   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
4378 }
4379
4380 static void
4381 gtk_text_view_scroll_pages (GtkTextView *text_view,
4382                             gint         count)
4383 {
4384   gdouble newval;
4385   GtkAdjustment *adj;
4386   gint cursor_x_pos, cursor_y_pos;
4387   GtkTextIter new_insert;
4388   GtkTextIter anchor;
4389   gint y0, y1;
4390
4391   g_return_if_fail (text_view->vadjustment != NULL);
4392
4393   adj = text_view->vadjustment;
4394
4395   /* Validate the region that will be brought into view by the cursor motion
4396    */
4397   if (count < 0)
4398     {
4399       gtk_text_view_get_first_para_iter (text_view, &anchor);
4400       y0 = adj->page_size;
4401       y1 = adj->page_size + count * adj->page_increment;
4402     }
4403   else
4404     {
4405       gtk_text_view_get_first_para_iter (text_view, &anchor);
4406       y0 = count * adj->page_increment + adj->page_size;
4407       y1 = 0;
4408     }
4409
4410   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
4411   /* FIXME do we need to update the adjustment ranges here? */
4412   
4413   gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
4414
4415   newval = adj->value;
4416
4417   newval += count * adj->page_increment;
4418
4419   cursor_y_pos += newval - adj->value;
4420   set_adjustment_clamped (adj, newval);
4421
4422   gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
4423   clamp_iter_onscreen (text_view, &new_insert);
4424   gtk_text_buffer_place_cursor (get_buffer (text_view), &new_insert);
4425
4426   gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
4427
4428   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
4429    * only guarantees 1 pixel onscreen.
4430    */
4431   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4432   gtk_text_view_scroll_mark_onscreen (text_view,
4433                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4434                                                                 "insert"));
4435 }
4436
4437 static gboolean
4438 whitespace (gunichar ch, gpointer user_data)
4439 {
4440   return (ch == ' ' || ch == '\t');
4441 }
4442
4443 static gboolean
4444 not_whitespace (gunichar ch, gpointer user_data)
4445 {
4446   return !whitespace (ch, user_data);
4447 }
4448
4449 static gboolean
4450 find_whitepace_region (const GtkTextIter *center,
4451                        GtkTextIter *start, GtkTextIter *end)
4452 {
4453   *start = *center;
4454   *end = *center;
4455
4456   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
4457     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
4458   if (whitespace (gtk_text_iter_get_char (end), NULL))
4459     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
4460
4461   return !gtk_text_iter_equal (start, end);
4462 }
4463
4464 static void
4465 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
4466                                 const gchar *str)
4467 {
4468   gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
4469                                                 text_view->editable);
4470 }
4471
4472 static void
4473 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
4474                                   GtkDeleteType  type,
4475                                   gint           count)
4476 {
4477   GtkTextIter insert;
4478   GtkTextIter start;
4479   GtkTextIter end;
4480   gboolean leave_one = FALSE;
4481
4482   gtk_text_view_reset_im_context (text_view);
4483
4484   if (type == GTK_DELETE_CHARS)
4485     {
4486       /* Char delete deletes the selection, if one exists */
4487       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
4488                                             text_view->editable))
4489         return;
4490     }
4491
4492   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
4493                                     &insert,
4494                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4495                                                               "insert"));
4496
4497   start = insert;
4498   end = insert;
4499
4500   switch (type)
4501     {
4502     case GTK_DELETE_CHARS:
4503       gtk_text_iter_forward_cursor_positions (&end, count);
4504       break;
4505
4506     case GTK_DELETE_WORD_ENDS:
4507       if (count > 0)
4508         gtk_text_iter_forward_word_ends (&end, count);
4509       else if (count < 0)
4510         gtk_text_iter_backward_word_starts (&start, 0 - count);
4511       break;
4512
4513     case GTK_DELETE_WORDS:
4514       break;
4515
4516     case GTK_DELETE_DISPLAY_LINE_ENDS:
4517       break;
4518
4519     case GTK_DELETE_DISPLAY_LINES:
4520       break;
4521
4522     case GTK_DELETE_PARAGRAPH_ENDS:
4523       /* If we're already at a newline, we need to
4524        * simply delete that newline, instead of
4525        * moving to the next one.
4526        */
4527       if (gtk_text_iter_ends_line (&end))
4528         {
4529           gtk_text_iter_forward_line (&end);
4530           --count;
4531         }
4532
4533       while (count > 0)
4534         {
4535           if (!gtk_text_iter_forward_to_line_end (&end))
4536             break;
4537
4538           --count;
4539         }
4540
4541       /* FIXME figure out what a negative count means
4542          and support that */
4543       break;
4544
4545     case GTK_DELETE_PARAGRAPHS:
4546       if (count > 0)
4547         {
4548           gtk_text_iter_set_line_offset (&start, 0);
4549           gtk_text_iter_forward_to_line_end (&end);
4550
4551           /* Do the lines beyond the first. */
4552           while (count > 1)
4553             {
4554               gtk_text_iter_forward_to_line_end (&end);
4555
4556               --count;
4557             }
4558         }
4559
4560       /* FIXME negative count? */
4561
4562       break;
4563
4564     case GTK_DELETE_WHITESPACE:
4565       {
4566         find_whitepace_region (&insert, &start, &end);
4567       }
4568       break;
4569
4570     default:
4571       break;
4572     }
4573
4574   if (!gtk_text_iter_equal (&start, &end))
4575     {
4576       gtk_text_buffer_begin_user_action (get_buffer (text_view));
4577
4578       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
4579                                               text_view->editable))
4580         {
4581           if (leave_one)
4582             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
4583                                                           " ", 1,
4584                                                           text_view->editable);
4585         }
4586
4587       gtk_text_buffer_end_user_action (get_buffer (text_view));
4588
4589       DV(g_print (G_STRLOC": scrolling onscreen\n"));
4590       gtk_text_view_scroll_mark_onscreen (text_view,
4591                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
4592     }
4593 }
4594
4595 static void
4596 gtk_text_view_cut_clipboard (GtkTextView *text_view)
4597 {
4598   gtk_text_buffer_cut_clipboard (get_buffer (text_view),
4599                                  gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
4600                                  text_view->editable);
4601   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4602   gtk_text_view_scroll_mark_onscreen (text_view,
4603                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4604                                                                 "insert"));
4605 }
4606
4607 static void
4608 gtk_text_view_copy_clipboard (GtkTextView *text_view)
4609 {
4610   gtk_text_buffer_copy_clipboard (get_buffer (text_view),
4611                                   gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
4612   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4613   gtk_text_view_scroll_mark_onscreen (text_view,
4614                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4615                                                                 "insert"));
4616 }
4617
4618 static void
4619 gtk_text_view_paste_clipboard (GtkTextView *text_view)
4620 {
4621   gtk_text_buffer_paste_clipboard (get_buffer (text_view),
4622                                    gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
4623                                    NULL,
4624                                    text_view->editable);
4625   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4626   gtk_text_view_scroll_mark_onscreen (text_view,
4627                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4628                                                                 "insert"));
4629 }
4630
4631 static void
4632 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
4633 {
4634   text_view->overwrite_mode = !text_view->overwrite_mode;
4635 }
4636
4637 /*
4638  * Selections
4639  */
4640
4641 static void
4642 gtk_text_view_unselect (GtkTextView *text_view)
4643 {
4644   GtkTextIter insert;
4645
4646   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
4647                                     &insert,
4648                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4649                                                               "insert"));
4650
4651   gtk_text_buffer_move_mark (get_buffer (text_view),
4652                              gtk_text_buffer_get_mark (get_buffer (text_view),
4653                                                        "selection_bound"),
4654                              &insert);
4655 }
4656
4657 static void
4658 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
4659                                  const gchar *mark_name)
4660 {
4661   gint x, y;
4662   GdkModifierType state;
4663   GtkTextIter newplace;
4664
4665   /*   DV(g_print (G_STRLOC": begin\n")); */
4666   
4667   gdk_window_get_pointer (text_view->text_window->bin_window,
4668                           &x, &y, &state);
4669
4670   /*   DV(g_print (G_STRLOC": get iter at pixel\n"); */
4671   gtk_text_layout_get_iter_at_pixel (text_view->layout,
4672                                      &newplace,
4673                                      x + text_view->xoffset,
4674                                      y + text_view->yoffset);
4675
4676   {
4677     GtkTextMark *mark =
4678       gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
4679
4680     DV(g_print (G_STRLOC": move mark\n"));
4681     gtk_text_buffer_move_mark (get_buffer (text_view),
4682                                mark,
4683                                &newplace);
4684
4685     DV(g_print (G_STRLOC": scrolling onscreen\n"));
4686     gtk_text_view_scroll_mark_onscreen (text_view, mark);
4687   }
4688 }
4689
4690 static gint
4691 selection_scan_timeout (gpointer data)
4692 {
4693   GtkTextView *text_view;
4694
4695   GDK_THREADS_ENTER ();
4696   
4697   text_view = GTK_TEXT_VIEW (data);
4698
4699   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
4700   move_mark_to_pointer_and_scroll (text_view, "insert");
4701
4702   GDK_THREADS_LEAVE ();
4703   
4704   return TRUE; /* remain installed. */
4705 }
4706
4707 #define DND_SCROLL_MARGIN 0.20
4708
4709 static gint
4710 drag_scan_timeout (gpointer data)
4711 {
4712   GtkTextView *text_view;
4713   gint x, y;
4714   GdkModifierType state;
4715   GtkTextIter newplace;
4716
4717   GDK_THREADS_ENTER ();
4718   
4719   text_view = GTK_TEXT_VIEW (data);
4720
4721   gdk_window_get_pointer (text_view->text_window->bin_window,
4722                           &x, &y, &state);
4723   
4724   gtk_text_layout_get_iter_at_pixel (text_view->layout,
4725                                      &newplace,
4726                                      x + text_view->xoffset,
4727                                      y + text_view->yoffset);
4728   
4729   gtk_text_buffer_move_mark (get_buffer (text_view),
4730                              text_view->dnd_mark,
4731                              &newplace);
4732
4733   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4734   gtk_text_view_scroll_to_mark (text_view,
4735                                 text_view->dnd_mark,
4736                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
4737
4738   GDK_THREADS_LEAVE ();
4739   
4740   return TRUE;
4741 }
4742
4743 static gint
4744 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
4745 {
4746   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
4747   move_mark_to_pointer_and_scroll (text_view, "insert");
4748
4749   /* If we had to scroll offscreen, insert a timeout to do so
4750    * again. Note that in the timeout, even if the mouse doesn't
4751    * move, due to this scroll xoffset/yoffset will have changed
4752    * and we'll need to scroll again.
4753    */
4754   if (text_view->scroll_timeout != 0) /* reset on every motion event */
4755     gtk_timeout_remove (text_view->scroll_timeout);
4756   
4757   text_view->scroll_timeout =
4758     gtk_timeout_add (50, selection_scan_timeout, text_view);
4759
4760   return TRUE;
4761 }
4762
4763 static void
4764 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
4765                                     const GtkTextIter *iter,
4766                                     GdkEventButton    *button)
4767 {
4768   GtkTextIter newplace;
4769   GtkTextBuffer *buffer;
4770   
4771   g_return_if_fail (text_view->selection_drag_handler == 0);
4772
4773   gtk_grab_add (GTK_WIDGET (text_view));
4774
4775   buffer = get_buffer (text_view);
4776   
4777   newplace = *iter;
4778
4779   if (button->state & GDK_SHIFT_MASK)
4780     {
4781       /* Extend selection */
4782       GtkTextIter start, end;
4783
4784       gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
4785
4786       if (gtk_text_iter_compare (&newplace, &start) <= 0)
4787         {
4788           gtk_text_buffer_move_mark_by_name (buffer, "insert",
4789                                              &newplace);
4790
4791           gtk_text_buffer_move_mark_by_name (buffer, "selection_bound",
4792                                              &end);
4793         }
4794       else if (gtk_text_iter_compare (&newplace, &end) >= 0)
4795         {
4796           gtk_text_buffer_move_mark_by_name (buffer, "insert",
4797                                              &newplace);
4798
4799           gtk_text_buffer_move_mark_by_name (buffer, "selection_bound",
4800                                              &start);
4801         }
4802     }
4803   else
4804     {
4805       /* Replace selection */
4806       gtk_text_buffer_place_cursor (buffer, &newplace);
4807     }
4808
4809   text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
4810                                                           "motion_notify_event",
4811                                                           GTK_SIGNAL_FUNC (selection_motion_event_handler),
4812                                                           NULL);
4813 }
4814
4815 /* returns whether we were really dragging */
4816 static gboolean
4817 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
4818 {
4819   if (text_view->selection_drag_handler == 0)
4820     return FALSE;
4821
4822   gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
4823   text_view->selection_drag_handler = 0;
4824
4825   if (text_view->scroll_timeout != 0)
4826     {
4827       gtk_timeout_remove (text_view->scroll_timeout);
4828       text_view->scroll_timeout = 0;
4829     }
4830
4831   /* one last update to current position */
4832   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
4833   move_mark_to_pointer_and_scroll (text_view, "insert");
4834
4835   gtk_grab_remove (GTK_WIDGET (text_view));
4836
4837   return TRUE;
4838 }
4839
4840 /*
4841  * Layout utils
4842  */
4843
4844 static void
4845 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
4846                                          GtkTextAttributes  *values,
4847                                          GtkStyle           *style)
4848 {
4849   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
4850   values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
4851
4852   if (values->font)
4853     pango_font_description_free (values->font);
4854
4855   values->font = pango_font_description_copy (style->font_desc);
4856 }
4857
4858 static void
4859 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
4860 {
4861   if (text_view->layout)
4862     {
4863       gboolean split_cursor;
4864       GtkTextDirection new_dir;
4865       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4866   
4867       g_object_get (G_OBJECT (settings),
4868                     "gtk-split-cursor", &split_cursor,
4869                     NULL);
4870       if (split_cursor)
4871         new_dir = GTK_TEXT_DIR_NONE;
4872       else
4873         new_dir = (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
4874           GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
4875       
4876       if (text_view->layout->cursor_direction != new_dir)
4877         gtk_text_layout_set_cursor_direction (text_view->layout, new_dir);
4878     }
4879 }
4880
4881 static void
4882 gtk_text_view_ensure_layout (GtkTextView *text_view)
4883 {
4884   GtkWidget *widget;
4885
4886   widget = GTK_WIDGET (text_view);
4887
4888   if (text_view->layout == NULL)
4889     {
4890       GtkTextAttributes *style;
4891       PangoContext *ltr_context, *rtl_context;
4892       GSList *tmp_list;
4893
4894       DV(g_print(G_STRLOC"\n"));
4895       
4896       text_view->layout = gtk_text_layout_new ();
4897
4898       g_signal_connect (G_OBJECT (text_view->layout),
4899                         "invalidated",
4900                         G_CALLBACK (invalidated_handler),
4901                         text_view);
4902
4903       g_signal_connect (G_OBJECT (text_view->layout),
4904                         "changed",
4905                         G_CALLBACK (changed_handler),
4906                         text_view);
4907
4908       g_signal_connect (G_OBJECT (text_view->layout),
4909                         "allocate_child",
4910                         G_CALLBACK (gtk_text_view_child_allocated),
4911                         text_view);
4912       
4913       if (get_buffer (text_view))
4914         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
4915
4916       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
4917         gtk_text_view_pend_cursor_blink (text_view);
4918       else
4919         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4920
4921       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
4922       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
4923       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
4924       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
4925
4926       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
4927
4928       g_object_unref (G_OBJECT (ltr_context));
4929       g_object_unref (G_OBJECT (rtl_context));
4930
4931       gtk_text_view_check_keymap_direction (text_view);
4932
4933       style = gtk_text_attributes_new ();
4934
4935       gtk_widget_ensure_style (widget);
4936       gtk_text_view_set_attributes_from_style (text_view,
4937                                                style, widget->style);
4938
4939       style->pixels_above_lines = text_view->pixels_above_lines;
4940       style->pixels_below_lines = text_view->pixels_below_lines;
4941       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
4942       style->left_margin = text_view->left_margin;
4943       style->right_margin = text_view->right_margin;
4944       style->indent = text_view->indent;
4945       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
4946
4947       style->wrap_mode = text_view->wrap_mode;
4948       style->justification = text_view->justify;
4949       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
4950
4951       gtk_text_layout_set_default_style (text_view->layout, style);
4952
4953       gtk_text_attributes_unref (style);
4954
4955       /* Set layout for all anchored children */
4956
4957       tmp_list = text_view->children;
4958       while (tmp_list != NULL)
4959         {
4960           GtkTextViewChild *vc = tmp_list->data;
4961
4962           if (vc->anchor)
4963             {
4964               gtk_text_anchored_child_set_layout (vc->widget,
4965                                                   text_view->layout);
4966               /* vc may now be invalid! */
4967             }
4968
4969           tmp_list = g_slist_next (tmp_list);
4970         }
4971     }
4972 }
4973
4974 /**
4975  * gtk_text_view_get_default_attributes:
4976  * @text_view: a #GtkTextView
4977  * 
4978  * Obtains a copy of the default text attributes. These are the
4979  * attributes used for text unless a tag overrides them.
4980  * You'd typically pass the default attributes in to
4981  * gtk_text_iter_get_attributes() in order to get the
4982  * attributes in effect at a given text position.
4983  *
4984  * The return value is a copy owned by the caller of this function,
4985  * and should be freed.
4986  * 
4987  * Return value: a new #GtkTextAttributes
4988  **/
4989 GtkTextAttributes*
4990 gtk_text_view_get_default_attributes (GtkTextView *text_view)
4991 {
4992   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
4993   
4994   gtk_text_view_ensure_layout (text_view);
4995
4996   return gtk_text_attributes_copy (text_view->layout->default_style);
4997 }
4998
4999 static void
5000 gtk_text_view_destroy_layout (GtkTextView *text_view)
5001 {
5002   if (text_view->layout)
5003     {
5004       GSList *tmp_list;
5005
5006       gtk_text_view_remove_validate_idles (text_view);
5007       
5008       /* Remove layout from all anchored children */
5009       tmp_list = text_view->children;
5010       while (tmp_list != NULL)
5011         {
5012           GtkTextViewChild *vc = tmp_list->data;
5013
5014           if (vc->anchor)
5015             {
5016               gtk_text_anchored_child_set_layout (vc->widget, NULL);
5017               /* vc may now be invalid! */
5018             }
5019
5020           tmp_list = g_slist_next (tmp_list);
5021         }
5022       
5023       gtk_text_view_stop_cursor_blink (text_view);
5024       gtk_text_view_end_selection_drag (text_view, NULL);
5025
5026       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
5027                                             invalidated_handler, text_view);
5028       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
5029                                             changed_handler, text_view);
5030       g_object_unref (G_OBJECT (text_view->layout));
5031       text_view->layout = NULL;
5032     }
5033 }
5034
5035 static void
5036 gtk_text_view_reset_im_context (GtkTextView *text_view)
5037 {
5038   if (text_view->need_im_reset)
5039     {
5040       text_view->need_im_reset = FALSE;
5041       gtk_im_context_reset (text_view->im_context);
5042     }
5043 }
5044
5045 /*
5046  * DND feature
5047  */
5048
5049 static void
5050 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
5051                                    const GtkTextIter *iter,
5052                                    GdkEventMotion    *event)
5053 {
5054   GdkDragContext *context;
5055   GtkTargetList *target_list;
5056
5057   text_view->drag_start_x = -1;
5058   text_view->drag_start_y = -1;
5059   text_view->pending_place_cursor_button = 0;
5060   
5061   target_list = gtk_target_list_new (target_table,
5062                                      G_N_ELEMENTS (target_table));
5063
5064   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
5065                             GDK_ACTION_COPY | GDK_ACTION_MOVE,
5066                             1, (GdkEvent*)event);
5067
5068   gtk_target_list_unref (target_list);
5069
5070   gtk_drag_set_icon_default (context);
5071 }
5072
5073 static void
5074 gtk_text_view_drag_begin (GtkWidget        *widget,
5075                           GdkDragContext   *context)
5076 {
5077   /* do nothing */
5078 }
5079
5080 static void
5081 gtk_text_view_drag_end (GtkWidget        *widget,
5082                         GdkDragContext   *context)
5083 {
5084   GtkTextView *text_view;
5085
5086   text_view = GTK_TEXT_VIEW (widget);
5087 }
5088
5089 static void
5090 gtk_text_view_drag_data_get (GtkWidget        *widget,
5091                              GdkDragContext   *context,
5092                              GtkSelectionData *selection_data,
5093                              guint             info,
5094                              guint             time)
5095 {
5096   GtkTextView *text_view;
5097
5098   text_view = GTK_TEXT_VIEW (widget);
5099
5100   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
5101     {
5102       GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
5103
5104       gtk_selection_data_set (selection_data,
5105                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
5106                               8, /* bytes */
5107                               (void*)&buffer,
5108                               sizeof (buffer));
5109     }
5110   else
5111     {
5112       gchar *str;
5113       GtkTextIter start;
5114       GtkTextIter end;
5115
5116       str = NULL;
5117
5118       if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
5119                                                 &start, &end))
5120         {
5121           /* Extract the selected text */
5122           str = gtk_text_iter_get_visible_text (&start, &end);
5123         }
5124
5125       if (str)
5126         {
5127           gtk_selection_data_set_text (selection_data, str, -1);
5128           g_free (str);
5129         }
5130     }
5131 }
5132
5133 static void
5134 gtk_text_view_drag_data_delete (GtkWidget        *widget,
5135                                 GdkDragContext   *context)
5136 {
5137   GtkTextView *text_view;
5138
5139   text_view = GTK_TEXT_VIEW (widget);
5140
5141   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
5142                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
5143 }
5144
5145 static void
5146 gtk_text_view_drag_leave (GtkWidget        *widget,
5147                           GdkDragContext   *context,
5148                           guint             time)
5149 {
5150   GtkTextView *text_view;
5151
5152   text_view = GTK_TEXT_VIEW (widget);
5153
5154   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
5155   
5156   if (text_view->scroll_timeout != 0)
5157     gtk_timeout_remove (text_view->scroll_timeout);
5158
5159   text_view->scroll_timeout = 0;
5160 }
5161
5162 static gboolean
5163 gtk_text_view_drag_motion (GtkWidget        *widget,
5164                            GdkDragContext   *context,
5165                            gint              x,
5166                            gint              y,
5167                            guint             time)
5168 {
5169   GtkTextIter newplace;
5170   GtkTextView *text_view;
5171   GtkTextIter start;
5172   GtkTextIter end;
5173   GdkRectangle target_rect;
5174   gint bx, by;
5175   GdkDragAction suggested_action = 0;
5176   
5177   text_view = GTK_TEXT_VIEW (widget);
5178
5179   target_rect = text_view->text_window->allocation;
5180   
5181   if (x < target_rect.x ||
5182       y < target_rect.y ||
5183       x > (target_rect.x + target_rect.width) ||
5184       y > (target_rect.y + target_rect.height))
5185     return FALSE; /* outside the text window, allow parent widgets to handle event */
5186
5187   gtk_text_view_window_to_buffer_coords (text_view,
5188                                          GTK_TEXT_WINDOW_WIDGET,
5189                                          x, y,
5190                                          &bx, &by);
5191
5192   gtk_text_layout_get_iter_at_pixel (text_view->layout,
5193                                      &newplace,
5194                                      bx, by);  
5195
5196   if (gtk_drag_dest_find_target (widget, context,
5197                                  gtk_drag_dest_get_target_list (widget)) == GDK_NONE)
5198     {
5199       /* can't accept any of the offered targets */
5200     }                                 
5201   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
5202                                             &start, &end) &&
5203            gtk_text_iter_in_range (&newplace, &start, &end))
5204     {
5205       /* We're inside the selection. */
5206     }
5207   else
5208     {      
5209       if (gtk_text_iter_can_insert (&newplace, text_view->editable))
5210         {
5211           GtkWidget *source_widget;
5212           
5213           suggested_action = context->suggested_action;
5214           
5215           source_widget = gtk_drag_get_source_widget (context);
5216           
5217           if (source_widget == widget)
5218             {
5219               /* Default to MOVE, unless the user has
5220                * pressed ctrl or alt to affect available actions
5221                */
5222               if ((context->actions & GDK_ACTION_MOVE) != 0)
5223                 suggested_action = GDK_ACTION_MOVE;
5224             }
5225         }
5226       else
5227         {
5228           /* Can't drop here. */
5229         }
5230     }
5231
5232   if (suggested_action != 0)
5233     {
5234       gtk_text_mark_set_visible (text_view->dnd_mark,
5235                                  text_view->cursor_visible);
5236       
5237       gdk_drag_status (context, suggested_action, time);
5238     }
5239   else
5240     {
5241       gdk_drag_status (context, 0, time);
5242       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
5243     }
5244       
5245   gtk_text_buffer_move_mark (get_buffer (text_view),
5246                              text_view->dnd_mark,
5247                              &newplace);
5248
5249   DV(g_print (G_STRLOC": scrolling to mark\n"));
5250   gtk_text_view_scroll_to_mark (text_view,
5251                                 text_view->dnd_mark,
5252                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
5253   
5254   if (text_view->scroll_timeout != 0) /* reset on every motion event */
5255     gtk_timeout_remove (text_view->scroll_timeout);
5256       
5257   text_view->scroll_timeout =
5258     gtk_timeout_add (50, drag_scan_timeout, text_view);
5259
5260   /* TRUE return means don't propagate the drag motion to parent
5261    * widgets that may also be drop sites.
5262    */
5263   return TRUE;
5264 }
5265
5266 static gboolean
5267 gtk_text_view_drag_drop (GtkWidget        *widget,
5268                          GdkDragContext   *context,
5269                          gint              x,
5270                          gint              y,
5271                          guint             time)
5272 {
5273   GtkTextView *text_view;
5274   GtkTextIter drop_point;
5275   GdkAtom target = GDK_NONE;
5276   
5277   text_view = GTK_TEXT_VIEW (widget);
5278   
5279   if (text_view->scroll_timeout != 0)
5280     gtk_timeout_remove (text_view->scroll_timeout);
5281
5282   text_view->scroll_timeout = 0;
5283
5284   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
5285
5286   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5287                                     &drop_point,
5288                                     text_view->dnd_mark);
5289
5290   if (gtk_text_iter_can_insert (&drop_point, text_view->editable))
5291     target = gtk_drag_dest_find_target (widget, context, NULL);
5292
5293   if (target != GDK_NONE)
5294     gtk_drag_get_data (widget, context, target, time);
5295   else
5296     gtk_drag_finish (context, FALSE, FALSE, time);
5297
5298   return TRUE;
5299 }
5300
5301 static void
5302 insert_text_data (GtkTextView      *text_view,
5303                   GtkTextIter      *drop_point,
5304                   GtkSelectionData *selection_data)
5305 {
5306   gchar *str;
5307
5308   str = gtk_selection_data_get_text (selection_data);
5309
5310   if (str)
5311     {
5312       gtk_text_buffer_insert_interactive (get_buffer (text_view),
5313                                           drop_point, str, -1,
5314                                           text_view->editable);
5315       g_free (str);
5316     }
5317 }
5318
5319 static void
5320 gtk_text_view_drag_data_received (GtkWidget        *widget,
5321                                   GdkDragContext   *context,
5322                                   gint              x,
5323                                   gint              y,
5324                                   GtkSelectionData *selection_data,
5325                                   guint             info,
5326                                   guint             time)
5327 {
5328   GtkTextIter drop_point;
5329   GtkTextView *text_view;
5330   gboolean success = FALSE;
5331
5332   text_view = GTK_TEXT_VIEW (widget);
5333
5334   if (!text_view->dnd_mark)
5335     goto done;
5336
5337   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5338                                     &drop_point,
5339                                     text_view->dnd_mark);
5340   
5341   if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
5342     goto done;
5343
5344   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
5345     {
5346       GtkTextBuffer *src_buffer = NULL;
5347       GtkTextIter start, end;
5348       gboolean copy_tags = TRUE;
5349
5350       if (selection_data->length != sizeof (src_buffer))
5351         return;
5352
5353       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
5354
5355       if (src_buffer == NULL)
5356         return;
5357
5358       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
5359
5360       if (gtk_text_buffer_get_tag_table (src_buffer) !=
5361           gtk_text_buffer_get_tag_table (get_buffer (text_view)))
5362         copy_tags = FALSE;
5363
5364       if (gtk_text_buffer_get_selection_bounds (src_buffer,
5365                                                 &start,
5366                                                 &end))
5367         {
5368           if (copy_tags)
5369             gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
5370                                                       &drop_point,
5371                                                       &start,
5372                                                       &end,
5373                                                       text_view->editable);
5374           else
5375             {
5376               gchar *str;
5377
5378               str = gtk_text_iter_get_visible_text (&start, &end);
5379               gtk_text_buffer_insert_interactive (get_buffer (text_view),
5380                                                   &drop_point, str, -1,
5381                                                   text_view->editable);
5382               g_free (str);
5383             }
5384         }
5385     }
5386   else
5387     insert_text_data (text_view, &drop_point, selection_data);
5388
5389   success = TRUE;
5390
5391  done:
5392   gtk_drag_finish (context, success,
5393                    success && context->action == GDK_ACTION_MOVE,
5394                    time);
5395 }
5396
5397 static GtkAdjustment*
5398 get_hadjustment (GtkTextView *text_view)
5399 {
5400   if (text_view->hadjustment == NULL)
5401     gtk_text_view_set_scroll_adjustments (text_view,
5402                                           NULL, /* forces creation */
5403                                           text_view->vadjustment);
5404
5405   return text_view->hadjustment;
5406 }
5407
5408 static GtkAdjustment*
5409 get_vadjustment (GtkTextView *text_view)
5410 {
5411   if (text_view->vadjustment == NULL)
5412     gtk_text_view_set_scroll_adjustments (text_view,
5413                                           text_view->hadjustment,
5414                                           NULL); /* forces creation */
5415   return text_view->vadjustment;
5416 }
5417
5418
5419 static void
5420 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
5421                                       GtkAdjustment *hadj,
5422                                       GtkAdjustment *vadj)
5423 {
5424   gboolean need_adjust = FALSE;
5425
5426   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5427
5428   if (hadj)
5429     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
5430   else
5431     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5432   if (vadj)
5433     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
5434   else
5435     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5436
5437   if (text_view->hadjustment && (text_view->hadjustment != hadj))
5438     {
5439       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
5440       g_object_unref (G_OBJECT (text_view->hadjustment));
5441     }
5442
5443   if (text_view->vadjustment && (text_view->vadjustment != vadj))
5444     {
5445       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
5446       g_object_unref (G_OBJECT (text_view->vadjustment));
5447     }
5448
5449   if (text_view->hadjustment != hadj)
5450     {
5451       text_view->hadjustment = hadj;
5452       g_object_ref (G_OBJECT (text_view->hadjustment));
5453       gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
5454       
5455       gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
5456                           (GtkSignalFunc) gtk_text_view_value_changed,
5457                           text_view);
5458       need_adjust = TRUE;
5459     }
5460
5461   if (text_view->vadjustment != vadj)
5462     {
5463       text_view->vadjustment = vadj;
5464       g_object_ref (G_OBJECT (text_view->vadjustment));
5465       gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
5466       
5467       gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
5468                           (GtkSignalFunc) gtk_text_view_value_changed,
5469                           text_view);
5470       need_adjust = TRUE;
5471     }
5472
5473   if (need_adjust)
5474     gtk_text_view_value_changed (NULL, text_view);
5475 }
5476
5477 static void
5478 gtk_text_view_value_changed (GtkAdjustment *adj,
5479                              GtkTextView   *text_view)
5480 {
5481   GtkTextIter iter;
5482   gint line_top;
5483   gint dx = 0;
5484   gint dy = 0;
5485   
5486   /* Note that we oddly call this function with adj == NULL
5487    * sometimes
5488    */
5489   
5490   text_view->onscreen_validated = FALSE;
5491
5492   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
5493              adj == text_view->hadjustment ? "hadj" : adj == text_view->vadjustment ? "vadj" : "none",
5494              adj ? adj->value : 0.0));
5495   
5496   if (adj == text_view->hadjustment)
5497     {
5498       dx = text_view->xoffset - (gint)adj->value;
5499       text_view->xoffset = adj->value;
5500     }
5501   else if (adj == text_view->vadjustment)
5502     {
5503       dy = text_view->yoffset - (gint)adj->value;
5504       text_view->yoffset = adj->value;
5505
5506       if (text_view->layout)
5507         {
5508           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
5509
5510           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
5511
5512           text_view->first_para_pixels = adj->value - line_top;
5513         }
5514     }
5515   
5516   if (dx != 0 || dy != 0)
5517     {
5518       GSList *tmp_list;
5519
5520       if (GTK_WIDGET_REALIZED (text_view))
5521         {
5522           if (dy != 0)
5523             {
5524               if (text_view->left_window)
5525                 text_window_scroll (text_view->left_window, 0, dy);
5526               if (text_view->right_window)
5527                 text_window_scroll (text_view->right_window, 0, dy);
5528             }
5529       
5530           if (dx != 0)
5531             {
5532               if (text_view->top_window)
5533                 text_window_scroll (text_view->top_window, dx, 0);
5534               if (text_view->bottom_window)
5535                 text_window_scroll (text_view->bottom_window, dx, 0);
5536             }
5537       
5538           /* It looks nicer to scroll the main area last, because
5539            * it takes a while, and making the side areas update
5540            * afterward emphasizes the slowness of scrolling the
5541            * main area.
5542            */
5543           text_window_scroll (text_view->text_window, dx, dy);
5544         }
5545       
5546       /* Children are now "moved" in the text window, poke
5547        * into widget->allocation for each child
5548        */
5549       tmp_list = text_view->children;
5550       while (tmp_list != NULL)
5551         {
5552           GtkTextViewChild *child = tmp_list->data;
5553           
5554           if (child->anchor)
5555             {              
5556               child->widget->allocation.x -= dx;
5557               child->widget->allocation.y -= dy;
5558
5559 #if 0
5560               g_print ("allocation for %p tweaked to %d,%d\n",
5561                        child->widget,
5562                        child->widget->allocation.x,
5563                        child->widget->allocation.y);
5564 #endif
5565             }
5566           
5567           tmp_list = g_slist_next (tmp_list);
5568         }
5569     }
5570
5571   /* This could result in invalidation, which would install the
5572    * first_validate_idle, which would validate onscreen;
5573    * but we're going to go ahead and validate here, so
5574    * first_validate_idle shouldn't have anything to do.
5575    */
5576   gtk_text_view_update_layout_width (text_view);
5577   
5578   /* note that validation of onscreen could invoke this function
5579    * recursively, by scrolling to maintain first_para, or in response
5580    * to updating the layout width, however there is no problem with
5581    * that, or shouldn't be.
5582    */
5583   gtk_text_view_validate_onscreen (text_view);
5584   
5585   /* process exposes */
5586   if (GTK_WIDGET_REALIZED (text_view))
5587     {
5588       if (text_view->left_window)
5589         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
5590
5591       if (text_view->right_window)
5592         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
5593
5594       if (text_view->top_window)
5595         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
5596       
5597       if (text_view->bottom_window)
5598         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
5599   
5600       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
5601     }
5602
5603   /* If this got installed, get rid of it, it's just a waste of time. */
5604   if (text_view->first_validate_idle != 0)
5605     {
5606       g_source_remove (text_view->first_validate_idle);
5607       text_view->first_validate_idle = 0;
5608     }
5609
5610   gtk_text_view_update_im_spot_location (text_view);
5611   
5612   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
5613 }
5614
5615 static void
5616 gtk_text_view_commit_handler (GtkIMContext  *context,
5617                               const gchar   *str,
5618                               GtkTextView   *text_view)
5619 {
5620   gtk_text_view_commit_text (text_view, str);
5621 }
5622
5623 static void
5624 gtk_text_view_commit_text (GtkTextView   *text_view,
5625                            const gchar   *str)
5626 {
5627   gboolean had_selection;
5628   
5629   gtk_text_buffer_begin_user_action (get_buffer (text_view));
5630
5631   had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
5632                                                         NULL, NULL);
5633   
5634   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5635                                     text_view->editable);
5636
5637   if (!strcmp (str, "\n"))
5638     {
5639       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
5640                                                     text_view->editable);
5641     }
5642   else
5643     {
5644       if (!had_selection && text_view->overwrite_mode)
5645         gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
5646       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
5647                                                     text_view->editable);
5648     }
5649
5650   gtk_text_buffer_end_user_action (get_buffer (text_view));
5651
5652   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5653   gtk_text_view_scroll_mark_onscreen (text_view,
5654                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5655                                                                 "insert"));
5656 }
5657
5658 static void
5659 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
5660                                        GtkTextView  *text_view)
5661 {
5662   gchar *str;
5663   PangoAttrList *attrs;
5664   gint cursor_pos;
5665
5666   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
5667   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
5668
5669   pango_attr_list_unref (attrs);
5670   g_free (str);
5671 }
5672
5673 static gboolean
5674 gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
5675                                             GtkTextView   *text_view)
5676 {
5677   GtkTextIter start;
5678   GtkTextIter end;
5679   gint pos;
5680   gchar *text;
5681
5682   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
5683                                     gtk_text_buffer_get_insert (text_view->buffer));
5684   end = start;
5685
5686   pos = gtk_text_iter_get_line_index (&start);
5687   gtk_text_iter_set_line_offset (&start, 0);
5688   gtk_text_iter_forward_to_line_end (&end);
5689
5690   text = gtk_text_iter_get_slice (&start, &end);
5691   gtk_im_context_set_surrounding (context, text, -1, pos);
5692   g_free (text);
5693
5694   return TRUE;
5695 }
5696
5697 static gboolean
5698 gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
5699                                           gint           offset,
5700                                           gint           n_chars,
5701                                           GtkTextView   *text_view)
5702 {
5703   GtkTextIter start;
5704   GtkTextIter end;
5705
5706   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
5707                                     gtk_text_buffer_get_insert (text_view->buffer));
5708   end = start;
5709
5710   gtk_text_iter_forward_chars (&start, offset);
5711   gtk_text_iter_forward_chars (&end, offset + n_chars);
5712
5713   gtk_text_buffer_delete (text_view->buffer, &start, &end);
5714
5715   return TRUE;
5716 }
5717
5718 static void
5719 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
5720                                 const GtkTextIter *location,
5721                                 GtkTextMark       *mark,
5722                                 gpointer           data)
5723 {
5724   GtkTextView *text_view = GTK_TEXT_VIEW (data);
5725   gboolean need_reset = FALSE;
5726
5727   if (mark == gtk_text_buffer_get_insert (buffer))
5728     {
5729       text_view->virtual_cursor_x = -1;
5730       text_view->virtual_cursor_y = -1;
5731       gtk_text_view_update_im_spot_location (text_view);
5732       need_reset = TRUE;
5733     }
5734   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
5735     {
5736       need_reset = TRUE;
5737     }
5738
5739   if (need_reset)
5740     gtk_text_view_reset_im_context (text_view);
5741 }
5742
5743 static void
5744 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
5745                                       gint        *x,
5746                                       gint        *y)
5747 {
5748   GdkRectangle strong_pos;
5749   GtkTextIter insert;
5750
5751   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5752                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5753                                                               "insert"));
5754
5755   if ((x && text_view->virtual_cursor_x == -1) ||
5756       (y && text_view->virtual_cursor_y == -1))
5757     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
5758
5759   if (x)
5760     {
5761       if (text_view->virtual_cursor_x != -1)
5762         *x = text_view->virtual_cursor_x;
5763       else
5764         *x = strong_pos.x;
5765     }
5766
5767   if (y)
5768     {
5769       if (text_view->virtual_cursor_x != -1)
5770         *y = text_view->virtual_cursor_y;
5771       else
5772         *y = strong_pos.y + strong_pos.height / 2;
5773     }
5774 }
5775
5776 static void
5777 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
5778                                       gint         x,
5779                                       gint         y)
5780 {
5781   GdkRectangle strong_pos;
5782   GtkTextIter insert;
5783
5784   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5785                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5786                                                               "insert"));
5787
5788   if (x == -1 || y == -1)
5789     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
5790
5791   text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
5792   text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
5793 }
5794
5795 /* Quick hack of a popup menu
5796  */
5797 static void
5798 activate_cb (GtkWidget   *menuitem,
5799              GtkTextView *text_view)
5800 {
5801   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
5802   gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal);
5803 }
5804
5805 static void
5806 append_action_signal (GtkTextView  *text_view,
5807                       GtkWidget    *menu,
5808                       const gchar  *stock_id,
5809                       const gchar  *signal,
5810                       gboolean      sensitive)
5811 {
5812   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
5813
5814   g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
5815   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
5816                       GTK_SIGNAL_FUNC (activate_cb), text_view);
5817
5818   gtk_widget_set_sensitive (menuitem, sensitive);
5819   
5820   gtk_widget_show (menuitem);
5821   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
5822 }
5823
5824 static void
5825 popup_menu_detach (GtkWidget *attach_widget,
5826                    GtkMenu   *menu)
5827 {
5828   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
5829 }
5830
5831 static void
5832 popup_position_func (GtkMenu   *menu,
5833                      gint      *x,
5834                      gint      *y,
5835                      gboolean  *push_in,
5836                      gpointer   user_data)
5837 {
5838   GtkTextView *text_view;
5839   GtkWidget *widget;
5840   GdkRectangle cursor_rect;
5841   GdkRectangle onscreen_rect;
5842   gint root_x, root_y;
5843   GtkTextIter iter;
5844   GtkRequisition req;      
5845   
5846   text_view = GTK_TEXT_VIEW (user_data);
5847   widget = GTK_WIDGET (text_view);
5848   
5849   g_return_if_fail (GTK_WIDGET_REALIZED (text_view));
5850
5851   gdk_window_get_origin (widget->window, &root_x, &root_y);
5852
5853   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5854                                     &iter,
5855                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5856
5857   gtk_text_view_get_iter_location (text_view,
5858                                    &iter,
5859                                    &cursor_rect);
5860
5861   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
5862   
5863   gtk_widget_size_request (text_view->popup_menu, &req);
5864
5865   /* can't use rectangle_intersect since cursor rect can have 0 width */
5866   if (cursor_rect.x >= onscreen_rect.x &&
5867       cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
5868       cursor_rect.y >= onscreen_rect.y &&
5869       cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
5870     {    
5871       gtk_text_view_buffer_to_window_coords (text_view,
5872                                              GTK_TEXT_WINDOW_WIDGET,
5873                                              cursor_rect.x, cursor_rect.y,
5874                                              &cursor_rect.x, &cursor_rect.y);
5875
5876       *x = root_x + cursor_rect.x + cursor_rect.width;
5877       *y = root_y + cursor_rect.y + cursor_rect.height;
5878     }
5879   else
5880     {
5881       /* Just center the menu, since cursor is offscreen. */      
5882       *x = root_x + (widget->allocation.width / 2 - req.width / 2);
5883       *y = root_y + (widget->allocation.height / 2 - req.height / 2);      
5884     }
5885
5886   /* Ensure sanity */
5887   *x = CLAMP (*x, root_x, (root_x + widget->allocation.width));
5888   *y = CLAMP (*y, root_y, (root_y + widget->allocation.height));
5889
5890   *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
5891   *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
5892 }
5893
5894 typedef struct
5895 {
5896   GtkTextView *text_view;
5897   gint button;
5898   guint time;
5899 } PopupInfo;
5900
5901 static gboolean
5902 range_contains_editable_text (const GtkTextIter *start,
5903                               const GtkTextIter *end,
5904                               gboolean default_editability)
5905 {
5906   GtkTextIter iter = *start;
5907
5908   while (gtk_text_iter_compare (&iter, end) < 0)
5909     {
5910       if (gtk_text_iter_editable (&iter, default_editability))
5911         return TRUE;
5912       
5913       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
5914     }
5915
5916   return FALSE;
5917 }                             
5918
5919 static void
5920 unichar_chosen_func (const char *text,
5921                      gpointer    data)
5922 {
5923   GtkTextView *text_view = GTK_TEXT_VIEW (data);
5924
5925   gtk_text_view_commit_text (text_view, text);
5926 }
5927
5928 static void
5929 popup_targets_received (GtkClipboard     *clipboard,
5930                         GtkSelectionData *data,
5931                         gpointer          user_data)
5932 {
5933   PopupInfo *info = user_data;
5934   GtkTextView *text_view = info->text_view;
5935   
5936   if (GTK_WIDGET_REALIZED (text_view))
5937     {
5938       /* We implicitely rely here on the fact that if we are pasting ourself, we'll
5939        * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
5940        */
5941       gboolean clipboard_contains_text = gtk_selection_data_targets_include_text (data);
5942       GtkWidget *menuitem;
5943       GtkWidget *submenu;
5944       gboolean have_selection;
5945       gboolean can_insert;
5946       GtkTextIter iter;
5947       GtkTextIter sel_start, sel_end;
5948       
5949       if (text_view->popup_menu)
5950         gtk_widget_destroy (text_view->popup_menu);
5951
5952       text_view->popup_menu = gtk_menu_new ();
5953       
5954       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
5955                                  GTK_WIDGET (text_view),
5956                                  popup_menu_detach);
5957       
5958       have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
5959                                                              &sel_start, &sel_end);
5960       
5961       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5962                                         &iter,
5963                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
5964       
5965       can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
5966       
5967       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
5968                             have_selection &&
5969                             range_contains_editable_text (&sel_start, &sel_end,
5970                                                           text_view->editable));
5971       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
5972                             have_selection);
5973       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
5974                             can_insert && clipboard_contains_text);
5975       
5976       menuitem = gtk_separator_menu_item_new ();
5977       gtk_widget_show (menuitem);
5978       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
5979       
5980       menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
5981       gtk_widget_show (menuitem);
5982       submenu = gtk_menu_new ();
5983       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
5984       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
5985       
5986       gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
5987                                             GTK_MENU_SHELL (submenu));
5988
5989       menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode control character"));
5990       gtk_widget_show (menuitem);
5991       gtk_widget_set_sensitive (menuitem, can_insert);
5992       
5993       submenu = gtk_menu_new ();
5994       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
5995       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);      
5996
5997       _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
5998                                                     unichar_chosen_func,
5999                                                     text_view);
6000       
6001       gtk_signal_emit (GTK_OBJECT (text_view),
6002                        signals[POPULATE_POPUP],
6003                        text_view->popup_menu);
6004       
6005       if (info->button)
6006         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
6007                         NULL, NULL,
6008                         info->button, info->time);
6009       else
6010         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
6011                         popup_position_func, text_view,
6012                         0, gtk_get_current_event_time ());
6013     }
6014
6015   g_object_unref (text_view);
6016   g_free (info);
6017 }
6018
6019 static void
6020 gtk_text_view_do_popup (GtkTextView    *text_view,
6021                         GdkEventButton *event)
6022 {
6023   PopupInfo *info = g_new (PopupInfo, 1);
6024
6025   /* In order to know what entries we should make sensitive, we
6026    * ask for the current targets of the clipboard, and when
6027    * we get them, then we actually pop up the menu.
6028    */
6029   info->text_view = g_object_ref (text_view);
6030   
6031   if (event)
6032     {
6033       info->button = event->button;
6034       info->time = event->time;
6035     }
6036   else
6037     {
6038       info->button = 0;
6039       info->time = gtk_get_current_event_time ();
6040     }
6041
6042   gtk_clipboard_request_contents (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
6043                                   gdk_atom_intern ("TARGETS", FALSE),
6044                                   popup_targets_received,
6045                                   info);
6046 }
6047
6048 static void
6049 gtk_text_view_popup_menu (GtkWidget *widget)
6050 {
6051   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
6052 }
6053
6054 /* Child GdkWindows */
6055
6056
6057 static GtkTextWindow*
6058 text_window_new (GtkTextWindowType  type,
6059                  GtkWidget         *widget,
6060                  gint               width_request,
6061                  gint               height_request)
6062 {
6063   GtkTextWindow *win;
6064
6065   win = g_new (GtkTextWindow, 1);
6066
6067   win->type = type;
6068   win->widget = widget;
6069   win->window = NULL;
6070   win->bin_window = NULL;
6071   win->requisition.width = width_request;
6072   win->requisition.height = height_request;
6073   win->allocation.width = width_request;
6074   win->allocation.height = height_request;
6075   win->allocation.x = 0;
6076   win->allocation.y = 0;
6077
6078   return win;
6079 }
6080
6081 static void
6082 text_window_free (GtkTextWindow *win)
6083 {
6084   if (win->window)
6085     text_window_unrealize (win);
6086
6087   g_free (win);
6088 }
6089
6090 static void
6091 text_window_realize (GtkTextWindow *win,
6092                      GdkWindow     *parent)
6093 {
6094   GdkWindowAttr attributes;
6095   gint attributes_mask;
6096   GdkCursor *cursor;
6097
6098   attributes.window_type = GDK_WINDOW_CHILD;
6099   attributes.x = win->allocation.x;
6100   attributes.y = win->allocation.y;
6101   attributes.width = win->allocation.width;
6102   attributes.height = win->allocation.height;
6103   attributes.wclass = GDK_INPUT_OUTPUT;
6104   attributes.visual = gtk_widget_get_visual (win->widget);
6105   attributes.colormap = gtk_widget_get_colormap (win->widget);
6106   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
6107
6108   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6109
6110   win->window = gdk_window_new (parent,
6111                                 &attributes,
6112                                 attributes_mask);
6113
6114   gdk_window_show (win->window);
6115   gdk_window_set_user_data (win->window, win->widget);
6116
6117   attributes.x = 0;
6118   attributes.y = 0;
6119   attributes.width = win->allocation.width;
6120   attributes.height = win->allocation.height;
6121   attributes.event_mask = (GDK_EXPOSURE_MASK            |
6122                            GDK_SCROLL_MASK              |
6123                            GDK_KEY_PRESS_MASK           |
6124                            GDK_BUTTON_PRESS_MASK        |
6125                            GDK_BUTTON_RELEASE_MASK      |
6126                            GDK_POINTER_MOTION_MASK      |
6127                            GDK_POINTER_MOTION_HINT_MASK |
6128                            gtk_widget_get_events (win->widget));
6129
6130   win->bin_window = gdk_window_new (win->window,
6131                                     &attributes,
6132                                     attributes_mask);
6133
6134   gdk_window_show (win->bin_window);
6135   gdk_window_set_user_data (win->bin_window, win->widget);
6136
6137   if (win->type == GTK_TEXT_WINDOW_TEXT)
6138     {
6139       /* I-beam cursor */
6140       cursor = gdk_cursor_new (GDK_XTERM);
6141       gdk_window_set_cursor (win->bin_window, cursor);
6142       gdk_cursor_destroy (cursor);
6143
6144       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
6145                                         win->window);
6146
6147
6148       gdk_window_set_background (win->bin_window,
6149                                  &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
6150     }
6151   else
6152     {
6153       gdk_window_set_background (win->bin_window,
6154                                  &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
6155     }
6156
6157   g_object_set_qdata (G_OBJECT (win->window),
6158                       g_quark_from_static_string ("gtk-text-view-text-window"),
6159                       win);
6160
6161   g_object_set_qdata (G_OBJECT (win->bin_window),
6162                       g_quark_from_static_string ("gtk-text-view-text-window"),
6163                       win);
6164 }
6165
6166 static void
6167 text_window_unrealize (GtkTextWindow *win)
6168 {
6169   if (win->type == GTK_TEXT_WINDOW_TEXT)
6170     {
6171       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
6172                                         NULL);
6173     }
6174
6175   gdk_window_set_user_data (win->window, NULL);
6176   gdk_window_set_user_data (win->bin_window, NULL);
6177   gdk_window_destroy (win->bin_window);
6178   gdk_window_destroy (win->window);
6179   win->window = NULL;
6180   win->bin_window = NULL;
6181 }
6182
6183 static void
6184 text_window_size_allocate (GtkTextWindow *win,
6185                            GdkRectangle  *rect)
6186 {
6187   win->allocation = *rect;
6188
6189   if (win->window)
6190     {
6191       gdk_window_move_resize (win->window,
6192                               rect->x, rect->y,
6193                               rect->width, rect->height);
6194
6195       gdk_window_resize (win->bin_window,
6196                          rect->width, rect->height);
6197     }
6198 }
6199
6200 static void
6201 text_window_scroll        (GtkTextWindow *win,
6202                            gint           dx,
6203                            gint           dy)
6204 {
6205   if (dx != 0 || dy != 0)
6206     {
6207       gdk_window_scroll (win->bin_window, dx, dy);
6208     }
6209 }
6210
6211 static void
6212 text_window_invalidate_rect (GtkTextWindow *win,
6213                              GdkRectangle  *rect)
6214 {
6215   GdkRectangle window_rect;
6216
6217   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
6218                                          win->type,
6219                                          rect->x,
6220                                          rect->y,
6221                                          &window_rect.x,
6222                                          &window_rect.y);
6223
6224   window_rect.width = rect->width;
6225   window_rect.height = rect->height;
6226   
6227   /* Adjust the rect as appropriate */
6228   
6229   switch (win->type)
6230     {
6231     case GTK_TEXT_WINDOW_TEXT:
6232       break;
6233
6234     case GTK_TEXT_WINDOW_LEFT:
6235     case GTK_TEXT_WINDOW_RIGHT:
6236       window_rect.x = 0;
6237       window_rect.width = win->allocation.width;
6238       break;
6239
6240     case GTK_TEXT_WINDOW_TOP:
6241     case GTK_TEXT_WINDOW_BOTTOM:
6242       window_rect.y = 0;
6243       window_rect.height = win->allocation.height;
6244       break;
6245
6246     default:
6247       g_warning ("%s: bug!", G_STRLOC);
6248       return;
6249       break;
6250     }
6251           
6252   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
6253
6254 #if 0
6255   {
6256     GdkColor color = { 0, 65535, 0, 0 };
6257     GdkGC *gc = gdk_gc_new (win->bin_window);
6258     gdk_gc_set_rgb_fg_color (gc, &color);
6259     gdk_draw_rectangle (win->bin_window,
6260                         gc, TRUE, window_rect.x, window_rect.y,
6261                         window_rect.width, window_rect.height);
6262     gdk_gc_unref (gc);
6263   }
6264 #endif
6265 }
6266
6267 static gint
6268 text_window_get_width (GtkTextWindow *win)
6269 {
6270   return win->allocation.width;
6271 }
6272
6273 static gint
6274 text_window_get_height (GtkTextWindow *win)
6275 {
6276   return win->allocation.height;
6277 }
6278
6279 static void
6280 text_window_get_allocation (GtkTextWindow *win,
6281                             GdkRectangle  *rect)
6282 {
6283   *rect = win->allocation;
6284 }
6285
6286 /* Windows */
6287
6288
6289 /**
6290  * gtk_text_view_get_window:
6291  * @text_view: a #GtkTextView
6292  * @win: window to get
6293  *
6294  * Retrieves the #GdkWindow corresponding to an area of the text view;
6295  * possible windows include the overall widget window, child windows
6296  * on the left, right, top, bottom, and the window that displays the
6297  * text buffer. Windows are %NULL and nonexistent if their width or
6298  * height is 0, and are nonexistent before the widget has been
6299  * realized.
6300  *
6301  * Return value: a #GdkWindow, or %NULL
6302  **/
6303 GdkWindow*
6304 gtk_text_view_get_window (GtkTextView *text_view,
6305                           GtkTextWindowType win)
6306 {
6307   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
6308
6309   switch (win)
6310     {
6311     case GTK_TEXT_WINDOW_WIDGET:
6312       return GTK_WIDGET (text_view)->window;
6313       break;
6314
6315     case GTK_TEXT_WINDOW_TEXT:
6316       return text_view->text_window->bin_window;
6317       break;
6318
6319     case GTK_TEXT_WINDOW_LEFT:
6320       if (text_view->left_window)
6321         return text_view->left_window->bin_window;
6322       else
6323         return NULL;
6324       break;
6325
6326     case GTK_TEXT_WINDOW_RIGHT:
6327       if (text_view->right_window)
6328         return text_view->right_window->bin_window;
6329       else
6330         return NULL;
6331       break;
6332
6333     case GTK_TEXT_WINDOW_TOP:
6334       if (text_view->top_window)
6335         return text_view->top_window->bin_window;
6336       else
6337         return NULL;
6338       break;
6339
6340     case GTK_TEXT_WINDOW_BOTTOM:
6341       if (text_view->bottom_window)
6342         return text_view->bottom_window->bin_window;
6343       else
6344         return NULL;
6345       break;
6346
6347     default:
6348       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
6349       return NULL;
6350       break;
6351     }
6352 }
6353
6354 /**
6355  * gtk_text_view_get_window_type:
6356  * @text_view: a #GtkTextView
6357  * @window: a window type
6358  *
6359  * Usually used to find out which window an event corresponds to.
6360  * If you connect to an event signal on @text_view, this function
6361  * should be called on <literal>event-&gt;window</literal> to
6362  * see which window it was.
6363  *
6364  * Return value: the window type.
6365  **/
6366 GtkTextWindowType
6367 gtk_text_view_get_window_type (GtkTextView *text_view,
6368                                GdkWindow   *window)
6369 {
6370   GtkTextWindow *win;
6371
6372   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
6373   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
6374
6375   if (window == GTK_WIDGET (text_view)->window)
6376     return GTK_TEXT_WINDOW_WIDGET;
6377
6378   win = g_object_get_qdata (G_OBJECT (window),
6379                             g_quark_try_string ("gtk-text-view-text-window"));
6380
6381   if (win)
6382     return win->type;
6383   else
6384     {
6385       return GTK_TEXT_WINDOW_PRIVATE;
6386     }
6387 }
6388
6389 static void
6390 buffer_to_widget (GtkTextView      *text_view,
6391                   gint              buffer_x,
6392                   gint              buffer_y,
6393                   gint             *window_x,
6394                   gint             *window_y)
6395 {
6396   gint focus_edge_width;
6397   gboolean interior_focus;
6398   gint focus_width;
6399   
6400   gtk_widget_style_get (GTK_WIDGET (text_view),
6401                         "interior_focus", &interior_focus,
6402                         "focus_line_width", &focus_width,
6403                         NULL);
6404
6405   if (interior_focus)
6406     focus_edge_width = 0;
6407   else
6408     focus_edge_width = focus_width;
6409   
6410   if (window_x)
6411     {
6412       *window_x = buffer_x - text_view->xoffset + focus_edge_width;
6413       if (text_view->left_window)
6414         *window_x += text_view->left_window->allocation.width;
6415     }
6416
6417   if (window_y)
6418     {
6419       *window_y = buffer_y - text_view->yoffset + focus_edge_width;
6420       if (text_view->top_window)
6421         *window_y += text_view->top_window->allocation.height;
6422     }
6423 }
6424
6425 static void
6426 widget_to_text_window (GtkTextWindow *win,
6427                        gint           widget_x,
6428                        gint           widget_y,
6429                        gint          *window_x,
6430                        gint          *window_y)
6431 {
6432   if (window_x)
6433     *window_x = widget_x - win->allocation.x;
6434
6435   if (window_y)
6436     *window_y = widget_y - win->allocation.y;
6437 }
6438
6439 static void
6440 buffer_to_text_window (GtkTextView   *text_view,
6441                        GtkTextWindow *win,
6442                        gint           buffer_x,
6443                        gint           buffer_y,
6444                        gint          *window_x,
6445                        gint          *window_y)
6446 {
6447   if (win == NULL)
6448     {
6449       g_warning ("Attempt to convert text buffer coordinates to coordinates "
6450                  "for a nonexistent or private child window of GtkTextView");
6451       return;
6452     }
6453
6454   buffer_to_widget (text_view,
6455                     buffer_x, buffer_y,
6456                     window_x, window_y);
6457
6458   widget_to_text_window (win,
6459                          window_x ? *window_x : 0,
6460                          window_y ? *window_y : 0,
6461                          window_x,
6462                          window_y);
6463 }
6464
6465 /**
6466  * gtk_text_view_buffer_to_window_coords:
6467  * @text_view: a #GtkTextView
6468  * @win: a #GtkTextWindowType
6469  * @buffer_x: buffer x coordinate
6470  * @buffer_y: buffer y coordinate
6471  * @window_x: window x coordinate return location
6472  * @window_y: window y coordinate return location
6473  *
6474  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
6475  * @win, and stores the result in (@window_x, @window_y).
6476  **/
6477 void
6478 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
6479                                        GtkTextWindowType win,
6480                                        gint              buffer_x,
6481                                        gint              buffer_y,
6482                                        gint             *window_x,
6483                                        gint             *window_y)
6484 {
6485   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6486
6487   switch (win)
6488     {
6489     case GTK_TEXT_WINDOW_WIDGET:
6490       buffer_to_widget (text_view,
6491                         buffer_x, buffer_y,
6492                         window_x, window_y);
6493       break;
6494
6495     case GTK_TEXT_WINDOW_TEXT:
6496       if (window_x)
6497         *window_x = buffer_x - text_view->xoffset;
6498       if (window_y)
6499         *window_y = buffer_y - text_view->yoffset;
6500       break;
6501
6502     case GTK_TEXT_WINDOW_LEFT:
6503       buffer_to_text_window (text_view,
6504                              text_view->left_window,
6505                              buffer_x, buffer_y,
6506                              window_x, window_y);
6507       break;
6508
6509     case GTK_TEXT_WINDOW_RIGHT:
6510       buffer_to_text_window (text_view,
6511                              text_view->right_window,
6512                              buffer_x, buffer_y,
6513                              window_x, window_y);
6514       break;
6515
6516     case GTK_TEXT_WINDOW_TOP:
6517       buffer_to_text_window (text_view,
6518                              text_view->top_window,
6519                              buffer_x, buffer_y,
6520                              window_x, window_y);
6521       break;
6522
6523     case GTK_TEXT_WINDOW_BOTTOM:
6524       buffer_to_text_window (text_view,
6525                              text_view->bottom_window,
6526                              buffer_x, buffer_y,
6527                              window_x, window_y);
6528       break;
6529
6530     case GTK_TEXT_WINDOW_PRIVATE:
6531       g_warning ("%s: can't get coords for private windows", G_STRLOC);
6532       break;
6533
6534     default:
6535       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
6536       break;
6537     }
6538 }
6539
6540 static void
6541 widget_to_buffer (GtkTextView *text_view,
6542                   gint         widget_x,
6543                   gint         widget_y,
6544                   gint        *buffer_x,
6545                   gint        *buffer_y)
6546 {
6547   gint focus_edge_width;
6548   gboolean interior_focus;
6549   gint focus_width;
6550   
6551   gtk_widget_style_get (GTK_WIDGET (text_view),
6552                         "interior_focus", &interior_focus,
6553                         "focus_line_width", &focus_width,
6554                         NULL);
6555
6556   if (interior_focus)
6557     focus_edge_width = 0;
6558   else
6559     focus_edge_width = focus_width;
6560   
6561   if (buffer_x)
6562     {
6563       *buffer_x = widget_x - focus_edge_width + text_view->xoffset;
6564       if (text_view->left_window)
6565         *buffer_x -= text_view->left_window->allocation.width;
6566     }
6567
6568   if (buffer_y)
6569     {
6570       *buffer_y = widget_y - focus_edge_width + text_view->yoffset;
6571       if (text_view->top_window)
6572         *buffer_y -= text_view->top_window->allocation.height;
6573     }
6574 }
6575
6576 static void
6577 text_window_to_widget (GtkTextWindow *win,
6578                        gint           window_x,
6579                        gint           window_y,
6580                        gint          *widget_x,
6581                        gint          *widget_y)
6582 {
6583   if (widget_x)
6584     *widget_x = window_x + win->allocation.x;
6585
6586   if (widget_y)
6587     *widget_y = window_y + win->allocation.y;
6588 }
6589
6590 static void
6591 text_window_to_buffer (GtkTextView   *text_view,
6592                        GtkTextWindow *win,
6593                        gint           window_x,
6594                        gint           window_y,
6595                        gint          *buffer_x,
6596                        gint          *buffer_y)
6597 {
6598   if (win == NULL)
6599     {
6600       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
6601                  "coordinates for a nonexistent child window.");
6602       return;
6603     }
6604
6605   text_window_to_widget (win,
6606                          window_x,
6607                          window_y,
6608                          buffer_x,
6609                          buffer_y);
6610
6611   widget_to_buffer (text_view,
6612                     buffer_x ? *buffer_x : 0,
6613                     buffer_y ? *buffer_y : 0,
6614                     buffer_x,
6615                     buffer_y);
6616 }
6617
6618 /**
6619  * gtk_text_view_window_to_buffer_coords:
6620  * @text_view: a #GtkTextView
6621  * @win: a #GtkTextWindowType
6622  * @window_x: window x coordinate
6623  * @window_y: window y coordinate
6624  * @buffer_x: buffer x coordinate return location
6625  * @buffer_y: buffer y coordinate return location
6626  *
6627  * Converts coordinates on the window identified by @win to buffer
6628  * coordinates, storing the result in (@buffer_x,@buffer_y).
6629  **/
6630 void
6631 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
6632                                        GtkTextWindowType win,
6633                                        gint              window_x,
6634                                        gint              window_y,
6635                                        gint             *buffer_x,
6636                                        gint             *buffer_y)
6637 {
6638   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6639
6640   switch (win)
6641     {
6642     case GTK_TEXT_WINDOW_WIDGET:
6643       widget_to_buffer (text_view,
6644                         window_x, window_y,
6645                         buffer_x, buffer_y);
6646       break;
6647
6648     case GTK_TEXT_WINDOW_TEXT:
6649       if (buffer_x)
6650         *buffer_x = window_x + text_view->xoffset;
6651       if (buffer_y)
6652         *buffer_y = window_y + text_view->yoffset;
6653       break;
6654
6655     case GTK_TEXT_WINDOW_LEFT:
6656       text_window_to_buffer (text_view,
6657                              text_view->left_window,
6658                              window_x, window_y,
6659                              buffer_x, buffer_y);
6660       break;
6661
6662     case GTK_TEXT_WINDOW_RIGHT:
6663       text_window_to_buffer (text_view,
6664                              text_view->right_window,
6665                              window_x, window_y,
6666                              buffer_x, buffer_y);
6667       break;
6668
6669     case GTK_TEXT_WINDOW_TOP:
6670       text_window_to_buffer (text_view,
6671                              text_view->top_window,
6672                              window_x, window_y,
6673                              buffer_x, buffer_y);
6674       break;
6675
6676     case GTK_TEXT_WINDOW_BOTTOM:
6677       text_window_to_buffer (text_view,
6678                              text_view->bottom_window,
6679                              window_x, window_y,
6680                              buffer_x, buffer_y);
6681       break;
6682
6683     case GTK_TEXT_WINDOW_PRIVATE:
6684       g_warning ("%s: can't get coords for private windows", G_STRLOC);
6685       break;
6686
6687     default:
6688       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
6689       break;
6690     }
6691 }
6692
6693 static void
6694 set_window_width (GtkTextView      *text_view,
6695                   gint              width,
6696                   GtkTextWindowType type,
6697                   GtkTextWindow   **winp)
6698 {
6699   if (width == 0)
6700     {
6701       if (*winp)
6702         {
6703           text_window_free (*winp);
6704           *winp = NULL;
6705           gtk_widget_queue_resize (GTK_WIDGET (text_view));
6706         }
6707     }
6708   else
6709     {
6710       if (*winp == NULL)
6711         {
6712           *winp = text_window_new (type,
6713                                    GTK_WIDGET (text_view),
6714                                    width, 0);
6715           /* if the widget is already realized we need to realize the child manually */
6716           if (GTK_WIDGET_REALIZED (text_view))
6717             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
6718         }
6719       else
6720         {
6721           if ((*winp)->requisition.width == width)
6722             return;
6723
6724           (*winp)->requisition.width = width;
6725         }
6726
6727       gtk_widget_queue_resize (GTK_WIDGET (text_view));
6728     }
6729 }
6730
6731
6732 static void
6733 set_window_height (GtkTextView      *text_view,
6734                    gint              height,
6735                    GtkTextWindowType type,
6736                    GtkTextWindow   **winp)
6737 {
6738   if (height == 0)
6739     {
6740       if (*winp)
6741         {
6742           text_window_free (*winp);
6743           *winp = NULL;
6744           gtk_widget_queue_resize (GTK_WIDGET (text_view));
6745         }
6746     }
6747   else
6748     {
6749       if (*winp == NULL)
6750         {
6751           *winp = text_window_new (type,
6752                                    GTK_WIDGET (text_view),
6753                                    0, height);
6754
6755           /* if the widget is already realized we need to realize the child manually */
6756           if (GTK_WIDGET_REALIZED (text_view))
6757             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
6758         }
6759       else
6760         {
6761           if ((*winp)->requisition.height == height)
6762             return;
6763
6764           (*winp)->requisition.height = height;
6765         }
6766
6767       gtk_widget_queue_resize (GTK_WIDGET (text_view));
6768     }
6769 }
6770
6771 /**
6772  * gtk_text_view_set_border_window_size:
6773  * @text_view: a #GtkTextView
6774  * @type: window to affect
6775  * @size: width or height of the window
6776  *
6777  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
6778  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
6779  * Automatically destroys the corresponding window if the size is set
6780  * to 0, and creates the window if the size is set to non-zero.  This
6781  * function can only be used for the "border windows," it doesn't work
6782  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
6783  * #GTK_TEXT_WINDOW_PRIVATE.
6784  **/
6785 void
6786 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
6787                                       GtkTextWindowType type,
6788                                       gint              size)
6789
6790 {
6791   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6792   g_return_if_fail (size >= 0);
6793
6794   switch (type)
6795     {
6796     case GTK_TEXT_WINDOW_LEFT:
6797       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
6798                         &text_view->left_window);
6799       break;
6800
6801     case GTK_TEXT_WINDOW_RIGHT:
6802       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
6803                         &text_view->right_window);
6804       break;
6805
6806     case GTK_TEXT_WINDOW_TOP:
6807       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
6808                          &text_view->top_window);
6809       break;
6810
6811     case GTK_TEXT_WINDOW_BOTTOM:
6812       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
6813                          &text_view->bottom_window);
6814       break;
6815
6816     default:
6817       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
6818       break;
6819     }
6820 }
6821
6822 /**
6823  * gtk_text_view_get_border_window_size:
6824  * @text_view: a #GtkTextView
6825  * @type: window to return size from
6826  *
6827  * Gets the width of the specified border window. See
6828  * gtk_text_view_set_border_window_size().
6829  *
6830  * Return value: width of window
6831  **/
6832 gint
6833 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
6834                                       GtkTextWindowType  type)
6835 {
6836   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
6837   
6838   switch (type)
6839     {
6840     case GTK_TEXT_WINDOW_LEFT:
6841       if (text_view->left_window)
6842         return text_view->left_window->requisition.width;
6843       
6844     case GTK_TEXT_WINDOW_RIGHT:
6845       if (text_view->right_window)
6846         return text_view->right_window->requisition.width;
6847       
6848     case GTK_TEXT_WINDOW_TOP:
6849       if (text_view->top_window)
6850         return text_view->top_window->requisition.height;
6851
6852     case GTK_TEXT_WINDOW_BOTTOM:
6853       if (text_view->bottom_window)
6854         return text_view->bottom_window->requisition.height;
6855       
6856     default:
6857       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
6858       break;
6859     }
6860
6861   return 0;
6862 }
6863
6864 /*
6865  * Child widgets
6866  */
6867
6868 static GtkTextViewChild*
6869 text_view_child_new_anchored (GtkWidget          *child,
6870                               GtkTextChildAnchor *anchor,
6871                               GtkTextLayout      *layout)
6872 {
6873   GtkTextViewChild *vc;
6874
6875   vc = g_new (GtkTextViewChild, 1);
6876
6877   vc->widget = child;
6878   vc->anchor = anchor;
6879
6880   vc->from_top_of_line = 0;
6881   vc->from_left_of_buffer = 0;
6882   
6883   g_object_ref (G_OBJECT (vc->widget));
6884   g_object_ref (G_OBJECT (vc->anchor));
6885
6886   g_object_set_data (G_OBJECT (child),
6887                      "gtk-text-view-child",
6888                      vc);
6889
6890   gtk_text_child_anchor_register_child (anchor, child, layout);
6891   
6892   return vc;
6893 }
6894
6895 static GtkTextViewChild*
6896 text_view_child_new_window (GtkWidget          *child,
6897                             GtkTextWindowType   type,
6898                             gint                x,
6899                             gint                y)
6900 {
6901   GtkTextViewChild *vc;
6902
6903   vc = g_new (GtkTextViewChild, 1);
6904
6905   vc->widget = child;
6906   vc->anchor = NULL;
6907
6908   vc->from_top_of_line = 0;
6909   vc->from_left_of_buffer = 0;
6910   
6911   g_object_ref (G_OBJECT (vc->widget));
6912
6913   vc->type = type;
6914   vc->x = x;
6915   vc->y = y;
6916
6917   g_object_set_data (G_OBJECT (child),
6918                      "gtk-text-view-child",
6919                      vc);
6920   
6921   return vc;
6922 }
6923
6924 static void
6925 text_view_child_free (GtkTextViewChild *child)
6926 {
6927   g_object_set_data (G_OBJECT (child->widget),
6928                      "gtk-text-view-child", NULL);
6929
6930   if (child->anchor)
6931     {
6932       gtk_text_child_anchor_unregister_child (child->anchor,
6933                                               child->widget);
6934       g_object_unref (G_OBJECT (child->anchor));
6935     }
6936
6937   g_object_unref (G_OBJECT (child->widget));
6938
6939   g_free (child);
6940 }
6941
6942 static void
6943 text_view_child_set_parent_window (GtkTextView      *text_view,
6944                                    GtkTextViewChild *vc)
6945 {
6946   if (vc->anchor)
6947     gtk_widget_set_parent_window (vc->widget,
6948                                   text_view->text_window->bin_window);
6949   else
6950     {
6951       GdkWindow *window;
6952       window = gtk_text_view_get_window (text_view,
6953                                          vc->type);
6954       gtk_widget_set_parent_window (vc->widget, window);
6955     }
6956 }
6957
6958 static void
6959 add_child (GtkTextView      *text_view,
6960            GtkTextViewChild *vc)
6961 {
6962   text_view->children = g_slist_prepend (text_view->children,
6963                                          vc);
6964
6965   if (GTK_WIDGET_REALIZED (text_view))
6966     text_view_child_set_parent_window (text_view, vc);
6967   
6968   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
6969 }
6970
6971 /**
6972  * gtk_text_view_add_child_at_anchor:
6973  * @text_view: a #GtkTextView
6974  * @child: a #GtkWidget
6975  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
6976  * 
6977  * Adds a child widget in the text buffer, at the given @anchor.
6978  * 
6979  **/
6980 void
6981 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
6982                                    GtkWidget            *child,
6983                                    GtkTextChildAnchor   *anchor)
6984 {
6985   GtkTextViewChild *vc;
6986
6987   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6988   g_return_if_fail (GTK_IS_WIDGET (child));
6989   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
6990   g_return_if_fail (child->parent == NULL);
6991
6992   gtk_text_view_ensure_layout (text_view);
6993
6994   vc = text_view_child_new_anchored (child, anchor,
6995                                      text_view->layout);
6996
6997   add_child (text_view, vc);
6998
6999   g_assert (vc->widget == child);
7000   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
7001 }
7002
7003 /**
7004  * gtk_text_view_add_child_in_window:
7005  * @text_view: a #GtkTextView
7006  * @child: a #GtkWidget
7007  * @which_window: which window the child should appear in
7008  * @xpos: X position of child in window coordinates
7009  * @ypos: Y position of child in window coordinates
7010  *
7011  * Adds a child at fixed coordinates in one of the text widget's
7012  * windows.  The window must have nonzero size (see
7013  * gtk_text_view_set_border_window_size()).  Note that the child
7014  * coordinates are given relative to the #GdkWindow in question, and
7015  * that these coordinates have no sane relationship to scrolling. When
7016  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
7017  * irrelevant, the child floats above all scrollable areas. But when
7018  * placing a child in one of the scrollable windows (border windows or
7019  * text window), you'll need to compute the child's correct position
7020  * in buffer coordinates any time scrolling occurs or buffer changes
7021  * occur, and then call gtk_text_view_move_child() to update the
7022  * child's position. Unfortunately there's no good way to detect that
7023  * scrolling has occurred, using the current API; a possible hack
7024  * would be to update all child positions when the scroll adjustments
7025  * change or the text buffer changes. See bug 64518 on
7026  * bugzilla.gnome.org for status of fixing this issue.
7027  *
7028  **/
7029 void
7030 gtk_text_view_add_child_in_window (GtkTextView          *text_view,
7031                                    GtkWidget            *child,
7032                                    GtkTextWindowType     which_window,
7033                                    gint                  xpos,
7034                                    gint                  ypos)
7035 {
7036   GtkTextViewChild *vc;
7037
7038   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7039   g_return_if_fail (GTK_IS_WIDGET (child));
7040   g_return_if_fail (child->parent == NULL);
7041
7042   vc = text_view_child_new_window (child, which_window,
7043                                    xpos, ypos);
7044
7045   add_child (text_view, vc);
7046
7047   g_assert (vc->widget == child);
7048   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
7049 }
7050
7051 /**
7052  * gtk_text_view_move_child:
7053  * @text_view: a #GtkTextView
7054  * @child: child widget already added to the text view
7055  * @xpos: new X position in window coordinates
7056  * @ypos: new Y position in window coordinates
7057  *
7058  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
7059  * 
7060  **/
7061 void
7062 gtk_text_view_move_child          (GtkTextView          *text_view,
7063                                    GtkWidget            *child,
7064                                    gint                  xpos,
7065                                    gint                  ypos)
7066 {
7067   GtkTextViewChild *vc;
7068
7069   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7070   g_return_if_fail (GTK_IS_WIDGET (child));
7071   g_return_if_fail (child->parent == (GtkWidget*) text_view);
7072
7073   vc = g_object_get_data (G_OBJECT (child),
7074                           "gtk-text-view-child");
7075
7076   g_assert (vc != NULL);
7077
7078   if (vc->x == xpos &&
7079       vc->y == ypos)
7080     return;
7081   
7082   vc->x = xpos;
7083   vc->y = ypos;
7084
7085   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
7086     gtk_widget_queue_resize (child);
7087 }
7088
7089
7090 /* Iterator operations */
7091
7092 /**
7093  * gtk_text_view_forward_display_line:
7094  * @text_view: a #GtkTextView
7095  * @iter: a #GtkTextIter
7096  * 
7097  * Moves the given @iter forward by one display (wrapped) line.  A
7098  * display line is different from a paragraph. Paragraphs are
7099  * separated by newlines or other paragraph separator characters.
7100  * Display lines are created by line-wrapping a paragraph.  If
7101  * wrapping is turned off, display lines and paragraphs will be the
7102  * same. Display lines are divided differently for each view, since
7103  * they depend on the view's width; paragraphs are the same in all
7104  * views, since they depend on the contents of the #GtkTextBuffer.
7105  * 
7106  * Return value: %TRUE if @iter was moved and is not on the end iterator
7107  **/
7108 gboolean
7109 gtk_text_view_forward_display_line (GtkTextView *text_view,
7110                                     GtkTextIter *iter)
7111 {
7112   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7113   g_return_val_if_fail (iter != NULL, FALSE);
7114
7115   gtk_text_view_ensure_layout (text_view);
7116
7117   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
7118 }
7119
7120 /**
7121  * gtk_text_view_backward_display_line:
7122  * @text_view: a #GtkTextView
7123  * @iter: a #GtkTextIter
7124  * 
7125  * Moves the given @iter backward by one display (wrapped) line.  A
7126  * display line is different from a paragraph. Paragraphs are
7127  * separated by newlines or other paragraph separator characters.
7128  * Display lines are created by line-wrapping a paragraph.  If
7129  * wrapping is turned off, display lines and paragraphs will be the
7130  * same. Display lines are divided differently for each view, since
7131  * they depend on the view's width; paragraphs are the same in all
7132  * views, since they depend on the contents of the #GtkTextBuffer.
7133  * 
7134  * Return value: %TRUE if @iter was moved and is not on the end iterator
7135  **/
7136 gboolean
7137 gtk_text_view_backward_display_line (GtkTextView *text_view,
7138                                      GtkTextIter *iter)
7139 {
7140   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7141   g_return_val_if_fail (iter != NULL, FALSE);
7142
7143   gtk_text_view_ensure_layout (text_view);
7144
7145   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
7146 }
7147
7148 /**
7149  * gtk_text_view_forward_display_line_end:
7150  * @text_view: a #GtkTextView
7151  * @iter: a #GtkTextIter
7152  * 
7153  * Moves the given @iter forward to the next display line end.  A
7154  * display line is different from a paragraph. Paragraphs are
7155  * separated by newlines or other paragraph separator characters.
7156  * Display lines are created by line-wrapping a paragraph.  If
7157  * wrapping is turned off, display lines and paragraphs will be the
7158  * same. Display lines are divided differently for each view, since
7159  * they depend on the view's width; paragraphs are the same in all
7160  * views, since they depend on the contents of the #GtkTextBuffer.
7161  * 
7162  * Return value: %TRUE if @iter was moved and is not on the end iterator
7163  **/
7164 gboolean
7165 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
7166                                         GtkTextIter *iter)
7167 {
7168   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7169   g_return_val_if_fail (iter != NULL, FALSE);
7170
7171   gtk_text_view_ensure_layout (text_view);
7172
7173   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
7174 }
7175
7176 /**
7177  * gtk_text_view_backward_display_line_start:
7178  * @text_view: a #GtkTextView
7179  * @iter: a #GtkTextIter
7180  * 
7181  * Moves the given @iter backward to the next display line start.  A
7182  * display line is different from a paragraph. Paragraphs are
7183  * separated by newlines or other paragraph separator characters.
7184  * Display lines are created by line-wrapping a paragraph.  If
7185  * wrapping is turned off, display lines and paragraphs will be the
7186  * same. Display lines are divided differently for each view, since
7187  * they depend on the view's width; paragraphs are the same in all
7188  * views, since they depend on the contents of the #GtkTextBuffer.
7189  * 
7190  * Return value: %TRUE if @iter was moved and is not on the end iterator
7191  **/
7192 gboolean
7193 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
7194                                            GtkTextIter *iter)
7195 {
7196   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7197   g_return_val_if_fail (iter != NULL, FALSE);
7198
7199   gtk_text_view_ensure_layout (text_view);
7200
7201   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
7202 }
7203
7204 /**
7205  * gtk_text_view_starts_display_line:
7206  * @text_view: a #GtkTextView
7207  * @iter: a #GtkTextIter
7208  * 
7209  * Determines whether @iter is at the start of a display line.
7210  * See gtk_text_view_forward_display_line() for an explanation of
7211  * display lines vs. paragraphs.
7212  * 
7213  * Return value: %TRUE if @iter begins a wrapped line
7214  **/
7215 gboolean
7216 gtk_text_view_starts_display_line (GtkTextView       *text_view,
7217                                    const GtkTextIter *iter)
7218 {
7219   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7220   g_return_val_if_fail (iter != NULL, FALSE);
7221
7222   gtk_text_view_ensure_layout (text_view);
7223
7224   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
7225 }
7226
7227 /**
7228  * gtk_text_view_move_visually:
7229  * @text_view: a #GtkTextView
7230  * @iter: a #GtkTextIter
7231  * @count: number of lines to move
7232  * 
7233  * Moves @iter up or down by @count display (wrapped) lines.
7234  * See gtk_text_view_forward_display_line() for an explanation of
7235  * display lines vs. paragraphs.
7236  * 
7237  * Return value: %TRUE if @iter moved and is not on the end iterator
7238  **/
7239 gboolean
7240 gtk_text_view_move_visually (GtkTextView *text_view,
7241                              GtkTextIter *iter,
7242                              gint         count)
7243 {
7244   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
7245   g_return_val_if_fail (iter != NULL, FALSE);
7246
7247   gtk_text_view_ensure_layout (text_view);
7248
7249   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
7250 }