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