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