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