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