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