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