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