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