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