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