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