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