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