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