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