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