]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
Add accessors for GtkTextView adjustments
[~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   guint scroll_after_paste : 1;
113 };
114
115
116 struct _GtkTextPendingScroll
117 {
118   GtkTextMark   *mark;
119   gdouble        within_margin;
120   gboolean       use_align;
121   gdouble        xalign;
122   gdouble        yalign;
123 };
124   
125 enum
126 {
127   SET_SCROLL_ADJUSTMENTS,
128   POPULATE_POPUP,
129   MOVE_CURSOR,
130   PAGE_HORIZONTALLY,
131   SET_ANCHOR,
132   INSERT_AT_CURSOR,
133   DELETE_FROM_CURSOR,
134   BACKSPACE,
135   CUT_CLIPBOARD,
136   COPY_CLIPBOARD,
137   PASTE_CLIPBOARD,
138   TOGGLE_OVERWRITE,
139   MOVE_VIEWPORT,
140   SELECT_ALL,
141   TOGGLE_CURSOR_VISIBLE,
142   PREEDIT_CHANGED,
143   LAST_SIGNAL
144 };
145
146 enum
147 {
148   PROP_0,
149   PROP_PIXELS_ABOVE_LINES,
150   PROP_PIXELS_BELOW_LINES,
151   PROP_PIXELS_INSIDE_WRAP,
152   PROP_EDITABLE,
153   PROP_WRAP_MODE,
154   PROP_JUSTIFICATION,
155   PROP_LEFT_MARGIN,
156   PROP_RIGHT_MARGIN,
157   PROP_INDENT,
158   PROP_TABS,
159   PROP_CURSOR_VISIBLE,
160   PROP_BUFFER,
161   PROP_OVERWRITE,
162   PROP_ACCEPTS_TAB,
163   PROP_IM_MODULE
164 };
165
166 static void gtk_text_view_destroy              (GtkObject        *object);
167 static void gtk_text_view_finalize             (GObject          *object);
168 static void gtk_text_view_set_property         (GObject         *object,
169                                                 guint            prop_id,
170                                                 const GValue    *value,
171                                                 GParamSpec      *pspec);
172 static void gtk_text_view_get_property         (GObject         *object,
173                                                 guint            prop_id,
174                                                 GValue          *value,
175                                                 GParamSpec      *pspec);
176 static void gtk_text_view_size_request         (GtkWidget        *widget,
177                                                 GtkRequisition   *requisition);
178 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
179                                                 GtkAllocation    *allocation);
180 static void gtk_text_view_realize              (GtkWidget        *widget);
181 static void gtk_text_view_unrealize            (GtkWidget        *widget);
182 static void gtk_text_view_style_set            (GtkWidget        *widget,
183                                                 GtkStyle         *previous_style);
184 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
185                                                 GtkTextDirection  previous_direction);
186 static void gtk_text_view_grab_notify          (GtkWidget        *widget,
187                                                 gboolean         was_grabbed);
188 static void gtk_text_view_state_changed        (GtkWidget        *widget,
189                                                 GtkStateType      previous_state);
190
191 static gint gtk_text_view_event                (GtkWidget        *widget,
192                                                 GdkEvent         *event);
193 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
194                                                 GdkEventKey      *event);
195 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
196                                                 GdkEventKey      *event);
197 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
198                                                 GdkEventButton   *event);
199 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
200                                                 GdkEventButton   *event);
201 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
202                                                 GdkEventFocus    *event);
203 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
204                                                 GdkEventFocus    *event);
205 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
206                                                 GdkEventMotion   *event);
207 static gint gtk_text_view_expose_event         (GtkWidget        *widget,
208                                                 GdkEventExpose   *expose);
209 static void gtk_text_view_draw_focus           (GtkWidget        *widget);
210 static gboolean gtk_text_view_focus            (GtkWidget        *widget,
211                                                 GtkDirectionType  direction);
212 static void gtk_text_view_move_focus           (GtkWidget        *widget,
213                                                 GtkDirectionType  direction_type);
214 static void gtk_text_view_select_all           (GtkWidget        *widget,
215                                                 gboolean          select);
216
217
218 /* Source side drag signals */
219 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
220                                             GdkDragContext   *context);
221 static void gtk_text_view_drag_end         (GtkWidget        *widget,
222                                             GdkDragContext   *context);
223 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
224                                             GdkDragContext   *context,
225                                             GtkSelectionData *selection_data,
226                                             guint             info,
227                                             guint             time);
228 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
229                                             GdkDragContext   *context);
230
231 /* Target side drag signals */
232 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
233                                                   GdkDragContext   *context,
234                                                   guint             time);
235 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
236                                                   GdkDragContext   *context,
237                                                   gint              x,
238                                                   gint              y,
239                                                   guint             time);
240 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
241                                                   GdkDragContext   *context,
242                                                   gint              x,
243                                                   gint              y,
244                                                   guint             time);
245 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
246                                                   GdkDragContext   *context,
247                                                   gint              x,
248                                                   gint              y,
249                                                   GtkSelectionData *selection_data,
250                                                   guint             info,
251                                                   guint             time);
252
253 static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
254                                                   GtkAdjustment *hadj,
255                                                   GtkAdjustment *vadj);
256 static gboolean gtk_text_view_popup_menu         (GtkWidget     *widget);
257
258 static void gtk_text_view_move_cursor       (GtkTextView           *text_view,
259                                              GtkMovementStep        step,
260                                              gint                   count,
261                                              gboolean               extend_selection);
262 static void gtk_text_view_page_horizontally (GtkTextView          *text_view,
263                                              gint                  count,
264                                              gboolean              extend_selection);
265 static gboolean gtk_text_view_move_viewport (GtkTextView           *text_view,
266                                              GtkScrollStep          step,
267                                              gint                   count);
268 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
269 static gboolean gtk_text_view_scroll_pages (GtkTextView           *text_view,
270                                             gint                   count,
271                                             gboolean               extend_selection);
272 static gboolean gtk_text_view_scroll_hpages(GtkTextView           *text_view,
273                                             gint                   count,
274                                             gboolean               extend_selection);
275 static void gtk_text_view_insert_at_cursor (GtkTextView           *text_view,
276                                             const gchar           *str);
277 static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
278                                               GtkDeleteType          type,
279                                               gint                   count);
280 static void gtk_text_view_backspace        (GtkTextView           *text_view);
281 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
282 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
283 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
284 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
285 static void gtk_text_view_toggle_cursor_visible (GtkTextView      *text_view);
286 static void gtk_text_view_compat_move_focus(GtkTextView           *text_view,
287                                             GtkDirectionType       direction_type);
288 static void gtk_text_view_unselect         (GtkTextView           *text_view);
289
290 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
291 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
292                                                      GtkTextIter        *iter);
293 static void     gtk_text_view_update_layout_width       (GtkTextView        *text_view);
294 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
295                                                          GtkTextAttributes *values,
296                                                          GtkStyle           *style);
297 static void     gtk_text_view_ensure_layout          (GtkTextView        *text_view);
298 static void     gtk_text_view_destroy_layout         (GtkTextView        *text_view);
299 static void     gtk_text_view_check_keymap_direction (GtkTextView        *text_view);
300 static void     gtk_text_view_reset_im_context       (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: 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: a #GtkTextIter
1581  * @trailing: 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: 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: return location for a y coordinate
1646  * @height: 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: a #GtkTextIter
1673  * @y: a y coordinate
1674  * @line_top: 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   if (!was_grabbed)
4089     {
4090       gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
4091       gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
4092     }
4093 }
4094
4095
4096 /*
4097  * Events
4098  */
4099
4100 static gboolean
4101 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
4102 {
4103   if (event)
4104     switch (event->type)
4105       {
4106       case GDK_MOTION_NOTIFY:
4107         *x = event->motion.x;
4108         *y = event->motion.y;
4109         return TRUE;
4110         break;
4111
4112       case GDK_BUTTON_PRESS:
4113       case GDK_2BUTTON_PRESS:
4114       case GDK_3BUTTON_PRESS:
4115       case GDK_BUTTON_RELEASE:
4116         *x = event->button.x;
4117         *y = event->button.y;
4118         return TRUE;
4119         break;
4120
4121       case GDK_KEY_PRESS:
4122       case GDK_KEY_RELEASE:
4123       case GDK_ENTER_NOTIFY:
4124       case GDK_LEAVE_NOTIFY:
4125       case GDK_PROPERTY_NOTIFY:
4126       case GDK_SELECTION_CLEAR:
4127       case GDK_SELECTION_REQUEST:
4128       case GDK_SELECTION_NOTIFY:
4129       case GDK_PROXIMITY_IN:
4130       case GDK_PROXIMITY_OUT:
4131       case GDK_DRAG_ENTER:
4132       case GDK_DRAG_LEAVE:
4133       case GDK_DRAG_MOTION:
4134       case GDK_DRAG_STATUS:
4135       case GDK_DROP_START:
4136       case GDK_DROP_FINISHED:
4137       default:
4138         return FALSE;
4139         break;
4140       }
4141
4142   return FALSE;
4143 }
4144
4145 static gint
4146 emit_event_on_tags (GtkWidget   *widget,
4147                     GdkEvent    *event,
4148                     GtkTextIter *iter)
4149 {
4150   GSList *tags;
4151   GSList *tmp;
4152   gboolean retval = FALSE;
4153
4154   tags = gtk_text_iter_get_tags (iter);
4155
4156   tmp = tags;
4157   while (tmp != NULL)
4158     {
4159       GtkTextTag *tag = tmp->data;
4160
4161       if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
4162         {
4163           retval = TRUE;
4164           break;
4165         }
4166
4167       tmp = g_slist_next (tmp);
4168     }
4169
4170   g_slist_free (tags);
4171
4172   return retval;
4173 }
4174
4175 static gint
4176 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
4177 {
4178   GtkTextView *text_view;
4179   gint x = 0, y = 0;
4180
4181   text_view = GTK_TEXT_VIEW (widget);
4182
4183   if (text_view->layout == NULL ||
4184       get_buffer (text_view) == NULL)
4185     return FALSE;
4186
4187   if (event->any.window != text_view->text_window->bin_window)
4188     return FALSE;
4189
4190   if (get_event_coordinates (event, &x, &y))
4191     {
4192       GtkTextIter iter;
4193
4194       x += text_view->xoffset;
4195       y += text_view->yoffset;
4196
4197       /* FIXME this is slow and we do it twice per event.
4198        * My favorite solution is to have GtkTextLayout cache
4199        * the last couple lookups.
4200        */
4201       gtk_text_layout_get_iter_at_pixel (text_view->layout,
4202                                          &iter,
4203                                          x, y);
4204
4205       return emit_event_on_tags (widget, event, &iter);
4206     }
4207   else if (event->type == GDK_KEY_PRESS ||
4208            event->type == GDK_KEY_RELEASE)
4209     {
4210       GtkTextIter iter;
4211
4212       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
4213                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
4214
4215       return emit_event_on_tags (widget, event, &iter);
4216     }
4217   else
4218     return FALSE;
4219 }
4220
4221 static gint
4222 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
4223 {
4224   gboolean retval = FALSE;
4225   gboolean obscure = FALSE;
4226   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4227   GtkTextMark *insert;
4228   GtkTextIter iter;
4229   gboolean can_insert;
4230   
4231   if (text_view->layout == NULL ||
4232       get_buffer (text_view) == NULL)
4233     return FALSE;
4234
4235   /* Make sure input method knows where it is */
4236   flush_update_im_spot_location (text_view);
4237
4238   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4239   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4240   can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
4241   if (gtk_im_context_filter_keypress (text_view->im_context, event))
4242     {
4243       text_view->need_im_reset = TRUE;
4244       if (!can_insert)
4245         gtk_text_view_reset_im_context (text_view);
4246       obscure = can_insert;
4247       retval = TRUE;
4248     }
4249   /* Binding set */
4250   else if (GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event (widget, event))
4251     {
4252       retval = TRUE;
4253     }
4254   /* use overall editability not can_insert, more predictable for users */
4255   else if (text_view->editable &&
4256            (event->keyval == GDK_Return ||
4257             event->keyval == GDK_ISO_Enter ||
4258             event->keyval == GDK_KP_Enter))
4259     {
4260       /* this won't actually insert the newline if the cursor isn't
4261        * editable
4262        */
4263       gtk_text_view_reset_im_context (text_view);
4264       gtk_text_view_commit_text (text_view, "\n");
4265
4266       obscure = TRUE;
4267       retval = TRUE;
4268     }
4269   /* Pass through Tab as literal tab, unless Control is held down */
4270   else if ((event->keyval == GDK_Tab ||
4271             event->keyval == GDK_KP_Tab ||
4272             event->keyval == GDK_ISO_Left_Tab) &&
4273            !(event->state & GDK_CONTROL_MASK))
4274     {
4275       /* If the text widget isn't editable overall, or if the application
4276        * has turned off "accepts_tab", move the focus instead
4277        */
4278       if (text_view->accepts_tab && text_view->editable)
4279         {
4280           gtk_text_view_reset_im_context (text_view);
4281           gtk_text_view_commit_text (text_view, "\t");
4282           obscure = TRUE;
4283         }
4284       else
4285         g_signal_emit_by_name (text_view, "move-focus",
4286                                (event->state & GDK_SHIFT_MASK) ?
4287                                GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
4288
4289       retval = TRUE;
4290     }
4291   else
4292     retval = FALSE;
4293
4294   if (obscure)
4295     gtk_text_view_obscure_mouse_cursor (text_view);
4296   
4297   gtk_text_view_reset_blink_time (text_view);
4298   gtk_text_view_pend_cursor_blink (text_view);
4299
4300   return retval;
4301 }
4302
4303 static gint
4304 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
4305 {
4306   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4307   GtkTextMark *insert;
4308   GtkTextIter iter;
4309
4310   if (text_view->layout == NULL || get_buffer (text_view) == NULL)
4311     return FALSE;
4312       
4313   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4314   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4315   if (gtk_text_iter_can_insert (&iter, text_view->editable) &&
4316       gtk_im_context_filter_keypress (text_view->im_context, event))
4317     {
4318       text_view->need_im_reset = TRUE;
4319       return TRUE;
4320     }
4321   else
4322     return GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_release_event (widget, event);
4323 }
4324
4325 static gint
4326 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
4327 {
4328   GtkTextView *text_view;
4329
4330   text_view = GTK_TEXT_VIEW (widget);
4331
4332   gtk_widget_grab_focus (widget);
4333
4334   if (event->window != text_view->text_window->bin_window)
4335     {
4336       /* Remove selection if any. */
4337       gtk_text_view_unselect (text_view);
4338       return FALSE;
4339     }
4340
4341   gtk_text_view_reset_blink_time (text_view);
4342
4343 #if 0
4344   /* debug hack */
4345   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
4346     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
4347   else if (event->button == 3)
4348     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
4349 #endif
4350
4351   if (event->type == GDK_BUTTON_PRESS)
4352     {
4353       gtk_text_view_reset_im_context (text_view);
4354
4355       if (event->button == 1)
4356         {
4357           /* If we're in the selection, start a drag copy/move of the
4358            * selection; otherwise, start creating a new selection.
4359            */
4360           GtkTextIter iter;
4361           GtkTextIter start, end;
4362
4363           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4364                                              &iter,
4365                                              event->x + text_view->xoffset,
4366                                              event->y + text_view->yoffset);
4367
4368           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4369                                                     &start, &end) &&
4370               gtk_text_iter_in_range (&iter, &start, &end) &&
4371               !(event->state & GDK_SHIFT_MASK))
4372             {
4373               text_view->drag_start_x = event->x;
4374               text_view->drag_start_y = event->y;
4375               text_view->pending_place_cursor_button = event->button;
4376             }
4377           else
4378             {
4379               gtk_text_view_start_selection_drag (text_view, &iter, event);
4380             }
4381
4382           return TRUE;
4383         }
4384       else if (event->button == 2)
4385         {
4386           GtkTextIter iter;
4387           GtkTextViewPrivate *priv;
4388
4389           /* We do not want to scroll back to the insert iter when we paste
4390              with the middle button */
4391           priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
4392           priv->scroll_after_paste = FALSE;
4393
4394           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4395                                              &iter,
4396                                              event->x + text_view->xoffset,
4397                                              event->y + text_view->yoffset);
4398
4399           gtk_text_buffer_paste_clipboard (get_buffer (text_view),
4400                                            gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY),
4401                                            &iter,
4402                                            text_view->editable);
4403           return TRUE;
4404         }
4405       else if (event->button == 3)
4406         {
4407           gtk_text_view_do_popup (text_view, event);
4408           return TRUE;
4409         }
4410     }
4411   else if ((event->type == GDK_2BUTTON_PRESS ||
4412             event->type == GDK_3BUTTON_PRESS) &&
4413            event->button == 1) 
4414     {
4415       GtkTextIter iter;
4416
4417       gtk_text_view_end_selection_drag (text_view);
4418
4419       gtk_text_layout_get_iter_at_pixel (text_view->layout,
4420                                          &iter,
4421                                          event->x + text_view->xoffset,
4422                                          event->y + text_view->yoffset);
4423       
4424       gtk_text_view_start_selection_drag (text_view, &iter, event);
4425       return TRUE;
4426     }
4427   
4428   return FALSE;
4429 }
4430
4431 static gint
4432 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
4433 {
4434   GtkTextView *text_view;
4435
4436   text_view = GTK_TEXT_VIEW (widget);
4437
4438   if (event->window != text_view->text_window->bin_window)
4439     return FALSE;
4440
4441   if (event->button == 1)
4442     {
4443       if (text_view->drag_start_x >= 0)
4444         {
4445           text_view->drag_start_x = -1;
4446           text_view->drag_start_y = -1;
4447         }
4448
4449       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget)))
4450         return TRUE;
4451       else if (text_view->pending_place_cursor_button == event->button)
4452         {
4453           GtkTextIter iter;
4454
4455           /* Unselect everything; we clicked inside selection, but
4456            * didn't move by the drag threshold, so just clear selection
4457            * and place cursor.
4458            */
4459           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4460                                              &iter,
4461                                              event->x + text_view->xoffset,
4462                                              event->y + text_view->yoffset);
4463
4464           gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
4465           gtk_text_view_check_cursor_blink (text_view);
4466           
4467           text_view->pending_place_cursor_button = 0;
4468           
4469           return FALSE;
4470         }
4471     }
4472
4473   return FALSE;
4474 }
4475
4476 static void
4477 keymap_direction_changed (GdkKeymap   *keymap,
4478                           GtkTextView *text_view)
4479 {
4480   gtk_text_view_check_keymap_direction (text_view);
4481 }
4482
4483 static gint
4484 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
4485 {
4486   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4487
4488   gtk_widget_queue_draw (widget);
4489
4490   DV(g_print (G_STRLOC": focus_in_event\n"));
4491
4492   gtk_text_view_reset_blink_time (text_view);
4493
4494   if (text_view->cursor_visible && text_view->layout)
4495     {
4496       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4497       gtk_text_view_check_cursor_blink (text_view);
4498     }
4499
4500   g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4501                     "direction-changed",
4502                     G_CALLBACK (keymap_direction_changed), text_view);
4503   gtk_text_view_check_keymap_direction (text_view);
4504
4505   if (text_view->editable)
4506     {
4507       text_view->need_im_reset = TRUE;
4508       gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
4509     }
4510
4511   return FALSE;
4512 }
4513
4514 static gint
4515 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
4516 {
4517   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4518
4519   gtk_text_view_end_selection_drag (text_view);
4520
4521   gtk_widget_queue_draw (widget);
4522
4523   DV(g_print (G_STRLOC": focus_out_event\n"));
4524   
4525   if (text_view->cursor_visible && text_view->layout)
4526     {
4527       gtk_text_view_check_cursor_blink (text_view);
4528       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4529     }
4530
4531   g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4532                                         keymap_direction_changed,
4533                                         text_view);
4534
4535   if (text_view->editable)
4536     {
4537       text_view->need_im_reset = TRUE;
4538       gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
4539     }
4540
4541   return FALSE;
4542 }
4543
4544 static gint
4545 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
4546 {
4547   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4548
4549   gtk_text_view_unobscure_mouse_cursor (text_view);
4550
4551   if (event->window == text_view->text_window->bin_window &&
4552       text_view->drag_start_x >= 0)
4553     {
4554       gint x = event->x;
4555       gint y = event->y;
4556
4557       gdk_event_request_motions (event);
4558
4559       if (gtk_drag_check_threshold (widget,
4560                                     text_view->drag_start_x, 
4561                                     text_view->drag_start_y,
4562                                     x, y))
4563         {
4564           GtkTextIter iter;
4565           gint buffer_x, buffer_y;
4566
4567           gtk_text_view_window_to_buffer_coords (text_view,
4568                                                  GTK_TEXT_WINDOW_TEXT,
4569                                                  text_view->drag_start_x,
4570                                                  text_view->drag_start_y,
4571                                                  &buffer_x,
4572                                                  &buffer_y);
4573
4574           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4575                                              &iter,
4576                                              buffer_x, buffer_y);
4577
4578           gtk_text_view_start_selection_dnd (text_view, &iter, event);
4579           return TRUE;
4580         }
4581     }
4582
4583   return FALSE;
4584 }
4585
4586 static void
4587 gtk_text_view_paint (GtkWidget      *widget,
4588                      GdkRectangle   *area,
4589                      GdkEventExpose *event)
4590 {
4591   GtkTextView *text_view;
4592   GList *child_exposes;
4593   GList *tmp_list;
4594   
4595   text_view = GTK_TEXT_VIEW (widget);
4596
4597   g_return_if_fail (text_view->layout != NULL);
4598   g_return_if_fail (text_view->xoffset >= 0);
4599   g_return_if_fail (text_view->yoffset >= 0);
4600
4601   while (text_view->first_validate_idle != 0)
4602     {
4603       DV (g_print (G_STRLOC": first_validate_idle: %d\n",
4604                    text_view->first_validate_idle));
4605       gtk_text_view_flush_first_validate (text_view);
4606     }
4607
4608   if (!text_view->onscreen_validated)
4609     {
4610       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.");
4611       g_assert_not_reached ();
4612     }
4613   
4614 #if 0
4615   printf ("painting %d,%d  %d x %d\n",
4616           area->x, area->y,
4617           area->width, area->height);
4618 #endif
4619
4620   child_exposes = NULL;
4621   gtk_text_layout_draw (text_view->layout,
4622                         widget,
4623                         text_view->text_window->bin_window,
4624                         NULL,
4625                         text_view->xoffset,
4626                         text_view->yoffset,
4627                         area->x, area->y,
4628                         area->width, area->height,
4629                         &child_exposes);
4630
4631   tmp_list = child_exposes;
4632   while (tmp_list != NULL)
4633     {
4634       GtkWidget *child = tmp_list->data;
4635   
4636       gtk_container_propagate_expose (GTK_CONTAINER (text_view),
4637                                       child,
4638                                       event);
4639
4640       g_object_unref (child);
4641       
4642       tmp_list = tmp_list->next;
4643     }
4644
4645   g_list_free (child_exposes);
4646 }
4647
4648 static gint
4649 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
4650 {
4651   GSList *tmp_list;
4652   
4653   if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
4654                                                  GTK_TEXT_WINDOW_TEXT))
4655     {
4656       DV(g_print (">Exposed ("G_STRLOC")\n"));
4657       gtk_text_view_paint (widget, &event->area, event);
4658     }
4659
4660   if (event->window == widget->window)
4661     gtk_text_view_draw_focus (widget);
4662
4663   /* Propagate exposes to all unanchored children. 
4664    * Anchored children are handled in gtk_text_view_paint(). 
4665    */
4666   tmp_list = GTK_TEXT_VIEW (widget)->children;
4667   while (tmp_list != NULL)
4668     {
4669       GtkTextViewChild *vc = tmp_list->data;
4670
4671       /* propagate_expose checks that event->window matches
4672        * child->window
4673        */
4674       if (!vc->anchor)
4675         gtk_container_propagate_expose (GTK_CONTAINER (widget),
4676                                         vc->widget,
4677                                         event);
4678       
4679       tmp_list = tmp_list->next;
4680     }
4681   
4682   return FALSE;
4683 }
4684
4685 static void
4686 gtk_text_view_draw_focus (GtkWidget *widget)
4687 {
4688   gboolean interior_focus;
4689
4690   /* We clear the focus if we are in interior focus mode. */
4691   gtk_widget_style_get (widget,
4692                         "interior-focus", &interior_focus,
4693                         NULL);
4694   
4695   if (gtk_widget_is_drawable (widget))
4696     {
4697       if (gtk_widget_has_focus (widget) && !interior_focus)
4698         {          
4699           gtk_paint_focus (widget->style, widget->window, gtk_widget_get_state (widget),
4700                            NULL, widget, "textview",
4701                            0, 0,
4702                            widget->allocation.width,
4703                            widget->allocation.height);
4704         }
4705       else
4706         {
4707           gdk_window_clear (widget->window);
4708         }
4709     }
4710 }
4711
4712 static gboolean
4713 gtk_text_view_focus (GtkWidget        *widget,
4714                      GtkDirectionType  direction)
4715 {
4716   GtkContainer *container;
4717   gboolean result;
4718   
4719   container = GTK_CONTAINER (widget);  
4720
4721   if (!gtk_widget_is_focus (widget) &&
4722       container->focus_child == NULL)
4723     {
4724       gtk_widget_grab_focus (widget);
4725       return TRUE;
4726     }
4727   else
4728     {
4729       /*
4730        * Unset CAN_FOCUS flag so that gtk_container_focus() allows
4731        * children to get the focus
4732        */
4733       gtk_widget_set_can_focus (widget, FALSE);
4734       result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
4735       gtk_widget_set_can_focus (widget, TRUE);
4736
4737       return result;
4738     }
4739 }
4740
4741 static void
4742 gtk_text_view_move_focus (GtkWidget        *widget,
4743                           GtkDirectionType  direction_type)
4744 {
4745   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4746
4747   if (GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus)
4748     GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus (text_view,
4749                                                      direction_type);
4750 }
4751
4752 /*
4753  * Container
4754  */
4755
4756 static void
4757 gtk_text_view_add (GtkContainer *container,
4758                    GtkWidget    *child)
4759 {
4760   /* This is pretty random. */
4761   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
4762                                      child,
4763                                      GTK_TEXT_WINDOW_WIDGET,
4764                                      0, 0);
4765 }
4766
4767 static void
4768 gtk_text_view_remove (GtkContainer *container,
4769                       GtkWidget    *child)
4770 {
4771   GSList *iter;
4772   GtkTextView *text_view;
4773   GtkTextViewChild *vc;
4774
4775   text_view = GTK_TEXT_VIEW (container);
4776
4777   vc = NULL;
4778   iter = text_view->children;
4779
4780   while (iter != NULL)
4781     {
4782       vc = iter->data;
4783
4784       if (vc->widget == child)
4785         break;
4786
4787       iter = g_slist_next (iter);
4788     }
4789
4790   g_assert (iter != NULL); /* be sure we had the child in the list */
4791
4792   text_view->children = g_slist_remove (text_view->children, vc);
4793
4794   gtk_widget_unparent (vc->widget);
4795
4796   text_view_child_free (vc);
4797 }
4798
4799 static void
4800 gtk_text_view_forall (GtkContainer *container,
4801                       gboolean      include_internals,
4802                       GtkCallback   callback,
4803                       gpointer      callback_data)
4804 {
4805   GSList *iter;
4806   GtkTextView *text_view;
4807   GSList *copy;
4808
4809   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4810   g_return_if_fail (callback != NULL);
4811
4812   text_view = GTK_TEXT_VIEW (container);
4813
4814   copy = g_slist_copy (text_view->children);
4815   iter = copy;
4816
4817   while (iter != NULL)
4818     {
4819       GtkTextViewChild *vc = iter->data;
4820
4821       (* callback) (vc->widget, callback_data);
4822
4823       iter = g_slist_next (iter);
4824     }
4825
4826   g_slist_free (copy);
4827 }
4828
4829 #define CURSOR_ON_MULTIPLIER 2
4830 #define CURSOR_OFF_MULTIPLIER 1
4831 #define CURSOR_PEND_MULTIPLIER 3
4832 #define CURSOR_DIVIDER 3
4833
4834 static gboolean
4835 cursor_blinks (GtkTextView *text_view)
4836 {
4837   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4838   gboolean blink;
4839
4840 #ifdef DEBUG_VALIDATION_AND_SCROLLING
4841   return FALSE;
4842 #endif
4843   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
4844     return FALSE;
4845
4846   g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
4847
4848   if (!blink)
4849     return FALSE;
4850
4851   if (text_view->editable)
4852     {
4853       GtkTextMark *insert;
4854       GtkTextIter iter;
4855       
4856       insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4857       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4858       
4859       if (gtk_text_iter_editable (&iter, text_view->editable))
4860         return blink;
4861     }
4862
4863   return FALSE;
4864 }
4865
4866 static gint
4867 get_cursor_time (GtkTextView *text_view)
4868 {
4869   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4870   gint time;
4871
4872   g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
4873
4874   return time;
4875 }
4876
4877 static gint
4878 get_cursor_blink_timeout (GtkTextView *text_view)
4879 {
4880   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4881   gint time;
4882
4883   g_object_get (settings, "gtk-cursor-blink-timeout", &time, NULL);
4884
4885   return time;
4886 }
4887
4888
4889 /*
4890  * Blink!
4891  */
4892
4893 static gint
4894 blink_cb (gpointer data)
4895 {
4896   GtkTextView *text_view;
4897   GtkTextViewPrivate *priv;
4898   gboolean visible;
4899   gint blink_timeout;
4900
4901   text_view = GTK_TEXT_VIEW (data);
4902   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
4903
4904   if (!gtk_widget_has_focus (GTK_WIDGET (text_view)))
4905     {
4906       g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
4907                  "connect a handler to this signal, it must return\n"
4908                  "FALSE so the text view gets the event as well");
4909
4910       gtk_text_view_check_cursor_blink (text_view);
4911
4912       return FALSE;
4913     }
4914
4915   g_assert (text_view->layout);
4916   g_assert (text_view->cursor_visible);
4917
4918   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
4919
4920   blink_timeout = get_cursor_blink_timeout (text_view);
4921   if (priv->blink_time > 1000 * blink_timeout &&
4922       blink_timeout < G_MAXINT/1000) 
4923     {
4924       /* we've blinked enough without the user doing anything, stop blinking */
4925       visible = 0;
4926       text_view->blink_timeout = 0;
4927     } 
4928   else if (visible)
4929     text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
4930                                               blink_cb,
4931                                               text_view);
4932   else 
4933     {
4934       text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
4935                                                 blink_cb,
4936                                                 text_view);
4937       priv->blink_time += get_cursor_time (text_view);
4938     }
4939
4940   /* Block changed_handler while changing the layout's cursor visibility
4941    * because it would expose the whole paragraph. Instead, we expose
4942    * the cursor's area(s) manually below.
4943    */
4944   g_signal_handlers_block_by_func (text_view->layout,
4945                                    changed_handler,
4946                                    text_view);
4947   gtk_text_layout_set_cursor_visible (text_view->layout, !visible);
4948   g_signal_handlers_unblock_by_func (text_view->layout,
4949                                      changed_handler,
4950                                      text_view);
4951
4952   text_window_invalidate_cursors (text_view->text_window);
4953
4954   /* Remove ourselves */
4955   return FALSE;
4956 }
4957
4958
4959 static void
4960 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
4961 {
4962   if (text_view->blink_timeout)  
4963     { 
4964       g_source_remove (text_view->blink_timeout);
4965       text_view->blink_timeout = 0;
4966     }
4967 }
4968
4969 static void
4970 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
4971 {
4972   if (text_view->layout != NULL &&
4973       text_view->cursor_visible &&
4974       gtk_widget_has_focus (GTK_WIDGET (text_view)))
4975     {
4976       if (cursor_blinks (text_view))
4977         {
4978           if (text_view->blink_timeout == 0)
4979             {
4980               gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4981               
4982               text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
4983                                                         blink_cb,
4984                                                         text_view);
4985             }
4986         }
4987       else
4988         {
4989           gtk_text_view_stop_cursor_blink (text_view);
4990           gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4991         }
4992     }
4993   else
4994     {
4995       gtk_text_view_stop_cursor_blink (text_view);
4996       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4997     }
4998 }
4999
5000 static void
5001 gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
5002 {
5003   if (text_view->layout != NULL &&
5004       text_view->cursor_visible &&
5005       gtk_widget_has_focus (GTK_WIDGET (text_view)) &&
5006       cursor_blinks (text_view))
5007     {
5008       gtk_text_view_stop_cursor_blink (text_view);
5009       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
5010       
5011       text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
5012                                                 blink_cb,
5013                                                 text_view);
5014     }
5015 }
5016
5017 static void
5018 gtk_text_view_reset_blink_time (GtkTextView *text_view)
5019 {
5020   GtkTextViewPrivate *priv;
5021
5022   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
5023
5024   priv->blink_time = 0;
5025 }
5026
5027
5028 /*
5029  * Key binding handlers
5030  */
5031
5032 static gboolean
5033 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
5034                                   GtkTextIter *newplace,
5035                                   gint         count)
5036 {
5037   gboolean ret = TRUE;
5038
5039   while (count < 0)
5040     {
5041       ret = gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
5042       count++;
5043     }
5044
5045   while (count > 0)
5046     {
5047       ret = gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
5048       count--;
5049     }
5050
5051   return ret;
5052 }
5053
5054 static void
5055 move_cursor (GtkTextView       *text_view,
5056              const GtkTextIter *new_location,
5057              gboolean           extend_selection)
5058 {
5059   if (extend_selection)
5060     gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
5061                                        "insert",
5062                                        new_location);
5063   else
5064       gtk_text_buffer_place_cursor (get_buffer (text_view),
5065                                     new_location);
5066   gtk_text_view_check_cursor_blink (text_view);
5067 }
5068
5069 static void
5070 gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
5071                                     GtkMovementStep  step,
5072                                     gint             count,
5073                                     gboolean         extend_selection)
5074 {
5075   GtkTextIter insert;
5076   GtkTextIter newplace;
5077   gboolean cancel_selection = FALSE;
5078   gint cursor_x_pos = 0;
5079   GtkDirectionType leave_direction = -1;
5080
5081   if (!text_view->cursor_visible) 
5082     {
5083       GtkScrollStep scroll_step;
5084
5085       switch (step) 
5086         {
5087         case GTK_MOVEMENT_VISUAL_POSITIONS:
5088           leave_direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
5089           /* fall through */
5090         case GTK_MOVEMENT_LOGICAL_POSITIONS:
5091         case GTK_MOVEMENT_WORDS:
5092           scroll_step = GTK_SCROLL_HORIZONTAL_STEPS;
5093           break;
5094         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5095           scroll_step = GTK_SCROLL_HORIZONTAL_ENDS;
5096           break;          
5097         case GTK_MOVEMENT_DISPLAY_LINES:
5098           leave_direction = count > 0 ? GTK_DIR_DOWN : GTK_DIR_UP;
5099           /* fall through */
5100         case GTK_MOVEMENT_PARAGRAPHS:
5101         case GTK_MOVEMENT_PARAGRAPH_ENDS:
5102           scroll_step = GTK_SCROLL_STEPS;
5103           break;
5104         case GTK_MOVEMENT_PAGES:
5105           scroll_step = GTK_SCROLL_PAGES;
5106           break;
5107         case GTK_MOVEMENT_HORIZONTAL_PAGES:
5108           scroll_step = GTK_SCROLL_HORIZONTAL_PAGES;
5109           break;
5110         case GTK_MOVEMENT_BUFFER_ENDS:
5111           scroll_step = GTK_SCROLL_ENDS;
5112           break;
5113         default:
5114           scroll_step = GTK_SCROLL_PAGES;
5115           break;
5116         }
5117
5118       if (!gtk_text_view_move_viewport (text_view, scroll_step, count))
5119         {
5120           if (leave_direction != -1 &&
5121               !gtk_widget_keynav_failed (GTK_WIDGET (text_view),
5122                                          leave_direction))
5123             {
5124               g_signal_emit_by_name (text_view, "move-focus", leave_direction);
5125             }
5126         }
5127
5128       return;
5129     }
5130
5131   gtk_text_view_reset_im_context (text_view);
5132
5133   if (step == GTK_MOVEMENT_PAGES)
5134     {
5135       if (!gtk_text_view_scroll_pages (text_view, count, extend_selection))
5136         gtk_widget_error_bell (GTK_WIDGET (text_view));
5137
5138       gtk_text_view_check_cursor_blink (text_view);
5139       gtk_text_view_pend_cursor_blink (text_view);
5140       return;
5141     }
5142   else if (step == GTK_MOVEMENT_HORIZONTAL_PAGES)
5143     {
5144       if (!gtk_text_view_scroll_hpages (text_view, count, extend_selection))
5145         gtk_widget_error_bell (GTK_WIDGET (text_view));
5146
5147       gtk_text_view_check_cursor_blink (text_view);
5148       gtk_text_view_pend_cursor_blink (text_view);
5149       return;
5150     }
5151
5152   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5153                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5154
5155   if (! extend_selection)
5156     {
5157       GtkTextIter sel_bound;
5158
5159       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &sel_bound,
5160                                         gtk_text_buffer_get_selection_bound (get_buffer (text_view)));
5161
5162       /* if we move forward, assume the cursor is at the end of the selection;
5163        * if we move backward, assume the cursor is at the start
5164        */
5165       if (count > 0)
5166         gtk_text_iter_order (&sel_bound, &insert);
5167       else
5168         gtk_text_iter_order (&insert, &sel_bound);
5169
5170       /* if we actually have a selection, just move *to* the beginning/end
5171        * of the selection and not *from* there on LOGICAL_POSITIONS
5172        * and VISUAL_POSITIONS movement
5173        */
5174       if (! gtk_text_iter_equal (&sel_bound, &insert))
5175         cancel_selection = TRUE;
5176     }
5177
5178   newplace = insert;
5179
5180   if (step == GTK_MOVEMENT_DISPLAY_LINES)
5181     gtk_text_view_get_virtual_cursor_pos (text_view, &insert, &cursor_x_pos, NULL);
5182
5183   switch (step)
5184     {
5185     case GTK_MOVEMENT_LOGICAL_POSITIONS:
5186       if (! cancel_selection)
5187         gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
5188       break;
5189
5190     case GTK_MOVEMENT_VISUAL_POSITIONS:
5191       if (! cancel_selection)
5192         gtk_text_layout_move_iter_visually (text_view->layout,
5193                                             &newplace, count);
5194       break;
5195
5196     case GTK_MOVEMENT_WORDS:
5197       if (count < 0)
5198         gtk_text_iter_backward_visible_word_starts (&newplace, -count);
5199       else if (count > 0) 
5200         {
5201           if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
5202             gtk_text_iter_forward_to_line_end (&newplace);
5203         }
5204       break;
5205
5206     case GTK_MOVEMENT_DISPLAY_LINES:
5207       if (count < 0)
5208         {
5209           leave_direction = GTK_DIR_UP;
5210
5211           if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
5212             gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
5213           else
5214             gtk_text_iter_set_line_offset (&newplace, 0);
5215         }
5216       if (count > 0)
5217         {
5218           leave_direction = GTK_DIR_DOWN;
5219
5220           if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
5221             gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
5222           else
5223             gtk_text_iter_forward_to_line_end (&newplace);
5224         }
5225       break;
5226
5227     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5228       if (count > 1)
5229         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
5230       else if (count < -1)
5231         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
5232
5233       if (count != 0)
5234         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
5235       break;
5236
5237     case GTK_MOVEMENT_PARAGRAPHS:
5238       if (count > 0)
5239         {
5240           if (!gtk_text_iter_ends_line (&newplace))
5241             {
5242               gtk_text_iter_forward_to_line_end (&newplace);
5243               --count;
5244             }
5245           gtk_text_iter_forward_visible_lines (&newplace, count);
5246           gtk_text_iter_forward_to_line_end (&newplace);
5247         }
5248       else if (count < 0)
5249         {
5250           if (gtk_text_iter_get_line_offset (&newplace) > 0)
5251             gtk_text_iter_set_line_offset (&newplace, 0);
5252           gtk_text_iter_forward_visible_lines (&newplace, count);
5253           gtk_text_iter_set_line_offset (&newplace, 0);
5254         }
5255       break;
5256
5257     case GTK_MOVEMENT_PARAGRAPH_ENDS:
5258       if (count > 0)
5259         {
5260           if (!gtk_text_iter_ends_line (&newplace))
5261             gtk_text_iter_forward_to_line_end (&newplace);
5262         }
5263       else if (count < 0)
5264         {
5265           gtk_text_iter_set_line_offset (&newplace, 0);
5266         }
5267       break;
5268
5269     case GTK_MOVEMENT_BUFFER_ENDS:
5270       if (count > 0)
5271         gtk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
5272       else if (count < 0)
5273         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
5274      break;
5275       
5276     default:
5277       break;
5278     }
5279
5280   /* call move_cursor() even if the cursor hasn't moved, since it 
5281      cancels the selection
5282   */
5283   move_cursor (text_view, &newplace, extend_selection);
5284
5285   if (!gtk_text_iter_equal (&insert, &newplace))
5286     {
5287       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5288       gtk_text_view_scroll_mark_onscreen (text_view,
5289                                           gtk_text_buffer_get_insert (get_buffer (text_view)));
5290
5291       if (step == GTK_MOVEMENT_DISPLAY_LINES)
5292         gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
5293     }
5294   else if (leave_direction != -1)
5295     {
5296       if (!gtk_widget_keynav_failed (GTK_WIDGET (text_view),
5297                                      leave_direction))
5298         {
5299           g_signal_emit_by_name (text_view, "move-focus", leave_direction);
5300         }
5301     }
5302   else if (! cancel_selection)
5303     {
5304       gtk_widget_error_bell (GTK_WIDGET (text_view));
5305     }
5306
5307   gtk_text_view_check_cursor_blink (text_view);
5308   gtk_text_view_pend_cursor_blink (text_view);
5309 }
5310
5311 static void
5312 gtk_text_view_move_cursor (GtkTextView     *text_view,
5313                            GtkMovementStep  step,
5314                            gint             count,
5315                            gboolean         extend_selection)
5316 {
5317   gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
5318 }
5319
5320 static void
5321 gtk_text_view_page_horizontally (GtkTextView     *text_view,
5322                                  gint             count,
5323                                  gboolean         extend_selection)
5324 {
5325   gtk_text_view_move_cursor_internal (text_view, GTK_MOVEMENT_HORIZONTAL_PAGES,
5326                                       count, extend_selection);
5327 }
5328
5329
5330 static gboolean
5331 gtk_text_view_move_viewport (GtkTextView     *text_view,
5332                              GtkScrollStep    step,
5333                              gint             count)
5334 {
5335   GtkAdjustment *adjustment;
5336   gdouble increment;
5337   
5338   switch (step) 
5339     {
5340     case GTK_SCROLL_STEPS:
5341     case GTK_SCROLL_PAGES:
5342     case GTK_SCROLL_ENDS:
5343       adjustment = get_vadjustment (text_view);
5344       break;
5345     case GTK_SCROLL_HORIZONTAL_STEPS:
5346     case GTK_SCROLL_HORIZONTAL_PAGES:
5347     case GTK_SCROLL_HORIZONTAL_ENDS:
5348       adjustment = get_hadjustment (text_view);
5349       break;
5350     default:
5351       adjustment = get_vadjustment (text_view);
5352       break;
5353     }
5354
5355   switch (step) 
5356     {
5357     case GTK_SCROLL_STEPS:
5358     case GTK_SCROLL_HORIZONTAL_STEPS:
5359       increment = adjustment->step_increment;
5360       break;
5361     case GTK_SCROLL_PAGES:
5362     case GTK_SCROLL_HORIZONTAL_PAGES:
5363       increment = adjustment->page_increment;
5364       break;
5365     case GTK_SCROLL_ENDS:
5366     case GTK_SCROLL_HORIZONTAL_ENDS:
5367       increment = adjustment->upper - adjustment->lower;
5368       break;
5369     default:
5370       increment = 0.0;
5371       break;
5372     }
5373
5374   return set_adjustment_clamped (adjustment, adjustment->value + count * increment);
5375 }
5376
5377 static void
5378 gtk_text_view_set_anchor (GtkTextView *text_view)
5379 {
5380   GtkTextIter insert;
5381
5382   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5383                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5384
5385   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
5386 }
5387
5388 static gboolean
5389 gtk_text_view_scroll_pages (GtkTextView *text_view,
5390                             gint         count,
5391                             gboolean     extend_selection)
5392 {
5393   gdouble newval;
5394   gdouble oldval;
5395   GtkAdjustment *adj;
5396   gint cursor_x_pos, cursor_y_pos;
5397   GtkTextMark *insert_mark;
5398   GtkTextIter old_insert;
5399   GtkTextIter new_insert;
5400   GtkTextIter anchor;
5401   gint y0, y1;
5402
5403   g_return_val_if_fail (text_view->vadjustment != NULL, FALSE);
5404   
5405   adj = text_view->vadjustment;
5406
5407   insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
5408
5409   /* Make sure we start from the current cursor position, even
5410    * if it was offscreen, but don't queue more scrolls if we're
5411    * already behind.
5412    */
5413   if (text_view->pending_scroll)
5414     cancel_pending_scroll (text_view);
5415   else
5416     gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5417
5418   /* Validate the region that will be brought into view by the cursor motion
5419    */
5420   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5421                                     &old_insert, insert_mark);
5422
5423   if (count < 0)
5424     {
5425       gtk_text_view_get_first_para_iter (text_view, &anchor);
5426       y0 = adj->page_size;
5427       y1 = adj->page_size + count * adj->page_increment;
5428     }
5429   else
5430     {
5431       gtk_text_view_get_first_para_iter (text_view, &anchor);
5432       y0 = count * adj->page_increment + adj->page_size;
5433       y1 = 0;
5434     }
5435
5436   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
5437   /* FIXME do we need to update the adjustment ranges here? */
5438
5439   new_insert = old_insert;
5440
5441   if (count < 0 && adj->value <= (adj->lower + 1e-12))
5442     {
5443       /* already at top, just be sure we are at offset 0 */
5444       gtk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
5445       move_cursor (text_view, &new_insert, extend_selection);
5446     }
5447   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5448     {
5449       /* already at bottom, just be sure we are at the end */
5450       gtk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
5451       move_cursor (text_view, &new_insert, extend_selection);
5452     }
5453   else
5454     {
5455       gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
5456
5457       oldval = adj->value;
5458       newval = adj->value;
5459
5460       newval += count * adj->page_increment;
5461
5462       set_adjustment_clamped (adj, newval);
5463       cursor_y_pos += adj->value - oldval;
5464
5465       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5466       clamp_iter_onscreen (text_view, &new_insert);
5467       move_cursor (text_view, &new_insert, extend_selection);
5468
5469       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5470     }
5471   
5472   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5473    * only guarantees 1 pixel onscreen.
5474    */
5475   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5476   gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5477
5478   return !gtk_text_iter_equal (&old_insert, &new_insert);
5479 }
5480
5481 static gboolean
5482 gtk_text_view_scroll_hpages (GtkTextView *text_view,
5483                              gint         count,
5484                              gboolean     extend_selection)
5485 {
5486   gdouble newval;
5487   gdouble oldval;
5488   GtkAdjustment *adj;
5489   gint cursor_x_pos, cursor_y_pos;
5490   GtkTextMark *insert_mark;
5491   GtkTextIter old_insert;
5492   GtkTextIter new_insert;
5493   gint y, height;
5494   
5495   g_return_val_if_fail (text_view->hadjustment != NULL, FALSE);
5496
5497   adj = text_view->hadjustment;
5498
5499   insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
5500
5501   /* Make sure we start from the current cursor position, even
5502    * if it was offscreen, but don't queue more scrolls if we're
5503    * already behind.
5504    */
5505   if (text_view->pending_scroll)
5506     cancel_pending_scroll (text_view);
5507   else
5508     gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5509
5510   /* Validate the line that we're moving within.
5511    */
5512   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5513                                     &old_insert, insert_mark);
5514
5515   gtk_text_layout_get_line_yrange (text_view->layout, &old_insert, &y, &height);
5516   gtk_text_layout_validate_yrange (text_view->layout, &old_insert, y, y + height);
5517   /* FIXME do we need to update the adjustment ranges here? */
5518
5519   new_insert = old_insert;
5520
5521   if (count < 0 && adj->value <= (adj->lower + 1e-12))
5522     {
5523       /* already at far left, just be sure we are at offset 0 */
5524       gtk_text_iter_set_line_offset (&new_insert, 0);
5525       move_cursor (text_view, &new_insert, extend_selection);
5526     }
5527   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5528     {
5529       /* already at far right, just be sure we are at the end */
5530       if (!gtk_text_iter_ends_line (&new_insert))
5531           gtk_text_iter_forward_to_line_end (&new_insert);
5532       move_cursor (text_view, &new_insert, extend_selection);
5533     }
5534   else
5535     {
5536       gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
5537
5538       oldval = adj->value;
5539       newval = adj->value;
5540
5541       newval += count * adj->page_increment;
5542
5543       set_adjustment_clamped (adj, newval);
5544       cursor_x_pos += adj->value - oldval;
5545
5546       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5547       clamp_iter_onscreen (text_view, &new_insert);
5548       move_cursor (text_view, &new_insert, extend_selection);
5549
5550       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5551     }
5552
5553   /*  FIXME for lines shorter than the overall widget width, this results in a
5554    *  "bounce" effect as we scroll to the right of the widget, then scroll
5555    *  back to get the end of the line onscreen.
5556    *      http://bugzilla.gnome.org/show_bug.cgi?id=68963
5557    */
5558   
5559   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5560    * only guarantees 1 pixel onscreen.
5561    */
5562   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5563   gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5564
5565   return !gtk_text_iter_equal (&old_insert, &new_insert);
5566 }
5567
5568 static gboolean
5569 whitespace (gunichar ch, gpointer user_data)
5570 {
5571   return (ch == ' ' || ch == '\t');
5572 }
5573
5574 static gboolean
5575 not_whitespace (gunichar ch, gpointer user_data)
5576 {
5577   return !whitespace (ch, user_data);
5578 }
5579
5580 static gboolean
5581 find_whitepace_region (const GtkTextIter *center,
5582                        GtkTextIter *start, GtkTextIter *end)
5583 {
5584   *start = *center;
5585   *end = *center;
5586
5587   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
5588     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
5589   if (whitespace (gtk_text_iter_get_char (end), NULL))
5590     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
5591
5592   return !gtk_text_iter_equal (start, end);
5593 }
5594
5595 static void
5596 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
5597                                 const gchar *str)
5598 {
5599   if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
5600                                                      text_view->editable))
5601     {
5602       gtk_widget_error_bell (GTK_WIDGET (text_view));
5603     }
5604 }
5605
5606 static void
5607 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
5608                                   GtkDeleteType  type,
5609                                   gint           count)
5610 {
5611   GtkTextIter insert;
5612   GtkTextIter start;
5613   GtkTextIter end;
5614   gboolean leave_one = FALSE;
5615
5616   gtk_text_view_reset_im_context (text_view);
5617
5618   if (type == GTK_DELETE_CHARS)
5619     {
5620       /* Char delete deletes the selection, if one exists */
5621       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5622                                             text_view->editable))
5623         return;
5624     }
5625
5626   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5627                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5628
5629   start = insert;
5630   end = insert;
5631
5632   switch (type)
5633     {
5634     case GTK_DELETE_CHARS:
5635       gtk_text_iter_forward_cursor_positions (&end, count);
5636       break;
5637
5638     case GTK_DELETE_WORD_ENDS:
5639       if (count > 0)
5640         gtk_text_iter_forward_word_ends (&end, count);
5641       else if (count < 0)
5642         gtk_text_iter_backward_word_starts (&start, 0 - count);
5643       break;
5644
5645     case GTK_DELETE_WORDS:
5646       break;
5647
5648     case GTK_DELETE_DISPLAY_LINE_ENDS:
5649       break;
5650
5651     case GTK_DELETE_DISPLAY_LINES:
5652       break;
5653
5654     case GTK_DELETE_PARAGRAPH_ENDS:
5655       if (count > 0)
5656         {
5657           /* If we're already at a newline, we need to
5658            * simply delete that newline, instead of
5659            * moving to the next one.
5660            */
5661           if (gtk_text_iter_ends_line (&end))
5662             {
5663               gtk_text_iter_forward_line (&end);
5664               --count;
5665             }
5666
5667           while (count > 0)
5668             {
5669               if (!gtk_text_iter_forward_to_line_end (&end))
5670                 break;
5671
5672               --count;
5673             }
5674         }
5675       else if (count < 0)
5676         {
5677           if (gtk_text_iter_starts_line (&start))
5678             {
5679               gtk_text_iter_backward_line (&start);
5680               if (!gtk_text_iter_ends_line (&end))
5681                 gtk_text_iter_forward_to_line_end (&start);
5682             }
5683           else
5684             {
5685               gtk_text_iter_set_line_offset (&start, 0);
5686             }
5687           ++count;
5688
5689           gtk_text_iter_backward_lines (&start, -count);
5690         }
5691       break;
5692
5693     case GTK_DELETE_PARAGRAPHS:
5694       if (count > 0)
5695         {
5696           gtk_text_iter_set_line_offset (&start, 0);
5697           gtk_text_iter_forward_to_line_end (&end);
5698
5699           /* Do the lines beyond the first. */
5700           while (count > 1)
5701             {
5702               gtk_text_iter_forward_to_line_end (&end);
5703
5704               --count;
5705             }
5706         }
5707
5708       /* FIXME negative count? */
5709
5710       break;
5711
5712     case GTK_DELETE_WHITESPACE:
5713       {
5714         find_whitepace_region (&insert, &start, &end);
5715       }
5716       break;
5717
5718     default:
5719       break;
5720     }
5721
5722   if (!gtk_text_iter_equal (&start, &end))
5723     {
5724       gtk_text_buffer_begin_user_action (get_buffer (text_view));
5725
5726       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
5727                                               text_view->editable))
5728         {
5729           if (leave_one)
5730             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
5731                                                           " ", 1,
5732                                                           text_view->editable);
5733         }
5734       else
5735         {
5736           gtk_widget_error_bell (GTK_WIDGET (text_view));
5737         }
5738
5739       gtk_text_buffer_end_user_action (get_buffer (text_view));
5740       gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5741
5742       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5743       gtk_text_view_scroll_mark_onscreen (text_view,
5744                                           gtk_text_buffer_get_insert (get_buffer (text_view)));
5745     }
5746   else
5747     {
5748       gtk_widget_error_bell (GTK_WIDGET (text_view));
5749     }
5750 }
5751
5752 static void
5753 gtk_text_view_backspace (GtkTextView *text_view)
5754 {
5755   GtkTextIter insert;
5756
5757   gtk_text_view_reset_im_context (text_view);
5758
5759   /* Backspace deletes the selection, if one exists */
5760   if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5761                                         text_view->editable))
5762     return;
5763
5764   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5765                                     &insert,
5766                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5767
5768   if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
5769                                  TRUE, text_view->editable))
5770     {
5771       gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5772       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5773       gtk_text_view_scroll_mark_onscreen (text_view,
5774                                           gtk_text_buffer_get_insert (get_buffer (text_view)));
5775     }
5776   else
5777     {
5778       gtk_widget_error_bell (GTK_WIDGET (text_view));
5779     }
5780 }
5781
5782 static void
5783 gtk_text_view_cut_clipboard (GtkTextView *text_view)
5784 {
5785   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5786                                                       GDK_SELECTION_CLIPBOARD);
5787   
5788   gtk_text_buffer_cut_clipboard (get_buffer (text_view),
5789                                  clipboard,
5790                                  text_view->editable);
5791   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5792   gtk_text_view_scroll_mark_onscreen (text_view,
5793                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
5794 }
5795
5796 static void
5797 gtk_text_view_copy_clipboard (GtkTextView *text_view)
5798 {
5799   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5800                                                       GDK_SELECTION_CLIPBOARD);
5801   
5802   gtk_text_buffer_copy_clipboard (get_buffer (text_view),
5803                                   clipboard);
5804
5805   /* on copy do not scroll, we are already onscreen */
5806 }
5807
5808 static void
5809 gtk_text_view_paste_clipboard (GtkTextView *text_view)
5810 {
5811   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5812                                                       GDK_SELECTION_CLIPBOARD);
5813   
5814   gtk_text_buffer_paste_clipboard (get_buffer (text_view),
5815                                    clipboard,
5816                                    NULL,
5817                                    text_view->editable);
5818 }
5819
5820 static void
5821 gtk_text_view_paste_done_handler (GtkTextBuffer *buffer,
5822                                   GtkClipboard  *clipboard,
5823                                   gpointer       data)
5824 {
5825   GtkTextView *text_view = data;
5826   GtkTextViewPrivate *priv;
5827
5828   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
5829
5830   if (priv->scroll_after_paste)
5831     {
5832       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5833       gtk_text_view_scroll_mark_onscreen (text_view, gtk_text_buffer_get_insert (buffer));
5834     }
5835
5836   priv->scroll_after_paste = TRUE;
5837 }
5838
5839 static void
5840 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
5841 {
5842   if (text_view->text_window)
5843     text_window_invalidate_cursors (text_view->text_window);
5844
5845   text_view->overwrite_mode = !text_view->overwrite_mode;
5846
5847   if (text_view->layout)
5848     gtk_text_layout_set_overwrite_mode (text_view->layout,
5849                                         text_view->overwrite_mode && text_view->editable);
5850
5851   if (text_view->text_window)
5852     text_window_invalidate_cursors (text_view->text_window);
5853
5854   gtk_text_view_pend_cursor_blink (text_view);
5855
5856   g_object_notify (G_OBJECT (text_view), "overwrite");
5857 }
5858
5859 /**
5860  * gtk_text_view_get_overwrite:
5861  * @text_view: a #GtkTextView
5862  *
5863  * Returns whether the #GtkTextView is in overwrite mode or not.
5864  *
5865  * Return value: whether @text_view is in overwrite mode or not.
5866  * 
5867  * Since: 2.4
5868  **/
5869 gboolean
5870 gtk_text_view_get_overwrite (GtkTextView *text_view)
5871 {
5872   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5873
5874   return text_view->overwrite_mode;
5875 }
5876
5877 /**
5878  * gtk_text_view_set_overwrite:
5879  * @text_view: a #GtkTextView
5880  * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
5881  *
5882  * Changes the #GtkTextView overwrite mode.
5883  *
5884  * Since: 2.4
5885  **/
5886 void
5887 gtk_text_view_set_overwrite (GtkTextView *text_view,
5888                              gboolean     overwrite)
5889 {
5890   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5891   overwrite = overwrite != FALSE;
5892
5893   if (text_view->overwrite_mode != overwrite)
5894     gtk_text_view_toggle_overwrite (text_view);
5895 }
5896
5897 /**
5898  * gtk_text_view_set_accepts_tab:
5899  * @text_view: A #GtkTextView
5900  * @accepts_tab: %TRUE if pressing the Tab key should insert a tab 
5901  *    character, %FALSE, if pressing the Tab key should move the 
5902  *    keyboard focus.
5903  * 
5904  * Sets the behavior of the text widget when the Tab key is pressed. 
5905  * If @accepts_tab is %TRUE, a tab character is inserted. If @accepts_tab 
5906  * is %FALSE the keyboard focus is moved to the next widget in the focus 
5907  * chain.
5908  * 
5909  * Since: 2.4
5910  **/
5911 void
5912 gtk_text_view_set_accepts_tab (GtkTextView *text_view,
5913                                gboolean     accepts_tab)
5914 {
5915   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5916
5917   accepts_tab = accepts_tab != FALSE;
5918
5919   if (text_view->accepts_tab != accepts_tab)
5920     {
5921       text_view->accepts_tab = accepts_tab;
5922
5923       g_object_notify (G_OBJECT (text_view), "accepts-tab");
5924     }
5925 }
5926
5927 /**
5928  * gtk_text_view_get_accepts_tab:
5929  * @text_view: A #GtkTextView
5930  * 
5931  * Returns whether pressing the Tab key inserts a tab characters.
5932  * gtk_text_view_set_accepts_tab().
5933  * 
5934  * Return value: %TRUE if pressing the Tab key inserts a tab character, 
5935  *   %FALSE if pressing the Tab key moves the keyboard focus.
5936  * 
5937  * Since: 2.4
5938  **/
5939 gboolean
5940 gtk_text_view_get_accepts_tab (GtkTextView *text_view)
5941 {
5942   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5943
5944   return text_view->accepts_tab;
5945 }
5946
5947 static void
5948 gtk_text_view_compat_move_focus (GtkTextView     *text_view,
5949                                  GtkDirectionType direction_type)
5950 {
5951   GSignalInvocationHint *hint = g_signal_get_invocation_hint (text_view);
5952
5953   /*  as of GTK+ 2.12, the "move-focus" signal has been moved to GtkWidget,
5954    *  the evil code below makes sure that both emitting the signal and
5955    *  calling the virtual function directly continue to work as expetcted
5956    */
5957
5958   if (hint->signal_id == g_signal_lookup ("move-focus", GTK_TYPE_WIDGET))
5959     {
5960       /*  if this is a signal emission, chain up  */
5961
5962       gboolean retval;
5963
5964       g_signal_chain_from_overridden_handler (text_view,
5965                                               direction_type, &retval);
5966     }
5967   else
5968     {
5969       /*  otherwise emit the signal, since somebody called the virtual
5970        *  function directly
5971        */
5972
5973       g_signal_emit_by_name (text_view, "move-focus", direction_type);
5974     }
5975 }
5976
5977 /*
5978  * Selections
5979  */
5980
5981 static void
5982 gtk_text_view_unselect (GtkTextView *text_view)
5983 {
5984   GtkTextIter insert;
5985
5986   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5987                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5988
5989   gtk_text_buffer_move_mark (get_buffer (text_view),
5990                              gtk_text_buffer_get_selection_bound (get_buffer (text_view)),
5991                              &insert);
5992 }
5993
5994 static void
5995 get_iter_at_pointer (GtkTextView *text_view,
5996                      GtkTextIter *iter,
5997                      gint        *x,
5998                      gint        *y)
5999 {
6000   gint xcoord, ycoord;
6001   GdkModifierType state;
6002
6003   gdk_window_get_pointer (text_view->text_window->bin_window,
6004                           &xcoord, &ycoord, &state);
6005   
6006   gtk_text_layout_get_iter_at_pixel (text_view->layout,
6007                                      iter,
6008                                      xcoord + text_view->xoffset,
6009                                      ycoord + text_view->yoffset);
6010   if (x)
6011     *x = xcoord;
6012
6013   if (y)
6014     *y = ycoord;
6015 }
6016
6017 static void
6018 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
6019                                  const gchar *mark_name)
6020 {
6021   GtkTextIter newplace;
6022   GtkTextMark *mark;
6023
6024   get_iter_at_pointer (text_view, &newplace, NULL, NULL);
6025   
6026   mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
6027   
6028   /* This may invalidate the layout */
6029   DV(g_print (G_STRLOC": move mark\n"));
6030   
6031   gtk_text_buffer_move_mark (get_buffer (text_view),
6032                              mark,
6033                              &newplace);
6034   
6035   DV(g_print (G_STRLOC": scrolling onscreen\n"));
6036   gtk_text_view_scroll_mark_onscreen (text_view, mark);
6037
6038   DV (g_print ("first validate idle leaving %s is %d\n",
6039                G_STRLOC, text_view->first_validate_idle));
6040 }
6041
6042 static gboolean
6043 selection_scan_timeout (gpointer data)
6044 {
6045   GtkTextView *text_view;
6046
6047   text_view = GTK_TEXT_VIEW (data);
6048
6049   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
6050   gtk_text_view_scroll_mark_onscreen (text_view, 
6051                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
6052
6053   return TRUE; /* remain installed. */
6054 }
6055
6056 #define UPPER_OFFSET_ANCHOR 0.8
6057 #define LOWER_OFFSET_ANCHOR 0.2
6058
6059 static gboolean
6060 check_scroll (gdouble offset, GtkAdjustment *adj)
6061 {
6062   if ((offset > UPPER_OFFSET_ANCHOR &&
6063        adj->value + adj->page_size < adj->upper) ||
6064       (offset < LOWER_OFFSET_ANCHOR &&
6065        adj->value > adj->lower))
6066     return TRUE;
6067
6068   return FALSE;
6069 }
6070
6071 static gint
6072 drag_scan_timeout (gpointer data)
6073 {
6074   GtkTextView *text_view;
6075   GtkTextIter newplace;
6076   gint x, y, width, height;
6077   gdouble pointer_xoffset, pointer_yoffset;
6078
6079   text_view = GTK_TEXT_VIEW (data);
6080
6081   get_iter_at_pointer (text_view, &newplace, &x, &y);
6082   gdk_drawable_get_size (text_view->text_window->bin_window, &width, &height);
6083
6084   gtk_text_buffer_move_mark (get_buffer (text_view),
6085                              text_view->dnd_mark,
6086                              &newplace);
6087
6088   pointer_xoffset = (gdouble) x / width;
6089   pointer_yoffset = (gdouble) y / height;
6090
6091   if (check_scroll (pointer_xoffset, text_view->hadjustment) ||
6092       check_scroll (pointer_yoffset, text_view->vadjustment))
6093     {
6094       /* do not make offsets surpass lower nor upper anchors, this makes
6095        * scrolling speed relative to the distance of the pointer to the
6096        * anchors when it moves beyond them.
6097        */
6098       pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
6099       pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
6100
6101       gtk_text_view_scroll_to_mark (text_view,
6102                                     text_view->dnd_mark,
6103                                     0., TRUE, pointer_xoffset, pointer_yoffset);
6104     }
6105
6106   return TRUE;
6107 }
6108
6109 typedef enum 
6110 {
6111   SELECT_CHARACTERS,
6112   SELECT_WORDS,
6113   SELECT_LINES
6114 } SelectionGranularity;
6115
6116 /*
6117  * Move @start and @end to the boundaries of the selection unit (indicated by 
6118  * @granularity) which contained @start initially.
6119  * If the selction unit is SELECT_WORDS and @start is not contained in a word
6120  * the selection is extended to all the white spaces between the end of the 
6121  * word preceding @start and the start of the one following.
6122  */
6123 static void
6124 extend_selection (GtkTextView *text_view, 
6125                   SelectionGranularity granularity, 
6126                   GtkTextIter *start, 
6127                   GtkTextIter *end)
6128 {
6129   *end = *start;
6130
6131   if (granularity == SELECT_WORDS) 
6132     {
6133       if (gtk_text_iter_inside_word (start))
6134         {
6135           if (!gtk_text_iter_starts_word (start))
6136             gtk_text_iter_backward_visible_word_start (start);
6137           
6138           if (!gtk_text_iter_ends_word (end))
6139             {
6140               if (!gtk_text_iter_forward_visible_word_end (end))
6141                 gtk_text_iter_forward_to_end (end);
6142             }
6143         }
6144       else
6145         {
6146           GtkTextIter tmp;
6147
6148           tmp = *start;
6149           if (gtk_text_iter_backward_visible_word_start (&tmp))
6150             gtk_text_iter_forward_visible_word_end (&tmp);
6151
6152           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
6153             *start = tmp;
6154           else
6155             gtk_text_iter_set_line_offset (start, 0);
6156
6157           tmp = *end;
6158           if (!gtk_text_iter_forward_visible_word_end (&tmp))
6159             gtk_text_iter_forward_to_end (&tmp);
6160
6161           if (gtk_text_iter_ends_word (&tmp))
6162             gtk_text_iter_backward_visible_word_start (&tmp);
6163
6164           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
6165             *end = tmp;
6166           else
6167             gtk_text_iter_forward_to_line_end (end);
6168         }
6169     }
6170   else if (granularity == SELECT_LINES) 
6171     {
6172       if (gtk_text_view_starts_display_line (text_view, start))
6173         {
6174           /* If on a display line boundary, we assume the user
6175            * clicked off the end of a line and we therefore select
6176            * the line before the boundary.
6177            */
6178           gtk_text_view_backward_display_line_start (text_view, start);
6179         }
6180       else
6181         {
6182           /* start isn't on the start of a line, so we move it to the
6183            * start, and move end to the end unless it's already there.
6184            */
6185           gtk_text_view_backward_display_line_start (text_view, start);
6186           
6187           if (!gtk_text_view_starts_display_line (text_view, end))
6188             gtk_text_view_forward_display_line_end (text_view, end);
6189         }
6190     }
6191 }
6192  
6193
6194 typedef struct
6195 {
6196   SelectionGranularity granularity;
6197   GtkTextMark *orig_start;
6198   GtkTextMark *orig_end;
6199 } SelectionData;
6200
6201 static void
6202 selection_data_free (SelectionData *data)
6203 {
6204   if (data->orig_start != NULL)
6205     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_start),
6206                                  data->orig_start);
6207   if (data->orig_end != NULL)
6208     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_end),
6209                                  data->orig_end);
6210   g_free (data);
6211 }
6212
6213 static gint
6214 selection_motion_event_handler (GtkTextView    *text_view, 
6215                                 GdkEventMotion *event, 
6216                                 SelectionData  *data)
6217 {
6218   gdk_event_request_motions (event);
6219
6220   if (data->granularity == SELECT_CHARACTERS) 
6221     {
6222       move_mark_to_pointer_and_scroll (text_view, "insert");
6223     }
6224   else 
6225     {
6226       GtkTextIter cursor, start, end;
6227       GtkTextIter orig_start, orig_end;
6228       GtkTextBuffer *buffer;
6229       
6230       buffer = get_buffer (text_view);
6231
6232       gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
6233       gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
6234
6235       get_iter_at_pointer (text_view, &cursor, NULL, NULL);
6236       
6237       start = cursor;
6238       extend_selection (text_view, data->granularity, &start, &end);
6239
6240       /* either the selection extends to the front, or end (or not) */
6241       if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
6242         gtk_text_buffer_select_range (buffer, &start, &orig_end);
6243       else
6244         gtk_text_buffer_select_range (buffer, &end, &orig_start);
6245
6246       gtk_text_view_scroll_mark_onscreen (text_view, 
6247                                           gtk_text_buffer_get_insert (buffer));
6248     }
6249
6250   /* If we had to scroll offscreen, insert a timeout to do so
6251    * again. Note that in the timeout, even if the mouse doesn't
6252    * move, due to this scroll xoffset/yoffset will have changed
6253    * and we'll need to scroll again.
6254    */
6255   if (text_view->scroll_timeout != 0) /* reset on every motion event */
6256     g_source_remove (text_view->scroll_timeout);
6257   
6258   text_view->scroll_timeout =
6259     gdk_threads_add_timeout (50, selection_scan_timeout, text_view);
6260
6261   return TRUE;
6262 }
6263
6264 static void
6265 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
6266                                     const GtkTextIter *iter,
6267                                     GdkEventButton    *button)
6268 {
6269   GtkTextIter cursor, ins, bound;
6270   GtkTextIter orig_start, orig_end;
6271   GtkTextBuffer *buffer;
6272   SelectionData *data;
6273
6274   if (text_view->selection_drag_handler != 0)
6275     return;
6276   
6277   data = g_new0 (SelectionData, 1);
6278
6279   if (button->type == GDK_2BUTTON_PRESS)
6280     data->granularity = SELECT_WORDS;
6281   else if (button->type == GDK_3BUTTON_PRESS)
6282     data->granularity = SELECT_LINES;
6283   else 
6284     data->granularity = SELECT_CHARACTERS;
6285
6286   gtk_grab_add (GTK_WIDGET (text_view));
6287
6288   buffer = get_buffer (text_view);
6289   
6290   cursor = *iter;
6291   ins = cursor;
6292   
6293   extend_selection (text_view, data->granularity, &ins, &bound);
6294   orig_start = ins;
6295   orig_end = bound;
6296
6297   if (button->state & GDK_SHIFT_MASK)
6298     {
6299       /* Extend selection */
6300       GtkTextIter old_ins, old_bound;
6301       GtkTextIter old_start, old_end;
6302
6303       gtk_text_buffer_get_iter_at_mark (buffer, &old_ins, gtk_text_buffer_get_insert (buffer));
6304       gtk_text_buffer_get_iter_at_mark (buffer, &old_bound, gtk_text_buffer_get_selection_bound (buffer));
6305       old_start = old_ins;
6306       old_end = old_bound;
6307       gtk_text_iter_order (&old_start, &old_end);
6308       
6309       /* move the front cursor, if the mouse is in front of the selection. Should the
6310        * cursor however be inside the selection (this happens on tripple click) then we
6311        * move the side which was last moved (current insert mark) */
6312       if (gtk_text_iter_compare (&cursor, &old_start) <= 0 ||
6313           (gtk_text_iter_compare (&cursor, &old_end) < 0 && 
6314            gtk_text_iter_compare (&old_ins, &old_bound) <= 0))
6315         {
6316           bound = old_end;
6317           orig_start = old_end;
6318           orig_end = old_end;
6319         }
6320       else
6321         {
6322           ins = bound;
6323           bound = old_start;
6324           orig_end = bound;
6325           orig_start = bound;
6326         }
6327     }
6328
6329   gtk_text_buffer_select_range (buffer, &ins, &bound);
6330
6331   gtk_text_iter_order (&orig_start, &orig_end);
6332   data->orig_start = gtk_text_buffer_create_mark (buffer, NULL,
6333                                                   &orig_start, TRUE);
6334   data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
6335                                                 &orig_end, TRUE);
6336
6337   gtk_text_view_check_cursor_blink (text_view);
6338
6339   text_view->selection_drag_handler = g_signal_connect_data (text_view,
6340                                                              "motion-notify-event",
6341                                                              G_CALLBACK (selection_motion_event_handler),
6342                                                              data,
6343                                                              (GClosureNotify) selection_data_free, 0);  
6344 }
6345
6346 /* returns whether we were really dragging */
6347 static gboolean
6348 gtk_text_view_end_selection_drag (GtkTextView    *text_view) 
6349 {
6350   if (text_view->selection_drag_handler == 0)
6351     return FALSE;
6352
6353   g_signal_handler_disconnect (text_view, text_view->selection_drag_handler);
6354   text_view->selection_drag_handler = 0;
6355
6356   if (text_view->scroll_timeout != 0)
6357     {
6358       g_source_remove (text_view->scroll_timeout);
6359       text_view->scroll_timeout = 0;
6360     }
6361
6362   gtk_grab_remove (GTK_WIDGET (text_view));
6363
6364   return TRUE;
6365 }
6366
6367 /*
6368  * Layout utils
6369  */
6370
6371 static void
6372 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
6373                                          GtkTextAttributes  *values,
6374                                          GtkStyle           *style)
6375 {
6376   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
6377   values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
6378
6379   if (values->font)
6380     pango_font_description_free (values->font);
6381
6382   values->font = pango_font_description_copy (style->font_desc);
6383 }
6384
6385 static void
6386 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
6387 {
6388   if (text_view->layout)
6389     {
6390       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
6391       GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
6392       GtkTextDirection new_cursor_dir;
6393       GtkTextDirection new_keyboard_dir;
6394       gboolean split_cursor;
6395
6396       g_object_get (settings,
6397                     "gtk-split-cursor", &split_cursor,
6398                     NULL);
6399       
6400       if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
6401         new_keyboard_dir = GTK_TEXT_DIR_RTL;
6402       else
6403         new_keyboard_dir  = GTK_TEXT_DIR_LTR;
6404   
6405       if (split_cursor)
6406         new_cursor_dir = GTK_TEXT_DIR_NONE;
6407       else
6408         new_cursor_dir = new_keyboard_dir;
6409       
6410       gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
6411       gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
6412     }
6413 }
6414
6415 static void
6416 gtk_text_view_ensure_layout (GtkTextView *text_view)
6417 {
6418   GtkWidget *widget;
6419
6420   widget = GTK_WIDGET (text_view);
6421
6422   if (text_view->layout == NULL)
6423     {
6424       GtkTextAttributes *style;
6425       PangoContext *ltr_context, *rtl_context;
6426       GSList *tmp_list;
6427
6428       DV(g_print(G_STRLOC"\n"));
6429       
6430       text_view->layout = gtk_text_layout_new ();
6431
6432       g_signal_connect (text_view->layout,
6433                         "invalidated",
6434                         G_CALLBACK (invalidated_handler),
6435                         text_view);
6436
6437       g_signal_connect (text_view->layout,
6438                         "changed",
6439                         G_CALLBACK (changed_handler),
6440                         text_view);
6441
6442       g_signal_connect (text_view->layout,
6443                         "allocate-child",
6444                         G_CALLBACK (gtk_text_view_child_allocated),
6445                         text_view);
6446       
6447       if (get_buffer (text_view))
6448         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
6449
6450       if ((gtk_widget_has_focus (widget) && text_view->cursor_visible))
6451         gtk_text_view_pend_cursor_blink (text_view);
6452       else
6453         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
6454
6455       gtk_text_layout_set_overwrite_mode (text_view->layout,
6456                                           text_view->overwrite_mode && text_view->editable);
6457
6458       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6459       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
6460       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6461       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
6462
6463       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
6464
6465       g_object_unref (ltr_context);
6466       g_object_unref (rtl_context);
6467
6468       gtk_text_view_check_keymap_direction (text_view);
6469
6470       style = gtk_text_attributes_new ();
6471
6472       gtk_widget_ensure_style (widget);
6473       gtk_text_view_set_attributes_from_style (text_view,
6474                                                style, widget->style);
6475
6476       style->pixels_above_lines = text_view->pixels_above_lines;
6477       style->pixels_below_lines = text_view->pixels_below_lines;
6478       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
6479       style->left_margin = text_view->left_margin;
6480       style->right_margin = text_view->right_margin;
6481       style->indent = text_view->indent;
6482       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
6483
6484       style->wrap_mode = text_view->wrap_mode;
6485       style->justification = text_view->justify;
6486       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
6487
6488       gtk_text_layout_set_default_style (text_view->layout, style);
6489
6490       gtk_text_attributes_unref (style);
6491
6492       /* Set layout for all anchored children */
6493
6494       tmp_list = text_view->children;
6495       while (tmp_list != NULL)
6496         {
6497           GtkTextViewChild *vc = tmp_list->data;
6498
6499           if (vc->anchor)
6500             {
6501               gtk_text_anchored_child_set_layout (vc->widget,
6502                                                   text_view->layout);
6503               /* vc may now be invalid! */
6504             }
6505
6506           tmp_list = g_slist_next (tmp_list);
6507         }
6508
6509       gtk_text_view_invalidate (text_view);
6510     }
6511 }
6512
6513 /**
6514  * gtk_text_view_get_default_attributes:
6515  * @text_view: a #GtkTextView
6516  * 
6517  * Obtains a copy of the default text attributes. These are the
6518  * attributes used for text unless a tag overrides them.
6519  * You'd typically pass the default attributes in to
6520  * gtk_text_iter_get_attributes() in order to get the
6521  * attributes in effect at a given text position.
6522  *
6523  * The return value is a copy owned by the caller of this function,
6524  * and should be freed.
6525  * 
6526  * Return value: a new #GtkTextAttributes
6527  **/
6528 GtkTextAttributes*
6529 gtk_text_view_get_default_attributes (GtkTextView *text_view)
6530 {
6531   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
6532   
6533   gtk_text_view_ensure_layout (text_view);
6534
6535   return gtk_text_attributes_copy (text_view->layout->default_style);
6536 }
6537
6538 static void
6539 gtk_text_view_destroy_layout (GtkTextView *text_view)
6540 {
6541   if (text_view->layout)
6542     {
6543       GSList *tmp_list;
6544
6545       gtk_text_view_remove_validate_idles (text_view);
6546
6547       g_signal_handlers_disconnect_by_func (text_view->layout,
6548                                             invalidated_handler,
6549                                             text_view);
6550       g_signal_handlers_disconnect_by_func (text_view->layout,
6551                                             changed_handler,
6552                                             text_view);
6553
6554       /* Remove layout from all anchored children */
6555       tmp_list = text_view->children;
6556       while (tmp_list != NULL)
6557         {
6558           GtkTextViewChild *vc = tmp_list->data;
6559
6560           if (vc->anchor)
6561             {
6562               gtk_text_anchored_child_set_layout (vc->widget, NULL);
6563               /* vc may now be invalid! */
6564             }
6565
6566           tmp_list = g_slist_next (tmp_list);
6567         }
6568
6569       gtk_text_view_stop_cursor_blink (text_view);
6570       gtk_text_view_end_selection_drag (text_view);
6571
6572       g_object_unref (text_view->layout);
6573       text_view->layout = NULL;
6574     }
6575 }
6576
6577 static void
6578 gtk_text_view_reset_im_context (GtkTextView *text_view)
6579 {
6580   if (text_view->need_im_reset)
6581     {
6582       text_view->need_im_reset = FALSE;
6583       gtk_im_context_reset (text_view->im_context);
6584     }
6585 }
6586
6587 /*
6588  * DND feature
6589  */
6590
6591 static void
6592 drag_begin_cb (GtkWidget      *widget,
6593                GdkDragContext *context,
6594                gpointer        data)
6595 {
6596   GtkTextView   *text_view = GTK_TEXT_VIEW (widget);
6597   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6598   GtkTextIter    start;
6599   GtkTextIter    end;
6600   GdkPixmap     *pixmap = NULL;
6601
6602   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
6603
6604   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6605     pixmap = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
6606
6607   if (pixmap)
6608     {
6609       gtk_drag_set_icon_pixmap (context,
6610                                 gdk_drawable_get_colormap (pixmap),
6611                                 pixmap,
6612                                 NULL,
6613                                 -2, -2);
6614       g_object_unref (pixmap);
6615     }
6616   else
6617     {
6618       gtk_drag_set_icon_default (context);
6619     }
6620 }
6621
6622 static void
6623 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
6624                                    const GtkTextIter *iter,
6625                                    GdkEventMotion    *event)
6626 {
6627   GtkTargetList *target_list;
6628
6629   text_view->drag_start_x = -1;
6630   text_view->drag_start_y = -1;
6631   text_view->pending_place_cursor_button = 0;
6632
6633   target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
6634
6635   g_signal_connect (text_view, "drag-begin",
6636                     G_CALLBACK (drag_begin_cb), NULL);
6637   gtk_drag_begin (GTK_WIDGET (text_view), target_list,
6638                   GDK_ACTION_COPY | GDK_ACTION_MOVE,
6639                   1, (GdkEvent*)event);
6640 }
6641
6642 static void
6643 gtk_text_view_drag_begin (GtkWidget        *widget,
6644                           GdkDragContext   *context)
6645 {
6646   /* do nothing */
6647 }
6648
6649 static void
6650 gtk_text_view_drag_end (GtkWidget        *widget,
6651                         GdkDragContext   *context)
6652 {
6653 }
6654
6655 static void
6656 gtk_text_view_drag_data_get (GtkWidget        *widget,
6657                              GdkDragContext   *context,
6658                              GtkSelectionData *selection_data,
6659                              guint             info,
6660                              guint             time)
6661 {
6662   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6663   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6664
6665   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6666     {
6667       gtk_selection_data_set (selection_data,
6668                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
6669                               8, /* bytes */
6670                               (void*)&buffer,
6671                               sizeof (buffer));
6672     }
6673   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6674     {
6675       GtkTextIter start;
6676       GtkTextIter end;
6677       guint8 *str = NULL;
6678       gsize len;
6679
6680       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6681         {
6682           /* Extract the selected text */
6683           str = gtk_text_buffer_serialize (buffer, buffer,
6684                                            selection_data->target,
6685                                            &start, &end,
6686                                            &len);
6687         }
6688
6689       if (str)
6690         {
6691           gtk_selection_data_set (selection_data,
6692                                   selection_data->target,
6693                                   8, /* bytes */
6694                                   (guchar *) str, len);
6695           g_free (str);
6696         }
6697     }
6698   else
6699     {
6700       GtkTextIter start;
6701       GtkTextIter end;
6702       gchar *str = NULL;
6703
6704       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6705         {
6706           /* Extract the selected text */
6707           str = gtk_text_iter_get_visible_text (&start, &end);
6708         }
6709
6710       if (str)
6711         {
6712           gtk_selection_data_set_text (selection_data, str, -1);
6713           g_free (str);
6714         }
6715     }
6716 }
6717
6718 static void
6719 gtk_text_view_drag_data_delete (GtkWidget        *widget,
6720                                 GdkDragContext   *context)
6721 {
6722   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
6723                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
6724 }
6725
6726 static void
6727 gtk_text_view_drag_leave (GtkWidget        *widget,
6728                           GdkDragContext   *context,
6729                           guint             time)
6730 {
6731   GtkTextView *text_view;
6732
6733   text_view = GTK_TEXT_VIEW (widget);
6734
6735   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6736   
6737   if (text_view->scroll_timeout != 0)
6738     g_source_remove (text_view->scroll_timeout);
6739
6740   text_view->scroll_timeout = 0;
6741 }
6742
6743 static gboolean
6744 gtk_text_view_drag_motion (GtkWidget        *widget,
6745                            GdkDragContext   *context,
6746                            gint              x,
6747                            gint              y,
6748                            guint             time)
6749 {
6750   GtkTextIter newplace;
6751   GtkTextView *text_view;
6752   GtkTextIter start;
6753   GtkTextIter end;
6754   GdkRectangle target_rect;
6755   gint bx, by;
6756   GdkAtom target;
6757   GdkDragAction suggested_action = 0;
6758   
6759   text_view = GTK_TEXT_VIEW (widget);
6760
6761   target_rect = text_view->text_window->allocation;
6762   
6763   if (x < target_rect.x ||
6764       y < target_rect.y ||
6765       x > (target_rect.x + target_rect.width) ||
6766       y > (target_rect.y + target_rect.height))
6767     return FALSE; /* outside the text window, allow parent widgets to handle event */
6768
6769   gtk_text_view_window_to_buffer_coords (text_view,
6770                                          GTK_TEXT_WINDOW_WIDGET,
6771                                          x, y,
6772                                          &bx, &by);
6773
6774   gtk_text_layout_get_iter_at_pixel (text_view->layout,
6775                                      &newplace,
6776                                      bx, by);  
6777
6778   target = gtk_drag_dest_find_target (widget, context,
6779                                       gtk_drag_dest_get_target_list (widget));
6780
6781   if (target == GDK_NONE)
6782     {
6783       /* can't accept any of the offered targets */
6784     }                                 
6785   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6786                                                  &start, &end) &&
6787            gtk_text_iter_compare (&newplace, &start) >= 0 &&
6788            gtk_text_iter_compare (&newplace, &end) <= 0)
6789     {
6790       /* We're inside the selection. */
6791     }
6792   else
6793     {      
6794       if (gtk_text_iter_can_insert (&newplace, text_view->editable))
6795         {
6796           GtkWidget *source_widget;
6797           
6798           suggested_action = context->suggested_action;
6799           
6800           source_widget = gtk_drag_get_source_widget (context);
6801           
6802           if (source_widget == widget)
6803             {
6804               /* Default to MOVE, unless the user has
6805                * pressed ctrl or alt to affect available actions
6806                */
6807               if ((context->actions & GDK_ACTION_MOVE) != 0)
6808                 suggested_action = GDK_ACTION_MOVE;
6809             }
6810         }
6811       else
6812         {
6813           /* Can't drop here. */
6814         }
6815     }
6816
6817   if (suggested_action != 0)
6818     {
6819       gtk_text_mark_set_visible (text_view->dnd_mark,
6820                                  text_view->cursor_visible);
6821       
6822       gdk_drag_status (context, suggested_action, time);
6823     }
6824   else
6825     {
6826       gdk_drag_status (context, 0, time);
6827       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6828     }
6829       
6830   if (!text_view->scroll_timeout)
6831     text_view->scroll_timeout =
6832       gdk_threads_add_timeout (100, drag_scan_timeout, text_view);
6833
6834   /* TRUE return means don't propagate the drag motion to parent
6835    * widgets that may also be drop sites.
6836    */
6837   return TRUE;
6838 }
6839
6840 static gboolean
6841 gtk_text_view_drag_drop (GtkWidget        *widget,
6842                          GdkDragContext   *context,
6843                          gint              x,
6844                          gint              y,
6845                          guint             time)
6846 {
6847   GtkTextView *text_view;
6848   GtkTextIter drop_point;
6849   GdkAtom target = GDK_NONE;
6850   
6851   text_view = GTK_TEXT_VIEW (widget);
6852   
6853   if (text_view->scroll_timeout != 0)
6854     g_source_remove (text_view->scroll_timeout);
6855
6856   text_view->scroll_timeout = 0;
6857
6858   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6859
6860   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6861                                     &drop_point,
6862                                     text_view->dnd_mark);
6863
6864   if (gtk_text_iter_can_insert (&drop_point, text_view->editable))
6865     target = gtk_drag_dest_find_target (widget, context, NULL);
6866
6867   if (target != GDK_NONE)
6868     gtk_drag_get_data (widget, context, target, time);
6869   else
6870     gtk_drag_finish (context, FALSE, FALSE, time);
6871
6872   return TRUE;
6873 }
6874
6875 static void
6876 insert_text_data (GtkTextView      *text_view,
6877                   GtkTextIter      *drop_point,
6878                   GtkSelectionData *selection_data)
6879 {
6880   guchar *str;
6881
6882   str = gtk_selection_data_get_text (selection_data);
6883
6884   if (str)
6885     {
6886       if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
6887                                                drop_point, (gchar *) str, -1,
6888                                                text_view->editable))
6889         {
6890           gtk_widget_error_bell (GTK_WIDGET (text_view));
6891         }
6892
6893       g_free (str);
6894     }
6895 }
6896
6897 static void
6898 gtk_text_view_drag_data_received (GtkWidget        *widget,
6899                                   GdkDragContext   *context,
6900                                   gint              x,
6901                                   gint              y,
6902                                   GtkSelectionData *selection_data,
6903                                   guint             info,
6904                                   guint             time)
6905 {
6906   GtkTextIter drop_point;
6907   GtkTextView *text_view;
6908   gboolean success = FALSE;
6909   GtkTextBuffer *buffer = NULL;
6910
6911   text_view = GTK_TEXT_VIEW (widget);
6912
6913   if (!text_view->dnd_mark)
6914     goto done;
6915
6916   buffer = get_buffer (text_view);
6917
6918   gtk_text_buffer_get_iter_at_mark (buffer,
6919                                     &drop_point,
6920                                     text_view->dnd_mark);
6921   
6922   if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
6923     goto done;
6924
6925   success = TRUE;
6926
6927   gtk_text_buffer_begin_user_action (buffer);
6928
6929   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6930     {
6931       GtkTextBuffer *src_buffer = NULL;
6932       GtkTextIter start, end;
6933       gboolean copy_tags = TRUE;
6934
6935       if (selection_data->length != sizeof (src_buffer))
6936         return;
6937
6938       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
6939
6940       if (src_buffer == NULL)
6941         return;
6942
6943       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
6944
6945       if (gtk_text_buffer_get_tag_table (src_buffer) !=
6946           gtk_text_buffer_get_tag_table (buffer))
6947         {
6948           /*  try to find a suitable rich text target instead  */
6949           GdkAtom *atoms;
6950           gint     n_atoms;
6951           GList   *list;
6952           GdkAtom  target = GDK_NONE;
6953
6954           copy_tags = FALSE;
6955
6956           atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
6957
6958           for (list = context->targets; list; list = g_list_next (list))
6959             {
6960               gint i;
6961
6962               for (i = 0; i < n_atoms; i++)
6963                 if (GUINT_TO_POINTER (atoms[i]) == list->data)
6964                   {
6965                     target = atoms[i];
6966                     break;
6967                   }
6968             }
6969
6970           g_free (atoms);
6971
6972           if (target != GDK_NONE)
6973             {
6974               gtk_drag_get_data (widget, context, target, time);
6975               gtk_text_buffer_end_user_action (buffer);
6976               return;
6977             }
6978         }
6979
6980       if (gtk_text_buffer_get_selection_bounds (src_buffer,
6981                                                 &start,
6982                                                 &end))
6983         {
6984           if (copy_tags)
6985             gtk_text_buffer_insert_range_interactive (buffer,
6986                                                       &drop_point,
6987                                                       &start,
6988                                                       &end,
6989                                                       text_view->editable);
6990           else
6991             {
6992               gchar *str;
6993
6994               str = gtk_text_iter_get_visible_text (&start, &end);
6995               gtk_text_buffer_insert_interactive (buffer,
6996                                                   &drop_point, str, -1,
6997                                                   text_view->editable);
6998               g_free (str);
6999             }
7000         }
7001     }
7002   else if (selection_data->length > 0 &&
7003            info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
7004     {
7005       gboolean retval;
7006       GError *error = NULL;
7007
7008       retval = gtk_text_buffer_deserialize (buffer, buffer,
7009                                             selection_data->target,
7010                                             &drop_point,
7011                                             (guint8 *) selection_data->data,
7012                                             selection_data->length,
7013                                             &error);
7014
7015       if (!retval)
7016         {
7017           g_warning ("error pasting: %s\n", error->message);
7018           g_clear_error (&error);
7019         }
7020     }
7021   else
7022     insert_text_data (text_view, &drop_point, selection_data);
7023
7024  done:
7025   gtk_drag_finish (context, success,
7026                    success && context->action == GDK_ACTION_MOVE,
7027                    time);
7028
7029   if (success)
7030     {
7031       gtk_text_buffer_get_iter_at_mark (buffer,
7032                                         &drop_point,
7033                                         text_view->dnd_mark);
7034       gtk_text_buffer_place_cursor (buffer, &drop_point);
7035
7036       gtk_text_buffer_end_user_action (buffer);
7037     }
7038 }
7039
7040 /**
7041  * gtk_text_view_get_hadjustment:
7042  * @text_view: a #GtkTextView
7043  *
7044  * Gets the horizontal-scrolling #GtkAdjustment.
7045  *
7046  * Returns: (transfer none): pointer to the horizontal #GtkAdjustment
7047  *
7048  * Since: 2.22
7049  **/
7050 GtkAdjustment*
7051 gtk_text_view_get_hadjustment (GtkTextView *text_view)
7052 {
7053   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7054
7055   return get_hadjustment (text_view);
7056 }
7057
7058 /**
7059  * gtk_text_view_get_vadjustment:
7060  * @text_view: a #GtkTextView
7061  *
7062  * Gets the vertical-scrolling #GtkAdjustment.
7063  *
7064  * Returns: (transfer none): pointer to the vertical #GtkAdjustment
7065  *
7066  * Since: 2.22
7067  **/
7068 GtkAdjustment*
7069 gtk_text_view_get_vadjustment (GtkTextView *text_view)
7070 {
7071   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7072
7073   return get_vadjustment (text_view);
7074 }
7075
7076 static GtkAdjustment*
7077 get_hadjustment (GtkTextView *text_view)
7078 {
7079   if (text_view->hadjustment == NULL)
7080     gtk_text_view_set_scroll_adjustments (text_view,
7081                                           NULL, /* forces creation */
7082                                           text_view->vadjustment);
7083
7084   return text_view->hadjustment;
7085 }
7086
7087 static GtkAdjustment*
7088 get_vadjustment (GtkTextView *text_view)
7089 {
7090   if (text_view->vadjustment == NULL)
7091     gtk_text_view_set_scroll_adjustments (text_view,
7092                                           text_view->hadjustment,
7093                                           NULL); /* forces creation */
7094   return text_view->vadjustment;
7095 }
7096
7097
7098 static void
7099 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
7100                                       GtkAdjustment *hadj,
7101                                       GtkAdjustment *vadj)
7102 {
7103   gboolean need_adjust = FALSE;
7104
7105   if (hadj)
7106     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7107   else
7108     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7109   if (vadj)
7110     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7111   else
7112     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7113
7114   if (text_view->hadjustment && (text_view->hadjustment != hadj))
7115     {
7116       g_signal_handlers_disconnect_by_func (text_view->hadjustment,
7117                                             gtk_text_view_value_changed,
7118                                             text_view);
7119       g_object_unref (text_view->hadjustment);
7120     }
7121
7122   if (text_view->vadjustment && (text_view->vadjustment != vadj))
7123     {
7124       g_signal_handlers_disconnect_by_func (text_view->vadjustment,
7125                                             gtk_text_view_value_changed,
7126                                             text_view);
7127       g_object_unref (text_view->vadjustment);
7128     }
7129
7130   if (text_view->hadjustment != hadj)
7131     {
7132       text_view->hadjustment = hadj;
7133       g_object_ref_sink (text_view->hadjustment);
7134       
7135       g_signal_connect (text_view->hadjustment, "value-changed",
7136                         G_CALLBACK (gtk_text_view_value_changed),
7137                         text_view);
7138       need_adjust = TRUE;
7139     }
7140
7141   if (text_view->vadjustment != vadj)
7142     {
7143       text_view->vadjustment = vadj;
7144       g_object_ref_sink (text_view->vadjustment);
7145       
7146       g_signal_connect (text_view->vadjustment, "value-changed",
7147                         G_CALLBACK (gtk_text_view_value_changed),
7148                         text_view);
7149       need_adjust = TRUE;
7150     }
7151
7152   if (need_adjust)
7153     gtk_text_view_value_changed (NULL, text_view);
7154 }
7155
7156 /* FIXME this adjust_allocation is a big cut-and-paste from
7157  * GtkCList, needs to be some "official" way to do this
7158  * factored out.
7159  */
7160 typedef struct
7161 {
7162   GdkWindow *window;
7163   int dx;
7164   int dy;
7165 } ScrollData;
7166
7167 /* The window to which widget->window is relative */
7168 #define ALLOCATION_WINDOW(widget)               \
7169    (!gtk_widget_get_has_window (widget) ?               \
7170     (widget)->window :                          \
7171      gdk_window_get_parent ((widget)->window))
7172
7173 static void
7174 adjust_allocation_recurse (GtkWidget *widget,
7175                            gpointer   data)
7176 {
7177   ScrollData *scroll_data = data;
7178
7179   /* Need to really size allocate instead of just poking
7180    * into widget->allocation if the widget is not realized.
7181    * FIXME someone figure out why this was.
7182    */
7183   if (!gtk_widget_get_realized (widget))
7184     {
7185       if (gtk_widget_get_visible (widget))
7186         {
7187           GdkRectangle tmp_rectangle = widget->allocation;
7188           tmp_rectangle.x += scroll_data->dx;
7189           tmp_rectangle.y += scroll_data->dy;
7190           
7191           gtk_widget_size_allocate (widget, &tmp_rectangle);
7192         }
7193     }
7194   else
7195     {
7196       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
7197         {
7198           widget->allocation.x += scroll_data->dx;
7199           widget->allocation.y += scroll_data->dy;
7200           
7201           if (GTK_IS_CONTAINER (widget))
7202             gtk_container_forall (GTK_CONTAINER (widget),
7203                                   adjust_allocation_recurse,
7204                                   data);
7205         }
7206     }
7207 }
7208
7209 static void
7210 adjust_allocation (GtkWidget *widget,
7211                    int        dx,
7212                    int        dy)
7213 {
7214   ScrollData scroll_data;
7215
7216   if (gtk_widget_get_realized (widget))
7217     scroll_data.window = ALLOCATION_WINDOW (widget);
7218   else
7219     scroll_data.window = NULL;
7220     
7221   scroll_data.dx = dx;
7222   scroll_data.dy = dy;
7223   
7224   adjust_allocation_recurse (widget, &scroll_data);
7225 }
7226             
7227 static void
7228 gtk_text_view_value_changed (GtkAdjustment *adj,
7229                              GtkTextView   *text_view)
7230 {
7231   GtkTextIter iter;
7232   gint line_top;
7233   gint dx = 0;
7234   gint dy = 0;
7235   
7236   /* Note that we oddly call this function with adj == NULL
7237    * sometimes
7238    */
7239   
7240   text_view->onscreen_validated = FALSE;
7241
7242   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
7243              adj == text_view->hadjustment ? "hadj" : adj == text_view->vadjustment ? "vadj" : "none",
7244              adj ? adj->value : 0.0));
7245   
7246   if (adj == text_view->hadjustment)
7247     {
7248       dx = text_view->xoffset - (gint)adj->value;
7249       text_view->xoffset = adj->value;
7250
7251       /* If the change is due to a size change we need 
7252        * to invalidate the entire text window because there might be
7253        * right-aligned or centered text 
7254        */
7255       if (text_view->width_changed)
7256         {
7257           if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7258             gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
7259           
7260           text_view->width_changed = FALSE;
7261         }
7262     }
7263   else if (adj == text_view->vadjustment)
7264     {
7265       dy = text_view->yoffset - (gint)adj->value;
7266       text_view->yoffset = adj->value;
7267
7268       if (text_view->layout)
7269         {
7270           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
7271
7272           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
7273
7274           text_view->first_para_pixels = adj->value - line_top;
7275         }
7276     }
7277   
7278   if (dx != 0 || dy != 0)
7279     {
7280       GSList *tmp_list;
7281
7282       if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7283         {
7284           if (dy != 0)
7285             {
7286               if (text_view->left_window)
7287                 text_window_scroll (text_view->left_window, 0, dy);
7288               if (text_view->right_window)
7289                 text_window_scroll (text_view->right_window, 0, dy);
7290             }
7291       
7292           if (dx != 0)
7293             {
7294               if (text_view->top_window)
7295                 text_window_scroll (text_view->top_window, dx, 0);
7296               if (text_view->bottom_window)
7297                 text_window_scroll (text_view->bottom_window, dx, 0);
7298             }
7299       
7300           /* It looks nicer to scroll the main area last, because
7301            * it takes a while, and making the side areas update
7302            * afterward emphasizes the slowness of scrolling the
7303            * main area.
7304            */
7305           text_window_scroll (text_view->text_window, dx, dy);
7306         }
7307       
7308       /* Children are now "moved" in the text window, poke
7309        * into widget->allocation for each child
7310        */
7311       tmp_list = text_view->children;
7312       while (tmp_list != NULL)
7313         {
7314           GtkTextViewChild *child = tmp_list->data;
7315           
7316           if (child->anchor)
7317             adjust_allocation (child->widget, dx, dy);
7318           
7319           tmp_list = g_slist_next (tmp_list);
7320         }
7321     }
7322
7323   /* This could result in invalidation, which would install the
7324    * first_validate_idle, which would validate onscreen;
7325    * but we're going to go ahead and validate here, so
7326    * first_validate_idle shouldn't have anything to do.
7327    */
7328   gtk_text_view_update_layout_width (text_view);
7329   
7330   /* We also update the IM spot location here, since the IM context
7331    * might do something that leads to validation.
7332    */
7333   gtk_text_view_update_im_spot_location (text_view);
7334
7335   /* note that validation of onscreen could invoke this function
7336    * recursively, by scrolling to maintain first_para, or in response
7337    * to updating the layout width, however there is no problem with
7338    * that, or shouldn't be.
7339    */
7340   gtk_text_view_validate_onscreen (text_view);
7341   
7342   /* process exposes */
7343   if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7344     {
7345       DV (g_print ("Processing updates (%s)\n", G_STRLOC));
7346       
7347       if (text_view->left_window)
7348         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
7349
7350       if (text_view->right_window)
7351         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
7352
7353       if (text_view->top_window)
7354         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
7355       
7356       if (text_view->bottom_window)
7357         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
7358   
7359       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
7360     }
7361
7362   /* If this got installed, get rid of it, it's just a waste of time. */
7363   if (text_view->first_validate_idle != 0)
7364     {
7365       g_source_remove (text_view->first_validate_idle);
7366       text_view->first_validate_idle = 0;
7367     }
7368
7369   /* Finally we update the IM cursor location again, to ensure any
7370    * changes made by the validation are pushed through.
7371    */
7372   gtk_text_view_update_im_spot_location (text_view);
7373   
7374   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
7375 }
7376
7377 static void
7378 gtk_text_view_commit_handler (GtkIMContext  *context,
7379                               const gchar   *str,
7380                               GtkTextView   *text_view)
7381 {
7382   gtk_text_view_commit_text (text_view, str);
7383 }
7384
7385 static void
7386 gtk_text_view_commit_text (GtkTextView   *text_view,
7387                            const gchar   *str)
7388 {
7389   gboolean had_selection;
7390   
7391   gtk_text_buffer_begin_user_action (get_buffer (text_view));
7392
7393   had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7394                                                         NULL, NULL);
7395   
7396   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7397                                     text_view->editable);
7398
7399   if (!strcmp (str, "\n"))
7400     {
7401       if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
7402                                                          text_view->editable))
7403         {
7404           gtk_widget_error_bell (GTK_WIDGET (text_view));
7405         }
7406     }
7407   else
7408     {
7409       if (!had_selection && text_view->overwrite_mode)
7410         {
7411           GtkTextIter insert;
7412
7413           gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7414                                             &insert,
7415                                             gtk_text_buffer_get_insert (get_buffer (text_view)));
7416           if (!gtk_text_iter_ends_line (&insert))
7417             gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
7418         }
7419
7420       if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
7421                                                          text_view->editable))
7422         {
7423           gtk_widget_error_bell (GTK_WIDGET (text_view));
7424         }
7425     }
7426
7427   gtk_text_buffer_end_user_action (get_buffer (text_view));
7428
7429   gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
7430   DV(g_print (G_STRLOC": scrolling onscreen\n"));
7431   gtk_text_view_scroll_mark_onscreen (text_view,
7432                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
7433 }
7434
7435 static void
7436 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
7437                                        GtkTextView  *text_view)
7438 {
7439   gchar *str;
7440   PangoAttrList *attrs;
7441   gint cursor_pos;
7442   GtkTextIter iter;
7443
7444   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
7445                                     gtk_text_buffer_get_insert (text_view->buffer));
7446
7447   /* Keypress events are passed to input method even if cursor position is
7448    * not editable; so beep here if it's multi-key input sequence, input
7449    * method will be reset in key-press-event handler.
7450    */
7451   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
7452
7453   if (str && str[0] && !gtk_text_iter_can_insert (&iter, text_view->editable))
7454     {
7455       gtk_widget_error_bell (GTK_WIDGET (text_view));
7456       goto out;
7457     }
7458
7459   g_signal_emit (text_view, signals[PREEDIT_CHANGED], 0, str);
7460
7461   if (text_view->layout)
7462     gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
7463   if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
7464     gtk_text_view_scroll_mark_onscreen (text_view,
7465                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
7466
7467 out:
7468   pango_attr_list_unref (attrs);
7469   g_free (str);
7470 }
7471
7472 static gboolean
7473 gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
7474                                             GtkTextView   *text_view)
7475 {
7476   GtkTextIter start;
7477   GtkTextIter end;
7478   gint pos;
7479   gchar *text;
7480
7481   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,
7482                                     gtk_text_buffer_get_insert (text_view->buffer));
7483   end = start;
7484
7485   pos = gtk_text_iter_get_line_index (&start);
7486   gtk_text_iter_set_line_offset (&start, 0);
7487   gtk_text_iter_forward_to_line_end (&end);
7488
7489   text = gtk_text_iter_get_slice (&start, &end);
7490   gtk_im_context_set_surrounding (context, text, -1, pos);
7491   g_free (text);
7492
7493   return TRUE;
7494 }
7495
7496 static gboolean
7497 gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
7498                                           gint           offset,
7499                                           gint           n_chars,
7500                                           GtkTextView   *text_view)
7501 {
7502   GtkTextIter start;
7503   GtkTextIter end;
7504
7505   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,
7506                                     gtk_text_buffer_get_insert (text_view->buffer));
7507   end = start;
7508
7509   gtk_text_iter_forward_chars (&start, offset);
7510   gtk_text_iter_forward_chars (&end, offset + n_chars);
7511
7512   gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
7513                                       text_view->editable);
7514
7515   return TRUE;
7516 }
7517
7518 static void
7519 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
7520                                 const GtkTextIter *location,
7521                                 GtkTextMark       *mark,
7522                                 gpointer           data)
7523 {
7524   GtkTextView *text_view = GTK_TEXT_VIEW (data);
7525   gboolean need_reset = FALSE;
7526
7527   if (mark == gtk_text_buffer_get_insert (buffer))
7528     {
7529       text_view->virtual_cursor_x = -1;
7530       text_view->virtual_cursor_y = -1;
7531       gtk_text_view_update_im_spot_location (text_view);
7532       need_reset = TRUE;
7533     }
7534   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
7535     {
7536       need_reset = TRUE;
7537     }
7538
7539   if (need_reset)
7540     gtk_text_view_reset_im_context (text_view);
7541 }
7542
7543 static void
7544 gtk_text_view_target_list_notify (GtkTextBuffer    *buffer,
7545                                   const GParamSpec *pspec,
7546                                   gpointer          data)
7547 {
7548   GtkWidget     *widget = GTK_WIDGET (data);
7549   GtkTargetList *view_list;
7550   GtkTargetList *buffer_list;
7551   GList         *list;
7552
7553   view_list = gtk_drag_dest_get_target_list (widget);
7554   buffer_list = gtk_text_buffer_get_paste_target_list (buffer);
7555
7556   if (view_list)
7557     gtk_target_list_ref (view_list);
7558   else
7559     view_list = gtk_target_list_new (NULL, 0);
7560
7561   list = view_list->list;
7562   while (list)
7563     {
7564       GtkTargetPair *pair = list->data;
7565
7566       list = g_list_next (list); /* get next element before removing */
7567
7568       if (pair->info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
7569           pair->info <= GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
7570         {
7571           gtk_target_list_remove (view_list, pair->target);
7572         }
7573     }
7574
7575   for (list = buffer_list->list; list; list = g_list_next (list))
7576     {
7577       GtkTargetPair *pair = list->data;
7578
7579       gtk_target_list_add (view_list, pair->target, pair->flags, pair->info);
7580     }
7581
7582   gtk_drag_dest_set_target_list (widget, view_list);
7583   gtk_target_list_unref (view_list);
7584 }
7585
7586 static void
7587 gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
7588                                     GdkRectangle  *pos)
7589 {
7590   GtkTextIter insert;
7591   
7592   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7593                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
7594
7595   gtk_text_layout_get_cursor_locations (text_view->layout, &insert, pos, NULL);
7596 }
7597
7598 static void
7599 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
7600                                       GtkTextIter *cursor,
7601                                       gint        *x,
7602                                       gint        *y)
7603 {
7604   GtkTextIter insert;
7605   GdkRectangle pos;
7606
7607   if (cursor)
7608     insert = *cursor;
7609   else
7610     gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7611                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
7612
7613   if ((x && text_view->virtual_cursor_x == -1) ||
7614       (y && text_view->virtual_cursor_y == -1))
7615     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &pos, NULL);
7616
7617   if (x)
7618     {
7619       if (text_view->virtual_cursor_x != -1)
7620         *x = text_view->virtual_cursor_x;
7621       else
7622         *x = pos.x;
7623     }
7624
7625   if (y)
7626     {
7627       if (text_view->virtual_cursor_x != -1)
7628         *y = text_view->virtual_cursor_y;
7629       else
7630         *y = pos.y + pos.height / 2;
7631     }
7632 }
7633
7634 static void
7635 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
7636                                       gint         x,
7637                                       gint         y)
7638 {
7639   GdkRectangle pos;
7640
7641   if (!text_view->layout)
7642     return;
7643
7644   if (x == -1 || y == -1)
7645     gtk_text_view_get_cursor_location (text_view, &pos);
7646
7647   text_view->virtual_cursor_x = (x == -1) ? pos.x : x;
7648   text_view->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
7649 }
7650
7651 /* Quick hack of a popup menu
7652  */
7653 static void
7654 activate_cb (GtkWidget   *menuitem,
7655              GtkTextView *text_view)
7656 {
7657   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
7658   g_signal_emit_by_name (text_view, signal);
7659 }
7660
7661 static void
7662 append_action_signal (GtkTextView  *text_view,
7663                       GtkWidget    *menu,
7664                       const gchar  *stock_id,
7665                       const gchar  *signal,
7666                       gboolean      sensitive)
7667 {
7668   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
7669
7670   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
7671   g_signal_connect (menuitem, "activate",
7672                     G_CALLBACK (activate_cb), text_view);
7673
7674   gtk_widget_set_sensitive (menuitem, sensitive);
7675   
7676   gtk_widget_show (menuitem);
7677   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
7678 }
7679
7680 static void
7681 gtk_text_view_select_all (GtkWidget *widget,
7682                           gboolean select)
7683 {
7684   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
7685   GtkTextBuffer *buffer;
7686   GtkTextIter start_iter, end_iter, insert;
7687
7688   buffer = text_view->buffer;
7689   if (select) 
7690     {
7691       gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
7692       gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
7693     }
7694   else 
7695     {
7696       gtk_text_buffer_get_iter_at_mark (buffer, &insert,
7697                                         gtk_text_buffer_get_insert (buffer));
7698       gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
7699     }
7700 }
7701
7702 static void
7703 select_all_cb (GtkWidget   *menuitem,
7704                GtkTextView *text_view)
7705 {
7706   gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
7707 }
7708
7709 static void
7710 delete_cb (GtkTextView *text_view)
7711 {
7712   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7713                                     text_view->editable);
7714 }
7715
7716 static void
7717 popup_menu_detach (GtkWidget *attach_widget,
7718                    GtkMenu   *menu)
7719 {
7720   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
7721 }
7722
7723 static void
7724 popup_position_func (GtkMenu   *menu,
7725                      gint      *x,
7726                      gint      *y,
7727                      gboolean  *push_in,
7728                      gpointer   user_data)
7729 {
7730   GtkTextView *text_view;
7731   GtkWidget *widget;
7732   GdkRectangle cursor_rect;
7733   GdkRectangle onscreen_rect;
7734   gint root_x, root_y;
7735   GtkTextIter iter;
7736   GtkRequisition req;      
7737   GdkScreen *screen;
7738   gint monitor_num;
7739   GdkRectangle monitor;
7740       
7741   text_view = GTK_TEXT_VIEW (user_data);
7742   widget = GTK_WIDGET (text_view);
7743   
7744   g_return_if_fail (gtk_widget_get_realized (widget));
7745   
7746   screen = gtk_widget_get_screen (widget);
7747
7748   gdk_window_get_origin (widget->window, &root_x, &root_y);
7749
7750   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7751                                     &iter,
7752                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
7753
7754   gtk_text_view_get_iter_location (text_view,
7755                                    &iter,
7756                                    &cursor_rect);
7757
7758   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
7759   
7760   gtk_widget_size_request (text_view->popup_menu, &req);
7761
7762   /* can't use rectangle_intersect since cursor rect can have 0 width */
7763   if (cursor_rect.x >= onscreen_rect.x &&
7764       cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
7765       cursor_rect.y >= onscreen_rect.y &&
7766       cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
7767     {    
7768       gtk_text_view_buffer_to_window_coords (text_view,
7769                                              GTK_TEXT_WINDOW_WIDGET,
7770                                              cursor_rect.x, cursor_rect.y,
7771                                              &cursor_rect.x, &cursor_rect.y);
7772
7773       *x = root_x + cursor_rect.x + cursor_rect.width;
7774       *y = root_y + cursor_rect.y + cursor_rect.height;
7775     }
7776   else
7777     {
7778       /* Just center the menu, since cursor is offscreen. */      
7779       *x = root_x + (widget->allocation.width / 2 - req.width / 2);
7780       *y = root_y + (widget->allocation.height / 2 - req.height / 2);      
7781     }
7782   
7783   /* Ensure sanity */
7784   *x = CLAMP (*x, root_x, (root_x + widget->allocation.width));
7785   *y = CLAMP (*y, root_y, (root_y + widget->allocation.height));
7786
7787   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
7788   gtk_menu_set_monitor (menu, monitor_num);
7789   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
7790
7791   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
7792   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
7793
7794   *push_in = FALSE;
7795 }
7796
7797 typedef struct
7798 {
7799   GtkTextView *text_view;
7800   gint button;
7801   guint time;
7802 } PopupInfo;
7803
7804 static gboolean
7805 range_contains_editable_text (const GtkTextIter *start,
7806                               const GtkTextIter *end,
7807                               gboolean default_editability)
7808 {
7809   GtkTextIter iter = *start;
7810
7811   while (gtk_text_iter_compare (&iter, end) < 0)
7812     {
7813       if (gtk_text_iter_editable (&iter, default_editability))
7814         return TRUE;
7815       
7816       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
7817     }
7818
7819   return FALSE;
7820 }                             
7821
7822 static void
7823 unichar_chosen_func (const char *text,
7824                      gpointer    data)
7825 {
7826   GtkTextView *text_view = GTK_TEXT_VIEW (data);
7827
7828   gtk_text_view_commit_text (text_view, text);
7829 }
7830
7831 static void
7832 popup_targets_received (GtkClipboard     *clipboard,
7833                         GtkSelectionData *data,
7834                         gpointer          user_data)
7835 {
7836   PopupInfo *info = user_data;
7837   GtkTextView *text_view = info->text_view;
7838   
7839   if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7840     {
7841       /* We implicitely rely here on the fact that if we are pasting ourself, we'll
7842        * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
7843        */
7844       gboolean clipboard_contains_text;
7845       GtkWidget *menuitem;
7846       GtkWidget *submenu;
7847       gboolean have_selection;
7848       gboolean can_insert;
7849       GtkTextIter iter;
7850       GtkTextIter sel_start, sel_end;
7851       gboolean show_input_method_menu;
7852       gboolean show_unicode_menu;
7853       
7854       clipboard_contains_text = gtk_selection_data_targets_include_text (data);
7855
7856       if (text_view->popup_menu)
7857         gtk_widget_destroy (text_view->popup_menu);
7858
7859       text_view->popup_menu = gtk_menu_new ();
7860       
7861       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
7862                                  GTK_WIDGET (text_view),
7863                                  popup_menu_detach);
7864       
7865       have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7866                                                              &sel_start, &sel_end);
7867       
7868       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7869                                         &iter,
7870                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
7871       
7872       can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
7873       
7874       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_CUT, "cut-clipboard",
7875                             have_selection &&
7876                             range_contains_editable_text (&sel_start, &sel_end,
7877                                                           text_view->editable));
7878       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_COPY, "copy-clipboard",
7879                             have_selection);
7880       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_PASTE, "paste-clipboard",
7881                             can_insert && clipboard_contains_text);
7882       
7883       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7884       gtk_widget_set_sensitive (menuitem, 
7885                                 have_selection &&
7886                                 range_contains_editable_text (&sel_start, &sel_end,
7887                                                               text_view->editable));
7888       g_signal_connect_swapped (menuitem, "activate",
7889                                 G_CALLBACK (delete_cb), text_view);
7890       gtk_widget_show (menuitem);
7891       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7892
7893       menuitem = gtk_separator_menu_item_new ();
7894       gtk_widget_show (menuitem);
7895       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7896
7897       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
7898       g_signal_connect (menuitem, "activate",
7899                         G_CALLBACK (select_all_cb), text_view);
7900       gtk_widget_show (menuitem);
7901       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7902
7903       g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
7904                     "gtk-show-input-method-menu", &show_input_method_menu,
7905                     "gtk-show-unicode-menu", &show_unicode_menu,
7906                     NULL);
7907       
7908       if (show_input_method_menu || show_unicode_menu)
7909         {
7910           menuitem = gtk_separator_menu_item_new ();
7911           gtk_widget_show (menuitem);
7912           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7913         }
7914
7915       if (show_input_method_menu)
7916         {
7917           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
7918           gtk_widget_show (menuitem);
7919           gtk_widget_set_sensitive (menuitem, can_insert);
7920
7921           submenu = gtk_menu_new ();
7922           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7923           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7924           
7925           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
7926                                                 GTK_MENU_SHELL (submenu));
7927         }
7928
7929       if (show_unicode_menu)
7930         {
7931           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
7932           gtk_widget_show (menuitem);
7933           gtk_widget_set_sensitive (menuitem, can_insert);
7934       
7935           submenu = gtk_menu_new ();
7936           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7937           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);      
7938           
7939           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
7940                                                         unichar_chosen_func,
7941                                                         text_view);
7942         }
7943           
7944       g_signal_emit (text_view,
7945                      signals[POPULATE_POPUP],
7946                      0,
7947                      text_view->popup_menu);
7948       
7949       if (info->button)
7950         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7951                         NULL, NULL,
7952                         info->button, info->time);
7953       else
7954         {
7955           gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7956                           popup_position_func, text_view,
7957                           0, gtk_get_current_event_time ());
7958           gtk_menu_shell_select_first (GTK_MENU_SHELL (text_view->popup_menu), FALSE);
7959         }
7960     }
7961
7962   g_object_unref (text_view);
7963   g_free (info);
7964 }
7965
7966 static void
7967 gtk_text_view_do_popup (GtkTextView    *text_view,
7968                         GdkEventButton *event)
7969 {
7970   PopupInfo *info = g_new (PopupInfo, 1);
7971
7972   /* In order to know what entries we should make sensitive, we
7973    * ask for the current targets of the clipboard, and when
7974    * we get them, then we actually pop up the menu.
7975    */
7976   info->text_view = g_object_ref (text_view);
7977   
7978   if (event)
7979     {
7980       info->button = event->button;
7981       info->time = event->time;
7982     }
7983   else
7984     {
7985       info->button = 0;
7986       info->time = gtk_get_current_event_time ();
7987     }
7988
7989   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
7990                                                             GDK_SELECTION_CLIPBOARD),
7991                                   gdk_atom_intern_static_string ("TARGETS"),
7992                                   popup_targets_received,
7993                                   info);
7994 }
7995
7996 static gboolean
7997 gtk_text_view_popup_menu (GtkWidget *widget)
7998 {
7999   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
8000   return TRUE;
8001 }
8002
8003 /* Child GdkWindows */
8004
8005
8006 static GtkTextWindow*
8007 text_window_new (GtkTextWindowType  type,
8008                  GtkWidget         *widget,
8009                  gint               width_request,
8010                  gint               height_request)
8011 {
8012   GtkTextWindow *win;
8013
8014   win = g_new (GtkTextWindow, 1);
8015
8016   win->type = type;
8017   win->widget = widget;
8018   win->window = NULL;
8019   win->bin_window = NULL;
8020   win->requisition.width = width_request;
8021   win->requisition.height = height_request;
8022   win->allocation.width = width_request;
8023   win->allocation.height = height_request;
8024   win->allocation.x = 0;
8025   win->allocation.y = 0;
8026
8027   return win;
8028 }
8029
8030 static void
8031 text_window_free (GtkTextWindow *win)
8032 {
8033   if (win->window)
8034     text_window_unrealize (win);
8035
8036   g_free (win);
8037 }
8038
8039 static void
8040 text_window_realize (GtkTextWindow *win,
8041                      GtkWidget     *widget)
8042 {
8043   GdkWindowAttr attributes;
8044   gint attributes_mask;
8045   GdkCursor *cursor;
8046
8047   attributes.window_type = GDK_WINDOW_CHILD;
8048   attributes.x = win->allocation.x;
8049   attributes.y = win->allocation.y;
8050   attributes.width = win->allocation.width;
8051   attributes.height = win->allocation.height;
8052   attributes.wclass = GDK_INPUT_OUTPUT;
8053   attributes.visual = gtk_widget_get_visual (win->widget);
8054   attributes.colormap = gtk_widget_get_colormap (win->widget);
8055   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
8056
8057   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
8058
8059   win->window = gdk_window_new (widget->window,
8060                                 &attributes,
8061                                 attributes_mask);
8062
8063   gdk_window_set_back_pixmap (win->window, NULL, FALSE);
8064   
8065   gdk_window_show (win->window);
8066   gdk_window_set_user_data (win->window, win->widget);
8067   gdk_window_lower (win->window);
8068
8069   attributes.x = 0;
8070   attributes.y = 0;
8071   attributes.width = win->allocation.width;
8072   attributes.height = win->allocation.height;
8073   attributes.event_mask = (GDK_EXPOSURE_MASK            |
8074                            GDK_SCROLL_MASK              |
8075                            GDK_KEY_PRESS_MASK           |
8076                            GDK_BUTTON_PRESS_MASK        |
8077                            GDK_BUTTON_RELEASE_MASK      |
8078                            GDK_POINTER_MOTION_MASK      |
8079                            GDK_POINTER_MOTION_HINT_MASK |
8080                            gtk_widget_get_events (win->widget));
8081
8082   win->bin_window = gdk_window_new (win->window,
8083                                     &attributes,
8084                                     attributes_mask);
8085
8086   gdk_window_show (win->bin_window);
8087   gdk_window_set_user_data (win->bin_window, win->widget);
8088
8089   if (win->type == GTK_TEXT_WINDOW_TEXT)
8090     {
8091       if (gtk_widget_is_sensitive (widget))
8092         {
8093           /* I-beam cursor */
8094           cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (widget->window),
8095                                                GDK_XTERM);
8096           gdk_window_set_cursor (win->bin_window, cursor);
8097           gdk_cursor_unref (cursor);
8098         } 
8099
8100       gtk_im_context_set_client_window (GTK_TEXT_VIEW (widget)->im_context,
8101                                         win->window);
8102
8103
8104       gdk_window_set_background (win->bin_window,
8105                                  &widget->style->base[gtk_widget_get_state (widget)]);
8106     }
8107   else
8108     {
8109       gdk_window_set_background (win->bin_window,
8110                                  &widget->style->bg[gtk_widget_get_state (widget)]);
8111     }
8112
8113   g_object_set_qdata (G_OBJECT (win->window),
8114                       g_quark_from_static_string ("gtk-text-view-text-window"),
8115                       win);
8116
8117   g_object_set_qdata (G_OBJECT (win->bin_window),
8118                       g_quark_from_static_string ("gtk-text-view-text-window"),
8119                       win);
8120 }
8121
8122 static void
8123 text_window_unrealize (GtkTextWindow *win)
8124 {
8125   if (win->type == GTK_TEXT_WINDOW_TEXT)
8126     {
8127       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
8128                                         NULL);
8129     }
8130
8131   gdk_window_set_user_data (win->window, NULL);
8132   gdk_window_set_user_data (win->bin_window, NULL);
8133   gdk_window_destroy (win->bin_window);
8134   gdk_window_destroy (win->window);
8135   win->window = NULL;
8136   win->bin_window = NULL;
8137 }
8138
8139 static void
8140 text_window_size_allocate (GtkTextWindow *win,
8141                            GdkRectangle  *rect)
8142 {
8143   win->allocation = *rect;
8144
8145   if (win->window)
8146     {
8147       gdk_window_move_resize (win->window,
8148                               rect->x, rect->y,
8149                               rect->width, rect->height);
8150
8151       gdk_window_resize (win->bin_window,
8152                          rect->width, rect->height);
8153     }
8154 }
8155
8156 static void
8157 text_window_scroll        (GtkTextWindow *win,
8158                            gint           dx,
8159                            gint           dy)
8160 {
8161   if (dx != 0 || dy != 0)
8162     {
8163       gdk_window_scroll (win->bin_window, dx, dy);
8164     }
8165 }
8166
8167 static void
8168 text_window_invalidate_rect (GtkTextWindow *win,
8169                              GdkRectangle  *rect)
8170 {
8171   GdkRectangle window_rect;
8172
8173   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
8174                                          win->type,
8175                                          rect->x,
8176                                          rect->y,
8177                                          &window_rect.x,
8178                                          &window_rect.y);
8179
8180   window_rect.width = rect->width;
8181   window_rect.height = rect->height;
8182   
8183   /* Adjust the rect as appropriate */
8184   
8185   switch (win->type)
8186     {
8187     case GTK_TEXT_WINDOW_TEXT:
8188       break;
8189
8190     case GTK_TEXT_WINDOW_LEFT:
8191     case GTK_TEXT_WINDOW_RIGHT:
8192       window_rect.x = 0;
8193       window_rect.width = win->allocation.width;
8194       break;
8195
8196     case GTK_TEXT_WINDOW_TOP:
8197     case GTK_TEXT_WINDOW_BOTTOM:
8198       window_rect.y = 0;
8199       window_rect.height = win->allocation.height;
8200       break;
8201
8202     default:
8203       g_warning ("%s: bug!", G_STRFUNC);
8204       return;
8205       break;
8206     }
8207           
8208   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
8209
8210 #if 0
8211   {
8212     cairo_t *cr = gdk_cairo_create (win->bin_window);
8213     gdk_cairo_rectangle (cr, &window_rect);
8214     cairo_set_source_rgb  (cr, 1.0, 0.0, 0.0);  /* red */
8215     cairo_fill (cr);
8216     cairo_destroy (cr);
8217   }
8218 #endif
8219 }
8220
8221 static void
8222 text_window_invalidate_cursors (GtkTextWindow *win)
8223 {
8224   GtkTextView *text_view = GTK_TEXT_VIEW (win->widget);
8225   GtkTextIter  iter;
8226   GdkRectangle strong;
8227   GdkRectangle weak;
8228   gboolean     draw_arrow;
8229   gfloat       cursor_aspect_ratio;
8230   gint         stem_width;
8231   gint         arrow_width;
8232
8233   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
8234                                     gtk_text_buffer_get_insert (text_view->buffer));
8235
8236   if (_gtk_text_layout_get_block_cursor (text_view->layout, &strong))
8237     {
8238       text_window_invalidate_rect (win, &strong);
8239       return;
8240     }
8241
8242   gtk_text_layout_get_cursor_locations (text_view->layout, &iter,
8243                                         &strong, &weak);
8244
8245   /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
8246    * ignoring the text direction be exposing both sides of the cursor
8247    */
8248
8249   draw_arrow = (strong.x != weak.x || strong.y != weak.y);
8250
8251   gtk_widget_style_get (win->widget,
8252                         "cursor-aspect-ratio", &cursor_aspect_ratio,
8253                         NULL);
8254   
8255   stem_width = strong.height * cursor_aspect_ratio + 1;
8256   arrow_width = stem_width + 1;
8257
8258   strong.width = stem_width;
8259
8260   /* round up to the next even number */
8261   if (stem_width & 1)
8262     stem_width++;
8263
8264   strong.x     -= stem_width / 2;
8265   strong.width += stem_width;
8266
8267   if (draw_arrow)
8268     {
8269       strong.x     -= arrow_width;
8270       strong.width += arrow_width * 2;
8271     }
8272
8273   text_window_invalidate_rect (win, &strong);
8274
8275   if (draw_arrow) /* == have weak */
8276     {
8277       stem_width = weak.height * cursor_aspect_ratio + 1;
8278       arrow_width = stem_width + 1;
8279
8280       weak.width = stem_width;
8281
8282       /* round up to the next even number */
8283       if (stem_width & 1)
8284         stem_width++;
8285
8286       weak.x     -= stem_width / 2;
8287       weak.width += stem_width;
8288
8289       weak.x     -= arrow_width;
8290       weak.width += arrow_width * 2;
8291
8292       text_window_invalidate_rect (win, &weak);
8293     }
8294 }
8295
8296 static gint
8297 text_window_get_width (GtkTextWindow *win)
8298 {
8299   return win->allocation.width;
8300 }
8301
8302 static gint
8303 text_window_get_height (GtkTextWindow *win)
8304 {
8305   return win->allocation.height;
8306 }
8307
8308 /* Windows */
8309
8310
8311 /**
8312  * gtk_text_view_get_window:
8313  * @text_view: a #GtkTextView
8314  * @win: window to get
8315  *
8316  * Retrieves the #GdkWindow corresponding to an area of the text view;
8317  * possible windows include the overall widget window, child windows
8318  * on the left, right, top, bottom, and the window that displays the
8319  * text buffer. Windows are %NULL and nonexistent if their width or
8320  * height is 0, and are nonexistent before the widget has been
8321  * realized.
8322  *
8323  * Return value: (transfer none): a #GdkWindow, or %NULL
8324  **/
8325 GdkWindow*
8326 gtk_text_view_get_window (GtkTextView *text_view,
8327                           GtkTextWindowType win)
8328 {
8329   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
8330
8331   switch (win)
8332     {
8333     case GTK_TEXT_WINDOW_WIDGET:
8334       return GTK_WIDGET (text_view)->window;
8335       break;
8336
8337     case GTK_TEXT_WINDOW_TEXT:
8338       return text_view->text_window->bin_window;
8339       break;
8340
8341     case GTK_TEXT_WINDOW_LEFT:
8342       if (text_view->left_window)
8343         return text_view->left_window->bin_window;
8344       else
8345         return NULL;
8346       break;
8347
8348     case GTK_TEXT_WINDOW_RIGHT:
8349       if (text_view->right_window)
8350         return text_view->right_window->bin_window;
8351       else
8352         return NULL;
8353       break;
8354
8355     case GTK_TEXT_WINDOW_TOP:
8356       if (text_view->top_window)
8357         return text_view->top_window->bin_window;
8358       else
8359         return NULL;
8360       break;
8361
8362     case GTK_TEXT_WINDOW_BOTTOM:
8363       if (text_view->bottom_window)
8364         return text_view->bottom_window->bin_window;
8365       else
8366         return NULL;
8367       break;
8368
8369     case GTK_TEXT_WINDOW_PRIVATE:
8370       g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_STRFUNC);
8371       return NULL;
8372       break;
8373     }
8374
8375   g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8376   return NULL;
8377 }
8378
8379 /**
8380  * gtk_text_view_get_window_type:
8381  * @text_view: a #GtkTextView
8382  * @window: a window type
8383  *
8384  * Usually used to find out which window an event corresponds to.
8385  * If you connect to an event signal on @text_view, this function
8386  * should be called on <literal>event-&gt;window</literal> to
8387  * see which window it was.
8388  *
8389  * Return value: the window type.
8390  **/
8391 GtkTextWindowType
8392 gtk_text_view_get_window_type (GtkTextView *text_view,
8393                                GdkWindow   *window)
8394 {
8395   GtkTextWindow *win;
8396
8397   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8398   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
8399
8400   if (window == GTK_WIDGET (text_view)->window)
8401     return GTK_TEXT_WINDOW_WIDGET;
8402
8403   win = g_object_get_qdata (G_OBJECT (window),
8404                             g_quark_try_string ("gtk-text-view-text-window"));
8405
8406   if (win)
8407     return win->type;
8408   else
8409     {
8410       return GTK_TEXT_WINDOW_PRIVATE;
8411     }
8412 }
8413
8414 static void
8415 buffer_to_widget (GtkTextView      *text_view,
8416                   gint              buffer_x,
8417                   gint              buffer_y,
8418                   gint             *window_x,
8419                   gint             *window_y)
8420 {  
8421   if (window_x)
8422     {
8423       *window_x = buffer_x - text_view->xoffset;
8424       *window_x += text_view->text_window->allocation.x;
8425     }
8426
8427   if (window_y)
8428     {
8429       *window_y = buffer_y - text_view->yoffset;
8430       *window_y += text_view->text_window->allocation.y;
8431     }
8432 }
8433
8434 static void
8435 widget_to_text_window (GtkTextWindow *win,
8436                        gint           widget_x,
8437                        gint           widget_y,
8438                        gint          *window_x,
8439                        gint          *window_y)
8440 {
8441   if (window_x)
8442     *window_x = widget_x - win->allocation.x;
8443
8444   if (window_y)
8445     *window_y = widget_y - win->allocation.y;
8446 }
8447
8448 static void
8449 buffer_to_text_window (GtkTextView   *text_view,
8450                        GtkTextWindow *win,
8451                        gint           buffer_x,
8452                        gint           buffer_y,
8453                        gint          *window_x,
8454                        gint          *window_y)
8455 {
8456   if (win == NULL)
8457     {
8458       g_warning ("Attempt to convert text buffer coordinates to coordinates "
8459                  "for a nonexistent or private child window of GtkTextView");
8460       return;
8461     }
8462
8463   buffer_to_widget (text_view,
8464                     buffer_x, buffer_y,
8465                     window_x, window_y);
8466
8467   widget_to_text_window (win,
8468                          window_x ? *window_x : 0,
8469                          window_y ? *window_y : 0,
8470                          window_x,
8471                          window_y);
8472 }
8473
8474 /**
8475  * gtk_text_view_buffer_to_window_coords:
8476  * @text_view: a #GtkTextView
8477  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8478  * @buffer_x: buffer x coordinate
8479  * @buffer_y: buffer y coordinate
8480  * @window_x: window x coordinate return location
8481  * @window_y: window y coordinate return location
8482  *
8483  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
8484  * @win, and stores the result in (@window_x, @window_y). 
8485  *
8486  * Note that you can't convert coordinates for a nonexisting window (see 
8487  * gtk_text_view_set_border_window_size()).
8488  **/
8489 void
8490 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
8491                                        GtkTextWindowType win,
8492                                        gint              buffer_x,
8493                                        gint              buffer_y,
8494                                        gint             *window_x,
8495                                        gint             *window_y)
8496 {
8497   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8498
8499   switch (win)
8500     {
8501     case GTK_TEXT_WINDOW_WIDGET:
8502       buffer_to_widget (text_view,
8503                         buffer_x, buffer_y,
8504                         window_x, window_y);
8505       break;
8506
8507     case GTK_TEXT_WINDOW_TEXT:
8508       if (window_x)
8509         *window_x = buffer_x - text_view->xoffset;
8510       if (window_y)
8511         *window_y = buffer_y - text_view->yoffset;
8512       break;
8513
8514     case GTK_TEXT_WINDOW_LEFT:
8515       buffer_to_text_window (text_view,
8516                              text_view->left_window,
8517                              buffer_x, buffer_y,
8518                              window_x, window_y);
8519       break;
8520
8521     case GTK_TEXT_WINDOW_RIGHT:
8522       buffer_to_text_window (text_view,
8523                              text_view->right_window,
8524                              buffer_x, buffer_y,
8525                              window_x, window_y);
8526       break;
8527
8528     case GTK_TEXT_WINDOW_TOP:
8529       buffer_to_text_window (text_view,
8530                              text_view->top_window,
8531                              buffer_x, buffer_y,
8532                              window_x, window_y);
8533       break;
8534
8535     case GTK_TEXT_WINDOW_BOTTOM:
8536       buffer_to_text_window (text_view,
8537                              text_view->bottom_window,
8538                              buffer_x, buffer_y,
8539                              window_x, window_y);
8540       break;
8541
8542     case GTK_TEXT_WINDOW_PRIVATE:
8543       g_warning ("%s: can't get coords for private windows", G_STRFUNC);
8544       break;
8545
8546     default:
8547       g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8548       break;
8549     }
8550 }
8551
8552 static void
8553 widget_to_buffer (GtkTextView *text_view,
8554                   gint         widget_x,
8555                   gint         widget_y,
8556                   gint        *buffer_x,
8557                   gint        *buffer_y)
8558 {  
8559   if (buffer_x)
8560     {
8561       *buffer_x = widget_x + text_view->xoffset;
8562       *buffer_x -= text_view->text_window->allocation.x;
8563     }
8564
8565   if (buffer_y)
8566     {
8567       *buffer_y = widget_y + text_view->yoffset;
8568       *buffer_y -= text_view->text_window->allocation.y;
8569     }
8570 }
8571
8572 static void
8573 text_window_to_widget (GtkTextWindow *win,
8574                        gint           window_x,
8575                        gint           window_y,
8576                        gint          *widget_x,
8577                        gint          *widget_y)
8578 {
8579   if (widget_x)
8580     *widget_x = window_x + win->allocation.x;
8581
8582   if (widget_y)
8583     *widget_y = window_y + win->allocation.y;
8584 }
8585
8586 static void
8587 text_window_to_buffer (GtkTextView   *text_view,
8588                        GtkTextWindow *win,
8589                        gint           window_x,
8590                        gint           window_y,
8591                        gint          *buffer_x,
8592                        gint          *buffer_y)
8593 {
8594   if (win == NULL)
8595     {
8596       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
8597                  "coordinates for a nonexistent child window.");
8598       return;
8599     }
8600
8601   text_window_to_widget (win,
8602                          window_x,
8603                          window_y,
8604                          buffer_x,
8605                          buffer_y);
8606
8607   widget_to_buffer (text_view,
8608                     buffer_x ? *buffer_x : 0,
8609                     buffer_y ? *buffer_y : 0,
8610                     buffer_x,
8611                     buffer_y);
8612 }
8613
8614 /**
8615  * gtk_text_view_window_to_buffer_coords:
8616  * @text_view: a #GtkTextView
8617  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8618  * @window_x: window x coordinate
8619  * @window_y: window y coordinate
8620  * @buffer_x: buffer x coordinate return location
8621  * @buffer_y: buffer y coordinate return location
8622  *
8623  * Converts coordinates on the window identified by @win to buffer
8624  * coordinates, storing the result in (@buffer_x,@buffer_y).
8625  *
8626  * Note that you can't convert coordinates for a nonexisting window (see 
8627  * gtk_text_view_set_border_window_size()).
8628  **/
8629 void
8630 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
8631                                        GtkTextWindowType win,
8632                                        gint              window_x,
8633                                        gint              window_y,
8634                                        gint             *buffer_x,
8635                                        gint             *buffer_y)
8636 {
8637   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8638
8639   switch (win)
8640     {
8641     case GTK_TEXT_WINDOW_WIDGET:
8642       widget_to_buffer (text_view,
8643                         window_x, window_y,
8644                         buffer_x, buffer_y);
8645       break;
8646
8647     case GTK_TEXT_WINDOW_TEXT:
8648       if (buffer_x)
8649         *buffer_x = window_x + text_view->xoffset;
8650       if (buffer_y)
8651         *buffer_y = window_y + text_view->yoffset;
8652       break;
8653
8654     case GTK_TEXT_WINDOW_LEFT:
8655       text_window_to_buffer (text_view,
8656                              text_view->left_window,
8657                              window_x, window_y,
8658                              buffer_x, buffer_y);
8659       break;
8660
8661     case GTK_TEXT_WINDOW_RIGHT:
8662       text_window_to_buffer (text_view,
8663                              text_view->right_window,
8664                              window_x, window_y,
8665                              buffer_x, buffer_y);
8666       break;
8667
8668     case GTK_TEXT_WINDOW_TOP:
8669       text_window_to_buffer (text_view,
8670                              text_view->top_window,
8671                              window_x, window_y,
8672                              buffer_x, buffer_y);
8673       break;
8674
8675     case GTK_TEXT_WINDOW_BOTTOM:
8676       text_window_to_buffer (text_view,
8677                              text_view->bottom_window,
8678                              window_x, window_y,
8679                              buffer_x, buffer_y);
8680       break;
8681
8682     case GTK_TEXT_WINDOW_PRIVATE:
8683       g_warning ("%s: can't get coords for private windows", G_STRFUNC);
8684       break;
8685
8686     default:
8687       g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8688       break;
8689     }
8690 }
8691
8692 static void
8693 set_window_width (GtkTextView      *text_view,
8694                   gint              width,
8695                   GtkTextWindowType type,
8696                   GtkTextWindow   **winp)
8697 {
8698   if (width == 0)
8699     {
8700       if (*winp)
8701         {
8702           text_window_free (*winp);
8703           *winp = NULL;
8704           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8705         }
8706     }
8707   else
8708     {
8709       if (*winp == NULL)
8710         {
8711           *winp = text_window_new (type,
8712                                    GTK_WIDGET (text_view),
8713                                    width, 0);
8714           /* if the widget is already realized we need to realize the child manually */
8715           if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
8716             text_window_realize (*winp, GTK_WIDGET (text_view));
8717         }
8718       else
8719         {
8720           if ((*winp)->requisition.width == width)
8721             return;
8722
8723           (*winp)->requisition.width = width;
8724         }
8725
8726       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8727     }
8728 }
8729
8730
8731 static void
8732 set_window_height (GtkTextView      *text_view,
8733                    gint              height,
8734                    GtkTextWindowType type,
8735                    GtkTextWindow   **winp)
8736 {
8737   if (height == 0)
8738     {
8739       if (*winp)
8740         {
8741           text_window_free (*winp);
8742           *winp = NULL;
8743           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8744         }
8745     }
8746   else
8747     {
8748       if (*winp == NULL)
8749         {
8750           *winp = text_window_new (type,
8751                                    GTK_WIDGET (text_view),
8752                                    0, height);
8753
8754           /* if the widget is already realized we need to realize the child manually */
8755           if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
8756             text_window_realize (*winp, GTK_WIDGET (text_view));
8757         }
8758       else
8759         {
8760           if ((*winp)->requisition.height == height)
8761             return;
8762
8763           (*winp)->requisition.height = height;
8764         }
8765
8766       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8767     }
8768 }
8769
8770 /**
8771  * gtk_text_view_set_border_window_size:
8772  * @text_view: a #GtkTextView
8773  * @type: window to affect
8774  * @size: width or height of the window
8775  *
8776  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
8777  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
8778  * Automatically destroys the corresponding window if the size is set
8779  * to 0, and creates the window if the size is set to non-zero.  This
8780  * function can only be used for the "border windows," it doesn't work
8781  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
8782  * #GTK_TEXT_WINDOW_PRIVATE.
8783  **/
8784 void
8785 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
8786                                       GtkTextWindowType type,
8787                                       gint              size)
8788
8789 {
8790   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8791   g_return_if_fail (size >= 0);
8792
8793   switch (type)
8794     {
8795     case GTK_TEXT_WINDOW_LEFT:
8796       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
8797                         &text_view->left_window);
8798       break;
8799
8800     case GTK_TEXT_WINDOW_RIGHT:
8801       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
8802                         &text_view->right_window);
8803       break;
8804
8805     case GTK_TEXT_WINDOW_TOP:
8806       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
8807                          &text_view->top_window);
8808       break;
8809
8810     case GTK_TEXT_WINDOW_BOTTOM:
8811       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
8812                          &text_view->bottom_window);
8813       break;
8814
8815     default:
8816       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
8817       break;
8818     }
8819 }
8820
8821 /**
8822  * gtk_text_view_get_border_window_size:
8823  * @text_view: a #GtkTextView
8824  * @type: window to return size from
8825  *
8826  * Gets the width of the specified border window. See
8827  * gtk_text_view_set_border_window_size().
8828  *
8829  * Return value: width of window
8830  **/
8831 gint
8832 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
8833                                       GtkTextWindowType  type)
8834 {
8835   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8836   
8837   switch (type)
8838     {
8839     case GTK_TEXT_WINDOW_LEFT:
8840       if (text_view->left_window)
8841         return text_view->left_window->requisition.width;
8842       break;
8843       
8844     case GTK_TEXT_WINDOW_RIGHT:
8845       if (text_view->right_window)
8846         return text_view->right_window->requisition.width;
8847       break;
8848       
8849     case GTK_TEXT_WINDOW_TOP:
8850       if (text_view->top_window)
8851         return text_view->top_window->requisition.height;
8852       break;
8853
8854     case GTK_TEXT_WINDOW_BOTTOM:
8855       if (text_view->bottom_window)
8856         return text_view->bottom_window->requisition.height;
8857       break;
8858       
8859     default:
8860       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
8861       break;
8862     }
8863
8864   return 0;
8865 }
8866
8867 /*
8868  * Child widgets
8869  */
8870
8871 static GtkTextViewChild*
8872 text_view_child_new_anchored (GtkWidget          *child,
8873                               GtkTextChildAnchor *anchor,
8874                               GtkTextLayout      *layout)
8875 {
8876   GtkTextViewChild *vc;
8877
8878   vc = g_new (GtkTextViewChild, 1);
8879
8880   vc->type = GTK_TEXT_WINDOW_PRIVATE;
8881   vc->widget = child;
8882   vc->anchor = anchor;
8883
8884   vc->from_top_of_line = 0;
8885   vc->from_left_of_buffer = 0;
8886   
8887   g_object_ref (vc->widget);
8888   g_object_ref (vc->anchor);
8889
8890   g_object_set_data (G_OBJECT (child),
8891                      I_("gtk-text-view-child"),
8892                      vc);
8893
8894   gtk_text_child_anchor_register_child (anchor, child, layout);
8895   
8896   return vc;
8897 }
8898
8899 static GtkTextViewChild*
8900 text_view_child_new_window (GtkWidget          *child,
8901                             GtkTextWindowType   type,
8902                             gint                x,
8903                             gint                y)
8904 {
8905   GtkTextViewChild *vc;
8906
8907   vc = g_new (GtkTextViewChild, 1);
8908
8909   vc->widget = child;
8910   vc->anchor = NULL;
8911
8912   vc->from_top_of_line = 0;
8913   vc->from_left_of_buffer = 0;
8914  
8915   g_object_ref (vc->widget);
8916
8917   vc->type = type;
8918   vc->x = x;
8919   vc->y = y;
8920
8921   g_object_set_data (G_OBJECT (child),
8922                      I_("gtk-text-view-child"),
8923                      vc);
8924   
8925   return vc;
8926 }
8927
8928 static void
8929 text_view_child_free (GtkTextViewChild *child)
8930 {
8931   g_object_set_data (G_OBJECT (child->widget),
8932                      I_("gtk-text-view-child"), NULL);
8933
8934   if (child->anchor)
8935     {
8936       gtk_text_child_anchor_unregister_child (child->anchor,
8937                                               child->widget);
8938       g_object_unref (child->anchor);
8939     }
8940
8941   g_object_unref (child->widget);
8942
8943   g_free (child);
8944 }
8945
8946 static void
8947 text_view_child_set_parent_window (GtkTextView      *text_view,
8948                                    GtkTextViewChild *vc)
8949 {
8950   if (vc->anchor)
8951     gtk_widget_set_parent_window (vc->widget,
8952                                   text_view->text_window->bin_window);
8953   else
8954     {
8955       GdkWindow *window;
8956       window = gtk_text_view_get_window (text_view,
8957                                          vc->type);
8958       gtk_widget_set_parent_window (vc->widget, window);
8959     }
8960 }
8961
8962 static void
8963 add_child (GtkTextView      *text_view,
8964            GtkTextViewChild *vc)
8965 {
8966   text_view->children = g_slist_prepend (text_view->children,
8967                                          vc);
8968
8969   if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
8970     text_view_child_set_parent_window (text_view, vc);
8971   
8972   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
8973 }
8974
8975 /**
8976  * gtk_text_view_add_child_at_anchor:
8977  * @text_view: a #GtkTextView
8978  * @child: a #GtkWidget
8979  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
8980  * 
8981  * Adds a child widget in the text buffer, at the given @anchor.
8982  **/
8983 void
8984 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
8985                                    GtkWidget            *child,
8986                                    GtkTextChildAnchor   *anchor)
8987 {
8988   GtkTextViewChild *vc;
8989
8990   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8991   g_return_if_fail (GTK_IS_WIDGET (child));
8992   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
8993   g_return_if_fail (child->parent == NULL);
8994
8995   gtk_text_view_ensure_layout (text_view);
8996
8997   vc = text_view_child_new_anchored (child, anchor,
8998                                      text_view->layout);
8999
9000   add_child (text_view, vc);
9001
9002   g_assert (vc->widget == child);
9003   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9004 }
9005
9006 /**
9007  * gtk_text_view_add_child_in_window:
9008  * @text_view: a #GtkTextView
9009  * @child: a #GtkWidget
9010  * @which_window: which window the child should appear in
9011  * @xpos: X position of child in window coordinates
9012  * @ypos: Y position of child in window coordinates
9013  *
9014  * Adds a child at fixed coordinates in one of the text widget's
9015  * windows. The window must have nonzero size (see
9016  * gtk_text_view_set_border_window_size()). Note that the child
9017  * coordinates are given relative to the #GdkWindow in question, and
9018  * that these coordinates have no sane relationship to scrolling. When
9019  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
9020  * irrelevant, the child floats above all scrollable areas. But when
9021  * placing a child in one of the scrollable windows (border windows or
9022  * text window), you'll need to compute the child's correct position
9023  * in buffer coordinates any time scrolling occurs or buffer changes
9024  * occur, and then call gtk_text_view_move_child() to update the
9025  * child's position. Unfortunately there's no good way to detect that
9026  * scrolling has occurred, using the current API; a possible hack
9027  * would be to update all child positions when the scroll adjustments
9028  * change or the text buffer changes. See bug 64518 on
9029  * bugzilla.gnome.org for status of fixing this issue.
9030  **/
9031 void
9032 gtk_text_view_add_child_in_window (GtkTextView       *text_view,
9033                                    GtkWidget         *child,
9034                                    GtkTextWindowType  which_window,
9035                                    gint               xpos,
9036                                    gint               ypos)
9037 {
9038   GtkTextViewChild *vc;
9039
9040   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9041   g_return_if_fail (GTK_IS_WIDGET (child));
9042   g_return_if_fail (child->parent == NULL);
9043
9044   vc = text_view_child_new_window (child, which_window,
9045                                    xpos, ypos);
9046
9047   add_child (text_view, vc);
9048
9049   g_assert (vc->widget == child);
9050   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9051 }
9052
9053 /**
9054  * gtk_text_view_move_child:
9055  * @text_view: a #GtkTextView
9056  * @child: child widget already added to the text view
9057  * @xpos: new X position in window coordinates
9058  * @ypos: new Y position in window coordinates
9059  *
9060  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
9061  **/
9062 void
9063 gtk_text_view_move_child (GtkTextView *text_view,
9064                           GtkWidget   *child,
9065                           gint         xpos,
9066                           gint         ypos)
9067 {
9068   GtkTextViewChild *vc;
9069
9070   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9071   g_return_if_fail (GTK_IS_WIDGET (child));
9072   g_return_if_fail (child->parent == (GtkWidget*) text_view);
9073
9074   vc = g_object_get_data (G_OBJECT (child),
9075                           "gtk-text-view-child");
9076
9077   g_assert (vc != NULL);
9078
9079   if (vc->x == xpos &&
9080       vc->y == ypos)
9081     return;
9082   
9083   vc->x = xpos;
9084   vc->y = ypos;
9085
9086   if (gtk_widget_get_visible (child) &&
9087       gtk_widget_get_visible (GTK_WIDGET (text_view)))
9088     gtk_widget_queue_resize (child);
9089 }
9090
9091
9092 /* Iterator operations */
9093
9094 /**
9095  * gtk_text_view_forward_display_line:
9096  * @text_view: a #GtkTextView
9097  * @iter: a #GtkTextIter
9098  * 
9099  * Moves the given @iter forward by one display (wrapped) line.
9100  * A display line is different from a paragraph. Paragraphs are
9101  * separated by newlines or other paragraph separator characters.
9102  * Display lines are created by line-wrapping a paragraph. If
9103  * wrapping is turned off, display lines and paragraphs will be the
9104  * same. Display lines are divided differently for each view, since
9105  * they depend on the view's width; paragraphs are the same in all
9106  * views, since they depend on the contents of the #GtkTextBuffer.
9107  * 
9108  * Return value: %TRUE if @iter was moved and is not on the end iterator
9109  **/
9110 gboolean
9111 gtk_text_view_forward_display_line (GtkTextView *text_view,
9112                                     GtkTextIter *iter)
9113 {
9114   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9115   g_return_val_if_fail (iter != NULL, FALSE);
9116
9117   gtk_text_view_ensure_layout (text_view);
9118
9119   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
9120 }
9121
9122 /**
9123  * gtk_text_view_backward_display_line:
9124  * @text_view: a #GtkTextView
9125  * @iter: a #GtkTextIter
9126  * 
9127  * Moves the given @iter backward by one display (wrapped) line.
9128  * A display line is different from a paragraph. Paragraphs are
9129  * separated by newlines or other paragraph separator characters.
9130  * Display lines are created by line-wrapping a paragraph. If
9131  * wrapping is turned off, display lines and paragraphs will be the
9132  * same. Display lines are divided differently for each view, since
9133  * they depend on the view's width; paragraphs are the same in all
9134  * views, since they depend on the contents of the #GtkTextBuffer.
9135  * 
9136  * Return value: %TRUE if @iter was moved and is not on the end iterator
9137  **/
9138 gboolean
9139 gtk_text_view_backward_display_line (GtkTextView *text_view,
9140                                      GtkTextIter *iter)
9141 {
9142   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9143   g_return_val_if_fail (iter != NULL, FALSE);
9144
9145   gtk_text_view_ensure_layout (text_view);
9146
9147   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
9148 }
9149
9150 /**
9151  * gtk_text_view_forward_display_line_end:
9152  * @text_view: a #GtkTextView
9153  * @iter: a #GtkTextIter
9154  * 
9155  * Moves the given @iter forward to the next display line end.
9156  * A display line is different from a paragraph. Paragraphs are
9157  * separated by newlines or other paragraph separator characters.
9158  * Display lines are created by line-wrapping a paragraph. If
9159  * wrapping is turned off, display lines and paragraphs will be the
9160  * same. Display lines are divided differently for each view, since
9161  * they depend on the view's width; paragraphs are the same in all
9162  * views, since they depend on the contents of the #GtkTextBuffer.
9163  * 
9164  * Return value: %TRUE if @iter was moved and is not on the end iterator
9165  **/
9166 gboolean
9167 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
9168                                         GtkTextIter *iter)
9169 {
9170   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9171   g_return_val_if_fail (iter != NULL, FALSE);
9172
9173   gtk_text_view_ensure_layout (text_view);
9174
9175   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
9176 }
9177
9178 /**
9179  * gtk_text_view_backward_display_line_start:
9180  * @text_view: a #GtkTextView
9181  * @iter: a #GtkTextIter
9182  * 
9183  * Moves the given @iter backward to the next display line start.
9184  * A display line is different from a paragraph. Paragraphs are
9185  * separated by newlines or other paragraph separator characters.
9186  * Display lines are created by line-wrapping a paragraph. If
9187  * wrapping is turned off, display lines and paragraphs will be the
9188  * same. Display lines are divided differently for each view, since
9189  * they depend on the view's width; paragraphs are the same in all
9190  * views, since they depend on the contents of the #GtkTextBuffer.
9191  * 
9192  * Return value: %TRUE if @iter was moved and is not on the end iterator
9193  **/
9194 gboolean
9195 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
9196                                            GtkTextIter *iter)
9197 {
9198   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9199   g_return_val_if_fail (iter != NULL, FALSE);
9200
9201   gtk_text_view_ensure_layout (text_view);
9202
9203   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
9204 }
9205
9206 /**
9207  * gtk_text_view_starts_display_line:
9208  * @text_view: a #GtkTextView
9209  * @iter: a #GtkTextIter
9210  * 
9211  * Determines whether @iter is at the start of a display line.
9212  * See gtk_text_view_forward_display_line() for an explanation of
9213  * display lines vs. paragraphs.
9214  * 
9215  * Return value: %TRUE if @iter begins a wrapped line
9216  **/
9217 gboolean
9218 gtk_text_view_starts_display_line (GtkTextView       *text_view,
9219                                    const GtkTextIter *iter)
9220 {
9221   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9222   g_return_val_if_fail (iter != NULL, FALSE);
9223
9224   gtk_text_view_ensure_layout (text_view);
9225
9226   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
9227 }
9228
9229 /**
9230  * gtk_text_view_move_visually:
9231  * @text_view: a #GtkTextView
9232  * @iter: a #GtkTextIter
9233  * @count: number of characters to move (negative moves left, 
9234  *    positive moves right)
9235  *
9236  * Move the iterator a given number of characters visually, treating
9237  * it as the strong cursor position. If @count is positive, then the
9238  * new strong cursor position will be @count positions to the right of
9239  * the old cursor position. If @count is negative then the new strong
9240  * cursor position will be @count positions to the left of the old
9241  * cursor position.
9242  *
9243  * In the presence of bi-directional text, the correspondence
9244  * between logical and visual order will depend on the direction
9245  * of the current run, and there may be jumps when the cursor
9246  * is moved off of the end of a run.
9247  * 
9248  * Return value: %TRUE if @iter moved and is not on the end iterator
9249  **/
9250 gboolean
9251 gtk_text_view_move_visually (GtkTextView *text_view,
9252                              GtkTextIter *iter,
9253                              gint         count)
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_visually (text_view->layout, iter, count);
9261 }
9262
9263 #define __GTK_TEXT_VIEW_C__
9264 #include "gtkaliasdef.c"