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