]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
Give this code a chance to work
[~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
137   GtkTextWindow *text_window;
138   GtkTextWindow *left_window;
139   GtkTextWindow *right_window;
140   GtkTextWindow *top_window;
141   GtkTextWindow *bottom_window;
142
143   GtkAdjustment *hadjustment;
144   GtkAdjustment *vadjustment;
145
146   gint xoffset;         /* Offsets between widget coordinates and buffer coordinates */
147   gint yoffset;
148   gint width;           /* Width and height of the buffer */
149   gint height;
150
151   /* This is used to monitor the overall size request 
152    * and decide whether we need to queue resizes when
153    * the buffer content changes. 
154    *
155    * FIXME: This could be done in a simpler way by 
156    * consulting the above width/height of the buffer + some
157    * padding values, however all of this request code needs
158    * to be changed to use GtkWidget     Iface and deserves
159    * more attention.
160    */
161   GtkRequisition cached_size_request;
162
163   /* The virtual cursor position is normally the same as the
164    * actual (strong) cursor position, except in two circumstances:
165    *
166    * a) When the cursor is moved vertically with the keyboard
167    * b) When the text view is scrolled with the keyboard
168    *
169    * In case a), virtual_cursor_x is preserved, but not virtual_cursor_y
170    * In case b), both virtual_cursor_x and virtual_cursor_y are preserved.
171    */
172   gint virtual_cursor_x;   /* -1 means use actual cursor position */
173   gint virtual_cursor_y;   /* -1 means use actual cursor position */
174
175   GtkTextMark *first_para_mark; /* Mark at the beginning of the first onscreen paragraph */
176   gint first_para_pixels;       /* Offset of top of screen in the first onscreen paragraph */
177
178   guint blink_timeout;
179   guint scroll_timeout;
180
181   guint first_validate_idle;        /* Idle to revalidate onscreen portion, runs before resize */
182   guint incremental_validate_idle;  /* Idle to revalidate offscreen portions, runs after redraw */
183
184   gint pending_place_cursor_button;
185
186   GtkTextMark *dnd_mark;
187
188   GtkIMContext *im_context;
189   GtkWidget *popup_menu;
190
191   gint drag_start_x;
192   gint drag_start_y;
193
194   GSList *children;
195
196   GtkTextPendingScroll *pending_scroll;
197
198   /* Default style settings */
199   gint pixels_above_lines;
200   gint pixels_below_lines;
201   gint pixels_inside_wrap;
202   GtkWrapMode wrap_mode;
203   GtkJustification justify;
204   gint left_margin;
205   gint right_margin;
206   gint indent;
207   PangoTabArray *tabs;
208   guint editable : 1;
209
210   guint overwrite_mode : 1;
211   guint cursor_visible : 1;
212
213   /* if we have reset the IM since the last character entered */
214   guint need_im_reset : 1;
215
216   guint accepts_tab : 1;
217
218   guint width_changed : 1;
219
220   /* debug flag - means that we've validated onscreen since the
221    * last "invalidate" signal from the layout
222    */
223   guint onscreen_validated : 1;
224
225   guint mouse_cursor_obscured : 1;
226
227   guint scroll_after_paste : 1;
228
229   /* GtkScrollablePolicy needs to be checked when
230    * driving the scrollable adjustment values */
231   guint hscroll_policy : 1;
232   guint vscroll_policy : 1;
233 };
234
235 struct _GtkTextPendingScroll
236 {
237   GtkTextMark   *mark;
238   gdouble        within_margin;
239   gboolean       use_align;
240   gdouble        xalign;
241   gdouble        yalign;
242 };
243
244 enum
245 {
246   POPULATE_POPUP,
247   MOVE_CURSOR,
248   PAGE_HORIZONTALLY,
249   SET_ANCHOR,
250   INSERT_AT_CURSOR,
251   DELETE_FROM_CURSOR,
252   BACKSPACE,
253   CUT_CLIPBOARD,
254   COPY_CLIPBOARD,
255   PASTE_CLIPBOARD,
256   TOGGLE_OVERWRITE,
257   MOVE_VIEWPORT,
258   SELECT_ALL,
259   TOGGLE_CURSOR_VISIBLE,
260   PREEDIT_CHANGED,
261   LAST_SIGNAL
262 };
263
264 enum
265 {
266   PROP_0,
267   PROP_PIXELS_ABOVE_LINES,
268   PROP_PIXELS_BELOW_LINES,
269   PROP_PIXELS_INSIDE_WRAP,
270   PROP_EDITABLE,
271   PROP_WRAP_MODE,
272   PROP_JUSTIFICATION,
273   PROP_LEFT_MARGIN,
274   PROP_RIGHT_MARGIN,
275   PROP_INDENT,
276   PROP_TABS,
277   PROP_CURSOR_VISIBLE,
278   PROP_BUFFER,
279   PROP_OVERWRITE,
280   PROP_ACCEPTS_TAB,
281   PROP_IM_MODULE,
282   PROP_HADJUSTMENT,
283   PROP_VADJUSTMENT,
284   PROP_HSCROLL_POLICY,
285   PROP_VSCROLL_POLICY
286 };
287
288 static void gtk_text_view_finalize             (GObject          *object);
289 static void gtk_text_view_set_property         (GObject         *object,
290                                                 guint            prop_id,
291                                                 const GValue    *value,
292                                                 GParamSpec      *pspec);
293 static void gtk_text_view_get_property         (GObject         *object,
294                                                 guint            prop_id,
295                                                 GValue          *value,
296                                                 GParamSpec      *pspec);
297 static void gtk_text_view_destroy              (GtkWidget        *widget);
298 static void gtk_text_view_size_request         (GtkWidget        *widget,
299                                                 GtkRequisition   *requisition);
300 static void gtk_text_view_get_preferred_width  (GtkWidget        *widget,
301                                                 gint             *minimum,
302                                                 gint             *natural);
303 static void gtk_text_view_get_preferred_height (GtkWidget        *widget,
304                                                 gint             *minimum,
305                                                 gint             *natural);
306 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
307                                                 GtkAllocation    *allocation);
308 static void gtk_text_view_realize              (GtkWidget        *widget);
309 static void gtk_text_view_unrealize            (GtkWidget        *widget);
310 static void gtk_text_view_style_updated        (GtkWidget        *widget);
311 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
312                                                 GtkTextDirection  previous_direction);
313 static void gtk_text_view_grab_notify          (GtkWidget        *widget,
314                                                 gboolean         was_grabbed);
315 static void gtk_text_view_state_flags_changed  (GtkWidget        *widget,
316                                                 GtkStateFlags     previous_state);
317
318 static gint gtk_text_view_event                (GtkWidget        *widget,
319                                                 GdkEvent         *event);
320 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
321                                                 GdkEventKey      *event);
322 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
323                                                 GdkEventKey      *event);
324 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
325                                                 GdkEventButton   *event);
326 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
327                                                 GdkEventButton   *event);
328 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
329                                                 GdkEventFocus    *event);
330 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
331                                                 GdkEventFocus    *event);
332 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
333                                                 GdkEventMotion   *event);
334 static gint gtk_text_view_draw                 (GtkWidget        *widget,
335                                                 cairo_t          *cr);
336 static void gtk_text_view_draw_focus           (GtkWidget        *widget,
337                                                 cairo_t          *cr);
338 static gboolean gtk_text_view_focus            (GtkWidget        *widget,
339                                                 GtkDirectionType  direction);
340 static void gtk_text_view_select_all           (GtkWidget        *widget,
341                                                 gboolean          select);
342
343
344 /* Source side drag signals */
345 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
346                                             GdkDragContext   *context);
347 static void gtk_text_view_drag_end         (GtkWidget        *widget,
348                                             GdkDragContext   *context);
349 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
350                                             GdkDragContext   *context,
351                                             GtkSelectionData *selection_data,
352                                             guint             info,
353                                             guint             time);
354 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
355                                             GdkDragContext   *context);
356
357 /* Target side drag signals */
358 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
359                                                   GdkDragContext   *context,
360                                                   guint             time);
361 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
362                                                   GdkDragContext   *context,
363                                                   gint              x,
364                                                   gint              y,
365                                                   guint             time);
366 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
367                                                   GdkDragContext   *context,
368                                                   gint              x,
369                                                   gint              y,
370                                                   guint             time);
371 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
372                                                   GdkDragContext   *context,
373                                                   gint              x,
374                                                   gint              y,
375                                                   GtkSelectionData *selection_data,
376                                                   guint             info,
377                                                   guint             time);
378
379 static gboolean gtk_text_view_popup_menu         (GtkWidget     *widget);
380
381 static void gtk_text_view_move_cursor       (GtkTextView           *text_view,
382                                              GtkMovementStep        step,
383                                              gint                   count,
384                                              gboolean               extend_selection);
385 static void gtk_text_view_move_viewport     (GtkTextView           *text_view,
386                                              GtkScrollStep          step,
387                                              gint                   count);
388 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
389 static gboolean gtk_text_view_scroll_pages (GtkTextView           *text_view,
390                                             gint                   count,
391                                             gboolean               extend_selection);
392 static gboolean gtk_text_view_scroll_hpages(GtkTextView           *text_view,
393                                             gint                   count,
394                                             gboolean               extend_selection);
395 static void gtk_text_view_insert_at_cursor (GtkTextView           *text_view,
396                                             const gchar           *str);
397 static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
398                                               GtkDeleteType          type,
399                                               gint                   count);
400 static void gtk_text_view_backspace        (GtkTextView           *text_view);
401 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
402 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
403 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
404 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
405 static void gtk_text_view_toggle_cursor_visible (GtkTextView      *text_view);
406
407 static void gtk_text_view_unselect         (GtkTextView           *text_view);
408
409 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
410 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
411                                                      GtkTextIter        *iter);
412 static void     gtk_text_view_update_layout_width       (GtkTextView        *text_view);
413 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
414                                                          GtkTextAttributes  *values);
415 static void     gtk_text_view_ensure_layout          (GtkTextView        *text_view);
416 static void     gtk_text_view_destroy_layout         (GtkTextView        *text_view);
417 static void     gtk_text_view_check_keymap_direction (GtkTextView        *text_view);
418 static void     gtk_text_view_start_selection_drag   (GtkTextView        *text_view,
419                                                       const GtkTextIter  *iter,
420                                                       GdkEventButton     *event);
421 static gboolean gtk_text_view_end_selection_drag     (GtkTextView        *text_view);
422 static void     gtk_text_view_start_selection_dnd    (GtkTextView        *text_view,
423                                                       const GtkTextIter  *iter,
424                                                       GdkEventMotion     *event);
425 static void     gtk_text_view_check_cursor_blink     (GtkTextView        *text_view);
426 static void     gtk_text_view_pend_cursor_blink      (GtkTextView        *text_view);
427 static void     gtk_text_view_stop_cursor_blink      (GtkTextView        *text_view);
428 static void     gtk_text_view_reset_blink_time       (GtkTextView        *text_view);
429
430 static void     gtk_text_view_value_changed                (GtkAdjustment *adjustment,
431                                                             GtkTextView   *view);
432 static void     gtk_text_view_commit_handler               (GtkIMContext  *context,
433                                                             const gchar   *str,
434                                                             GtkTextView   *text_view);
435 static void     gtk_text_view_commit_text                  (GtkTextView   *text_view,
436                                                             const gchar   *text);
437 static void     gtk_text_view_preedit_changed_handler      (GtkIMContext  *context,
438                                                             GtkTextView   *text_view);
439 static gboolean gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
440                                                             GtkTextView   *text_view);
441 static gboolean gtk_text_view_delete_surrounding_handler   (GtkIMContext  *context,
442                                                             gint           offset,
443                                                             gint           n_chars,
444                                                             GtkTextView   *text_view);
445
446 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
447                                                   const GtkTextIter *location,
448                                                   GtkTextMark       *mark,
449                                                   gpointer           data);
450 static void gtk_text_view_target_list_notify     (GtkTextBuffer     *buffer,
451                                                   const GParamSpec  *pspec,
452                                                   gpointer           data);
453 static void gtk_text_view_paste_done_handler     (GtkTextBuffer     *buffer,
454                                                   GtkClipboard      *clipboard,
455                                                   gpointer           data);
456 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
457                                                   GtkTextIter       *cursor,
458                                                   gint              *x,
459                                                   gint              *y);
460 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
461                                                   gint               x,
462                                                   gint               y);
463
464 static void gtk_text_view_do_popup               (GtkTextView       *text_view,
465                                                   GdkEventButton    *event);
466
467 static void cancel_pending_scroll                (GtkTextView   *text_view);
468 static void gtk_text_view_queue_scroll           (GtkTextView   *text_view,
469                                                   GtkTextMark   *mark,
470                                                   gdouble        within_margin,
471                                                   gboolean       use_align,
472                                                   gdouble        xalign,
473                                                   gdouble        yalign);
474
475 static gboolean gtk_text_view_flush_scroll         (GtkTextView *text_view);
476 static void     gtk_text_view_update_adjustments   (GtkTextView *text_view);
477 static void     gtk_text_view_invalidate           (GtkTextView *text_view);
478 static void     gtk_text_view_flush_first_validate (GtkTextView *text_view);
479
480 static void     gtk_text_view_set_hadjustment        (GtkTextView   *text_view,
481                                                       GtkAdjustment *adjustment);
482 static void     gtk_text_view_set_vadjustment        (GtkTextView   *text_view,
483                                                       GtkAdjustment *adjustment);
484 static void     gtk_text_view_set_hadjustment_values (GtkTextView   *text_view);
485 static void     gtk_text_view_set_vadjustment_values (GtkTextView   *text_view);
486
487 static void gtk_text_view_update_im_spot_location (GtkTextView *text_view);
488
489 /* Container methods */
490 static void gtk_text_view_add    (GtkContainer *container,
491                                   GtkWidget    *child);
492 static void gtk_text_view_remove (GtkContainer *container,
493                                   GtkWidget    *child);
494 static void gtk_text_view_forall (GtkContainer *container,
495                                   gboolean      include_internals,
496                                   GtkCallback   callback,
497                                   gpointer      callback_data);
498
499 /* FIXME probably need the focus methods. */
500
501 typedef struct _GtkTextViewChild GtkTextViewChild;
502
503 struct _GtkTextViewChild
504 {
505   GtkWidget *widget;
506
507   GtkTextChildAnchor *anchor;
508
509   gint from_top_of_line;
510   gint from_left_of_buffer;
511   
512   /* These are ignored if anchor != NULL */
513   GtkTextWindowType type;
514   gint x;
515   gint y;
516 };
517
518 static GtkTextViewChild* text_view_child_new_anchored      (GtkWidget          *child,
519                                                             GtkTextChildAnchor *anchor,
520                                                             GtkTextLayout      *layout);
521 static GtkTextViewChild* text_view_child_new_window        (GtkWidget          *child,
522                                                             GtkTextWindowType   type,
523                                                             gint                x,
524                                                             gint                y);
525 static void              text_view_child_free              (GtkTextViewChild   *child);
526 static void              text_view_child_set_parent_window (GtkTextView        *text_view,
527                                                             GtkTextViewChild   *child);
528
529 struct _GtkTextWindow
530 {
531   GtkTextWindowType type;
532   GtkWidget *widget;
533   GdkWindow *window;
534   GdkWindow *bin_window;
535   GtkRequisition requisition;
536   GdkRectangle allocation;
537 };
538
539 static GtkTextWindow *text_window_new             (GtkTextWindowType  type,
540                                                    GtkWidget         *widget,
541                                                    gint               width_request,
542                                                    gint               height_request);
543 static void           text_window_free            (GtkTextWindow     *win);
544 static void           text_window_realize         (GtkTextWindow     *win,
545                                                    GtkWidget         *widget);
546 static void           text_window_unrealize       (GtkTextWindow     *win);
547 static void           text_window_size_allocate   (GtkTextWindow     *win,
548                                                    GdkRectangle      *rect);
549 static void           text_window_scroll          (GtkTextWindow     *win,
550                                                    gint               dx,
551                                                    gint               dy);
552 static void           text_window_invalidate_rect (GtkTextWindow     *win,
553                                                    GdkRectangle      *rect);
554 static void           text_window_invalidate_cursors (GtkTextWindow  *win);
555
556 static gint           text_window_get_width       (GtkTextWindow     *win);
557 static gint           text_window_get_height      (GtkTextWindow     *win);
558
559
560 static guint signals[LAST_SIGNAL] = { 0 };
561
562 G_DEFINE_TYPE_WITH_CODE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER,
563                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
564
565 static void
566 add_move_binding (GtkBindingSet  *binding_set,
567                   guint           keyval,
568                   guint           modmask,
569                   GtkMovementStep step,
570                   gint            count)
571 {
572   g_assert ((modmask & GDK_SHIFT_MASK) == 0);
573
574   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
575                                 "move-cursor", 3,
576                                 G_TYPE_ENUM, step,
577                                 G_TYPE_INT, count,
578                                 G_TYPE_BOOLEAN, FALSE);
579
580   /* Selection-extending version */
581   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
582                                 "move-cursor", 3,
583                                 G_TYPE_ENUM, step,
584                                 G_TYPE_INT, count,
585                                 G_TYPE_BOOLEAN, TRUE);
586 }
587
588 static void
589 gtk_text_view_class_init (GtkTextViewClass *klass)
590 {
591   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
592   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
593   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
594   GtkBindingSet *binding_set;
595
596   /* Default handlers and virtual methods
597    */
598   gobject_class->set_property = gtk_text_view_set_property;
599   gobject_class->get_property = gtk_text_view_get_property;
600   gobject_class->finalize = gtk_text_view_finalize;
601
602   widget_class->destroy = gtk_text_view_destroy;
603   widget_class->realize = gtk_text_view_realize;
604   widget_class->unrealize = gtk_text_view_unrealize;
605   widget_class->style_updated = gtk_text_view_style_updated;
606   widget_class->direction_changed = gtk_text_view_direction_changed;
607   widget_class->grab_notify = gtk_text_view_grab_notify;
608   widget_class->state_flags_changed = gtk_text_view_state_flags_changed;
609   widget_class->get_preferred_width = gtk_text_view_get_preferred_width;
610   widget_class->get_preferred_height = gtk_text_view_get_preferred_height;
611   widget_class->size_allocate = gtk_text_view_size_allocate;
612   widget_class->event = gtk_text_view_event;
613   widget_class->key_press_event = gtk_text_view_key_press_event;
614   widget_class->key_release_event = gtk_text_view_key_release_event;
615   widget_class->button_press_event = gtk_text_view_button_press_event;
616   widget_class->button_release_event = gtk_text_view_button_release_event;
617   widget_class->focus_in_event = gtk_text_view_focus_in_event;
618   widget_class->focus_out_event = gtk_text_view_focus_out_event;
619   widget_class->motion_notify_event = gtk_text_view_motion_event;
620   widget_class->draw = gtk_text_view_draw;
621   widget_class->focus = gtk_text_view_focus;
622   widget_class->drag_begin = gtk_text_view_drag_begin;
623   widget_class->drag_end = gtk_text_view_drag_end;
624   widget_class->drag_data_get = gtk_text_view_drag_data_get;
625   widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
626
627   widget_class->drag_leave = gtk_text_view_drag_leave;
628   widget_class->drag_motion = gtk_text_view_drag_motion;
629   widget_class->drag_drop = gtk_text_view_drag_drop;
630   widget_class->drag_data_received = gtk_text_view_drag_data_received;
631
632   widget_class->popup_menu = gtk_text_view_popup_menu;
633   
634   container_class->add = gtk_text_view_add;
635   container_class->remove = gtk_text_view_remove;
636   container_class->forall = gtk_text_view_forall;
637
638   klass->move_cursor = gtk_text_view_move_cursor;
639   klass->set_anchor = gtk_text_view_set_anchor;
640   klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
641   klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
642   klass->backspace = gtk_text_view_backspace;
643   klass->cut_clipboard = gtk_text_view_cut_clipboard;
644   klass->copy_clipboard = gtk_text_view_copy_clipboard;
645   klass->paste_clipboard = gtk_text_view_paste_clipboard;
646   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
647
648   /*
649    * Properties
650    */
651  
652   g_object_class_install_property (gobject_class,
653                                    PROP_PIXELS_ABOVE_LINES,
654                                    g_param_spec_int ("pixels-above-lines",
655                                                      P_("Pixels Above Lines"),
656                                                      P_("Pixels of blank space above paragraphs"),
657                                                      0,
658                                                      G_MAXINT,
659                                                      0,
660                                                      GTK_PARAM_READWRITE));
661  
662   g_object_class_install_property (gobject_class,
663                                    PROP_PIXELS_BELOW_LINES,
664                                    g_param_spec_int ("pixels-below-lines",
665                                                      P_("Pixels Below Lines"),
666                                                      P_("Pixels of blank space below paragraphs"),
667                                                      0,
668                                                      G_MAXINT,
669                                                      0,
670                                                      GTK_PARAM_READWRITE));
671  
672   g_object_class_install_property (gobject_class,
673                                    PROP_PIXELS_INSIDE_WRAP,
674                                    g_param_spec_int ("pixels-inside-wrap",
675                                                      P_("Pixels Inside Wrap"),
676                                                      P_("Pixels of blank space between wrapped lines in a paragraph"),
677                                                      0,
678                                                      G_MAXINT,
679                                                      0,
680                                                      GTK_PARAM_READWRITE));
681
682   g_object_class_install_property (gobject_class,
683                                    PROP_EDITABLE,
684                                    g_param_spec_boolean ("editable",
685                                                          P_("Editable"),
686                                                          P_("Whether the text can be modified by the user"),
687                                                          TRUE,
688                                                          GTK_PARAM_READWRITE));
689
690   g_object_class_install_property (gobject_class,
691                                    PROP_WRAP_MODE,
692                                    g_param_spec_enum ("wrap-mode",
693                                                       P_("Wrap Mode"),
694                                                       P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
695                                                       GTK_TYPE_WRAP_MODE,
696                                                       GTK_WRAP_NONE,
697                                                       GTK_PARAM_READWRITE));
698  
699   g_object_class_install_property (gobject_class,
700                                    PROP_JUSTIFICATION,
701                                    g_param_spec_enum ("justification",
702                                                       P_("Justification"),
703                                                       P_("Left, right, or center justification"),
704                                                       GTK_TYPE_JUSTIFICATION,
705                                                       GTK_JUSTIFY_LEFT,
706                                                       GTK_PARAM_READWRITE));
707  
708   g_object_class_install_property (gobject_class,
709                                    PROP_LEFT_MARGIN,
710                                    g_param_spec_int ("left-margin",
711                                                      P_("Left Margin"),
712                                                      P_("Width of the left margin in pixels"),
713                                                      0,
714                                                      G_MAXINT,
715                                                      0,
716                                                      GTK_PARAM_READWRITE));
717
718   g_object_class_install_property (gobject_class,
719                                    PROP_RIGHT_MARGIN,
720                                    g_param_spec_int ("right-margin",
721                                                      P_("Right Margin"),
722                                                      P_("Width of the right margin in pixels"),
723                                                      0,
724                                                      G_MAXINT,
725                                                      0,
726                                                      GTK_PARAM_READWRITE));
727
728   g_object_class_install_property (gobject_class,
729                                    PROP_INDENT,
730                                    g_param_spec_int ("indent",
731                                                      P_("Indent"),
732                                                      P_("Amount to indent the paragraph, in pixels"),
733                                                      G_MININT,
734                                                      G_MAXINT,
735                                                      0,
736                                                      GTK_PARAM_READWRITE));
737
738   g_object_class_install_property (gobject_class,
739                                    PROP_TABS,
740                                    g_param_spec_boxed ("tabs",
741                                                        P_("Tabs"),
742                                                        P_("Custom tabs for this text"),
743                                                        PANGO_TYPE_TAB_ARRAY,
744                                                        GTK_PARAM_READWRITE));
745
746   g_object_class_install_property (gobject_class,
747                                    PROP_CURSOR_VISIBLE,
748                                    g_param_spec_boolean ("cursor-visible",
749                                                          P_("Cursor Visible"),
750                                                          P_("If the insertion cursor is shown"),
751                                                          TRUE,
752                                                          GTK_PARAM_READWRITE));
753
754   g_object_class_install_property (gobject_class,
755                                    PROP_BUFFER,
756                                    g_param_spec_object ("buffer",
757                                                         P_("Buffer"),
758                                                         P_("The buffer which is displayed"),
759                                                         GTK_TYPE_TEXT_BUFFER,
760                                                         GTK_PARAM_READWRITE));
761
762   g_object_class_install_property (gobject_class,
763                                    PROP_OVERWRITE,
764                                    g_param_spec_boolean ("overwrite",
765                                                          P_("Overwrite mode"),
766                                                          P_("Whether entered text overwrites existing contents"),
767                                                          FALSE,
768                                                          GTK_PARAM_READWRITE));
769
770   g_object_class_install_property (gobject_class,
771                                    PROP_ACCEPTS_TAB,
772                                    g_param_spec_boolean ("accepts-tab",
773                                                          P_("Accepts tab"),
774                                                          P_("Whether Tab will result in a tab character being entered"),
775                                                          TRUE,
776                                                          GTK_PARAM_READWRITE));
777
778    /**
779     * GtkTextView:im-module:
780     *
781     * Which IM (input method) module should be used for this entry. 
782     * See #GtkIMContext.
783     *
784     * Setting this to a non-%NULL value overrides the
785     * system-wide IM module setting. See the GtkSettings 
786     * #GtkSettings:gtk-im-module property.
787     *
788     * Since: 2.16
789     */
790    g_object_class_install_property (gobject_class,
791                                     PROP_IM_MODULE,
792                                     g_param_spec_string ("im-module",
793                                                          P_("IM module"),
794                                                          P_("Which IM module should be used"),
795                                                          NULL,
796                                                          GTK_PARAM_READWRITE));
797
798    /* GtkScrollable interface */
799    g_object_class_override_property (gobject_class, PROP_HADJUSTMENT,    "hadjustment");
800    g_object_class_override_property (gobject_class, PROP_VADJUSTMENT,    "vadjustment");
801    g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
802    g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
803
804   /*
805    * Style properties
806    */
807   gtk_widget_class_install_style_property (widget_class,
808                                            g_param_spec_boxed ("error-underline-color",
809                                                                P_("Error underline color"),
810                                                                P_("Color with which to draw error-indication underlines"),
811                                                                GDK_TYPE_COLOR,
812                                                                GTK_PARAM_READABLE));
813   
814   /*
815    * Signals
816    */
817
818   /**
819    * GtkTextView::move-cursor: 
820    * @text_view: the object which received the signal
821    * @step: the granularity of the move, as a #GtkMovementStep
822    * @count: the number of @step units to move
823    * @extend_selection: %TRUE if the move should extend the selection
824    *  
825    * The ::move-cursor signal is a 
826    * <link linkend="keybinding-signals">keybinding signal</link> 
827    * which gets emitted when the user initiates a cursor movement. 
828    * If the cursor is not visible in @text_view, this signal causes
829    * the viewport to be moved instead.
830    *
831    * Applications should not connect to it, but may emit it with 
832    * g_signal_emit_by_name() if they need to control the cursor
833    * programmatically.
834    *
835    * The default bindings for this signal come in two variants,
836    * the variant with the Shift modifier extends the selection,
837    * the variant without the Shift modifer does not.
838    * There are too many key combinations to list them all here.
839    * <itemizedlist>
840    * <listitem>Arrow keys move by individual characters/lines</listitem>
841    * <listitem>Ctrl-arrow key combinations move by words/paragraphs</listitem>
842    * <listitem>Home/End keys move to the ends of the buffer</listitem>
843    * <listitem>PageUp/PageDown keys move vertically by pages</listitem>
844    * <listitem>Ctrl-PageUp/PageDown keys move horizontally by pages</listitem>
845    * </itemizedlist>
846    */
847   signals[MOVE_CURSOR] = 
848     g_signal_new (I_("move-cursor"),
849                   G_OBJECT_CLASS_TYPE (gobject_class), 
850                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 
851                   G_STRUCT_OFFSET (GtkTextViewClass, move_cursor),
852                   NULL, NULL, 
853                   _gtk_marshal_VOID__ENUM_INT_BOOLEAN, 
854                   G_TYPE_NONE, 3,
855                   GTK_TYPE_MOVEMENT_STEP, 
856                   G_TYPE_INT, 
857                   G_TYPE_BOOLEAN);
858
859   /**
860    * GtkTextView::move-viewport:
861    * @text_view: the object which received the signal
862    * @step: the granularity of the move, as a #GtkMovementStep
863    * @count: the number of @step units to move
864    *
865    * The ::move-viewport signal is a 
866    * <link linkend="keybinding-signals">keybinding signal</link> 
867    * which can be bound to key combinations to allow the user
868    * to move the viewport, i.e. change what part of the text view
869    * is visible in a containing scrolled window.
870    *
871    * There are no default bindings for this signal.
872    */
873   signals[MOVE_VIEWPORT] =
874     g_signal_new_class_handler (I_("move-viewport"),
875                                 G_OBJECT_CLASS_TYPE (gobject_class),
876                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
877                                 G_CALLBACK (gtk_text_view_move_viewport),
878                                 NULL, NULL,
879                                 _gtk_marshal_VOID__ENUM_INT,
880                                 G_TYPE_NONE, 2,
881                                 GTK_TYPE_SCROLL_STEP,
882                                 G_TYPE_INT);
883
884   /**
885    * GtkTextView::set-anchor:
886    * @text_view: the object which received the signal
887    *
888    * The ::set-anchor signal is a
889    * <link linkend="keybinding-signals">keybinding signal</link>
890    * which gets emitted when the user initiates setting the "anchor" 
891    * mark. The "anchor" mark gets placed at the same position as the
892    * "insert" mark.
893    *
894    * This signal has no default bindings.
895    */   
896   signals[SET_ANCHOR] =
897     g_signal_new (I_("set-anchor"),
898                   G_OBJECT_CLASS_TYPE (gobject_class),
899                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
900                   G_STRUCT_OFFSET (GtkTextViewClass, set_anchor),
901                   NULL, NULL,
902                   _gtk_marshal_VOID__VOID,
903                   G_TYPE_NONE, 0);
904
905   /**
906    * GtkTextView::insert-at-cursor:
907    * @text_view: the object which received the signal
908    * @string: the string to insert
909    *
910    * The ::insert-at-cursor signal is a
911    * <link linkend="keybinding-signals">keybinding signal</link>
912    * which gets emitted when the user initiates the insertion of a 
913    * fixed string at the cursor.
914    *
915    * This signal has no default bindings.
916    */
917   signals[INSERT_AT_CURSOR] =
918     g_signal_new (I_("insert-at-cursor"),
919                   G_OBJECT_CLASS_TYPE (gobject_class),
920                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
921                   G_STRUCT_OFFSET (GtkTextViewClass, insert_at_cursor),
922                   NULL, NULL,
923                   _gtk_marshal_VOID__STRING,
924                   G_TYPE_NONE, 1,
925                   G_TYPE_STRING);
926
927   /**
928    * GtkTextView::delete-from-cursor:
929    * @text_view: the object which received the signal
930    * @type: the granularity of the deletion, as a #GtkDeleteType
931    * @count: the number of @type units to delete
932    *
933    * The ::delete-from-cursor signal is a 
934    * <link linkend="keybinding-signals">keybinding signal</link> 
935    * which gets emitted when the user initiates a text deletion.
936    *
937    * If the @type is %GTK_DELETE_CHARS, GTK+ deletes the selection
938    * if there is one, otherwise it deletes the requested number
939    * of characters.
940    *
941    * The default bindings for this signal are
942    * Delete for deleting a character, Ctrl-Delete for 
943    * deleting a word and Ctrl-Backspace for deleting a word 
944    * backwords.
945    */
946   signals[DELETE_FROM_CURSOR] =
947     g_signal_new (I_("delete-from-cursor"),
948                   G_OBJECT_CLASS_TYPE (gobject_class),
949                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
950                   G_STRUCT_OFFSET (GtkTextViewClass, delete_from_cursor),
951                   NULL, NULL,
952                   _gtk_marshal_VOID__ENUM_INT,
953                   G_TYPE_NONE, 2,
954                   GTK_TYPE_DELETE_TYPE,
955                   G_TYPE_INT);
956
957   /**
958    * GtkTextView::backspace:
959    * @text_view: the object which received the signal
960    *
961    * The ::backspace signal is a 
962    * <link linkend="keybinding-signals">keybinding signal</link> 
963    * which gets emitted when the user asks for it.
964    * 
965    * The default bindings for this signal are
966    * Backspace and Shift-Backspace.
967    */
968   signals[BACKSPACE] =
969     g_signal_new (I_("backspace"),
970                   G_OBJECT_CLASS_TYPE (gobject_class),
971                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
972                   G_STRUCT_OFFSET (GtkTextViewClass, backspace),
973                   NULL, NULL,
974                   _gtk_marshal_VOID__VOID,
975                   G_TYPE_NONE, 0);
976
977   /**
978    * GtkTextView::cut-clipboard:
979    * @text_view: the object which received the signal
980    *
981    * The ::cut-clipboard signal is a 
982    * <link linkend="keybinding-signals">keybinding signal</link> 
983    * which gets emitted to cut the selection to the clipboard.
984    * 
985    * The default bindings for this signal are
986    * Ctrl-x and Shift-Delete.
987    */
988   signals[CUT_CLIPBOARD] =
989     g_signal_new (I_("cut-clipboard"),
990                   G_OBJECT_CLASS_TYPE (gobject_class),
991                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
992                   G_STRUCT_OFFSET (GtkTextViewClass, cut_clipboard),
993                   NULL, NULL,
994                   _gtk_marshal_VOID__VOID,
995                   G_TYPE_NONE, 0);
996
997   /**
998    * GtkTextView::copy-clipboard:
999    * @text_view: the object which received the signal
1000    *
1001    * The ::copy-clipboard signal is a 
1002    * <link linkend="keybinding-signals">keybinding signal</link> 
1003    * which gets emitted to copy the selection to the clipboard.
1004    * 
1005    * The default bindings for this signal are
1006    * Ctrl-c and Ctrl-Insert.
1007    */
1008   signals[COPY_CLIPBOARD] =
1009     g_signal_new (I_("copy-clipboard"),
1010                   G_OBJECT_CLASS_TYPE (gobject_class),
1011                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1012                   G_STRUCT_OFFSET (GtkTextViewClass, copy_clipboard),
1013                   NULL, NULL,
1014                   _gtk_marshal_VOID__VOID,
1015                   G_TYPE_NONE, 0);
1016
1017   /**
1018    * GtkTextView::paste-clipboard:
1019    * @text_view: the object which received the signal
1020    *
1021    * The ::paste-clipboard signal is a 
1022    * <link linkend="keybinding-signals">keybinding signal</link> 
1023    * which gets emitted to paste the contents of the clipboard 
1024    * into the text view.
1025    * 
1026    * The default bindings for this signal are
1027    * Ctrl-v and Shift-Insert.
1028    */
1029   signals[PASTE_CLIPBOARD] =
1030     g_signal_new (I_("paste-clipboard"),
1031                   G_OBJECT_CLASS_TYPE (gobject_class),
1032                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1033                   G_STRUCT_OFFSET (GtkTextViewClass, paste_clipboard),
1034                   NULL, NULL,
1035                   _gtk_marshal_VOID__VOID,
1036                   G_TYPE_NONE, 0);
1037
1038   /**
1039    * GtkTextView::toggle-overwrite:
1040    * @text_view: the object which received the signal
1041    *
1042    * The ::toggle-overwrite signal is a 
1043    * <link linkend="keybinding-signals">keybinding signal</link> 
1044    * which gets emitted to toggle the overwrite mode of the text view.
1045    * 
1046    * The default bindings for this signal is Insert.
1047    */ 
1048   signals[TOGGLE_OVERWRITE] =
1049     g_signal_new (I_("toggle-overwrite"),
1050                   G_OBJECT_CLASS_TYPE (gobject_class),
1051                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1052                   G_STRUCT_OFFSET (GtkTextViewClass, toggle_overwrite),
1053                   NULL, NULL,
1054                   _gtk_marshal_VOID__VOID,
1055                   G_TYPE_NONE, 0);
1056
1057   /**
1058    * GtkTextView::populate-popup:
1059    * @entry: The text view on which the signal is emitted
1060    * @menu: the menu that is being populated
1061    *
1062    * The ::populate-popup signal gets emitted before showing the 
1063    * context menu of the text view.
1064    *
1065    * If you need to add items to the context menu, connect
1066    * to this signal and append your menuitems to the @menu.
1067    */
1068   signals[POPULATE_POPUP] =
1069     g_signal_new (I_("populate-popup"),
1070                   G_OBJECT_CLASS_TYPE (gobject_class),
1071                   G_SIGNAL_RUN_LAST,
1072                   G_STRUCT_OFFSET (GtkTextViewClass, populate_popup),
1073                   NULL, NULL,
1074                   _gtk_marshal_VOID__OBJECT,
1075                   G_TYPE_NONE, 1,
1076                   GTK_TYPE_MENU);
1077   
1078   /**
1079    * GtkTextView::select-all:
1080    * @text_view: the object which received the signal
1081    * @select: %TRUE to select, %FALSE to unselect
1082    *
1083    * The ::select-all signal is a 
1084    * <link linkend="keybinding-signals">keybinding signal</link> 
1085    * which gets emitted to select or unselect the complete
1086    * contents of the text view.
1087    *
1088    * The default bindings for this signal are Ctrl-a and Ctrl-/ 
1089    * for selecting and Shift-Ctrl-a and Ctrl-\ for unselecting.
1090    */
1091   signals[SELECT_ALL] =
1092     g_signal_new_class_handler (I_("select-all"),
1093                                 G_OBJECT_CLASS_TYPE (gobject_class),
1094                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1095                                 G_CALLBACK (gtk_text_view_select_all),
1096                                 NULL, NULL,
1097                                 _gtk_marshal_VOID__BOOLEAN,
1098                                 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
1099
1100   /**
1101    * GtkTextView::toggle-cursor-visible:
1102    * @text_view: the object which received the signal
1103    *
1104    * The ::toggle-cursor-visible signal is a 
1105    * <link linkend="keybinding-signals">keybinding signal</link> 
1106    * which gets emitted to toggle the visibility of the cursor.
1107    *
1108    * The default binding for this signal is F7.
1109    */ 
1110   signals[TOGGLE_CURSOR_VISIBLE] =
1111     g_signal_new_class_handler (I_("toggle-cursor-visible"),
1112                                 G_OBJECT_CLASS_TYPE (gobject_class),
1113                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1114                                 G_CALLBACK (gtk_text_view_toggle_cursor_visible),
1115                                 NULL, NULL,
1116                                 _gtk_marshal_VOID__VOID,
1117                                 G_TYPE_NONE, 0);
1118
1119   /**
1120    * GtkTextView::preedit-changed:
1121    * @text_view: the object which received the signal
1122    * @preedit: the current preedit string
1123    *
1124    * If an input method is used, the typed text will not immediately
1125    * be committed to the buffer. So if you are interested in the text,
1126    * connect to this signal.
1127    *
1128    * This signal is only emitted if the text at the given position
1129    * is actually editable.
1130    *
1131    * Since: 2.20
1132    */
1133   signals[PREEDIT_CHANGED] =
1134     g_signal_new_class_handler (I_("preedit-changed"),
1135                                 G_OBJECT_CLASS_TYPE (gobject_class),
1136                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1137                                 NULL,
1138                                 NULL, NULL,
1139                                 _gtk_marshal_VOID__STRING,
1140                                 G_TYPE_NONE, 1,
1141                                 G_TYPE_STRING);
1142
1143   /*
1144    * Key bindings
1145    */
1146
1147   binding_set = gtk_binding_set_by_class (klass);
1148   
1149   /* Moving the insertion point */
1150   add_move_binding (binding_set, GDK_KEY_Right, 0,
1151                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1152
1153   add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
1154                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1155   
1156   add_move_binding (binding_set, GDK_KEY_Left, 0,
1157                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1158
1159   add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
1160                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1161   
1162   add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1163                     GTK_MOVEMENT_WORDS, 1);
1164
1165   add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1166                     GTK_MOVEMENT_WORDS, 1);
1167   
1168   add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1169                     GTK_MOVEMENT_WORDS, -1);
1170
1171   add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1172                     GTK_MOVEMENT_WORDS, -1);
1173   
1174   add_move_binding (binding_set, GDK_KEY_Up, 0,
1175                     GTK_MOVEMENT_DISPLAY_LINES, -1);
1176
1177   add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
1178                     GTK_MOVEMENT_DISPLAY_LINES, -1);
1179   
1180   add_move_binding (binding_set, GDK_KEY_Down, 0,
1181                     GTK_MOVEMENT_DISPLAY_LINES, 1);
1182
1183   add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
1184                     GTK_MOVEMENT_DISPLAY_LINES, 1);
1185   
1186   add_move_binding (binding_set, GDK_KEY_Up, GDK_CONTROL_MASK,
1187                     GTK_MOVEMENT_PARAGRAPHS, -1);
1188
1189   add_move_binding (binding_set, GDK_KEY_KP_Up, GDK_CONTROL_MASK,
1190                     GTK_MOVEMENT_PARAGRAPHS, -1);
1191   
1192   add_move_binding (binding_set, GDK_KEY_Down, GDK_CONTROL_MASK,
1193                     GTK_MOVEMENT_PARAGRAPHS, 1);
1194
1195   add_move_binding (binding_set, GDK_KEY_KP_Down, GDK_CONTROL_MASK,
1196                     GTK_MOVEMENT_PARAGRAPHS, 1);
1197   
1198   add_move_binding (binding_set, GDK_KEY_Home, 0,
1199                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1200
1201   add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1202                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1203   
1204   add_move_binding (binding_set, GDK_KEY_End, 0,
1205                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1206
1207   add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1208                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1209   
1210   add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK,
1211                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1212
1213   add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK,
1214                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1215   
1216   add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK,
1217                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1218
1219   add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK,
1220                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1221   
1222   add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
1223                     GTK_MOVEMENT_PAGES, -1);
1224
1225   add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
1226                     GTK_MOVEMENT_PAGES, -1);
1227   
1228   add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
1229                     GTK_MOVEMENT_PAGES, 1);
1230
1231   add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
1232                     GTK_MOVEMENT_PAGES, 1);
1233
1234   add_move_binding (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1235                     GTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1236
1237   add_move_binding (binding_set, GDK_KEY_KP_Page_Up, GDK_CONTROL_MASK,
1238                     GTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1239   
1240   add_move_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1241                     GTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1242
1243   add_move_binding (binding_set, GDK_KEY_KP_Page_Down, GDK_CONTROL_MASK,
1244                     GTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1245
1246   /* Select all */
1247   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
1248                                 "select-all", 1,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250
1251   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK,
1252                                 "select-all", 1,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254   
1255   /* Unselect all */
1256   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK,
1257                                  "select-all", 1,
1258                                  G_TYPE_BOOLEAN, FALSE);
1259
1260   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1261                                  "select-all", 1,
1262                                  G_TYPE_BOOLEAN, FALSE);
1263
1264   /* Deleting text */
1265   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
1266                                 "delete-from-cursor", 2,
1267                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
1268                                 G_TYPE_INT, 1);
1269
1270   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
1271                                 "delete-from-cursor", 2,
1272                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
1273                                 G_TYPE_INT, 1);
1274   
1275   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
1276                                 "backspace", 0);
1277
1278   /* Make this do the same as Backspace, to help with mis-typing */
1279   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK,
1280                                 "backspace", 0);
1281
1282   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK,
1283                                 "delete-from-cursor", 2,
1284                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1285                                 G_TYPE_INT, 1);
1286
1287   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK,
1288                                 "delete-from-cursor", 2,
1289                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1290                                 G_TYPE_INT, 1);
1291   
1292   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK,
1293                                 "delete-from-cursor", 2,
1294                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1295                                 G_TYPE_INT, -1);
1296
1297   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1298                                 "delete-from-cursor", 2,
1299                                 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1300                                 G_TYPE_INT, 1);
1301
1302   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1303                                 "delete-from-cursor", 2,
1304                                 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1305                                 G_TYPE_INT, 1);
1306
1307   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1308                                 "delete-from-cursor", 2,
1309                                 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1310                                 G_TYPE_INT, -1);
1311
1312   /* Cut/copy/paste */
1313
1314   gtk_binding_entry_add_signal (binding_set, GDK_KEY_x, GDK_CONTROL_MASK,
1315                                 "cut-clipboard", 0);
1316   gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK,
1317                                 "copy-clipboard", 0);
1318   gtk_binding_entry_add_signal (binding_set, GDK_KEY_v, GDK_CONTROL_MASK,
1319                                 "paste-clipboard", 0);
1320
1321   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
1322                                 "cut-clipboard", 0);
1323   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_CONTROL_MASK,
1324                                 "copy-clipboard", 0);
1325   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_SHIFT_MASK,
1326                                 "paste-clipboard", 0);
1327
1328   /* Overwrite */
1329   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, 0,
1330                                 "toggle-overwrite", 0);
1331   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0,
1332                                 "toggle-overwrite", 0);
1333
1334   /* Caret mode */
1335   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F7, 0,
1336                                 "toggle-cursor-visible", 0);
1337
1338   /* Control-tab focus motion */
1339   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, GDK_CONTROL_MASK,
1340                                 "move-focus", 1,
1341                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
1342   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, GDK_CONTROL_MASK,
1343                                 "move-focus", 1,
1344                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
1345   
1346   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1347                                 "move-focus", 1,
1348                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
1349   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1350                                 "move-focus", 1,
1351                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
1352
1353   g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
1354 }
1355
1356 static void
1357 gtk_text_view_init (GtkTextView *text_view)
1358 {
1359   GtkWidget *widget = GTK_WIDGET (text_view);
1360   GtkTargetList *target_list;
1361   GtkTextViewPrivate *priv;
1362
1363   text_view->priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
1364   priv = text_view->priv;
1365
1366   gtk_widget_set_can_focus (widget, TRUE);
1367
1368   /* Set up default style */
1369   priv->wrap_mode = GTK_WRAP_NONE;
1370   priv->pixels_above_lines = 0;
1371   priv->pixels_below_lines = 0;
1372   priv->pixels_inside_wrap = 0;
1373   priv->justify = GTK_JUSTIFY_LEFT;
1374   priv->left_margin = 0;
1375   priv->right_margin = 0;
1376   priv->indent = 0;
1377   priv->tabs = NULL;
1378   priv->editable = TRUE;
1379
1380   priv->scroll_after_paste = TRUE;
1381
1382   gtk_drag_dest_set (widget, 0, NULL, 0,
1383                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
1384
1385   target_list = gtk_target_list_new (NULL, 0);
1386   gtk_drag_dest_set_target_list (widget, target_list);
1387   gtk_target_list_unref (target_list);
1388
1389   priv->virtual_cursor_x = -1;
1390   priv->virtual_cursor_y = -1;
1391
1392   /* This object is completely private. No external entity can gain a reference
1393    * to it; so we create it here and destroy it in finalize ().
1394    */
1395   priv->im_context = gtk_im_multicontext_new ();
1396
1397   g_signal_connect (priv->im_context, "commit",
1398                     G_CALLBACK (gtk_text_view_commit_handler), text_view);
1399   g_signal_connect (priv->im_context, "preedit-changed",
1400                     G_CALLBACK (gtk_text_view_preedit_changed_handler), text_view);
1401   g_signal_connect (priv->im_context, "retrieve-surrounding",
1402                     G_CALLBACK (gtk_text_view_retrieve_surrounding_handler), text_view);
1403   g_signal_connect (priv->im_context, "delete-surrounding",
1404                     G_CALLBACK (gtk_text_view_delete_surrounding_handler), text_view);
1405
1406   priv->cursor_visible = TRUE;
1407
1408   priv->accepts_tab = TRUE;
1409
1410   priv->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
1411                                        widget, 200, 200);
1412
1413   priv->drag_start_x = -1;
1414   priv->drag_start_y = -1;
1415
1416   priv->pending_place_cursor_button = 0;
1417
1418   /* We handle all our own redrawing */
1419   gtk_widget_set_redraw_on_allocate (widget, FALSE);
1420 }
1421
1422 /**
1423  * gtk_text_view_new:
1424  *
1425  * Creates a new #GtkTextView. If you don't call gtk_text_view_set_buffer()
1426  * before using the text view, an empty default buffer will be created
1427  * for you. Get the buffer with gtk_text_view_get_buffer(). If you want
1428  * to specify your own buffer, consider gtk_text_view_new_with_buffer().
1429  *
1430  * Return value: a new #GtkTextView
1431  **/
1432 GtkWidget*
1433 gtk_text_view_new (void)
1434 {
1435   return g_object_new (GTK_TYPE_TEXT_VIEW, NULL);
1436 }
1437
1438 /**
1439  * gtk_text_view_new_with_buffer:
1440  * @buffer: a #GtkTextBuffer
1441  *
1442  * Creates a new #GtkTextView widget displaying the buffer
1443  * @buffer. One buffer can be shared among many widgets.
1444  * @buffer may be %NULL to create a default buffer, in which case
1445  * this function is equivalent to gtk_text_view_new(). The
1446  * text view adds its own reference count to the buffer; it does not
1447  * take over an existing reference.
1448  *
1449  * Return value: a new #GtkTextView.
1450  **/
1451 GtkWidget*
1452 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
1453 {
1454   GtkTextView *text_view;
1455
1456   text_view = (GtkTextView*)gtk_text_view_new ();
1457
1458   gtk_text_view_set_buffer (text_view, buffer);
1459
1460   return GTK_WIDGET (text_view);
1461 }
1462
1463 /**
1464  * gtk_text_view_set_buffer:
1465  * @text_view: a #GtkTextView
1466  * @buffer: (allow-none): a #GtkTextBuffer
1467  *
1468  * Sets @buffer as the buffer being displayed by @text_view. The previous
1469  * buffer displayed by the text view is unreferenced, and a reference is
1470  * added to @buffer. If you owned a reference to @buffer before passing it
1471  * to this function, you must remove that reference yourself; #GtkTextView
1472  * will not "adopt" it.
1473  **/
1474 void
1475 gtk_text_view_set_buffer (GtkTextView   *text_view,
1476                           GtkTextBuffer *buffer)
1477 {
1478   GtkTextViewPrivate *priv;
1479
1480   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1481   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
1482
1483   priv = text_view->priv;
1484
1485   if (priv->buffer == buffer)
1486     return;
1487
1488   if (priv->buffer != NULL)
1489     {
1490       /* Destroy all anchored children */
1491       GSList *tmp_list;
1492       GSList *copy;
1493
1494       copy = g_slist_copy (priv->children);
1495       tmp_list = copy;
1496       while (tmp_list != NULL)
1497         {
1498           GtkTextViewChild *vc = tmp_list->data;
1499
1500           if (vc->anchor)
1501             {
1502               gtk_widget_destroy (vc->widget);
1503               /* vc may now be invalid! */
1504             }
1505
1506           tmp_list = g_slist_next (tmp_list);
1507         }
1508
1509       g_slist_free (copy);
1510
1511       g_signal_handlers_disconnect_by_func (priv->buffer,
1512                                             gtk_text_view_mark_set_handler,
1513                                             text_view);
1514       g_signal_handlers_disconnect_by_func (priv->buffer,
1515                                             gtk_text_view_target_list_notify,
1516                                             text_view);
1517       g_signal_handlers_disconnect_by_func (priv->buffer,
1518                                             gtk_text_view_paste_done_handler,
1519                                             text_view);
1520
1521       if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
1522         {
1523           GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
1524                                                               GDK_SELECTION_PRIMARY);
1525           gtk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
1526         }
1527
1528       if (priv->layout)
1529         gtk_text_layout_set_buffer (priv->layout, NULL);
1530
1531       g_object_unref (priv->buffer);
1532       priv->dnd_mark = NULL;
1533       priv->first_para_mark = NULL;
1534       cancel_pending_scroll (text_view);
1535     }
1536
1537   priv->buffer = buffer;
1538
1539   if (priv->layout)
1540     gtk_text_layout_set_buffer (priv->layout, buffer);
1541
1542   if (buffer != NULL)
1543     {
1544       GtkTextIter start;
1545
1546       g_object_ref (buffer);
1547
1548       gtk_text_buffer_get_iter_at_offset (priv->buffer, &start, 0);
1549
1550       priv->dnd_mark = gtk_text_buffer_create_mark (priv->buffer,
1551                                                     "gtk_drag_target",
1552                                                     &start, FALSE);
1553
1554       priv->first_para_mark = gtk_text_buffer_create_mark (priv->buffer,
1555                                                            NULL,
1556                                                            &start, TRUE);
1557
1558       priv->first_para_pixels = 0;
1559
1560
1561       g_signal_connect (priv->buffer, "mark-set",
1562                         G_CALLBACK (gtk_text_view_mark_set_handler),
1563                         text_view);
1564       g_signal_connect (priv->buffer, "notify::paste-target-list",
1565                         G_CALLBACK (gtk_text_view_target_list_notify),
1566                         text_view);
1567       g_signal_connect (priv->buffer, "paste-done",
1568                         G_CALLBACK (gtk_text_view_paste_done_handler),
1569                         text_view);
1570
1571       gtk_text_view_target_list_notify (priv->buffer, NULL, text_view);
1572
1573       if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
1574         {
1575           GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
1576                                                               GDK_SELECTION_PRIMARY);
1577           gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
1578         }
1579     }
1580
1581   g_object_notify (G_OBJECT (text_view), "buffer");
1582   
1583   if (gtk_widget_get_visible (GTK_WIDGET (text_view)))
1584     gtk_widget_queue_draw (GTK_WIDGET (text_view));
1585
1586   DV(g_print ("Invalidating due to set_buffer\n"));
1587   gtk_text_view_invalidate (text_view);
1588 }
1589
1590 static GtkTextBuffer*
1591 get_buffer (GtkTextView *text_view)
1592 {
1593   if (text_view->priv->buffer == NULL)
1594     {
1595       GtkTextBuffer *b;
1596       b = gtk_text_buffer_new (NULL);
1597       gtk_text_view_set_buffer (text_view, b);
1598       g_object_unref (b);
1599     }
1600
1601   return text_view->priv->buffer;
1602 }
1603
1604 /**
1605  * gtk_text_view_get_buffer:
1606  * @text_view: a #GtkTextView
1607  *
1608  * Returns the #GtkTextBuffer being displayed by this text view.
1609  * The reference count on the buffer is not incremented; the caller
1610  * of this function won't own a new reference.
1611  *
1612  * Return value: (transfer none): a #GtkTextBuffer
1613  **/
1614 GtkTextBuffer*
1615 gtk_text_view_get_buffer (GtkTextView *text_view)
1616 {
1617   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
1618
1619   return get_buffer (text_view);
1620 }
1621
1622 /**
1623  * gtk_text_view_get_cursor_locations:
1624  * @text_view: a #GtkTextView
1625  * @iter: (allow-none): a #GtkTextIter
1626  * @strong: (out) (allow-none): location to store the strong
1627  *     cursor position (may be %NULL)
1628  * @weak: (out) (allow-none): location to store the weak
1629  *     cursor position (may be %NULL)
1630  *
1631  * Given an @iter within a text layout, determine the positions of the
1632  * strong and weak cursors if the insertion point is at that
1633  * iterator. The position of each cursor is stored as a zero-width
1634  * rectangle. The strong cursor location is the location where
1635  * characters of the directionality equal to the base direction of the
1636  * paragraph are inserted.  The weak cursor location is the location
1637  * where characters of the directionality opposite to the base
1638  * direction of the paragraph are inserted.
1639  *
1640  * If @iter is %NULL, the actual cursor position is used.
1641  *
1642  * Note that if @iter happens to be the actual cursor position, and
1643  * there is currently an IM preedit sequence being entered, the
1644  * returned locations will be adjusted to account for the preedit
1645  * cursor's offset within the preedit sequence.
1646  *
1647  * The rectangle position is in buffer coordinates; use
1648  * gtk_text_view_buffer_to_window_coords() to convert these
1649  * coordinates to coordinates for one of the windows in the text view.
1650  *
1651  * Since: 3.0
1652  **/
1653 void
1654 gtk_text_view_get_cursor_locations (GtkTextView       *text_view,
1655                                     const GtkTextIter *iter,
1656                                     GdkRectangle      *strong,
1657                                     GdkRectangle      *weak)
1658 {
1659   GtkTextIter insert;
1660
1661   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1662   g_return_if_fail (iter == NULL ||
1663                     gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1664
1665   gtk_text_view_ensure_layout (text_view);
1666
1667   if (iter)
1668     insert = *iter;
1669   else
1670     gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
1671                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
1672
1673   gtk_text_layout_get_cursor_locations (text_view->priv->layout, &insert,
1674                                         strong, weak);
1675 }
1676
1677 /**
1678  * gtk_text_view_get_iter_at_location:
1679  * @text_view: a #GtkTextView
1680  * @iter: (out): a #GtkTextIter
1681  * @x: x position, in buffer coordinates
1682  * @y: y position, in buffer coordinates
1683  *
1684  * Retrieves the iterator at buffer coordinates @x and @y. Buffer
1685  * coordinates are coordinates for the entire buffer, not just the
1686  * currently-displayed portion.  If you have coordinates from an
1687  * event, you have to convert those to buffer coordinates with
1688  * gtk_text_view_window_to_buffer_coords().
1689  **/
1690 void
1691 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
1692                                     GtkTextIter *iter,
1693                                     gint         x,
1694                                     gint         y)
1695 {
1696   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1697   g_return_if_fail (iter != NULL);
1698
1699   gtk_text_view_ensure_layout (text_view);
1700   
1701   gtk_text_layout_get_iter_at_pixel (text_view->priv->layout,
1702                                      iter, x, y);
1703 }
1704
1705 /**
1706  * gtk_text_view_get_iter_at_position:
1707  * @text_view: a #GtkTextView
1708  * @iter: (out): a #GtkTextIter
1709  * @trailing: (out) (allow-none): if non-%NULL, location to store an integer indicating where
1710  *    in the grapheme the user clicked. It will either be
1711  *    zero, or the number of characters in the grapheme. 
1712  *    0 represents the trailing edge of the grapheme.
1713  * @x: x position, in buffer coordinates
1714  * @y: y position, in buffer coordinates
1715  *
1716  * Retrieves the iterator pointing to the character at buffer 
1717  * coordinates @x and @y. Buffer coordinates are coordinates for 
1718  * the entire buffer, not just the currently-displayed portion.  
1719  * If you have coordinates from an event, you have to convert 
1720  * those to buffer coordinates with 
1721  * gtk_text_view_window_to_buffer_coords().
1722  *
1723  * Note that this is different from gtk_text_view_get_iter_at_location(),
1724  * which returns cursor locations, i.e. positions <emphasis>between</emphasis>
1725  * characters.
1726  *
1727  * Since: 2.6
1728  **/
1729 void
1730 gtk_text_view_get_iter_at_position (GtkTextView *text_view,
1731                                     GtkTextIter *iter,
1732                                     gint        *trailing,
1733                                     gint         x,
1734                                     gint         y)
1735 {
1736   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1737   g_return_if_fail (iter != NULL);
1738
1739   gtk_text_view_ensure_layout (text_view);
1740   
1741   gtk_text_layout_get_iter_at_position (text_view->priv->layout,
1742                                         iter, trailing, x, y);
1743 }
1744
1745 /**
1746  * gtk_text_view_get_iter_location:
1747  * @text_view: a #GtkTextView
1748  * @iter: a #GtkTextIter
1749  * @location: (out): bounds of the character at @iter
1750  *
1751  * Gets a rectangle which roughly contains the character at @iter.
1752  * The rectangle position is in buffer coordinates; use
1753  * gtk_text_view_buffer_to_window_coords() to convert these
1754  * coordinates to coordinates for one of the windows in the text view.
1755  **/
1756 void
1757 gtk_text_view_get_iter_location (GtkTextView       *text_view,
1758                                  const GtkTextIter *iter,
1759                                  GdkRectangle      *location)
1760 {
1761   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1762   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1763
1764   gtk_text_view_ensure_layout (text_view);
1765   
1766   gtk_text_layout_get_iter_location (text_view->priv->layout, iter, location);
1767 }
1768
1769 /**
1770  * gtk_text_view_get_line_yrange:
1771  * @text_view: a #GtkTextView
1772  * @iter: a #GtkTextIter
1773  * @y: (out): return location for a y coordinate
1774  * @height: (out): return location for a height
1775  *
1776  * Gets the y coordinate of the top of the line containing @iter,
1777  * and the height of the line. The coordinate is a buffer coordinate;
1778  * convert to window coordinates with gtk_text_view_buffer_to_window_coords().
1779  **/
1780 void
1781 gtk_text_view_get_line_yrange (GtkTextView       *text_view,
1782                                const GtkTextIter *iter,
1783                                gint              *y,
1784                                gint              *height)
1785 {
1786   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1787   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1788
1789   gtk_text_view_ensure_layout (text_view);
1790   
1791   gtk_text_layout_get_line_yrange (text_view->priv->layout,
1792                                    iter,
1793                                    y,
1794                                    height);
1795 }
1796
1797 /**
1798  * gtk_text_view_get_line_at_y:
1799  * @text_view: a #GtkTextView
1800  * @target_iter: (out): a #GtkTextIter
1801  * @y: a y coordinate
1802  * @line_top: (out): return location for top coordinate of the line
1803  *
1804  * Gets the #GtkTextIter at the start of the line containing
1805  * the coordinate @y. @y is in buffer coordinates, convert from
1806  * window coordinates with gtk_text_view_window_to_buffer_coords().
1807  * If non-%NULL, @line_top will be filled with the coordinate of the top
1808  * edge of the line.
1809  **/
1810 void
1811 gtk_text_view_get_line_at_y (GtkTextView *text_view,
1812                              GtkTextIter *target_iter,
1813                              gint         y,
1814                              gint        *line_top)
1815 {
1816   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1817
1818   gtk_text_view_ensure_layout (text_view);
1819   
1820   gtk_text_layout_get_line_at_y (text_view->priv->layout,
1821                                  target_iter,
1822                                  y,
1823                                  line_top);
1824 }
1825
1826 /**
1827  * gtk_text_view_scroll_to_iter:
1828  * @text_view: a #GtkTextView
1829  * @iter: a #GtkTextIter
1830  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1831  * @use_align: whether to use alignment arguments (if %FALSE, 
1832  *    just get the mark onscreen)
1833  * @xalign: horizontal alignment of mark within visible area
1834  * @yalign: vertical alignment of mark within visible area
1835  *
1836  * Scrolls @text_view so that @iter is on the screen in the position
1837  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1838  * left or top, 1.0 indicates right or bottom, 0.5 means center. 
1839  * If @use_align is %FALSE, the text scrolls the minimal distance to 
1840  * get the mark onscreen, possibly not scrolling at all. The effective 
1841  * screen for purposes of this function is reduced by a margin of size 
1842  * @within_margin.
1843  *
1844  * Note that this function uses the currently-computed height of the
1845  * lines in the text buffer. Line heights are computed in an idle 
1846  * handler; so this function may not have the desired effect if it's 
1847  * called before the height computations. To avoid oddness, consider 
1848  * using gtk_text_view_scroll_to_mark() which saves a point to be 
1849  * scrolled to after line validation.
1850  *
1851  * Return value: %TRUE if scrolling occurred
1852  **/
1853 gboolean
1854 gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
1855                               GtkTextIter   *iter,
1856                               gdouble        within_margin,
1857                               gboolean       use_align,
1858                               gdouble        xalign,
1859                               gdouble        yalign)
1860 {
1861   GdkRectangle rect;
1862   GdkRectangle screen;
1863   gint screen_bottom;
1864   gint screen_right;
1865   gint scroll_dest;
1866   GtkWidget *widget;
1867   gboolean retval = FALSE;
1868   gint scroll_inc;
1869   gint screen_xoffset, screen_yoffset;
1870   gint current_x_scroll, current_y_scroll;
1871
1872   /* FIXME why don't we do the validate-at-scroll-destination thing
1873    * from flush_scroll in this function? I think it wasn't done before
1874    * because changed_handler was screwed up, but I could be wrong.
1875    */
1876   
1877   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1878   g_return_val_if_fail (iter != NULL, FALSE);
1879   g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE);
1880   g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE);
1881   g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE);
1882   
1883   widget = GTK_WIDGET (text_view);
1884
1885   DV(g_print(G_STRLOC"\n"));
1886   
1887   gtk_text_layout_get_iter_location (text_view->priv->layout,
1888                                      iter,
1889                                      &rect);
1890
1891   DV (g_print (" target rect %d,%d  %d x %d\n", rect.x, rect.y, rect.width, rect.height));
1892   
1893   current_x_scroll = text_view->priv->xoffset;
1894   current_y_scroll = text_view->priv->yoffset;
1895
1896   screen.x = current_x_scroll;
1897   screen.y = current_y_scroll;
1898   screen.width = SCREEN_WIDTH (widget);
1899   screen.height = SCREEN_HEIGHT (widget);
1900   
1901   screen_xoffset = screen.width * within_margin;
1902   screen_yoffset = screen.height * within_margin;
1903   
1904   screen.x += screen_xoffset;
1905   screen.y += screen_yoffset;
1906   screen.width -= screen_xoffset * 2;
1907   screen.height -= screen_yoffset * 2;
1908
1909   /* paranoia check */
1910   if (screen.width < 1)
1911     screen.width = 1;
1912   if (screen.height < 1)
1913     screen.height = 1;
1914   
1915   /* The -1 here ensures that we leave enough space to draw the cursor
1916    * when this function is used for horizontal scrolling. 
1917    */
1918   screen_right = screen.x + screen.width - 1;
1919   screen_bottom = screen.y + screen.height;
1920   
1921   /* The alignment affects the point in the target character that we
1922    * choose to align. If we're doing right/bottom alignment, we align
1923    * the right/bottom edge of the character the mark is at; if we're
1924    * doing left/top we align the left/top edge of the character; if
1925    * we're doing center alignment we align the center of the
1926    * character.
1927    */
1928   
1929   /* Vertical scroll */
1930
1931   scroll_inc = 0;
1932   scroll_dest = current_y_scroll;
1933   
1934   if (use_align)
1935     {      
1936       scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
1937       
1938       /* if scroll_dest < screen.y, we move a negative increment (up),
1939        * else a positive increment (down)
1940        */
1941       scroll_inc = scroll_dest - screen.y + screen_yoffset;
1942     }
1943   else
1944     {
1945       /* move minimum to get onscreen */
1946       if (rect.y < screen.y)
1947         {
1948           scroll_dest = rect.y;
1949           scroll_inc = scroll_dest - screen.y - screen_yoffset;
1950         }
1951       else if ((rect.y + rect.height) > screen_bottom)
1952         {
1953           scroll_dest = rect.y + rect.height;
1954           scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
1955         }
1956     }  
1957   
1958   if (scroll_inc != 0)
1959     {
1960       gtk_adjustment_set_value (text_view->priv->vadjustment,
1961                                 current_y_scroll + scroll_inc);
1962
1963       DV (g_print (" vert increment %d\n", scroll_inc));
1964     }
1965
1966   /* Horizontal scroll */
1967   
1968   scroll_inc = 0;
1969   scroll_dest = current_x_scroll;
1970   
1971   if (use_align)
1972     {      
1973       scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
1974
1975       /* if scroll_dest < screen.y, we move a negative increment (left),
1976        * else a positive increment (right)
1977        */
1978       scroll_inc = scroll_dest - screen.x + screen_xoffset;
1979     }
1980   else
1981     {
1982       /* move minimum to get onscreen */
1983       if (rect.x < screen.x)
1984         {
1985           scroll_dest = rect.x;
1986           scroll_inc = scroll_dest - screen.x - screen_xoffset;
1987         }
1988       else if ((rect.x + rect.width) > screen_right)
1989         {
1990           scroll_dest = rect.x + rect.width;
1991           scroll_inc = scroll_dest - screen_right + screen_xoffset;
1992         }
1993     }
1994   
1995   if (scroll_inc != 0)
1996     {
1997       gtk_adjustment_set_value (text_view->priv->hadjustment,
1998                                 current_x_scroll + scroll_inc);
1999
2000       DV (g_print (" horiz increment %d\n", scroll_inc));
2001     }
2002   
2003   retval = (current_y_scroll != gtk_adjustment_get_value (text_view->priv->vadjustment))
2004            || (current_x_scroll != gtk_adjustment_get_value (text_view->priv->hadjustment));
2005
2006   if (retval)
2007     {
2008       DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
2009     }
2010   else
2011     {
2012       DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
2013     }
2014   
2015   return retval;
2016 }
2017
2018 static void
2019 free_pending_scroll (GtkTextPendingScroll *scroll)
2020 {
2021   if (!gtk_text_mark_get_deleted (scroll->mark))
2022     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (scroll->mark),
2023                                  scroll->mark);
2024   g_object_unref (scroll->mark);
2025   g_free (scroll);
2026 }
2027
2028 static void
2029 cancel_pending_scroll (GtkTextView *text_view)
2030 {
2031   if (text_view->priv->pending_scroll)
2032     {
2033       free_pending_scroll (text_view->priv->pending_scroll);
2034       text_view->priv->pending_scroll = NULL;
2035     }
2036 }
2037
2038 static void
2039 gtk_text_view_queue_scroll (GtkTextView   *text_view,
2040                             GtkTextMark   *mark,
2041                             gdouble        within_margin,
2042                             gboolean       use_align,
2043                             gdouble        xalign,
2044                             gdouble        yalign)
2045 {
2046   GtkTextIter iter;
2047   GtkTextPendingScroll *scroll;
2048
2049   DV(g_print(G_STRLOC"\n"));
2050   
2051   scroll = g_new (GtkTextPendingScroll, 1);
2052
2053   scroll->within_margin = within_margin;
2054   scroll->use_align = use_align;
2055   scroll->xalign = xalign;
2056   scroll->yalign = yalign;
2057   
2058   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2059
2060   scroll->mark = gtk_text_buffer_create_mark (get_buffer (text_view),
2061                                               NULL,
2062                                               &iter,
2063                                               gtk_text_mark_get_left_gravity (mark));
2064
2065   g_object_ref (scroll->mark);
2066   
2067   cancel_pending_scroll (text_view);
2068
2069   text_view->priv->pending_scroll = scroll;
2070 }
2071
2072 static gboolean
2073 gtk_text_view_flush_scroll (GtkTextView *text_view)
2074 {
2075   GtkAllocation allocation;
2076   GtkTextIter iter;
2077   GtkTextPendingScroll *scroll;
2078   gboolean retval;
2079   GtkWidget *widget;
2080
2081   widget = GTK_WIDGET (text_view);
2082   
2083   DV(g_print(G_STRLOC"\n"));
2084   
2085   if (text_view->priv->pending_scroll == NULL)
2086     {
2087       DV (g_print ("in flush scroll, no pending scroll\n"));
2088       return FALSE;
2089     }
2090
2091   scroll = text_view->priv->pending_scroll;
2092
2093   /* avoid recursion */
2094   text_view->priv->pending_scroll = NULL;
2095   
2096   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, scroll->mark);
2097
2098   /* Validate area around the scroll destination, so the adjustment
2099    * can meaningfully point into that area. We must validate
2100    * enough area to be sure that after we scroll, everything onscreen
2101    * is valid; otherwise, validation will maintain the first para
2102    * in one place, but may push the target iter off the bottom of
2103    * the screen.
2104    */
2105   DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
2106   gtk_widget_get_allocation (widget, &allocation);
2107   gtk_text_layout_validate_yrange (text_view->priv->layout, &iter,
2108                                    -(allocation.height * 2),
2109                                    allocation.height * 2);
2110
2111   DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
2112
2113   /* Ensure we have updated width/height */
2114   gtk_text_view_update_adjustments (text_view);
2115   
2116   retval = gtk_text_view_scroll_to_iter (text_view,
2117                                          &iter,
2118                                          scroll->within_margin,
2119                                          scroll->use_align,
2120                                          scroll->xalign,
2121                                          scroll->yalign);
2122
2123   free_pending_scroll (scroll);
2124
2125   return retval;
2126 }
2127
2128 static void
2129 gtk_text_view_update_adjustments (GtkTextView *text_view)
2130 {
2131   GtkTextViewPrivate *priv;
2132   gint width = 0, height = 0;
2133
2134   DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
2135
2136   priv = text_view->priv;
2137
2138   if (priv->layout)
2139     gtk_text_layout_get_size (priv->layout, &width, &height);
2140
2141   /* Make room for the cursor after the last character in the widest line */
2142   width += SPACE_FOR_CURSOR;
2143
2144   if (priv->width != width || priv->height != height)
2145     {
2146       if (priv->width != width)
2147         priv->width_changed = TRUE;
2148
2149       priv->width = width;
2150       priv->height = height;
2151
2152       gtk_text_view_set_hadjustment_values (text_view);
2153       gtk_text_view_set_vadjustment_values (text_view);
2154     }
2155 }
2156
2157 static void
2158 gtk_text_view_update_layout_width (GtkTextView *text_view)
2159 {
2160   DV(g_print(">Updating layout width ("G_STRLOC")\n"));
2161   
2162   gtk_text_view_ensure_layout (text_view);
2163
2164   gtk_text_layout_set_screen_width (text_view->priv->layout,
2165                                     MAX (1, SCREEN_WIDTH (text_view) - SPACE_FOR_CURSOR));
2166 }
2167
2168 static void
2169 gtk_text_view_update_im_spot_location (GtkTextView *text_view)
2170 {
2171   GdkRectangle area;
2172
2173   if (text_view->priv->layout == NULL)
2174     return;
2175   
2176   gtk_text_view_get_cursor_locations (text_view, NULL, &area, NULL);
2177
2178   area.x -= text_view->priv->xoffset;
2179   area.y -= text_view->priv->yoffset;
2180     
2181   /* Width returned by Pango indicates direction of cursor,
2182    * by its sign more than the size of cursor.
2183    */
2184   area.width = 0;
2185
2186   gtk_im_context_set_cursor_location (text_view->priv->im_context, &area);
2187 }
2188
2189 static gboolean
2190 do_update_im_spot_location (gpointer text_view)
2191 {
2192   GtkTextViewPrivate *priv;
2193
2194   priv = GTK_TEXT_VIEW (text_view)->priv;
2195   priv->im_spot_idle = 0;
2196
2197   gtk_text_view_update_im_spot_location (text_view);
2198   return FALSE;
2199 }
2200
2201 static void
2202 queue_update_im_spot_location (GtkTextView *text_view)
2203 {
2204   GtkTextViewPrivate *priv;
2205
2206   priv = text_view->priv;
2207
2208   /* Use priority a little higher than GTK_TEXT_VIEW_PRIORITY_VALIDATE,
2209    * so we don't wait until the entire buffer has been validated. */
2210   if (!priv->im_spot_idle)
2211     priv->im_spot_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE - 1,
2212                                                     do_update_im_spot_location,
2213                                                     text_view,
2214                                                     NULL);
2215 }
2216
2217 static void
2218 flush_update_im_spot_location (GtkTextView *text_view)
2219 {
2220   GtkTextViewPrivate *priv;
2221
2222   priv = text_view->priv;
2223
2224   if (priv->im_spot_idle)
2225     {
2226       g_source_remove (priv->im_spot_idle);
2227       priv->im_spot_idle = 0;
2228       gtk_text_view_update_im_spot_location (text_view);
2229     }
2230 }
2231
2232 /**
2233  * gtk_text_view_scroll_to_mark:
2234  * @text_view: a #GtkTextView
2235  * @mark: a #GtkTextMark
2236  * @within_margin: margin as a [0.0,0.5) fraction of screen size
2237  * @use_align: whether to use alignment arguments (if %FALSE, just 
2238  *    get the mark onscreen)
2239  * @xalign: horizontal alignment of mark within visible area
2240  * @yalign: vertical alignment of mark within visible area
2241  *
2242  * Scrolls @text_view so that @mark is on the screen in the position
2243  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
2244  * left or top, 1.0 indicates right or bottom, 0.5 means center. 
2245  * If @use_align is %FALSE, the text scrolls the minimal distance to 
2246  * get the mark onscreen, possibly not scrolling at all. The effective 
2247  * screen for purposes of this function is reduced by a margin of size 
2248  * @within_margin.
2249  **/
2250 void
2251 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
2252                               GtkTextMark *mark,
2253                               gdouble      within_margin,
2254                               gboolean     use_align,
2255                               gdouble      xalign,
2256                               gdouble      yalign)
2257 {  
2258   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2259   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2260   g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5);
2261   g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
2262   g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
2263
2264   /* We need to verify that the buffer contains the mark, otherwise this
2265    * can lead to data structure corruption later on.
2266    */
2267   g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
2268
2269   gtk_text_view_queue_scroll (text_view, mark,
2270                               within_margin,
2271                               use_align,
2272                               xalign,
2273                               yalign);
2274
2275   /* If no validation is pending, we need to go ahead and force an
2276    * immediate scroll.
2277    */
2278   if (text_view->priv->layout &&
2279       gtk_text_layout_is_valid (text_view->priv->layout))
2280     gtk_text_view_flush_scroll (text_view);
2281 }
2282
2283 /**
2284  * gtk_text_view_scroll_mark_onscreen:
2285  * @text_view: a #GtkTextView
2286  * @mark: a mark in the buffer for @text_view
2287  * 
2288  * Scrolls @text_view the minimum distance such that @mark is contained
2289  * within the visible area of the widget.
2290  **/
2291 void
2292 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
2293                                     GtkTextMark *mark)
2294 {
2295   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2296   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2297
2298   /* We need to verify that the buffer contains the mark, otherwise this
2299    * can lead to data structure corruption later on.
2300    */
2301   g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
2302
2303   gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
2304 }
2305
2306 static gboolean
2307 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
2308 {
2309   GdkRectangle visible_rect;
2310   gtk_text_view_get_visible_rect (text_view, &visible_rect);
2311
2312   return gtk_text_layout_clamp_iter_to_vrange (text_view->priv->layout, iter,
2313                                                visible_rect.y,
2314                                                visible_rect.y + visible_rect.height);
2315 }
2316
2317 /**
2318  * gtk_text_view_move_mark_onscreen:
2319  * @text_view: a #GtkTextView
2320  * @mark: a #GtkTextMark
2321  *
2322  * Moves a mark within the buffer so that it's
2323  * located within the currently-visible text area.
2324  *
2325  * Return value: %TRUE if the mark moved (wasn't already onscreen)
2326  **/
2327 gboolean
2328 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
2329                                   GtkTextMark *mark)
2330 {
2331   GtkTextIter iter;
2332
2333   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2334   g_return_val_if_fail (mark != NULL, FALSE);
2335
2336   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2337
2338   if (clamp_iter_onscreen (text_view, &iter))
2339     {
2340       gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
2341       return TRUE;
2342     }
2343   else
2344     return FALSE;
2345 }
2346
2347 /**
2348  * gtk_text_view_get_visible_rect:
2349  * @text_view: a #GtkTextView
2350  * @visible_rect: (out): rectangle to fill
2351  *
2352  * Fills @visible_rect with the currently-visible
2353  * region of the buffer, in buffer coordinates. Convert to window coordinates
2354  * with gtk_text_view_buffer_to_window_coords().
2355  **/
2356 void
2357 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
2358                                 GdkRectangle *visible_rect)
2359 {
2360   GtkWidget *widget;
2361
2362   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2363
2364   widget = GTK_WIDGET (text_view);
2365
2366   if (visible_rect)
2367     {
2368       visible_rect->x = text_view->priv->xoffset;
2369       visible_rect->y = text_view->priv->yoffset;
2370       visible_rect->width = SCREEN_WIDTH (widget);
2371       visible_rect->height = SCREEN_HEIGHT (widget);
2372
2373       DV(g_print(" visible rect: %d,%d %d x %d\n",
2374                  visible_rect->x,
2375                  visible_rect->y,
2376                  visible_rect->width,
2377                  visible_rect->height));
2378     }
2379 }
2380
2381 /**
2382  * gtk_text_view_set_wrap_mode:
2383  * @text_view: a #GtkTextView
2384  * @wrap_mode: a #GtkWrapMode
2385  *
2386  * Sets the line wrapping for the view.
2387  **/
2388 void
2389 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
2390                              GtkWrapMode  wrap_mode)
2391 {
2392   GtkTextViewPrivate *priv;
2393
2394   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2395
2396   priv = text_view->priv;
2397
2398   if (priv->wrap_mode != wrap_mode)
2399     {
2400       priv->wrap_mode = wrap_mode;
2401
2402       if (priv->layout && priv->layout->default_style)
2403         {
2404           priv->layout->default_style->wrap_mode = wrap_mode;
2405           gtk_text_layout_default_style_changed (priv->layout);
2406         }
2407     }
2408
2409   g_object_notify (G_OBJECT (text_view), "wrap-mode");
2410 }
2411
2412 /**
2413  * gtk_text_view_get_wrap_mode:
2414  * @text_view: a #GtkTextView
2415  *
2416  * Gets the line wrapping for the view.
2417  *
2418  * Return value: the line wrap setting
2419  **/
2420 GtkWrapMode
2421 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
2422 {
2423   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAP_NONE);
2424
2425   return text_view->priv->wrap_mode;
2426 }
2427
2428 /**
2429  * gtk_text_view_set_editable:
2430  * @text_view: a #GtkTextView
2431  * @setting: whether it's editable
2432  *
2433  * Sets the default editability of the #GtkTextView. You can override
2434  * this default setting with tags in the buffer, using the "editable"
2435  * attribute of tags.
2436  **/
2437 void
2438 gtk_text_view_set_editable (GtkTextView *text_view,
2439                             gboolean     setting)
2440 {
2441   GtkTextViewPrivate *priv;
2442
2443   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2444
2445   priv = text_view->priv;
2446   setting = setting != FALSE;
2447
2448   if (priv->editable != setting)
2449     {
2450       if (!setting)
2451         {
2452           gtk_text_view_reset_im_context(text_view);
2453           if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
2454             gtk_im_context_focus_out (priv->im_context);
2455         }
2456
2457       priv->editable = setting;
2458
2459       if (setting && gtk_widget_has_focus (GTK_WIDGET (text_view)))
2460         gtk_im_context_focus_in (priv->im_context);
2461
2462       if (priv->layout && priv->layout->default_style)
2463         {
2464           gtk_text_layout_set_overwrite_mode (priv->layout,
2465                                               priv->overwrite_mode && priv->editable);
2466           priv->layout->default_style->editable = priv->editable;
2467           gtk_text_layout_default_style_changed (priv->layout);
2468         }
2469
2470       g_object_notify (G_OBJECT (text_view), "editable");
2471     }
2472 }
2473
2474 /**
2475  * gtk_text_view_get_editable:
2476  * @text_view: a #GtkTextView
2477  *
2478  * Returns the default editability of the #GtkTextView. Tags in the
2479  * buffer may override this setting for some ranges of text.
2480  *
2481  * Return value: whether text is editable by default
2482  **/
2483 gboolean
2484 gtk_text_view_get_editable (GtkTextView *text_view)
2485 {
2486   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2487
2488   return text_view->priv->editable;
2489 }
2490
2491 /**
2492  * gtk_text_view_set_pixels_above_lines:
2493  * @text_view: a #GtkTextView
2494  * @pixels_above_lines: pixels above paragraphs
2495  * 
2496  * Sets the default number of blank pixels above paragraphs in @text_view.
2497  * Tags in the buffer for @text_view may override the defaults.
2498  **/
2499 void
2500 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
2501                                       gint         pixels_above_lines)
2502 {
2503   GtkTextViewPrivate *priv;
2504
2505   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2506
2507   priv = text_view->priv;
2508
2509   if (priv->pixels_above_lines != pixels_above_lines)
2510     {
2511       priv->pixels_above_lines = pixels_above_lines;
2512
2513       if (priv->layout && priv->layout->default_style)
2514         {
2515           priv->layout->default_style->pixels_above_lines = pixels_above_lines;
2516           gtk_text_layout_default_style_changed (priv->layout);
2517         }
2518
2519       g_object_notify (G_OBJECT (text_view), "pixels-above-lines");
2520     }
2521 }
2522
2523 /**
2524  * gtk_text_view_get_pixels_above_lines:
2525  * @text_view: a #GtkTextView
2526  * 
2527  * Gets the default number of pixels to put above paragraphs.
2528  * 
2529  * Return value: default number of pixels above paragraphs
2530  **/
2531 gint
2532 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
2533 {
2534   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2535
2536   return text_view->priv->pixels_above_lines;
2537 }
2538
2539 /**
2540  * gtk_text_view_set_pixels_below_lines:
2541  * @text_view: a #GtkTextView
2542  * @pixels_below_lines: pixels below paragraphs 
2543  *
2544  * Sets the default number of pixels of blank space
2545  * to put below paragraphs in @text_view. May be overridden
2546  * by tags applied to @text_view's buffer. 
2547  **/
2548 void
2549 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
2550                                       gint         pixels_below_lines)
2551 {
2552   GtkTextViewPrivate *priv;
2553
2554   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2555
2556   priv = text_view->priv;
2557
2558   if (priv->pixels_below_lines != pixels_below_lines)
2559     {
2560       priv->pixels_below_lines = pixels_below_lines;
2561
2562       if (priv->layout && priv->layout->default_style)
2563         {
2564           priv->layout->default_style->pixels_below_lines = pixels_below_lines;
2565           gtk_text_layout_default_style_changed (priv->layout);
2566         }
2567
2568       g_object_notify (G_OBJECT (text_view), "pixels-below-lines");
2569     }
2570 }
2571
2572 /**
2573  * gtk_text_view_get_pixels_below_lines:
2574  * @text_view: a #GtkTextView
2575  * 
2576  * Gets the value set by gtk_text_view_set_pixels_below_lines().
2577  * 
2578  * Return value: default number of blank pixels below paragraphs
2579  **/
2580 gint
2581 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
2582 {
2583   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2584
2585   return text_view->priv->pixels_below_lines;
2586 }
2587
2588 /**
2589  * gtk_text_view_set_pixels_inside_wrap:
2590  * @text_view: a #GtkTextView
2591  * @pixels_inside_wrap: default number of pixels between wrapped lines
2592  *
2593  * Sets the default number of pixels of blank space to leave between
2594  * display/wrapped lines within a paragraph. May be overridden by
2595  * tags in @text_view's buffer.
2596  **/
2597 void
2598 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
2599                                       gint         pixels_inside_wrap)
2600 {
2601   GtkTextViewPrivate *priv;
2602
2603   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2604
2605   priv = text_view->priv;
2606
2607   if (priv->pixels_inside_wrap != pixels_inside_wrap)
2608     {
2609       priv->pixels_inside_wrap = pixels_inside_wrap;
2610
2611       if (priv->layout && priv->layout->default_style)
2612         {
2613           priv->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
2614           gtk_text_layout_default_style_changed (priv->layout);
2615         }
2616
2617       g_object_notify (G_OBJECT (text_view), "pixels-inside-wrap");
2618     }
2619 }
2620
2621 /**
2622  * gtk_text_view_get_pixels_inside_wrap:
2623  * @text_view: a #GtkTextView
2624  * 
2625  * Gets the value set by gtk_text_view_set_pixels_inside_wrap().
2626  * 
2627  * Return value: default number of pixels of blank space between wrapped lines
2628  **/
2629 gint
2630 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
2631 {
2632   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2633
2634   return text_view->priv->pixels_inside_wrap;
2635 }
2636
2637 /**
2638  * gtk_text_view_set_justification:
2639  * @text_view: a #GtkTextView
2640  * @justification: justification
2641  *
2642  * Sets the default justification of text in @text_view.
2643  * Tags in the view's buffer may override the default.
2644  * 
2645  **/
2646 void
2647 gtk_text_view_set_justification (GtkTextView     *text_view,
2648                                  GtkJustification justification)
2649 {
2650   GtkTextViewPrivate *priv;
2651
2652   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2653
2654   priv = text_view->priv;
2655
2656   if (priv->justify != justification)
2657     {
2658       priv->justify = justification;
2659
2660       if (priv->layout && priv->layout->default_style)
2661         {
2662           priv->layout->default_style->justification = justification;
2663           gtk_text_layout_default_style_changed (priv->layout);
2664         }
2665
2666       g_object_notify (G_OBJECT (text_view), "justification");
2667     }
2668 }
2669
2670 /**
2671  * gtk_text_view_get_justification:
2672  * @text_view: a #GtkTextView
2673  * 
2674  * Gets the default justification of paragraphs in @text_view.
2675  * Tags in the buffer may override the default.
2676  * 
2677  * Return value: default justification
2678  **/
2679 GtkJustification
2680 gtk_text_view_get_justification (GtkTextView *text_view)
2681 {
2682   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
2683
2684   return text_view->priv->justify;
2685 }
2686
2687 /**
2688  * gtk_text_view_set_left_margin:
2689  * @text_view: a #GtkTextView
2690  * @left_margin: left margin in pixels
2691  * 
2692  * Sets the default left margin for text in @text_view.
2693  * Tags in the buffer may override the default.
2694  **/
2695 void
2696 gtk_text_view_set_left_margin (GtkTextView *text_view,
2697                                gint         left_margin)
2698 {
2699   GtkTextViewPrivate *priv;
2700
2701   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2702
2703   priv = text_view->priv;
2704
2705   if (priv->left_margin != left_margin)
2706     {
2707       priv->left_margin = left_margin;
2708
2709       if (priv->layout && priv->layout->default_style)
2710         {
2711           priv->layout->default_style->left_margin = left_margin;
2712           gtk_text_layout_default_style_changed (priv->layout);
2713         }
2714
2715       g_object_notify (G_OBJECT (text_view), "left-margin");
2716     }
2717 }
2718
2719 /**
2720  * gtk_text_view_get_left_margin:
2721  * @text_view: a #GtkTextView
2722  * 
2723  * Gets the default left margin size of paragraphs in the @text_view.
2724  * Tags in the buffer may override the default.
2725  * 
2726  * Return value: left margin in pixels
2727  **/
2728 gint
2729 gtk_text_view_get_left_margin (GtkTextView *text_view)
2730 {
2731   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2732
2733   return text_view->priv->left_margin;
2734 }
2735
2736 /**
2737  * gtk_text_view_set_right_margin:
2738  * @text_view: a #GtkTextView
2739  * @right_margin: right margin in pixels
2740  *
2741  * Sets the default right margin for text in the text view.
2742  * Tags in the buffer may override the default.
2743  **/
2744 void
2745 gtk_text_view_set_right_margin (GtkTextView *text_view,
2746                                 gint         right_margin)
2747 {
2748   GtkTextViewPrivate *priv = text_view->priv;
2749
2750   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2751
2752   if (priv->right_margin != right_margin)
2753     {
2754       priv->right_margin = right_margin;
2755
2756       if (priv->layout && priv->layout->default_style)
2757         {
2758           priv->layout->default_style->right_margin = right_margin;
2759           gtk_text_layout_default_style_changed (priv->layout);
2760         }
2761
2762       g_object_notify (G_OBJECT (text_view), "right-margin");
2763     }
2764 }
2765
2766 /**
2767  * gtk_text_view_get_right_margin:
2768  * @text_view: a #GtkTextView
2769  * 
2770  * Gets the default right margin for text in @text_view. Tags
2771  * in the buffer may override the default.
2772  * 
2773  * Return value: right margin in pixels
2774  **/
2775 gint
2776 gtk_text_view_get_right_margin (GtkTextView *text_view)
2777 {
2778   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2779
2780   return text_view->priv->right_margin;
2781 }
2782
2783 /**
2784  * gtk_text_view_set_indent:
2785  * @text_view: a #GtkTextView
2786  * @indent: indentation in pixels
2787  *
2788  * Sets the default indentation for paragraphs in @text_view.
2789  * Tags in the buffer may override the default.
2790  **/
2791 void
2792 gtk_text_view_set_indent (GtkTextView *text_view,
2793                           gint         indent)
2794 {
2795   GtkTextViewPrivate *priv;
2796
2797   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2798
2799   priv = text_view->priv;
2800
2801   if (priv->indent != indent)
2802     {
2803       priv->indent = indent;
2804
2805       if (priv->layout && priv->layout->default_style)
2806         {
2807           priv->layout->default_style->indent = indent;
2808           gtk_text_layout_default_style_changed (priv->layout);
2809         }
2810
2811       g_object_notify (G_OBJECT (text_view), "indent");
2812     }
2813 }
2814
2815 /**
2816  * gtk_text_view_get_indent:
2817  * @text_view: a #GtkTextView
2818  * 
2819  * Gets the default indentation of paragraphs in @text_view.
2820  * Tags in the view's buffer may override the default.
2821  * The indentation may be negative.
2822  * 
2823  * Return value: number of pixels of indentation
2824  **/
2825 gint
2826 gtk_text_view_get_indent (GtkTextView *text_view)
2827 {
2828   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2829
2830   return text_view->priv->indent;
2831 }
2832
2833 /**
2834  * gtk_text_view_set_tabs:
2835  * @text_view: a #GtkTextView
2836  * @tabs: tabs as a #PangoTabArray
2837  *
2838  * Sets the default tab stops for paragraphs in @text_view.
2839  * Tags in the buffer may override the default.
2840  **/
2841 void
2842 gtk_text_view_set_tabs (GtkTextView   *text_view,
2843                         PangoTabArray *tabs)
2844 {
2845   GtkTextViewPrivate *priv;
2846
2847   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2848
2849   priv = text_view->priv;
2850
2851   if (priv->tabs)
2852     pango_tab_array_free (priv->tabs);
2853
2854   priv->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
2855
2856   if (priv->layout && priv->layout->default_style)
2857     {
2858       /* some unkosher futzing in internal struct details... */
2859       if (priv->layout->default_style->tabs)
2860         pango_tab_array_free (priv->layout->default_style->tabs);
2861
2862       priv->layout->default_style->tabs =
2863         priv->tabs ? pango_tab_array_copy (priv->tabs) : NULL;
2864
2865       gtk_text_layout_default_style_changed (priv->layout);
2866     }
2867
2868   g_object_notify (G_OBJECT (text_view), "tabs");
2869 }
2870
2871 /**
2872  * gtk_text_view_get_tabs:
2873  * @text_view: a #GtkTextView
2874  * 
2875  * Gets the default tabs for @text_view. Tags in the buffer may
2876  * override the defaults. The returned array will be %NULL if
2877  * "standard" (8-space) tabs are used. Free the return value
2878  * with pango_tab_array_free().
2879  * 
2880  * Return value: copy of default tab array, or %NULL if "standard" 
2881  *    tabs are used; must be freed with pango_tab_array_free().
2882  **/
2883 PangoTabArray*
2884 gtk_text_view_get_tabs (GtkTextView *text_view)
2885 {
2886   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
2887
2888   return text_view->priv->tabs ? pango_tab_array_copy (text_view->priv->tabs) : NULL;
2889 }
2890
2891 static void
2892 gtk_text_view_toggle_cursor_visible (GtkTextView *text_view)
2893 {
2894   gtk_text_view_set_cursor_visible (text_view, !text_view->priv->cursor_visible);
2895 }
2896
2897 /**
2898  * gtk_text_view_set_cursor_visible:
2899  * @text_view: a #GtkTextView
2900  * @setting: whether to show the insertion cursor
2901  *
2902  * Toggles whether the insertion point is displayed. A buffer with no editable
2903  * text probably shouldn't have a visible cursor, so you may want to turn
2904  * the cursor off.
2905  **/
2906 void
2907 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
2908                                   gboolean     setting)
2909 {
2910   GtkTextViewPrivate *priv;
2911
2912   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2913
2914   priv = text_view->priv;
2915   setting = (setting != FALSE);
2916
2917   if (priv->cursor_visible != setting)
2918     {
2919       priv->cursor_visible = setting;
2920
2921       if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
2922         {
2923           if (priv->layout)
2924             {
2925               gtk_text_layout_set_cursor_visible (priv->layout, setting);
2926               gtk_text_view_check_cursor_blink (text_view);
2927             }
2928         }
2929
2930       g_object_notify (G_OBJECT (text_view), "cursor-visible");
2931     }
2932 }
2933
2934 /**
2935  * gtk_text_view_get_cursor_visible:
2936  * @text_view: a #GtkTextView
2937  *
2938  * Find out whether the cursor is being displayed.
2939  *
2940  * Return value: whether the insertion mark is visible
2941  **/
2942 gboolean
2943 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
2944 {
2945   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2946
2947   return text_view->priv->cursor_visible;
2948 }
2949
2950
2951 /**
2952  * gtk_text_view_place_cursor_onscreen:
2953  * @text_view: a #GtkTextView
2954  *
2955  * Moves the cursor to the currently visible region of the
2956  * buffer, it it isn't there already.
2957  *
2958  * Return value: %TRUE if the cursor had to be moved.
2959  **/
2960 gboolean
2961 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
2962 {
2963   GtkTextIter insert;
2964
2965   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2966
2967   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2968                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
2969
2970   if (clamp_iter_onscreen (text_view, &insert))
2971     {
2972       gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
2973       return TRUE;
2974     }
2975   else
2976     return FALSE;
2977 }
2978
2979 static void
2980 gtk_text_view_remove_validate_idles (GtkTextView *text_view)
2981 {
2982   GtkTextViewPrivate *priv = text_view->priv;
2983
2984   if (priv->first_validate_idle != 0)
2985     {
2986       DV (g_print ("Removing first validate idle: %s\n", G_STRLOC));
2987       g_source_remove (priv->first_validate_idle);
2988       priv->first_validate_idle = 0;
2989     }
2990
2991   if (priv->incremental_validate_idle != 0)
2992     {
2993       g_source_remove (priv->incremental_validate_idle);
2994       priv->incremental_validate_idle = 0;
2995     }
2996 }
2997
2998 static void
2999 gtk_text_view_destroy (GtkWidget *widget)
3000 {
3001   GtkTextView *text_view;
3002   GtkTextViewPrivate *priv;
3003
3004   text_view = GTK_TEXT_VIEW (widget);
3005   priv = text_view->priv;
3006
3007   gtk_text_view_remove_validate_idles (text_view);
3008   gtk_text_view_set_buffer (text_view, NULL);
3009   gtk_text_view_destroy_layout (text_view);
3010
3011   if (text_view->priv->scroll_timeout)
3012     {
3013       g_source_remove (text_view->priv->scroll_timeout);
3014       text_view->priv->scroll_timeout = 0;
3015     }
3016
3017   if (priv->im_spot_idle)
3018     {
3019       g_source_remove (priv->im_spot_idle);
3020       priv->im_spot_idle = 0;
3021     }
3022
3023   GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget);
3024 }
3025
3026 static void
3027 gtk_text_view_finalize (GObject *object)
3028 {
3029   GtkTextView *text_view;
3030   GtkTextViewPrivate *priv;
3031
3032   text_view = GTK_TEXT_VIEW (object);
3033   priv = text_view->priv;
3034
3035   gtk_text_view_destroy_layout (text_view);
3036   gtk_text_view_set_buffer (text_view, NULL);
3037
3038   /* at this point, no "notify::buffer" handler should recreate the buffer. */
3039   g_assert (priv->buffer == NULL);
3040   
3041   cancel_pending_scroll (text_view);
3042
3043   if (priv->tabs)
3044     pango_tab_array_free (priv->tabs);
3045   
3046   if (priv->hadjustment)
3047     g_object_unref (priv->hadjustment);
3048   if (priv->vadjustment)
3049     g_object_unref (priv->vadjustment);
3050
3051   text_window_free (priv->text_window);
3052
3053   if (priv->left_window)
3054     text_window_free (priv->left_window);
3055
3056   if (priv->top_window)
3057     text_window_free (priv->top_window);
3058
3059   if (priv->right_window)
3060     text_window_free (priv->right_window);
3061
3062   if (priv->bottom_window)
3063     text_window_free (priv->bottom_window);
3064
3065   g_object_unref (priv->im_context);
3066
3067   g_free (priv->im_module);
3068
3069   G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize (object);
3070 }
3071
3072 static void
3073 gtk_text_view_set_property (GObject         *object,
3074                             guint            prop_id,
3075                             const GValue    *value,
3076                             GParamSpec      *pspec)
3077 {
3078   GtkTextView *text_view;
3079   GtkTextViewPrivate *priv;
3080
3081   text_view = GTK_TEXT_VIEW (object);
3082   priv = text_view->priv;
3083
3084   switch (prop_id)
3085     {
3086     case PROP_PIXELS_ABOVE_LINES:
3087       gtk_text_view_set_pixels_above_lines (text_view, g_value_get_int (value));
3088       break;
3089
3090     case PROP_PIXELS_BELOW_LINES:
3091       gtk_text_view_set_pixels_below_lines (text_view, g_value_get_int (value));
3092       break;
3093
3094     case PROP_PIXELS_INSIDE_WRAP:
3095       gtk_text_view_set_pixels_inside_wrap (text_view, g_value_get_int (value));
3096       break;
3097
3098     case PROP_EDITABLE:
3099       gtk_text_view_set_editable (text_view, g_value_get_boolean (value));
3100       break;
3101
3102     case PROP_WRAP_MODE:
3103       gtk_text_view_set_wrap_mode (text_view, g_value_get_enum (value));
3104       break;
3105       
3106     case PROP_JUSTIFICATION:
3107       gtk_text_view_set_justification (text_view, g_value_get_enum (value));
3108       break;
3109
3110     case PROP_LEFT_MARGIN:
3111       gtk_text_view_set_left_margin (text_view, g_value_get_int (value));
3112       break;
3113
3114     case PROP_RIGHT_MARGIN:
3115       gtk_text_view_set_right_margin (text_view, g_value_get_int (value));
3116       break;
3117
3118     case PROP_INDENT:
3119       gtk_text_view_set_indent (text_view, g_value_get_int (value));
3120       break;
3121
3122     case PROP_TABS:
3123       gtk_text_view_set_tabs (text_view, g_value_get_boxed (value));
3124       break;
3125
3126     case PROP_CURSOR_VISIBLE:
3127       gtk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
3128       break;
3129
3130     case PROP_OVERWRITE:
3131       gtk_text_view_set_overwrite (text_view, g_value_get_boolean (value));
3132       break;
3133
3134     case PROP_BUFFER:
3135       gtk_text_view_set_buffer (text_view, GTK_TEXT_BUFFER (g_value_get_object (value)));
3136       break;
3137
3138     case PROP_ACCEPTS_TAB:
3139       gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
3140       break;
3141       
3142     case PROP_IM_MODULE:
3143       g_free (priv->im_module);
3144       priv->im_module = g_value_dup_string (value);
3145       if (GTK_IS_IM_MULTICONTEXT (priv->im_context))
3146         gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (priv->im_context), priv->im_module);
3147       break;
3148
3149     case PROP_HADJUSTMENT:
3150       gtk_text_view_set_hadjustment (text_view, g_value_get_object (value));
3151       break;
3152
3153     case PROP_VADJUSTMENT:
3154       gtk_text_view_set_vadjustment (text_view, g_value_get_object (value));
3155       break;
3156
3157     case PROP_HSCROLL_POLICY:
3158       priv->hscroll_policy = g_value_get_enum (value);
3159       gtk_widget_queue_resize (GTK_WIDGET (text_view));
3160       break;
3161
3162     case PROP_VSCROLL_POLICY:
3163       priv->vscroll_policy = g_value_get_enum (value);
3164       gtk_widget_queue_resize (GTK_WIDGET (text_view));
3165       break;
3166
3167     default:
3168       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3169       break;
3170     }
3171 }
3172
3173 static void
3174 gtk_text_view_get_property (GObject         *object,
3175                             guint            prop_id,
3176                             GValue          *value,
3177                             GParamSpec      *pspec)
3178 {
3179   GtkTextView *text_view;
3180   GtkTextViewPrivate *priv;
3181
3182   text_view = GTK_TEXT_VIEW (object);
3183   priv = text_view->priv;
3184
3185   switch (prop_id)
3186     {
3187     case PROP_PIXELS_ABOVE_LINES:
3188       g_value_set_int (value, priv->pixels_above_lines);
3189       break;
3190
3191     case PROP_PIXELS_BELOW_LINES:
3192       g_value_set_int (value, priv->pixels_below_lines);
3193       break;
3194
3195     case PROP_PIXELS_INSIDE_WRAP:
3196       g_value_set_int (value, priv->pixels_inside_wrap);
3197       break;
3198
3199     case PROP_EDITABLE:
3200       g_value_set_boolean (value, priv->editable);
3201       break;
3202       
3203     case PROP_WRAP_MODE:
3204       g_value_set_enum (value, priv->wrap_mode);
3205       break;
3206
3207     case PROP_JUSTIFICATION:
3208       g_value_set_enum (value, priv->justify);
3209       break;
3210
3211     case PROP_LEFT_MARGIN:
3212       g_value_set_int (value, priv->left_margin);
3213       break;
3214
3215     case PROP_RIGHT_MARGIN:
3216       g_value_set_int (value, priv->right_margin);
3217       break;
3218
3219     case PROP_INDENT:
3220       g_value_set_int (value, priv->indent);
3221       break;
3222
3223     case PROP_TABS:
3224       g_value_set_boxed (value, priv->tabs);
3225       break;
3226
3227     case PROP_CURSOR_VISIBLE:
3228       g_value_set_boolean (value, priv->cursor_visible);
3229       break;
3230
3231     case PROP_BUFFER:
3232       g_value_set_object (value, get_buffer (text_view));
3233       break;
3234
3235     case PROP_OVERWRITE:
3236       g_value_set_boolean (value, priv->overwrite_mode);
3237       break;
3238
3239     case PROP_ACCEPTS_TAB:
3240       g_value_set_boolean (value, priv->accepts_tab);
3241       break;
3242       
3243     case PROP_IM_MODULE:
3244       g_value_set_string (value, priv->im_module);
3245       break;
3246
3247     case PROP_HADJUSTMENT:
3248       g_value_set_object (value, priv->hadjustment);
3249       break;
3250
3251     case PROP_VADJUSTMENT:
3252       g_value_set_object (value, priv->vadjustment);
3253       break;
3254
3255     case PROP_HSCROLL_POLICY:
3256       g_value_set_enum (value, priv->hscroll_policy);
3257       break;
3258
3259     case PROP_VSCROLL_POLICY:
3260       g_value_set_enum (value, priv->vscroll_policy);
3261       break;
3262
3263     default:
3264       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3265       break;
3266     }
3267 }
3268
3269 static void
3270 gtk_text_view_size_request (GtkWidget      *widget,
3271                             GtkRequisition *requisition)
3272 {
3273   GtkTextView *text_view;
3274   GtkTextViewPrivate *priv;
3275   GSList *tmp_list;
3276   gint focus_edge_width;
3277   gint focus_width;
3278   guint border_width;
3279   gboolean interior_focus;
3280
3281   text_view = GTK_TEXT_VIEW (widget);
3282   priv = text_view->priv;
3283
3284   gtk_widget_style_get (widget,
3285                         "interior-focus", &interior_focus,
3286                         "focus-line-width", &focus_width,
3287                         NULL);
3288
3289   if (interior_focus)
3290     focus_edge_width = 0;
3291   else
3292     focus_edge_width = focus_width;
3293
3294   if (priv->layout)
3295     {
3296       priv->text_window->requisition.width = priv->layout->width;
3297       priv->text_window->requisition.height = priv->layout->height;
3298     }
3299   else
3300     {
3301       priv->text_window->requisition.width = 0;
3302       priv->text_window->requisition.height = 0;
3303     }
3304   
3305   requisition->width = priv->text_window->requisition.width + focus_edge_width * 2;
3306   requisition->height = priv->text_window->requisition.height + focus_edge_width * 2;
3307
3308   if (priv->left_window)
3309     requisition->width += priv->left_window->requisition.width;
3310
3311   if (priv->right_window)
3312     requisition->width += priv->right_window->requisition.width;
3313
3314   if (priv->top_window)
3315     requisition->height += priv->top_window->requisition.height;
3316
3317   if (priv->bottom_window)
3318     requisition->height += priv->bottom_window->requisition.height;
3319
3320   border_width = gtk_container_get_border_width (GTK_CONTAINER (text_view));
3321   requisition->width += border_width * 2;
3322   requisition->height += border_width * 2;
3323   
3324   tmp_list = priv->children;
3325   while (tmp_list != NULL)
3326     {
3327       GtkTextViewChild *child = tmp_list->data;
3328
3329       if (child->anchor)
3330         {
3331           GtkRequisition child_req;
3332           GtkRequisition old_req;
3333
3334           gtk_widget_get_preferred_size (child->widget, &old_req, NULL);
3335
3336           gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
3337
3338           /* Invalidate layout lines if required */
3339           if (priv->layout &&
3340               (old_req.width != child_req.width ||
3341                old_req.height != child_req.height))
3342             gtk_text_child_anchor_queue_resize (child->anchor,
3343                                                 priv->layout);
3344         }
3345       else
3346         {
3347           GtkRequisition child_req;
3348
3349           gtk_widget_get_preferred_size (child->widget,
3350                                          &child_req, NULL);
3351         }
3352
3353       tmp_list = g_slist_next (tmp_list);
3354     }
3355
3356   /* Cache the requested size of the text view so we can 
3357    * compare it in the changed_handler() */
3358   priv->cached_size_request = *requisition;
3359 }
3360
3361 static void
3362 gtk_text_view_get_preferred_width (GtkWidget *widget,
3363                                    gint      *minimum,
3364                                    gint      *natural)
3365 {
3366   GtkRequisition requisition;
3367
3368   gtk_text_view_size_request (widget, &requisition);
3369
3370   *minimum = *natural = requisition.width;
3371 }
3372
3373 static void
3374 gtk_text_view_get_preferred_height (GtkWidget *widget,
3375                                     gint      *minimum,
3376                                     gint      *natural)
3377 {
3378   GtkRequisition requisition;
3379
3380   gtk_text_view_size_request (widget, &requisition);
3381
3382   *minimum = *natural = requisition.height;
3383 }
3384
3385
3386 static void
3387 gtk_text_view_compute_child_allocation (GtkTextView      *text_view,
3388                                         GtkTextViewChild *vc,
3389                                         GtkAllocation    *allocation)
3390 {
3391   gint buffer_y;
3392   GtkTextIter iter;
3393   GtkRequisition req;
3394   
3395   gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3396                                             &iter,
3397                                             vc->anchor);
3398
3399   gtk_text_layout_get_line_yrange (text_view->priv->layout, &iter,
3400                                    &buffer_y, NULL);
3401
3402   buffer_y += vc->from_top_of_line;
3403
3404   allocation->x = vc->from_left_of_buffer - text_view->priv->xoffset;
3405   allocation->y = buffer_y - text_view->priv->yoffset;
3406
3407   gtk_widget_get_preferred_size (vc->widget, &req, NULL);
3408   allocation->width = req.width;
3409   allocation->height = req.height;
3410 }
3411
3412 static void
3413 gtk_text_view_update_child_allocation (GtkTextView      *text_view,
3414                                        GtkTextViewChild *vc)
3415 {
3416   GtkAllocation allocation;
3417
3418   gtk_text_view_compute_child_allocation (text_view, vc, &allocation);
3419   
3420   gtk_widget_size_allocate (vc->widget, &allocation);
3421
3422 #if 0
3423   g_print ("allocation for %p allocated to %d,%d yoffset = %d\n",
3424            vc->widget,
3425            vc->widget->allocation.x,
3426            vc->widget->allocation.y,
3427            text_view->priv->yoffset);
3428 #endif
3429 }
3430
3431 static void
3432 gtk_text_view_child_allocated (GtkTextLayout *layout,
3433                                GtkWidget     *child,
3434                                gint           x,
3435                                gint           y,
3436                                gpointer       data)
3437 {
3438   GtkTextViewChild *vc = NULL;
3439   GtkTextView *text_view = data;
3440   
3441   /* x,y is the position of the child from the top of the line, and
3442    * from the left of the buffer. We have to translate that into text
3443    * window coordinates, then size_allocate the child.
3444    */
3445
3446   vc = g_object_get_data (G_OBJECT (child),
3447                           "gtk-text-view-child");
3448
3449   g_assert (vc != NULL);
3450
3451   DV (g_print ("child allocated at %d,%d\n", x, y));
3452   
3453   vc->from_left_of_buffer = x;
3454   vc->from_top_of_line = y;
3455
3456   gtk_text_view_update_child_allocation (text_view, vc);
3457 }
3458
3459 static void
3460 gtk_text_view_allocate_children (GtkTextView *text_view)
3461 {
3462   GSList *tmp_list;
3463
3464   DV(g_print(G_STRLOC"\n"));
3465   
3466   tmp_list = text_view->priv->children;
3467   while (tmp_list != NULL)
3468     {
3469       GtkTextViewChild *child = tmp_list->data;
3470
3471       g_assert (child != NULL);
3472           
3473       if (child->anchor)
3474         {
3475           /* We need to force-validate the regions containing
3476            * children.
3477            */
3478           GtkTextIter child_loc;
3479           gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3480                                                     &child_loc,
3481                                                     child->anchor);
3482
3483           /* Since anchored children are only ever allocated from
3484            * gtk_text_layout_get_line_display() we have to make sure
3485            * that the display line caching in the layout doesn't 
3486            * get in the way. Invalidating the layout around the anchor
3487            * achieves this.
3488            */ 
3489           if (_gtk_widget_get_alloc_needed (child->widget))
3490             {
3491               GtkTextIter end = child_loc;
3492               gtk_text_iter_forward_char (&end);
3493               gtk_text_layout_invalidate (text_view->priv->layout, &child_loc, &end);
3494             }
3495
3496           gtk_text_layout_validate_yrange (text_view->priv->layout,
3497                                            &child_loc,
3498                                            0, 1);
3499         }
3500       else
3501         {
3502           GtkAllocation allocation;
3503           GtkRequisition child_req;
3504              
3505           allocation.x = child->x;
3506           allocation.y = child->y;
3507
3508           gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
3509
3510           allocation.width = child_req.width;
3511           allocation.height = child_req.height;
3512           
3513           gtk_widget_size_allocate (child->widget, &allocation);          
3514         }
3515
3516       tmp_list = g_slist_next (tmp_list);
3517     }
3518 }
3519
3520 static void
3521 gtk_text_view_size_allocate (GtkWidget *widget,
3522                              GtkAllocation *allocation)
3523 {
3524   GtkAllocation widget_allocation;
3525   GtkTextView *text_view;
3526   GtkTextViewPrivate *priv;
3527   gint width, height;
3528   GdkRectangle text_rect;
3529   GdkRectangle left_rect;
3530   GdkRectangle right_rect;
3531   GdkRectangle top_rect;
3532   GdkRectangle bottom_rect;
3533   gint focus_edge_width;
3534   gint focus_width;
3535   guint border_width;
3536   gboolean interior_focus;
3537   gboolean size_changed;
3538   
3539   text_view = GTK_TEXT_VIEW (widget);
3540   priv = text_view->priv;
3541
3542   DV(g_print(G_STRLOC"\n"));
3543
3544   gtk_widget_get_allocation (widget, &widget_allocation);
3545   size_changed =
3546     widget_allocation.width != allocation->width ||
3547     widget_allocation.height != allocation->height;
3548
3549   border_width = gtk_container_get_border_width (GTK_CONTAINER (text_view));
3550
3551   gtk_widget_set_allocation (widget, allocation);
3552
3553   if (gtk_widget_get_realized (widget))
3554     {
3555       gdk_window_move_resize (gtk_widget_get_window (widget),
3556                               allocation->x, allocation->y,
3557                               allocation->width, allocation->height);
3558     }
3559
3560   /* distribute width/height among child windows. Ensure all
3561    * windows get at least a 1x1 allocation.
3562    */
3563
3564   gtk_widget_style_get (widget,
3565                         "interior-focus", &interior_focus,
3566                         "focus-line-width", &focus_width,
3567                         NULL);
3568
3569   if (interior_focus)
3570     focus_edge_width = 0;
3571   else
3572     focus_edge_width = focus_width;
3573   
3574   width = allocation->width - focus_edge_width * 2 - border_width * 2;
3575
3576   if (priv->left_window)
3577     left_rect.width = priv->left_window->requisition.width;
3578   else
3579     left_rect.width = 0;
3580
3581   width -= left_rect.width;
3582
3583   if (priv->right_window)
3584     right_rect.width = priv->right_window->requisition.width;
3585   else
3586     right_rect.width = 0;
3587
3588   width -= right_rect.width;
3589
3590   text_rect.width = MAX (1, width);
3591
3592   top_rect.width = text_rect.width;
3593   bottom_rect.width = text_rect.width;
3594
3595
3596   height = allocation->height - focus_edge_width * 2 - border_width * 2;
3597
3598   if (priv->top_window)
3599     top_rect.height = priv->top_window->requisition.height;
3600   else
3601     top_rect.height = 0;
3602
3603   height -= top_rect.height;
3604
3605   if (priv->bottom_window)
3606     bottom_rect.height = priv->bottom_window->requisition.height;
3607   else
3608     bottom_rect.height = 0;
3609
3610   height -= bottom_rect.height;
3611
3612   text_rect.height = MAX (1, height);
3613
3614   left_rect.height = text_rect.height;
3615   right_rect.height = text_rect.height;
3616
3617   /* Origins */
3618   left_rect.x = focus_edge_width + border_width;
3619   top_rect.y = focus_edge_width + border_width;
3620
3621   text_rect.x = left_rect.x + left_rect.width;
3622   text_rect.y = top_rect.y + top_rect.height;
3623
3624   left_rect.y = text_rect.y;
3625   right_rect.y = text_rect.y;
3626
3627   top_rect.x = text_rect.x;
3628   bottom_rect.x = text_rect.x;
3629
3630   right_rect.x = text_rect.x + text_rect.width;
3631   bottom_rect.y = text_rect.y + text_rect.height;
3632
3633   text_window_size_allocate (priv->text_window,
3634                              &text_rect);
3635
3636   if (priv->left_window)
3637     text_window_size_allocate (priv->left_window,
3638                                &left_rect);
3639
3640   if (priv->right_window)
3641     text_window_size_allocate (priv->right_window,
3642                                &right_rect);
3643
3644   if (priv->top_window)
3645     text_window_size_allocate (priv->top_window,
3646                                &top_rect);
3647
3648   if (priv->bottom_window)
3649     text_window_size_allocate (priv->bottom_window,
3650                                &bottom_rect);
3651
3652   gtk_text_view_update_layout_width (text_view);
3653   
3654   /* Note that this will do some layout validation */
3655   gtk_text_view_allocate_children (text_view);
3656
3657   /* Update adjustments */
3658   gtk_text_view_set_hadjustment_values (text_view);
3659   gtk_text_view_set_vadjustment_values (text_view);
3660
3661   /* The GTK resize loop processes all the pending exposes right
3662    * after doing the resize stuff, so the idle sizer won't have a
3663    * chance to run. So we do the work here. 
3664    */
3665   gtk_text_view_flush_first_validate (text_view);
3666
3667   /* widget->window doesn't get auto-redrawn as the layout is computed, so has to
3668    * be invalidated
3669    */
3670   if (size_changed && gtk_widget_get_realized (widget))
3671     gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);
3672 }
3673
3674 static void
3675 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
3676                                    GtkTextIter *iter)
3677 {
3678   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
3679                                     text_view->priv->first_para_mark);
3680 }
3681
3682 static void
3683 gtk_text_view_validate_onscreen (GtkTextView *text_view)
3684 {
3685   GtkWidget *widget;
3686   GtkTextViewPrivate *priv;
3687
3688   widget = GTK_WIDGET (text_view);
3689   priv = text_view->priv;
3690   
3691   DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
3692   
3693   if (SCREEN_HEIGHT (widget) > 0)
3694     {
3695       GtkTextIter first_para;
3696
3697       /* Be sure we've validated the stuff onscreen; if we
3698        * scrolled, these calls won't have any effect, because
3699        * they were called in the recursive validate_onscreen
3700        */
3701       gtk_text_view_get_first_para_iter (text_view, &first_para);
3702
3703       gtk_text_layout_validate_yrange (priv->layout,
3704                                        &first_para,
3705                                        0,
3706                                        priv->first_para_pixels +
3707                                        SCREEN_HEIGHT (widget));
3708     }
3709
3710   priv->onscreen_validated = TRUE;
3711
3712   DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
3713   
3714   /* This can have the odd side effect of triggering a scroll, which should
3715    * flip "onscreen_validated" back to FALSE, but should also get us
3716    * back into this function to turn it on again.
3717    */
3718   gtk_text_view_update_adjustments (text_view);
3719
3720   g_assert (priv->onscreen_validated);
3721 }
3722
3723 static void
3724 gtk_text_view_flush_first_validate (GtkTextView *text_view)
3725 {
3726   GtkTextViewPrivate *priv = text_view->priv;
3727
3728   if (priv->first_validate_idle == 0)
3729     return;
3730
3731   /* Do this first, which means that if an "invalidate"
3732    * occurs during any of this process, a new first_validate_callback
3733    * will be installed, and we'll start again.
3734    */
3735   DV (g_print ("removing first validate in %s\n", G_STRLOC));
3736   g_source_remove (priv->first_validate_idle);
3737   priv->first_validate_idle = 0;
3738   
3739   /* be sure we have up-to-date screen size set on the
3740    * layout.
3741    */
3742   gtk_text_view_update_layout_width (text_view);
3743
3744   /* Bail out if we invalidated stuff; scrolling right away will just
3745    * confuse the issue.
3746    */
3747   if (priv->first_validate_idle != 0)
3748     {
3749       DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
3750     }
3751   else
3752     {
3753       /* scroll to any marks, if that's pending. This can jump us to
3754        * the validation codepath used for scrolling onscreen, if so we
3755        * bail out.  It won't jump if already in that codepath since
3756        * value_changed is not recursive, so also validate if
3757        * necessary.
3758        */
3759       if (!gtk_text_view_flush_scroll (text_view) ||
3760           !priv->onscreen_validated)
3761         gtk_text_view_validate_onscreen (text_view);
3762       
3763       DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
3764       
3765       g_assert (priv->onscreen_validated);
3766     }
3767 }
3768
3769 static gboolean
3770 first_validate_callback (gpointer data)
3771 {
3772   GtkTextView *text_view = data;
3773
3774   /* Note that some of this code is duplicated at the end of size_allocate,
3775    * keep in sync with that.
3776    */
3777   
3778   DV(g_print(G_STRLOC"\n"));
3779
3780   gtk_text_view_flush_first_validate (text_view);
3781   
3782   return FALSE;
3783 }
3784
3785 static gboolean
3786 incremental_validate_callback (gpointer data)
3787 {
3788   GtkTextView *text_view = data;
3789   gboolean result = TRUE;
3790
3791   DV(g_print(G_STRLOC"\n"));
3792   
3793   gtk_text_layout_validate (text_view->priv->layout, 2000);
3794
3795   gtk_text_view_update_adjustments (text_view);
3796   
3797   if (gtk_text_layout_is_valid (text_view->priv->layout))
3798     {
3799       text_view->priv->incremental_validate_idle = 0;
3800       result = FALSE;
3801     }
3802
3803   return result;
3804 }
3805
3806 static void
3807 gtk_text_view_invalidate (GtkTextView *text_view)
3808 {
3809   GtkTextViewPrivate *priv = text_view->priv;
3810
3811   DV (g_print (">Invalidate, onscreen_validated = %d now FALSE ("G_STRLOC")\n",
3812                priv->onscreen_validated));
3813
3814   priv->onscreen_validated = FALSE;
3815
3816   /* We'll invalidate when the layout is created */
3817   if (priv->layout == NULL)
3818     return;
3819   
3820   if (!priv->first_validate_idle)
3821     {
3822       priv->first_validate_idle = gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
3823       DV (g_print (G_STRLOC": adding first validate idle %d\n",
3824                    priv->first_validate_idle));
3825     }
3826       
3827   if (!priv->incremental_validate_idle)
3828     {
3829       priv->incremental_validate_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
3830       DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
3831                    priv->incremental_validate_idle));
3832     }
3833 }
3834
3835 static void
3836 invalidated_handler (GtkTextLayout *layout,
3837                      gpointer       data)
3838 {
3839   GtkTextView *text_view;
3840
3841   text_view = GTK_TEXT_VIEW (data);
3842
3843   DV (g_print ("Invalidating due to layout invalidate signal\n"));
3844   gtk_text_view_invalidate (text_view);
3845 }
3846
3847 static void
3848 changed_handler (GtkTextLayout     *layout,
3849                  gint               start_y,
3850                  gint               old_height,
3851                  gint               new_height,
3852                  gpointer           data)
3853 {
3854   GtkTextView *text_view;
3855   GtkTextViewPrivate *priv;
3856   GtkWidget *widget;
3857   GdkRectangle visible_rect;
3858   GdkRectangle redraw_rect;
3859   
3860   text_view = GTK_TEXT_VIEW (data);
3861   priv = text_view->priv;
3862   widget = GTK_WIDGET (data);
3863   
3864   DV(g_print(">Lines Validated ("G_STRLOC")\n"));
3865
3866   if (gtk_widget_get_realized (widget))
3867     {      
3868       gtk_text_view_get_visible_rect (text_view, &visible_rect);
3869
3870       redraw_rect.x = visible_rect.x;
3871       redraw_rect.width = visible_rect.width;
3872       redraw_rect.y = start_y;
3873
3874       if (old_height == new_height)
3875         redraw_rect.height = old_height;
3876       else if (start_y + old_height > visible_rect.y)
3877         redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
3878       else
3879         redraw_rect.height = 0;
3880         
3881       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
3882         {
3883           /* text_window_invalidate_rect() takes buffer coordinates */
3884           text_window_invalidate_rect (priv->text_window,
3885                                        &redraw_rect);
3886
3887           DV(g_print(" invalidated rect: %d,%d %d x %d\n",
3888                      redraw_rect.x,
3889                      redraw_rect.y,
3890                      redraw_rect.width,
3891                      redraw_rect.height));
3892           
3893           if (priv->left_window)
3894             text_window_invalidate_rect (priv->left_window,
3895                                          &redraw_rect);
3896           if (priv->right_window)
3897             text_window_invalidate_rect (priv->right_window,
3898                                          &redraw_rect);
3899           if (priv->top_window)
3900             text_window_invalidate_rect (priv->top_window,
3901                                          &redraw_rect);
3902           if (priv->bottom_window)
3903             text_window_invalidate_rect (priv->bottom_window,
3904                                          &redraw_rect);
3905
3906           queue_update_im_spot_location (text_view);
3907         }
3908     }
3909   
3910   if (old_height != new_height)
3911     {
3912       GSList *tmp_list;
3913       int new_first_para_top;
3914       int old_first_para_top;
3915       GtkTextIter first;
3916       
3917       /* If the bottom of the old area was above the top of the
3918        * screen, we need to scroll to keep the current top of the
3919        * screen in place.  Remember that first_para_pixels is the
3920        * position of the top of the screen in coordinates relative to
3921        * the first paragraph onscreen.
3922        *
3923        * In short we are adding the height delta of the portion of the
3924        * changed region above first_para_mark to priv->yoffset.
3925        */
3926       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &first,
3927                                         priv->first_para_mark);
3928
3929       gtk_text_layout_get_line_yrange (layout, &first, &new_first_para_top, NULL);
3930
3931       old_first_para_top = priv->yoffset - priv->first_para_pixels;
3932
3933       if (new_first_para_top != old_first_para_top)
3934         {
3935           priv->yoffset += new_first_para_top - old_first_para_top;
3936           
3937           gtk_adjustment_set_value (text_view->priv->vadjustment, priv->yoffset);
3938         }
3939
3940       /* FIXME be smarter about which anchored widgets we update */
3941
3942       tmp_list = priv->children;
3943       while (tmp_list != NULL)
3944         {
3945           GtkTextViewChild *child = tmp_list->data;
3946
3947           if (child->anchor)
3948             gtk_text_view_update_child_allocation (text_view, child);
3949
3950           tmp_list = g_slist_next (tmp_list);
3951         }
3952     }
3953
3954   {
3955     GtkRequisition old_req = priv->cached_size_request;
3956     GtkRequisition new_req;
3957
3958     /* Use this instead of gtk_widget_size_request wrapper
3959      * to avoid the optimization which just returns widget->requisition
3960      * if a resize hasn't been queued.
3961      */
3962     gtk_text_view_size_request (widget, &new_req);
3963
3964     if (old_req.width != new_req.width ||
3965         old_req.height != new_req.height)
3966       {
3967         gtk_widget_queue_resize_no_redraw (widget);
3968       }
3969   }
3970 }
3971
3972 static void
3973 gtk_text_view_realize (GtkWidget *widget)
3974 {
3975   GtkAllocation allocation;
3976   GtkTextView *text_view;
3977   GtkTextViewPrivate *priv;
3978   GtkStyleContext *context;
3979   GtkStateFlags state;
3980   GdkWindow *window;
3981   GdkWindowAttr attributes;
3982   gint attributes_mask;
3983   GSList *tmp_list;
3984   GdkRGBA color;
3985
3986   text_view = GTK_TEXT_VIEW (widget);
3987   priv = text_view->priv;
3988
3989   gtk_widget_set_realized (widget, TRUE);
3990
3991   gtk_widget_get_allocation (widget, &allocation);
3992
3993   attributes.window_type = GDK_WINDOW_CHILD;
3994   attributes.x = allocation.x;
3995   attributes.y = allocation.y;
3996   attributes.width = allocation.width;
3997   attributes.height = allocation.height;
3998   attributes.wclass = GDK_INPUT_OUTPUT;
3999   attributes.visual = gtk_widget_get_visual (widget);
4000   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
4001
4002   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
4003
4004   window = gdk_window_new (gtk_widget_get_parent_window (widget),
4005                            &attributes, attributes_mask);
4006   gtk_widget_set_window (widget, window);
4007   gdk_window_set_user_data (window, widget);
4008
4009   context = gtk_widget_get_style_context (widget);
4010   state = gtk_widget_get_state_flags (widget);
4011
4012   gtk_style_context_get_background_color (context, state, &color);
4013   gdk_window_set_background_rgba (window, &color);
4014
4015   text_window_realize (priv->text_window, widget);
4016
4017   if (priv->left_window)
4018     text_window_realize (priv->left_window, widget);
4019
4020   if (priv->top_window)
4021     text_window_realize (priv->top_window, widget);
4022
4023   if (priv->right_window)
4024     text_window_realize (priv->right_window, widget);
4025
4026   if (priv->bottom_window)
4027     text_window_realize (priv->bottom_window, widget);
4028
4029   gtk_text_view_ensure_layout (text_view);
4030   gtk_text_view_invalidate (text_view);
4031
4032   if (priv->buffer)
4033     {
4034       GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
4035                                                           GDK_SELECTION_PRIMARY);
4036       gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
4037     }
4038
4039   tmp_list = priv->children;
4040   while (tmp_list != NULL)
4041     {
4042       GtkTextViewChild *vc = tmp_list->data;
4043       
4044       text_view_child_set_parent_window (text_view, vc);
4045       
4046       tmp_list = tmp_list->next;
4047     }
4048
4049   /* Ensure updating the spot location. */
4050   gtk_text_view_update_im_spot_location (text_view);
4051 }
4052
4053 static void
4054 gtk_text_view_unrealize (GtkWidget *widget)
4055 {
4056   GtkTextView *text_view;
4057   GtkTextViewPrivate *priv;
4058
4059   text_view = GTK_TEXT_VIEW (widget);
4060   priv = text_view->priv;
4061
4062   if (priv->buffer)
4063     {
4064       GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
4065                                                           GDK_SELECTION_PRIMARY);
4066       gtk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
4067     }
4068
4069   gtk_text_view_remove_validate_idles (text_view);
4070
4071   if (priv->popup_menu)
4072     {
4073       gtk_widget_destroy (priv->popup_menu);
4074       priv->popup_menu = NULL;
4075     }
4076
4077   text_window_unrealize (priv->text_window);
4078
4079   if (priv->left_window)
4080     text_window_unrealize (priv->left_window);
4081
4082   if (priv->top_window)
4083     text_window_unrealize (priv->top_window);
4084
4085   if (priv->right_window)
4086     text_window_unrealize (priv->right_window);
4087
4088   if (priv->bottom_window)
4089     text_window_unrealize (priv->bottom_window);
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 }
6733
6734 /**
6735  * gtk_text_view_get_default_attributes:
6736  * @text_view: a #GtkTextView
6737  * 
6738  * Obtains a copy of the default text attributes. These are the
6739  * attributes used for text unless a tag overrides them.
6740  * You'd typically pass the default attributes in to
6741  * gtk_text_iter_get_attributes() in order to get the
6742  * attributes in effect at a given text position.
6743  *
6744  * The return value is a copy owned by the caller of this function,
6745  * and should be freed.
6746  * 
6747  * Return value: a new #GtkTextAttributes
6748  **/
6749 GtkTextAttributes*
6750 gtk_text_view_get_default_attributes (GtkTextView *text_view)
6751 {
6752   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
6753   
6754   gtk_text_view_ensure_layout (text_view);
6755
6756   return gtk_text_attributes_copy (text_view->priv->layout->default_style);
6757 }
6758
6759 static void
6760 gtk_text_view_destroy_layout (GtkTextView *text_view)
6761 {
6762   GtkTextViewPrivate *priv = text_view->priv;
6763
6764   if (priv->layout)
6765     {
6766       GSList *tmp_list;
6767
6768       gtk_text_view_remove_validate_idles (text_view);
6769
6770       g_signal_handlers_disconnect_by_func (priv->layout,
6771                                             invalidated_handler,
6772                                             text_view);
6773       g_signal_handlers_disconnect_by_func (priv->layout,
6774                                             changed_handler,
6775                                             text_view);
6776
6777       /* Remove layout from all anchored children */
6778       tmp_list = priv->children;
6779       while (tmp_list != NULL)
6780         {
6781           GtkTextViewChild *vc = tmp_list->data;
6782
6783           if (vc->anchor)
6784             {
6785               gtk_text_anchored_child_set_layout (vc->widget, NULL);
6786               /* vc may now be invalid! */
6787             }
6788
6789           tmp_list = g_slist_next (tmp_list);
6790         }
6791
6792       gtk_text_view_stop_cursor_blink (text_view);
6793       gtk_text_view_end_selection_drag (text_view);
6794
6795       g_object_unref (priv->layout);
6796       priv->layout = NULL;
6797     }
6798 }
6799
6800 /**
6801  * gtk_text_view_reset_im_context:
6802  * @text_view: a #GtkTextView
6803  *
6804  * Reset the input method context of the text view if needed.
6805  *
6806  * This can be necessary in the case where modifying the buffer
6807  * would confuse on-going input method behavior.
6808  *
6809  * Since: 2.22
6810  */
6811 void
6812 gtk_text_view_reset_im_context (GtkTextView *text_view)
6813 {
6814   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6815
6816   if (text_view->priv->need_im_reset)
6817     {
6818       text_view->priv->need_im_reset = FALSE;
6819       gtk_im_context_reset (text_view->priv->im_context);
6820     }
6821 }
6822
6823 /**
6824  * gtk_text_view_im_context_filter_keypress:
6825  * @text_view: a #GtkTextView
6826  * @event: the key event
6827  *
6828  * Allow the #GtkTextView input method to internally handle key press
6829  * and release events. If this function returns %TRUE, then no further
6830  * processing should be done for this key event. See
6831  * gtk_im_context_filter_keypress().
6832  *
6833  * Note that you are expected to call this function from your handler
6834  * when overriding key event handling. This is needed in the case when
6835  * you need to insert your own key handling between the input method
6836  * and the default key event handling of the #GtkTextView.
6837  *
6838  * |[
6839  * static gboolean
6840  * gtk_foo_bar_key_press_event (GtkWidget   *widget,
6841  *                              GdkEventKey *event)
6842  * {
6843  *   if ((key->keyval == GDK_KEY_Return || key->keyval == GDK_KEY_KP_Enter))
6844  *     {
6845  *       if (gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
6846  *         return TRUE;
6847  *     }
6848  *
6849  *     /&ast; Do some stuff &ast;/
6850  *
6851  *   return GTK_WIDGET_CLASS (gtk_foo_bar_parent_class)->key_press_event (widget, event);
6852  * }
6853  * ]|
6854  *
6855  * Return value: %TRUE if the input method handled the key event.
6856  *
6857  * Since: 2.22
6858  */
6859 gboolean
6860 gtk_text_view_im_context_filter_keypress (GtkTextView  *text_view,
6861                                           GdkEventKey  *event)
6862 {
6863   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
6864
6865   return gtk_im_context_filter_keypress (text_view->priv->im_context, event);
6866 }
6867
6868 /*
6869  * DND feature
6870  */
6871
6872 static void
6873 drag_begin_cb (GtkWidget      *widget,
6874                GdkDragContext *context,
6875                gpointer        data)
6876 {
6877   GtkTextView     *text_view = GTK_TEXT_VIEW (widget);
6878   GtkTextBuffer   *buffer = gtk_text_view_get_buffer (text_view);
6879   GtkTextIter      start;
6880   GtkTextIter      end;
6881   cairo_surface_t *surface = NULL;
6882
6883   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
6884
6885   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6886     surface = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
6887
6888   if (surface)
6889     {
6890       gtk_drag_set_icon_surface (context, surface);
6891       cairo_surface_destroy (surface);
6892     }
6893   else
6894     {
6895       gtk_drag_set_icon_default (context);
6896     }
6897 }
6898
6899 static void
6900 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
6901                                    const GtkTextIter *iter,
6902                                    GdkEventMotion    *event)
6903 {
6904   GtkTargetList *target_list;
6905
6906   text_view->priv->drag_start_x = -1;
6907   text_view->priv->drag_start_y = -1;
6908   text_view->priv->pending_place_cursor_button = 0;
6909
6910   target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
6911
6912   g_signal_connect (text_view, "drag-begin",
6913                     G_CALLBACK (drag_begin_cb), NULL);
6914   gtk_drag_begin (GTK_WIDGET (text_view), target_list,
6915                   GDK_ACTION_COPY | GDK_ACTION_MOVE,
6916                   1, (GdkEvent*)event);
6917 }
6918
6919 static void
6920 gtk_text_view_drag_begin (GtkWidget        *widget,
6921                           GdkDragContext   *context)
6922 {
6923   /* do nothing */
6924 }
6925
6926 static void
6927 gtk_text_view_drag_end (GtkWidget        *widget,
6928                         GdkDragContext   *context)
6929 {
6930 }
6931
6932 static void
6933 gtk_text_view_drag_data_get (GtkWidget        *widget,
6934                              GdkDragContext   *context,
6935                              GtkSelectionData *selection_data,
6936                              guint             info,
6937                              guint             time)
6938 {
6939   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6940   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6941
6942   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6943     {
6944       gtk_selection_data_set (selection_data,
6945                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
6946                               8, /* bytes */
6947                               (void*)&buffer,
6948                               sizeof (buffer));
6949     }
6950   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6951     {
6952       GtkTextIter start;
6953       GtkTextIter end;
6954       guint8 *str = NULL;
6955       gsize len;
6956
6957       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6958         {
6959           /* Extract the selected text */
6960           str = gtk_text_buffer_serialize (buffer, buffer,
6961                                            gtk_selection_data_get_target (selection_data),
6962                                            &start, &end,
6963                                            &len);
6964         }
6965
6966       if (str)
6967         {
6968           gtk_selection_data_set (selection_data,
6969                                   gtk_selection_data_get_target (selection_data),
6970                                   8, /* bytes */
6971                                   (guchar *) str, len);
6972           g_free (str);
6973         }
6974     }
6975   else
6976     {
6977       GtkTextIter start;
6978       GtkTextIter end;
6979       gchar *str = NULL;
6980
6981       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6982         {
6983           /* Extract the selected text */
6984           str = gtk_text_iter_get_visible_text (&start, &end);
6985         }
6986
6987       if (str)
6988         {
6989           gtk_selection_data_set_text (selection_data, str, -1);
6990           g_free (str);
6991         }
6992     }
6993 }
6994
6995 static void
6996 gtk_text_view_drag_data_delete (GtkWidget        *widget,
6997                                 GdkDragContext   *context)
6998 {
6999   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->priv->buffer,
7000                                     TRUE, GTK_TEXT_VIEW (widget)->priv->editable);
7001 }
7002
7003 static void
7004 gtk_text_view_drag_leave (GtkWidget        *widget,
7005                           GdkDragContext   *context,
7006                           guint             time)
7007 {
7008   GtkTextView *text_view;
7009   GtkTextViewPrivate *priv;
7010
7011   text_view = GTK_TEXT_VIEW (widget);
7012   priv = text_view->priv;
7013
7014   gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
7015
7016   if (priv->dnd_device)
7017     priv->dnd_device = NULL;
7018
7019   if (priv->scroll_timeout != 0)
7020     g_source_remove (priv->scroll_timeout);
7021
7022   priv->scroll_timeout = 0;
7023 }
7024
7025 static gboolean
7026 gtk_text_view_drag_motion (GtkWidget        *widget,
7027                            GdkDragContext   *context,
7028                            gint              x,
7029                            gint              y,
7030                            guint             time)
7031 {
7032   GtkTextIter newplace;
7033   GtkTextView *text_view;
7034   GtkTextViewPrivate *priv;
7035   GtkTextIter start;
7036   GtkTextIter end;
7037   GdkRectangle target_rect;
7038   gint bx, by;
7039   GdkAtom target;
7040   GdkDragAction suggested_action = 0;
7041   
7042   text_view = GTK_TEXT_VIEW (widget);
7043   priv = text_view->priv;
7044
7045   target_rect = priv->text_window->allocation;
7046   
7047   if (x < target_rect.x ||
7048       y < target_rect.y ||
7049       x > (target_rect.x + target_rect.width) ||
7050       y > (target_rect.y + target_rect.height))
7051     return FALSE; /* outside the text window, allow parent widgets to handle event */
7052
7053   gtk_text_view_window_to_buffer_coords (text_view,
7054                                          GTK_TEXT_WINDOW_WIDGET,
7055                                          x, y,
7056                                          &bx, &by);
7057
7058   gtk_text_layout_get_iter_at_pixel (priv->layout,
7059                                      &newplace,
7060                                      bx, by);  
7061
7062   target = gtk_drag_dest_find_target (widget, context,
7063                                       gtk_drag_dest_get_target_list (widget));
7064
7065   if (target == GDK_NONE)
7066     {
7067       /* can't accept any of the offered targets */
7068     }                                 
7069   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7070                                                  &start, &end) &&
7071            gtk_text_iter_compare (&newplace, &start) >= 0 &&
7072            gtk_text_iter_compare (&newplace, &end) <= 0)
7073     {
7074       /* We're inside the selection. */
7075     }
7076   else
7077     {      
7078       if (gtk_text_iter_can_insert (&newplace, priv->editable))
7079         {
7080           GtkWidget *source_widget;
7081           
7082           suggested_action = gdk_drag_context_get_suggested_action (context);
7083           
7084           source_widget = gtk_drag_get_source_widget (context);
7085           
7086           if (source_widget == widget)
7087             {
7088               /* Default to MOVE, unless the user has
7089                * pressed ctrl or alt to affect available actions
7090                */
7091               if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7092                 suggested_action = GDK_ACTION_MOVE;
7093             }
7094         }
7095       else
7096         {
7097           /* Can't drop here. */
7098         }
7099     }
7100
7101   if (suggested_action != 0)
7102     {
7103       gtk_text_mark_set_visible (priv->dnd_mark,
7104                                  priv->cursor_visible);
7105       
7106       gdk_drag_status (context, suggested_action, time);
7107     }
7108   else
7109     {
7110       gdk_drag_status (context, 0, time);
7111       gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
7112     }
7113
7114   priv->dnd_device = gdk_drag_context_get_device (context);
7115
7116   if (!priv->scroll_timeout)
7117     priv->scroll_timeout =
7118       gdk_threads_add_timeout (100, drag_scan_timeout, text_view);
7119
7120   /* TRUE return means don't propagate the drag motion to parent
7121    * widgets that may also be drop sites.
7122    */
7123   return TRUE;
7124 }
7125
7126 static gboolean
7127 gtk_text_view_drag_drop (GtkWidget        *widget,
7128                          GdkDragContext   *context,
7129                          gint              x,
7130                          gint              y,
7131                          guint             time)
7132 {
7133   GtkTextView *text_view;
7134   GtkTextViewPrivate *priv;
7135   GtkTextIter drop_point;
7136   GdkAtom target = GDK_NONE;
7137
7138   text_view = GTK_TEXT_VIEW (widget);
7139   priv = text_view->priv;
7140
7141   if (priv->scroll_timeout != 0)
7142     g_source_remove (priv->scroll_timeout);
7143
7144   priv->scroll_timeout = 0;
7145
7146   gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
7147
7148   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7149                                     &drop_point,
7150                                     priv->dnd_mark);
7151
7152   if (gtk_text_iter_can_insert (&drop_point, priv->editable))
7153     target = gtk_drag_dest_find_target (widget, context, NULL);
7154
7155   if (target != GDK_NONE)
7156     gtk_drag_get_data (widget, context, target, time);
7157   else
7158     gtk_drag_finish (context, FALSE, FALSE, time);
7159
7160   return TRUE;
7161 }
7162
7163 static void
7164 insert_text_data (GtkTextView      *text_view,
7165                   GtkTextIter      *drop_point,
7166                   GtkSelectionData *selection_data)
7167 {
7168   guchar *str;
7169
7170   str = gtk_selection_data_get_text (selection_data);
7171
7172   if (str)
7173     {
7174       if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
7175                                                drop_point, (gchar *) str, -1,
7176                                                text_view->priv->editable))
7177         {
7178           gtk_widget_error_bell (GTK_WIDGET (text_view));
7179         }
7180
7181       g_free (str);
7182     }
7183 }
7184
7185 static void
7186 gtk_text_view_drag_data_received (GtkWidget        *widget,
7187                                   GdkDragContext   *context,
7188                                   gint              x,
7189                                   gint              y,
7190                                   GtkSelectionData *selection_data,
7191                                   guint             info,
7192                                   guint             time)
7193 {
7194   GtkTextIter drop_point;
7195   GtkTextView *text_view;
7196   GtkTextViewPrivate *priv;
7197   gboolean success = FALSE;
7198   GtkTextBuffer *buffer = NULL;
7199
7200   text_view = GTK_TEXT_VIEW (widget);
7201   priv = text_view->priv;
7202
7203   if (!priv->dnd_mark)
7204     goto done;
7205
7206   buffer = get_buffer (text_view);
7207
7208   gtk_text_buffer_get_iter_at_mark (buffer,
7209                                     &drop_point,
7210                                     priv->dnd_mark);
7211   
7212   if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
7213     goto done;
7214
7215   success = TRUE;
7216
7217   gtk_text_buffer_begin_user_action (buffer);
7218
7219   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
7220     {
7221       GtkTextBuffer *src_buffer = NULL;
7222       GtkTextIter start, end;
7223       gboolean copy_tags = TRUE;
7224
7225       if (gtk_selection_data_get_length (selection_data) != sizeof (src_buffer))
7226         return;
7227
7228       memcpy (&src_buffer, gtk_selection_data_get_data (selection_data), sizeof (src_buffer));
7229
7230       if (src_buffer == NULL)
7231         return;
7232
7233       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
7234
7235       if (gtk_text_buffer_get_tag_table (src_buffer) !=
7236           gtk_text_buffer_get_tag_table (buffer))
7237         {
7238           /*  try to find a suitable rich text target instead  */
7239           GdkAtom *atoms;
7240           gint     n_atoms;
7241           GList   *list;
7242           GdkAtom  target = GDK_NONE;
7243
7244           copy_tags = FALSE;
7245
7246           atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
7247
7248           for (list = gdk_drag_context_list_targets (context); list; list = g_list_next (list))
7249             {
7250               gint i;
7251
7252               for (i = 0; i < n_atoms; i++)
7253                 if (GUINT_TO_POINTER (atoms[i]) == list->data)
7254                   {
7255                     target = atoms[i];
7256                     break;
7257                   }
7258             }
7259
7260           g_free (atoms);
7261
7262           if (target != GDK_NONE)
7263             {
7264               gtk_drag_get_data (widget, context, target, time);
7265               gtk_text_buffer_end_user_action (buffer);
7266               return;
7267             }
7268         }
7269
7270       if (gtk_text_buffer_get_selection_bounds (src_buffer,
7271                                                 &start,
7272                                                 &end))
7273         {
7274           if (copy_tags)
7275             gtk_text_buffer_insert_range_interactive (buffer,
7276                                                       &drop_point,
7277                                                       &start,
7278                                                       &end,
7279                                                       priv->editable);
7280           else
7281             {
7282               gchar *str;
7283
7284               str = gtk_text_iter_get_visible_text (&start, &end);
7285               gtk_text_buffer_insert_interactive (buffer,
7286                                                   &drop_point, str, -1,
7287                                                   priv->editable);
7288               g_free (str);
7289             }
7290         }
7291     }
7292   else if (gtk_selection_data_get_length (selection_data) > 0 &&
7293            info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
7294     {
7295       gboolean retval;
7296       GError *error = NULL;
7297
7298       retval = gtk_text_buffer_deserialize (buffer, buffer,
7299                                             gtk_selection_data_get_target (selection_data),
7300                                             &drop_point,
7301                                             (guint8 *) gtk_selection_data_get_data (selection_data),
7302                                             gtk_selection_data_get_length (selection_data),
7303                                             &error);
7304
7305       if (!retval)
7306         {
7307           g_warning ("error pasting: %s\n", error->message);
7308           g_clear_error (&error);
7309         }
7310     }
7311   else
7312     insert_text_data (text_view, &drop_point, selection_data);
7313
7314  done:
7315   gtk_drag_finish (context, success,
7316                    success && gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE,
7317                    time);
7318
7319   if (success)
7320     {
7321       gtk_text_buffer_get_iter_at_mark (buffer,
7322                                         &drop_point,
7323                                         priv->dnd_mark);
7324       gtk_text_buffer_place_cursor (buffer, &drop_point);
7325
7326       gtk_text_buffer_end_user_action (buffer);
7327     }
7328 }
7329
7330 /**
7331  * gtk_text_view_get_hadjustment:
7332  * @text_view: a #GtkTextView
7333  *
7334  * Gets the horizontal-scrolling #GtkAdjustment.
7335  *
7336  * Returns: (transfer none): pointer to the horizontal #GtkAdjustment
7337  *
7338  * Since: 2.22
7339  *
7340  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
7341  **/
7342 GtkAdjustment*
7343 gtk_text_view_get_hadjustment (GtkTextView *text_view)
7344 {
7345   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7346
7347   return text_view->priv->hadjustment;
7348 }
7349
7350 static void
7351 gtk_text_view_set_hadjustment (GtkTextView   *text_view,
7352                                GtkAdjustment *adjustment)
7353 {
7354   GtkTextViewPrivate *priv = text_view->priv;
7355
7356   if (adjustment && priv->hadjustment == adjustment)
7357     return;
7358
7359   if (priv->hadjustment != NULL)
7360     {
7361       g_signal_handlers_disconnect_by_func (priv->hadjustment,
7362                                             gtk_text_view_value_changed,
7363                                             text_view);
7364       g_object_unref (priv->hadjustment);
7365     }
7366
7367   if (adjustment == NULL)
7368     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
7369
7370   g_signal_connect (adjustment, "value-changed",
7371                     G_CALLBACK (gtk_text_view_value_changed), text_view);
7372   priv->hadjustment = g_object_ref_sink (adjustment);
7373   gtk_text_view_set_hadjustment_values (text_view);
7374
7375   g_object_notify (G_OBJECT (text_view), "hadjustment");
7376 }
7377
7378 /**
7379  * gtk_text_view_get_vadjustment:
7380  * @text_view: a #GtkTextView
7381  *
7382  * Gets the vertical-scrolling #GtkAdjustment.
7383  *
7384  * Returns: (transfer none): pointer to the vertical #GtkAdjustment
7385  *
7386  * Since: 2.22
7387  *
7388  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
7389  **/
7390 GtkAdjustment*
7391 gtk_text_view_get_vadjustment (GtkTextView *text_view)
7392 {
7393   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7394
7395   return text_view->priv->vadjustment;
7396 }
7397
7398 static void
7399 gtk_text_view_set_vadjustment (GtkTextView   *text_view,
7400                                GtkAdjustment *adjustment)
7401 {
7402   GtkTextViewPrivate *priv = text_view->priv;
7403
7404   if (adjustment && priv->vadjustment == adjustment)
7405     return;
7406
7407   if (priv->vadjustment != NULL)
7408     {
7409       g_signal_handlers_disconnect_by_func (priv->vadjustment,
7410                                             gtk_text_view_value_changed,
7411                                             text_view);
7412       g_object_unref (priv->vadjustment);
7413     }
7414
7415   if (adjustment == NULL)
7416     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
7417
7418   g_signal_connect (adjustment, "value-changed",
7419                     G_CALLBACK (gtk_text_view_value_changed), text_view);
7420   priv->vadjustment = g_object_ref_sink (adjustment);
7421   gtk_text_view_set_vadjustment_values (text_view);
7422
7423   g_object_notify (G_OBJECT (text_view), "vadjustment");
7424 }
7425
7426 static void
7427 gtk_text_view_set_hadjustment_values (GtkTextView *text_view)
7428 {
7429   GtkTextViewPrivate *priv;
7430   gint screen_width;
7431   gdouble old_value;
7432   gdouble new_value;
7433   gdouble new_upper;
7434
7435   priv = text_view->priv;
7436
7437   screen_width = SCREEN_WIDTH (text_view);
7438   old_value = gtk_adjustment_get_value (priv->hadjustment);
7439   new_upper = MAX (screen_width, priv->width);
7440
7441   g_object_set (priv->hadjustment,
7442                 "lower", 0.0,
7443                 "upper", new_upper,
7444                 "page-size", (gdouble)screen_width,
7445                 "step-increment", screen_width * 0.1,
7446                 "page-increment", screen_width * 0.9,
7447                 NULL);
7448
7449   new_value = CLAMP (old_value, 0, new_upper - screen_width);
7450   if (new_value != old_value)
7451     gtk_adjustment_set_value (priv->hadjustment, new_value);
7452 }
7453
7454 static void
7455 gtk_text_view_set_vadjustment_values (GtkTextView *text_view)
7456 {
7457   GtkTextViewPrivate *priv;
7458   GtkTextIter first_para;
7459   gint screen_height;
7460   gint y;
7461   gdouble old_value;
7462   gdouble new_value;
7463   gdouble new_upper;
7464
7465   priv = text_view->priv;
7466
7467   screen_height = SCREEN_HEIGHT (text_view);
7468   old_value = gtk_adjustment_get_value (priv->vadjustment);
7469   new_upper = MAX (screen_height, priv->height);
7470
7471   g_object_set (priv->vadjustment,
7472                 "lower", 0.0,
7473                 "upper", new_upper,
7474                 "page-size", (gdouble)screen_height,
7475                 "step-increment", screen_height * 0.1,
7476                 "page-increment", screen_height * 0.9,
7477                 NULL);
7478
7479   /* Now adjust the value of the adjustment to keep the cursor at the
7480    * same place in the buffer */
7481   gtk_text_view_ensure_layout (text_view);
7482   gtk_text_view_get_first_para_iter (text_view, &first_para);
7483   gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
7484
7485   y += priv->first_para_pixels;
7486
7487   new_value = CLAMP (y, 0, new_upper - screen_height);
7488   if (new_value != old_value)
7489     gtk_adjustment_set_value (priv->vadjustment, new_value);
7490  }
7491
7492
7493 /* FIXME this adjust_allocation is a big cut-and-paste from
7494  * GtkCList, needs to be some "official" way to do this
7495  * factored out.
7496  */
7497 typedef struct
7498 {
7499   GdkWindow *window;
7500   int dx;
7501   int dy;
7502 } ScrollData;
7503
7504 /* The window to which widget->window is relative */
7505 #define ALLOCATION_WINDOW(widget)               \
7506    (!gtk_widget_get_has_window (widget) ?                   \
7507     gtk_widget_get_window (widget) :                        \
7508     gdk_window_get_parent (gtk_widget_get_window (widget)))
7509
7510 static void
7511 adjust_allocation_recurse (GtkWidget *widget,
7512                            gpointer   data)
7513 {
7514   GtkAllocation allocation;
7515   ScrollData *scroll_data = data;
7516
7517   /* Need to really size allocate instead of just poking
7518    * into widget->allocation if the widget is not realized.
7519    * FIXME someone figure out why this was.
7520    */
7521   gtk_widget_get_allocation (widget, &allocation);
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       gtk_widget_set_sensitive (menuitem,
8254                                 gtk_text_buffer_get_char_count (priv->buffer) > 0);
8255       g_signal_connect (menuitem, "activate",
8256                         G_CALLBACK (select_all_cb), text_view);
8257       gtk_widget_show (menuitem);
8258       gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8259
8260       g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
8261                     "gtk-show-input-method-menu", &show_input_method_menu,
8262                     "gtk-show-unicode-menu", &show_unicode_menu,
8263                     NULL);
8264       
8265       if (show_input_method_menu || show_unicode_menu)
8266         {
8267           menuitem = gtk_separator_menu_item_new ();
8268           gtk_widget_show (menuitem);
8269           gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8270         }
8271
8272       if (show_input_method_menu)
8273         {
8274           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
8275           gtk_widget_show (menuitem);
8276           gtk_widget_set_sensitive (menuitem, can_insert);
8277
8278           submenu = gtk_menu_new ();
8279           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8280           gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8281           
8282           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (priv->im_context),
8283                                                 GTK_MENU_SHELL (submenu));
8284         }
8285
8286       if (show_unicode_menu)
8287         {
8288           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
8289           gtk_widget_show (menuitem);
8290           gtk_widget_set_sensitive (menuitem, can_insert);
8291       
8292           submenu = gtk_menu_new ();
8293           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8294           gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8295           
8296           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
8297                                                         unichar_chosen_func,
8298                                                         text_view);
8299         }
8300           
8301       g_signal_emit (text_view,
8302                      signals[POPULATE_POPUP],
8303                      0,
8304                      priv->popup_menu);
8305       
8306       if (info->button)
8307         gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
8308                         NULL, NULL,
8309                         info->button, info->time);
8310       else
8311         {
8312           gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
8313                           popup_position_func, text_view,
8314                           0, gtk_get_current_event_time ());
8315           gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
8316         }
8317     }
8318
8319   g_object_unref (text_view);
8320   g_free (info);
8321 }
8322
8323 static void
8324 gtk_text_view_do_popup (GtkTextView    *text_view,
8325                         GdkEventButton *event)
8326 {
8327   PopupInfo *info = g_new (PopupInfo, 1);
8328
8329   /* In order to know what entries we should make sensitive, we
8330    * ask for the current targets of the clipboard, and when
8331    * we get them, then we actually pop up the menu.
8332    */
8333   info->text_view = g_object_ref (text_view);
8334   
8335   if (event)
8336     {
8337       info->button = event->button;
8338       info->time = event->time;
8339     }
8340   else
8341     {
8342       info->button = 0;
8343       info->time = gtk_get_current_event_time ();
8344     }
8345
8346   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
8347                                                             GDK_SELECTION_CLIPBOARD),
8348                                   gdk_atom_intern_static_string ("TARGETS"),
8349                                   popup_targets_received,
8350                                   info);
8351 }
8352
8353 static gboolean
8354 gtk_text_view_popup_menu (GtkWidget *widget)
8355 {
8356   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
8357   return TRUE;
8358 }
8359
8360 /* Child GdkWindows */
8361
8362
8363 static GtkTextWindow*
8364 text_window_new (GtkTextWindowType  type,
8365                  GtkWidget         *widget,
8366                  gint               width_request,
8367                  gint               height_request)
8368 {
8369   GtkTextWindow *win;
8370
8371   win = g_new (GtkTextWindow, 1);
8372
8373   win->type = type;
8374   win->widget = widget;
8375   win->window = NULL;
8376   win->bin_window = NULL;
8377   win->requisition.width = width_request;
8378   win->requisition.height = height_request;
8379   win->allocation.width = width_request;
8380   win->allocation.height = height_request;
8381   win->allocation.x = 0;
8382   win->allocation.y = 0;
8383
8384   return win;
8385 }
8386
8387 static void
8388 text_window_free (GtkTextWindow *win)
8389 {
8390   if (win->window)
8391     text_window_unrealize (win);
8392
8393   g_free (win);
8394 }
8395
8396 static void
8397 text_window_realize (GtkTextWindow *win,
8398                      GtkWidget     *widget)
8399 {
8400   GtkStyleContext *context;
8401   GtkStateFlags state;
8402   GdkWindow *window;
8403   GdkWindowAttr attributes;
8404   gint attributes_mask;
8405   GdkCursor *cursor;
8406   GdkRGBA color;
8407
8408   attributes.window_type = GDK_WINDOW_CHILD;
8409   attributes.x = win->allocation.x;
8410   attributes.y = win->allocation.y;
8411   attributes.width = win->allocation.width;
8412   attributes.height = win->allocation.height;
8413   attributes.wclass = GDK_INPUT_OUTPUT;
8414   attributes.visual = gtk_widget_get_visual (win->widget);
8415   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
8416
8417   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
8418
8419   window = gtk_widget_get_window (widget);
8420
8421   win->window = gdk_window_new (window,
8422                                 &attributes, attributes_mask);
8423
8424   gdk_window_show (win->window);
8425   gdk_window_set_user_data (win->window, win->widget);
8426   gdk_window_lower (win->window);
8427
8428   attributes.x = 0;
8429   attributes.y = 0;
8430   attributes.width = win->allocation.width;
8431   attributes.height = win->allocation.height;
8432   attributes.event_mask = (GDK_EXPOSURE_MASK            |
8433                            GDK_SCROLL_MASK              |
8434                            GDK_KEY_PRESS_MASK           |
8435                            GDK_BUTTON_PRESS_MASK        |
8436                            GDK_BUTTON_RELEASE_MASK      |
8437                            GDK_POINTER_MOTION_MASK      |
8438                            GDK_POINTER_MOTION_HINT_MASK |
8439                            gtk_widget_get_events (win->widget));
8440
8441   win->bin_window = gdk_window_new (win->window,
8442                                     &attributes,
8443                                     attributes_mask);
8444
8445   gdk_window_show (win->bin_window);
8446   gdk_window_set_user_data (win->bin_window, win->widget);
8447
8448   context = gtk_widget_get_style_context (widget);
8449   state = gtk_widget_get_state_flags (widget);
8450
8451   if (win->type == GTK_TEXT_WINDOW_TEXT)
8452     {
8453       if (gtk_widget_is_sensitive (widget))
8454         {
8455           /* I-beam cursor */
8456           cursor = gdk_cursor_new_for_display (gdk_window_get_display (window),
8457                                                GDK_XTERM);
8458           gdk_window_set_cursor (win->bin_window, cursor);
8459           g_object_unref (cursor);
8460         } 
8461
8462       gtk_im_context_set_client_window (GTK_TEXT_VIEW (widget)->priv->im_context,
8463                                         win->window);
8464
8465       gtk_style_context_save (context);
8466       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8467
8468       gtk_style_context_get_background_color (context, state, &color);
8469       gdk_window_set_background_rgba (win->bin_window, &color);
8470
8471       gtk_style_context_restore (context);
8472     }
8473   else
8474     {
8475       gtk_style_context_get_background_color (context, state, &color);
8476       gdk_window_set_background_rgba (win->bin_window, &color);
8477     }
8478
8479   g_object_set_qdata (G_OBJECT (win->window),
8480                       g_quark_from_static_string ("gtk-text-view-text-window"),
8481                       win);
8482
8483   g_object_set_qdata (G_OBJECT (win->bin_window),
8484                       g_quark_from_static_string ("gtk-text-view-text-window"),
8485                       win);
8486 }
8487
8488 static void
8489 text_window_unrealize (GtkTextWindow *win)
8490 {
8491   if (win->type == GTK_TEXT_WINDOW_TEXT)
8492     {
8493       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->priv->im_context,
8494                                         NULL);
8495     }
8496
8497   gdk_window_set_user_data (win->window, NULL);
8498   gdk_window_set_user_data (win->bin_window, NULL);
8499   gdk_window_destroy (win->bin_window);
8500   gdk_window_destroy (win->window);
8501   win->window = NULL;
8502   win->bin_window = NULL;
8503 }
8504
8505 static void
8506 text_window_size_allocate (GtkTextWindow *win,
8507                            GdkRectangle  *rect)
8508 {
8509   win->allocation = *rect;
8510
8511   if (win->window)
8512     {
8513       gdk_window_move_resize (win->window,
8514                               rect->x, rect->y,
8515                               rect->width, rect->height);
8516
8517       gdk_window_resize (win->bin_window,
8518                          rect->width, rect->height);
8519     }
8520 }
8521
8522 static void
8523 text_window_scroll        (GtkTextWindow *win,
8524                            gint           dx,
8525                            gint           dy)
8526 {
8527   if (dx != 0 || dy != 0)
8528     {
8529       gdk_window_scroll (win->bin_window, dx, dy);
8530     }
8531 }
8532
8533 static void
8534 text_window_invalidate_rect (GtkTextWindow *win,
8535                              GdkRectangle  *rect)
8536 {
8537   GdkRectangle window_rect;
8538
8539   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
8540                                          win->type,
8541                                          rect->x,
8542                                          rect->y,
8543                                          &window_rect.x,
8544                                          &window_rect.y);
8545
8546   window_rect.width = rect->width;
8547   window_rect.height = rect->height;
8548   
8549   /* Adjust the rect as appropriate */
8550   
8551   switch (win->type)
8552     {
8553     case GTK_TEXT_WINDOW_TEXT:
8554       break;
8555
8556     case GTK_TEXT_WINDOW_LEFT:
8557     case GTK_TEXT_WINDOW_RIGHT:
8558       window_rect.x = 0;
8559       window_rect.width = win->allocation.width;
8560       break;
8561
8562     case GTK_TEXT_WINDOW_TOP:
8563     case GTK_TEXT_WINDOW_BOTTOM:
8564       window_rect.y = 0;
8565       window_rect.height = win->allocation.height;
8566       break;
8567
8568     default:
8569       g_warning ("%s: bug!", G_STRFUNC);
8570       return;
8571       break;
8572     }
8573           
8574   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
8575
8576 #if 0
8577   {
8578     cairo_t *cr = gdk_cairo_create (win->bin_window);
8579     gdk_cairo_rectangle (cr, &window_rect);
8580     cairo_set_source_rgb  (cr, 1.0, 0.0, 0.0);  /* red */
8581     cairo_fill (cr);
8582     cairo_destroy (cr);
8583   }
8584 #endif
8585 }
8586
8587 static void
8588 text_window_invalidate_cursors (GtkTextWindow *win)
8589 {
8590   GtkTextView *text_view;
8591   GtkTextViewPrivate *priv;
8592   GtkTextIter  iter;
8593   GdkRectangle strong;
8594   GdkRectangle weak;
8595   gboolean     draw_arrow;
8596   gfloat       cursor_aspect_ratio;
8597   gint         stem_width;
8598   gint         arrow_width;
8599
8600   text_view = GTK_TEXT_VIEW (win->widget);
8601   priv = text_view->priv;
8602
8603   gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
8604                                     gtk_text_buffer_get_insert (priv->buffer));
8605
8606   if (_gtk_text_layout_get_block_cursor (priv->layout, &strong))
8607     {
8608       text_window_invalidate_rect (win, &strong);
8609       return;
8610     }
8611
8612   gtk_text_layout_get_cursor_locations (priv->layout, &iter,
8613                                         &strong, &weak);
8614
8615   /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
8616    * ignoring the text direction be exposing both sides of the cursor
8617    */
8618
8619   draw_arrow = (strong.x != weak.x || strong.y != weak.y);
8620
8621   gtk_widget_style_get (win->widget,
8622                         "cursor-aspect-ratio", &cursor_aspect_ratio,
8623                         NULL);
8624   
8625   stem_width = strong.height * cursor_aspect_ratio + 1;
8626   arrow_width = stem_width + 1;
8627
8628   strong.width = stem_width;
8629
8630   /* round up to the next even number */
8631   if (stem_width & 1)
8632     stem_width++;
8633
8634   strong.x     -= stem_width / 2;
8635   strong.width += stem_width;
8636
8637   if (draw_arrow)
8638     {
8639       strong.x     -= arrow_width;
8640       strong.width += arrow_width * 2;
8641     }
8642
8643   text_window_invalidate_rect (win, &strong);
8644
8645   if (draw_arrow) /* == have weak */
8646     {
8647       stem_width = weak.height * cursor_aspect_ratio + 1;
8648       arrow_width = stem_width + 1;
8649
8650       weak.width = stem_width;
8651
8652       /* round up to the next even number */
8653       if (stem_width & 1)
8654         stem_width++;
8655
8656       weak.x     -= stem_width / 2;
8657       weak.width += stem_width;
8658
8659       weak.x     -= arrow_width;
8660       weak.width += arrow_width * 2;
8661
8662       text_window_invalidate_rect (win, &weak);
8663     }
8664 }
8665
8666 static gint
8667 text_window_get_width (GtkTextWindow *win)
8668 {
8669   return win->allocation.width;
8670 }
8671
8672 static gint
8673 text_window_get_height (GtkTextWindow *win)
8674 {
8675   return win->allocation.height;
8676 }
8677
8678 /* Windows */
8679
8680
8681 /**
8682  * gtk_text_view_get_window:
8683  * @text_view: a #GtkTextView
8684  * @win: window to get
8685  *
8686  * Retrieves the #GdkWindow corresponding to an area of the text view;
8687  * possible windows include the overall widget window, child windows
8688  * on the left, right, top, bottom, and the window that displays the
8689  * text buffer. Windows are %NULL and nonexistent if their width or
8690  * height is 0, and are nonexistent before the widget has been
8691  * realized.
8692  *
8693  * Return value: (transfer none): a #GdkWindow, or %NULL
8694  **/
8695 GdkWindow*
8696 gtk_text_view_get_window (GtkTextView *text_view,
8697                           GtkTextWindowType win)
8698 {
8699   GtkTextViewPrivate *priv = text_view->priv;
8700
8701   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
8702
8703   switch (win)
8704     {
8705     case GTK_TEXT_WINDOW_WIDGET:
8706       return gtk_widget_get_window (GTK_WIDGET (text_view));
8707       break;
8708
8709     case GTK_TEXT_WINDOW_TEXT:
8710       return priv->text_window->bin_window;
8711       break;
8712
8713     case GTK_TEXT_WINDOW_LEFT:
8714       if (priv->left_window)
8715         return priv->left_window->bin_window;
8716       else
8717         return NULL;
8718       break;
8719
8720     case GTK_TEXT_WINDOW_RIGHT:
8721       if (priv->right_window)
8722         return priv->right_window->bin_window;
8723       else
8724         return NULL;
8725       break;
8726
8727     case GTK_TEXT_WINDOW_TOP:
8728       if (priv->top_window)
8729         return priv->top_window->bin_window;
8730       else
8731         return NULL;
8732       break;
8733
8734     case GTK_TEXT_WINDOW_BOTTOM:
8735       if (priv->bottom_window)
8736         return priv->bottom_window->bin_window;
8737       else
8738         return NULL;
8739       break;
8740
8741     case GTK_TEXT_WINDOW_PRIVATE:
8742       g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_STRFUNC);
8743       return NULL;
8744       break;
8745     }
8746
8747   g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8748   return NULL;
8749 }
8750
8751 /**
8752  * gtk_text_view_get_window_type:
8753  * @text_view: a #GtkTextView
8754  * @window: a window type
8755  *
8756  * Usually used to find out which window an event corresponds to.
8757  * If you connect to an event signal on @text_view, this function
8758  * should be called on <literal>event-&gt;window</literal> to
8759  * see which window it was.
8760  *
8761  * Return value: the window type.
8762  **/
8763 GtkTextWindowType
8764 gtk_text_view_get_window_type (GtkTextView *text_view,
8765                                GdkWindow   *window)
8766 {
8767   GtkTextWindow *win;
8768
8769   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8770   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
8771
8772   if (window == gtk_widget_get_window (GTK_WIDGET (text_view)))
8773     return GTK_TEXT_WINDOW_WIDGET;
8774
8775   win = g_object_get_qdata (G_OBJECT (window),
8776                             g_quark_try_string ("gtk-text-view-text-window"));
8777
8778   if (win)
8779     return win->type;
8780   else
8781     {
8782       return GTK_TEXT_WINDOW_PRIVATE;
8783     }
8784 }
8785
8786 static void
8787 buffer_to_widget (GtkTextView      *text_view,
8788                   gint              buffer_x,
8789                   gint              buffer_y,
8790                   gint             *window_x,
8791                   gint             *window_y)
8792 {
8793   GtkTextViewPrivate *priv = text_view->priv;
8794
8795   if (window_x)
8796     {
8797       *window_x = buffer_x - priv->xoffset;
8798       *window_x += priv->text_window->allocation.x;
8799     }
8800
8801   if (window_y)
8802     {
8803       *window_y = buffer_y - priv->yoffset;
8804       *window_y += priv->text_window->allocation.y;
8805     }
8806 }
8807
8808 static void
8809 widget_to_text_window (GtkTextWindow *win,
8810                        gint           widget_x,
8811                        gint           widget_y,
8812                        gint          *window_x,
8813                        gint          *window_y)
8814 {
8815   if (window_x)
8816     *window_x = widget_x - win->allocation.x;
8817
8818   if (window_y)
8819     *window_y = widget_y - win->allocation.y;
8820 }
8821
8822 static void
8823 buffer_to_text_window (GtkTextView   *text_view,
8824                        GtkTextWindow *win,
8825                        gint           buffer_x,
8826                        gint           buffer_y,
8827                        gint          *window_x,
8828                        gint          *window_y)
8829 {
8830   if (win == NULL)
8831     {
8832       g_warning ("Attempt to convert text buffer coordinates to coordinates "
8833                  "for a nonexistent or private child window of GtkTextView");
8834       return;
8835     }
8836
8837   buffer_to_widget (text_view,
8838                     buffer_x, buffer_y,
8839                     window_x, window_y);
8840
8841   widget_to_text_window (win,
8842                          window_x ? *window_x : 0,
8843                          window_y ? *window_y : 0,
8844                          window_x,
8845                          window_y);
8846 }
8847
8848 /**
8849  * gtk_text_view_buffer_to_window_coords:
8850  * @text_view: a #GtkTextView
8851  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8852  * @buffer_x: buffer x coordinate
8853  * @buffer_y: buffer y coordinate
8854  * @window_x: (out) (allow-none): window x coordinate return location or %NULL
8855  * @window_y: (out) (allow-none): window y coordinate return location or %NULL
8856  *
8857  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
8858  * @win, and stores the result in (@window_x, @window_y). 
8859  *
8860  * Note that you can't convert coordinates for a nonexisting window (see 
8861  * gtk_text_view_set_border_window_size()).
8862  **/
8863 void
8864 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
8865                                        GtkTextWindowType win,
8866                                        gint              buffer_x,
8867                                        gint              buffer_y,
8868                                        gint             *window_x,
8869                                        gint             *window_y)
8870 {
8871   GtkTextViewPrivate *priv = text_view->priv;
8872
8873   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8874
8875   switch (win)
8876     {
8877     case GTK_TEXT_WINDOW_WIDGET:
8878       buffer_to_widget (text_view,
8879                         buffer_x, buffer_y,
8880                         window_x, window_y);
8881       break;
8882
8883     case GTK_TEXT_WINDOW_TEXT:
8884       if (window_x)
8885         *window_x = buffer_x - priv->xoffset;
8886       if (window_y)
8887         *window_y = buffer_y - priv->yoffset;
8888       break;
8889
8890     case GTK_TEXT_WINDOW_LEFT:
8891       buffer_to_text_window (text_view,
8892                              priv->left_window,
8893                              buffer_x, buffer_y,
8894                              window_x, window_y);
8895       break;
8896
8897     case GTK_TEXT_WINDOW_RIGHT:
8898       buffer_to_text_window (text_view,
8899                              priv->right_window,
8900                              buffer_x, buffer_y,
8901                              window_x, window_y);
8902       break;
8903
8904     case GTK_TEXT_WINDOW_TOP:
8905       buffer_to_text_window (text_view,
8906                              priv->top_window,
8907                              buffer_x, buffer_y,
8908                              window_x, window_y);
8909       break;
8910
8911     case GTK_TEXT_WINDOW_BOTTOM:
8912       buffer_to_text_window (text_view,
8913                              priv->bottom_window,
8914                              buffer_x, buffer_y,
8915                              window_x, window_y);
8916       break;
8917
8918     case GTK_TEXT_WINDOW_PRIVATE:
8919       g_warning ("%s: can't get coords for private windows", G_STRFUNC);
8920       break;
8921
8922     default:
8923       g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8924       break;
8925     }
8926 }
8927
8928 static void
8929 widget_to_buffer (GtkTextView *text_view,
8930                   gint         widget_x,
8931                   gint         widget_y,
8932                   gint        *buffer_x,
8933                   gint        *buffer_y)
8934 {
8935   GtkTextViewPrivate *priv = text_view->priv;
8936
8937   if (buffer_x)
8938     {
8939       *buffer_x = widget_x + priv->xoffset;
8940       *buffer_x -= priv->text_window->allocation.x;
8941     }
8942
8943   if (buffer_y)
8944     {
8945       *buffer_y = widget_y + priv->yoffset;
8946       *buffer_y -= priv->text_window->allocation.y;
8947     }
8948 }
8949
8950 static void
8951 text_window_to_widget (GtkTextWindow *win,
8952                        gint           window_x,
8953                        gint           window_y,
8954                        gint          *widget_x,
8955                        gint          *widget_y)
8956 {
8957   if (widget_x)
8958     *widget_x = window_x + win->allocation.x;
8959
8960   if (widget_y)
8961     *widget_y = window_y + win->allocation.y;
8962 }
8963
8964 static void
8965 text_window_to_buffer (GtkTextView   *text_view,
8966                        GtkTextWindow *win,
8967                        gint           window_x,
8968                        gint           window_y,
8969                        gint          *buffer_x,
8970                        gint          *buffer_y)
8971 {
8972   if (win == NULL)
8973     {
8974       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
8975                  "coordinates for a nonexistent child window.");
8976       return;
8977     }
8978
8979   text_window_to_widget (win,
8980                          window_x,
8981                          window_y,
8982                          buffer_x,
8983                          buffer_y);
8984
8985   widget_to_buffer (text_view,
8986                     buffer_x ? *buffer_x : 0,
8987                     buffer_y ? *buffer_y : 0,
8988                     buffer_x,
8989                     buffer_y);
8990 }
8991
8992 /**
8993  * gtk_text_view_window_to_buffer_coords:
8994  * @text_view: a #GtkTextView
8995  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8996  * @window_x: window x coordinate
8997  * @window_y: window y coordinate
8998  * @buffer_x: (out) (allow-none): buffer x coordinate return location or %NULL
8999  * @buffer_y: (out) (allow-none): buffer y coordinate return location or %NULL
9000  *
9001  * Converts coordinates on the window identified by @win to buffer
9002  * coordinates, storing the result in (@buffer_x,@buffer_y).
9003  *
9004  * Note that you can't convert coordinates for a nonexisting window (see 
9005  * gtk_text_view_set_border_window_size()).
9006  **/
9007 void
9008 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
9009                                        GtkTextWindowType win,
9010                                        gint              window_x,
9011                                        gint              window_y,
9012                                        gint             *buffer_x,
9013                                        gint             *buffer_y)
9014 {
9015   GtkTextViewPrivate *priv = text_view->priv;
9016
9017   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9018
9019   switch (win)
9020     {
9021     case GTK_TEXT_WINDOW_WIDGET:
9022       widget_to_buffer (text_view,
9023                         window_x, window_y,
9024                         buffer_x, buffer_y);
9025       break;
9026
9027     case GTK_TEXT_WINDOW_TEXT:
9028       if (buffer_x)
9029         *buffer_x = window_x + priv->xoffset;
9030       if (buffer_y)
9031         *buffer_y = window_y + priv->yoffset;
9032       break;
9033
9034     case GTK_TEXT_WINDOW_LEFT:
9035       text_window_to_buffer (text_view,
9036                              priv->left_window,
9037                              window_x, window_y,
9038                              buffer_x, buffer_y);
9039       break;
9040
9041     case GTK_TEXT_WINDOW_RIGHT:
9042       text_window_to_buffer (text_view,
9043                              priv->right_window,
9044                              window_x, window_y,
9045                              buffer_x, buffer_y);
9046       break;
9047
9048     case GTK_TEXT_WINDOW_TOP:
9049       text_window_to_buffer (text_view,
9050                              priv->top_window,
9051                              window_x, window_y,
9052                              buffer_x, buffer_y);
9053       break;
9054
9055     case GTK_TEXT_WINDOW_BOTTOM:
9056       text_window_to_buffer (text_view,
9057                              priv->bottom_window,
9058                              window_x, window_y,
9059                              buffer_x, buffer_y);
9060       break;
9061
9062     case GTK_TEXT_WINDOW_PRIVATE:
9063       g_warning ("%s: can't get coords for private windows", G_STRFUNC);
9064       break;
9065
9066     default:
9067       g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
9068       break;
9069     }
9070 }
9071
9072 static void
9073 set_window_width (GtkTextView      *text_view,
9074                   gint              width,
9075                   GtkTextWindowType type,
9076                   GtkTextWindow   **winp)
9077 {
9078   if (width == 0)
9079     {
9080       if (*winp)
9081         {
9082           text_window_free (*winp);
9083           *winp = NULL;
9084           gtk_widget_queue_resize (GTK_WIDGET (text_view));
9085         }
9086     }
9087   else
9088     {
9089       if (*winp == NULL)
9090         {
9091           *winp = text_window_new (type,
9092                                    GTK_WIDGET (text_view),
9093                                    width, 0);
9094           /* if the widget is already realized we need to realize the child manually */
9095           if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9096             text_window_realize (*winp, GTK_WIDGET (text_view));
9097         }
9098       else
9099         {
9100           if ((*winp)->requisition.width == width)
9101             return;
9102
9103           (*winp)->requisition.width = width;
9104         }
9105
9106       gtk_widget_queue_resize (GTK_WIDGET (text_view));
9107     }
9108 }
9109
9110
9111 static void
9112 set_window_height (GtkTextView      *text_view,
9113                    gint              height,
9114                    GtkTextWindowType type,
9115                    GtkTextWindow   **winp)
9116 {
9117   if (height == 0)
9118     {
9119       if (*winp)
9120         {
9121           text_window_free (*winp);
9122           *winp = NULL;
9123           gtk_widget_queue_resize (GTK_WIDGET (text_view));
9124         }
9125     }
9126   else
9127     {
9128       if (*winp == NULL)
9129         {
9130           *winp = text_window_new (type,
9131                                    GTK_WIDGET (text_view),
9132                                    0, height);
9133
9134           /* if the widget is already realized we need to realize the child manually */
9135           if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9136             text_window_realize (*winp, GTK_WIDGET (text_view));
9137         }
9138       else
9139         {
9140           if ((*winp)->requisition.height == height)
9141             return;
9142
9143           (*winp)->requisition.height = height;
9144         }
9145
9146       gtk_widget_queue_resize (GTK_WIDGET (text_view));
9147     }
9148 }
9149
9150 /**
9151  * gtk_text_view_set_border_window_size:
9152  * @text_view: a #GtkTextView
9153  * @type: window to affect
9154  * @size: width or height of the window
9155  *
9156  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
9157  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
9158  * Automatically destroys the corresponding window if the size is set
9159  * to 0, and creates the window if the size is set to non-zero.  This
9160  * function can only be used for the "border windows," it doesn't work
9161  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
9162  * #GTK_TEXT_WINDOW_PRIVATE.
9163  **/
9164 void
9165 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
9166                                       GtkTextWindowType type,
9167                                       gint              size)
9168 {
9169   GtkTextViewPrivate *priv = text_view->priv;
9170
9171   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9172   g_return_if_fail (size >= 0);
9173
9174   switch (type)
9175     {
9176     case GTK_TEXT_WINDOW_LEFT:
9177       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
9178                         &priv->left_window);
9179       break;
9180
9181     case GTK_TEXT_WINDOW_RIGHT:
9182       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
9183                         &priv->right_window);
9184       break;
9185
9186     case GTK_TEXT_WINDOW_TOP:
9187       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
9188                          &priv->top_window);
9189       break;
9190
9191     case GTK_TEXT_WINDOW_BOTTOM:
9192       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
9193                          &priv->bottom_window);
9194       break;
9195
9196     default:
9197       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
9198       break;
9199     }
9200 }
9201
9202 /**
9203  * gtk_text_view_get_border_window_size:
9204  * @text_view: a #GtkTextView
9205  * @type: window to return size from
9206  *
9207  * Gets the width of the specified border window. See
9208  * gtk_text_view_set_border_window_size().
9209  *
9210  * Return value: width of window
9211  **/
9212 gint
9213 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
9214                                       GtkTextWindowType  type)
9215 {
9216   GtkTextViewPrivate *priv = text_view->priv;
9217
9218   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
9219   
9220   switch (type)
9221     {
9222     case GTK_TEXT_WINDOW_LEFT:
9223       if (priv->left_window)
9224         return priv->left_window->requisition.width;
9225       break;
9226       
9227     case GTK_TEXT_WINDOW_RIGHT:
9228       if (priv->right_window)
9229         return priv->right_window->requisition.width;
9230       break;
9231       
9232     case GTK_TEXT_WINDOW_TOP:
9233       if (priv->top_window)
9234         return priv->top_window->requisition.height;
9235       break;
9236
9237     case GTK_TEXT_WINDOW_BOTTOM:
9238       if (priv->bottom_window)
9239         return priv->bottom_window->requisition.height;
9240       break;
9241       
9242     default:
9243       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
9244       break;
9245     }
9246
9247   return 0;
9248 }
9249
9250 /*
9251  * Child widgets
9252  */
9253
9254 static GtkTextViewChild*
9255 text_view_child_new_anchored (GtkWidget          *child,
9256                               GtkTextChildAnchor *anchor,
9257                               GtkTextLayout      *layout)
9258 {
9259   GtkTextViewChild *vc;
9260
9261   vc = g_new (GtkTextViewChild, 1);
9262
9263   vc->type = GTK_TEXT_WINDOW_PRIVATE;
9264   vc->widget = child;
9265   vc->anchor = anchor;
9266
9267   vc->from_top_of_line = 0;
9268   vc->from_left_of_buffer = 0;
9269   
9270   g_object_ref (vc->widget);
9271   g_object_ref (vc->anchor);
9272
9273   g_object_set_data (G_OBJECT (child),
9274                      I_("gtk-text-view-child"),
9275                      vc);
9276
9277   gtk_text_child_anchor_register_child (anchor, child, layout);
9278   
9279   return vc;
9280 }
9281
9282 static GtkTextViewChild*
9283 text_view_child_new_window (GtkWidget          *child,
9284                             GtkTextWindowType   type,
9285                             gint                x,
9286                             gint                y)
9287 {
9288   GtkTextViewChild *vc;
9289
9290   vc = g_new (GtkTextViewChild, 1);
9291
9292   vc->widget = child;
9293   vc->anchor = NULL;
9294
9295   vc->from_top_of_line = 0;
9296   vc->from_left_of_buffer = 0;
9297  
9298   g_object_ref (vc->widget);
9299
9300   vc->type = type;
9301   vc->x = x;
9302   vc->y = y;
9303
9304   g_object_set_data (G_OBJECT (child),
9305                      I_("gtk-text-view-child"),
9306                      vc);
9307   
9308   return vc;
9309 }
9310
9311 static void
9312 text_view_child_free (GtkTextViewChild *child)
9313 {
9314   g_object_set_data (G_OBJECT (child->widget),
9315                      I_("gtk-text-view-child"), NULL);
9316
9317   if (child->anchor)
9318     {
9319       gtk_text_child_anchor_unregister_child (child->anchor,
9320                                               child->widget);
9321       g_object_unref (child->anchor);
9322     }
9323
9324   g_object_unref (child->widget);
9325
9326   g_free (child);
9327 }
9328
9329 static void
9330 text_view_child_set_parent_window (GtkTextView      *text_view,
9331                                    GtkTextViewChild *vc)
9332 {
9333   if (vc->anchor)
9334     gtk_widget_set_parent_window (vc->widget,
9335                                   text_view->priv->text_window->bin_window);
9336   else
9337     {
9338       GdkWindow *window;
9339       window = gtk_text_view_get_window (text_view,
9340                                          vc->type);
9341       gtk_widget_set_parent_window (vc->widget, window);
9342     }
9343 }
9344
9345 static void
9346 add_child (GtkTextView      *text_view,
9347            GtkTextViewChild *vc)
9348 {
9349   text_view->priv->children = g_slist_prepend (text_view->priv->children,
9350                                                vc);
9351
9352   if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9353     text_view_child_set_parent_window (text_view, vc);
9354   
9355   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
9356 }
9357
9358 /**
9359  * gtk_text_view_add_child_at_anchor:
9360  * @text_view: a #GtkTextView
9361  * @child: a #GtkWidget
9362  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
9363  * 
9364  * Adds a child widget in the text buffer, at the given @anchor.
9365  **/
9366 void
9367 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
9368                                    GtkWidget            *child,
9369                                    GtkTextChildAnchor   *anchor)
9370 {
9371   GtkTextViewChild *vc;
9372
9373   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9374   g_return_if_fail (GTK_IS_WIDGET (child));
9375   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
9376   g_return_if_fail (gtk_widget_get_parent (child) == NULL);
9377
9378   gtk_text_view_ensure_layout (text_view);
9379
9380   vc = text_view_child_new_anchored (child, anchor,
9381                                      text_view->priv->layout);
9382
9383   add_child (text_view, vc);
9384
9385   g_assert (vc->widget == child);
9386   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9387 }
9388
9389 /**
9390  * gtk_text_view_add_child_in_window:
9391  * @text_view: a #GtkTextView
9392  * @child: a #GtkWidget
9393  * @which_window: which window the child should appear in
9394  * @xpos: X position of child in window coordinates
9395  * @ypos: Y position of child in window coordinates
9396  *
9397  * Adds a child at fixed coordinates in one of the text widget's
9398  * windows.
9399  *
9400  * The window must have nonzero size (see
9401  * gtk_text_view_set_border_window_size()). Note that the child
9402  * coordinates are given relative to the #GdkWindow in question, and
9403  * that these coordinates have no sane relationship to scrolling. When
9404  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
9405  * irrelevant, the child floats above all scrollable areas. But when
9406  * placing a child in one of the scrollable windows (border windows or
9407  * text window), you'll need to compute the child's correct position
9408  * in buffer coordinates any time scrolling occurs or buffer changes
9409  * occur, and then call gtk_text_view_move_child() to update the
9410  * child's position.
9411  */
9412 void
9413 gtk_text_view_add_child_in_window (GtkTextView       *text_view,
9414                                    GtkWidget         *child,
9415                                    GtkTextWindowType  which_window,
9416                                    gint               xpos,
9417                                    gint               ypos)
9418 {
9419   GtkTextViewChild *vc;
9420
9421   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9422   g_return_if_fail (GTK_IS_WIDGET (child));
9423   g_return_if_fail (gtk_widget_get_parent (child) == NULL);
9424
9425   vc = text_view_child_new_window (child, which_window,
9426                                    xpos, ypos);
9427
9428   add_child (text_view, vc);
9429
9430   g_assert (vc->widget == child);
9431   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9432 }
9433
9434 /**
9435  * gtk_text_view_move_child:
9436  * @text_view: a #GtkTextView
9437  * @child: child widget already added to the text view
9438  * @xpos: new X position in window coordinates
9439  * @ypos: new Y position in window coordinates
9440  *
9441  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
9442  **/
9443 void
9444 gtk_text_view_move_child (GtkTextView *text_view,
9445                           GtkWidget   *child,
9446                           gint         xpos,
9447                           gint         ypos)
9448 {
9449   GtkTextViewChild *vc;
9450
9451   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9452   g_return_if_fail (GTK_IS_WIDGET (child));
9453   g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9454
9455   vc = g_object_get_data (G_OBJECT (child),
9456                           "gtk-text-view-child");
9457
9458   g_assert (vc != NULL);
9459
9460   if (vc->x == xpos &&
9461       vc->y == ypos)
9462     return;
9463   
9464   vc->x = xpos;
9465   vc->y = ypos;
9466
9467   if (gtk_widget_get_visible (child) &&
9468       gtk_widget_get_visible (GTK_WIDGET (text_view)))
9469     gtk_widget_queue_resize (child);
9470 }
9471
9472
9473 /* Iterator operations */
9474
9475 /**
9476  * gtk_text_view_forward_display_line:
9477  * @text_view: a #GtkTextView
9478  * @iter: a #GtkTextIter
9479  * 
9480  * Moves the given @iter forward by one display (wrapped) line.
9481  * A display line is different from a paragraph. Paragraphs are
9482  * separated by newlines or other paragraph separator characters.
9483  * Display lines are created by line-wrapping a paragraph. If
9484  * wrapping is turned off, display lines and paragraphs will be the
9485  * same. Display lines are divided differently for each view, since
9486  * they depend on the view's width; paragraphs are the same in all
9487  * views, since they depend on the contents of the #GtkTextBuffer.
9488  * 
9489  * Return value: %TRUE if @iter was moved and is not on the end iterator
9490  **/
9491 gboolean
9492 gtk_text_view_forward_display_line (GtkTextView *text_view,
9493                                     GtkTextIter *iter)
9494 {
9495   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9496   g_return_val_if_fail (iter != NULL, FALSE);
9497
9498   gtk_text_view_ensure_layout (text_view);
9499
9500   return gtk_text_layout_move_iter_to_next_line (text_view->priv->layout, iter);
9501 }
9502
9503 /**
9504  * gtk_text_view_backward_display_line:
9505  * @text_view: a #GtkTextView
9506  * @iter: a #GtkTextIter
9507  * 
9508  * Moves the given @iter backward by one display (wrapped) line.
9509  * A display line is different from a paragraph. Paragraphs are
9510  * separated by newlines or other paragraph separator characters.
9511  * Display lines are created by line-wrapping a paragraph. If
9512  * wrapping is turned off, display lines and paragraphs will be the
9513  * same. Display lines are divided differently for each view, since
9514  * they depend on the view's width; paragraphs are the same in all
9515  * views, since they depend on the contents of the #GtkTextBuffer.
9516  * 
9517  * Return value: %TRUE if @iter was moved and is not on the end iterator
9518  **/
9519 gboolean
9520 gtk_text_view_backward_display_line (GtkTextView *text_view,
9521                                      GtkTextIter *iter)
9522 {
9523   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9524   g_return_val_if_fail (iter != NULL, FALSE);
9525
9526   gtk_text_view_ensure_layout (text_view);
9527
9528   return gtk_text_layout_move_iter_to_previous_line (text_view->priv->layout, iter);
9529 }
9530
9531 /**
9532  * gtk_text_view_forward_display_line_end:
9533  * @text_view: a #GtkTextView
9534  * @iter: a #GtkTextIter
9535  * 
9536  * Moves the given @iter forward to the next display line end.
9537  * A display line is different from a paragraph. Paragraphs are
9538  * separated by newlines or other paragraph separator characters.
9539  * Display lines are created by line-wrapping a paragraph. If
9540  * wrapping is turned off, display lines and paragraphs will be the
9541  * same. Display lines are divided differently for each view, since
9542  * they depend on the view's width; paragraphs are the same in all
9543  * views, since they depend on the contents of the #GtkTextBuffer.
9544  * 
9545  * Return value: %TRUE if @iter was moved and is not on the end iterator
9546  **/
9547 gboolean
9548 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
9549                                         GtkTextIter *iter)
9550 {
9551   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9552   g_return_val_if_fail (iter != NULL, FALSE);
9553
9554   gtk_text_view_ensure_layout (text_view);
9555
9556   return gtk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, 1);
9557 }
9558
9559 /**
9560  * gtk_text_view_backward_display_line_start:
9561  * @text_view: a #GtkTextView
9562  * @iter: a #GtkTextIter
9563  * 
9564  * Moves the given @iter backward to the next display line start.
9565  * A display line is different from a paragraph. Paragraphs are
9566  * separated by newlines or other paragraph separator characters.
9567  * Display lines are created by line-wrapping a paragraph. If
9568  * wrapping is turned off, display lines and paragraphs will be the
9569  * same. Display lines are divided differently for each view, since
9570  * they depend on the view's width; paragraphs are the same in all
9571  * views, since they depend on the contents of the #GtkTextBuffer.
9572  * 
9573  * Return value: %TRUE if @iter was moved and is not on the end iterator
9574  **/
9575 gboolean
9576 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
9577                                            GtkTextIter *iter)
9578 {
9579   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9580   g_return_val_if_fail (iter != NULL, FALSE);
9581
9582   gtk_text_view_ensure_layout (text_view);
9583
9584   return gtk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, -1);
9585 }
9586
9587 /**
9588  * gtk_text_view_starts_display_line:
9589  * @text_view: a #GtkTextView
9590  * @iter: a #GtkTextIter
9591  * 
9592  * Determines whether @iter is at the start of a display line.
9593  * See gtk_text_view_forward_display_line() for an explanation of
9594  * display lines vs. paragraphs.
9595  * 
9596  * Return value: %TRUE if @iter begins a wrapped line
9597  **/
9598 gboolean
9599 gtk_text_view_starts_display_line (GtkTextView       *text_view,
9600                                    const GtkTextIter *iter)
9601 {
9602   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9603   g_return_val_if_fail (iter != NULL, FALSE);
9604
9605   gtk_text_view_ensure_layout (text_view);
9606
9607   return gtk_text_layout_iter_starts_line (text_view->priv->layout, iter);
9608 }
9609
9610 /**
9611  * gtk_text_view_move_visually:
9612  * @text_view: a #GtkTextView
9613  * @iter: a #GtkTextIter
9614  * @count: number of characters to move (negative moves left, 
9615  *    positive moves right)
9616  *
9617  * Move the iterator a given number of characters visually, treating
9618  * it as the strong cursor position. If @count is positive, then the
9619  * new strong cursor position will be @count positions to the right of
9620  * the old cursor position. If @count is negative then the new strong
9621  * cursor position will be @count positions to the left of the old
9622  * cursor position.
9623  *
9624  * In the presence of bi-directional text, the correspondence
9625  * between logical and visual order will depend on the direction
9626  * of the current run, and there may be jumps when the cursor
9627  * is moved off of the end of a run.
9628  * 
9629  * Return value: %TRUE if @iter moved and is not on the end iterator
9630  **/
9631 gboolean
9632 gtk_text_view_move_visually (GtkTextView *text_view,
9633                              GtkTextIter *iter,
9634                              gint         count)
9635 {
9636   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9637   g_return_val_if_fail (iter != NULL, FALSE);
9638
9639   gtk_text_view_ensure_layout (text_view);
9640
9641   return gtk_text_layout_move_iter_visually (text_view->priv->layout, iter, count);
9642 }