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