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