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