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