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