]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
adapt to handle PangoColor
[~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 #include "gtkbindings.h"
30 #include "gtkdnd.h"
31 #include "gtkintl.h"
32 #include "gtkmain.h"
33 #include "gtkmenu.h"
34 #include "gtkmenuitem.h"
35 #include "gtksignal.h"
36 #include "gtktext.h"
37 #include "gtktextdisplay.h"
38 #include "gtktextview.h"
39 #include "gtkimmulticontext.h"
40 #include "gdk/gdkkeysyms.h"
41 #include <string.h>
42
43 /* How scrolling, validation, exposes, etc. work.
44  *
45  * The expose_event handler has the invariant that the onscreen lines
46  * have been validated.
47  *
48  * There are two ways that onscreen lines can become invalid. The first
49  * is to change which lines are onscreen. This happens when the value
50  * of a scroll adjustment changes. So the code path begins in
51  * gtk_text_view_value_changed() and goes like this:
52  *   - gdk_window_scroll() to reflect the new adjustment value
53  *   - validate the lines that were moved onscreen
54  *   - gdk_window_process_updates() to handle the exposes immediately
55  *
56  * The second way is that you get the "invalidated" signal from the layout,
57  * indicating that lines have become invalid. This code path begins in
58  * invalidated_handler() and goes like this:
59  *   - install high-priority idle which does the rest of the steps
60  *   - if a scroll is pending from scroll_to_mark(), do the scroll,
61  *     jumping to the gtk_text_view_value_changed() code path
62  *   - otherwise, validate the onscreen lines
63  *   - DO NOT process updates
64  *
65  * In both cases, validating the onscreen lines can trigger a scroll
66  * due to maintaining the first_para on the top of the screen.
67  * If validation triggers a scroll, we jump to the top of the code path
68  * for value_changed, and bail out of the current code path.
69  *
70  * Also, in size_allocate, if we invalidate some lines from changing
71  * the layout width, we need to go ahead and run the high-priority idle,
72  * because GTK sends exposes right after doing the size allocates without
73  * returning to the main loop. This is also why the high-priority idle
74  * is at a higher priority than resizing.
75  *
76  */
77
78 #define FOCUS_EDGE_WIDTH 1
79
80 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
81 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
82
83 /* #define DEBUG_VALIDATION_AND_SCROLLING */
84
85 #ifdef DEBUG_VALIDATION_AND_SCROLLING
86 #define DV(x) (x)
87 #else
88 #define DV(x)
89 #endif
90
91 struct _GtkTextPendingScroll
92 {
93   GtkTextMark   *mark;
94   gdouble        within_margin;
95   gboolean       use_align;
96   gdouble        xalign;
97   gdouble        yalign;
98 };
99   
100 enum
101 {
102   MOVE_CURSOR,
103   SET_ANCHOR,
104   INSERT_AT_CURSOR,
105   DELETE_FROM_CURSOR,
106   CUT_CLIPBOARD,
107   COPY_CLIPBOARD,
108   PASTE_CLIPBOARD,
109   TOGGLE_OVERWRITE,
110   SET_SCROLL_ADJUSTMENTS,
111   LAST_SIGNAL
112 };
113
114 enum
115 {
116   ARG_0,
117   ARG_HEIGHT_LINES,
118   ARG_WIDTH_COLUMNS,
119   ARG_PIXELS_ABOVE_LINES,
120   ARG_PIXELS_BELOW_LINES,
121   ARG_PIXELS_INSIDE_WRAP,
122   ARG_EDITABLE,
123   ARG_WRAP_MODE,
124   ARG_JUSTIFY,
125   ARG_LEFT_MARGIN,
126   ARG_RIGHT_MARGIN,
127   ARG_INDENT,
128   ARG_TABS,
129   LAST_ARG
130 };
131
132 static void gtk_text_view_init                 (GtkTextView      *text_view);
133 static void gtk_text_view_class_init           (GtkTextViewClass *klass);
134 static void gtk_text_view_destroy              (GtkObject        *object);
135 static void gtk_text_view_finalize             (GObject          *object);
136 static void gtk_text_view_set_arg              (GtkObject        *object,
137                                                 GtkArg           *arg,
138                                                 guint             arg_id);
139 static void gtk_text_view_get_arg              (GtkObject        *object,
140                                                 GtkArg           *arg,
141                                                 guint             arg_id);
142 static void gtk_text_view_size_request         (GtkWidget        *widget,
143                                                 GtkRequisition   *requisition);
144 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
145                                                 GtkAllocation    *allocation);
146 static void gtk_text_view_realize              (GtkWidget        *widget);
147 static void gtk_text_view_unrealize            (GtkWidget        *widget);
148 static void gtk_text_view_style_set            (GtkWidget        *widget,
149                                                 GtkStyle         *previous_style);
150 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
151                                                 GtkTextDirection  previous_direction);
152 static gint gtk_text_view_event                (GtkWidget        *widget,
153                                                 GdkEvent         *event);
154 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
155                                                 GdkEventKey      *event);
156 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
157                                                 GdkEventKey      *event);
158 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
159                                                 GdkEventButton   *event);
160 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
161                                                 GdkEventButton   *event);
162 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
163                                                 GdkEventFocus    *event);
164 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
165                                                 GdkEventFocus    *event);
166 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
167                                                 GdkEventMotion   *event);
168 static gint gtk_text_view_expose_event         (GtkWidget        *widget,
169                                                 GdkEventExpose   *expose);
170 static void gtk_text_view_draw_focus           (GtkWidget        *widget);
171
172 /* Source side drag signals */
173 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
174                                             GdkDragContext   *context);
175 static void gtk_text_view_drag_end         (GtkWidget        *widget,
176                                             GdkDragContext   *context);
177 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
178                                             GdkDragContext   *context,
179                                             GtkSelectionData *selection_data,
180                                             guint             info,
181                                             guint             time);
182 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
183                                             GdkDragContext   *context);
184
185 /* Target side drag signals */
186 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
187                                                   GdkDragContext   *context,
188                                                   guint             time);
189 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
190                                                   GdkDragContext   *context,
191                                                   gint              x,
192                                                   gint              y,
193                                                   guint             time);
194 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
195                                                   GdkDragContext   *context,
196                                                   gint              x,
197                                                   gint              y,
198                                                   guint             time);
199 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
200                                                   GdkDragContext   *context,
201                                                   gint              x,
202                                                   gint              y,
203                                                   GtkSelectionData *selection_data,
204                                                   guint             info,
205                                                   guint             time);
206
207 static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
208                                                   GtkAdjustment *hadj,
209                                                   GtkAdjustment *vadj);
210
211 static void gtk_text_view_move_cursor      (GtkTextView           *text_view,
212                                             GtkMovementStep        step,
213                                             gint                   count,
214                                             gboolean               extend_selection);
215 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
216 static void gtk_text_view_scroll_pages     (GtkTextView           *text_view,
217                                             gint                   count);
218 static void gtk_text_view_insert_at_cursor (GtkTextView           *text_view,
219                                             const gchar           *str);
220 static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
221                                               GtkDeleteType          type,
222                                               gint                   count);
223 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
224 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
225 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
226 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
227 static void gtk_text_view_unselect         (GtkTextView           *text_view);
228
229 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
230 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
231                                                      GtkTextIter        *iter);
232 static void     gtk_text_view_update_layout_width       (GtkTextView        *text_view);
233 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
234                                                          GtkTextAttributes *values,
235                                                          GtkStyle           *style);
236 static void     gtk_text_view_ensure_layout         (GtkTextView        *text_view);
237 static void     gtk_text_view_destroy_layout        (GtkTextView        *text_view);
238 static void     gtk_text_view_reset_im_context      (GtkTextView        *text_view);
239 static void     gtk_text_view_start_selection_drag  (GtkTextView        *text_view,
240                                                      const GtkTextIter  *iter,
241                                                      GdkEventButton     *event);
242 static gboolean gtk_text_view_end_selection_drag    (GtkTextView        *text_view,
243                                                      GdkEventButton     *event);
244 static void     gtk_text_view_start_selection_dnd   (GtkTextView        *text_view,
245                                                      const GtkTextIter  *iter,
246                                                      GdkEventMotion     *event);
247 static void     gtk_text_view_start_cursor_blink    (GtkTextView        *text_view,
248                                                      gboolean            with_delay);
249 static void     gtk_text_view_stop_cursor_blink     (GtkTextView        *text_view);
250
251 static void gtk_text_view_value_changed           (GtkAdjustment *adj,
252                                                    GtkTextView   *view);
253 static void gtk_text_view_commit_handler          (GtkIMContext  *context,
254                                                    const gchar   *str,
255                                                    GtkTextView   *text_view);
256 static void gtk_text_view_preedit_changed_handler (GtkIMContext  *context,
257                                                    GtkTextView   *text_view);
258
259 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
260                                                   const GtkTextIter *location,
261                                                   GtkTextMark       *mark,
262                                                   gpointer           data);
263 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
264                                                   gint              *x,
265                                                   gint              *y);
266 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
267                                                   gint               x,
268                                                   gint               y);
269
270 static GtkAdjustment* get_hadjustment            (GtkTextView       *text_view);
271 static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
272
273 static void gtk_text_view_popup_menu             (GtkTextView       *text_view,
274                                                   GdkEventButton    *event);
275
276 static void gtk_text_view_queue_scroll           (GtkTextView   *text_view,
277                                                   GtkTextMark   *mark,
278                                                   gdouble        within_margin,
279                                                   gboolean       use_align,
280                                                   gdouble        xalign,
281                                                   gdouble        yalign);
282
283 static gboolean gtk_text_view_flush_scroll       (GtkTextView *text_view);
284
285 /* Container methods */
286 static void gtk_text_view_add    (GtkContainer *container,
287                                   GtkWidget    *child);
288 static void gtk_text_view_remove (GtkContainer *container,
289                                   GtkWidget    *child);
290 static void gtk_text_view_forall (GtkContainer *container,
291                                   gboolean      include_internals,
292                                   GtkCallback   callback,
293                                   gpointer      callback_data);
294
295 /* FIXME probably need the focus methods. */
296
297 /* Hack-around */
298 #define g_signal_handlers_disconnect_by_func(obj, func, data) g_signal_handlers_disconnect_matched (obj, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, func, data)
299
300 typedef struct _GtkTextViewChild GtkTextViewChild;
301
302 struct _GtkTextViewChild
303 {
304   GtkWidget *widget;
305
306   GtkTextChildAnchor *anchor;
307
308   gint from_top_of_line;
309   gint from_left_of_buffer;
310   
311   /* These are ignored if anchor != NULL */
312   GtkTextWindowType type;
313   gint x;
314   gint y;
315 };
316
317 static GtkTextViewChild* text_view_child_new_anchored (GtkWidget          *child,
318                                                        GtkTextChildAnchor *anchor,
319                                                        GtkTextLayout      *layout);
320 static GtkTextViewChild* text_view_child_new_window   (GtkWidget          *child,
321                                                        GtkTextWindowType   type,
322                                                        gint                x,
323                                                        gint                y);
324 static void              text_view_child_free         (GtkTextViewChild   *child);
325
326 static void              text_view_child_realize      (GtkTextView      *text_view,
327                                                        GtkTextViewChild *child);
328
329 struct _GtkTextWindow
330 {
331   GtkTextWindowType type;
332   GtkWidget *widget;
333   GdkWindow *window;
334   GdkWindow *bin_window;
335   GtkRequisition requisition;
336   GdkRectangle allocation;
337 };
338
339 static GtkTextWindow *text_window_new             (GtkTextWindowType  type,
340                                                    GtkWidget         *widget,
341                                                    gint               width_request,
342                                                    gint               height_request);
343 static void           text_window_free            (GtkTextWindow     *win);
344 static void           text_window_realize         (GtkTextWindow     *win,
345                                                    GdkWindow         *parent);
346 static void           text_window_unrealize       (GtkTextWindow     *win);
347 static void           text_window_size_allocate   (GtkTextWindow     *win,
348                                                    GdkRectangle      *rect);
349 static void           text_window_scroll          (GtkTextWindow     *win,
350                                                    gint               dx,
351                                                    gint               dy);
352 static void           text_window_invalidate_rect (GtkTextWindow     *win,
353                                                    GdkRectangle      *rect);
354
355 static gint           text_window_get_width       (GtkTextWindow     *win);
356 static gint           text_window_get_height      (GtkTextWindow     *win);
357 static void           text_window_get_allocation  (GtkTextWindow     *win,
358                                                    GdkRectangle      *rect);
359
360
361 enum
362 {
363   TARGET_STRING,
364   TARGET_TEXT,
365   TARGET_COMPOUND_TEXT,
366   TARGET_UTF8_STRING,
367   TARGET_TEXT_BUFFER_CONTENTS
368 };
369
370 static GtkTargetEntry target_table[] = {
371   { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP,
372     TARGET_TEXT_BUFFER_CONTENTS },
373   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
374   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
375   { "TEXT", 0, TARGET_TEXT },
376   { "text/plain", 0, TARGET_STRING },
377   { "STRING",     0, TARGET_STRING }
378 };
379
380 static GtkContainerClass *parent_class = NULL;
381 static guint signals[LAST_SIGNAL] = { 0 };
382
383 GtkType
384 gtk_text_view_get_type (void)
385 {
386   static GtkType our_type = 0;
387
388   if (our_type == 0)
389     {
390       static const GtkTypeInfo our_info =
391       {
392         "GtkTextView",
393         sizeof (GtkTextView),
394         sizeof (GtkTextViewClass),
395         (GtkClassInitFunc) gtk_text_view_class_init,
396         (GtkObjectInitFunc) gtk_text_view_init,
397         /* reserved_1 */ NULL,
398         /* reserved_2 */ NULL,
399         (GtkClassInitFunc) NULL
400       };
401
402       our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
403     }
404
405   return our_type;
406 }
407
408 static void
409 add_move_binding (GtkBindingSet  *binding_set,
410                   guint           keyval,
411                   guint           modmask,
412                   GtkMovementStep step,
413                   gint            count)
414 {
415   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
416
417   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
418                                 "move_cursor", 3,
419                                 GTK_TYPE_ENUM, step,
420                                 GTK_TYPE_INT, count,
421                                 GTK_TYPE_BOOL, FALSE);
422
423   /* Selection-extending version */
424   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
425                                 "move_cursor", 3,
426                                 GTK_TYPE_ENUM, step,
427                                 GTK_TYPE_INT, count,
428                                 GTK_TYPE_BOOL, TRUE);
429 }
430
431 static void
432 gtk_text_view_class_init (GtkTextViewClass *klass)
433 {
434   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
435   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
436   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
437   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
438   GtkBindingSet *binding_set;
439
440   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
441
442   /* Default handlers and virtual methods
443    */
444   object_class->set_arg = gtk_text_view_set_arg;
445   object_class->get_arg = gtk_text_view_get_arg;
446
447   object_class->destroy = gtk_text_view_destroy;
448   gobject_class->finalize = gtk_text_view_finalize;
449
450   widget_class->realize = gtk_text_view_realize;
451   widget_class->unrealize = gtk_text_view_unrealize;
452   widget_class->style_set = gtk_text_view_style_set;
453   widget_class->direction_changed = gtk_text_view_direction_changed;
454   widget_class->size_request = gtk_text_view_size_request;
455   widget_class->size_allocate = gtk_text_view_size_allocate;
456   widget_class->event = gtk_text_view_event;
457   widget_class->key_press_event = gtk_text_view_key_press_event;
458   widget_class->key_release_event = gtk_text_view_key_release_event;
459   widget_class->button_press_event = gtk_text_view_button_press_event;
460   widget_class->button_release_event = gtk_text_view_button_release_event;
461   widget_class->focus_in_event = gtk_text_view_focus_in_event;
462   widget_class->focus_out_event = gtk_text_view_focus_out_event;
463   widget_class->motion_notify_event = gtk_text_view_motion_event;
464   widget_class->expose_event = gtk_text_view_expose_event;
465   widget_class->draw_focus = gtk_text_view_draw_focus;
466
467   widget_class->drag_begin = gtk_text_view_drag_begin;
468   widget_class->drag_end = gtk_text_view_drag_end;
469   widget_class->drag_data_get = gtk_text_view_drag_data_get;
470   widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
471
472   widget_class->drag_leave = gtk_text_view_drag_leave;
473   widget_class->drag_motion = gtk_text_view_drag_motion;
474   widget_class->drag_drop = gtk_text_view_drag_drop;
475   widget_class->drag_data_received = gtk_text_view_drag_data_received;
476
477   container_class->add = gtk_text_view_add;
478   container_class->remove = gtk_text_view_remove;
479   container_class->forall = gtk_text_view_forall;
480
481   klass->move_cursor = gtk_text_view_move_cursor;
482   klass->set_anchor = gtk_text_view_set_anchor;
483   klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
484   klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
485   klass->cut_clipboard = gtk_text_view_cut_clipboard;
486   klass->copy_clipboard = gtk_text_view_copy_clipboard;
487   klass->paste_clipboard = gtk_text_view_paste_clipboard;
488   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
489   klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
490
491   /*
492    * Arguments
493    */
494   gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
495                            GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
496   gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
497                            GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
498   gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
499                            GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
500   gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
501                            GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
502   gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
503                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
504   gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
505                            GTK_ARG_READWRITE, ARG_EDITABLE);
506   gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
507                            GTK_ARG_READWRITE, ARG_WRAP_MODE);
508   gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_ENUM,
509                            GTK_ARG_READWRITE, ARG_JUSTIFY);
510   gtk_object_add_arg_type ("GtkTextView::left_margin", GTK_TYPE_INT,
511                            GTK_ARG_READWRITE, ARG_LEFT_MARGIN);
512   gtk_object_add_arg_type ("GtkTextView::right_margin", GTK_TYPE_INT,
513                            GTK_ARG_READWRITE, ARG_RIGHT_MARGIN);
514   gtk_object_add_arg_type ("GtkTextView::indent", GTK_TYPE_INT,
515                            GTK_ARG_READWRITE, ARG_INDENT);
516   gtk_object_add_arg_type ("GtkTextView::tabs", GTK_TYPE_POINTER, /* FIXME */
517                            GTK_ARG_READWRITE, ARG_TABS);
518
519   /*
520    * Signals
521    */
522
523   signals[MOVE_CURSOR] =
524     gtk_signal_new ("move_cursor",
525                     GTK_RUN_LAST | GTK_RUN_ACTION,
526                     GTK_CLASS_TYPE (object_class),
527                     GTK_SIGNAL_OFFSET (GtkTextViewClass, move_cursor),
528                     gtk_marshal_VOID__ENUM_INT_BOOLEAN,
529                     GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
530
531   signals[SET_ANCHOR] =
532     gtk_signal_new ("set_anchor",
533                     GTK_RUN_LAST | GTK_RUN_ACTION,
534                     GTK_CLASS_TYPE (object_class),
535                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
536                     gtk_marshal_VOID__VOID,
537                     GTK_TYPE_NONE, 0);
538
539   signals[INSERT_AT_CURSOR] =
540     gtk_signal_new ("insert_at_cursor",
541                     GTK_RUN_LAST | GTK_RUN_ACTION,
542                     GTK_CLASS_TYPE (object_class),
543                     GTK_SIGNAL_OFFSET (GtkTextViewClass, insert_at_cursor),
544                     gtk_marshal_VOID__POINTER,
545                     GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
546
547   signals[DELETE_FROM_CURSOR] =
548     gtk_signal_new ("delete_from_cursor",
549                     GTK_RUN_LAST | GTK_RUN_ACTION,
550                     GTK_CLASS_TYPE (object_class),
551                     GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_from_cursor),
552                     gtk_marshal_VOID__ENUM_INT,
553                     GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
554
555   signals[CUT_CLIPBOARD] =
556     gtk_signal_new ("cut_clipboard",
557                     GTK_RUN_LAST | GTK_RUN_ACTION,
558                     GTK_CLASS_TYPE (object_class),
559                     GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_clipboard),
560                     gtk_marshal_VOID__VOID,
561                     GTK_TYPE_NONE, 0);
562
563   signals[COPY_CLIPBOARD] =
564     gtk_signal_new ("copy_clipboard",
565                     GTK_RUN_LAST | GTK_RUN_ACTION,
566                     GTK_CLASS_TYPE (object_class),
567                     GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_clipboard),
568                     gtk_marshal_VOID__VOID,
569                     GTK_TYPE_NONE, 0);
570
571   signals[PASTE_CLIPBOARD] =
572     gtk_signal_new ("paste_clipboard",
573                     GTK_RUN_LAST | GTK_RUN_ACTION,
574                     GTK_CLASS_TYPE (object_class),
575                     GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_clipboard),
576                     gtk_marshal_VOID__VOID,
577                     GTK_TYPE_NONE, 0);
578
579   signals[TOGGLE_OVERWRITE] =
580     gtk_signal_new ("toggle_overwrite",
581                     GTK_RUN_LAST | GTK_RUN_ACTION,
582                     GTK_CLASS_TYPE (object_class),
583                     GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
584                     gtk_marshal_VOID__VOID,
585                     GTK_TYPE_NONE, 0);
586
587   signals[SET_SCROLL_ADJUSTMENTS] =
588     gtk_signal_new ("set_scroll_adjustments",
589                     GTK_RUN_LAST,
590                     GTK_CLASS_TYPE (object_class),
591                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
592                     gtk_marshal_VOID__POINTER_POINTER,
593                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
594   widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
595
596   /*
597    * Key bindings
598    */
599
600   binding_set = gtk_binding_set_by_class (klass);
601
602   /* Moving the insertion point */
603   add_move_binding (binding_set, GDK_Right, 0,
604                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
605
606   add_move_binding (binding_set, GDK_Left, 0,
607                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
608
609   add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
610                     GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
611
612   add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
613                     GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
614
615   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
616                     GTK_MOVEMENT_WORDS, 1);
617
618   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
619                     GTK_MOVEMENT_WORDS, -1);
620
621   /* Eventually we want to move by display lines, not paragraphs */
622   add_move_binding (binding_set, GDK_Up, 0,
623                     GTK_MOVEMENT_DISPLAY_LINES, -1);
624
625   add_move_binding (binding_set, GDK_Down, 0,
626                     GTK_MOVEMENT_DISPLAY_LINES, 1);
627
628   add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
629                     GTK_MOVEMENT_DISPLAY_LINES, -1);
630
631   add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
632                     GTK_MOVEMENT_DISPLAY_LINES, 1);
633
634   add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
635                     GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
636
637   add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
638                     GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
639
640   add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
641                     GTK_MOVEMENT_WORDS, 1);
642
643   add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
644                     GTK_MOVEMENT_WORDS, -1);
645
646   add_move_binding (binding_set, GDK_Home, 0,
647                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
648
649   add_move_binding (binding_set, GDK_End, 0,
650                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
651
652   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
653                     GTK_MOVEMENT_BUFFER_ENDS, -1);
654
655   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
656                     GTK_MOVEMENT_BUFFER_ENDS, 1);
657
658   add_move_binding (binding_set, GDK_Page_Up, 0,
659                     GTK_MOVEMENT_PAGES, -1);
660
661   add_move_binding (binding_set, GDK_Page_Down, 0,
662                     GTK_MOVEMENT_PAGES, 1);
663
664
665   /* Setting the cut/paste/copy anchor */
666   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
667                                 "set_anchor", 0);
668
669   /* Deleting text */
670   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
671                                 "delete_from_cursor", 2,
672                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
673                                 GTK_TYPE_INT, 1);
674
675   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
676                                 "delete_from_cursor", 2,
677                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
678                                 GTK_TYPE_INT, 1);
679
680   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
681                                 "delete_from_cursor", 2,
682                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
683                                 GTK_TYPE_INT, -1);
684
685   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
686                                 "delete_from_cursor", 2,
687                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
688                                 GTK_TYPE_INT, 1);
689
690   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
691                                 "delete_from_cursor", 2,
692                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
693                                 GTK_TYPE_INT, 1);
694
695   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
696                                 "delete_from_cursor", 2,
697                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
698                                 GTK_TYPE_INT, -1);
699
700   gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
701                                 "delete_from_cursor", 2,
702                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
703                                 GTK_TYPE_INT, 1);
704
705   gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
706                                 "delete_from_cursor", 2,
707                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
708                                 GTK_TYPE_INT, 1);
709
710   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
711                                 "delete_from_cursor", 2,
712                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
713                                 GTK_TYPE_INT, 1);
714   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
715                                 "insert_at_cursor", 1,
716                                 GTK_TYPE_STRING, " ");
717
718   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
719                                 "delete_from_cursor", 2,
720                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
721                                 GTK_TYPE_INT, 1);
722
723   /* Cut/copy/paste */
724
725   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
726                                 "cut_clipboard", 0);
727
728   gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
729                                 "cut_clipboard", 0);
730
731   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
732                                 "copy_clipboard", 0);
733
734   gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
735                                 "paste_clipboard", 0);
736
737   gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
738                                 "paste_clipboard", 0);
739
740   /* Overwrite */
741   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
742                                 "toggle_overwrite", 0);
743 }
744
745 void
746 gtk_text_view_init (GtkTextView *text_view)
747 {
748   GtkWidget *widget;
749
750   widget = GTK_WIDGET (text_view);
751
752   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
753
754   /* Set up default style */
755   text_view->wrap_mode = GTK_WRAP_NONE;
756   text_view->pixels_above_lines = 0;
757   text_view->pixels_below_lines = 0;
758   text_view->pixels_inside_wrap = 0;
759   text_view->justify = GTK_JUSTIFY_LEFT;
760   text_view->left_margin = 0;
761   text_view->right_margin = 0;
762   text_view->indent = 0;
763   text_view->tabs = NULL;
764   text_view->editable = TRUE;
765
766   gtk_drag_dest_set (widget,
767                      GTK_DEST_DEFAULT_DROP,
768                      target_table, G_N_ELEMENTS (target_table),
769                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
770
771   text_view->virtual_cursor_x = -1;
772   text_view->virtual_cursor_y = -1;
773
774   /* This object is completely private. No external entity can gain a reference
775    * to it; so we create it here and destroy it in finalize ().
776    */
777   text_view->im_context = gtk_im_multicontext_new ();
778
779   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
780                       GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
781
782   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "preedit_changed",
783                       GTK_SIGNAL_FUNC (gtk_text_view_preedit_changed_handler), text_view);
784
785   text_view->cursor_visible = TRUE;
786
787   text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
788                                             widget, 200, 200);
789
790   text_view->drag_start_x = -1;
791   text_view->drag_start_y = -1;
792 }
793
794 /**
795  * gtk_text_view_new:
796  *
797  * Creates a new #GtkTextView. If you don't call gtk_text_view_set_buffer()
798  * before using the text view, an empty default buffer will be created
799  * for you. Get the buffer with gtk_text_view_get_buffer(). If you want
800  * to specify your own buffer, consider gtk_text_view_new_with_buffer().
801  *
802  * Return value: a new #GtkTextView
803  **/
804 GtkWidget*
805 gtk_text_view_new (void)
806 {
807   return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
808 }
809
810 /**
811  * gtk_text_view_new_with_buffer:
812  * @buffer: a #GtkTextBuffer
813  *
814  * Creates a new #GtkTextView widget displaying the buffer
815  * @buffer. One buffer can be shared among many widgets.
816  * @buffer may be NULL to create a default buffer, in which case
817  * this function is equivalent to gtk_text_view_new(). The
818  * text view adds its own reference count to the buffer; it does not
819  * take over an existing reference.
820  *
821  * Return value: a new #GtkTextView.
822  **/
823 GtkWidget*
824 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
825 {
826   GtkTextView *text_view;
827
828   text_view = (GtkTextView*)gtk_text_view_new ();
829
830   gtk_text_view_set_buffer (text_view, buffer);
831
832   return GTK_WIDGET (text_view);
833 }
834
835 /**
836  * gtk_text_view_set_buffer:
837  * @text_view: a #GtkTextView
838  * @buffer: a #GtkTextBuffer
839  *
840  * Sets @buffer as the buffer being displayed by @text_view. The previous
841  * buffer displayed by the text view is unreferenced, and a reference is
842  * added to @buffer. If you owned a reference to @buffer before passing it
843  * to this function, you must remove that reference yourself; #GtkTextView
844  * will not "adopt" it.
845  *
846  **/
847 void
848 gtk_text_view_set_buffer (GtkTextView   *text_view,
849                           GtkTextBuffer *buffer)
850 {
851   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
852   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
853
854   if (text_view->buffer == buffer)
855     return;
856
857   if (text_view->buffer != NULL)
858     {
859       /* Destroy all anchored children */
860       GSList *tmp_list;
861       GSList *copy;
862
863       copy = g_slist_copy (text_view->children);
864       tmp_list = copy;
865       while (tmp_list != NULL)
866         {
867           GtkTextViewChild *vc = tmp_list->data;
868
869           if (vc->anchor)
870             {
871               gtk_widget_destroy (vc->widget);
872               /* vc may now be invalid! */
873             }
874
875           tmp_list = g_slist_next (tmp_list);
876         }
877
878       g_slist_free (copy);
879
880       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->buffer),
881                                             gtk_text_view_mark_set_handler, text_view);
882       g_object_unref (G_OBJECT (text_view->buffer));
883       text_view->dnd_mark = NULL;
884     }
885
886   text_view->buffer = buffer;
887
888   if (buffer != NULL)
889     {
890       GtkTextIter start;
891
892       g_object_ref (G_OBJECT (buffer));
893
894       if (text_view->layout)
895         gtk_text_layout_set_buffer (text_view->layout, buffer);
896
897       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
898
899       text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
900                                                          "gtk_drag_target",
901                                                          &start, FALSE);
902
903       text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
904                                                                 NULL,
905                                                                 &start, TRUE);
906
907       text_view->first_para_pixels = 0;
908
909       g_signal_connect_data (G_OBJECT (text_view->buffer), "mark_set",
910                              gtk_text_view_mark_set_handler, text_view,
911                              NULL, FALSE, FALSE);
912     }
913
914   if (GTK_WIDGET_VISIBLE (text_view))
915     gtk_widget_queue_draw (GTK_WIDGET (text_view));
916 }
917
918 static GtkTextBuffer*
919 get_buffer (GtkTextView *text_view)
920 {
921   if (text_view->buffer == NULL)
922     {
923       GtkTextBuffer *b;
924       b = gtk_text_buffer_new (NULL);
925       gtk_text_view_set_buffer (text_view, b);
926       g_object_unref (G_OBJECT (b));
927     }
928
929   return text_view->buffer;
930 }
931
932 /**
933  * gtk_text_view_get_buffer:
934  * @text_view: a #GtkTextView
935  *
936  * Returns the #GtkTextBuffer being displayed by this text view.
937  * The reference count on the buffer is not incremented; the caller
938  * of this function won't own a new reference.
939  *
940  * Return value: a #GtkTextBuffer
941  **/
942 GtkTextBuffer*
943 gtk_text_view_get_buffer (GtkTextView *text_view)
944 {
945   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
946
947   return get_buffer (text_view);
948 }
949
950 /**
951  * gtk_text_view_get_iter_at_location:
952  * @text_view: a #GtkTextView
953  * @iter: a #GtkTextIter
954  * @x: x position, in buffer coordinates
955  * @y: y position, in buffer coordinates
956  *
957  * Retrieves the iterator at buffer coordinates @x and @y. Buffer
958  * coordinates are coordinates for the entire buffer, not just the
959  * currently-displayed portion.  If you have coordinates from an
960  * event, you have to convert those to buffer coordinates with
961  * gtk_text_view_window_to_buffer_coords().
962  *
963  **/
964 void
965 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
966                                     GtkTextIter *iter,
967                                     gint         x,
968                                     gint         y)
969 {
970   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
971   g_return_if_fail (iter != NULL);
972   g_return_if_fail (text_view->layout != NULL);
973
974   gtk_text_layout_get_iter_at_pixel (text_view->layout,
975                                      iter,
976                                      x,
977                                      y);
978 }
979
980 /**
981  * gtk_text_view_get_iter_location:
982  * @text_view: a #GtkTextView
983  * @iter: a #GtkTextIter
984  * @location: bounds of the character at @iter
985  *
986  * Gets a rectangle which roughly contains the character at @iter.
987  * The rectangle position is in buffer coordinates; use
988  * gtk_text_view_buffer_to_window_coords() to convert these
989  * coordinates to coordinates for one of the windows in the text view.
990  *
991  **/
992 void
993 gtk_text_view_get_iter_location (GtkTextView       *text_view,
994                                  const GtkTextIter *iter,
995                                  GdkRectangle      *location)
996 {
997   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
998   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
999
1000   gtk_text_layout_get_iter_location (text_view->layout, iter, location);
1001 }
1002
1003 /**
1004  * gtk_text_view_get_line_yrange:
1005  * @text_view: a #GtkTextView
1006  * @iter: a #GtkTextIter
1007  * @y: return location for a y coordinate
1008  * @height: return location for a height
1009  *
1010  * Gets the y coordinate of the top of the line containing @iter,
1011  * and the height of the line. The coordinate is a buffer coordinate;
1012  * convert to window coordinates with gtk_text_view_buffer_to_window_coords().
1013  *
1014  **/
1015 void
1016 gtk_text_view_get_line_yrange (GtkTextView       *text_view,
1017                                const GtkTextIter *iter,
1018                                gint              *y,
1019                                gint              *height)
1020 {
1021   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1022   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1023
1024   gtk_text_layout_get_line_yrange (text_view->layout,
1025                                    iter,
1026                                    y,
1027                                    height);
1028 }
1029
1030 /**
1031  * gtk_text_view_get_line_at_y:
1032  * @text_view: a #GtkTextView
1033  * @target_iter: a #GtkTextIter
1034  * @y: a y coordinate
1035  * @line_top: return location for top coordinate of the line
1036  *
1037  * Gets the #GtkTextIter at the start of the line containing
1038  * the coordinate @y. @y is in buffer coordinates, convert from
1039  * window coordinates with gtk_text_view_window_to_buffer_coords().
1040  * If non-%NULL, @line_top will be filled with the coordinate of the top
1041  * edge of the line.
1042  **/
1043 void
1044 gtk_text_view_get_line_at_y (GtkTextView *text_view,
1045                              GtkTextIter *target_iter,
1046                              gint         y,
1047                              gint        *line_top)
1048 {
1049   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1050
1051   gtk_text_layout_get_line_at_y (text_view->layout,
1052                                  target_iter,
1053                                  y,
1054                                  line_top);
1055 }
1056
1057 static gboolean
1058 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
1059 {
1060   /* We don't really want to clamp to upper; we want to clamp to
1061      upper - page_size which is the highest value the scrollbar
1062      will let us reach. */
1063   if (val > (adj->upper - adj->page_size))
1064     val = adj->upper - adj->page_size;
1065
1066   if (val < adj->lower)
1067     val = adj->lower;
1068
1069   if (val != adj->value)
1070     {
1071       gtk_adjustment_set_value (adj, val);
1072       return TRUE;
1073     }
1074   else
1075     return FALSE;
1076 }
1077
1078 /**
1079  * gtk_text_view_scroll_to_iter:
1080  * @text_view: a #GtkTextView
1081  * @iter: a #GtkTextIter
1082  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1083  * @use_align: whether to use alignment arguments (if %FALSE, just get the mark onscreen)
1084  * @xalign: horizontal alignment of mark within visible area.
1085  * @yalign: vertical alignment of mark within visible area
1086  *
1087  * Scrolls @text_view so that @iter is on the screen in the position
1088  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1089  * left or top, 1.0 indicates right or bottom, 0.5 means center. If @use_align
1090  * is %FALSE, the text scrolls the minimal distance to get the mark onscreen,
1091  * possibly not scrolling at all. The effective screen for purposes
1092  * of this function is reduced by a margin of size @within_margin.
1093  * NOTE: This function uses the currently-computed height of the
1094  * lines in the text buffer. Note that line heights are computed
1095  * in an idle handler; so this function may not have the desired effect
1096  * if it's called before the height computations. To avoid oddness,
1097  * consider using gtk_text_view_scroll_to_mark() which saves a point
1098  * to be scrolled to after line validation.
1099  *
1100  * Return value: %TRUE if scrolling occurred
1101  **/
1102 gboolean
1103 gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
1104                               GtkTextIter   *iter,
1105                               gdouble        within_margin,
1106                               gboolean       use_align,
1107                               gdouble        xalign,
1108                               gdouble        yalign)
1109 {
1110   GdkRectangle rect;
1111   GdkRectangle screen;
1112   gint screen_bottom;
1113   gint screen_right;
1114   gint scroll_dest;
1115   GtkWidget *widget;
1116   gboolean retval = FALSE;
1117   gint scroll_inc;
1118   gint screen_xoffset, screen_yoffset;
1119   gint current_x_scroll, current_y_scroll;
1120   
1121   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1122   g_return_val_if_fail (iter != NULL, FALSE);
1123   g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE);
1124   g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE);
1125   g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE);
1126   
1127   widget = GTK_WIDGET (text_view);
1128
1129   DV(g_print(G_STRLOC"\n"));
1130   
1131   if (!GTK_WIDGET_MAPPED (widget))
1132     {
1133       g_warning ("%s: calling this function before mapping the GtkTextView doesn't make sense, maybe try gtk_text_view_scroll_to_mark() instead", G_STRLOC);
1134       return FALSE;
1135     }
1136   
1137   gtk_text_layout_get_iter_location (text_view->layout,
1138                                      iter,
1139                                      &rect);
1140
1141   current_x_scroll = text_view->xoffset;
1142   current_y_scroll = text_view->yoffset;
1143
1144   screen.x = current_x_scroll;
1145   screen.y = current_y_scroll;
1146   screen.width = SCREEN_WIDTH (widget);
1147   screen.height = SCREEN_HEIGHT (widget);
1148   
1149   screen_xoffset = screen.width * within_margin;
1150   screen_yoffset = screen.height * within_margin;
1151   
1152   screen.x += screen_xoffset;
1153   screen.y += screen_yoffset;
1154   screen.width -= screen_xoffset * 2;
1155   screen.height -= screen_yoffset * 2;
1156
1157   /* paranoia check */
1158   if (screen.width < 1)
1159     screen.width = 1;
1160   if (screen.height < 1)
1161     screen.height = 1;
1162   
1163   screen_right = screen.x + screen.width;
1164   screen_bottom = screen.y + screen.height;
1165   
1166   /* The alignment affects the point in the target character that we
1167    * choose to align. If we're doing right/bottom alignment, we align
1168    * the right/bottom edge of the character the mark is at; if we're
1169    * doing left/top we align the left/top edge of the character; if
1170    * we're doing center alignment we align the center of the
1171    * character.
1172    */
1173   
1174   /* Vertical scroll */
1175
1176   scroll_inc = 0;
1177   scroll_dest = current_y_scroll;
1178   
1179   if (use_align)
1180     {      
1181       scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
1182       
1183       /* if scroll_dest < screen.y, we move a negative increment (up),
1184        * else a positive increment (down)
1185        */
1186       scroll_inc = scroll_dest - screen.y + screen_yoffset;
1187     }
1188   else
1189     {
1190       /* move minimum to get onscreen */
1191       if (rect.y < screen.y)
1192         {
1193           scroll_dest = rect.y;
1194           scroll_inc = scroll_dest - screen.y - screen_yoffset;
1195         }
1196       else if ((rect.y + rect.height) > screen_bottom)
1197         {
1198           scroll_dest = rect.y + rect.height;
1199           scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
1200         }
1201     }  
1202   
1203   if (scroll_inc != 0)
1204     {
1205       retval = set_adjustment_clamped (get_vadjustment (text_view),
1206                                        current_y_scroll + scroll_inc);
1207     }
1208
1209   /* Horizontal scroll */
1210   
1211   scroll_inc = 0;
1212   scroll_dest = current_x_scroll;
1213   
1214   if (use_align)
1215     {      
1216       scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
1217
1218       /* if scroll_dest < screen.y, we move a negative increment (left),
1219        * else a positive increment (right)
1220        */
1221       scroll_inc = scroll_dest - screen.x + screen_xoffset;
1222     }
1223   else
1224     {
1225       /* move minimum to get onscreen */
1226       if (rect.x < screen.x)
1227         {
1228           scroll_dest = rect.x;
1229           scroll_inc = scroll_dest - screen.x - screen_xoffset;
1230         }
1231       else if ((rect.x + rect.width) > screen_right)
1232         {
1233           scroll_dest = rect.x + rect.width;
1234           scroll_inc = scroll_dest - screen_right + screen_xoffset;
1235         }
1236     }
1237   
1238   if (scroll_inc != 0)
1239     {
1240       retval = set_adjustment_clamped (get_hadjustment (text_view),
1241                                        current_x_scroll + scroll_inc);
1242     }
1243
1244   if (retval)
1245     DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
1246   else
1247     DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
1248   
1249   return retval;
1250 }
1251
1252 static void
1253 free_pending_scroll (GtkTextPendingScroll *scroll)
1254 {
1255   if (!gtk_text_mark_get_deleted (scroll->mark))
1256     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (scroll->mark),
1257                                  scroll->mark);
1258   g_object_unref (G_OBJECT (scroll->mark));
1259   g_free (scroll);
1260 }
1261
1262 static void
1263 gtk_text_view_queue_scroll (GtkTextView   *text_view,
1264                             GtkTextMark   *mark,
1265                             gdouble        within_margin,
1266                             gboolean       use_align,
1267                             gdouble        xalign,
1268                             gdouble        yalign)
1269 {
1270   GtkTextIter iter;
1271   GtkTextPendingScroll *scroll;
1272
1273   DV(g_print(G_STRLOC"\n"));
1274   
1275   scroll = g_new (GtkTextPendingScroll, 1);
1276
1277   scroll->within_margin = within_margin;
1278   scroll->use_align = use_align;
1279   scroll->xalign = xalign;
1280   scroll->yalign = yalign;
1281   
1282   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1283
1284   scroll->mark = gtk_text_buffer_create_mark (get_buffer (text_view),
1285                                               NULL,
1286                                               &iter,
1287                                               gtk_text_mark_get_left_gravity (mark));
1288
1289   g_object_ref (G_OBJECT (scroll->mark));
1290   
1291   if (text_view->pending_scroll)
1292     free_pending_scroll (text_view->pending_scroll);
1293
1294   text_view->pending_scroll = scroll;
1295 }
1296
1297 static gboolean
1298 gtk_text_view_flush_scroll (GtkTextView *text_view)
1299 {
1300   GtkTextIter iter, start, end;
1301   GtkTextPendingScroll *scroll;
1302   gint y0, y1, height;
1303   gboolean retval;
1304   
1305   DV(g_print(G_STRLOC"\n"));
1306   
1307   if (text_view->pending_scroll == NULL)
1308     return FALSE;
1309
1310   scroll = text_view->pending_scroll;
1311
1312   /* avoid recursion */
1313   text_view->pending_scroll = NULL;
1314   
1315   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, scroll->mark);
1316
1317   start = iter;
1318   end = iter;
1319
1320   /* Force-validate the region around the iterator, at least the lines
1321    * on either side, so that we can meaningfully get the iter location
1322    */
1323   gtk_text_iter_backward_line (&start);
1324   gtk_text_iter_forward_line (&end);
1325   
1326   gtk_text_layout_get_line_yrange (text_view->layout, &start, &y0, NULL);
1327   gtk_text_layout_get_line_yrange (text_view->layout, &end, &y1, &height);
1328
1329   DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
1330   gtk_text_layout_validate_yrange (text_view->layout, &start, y0, y1 + height);
1331
1332   DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
1333   
1334   retval = gtk_text_view_scroll_to_iter (text_view,
1335                                          &iter,
1336                                          scroll->within_margin,
1337                                          scroll->use_align,
1338                                          scroll->xalign,
1339                                          scroll->yalign);
1340   
1341   free_pending_scroll (scroll);
1342
1343   return retval;
1344 }
1345
1346 static void
1347 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
1348 {  
1349   if (upper != adj->upper)
1350     {
1351       gfloat min = MAX (0., upper - adj->page_size);
1352       gboolean value_changed = FALSE;
1353
1354       adj->upper = upper;
1355
1356       if (adj->value > min)
1357         {
1358           adj->value = min;
1359           value_changed = TRUE;
1360         }
1361
1362       gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
1363       DV(g_print(">Changed adj upper to %d ("G_STRLOC")\n", upper));
1364       
1365       if (value_changed)
1366         {
1367           DV(g_print(">Changed adj value because upper descreased ("G_STRLOC")\n"));
1368           gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
1369         }
1370     }
1371 }
1372
1373 static void
1374 gtk_text_view_update_adjustments (GtkTextView *text_view)
1375 {
1376   gint width = 0, height = 0;
1377
1378   DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
1379   
1380   gtk_text_layout_get_size (text_view->layout, &width, &height);
1381
1382   if (text_view->width != width || text_view->height != height)
1383     {
1384       text_view->width = width;
1385       text_view->height = height;
1386
1387       gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
1388                                           MAX (SCREEN_WIDTH (text_view), width));
1389       gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
1390                                           MAX (SCREEN_HEIGHT (text_view), height));
1391       
1392       /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
1393
1394       /* Set up the step sizes; we'll say that a page is
1395          our allocation minus one step, and a step is
1396          1/10 of our allocation. */
1397       text_view->hadjustment->step_increment =
1398         SCREEN_WIDTH (text_view) / 10.0;
1399       text_view->hadjustment->page_increment =
1400         SCREEN_WIDTH (text_view) * 0.9;
1401       
1402       text_view->vadjustment->step_increment =
1403         SCREEN_HEIGHT (text_view) / 10.0;
1404       text_view->vadjustment->page_increment =
1405         SCREEN_HEIGHT (text_view) * 0.9;
1406
1407       gtk_signal_emit_by_name (GTK_OBJECT (get_hadjustment (text_view)), "changed");
1408       gtk_signal_emit_by_name (GTK_OBJECT (get_hadjustment (text_view)), "changed");
1409     }
1410 }
1411
1412 static void
1413 gtk_text_view_update_layout_width (GtkTextView *text_view)
1414 {
1415   DV(g_print(">Updating layout width ("G_STRLOC")\n"));
1416   
1417   gtk_text_view_ensure_layout (text_view);
1418
1419   gtk_text_layout_set_screen_width (text_view->layout,
1420                                     SCREEN_WIDTH (text_view));
1421 }
1422
1423 /**
1424  * gtk_text_view_scroll_to_mark:
1425  * @text_view: a #GtkTextView
1426  * @mark: a #GtkTextMark
1427  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1428  * @use_align: whether to use alignment arguments (if %FALSE, just get the mark onscreen)
1429  * @xalign: horizontal alignment of mark within visible area.
1430  * @yalign: vertical alignment of mark within visible area
1431  *
1432  * Scrolls @text_view so that @mark is on the screen in the position
1433  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1434  * left or top, 1.0 indicates right or bottom, 0.5 means center. If @use_align
1435  * is %FALSE, the text scrolls the minimal distance to get the mark onscreen,
1436  * possibly not scrolling at all. The effective screen for purposes
1437  * of this function is reduced by a margin of size @within_margin.
1438  *
1439  **/
1440 void
1441 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
1442                               GtkTextMark *mark,
1443                               gdouble      within_margin,
1444                               gboolean     use_align,
1445                               gdouble      xalign,
1446                               gdouble      yalign)
1447 {  
1448   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1449   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1450   g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5);
1451   g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
1452   g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
1453
1454   gtk_text_view_queue_scroll (text_view, mark,
1455                               within_margin,
1456                               use_align,
1457                               xalign,
1458                               yalign);
1459
1460   /* If no validation is pending, we need to go ahead and force an
1461    * immediate scroll.
1462    */
1463   if (text_view->layout &&
1464       gtk_text_layout_is_valid (text_view->layout))
1465     gtk_text_view_flush_scroll (text_view);
1466 }
1467
1468 void
1469 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
1470                                     GtkTextMark *mark)
1471 {
1472   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1473   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1474
1475   gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
1476 }
1477
1478 static gboolean
1479 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
1480 {
1481   GdkRectangle visible_rect;
1482   gtk_text_view_get_visible_rect (text_view, &visible_rect);
1483
1484   return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
1485                                                visible_rect.y,
1486                                                visible_rect.y + visible_rect.height);
1487 }
1488
1489 /**
1490  * gtk_text_view_move_mark_onscreen:
1491  * @text_view: a #GtkTextView
1492  * @mark: a #GtkTextMark
1493  *
1494  * Moves a mark within the buffer so that it's
1495  * located within the currently-visible text area.
1496  *
1497  * Return value: %TRUE if the mark moved (wasn't already onscreen)
1498  **/
1499 gboolean
1500 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
1501                                   GtkTextMark *mark)
1502 {
1503   GtkTextIter iter;
1504
1505   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1506   g_return_val_if_fail (mark != NULL, FALSE);
1507
1508   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1509
1510   if (clamp_iter_onscreen (text_view, &iter))
1511     {
1512       gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
1513       return TRUE;
1514     }
1515   else
1516     return FALSE;
1517 }
1518
1519 /**
1520  * gtk_text_view_get_visible_rect:
1521  * @text_view: a #GtkTextView
1522  * @visible_rect: rectangle to fill
1523  *
1524  * Fills @visible_rect with the currently-visible
1525  * region of the buffer, in buffer coordinates. Convert to window coordinates
1526  * with gtk_text_view_buffer_to_window_coords().
1527  **/
1528 void
1529 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
1530                                 GdkRectangle *visible_rect)
1531 {
1532   GtkWidget *widget;
1533
1534   g_return_if_fail (text_view != NULL);
1535   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1536
1537   widget = GTK_WIDGET (text_view);
1538
1539   if (visible_rect)
1540     {
1541       visible_rect->x = text_view->xoffset;
1542       visible_rect->y = text_view->yoffset;
1543       visible_rect->width = SCREEN_WIDTH (widget);
1544       visible_rect->height = SCREEN_HEIGHT (widget);
1545
1546       DV(g_print(" visible rect: %d,%d %d x %d\n",
1547                  visible_rect->x,
1548                  visible_rect->y,
1549                  visible_rect->width,
1550                  visible_rect->height));
1551     }
1552 }
1553
1554 /**
1555  * gtk_text_view_set_wrap_mode:
1556  * @text_view: a #GtkTextView
1557  * @wrap_mode: a #GtkWrapMode
1558  *
1559  * Sets the line wrapping for the view.
1560  **/
1561 void
1562 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
1563                              GtkWrapMode  wrap_mode)
1564 {
1565   g_return_if_fail (text_view != NULL);
1566   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1567
1568   if (text_view->wrap_mode != wrap_mode)
1569     {
1570       text_view->wrap_mode = wrap_mode;
1571
1572       if (text_view->layout)
1573         {
1574           text_view->layout->default_style->wrap_mode = wrap_mode;
1575           gtk_text_layout_default_style_changed (text_view->layout);
1576         }
1577     }
1578 }
1579
1580 /**
1581  * gtk_text_view_get_wrap_mode:
1582  * @text_view: a #GtkTextView
1583  *
1584  * Gets the line wrapping for the view.
1585  *
1586  * Return value: the line wrap setting
1587  **/
1588 GtkWrapMode
1589 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
1590 {
1591   g_return_val_if_fail (text_view != NULL, GTK_WRAP_NONE);
1592   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAP_NONE);
1593
1594   return text_view->wrap_mode;
1595 }
1596
1597 /**
1598  * gtk_text_view_set_editable:
1599  * @text_view: a #GtkTextView
1600  * @setting: whether it's editable
1601  *
1602  * Sets the default editability of the #GtkTextView. You can override
1603  * this default setting with tags in the buffer, using the "editable"
1604  * attribute of tags.
1605  **/
1606 void
1607 gtk_text_view_set_editable (GtkTextView *text_view,
1608                             gboolean     setting)
1609 {
1610   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1611
1612   if (text_view->editable != setting)
1613     {
1614       text_view->editable = setting;
1615
1616       if (text_view->layout)
1617         {
1618           text_view->layout->default_style->editable = text_view->editable;
1619           gtk_text_layout_default_style_changed (text_view->layout);
1620         }
1621     }
1622 }
1623
1624 /**
1625  * gtk_text_view_get_editable:
1626  * @text_view: a #GtkTextView
1627  *
1628  * Returns the default editability of the #GtkTextView. Tags in the
1629  * buffer may override this setting for some ranges of text.
1630  *
1631  * Return value: whether text is editable by default
1632  **/
1633 gboolean
1634 gtk_text_view_get_editable (GtkTextView *text_view)
1635 {
1636   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1637
1638   return text_view->editable;
1639 }
1640
1641 void
1642 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
1643                                       gint         pixels_above_lines)
1644 {
1645   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1646
1647   if (text_view->pixels_above_lines != pixels_above_lines)
1648     {
1649       text_view->pixels_above_lines = pixels_above_lines;
1650
1651       if (text_view->layout)
1652         {
1653           text_view->layout->default_style->pixels_above_lines = pixels_above_lines;
1654           gtk_text_layout_default_style_changed (text_view->layout);
1655         }
1656     }
1657 }
1658
1659 gint
1660 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
1661 {
1662   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1663
1664   return text_view->pixels_above_lines;
1665 }
1666
1667 void
1668 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
1669                                       gint         pixels_below_lines)
1670 {
1671   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1672
1673   if (text_view->pixels_below_lines != pixels_below_lines)
1674     {
1675       text_view->pixels_below_lines = pixels_below_lines;
1676
1677       if (text_view->layout)
1678         {
1679           text_view->layout->default_style->pixels_below_lines = pixels_below_lines;
1680           gtk_text_layout_default_style_changed (text_view->layout);
1681         }
1682     }
1683 }
1684
1685 gint
1686 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
1687 {
1688   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1689
1690   return text_view->pixels_below_lines;
1691 }
1692
1693 void
1694 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
1695                                       gint         pixels_inside_wrap)
1696 {
1697   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1698
1699   if (text_view->pixels_inside_wrap != pixels_inside_wrap)
1700     {
1701       text_view->pixels_inside_wrap = pixels_inside_wrap;
1702
1703       if (text_view->layout)
1704         {
1705           text_view->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
1706           gtk_text_layout_default_style_changed (text_view->layout);
1707         }
1708     }
1709 }
1710
1711 gint
1712 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
1713 {
1714   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1715
1716   return text_view->pixels_inside_wrap;
1717 }
1718
1719 void
1720 gtk_text_view_set_justification (GtkTextView     *text_view,
1721                                  GtkJustification justify)
1722 {
1723   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1724
1725   if (text_view->justify != justify)
1726     {
1727       text_view->justify = justify;
1728
1729       if (text_view->layout)
1730         {
1731           text_view->layout->default_style->justification = justify;
1732           gtk_text_layout_default_style_changed (text_view->layout);
1733         }
1734     }
1735 }
1736
1737 GtkJustification
1738 gtk_text_view_get_justification (GtkTextView *text_view)
1739 {
1740   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
1741
1742   return text_view->justify;
1743 }
1744
1745 void
1746 gtk_text_view_set_left_margin (GtkTextView *text_view,
1747                                gint         left_margin)
1748 {
1749   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1750
1751   if (text_view->left_margin != left_margin)
1752     {
1753       text_view->left_margin = left_margin;
1754
1755       if (text_view->layout)
1756         {
1757           text_view->layout->default_style->left_margin = left_margin;
1758           gtk_text_layout_default_style_changed (text_view->layout);
1759         }
1760     }
1761 }
1762
1763 gint
1764 gtk_text_view_get_left_margin (GtkTextView *text_view)
1765 {
1766   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1767
1768   return text_view->left_margin;
1769 }
1770
1771 void
1772 gtk_text_view_set_right_margin (GtkTextView *text_view,
1773                                 gint         right_margin)
1774 {
1775   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1776
1777   if (text_view->right_margin != right_margin)
1778     {
1779       text_view->right_margin = right_margin;
1780
1781       if (text_view->layout)
1782         {
1783           text_view->layout->default_style->right_margin = right_margin;
1784           gtk_text_layout_default_style_changed (text_view->layout);
1785         }
1786     }
1787 }
1788
1789 gint
1790 gtk_text_view_get_right_margin (GtkTextView *text_view)
1791 {
1792   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1793
1794   return text_view->right_margin;
1795 }
1796
1797 void
1798 gtk_text_view_set_indent (GtkTextView *text_view,
1799                           gint         indent)
1800 {
1801   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1802
1803   if (text_view->indent != indent)
1804     {
1805       text_view->indent = indent;
1806
1807       if (text_view->layout)
1808         {
1809           text_view->layout->default_style->indent = indent;
1810           gtk_text_layout_default_style_changed (text_view->layout);
1811         }
1812     }
1813 }
1814
1815 gint
1816 gtk_text_view_get_indent (GtkTextView *text_view)
1817 {
1818   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1819
1820   return text_view->indent;
1821 }
1822
1823 void
1824 gtk_text_view_set_tabs (GtkTextView   *text_view,
1825                         PangoTabArray *tabs)
1826 {
1827   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1828
1829   if (text_view->tabs)
1830     pango_tab_array_free (text_view->tabs);
1831
1832   text_view->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
1833
1834   if (text_view->layout)
1835     {
1836       /* some unkosher futzing in internal struct details... */
1837       if (text_view->layout->default_style->tabs)
1838         pango_tab_array_free (text_view->layout->default_style->tabs);
1839
1840       text_view->layout->default_style->tabs =
1841         text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
1842
1843       gtk_text_layout_default_style_changed (text_view->layout);
1844     }
1845 }
1846
1847 PangoTabArray*
1848 gtk_text_view_get_tabs (GtkTextView *text_view)
1849 {
1850   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
1851
1852   return text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
1853 }
1854
1855 /**
1856  * gtk_text_view_set_cursor_visible:
1857  * @text_view: a #GtkTextView
1858  * @setting: whether to show the insertion cursor
1859  *
1860  * Toggles whether the insertion point is displayed. A buffer with no editable
1861  * text probably shouldn't have a visible cursor, so you may want to turn
1862  * the cursor off.
1863  **/
1864 void
1865 gtk_text_view_set_cursor_visible    (GtkTextView   *text_view,
1866                                      gboolean       setting)
1867 {
1868   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1869
1870   setting = (setting != FALSE);
1871
1872   if (text_view->cursor_visible != setting)
1873     {
1874       text_view->cursor_visible = setting;
1875
1876       if (GTK_WIDGET_HAS_FOCUS (text_view))
1877         {
1878           if (text_view->layout)
1879             {
1880               gtk_text_layout_set_cursor_visible (text_view->layout, setting);
1881
1882               if (setting)
1883                 gtk_text_view_start_cursor_blink (text_view, FALSE);
1884               else
1885                 gtk_text_view_stop_cursor_blink (text_view);
1886             }
1887         }
1888     }
1889 }
1890
1891 /**
1892  * gtk_text_view_get_cursor_visible:
1893  * @text_view: a #GtkTextView
1894  *
1895  * Find out whether the cursor is being displayed.
1896  *
1897  * Return value: whether the insertion mark is visible
1898  **/
1899 gboolean
1900 gtk_text_view_get_cursor_visible    (GtkTextView   *text_view)
1901 {
1902   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1903
1904   return text_view->cursor_visible;
1905 }
1906
1907
1908 /**
1909  * gtk_text_view_place_cursor_onscreen:
1910  * @text_view: a #GtkTextView
1911  *
1912  * Moves the cursor to the currently visible region of the
1913  * buffer, it it isn't there already.
1914  *
1915  * Return value: TRUE if the cursor had to be moved.
1916  **/
1917 gboolean
1918 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
1919 {
1920   GtkTextIter insert;
1921
1922   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1923
1924   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
1925                                     gtk_text_buffer_get_mark (get_buffer (text_view),
1926                                                               "insert"));
1927
1928   if (clamp_iter_onscreen (text_view, &insert))
1929     {
1930       gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
1931       return TRUE;
1932     }
1933   else
1934     return FALSE;
1935 }
1936
1937 static void
1938 gtk_text_view_destroy (GtkObject *object)
1939 {
1940   GtkTextView *text_view;
1941   GtkTextLayout *layout;
1942   
1943   text_view = GTK_TEXT_VIEW (object);
1944
1945   layout = text_view->layout;
1946   
1947   gtk_text_view_destroy_layout (text_view);
1948   gtk_text_view_set_buffer (text_view, NULL);
1949
1950   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1951 }
1952
1953 static void
1954 gtk_text_view_finalize (GObject *object)
1955 {
1956   GtkTextView *text_view;
1957
1958   text_view = GTK_TEXT_VIEW (object);
1959
1960   g_return_if_fail (text_view->buffer == NULL);
1961
1962   gtk_text_view_destroy_layout (text_view);
1963   gtk_text_view_set_buffer (text_view, NULL);
1964   
1965   if (text_view->pending_scroll)
1966     {
1967       free_pending_scroll (text_view->pending_scroll);
1968       text_view->pending_scroll = NULL;
1969     }
1970   
1971   if (text_view->hadjustment)
1972     g_object_unref (G_OBJECT (text_view->hadjustment));
1973   if (text_view->vadjustment)
1974     g_object_unref (G_OBJECT (text_view->vadjustment));
1975
1976   text_window_free (text_view->text_window);
1977
1978   if (text_view->left_window)
1979     text_window_free (text_view->left_window);
1980
1981   if (text_view->top_window)
1982     text_window_free (text_view->top_window);
1983
1984   if (text_view->right_window)
1985     text_window_free (text_view->right_window);
1986
1987   if (text_view->bottom_window)
1988     text_window_free (text_view->bottom_window);
1989
1990   g_object_unref (G_OBJECT (text_view->im_context));
1991
1992   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1993 }
1994
1995 static void
1996 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1997 {
1998   GtkTextView *text_view;
1999
2000   text_view = GTK_TEXT_VIEW (object);
2001
2002   switch (arg_id)
2003     {
2004     case ARG_HEIGHT_LINES:
2005       g_warning ("FIXME");
2006       break;
2007
2008     case ARG_WIDTH_COLUMNS:
2009       g_warning ("FIXME");
2010       break;
2011
2012     case ARG_PIXELS_ABOVE_LINES:
2013       gtk_text_view_set_pixels_above_lines (text_view, GTK_VALUE_INT (*arg));
2014       break;
2015
2016     case ARG_PIXELS_BELOW_LINES:
2017       gtk_text_view_set_pixels_below_lines (text_view, GTK_VALUE_INT (*arg));
2018       break;
2019
2020     case ARG_PIXELS_INSIDE_WRAP:
2021       gtk_text_view_set_pixels_inside_wrap (text_view, GTK_VALUE_INT (*arg));
2022       break;
2023
2024     case ARG_EDITABLE:
2025       gtk_text_view_set_editable (text_view, GTK_VALUE_BOOL (*arg));
2026       break;
2027
2028     case ARG_WRAP_MODE:
2029       gtk_text_view_set_wrap_mode (text_view, GTK_VALUE_ENUM (*arg));
2030       break;
2031
2032     case ARG_JUSTIFY:
2033       gtk_text_view_set_justification (text_view, GTK_VALUE_ENUM (*arg));
2034       break;
2035
2036     case ARG_LEFT_MARGIN:
2037       gtk_text_view_set_left_margin (text_view, GTK_VALUE_INT (*arg));
2038       break;
2039
2040     case ARG_RIGHT_MARGIN:
2041       gtk_text_view_set_right_margin (text_view, GTK_VALUE_INT (*arg));
2042       break;
2043
2044     case ARG_INDENT:
2045       gtk_text_view_set_indent (text_view, GTK_VALUE_INT (*arg));
2046       break;
2047
2048     case ARG_TABS:
2049       gtk_text_view_set_tabs (text_view, GTK_VALUE_POINTER (*arg));
2050       break;
2051
2052     default:
2053       g_assert_not_reached ();
2054       break;
2055     }
2056 }
2057
2058 static void
2059 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
2060 {
2061   GtkTextView *text_view;
2062
2063   text_view = GTK_TEXT_VIEW (object);
2064
2065   switch (arg_id)
2066     {
2067     case ARG_HEIGHT_LINES:
2068       g_warning ("FIXME");
2069       break;
2070
2071     case ARG_WIDTH_COLUMNS:
2072       g_warning ("FIXME");
2073       break;
2074
2075     case ARG_PIXELS_ABOVE_LINES:
2076       GTK_VALUE_INT (*arg) = text_view->pixels_above_lines;
2077       break;
2078
2079     case ARG_PIXELS_BELOW_LINES:
2080       GTK_VALUE_INT (*arg) = text_view->pixels_below_lines;
2081       break;
2082
2083     case ARG_PIXELS_INSIDE_WRAP:
2084       GTK_VALUE_INT (*arg) = text_view->pixels_inside_wrap;
2085       break;
2086
2087     case ARG_EDITABLE:
2088       GTK_VALUE_BOOL (*arg) = text_view->editable;
2089       break;
2090
2091     case ARG_WRAP_MODE:
2092       GTK_VALUE_ENUM (*arg) = text_view->wrap_mode;
2093       break;
2094
2095     case ARG_JUSTIFY:
2096       GTK_VALUE_ENUM (*arg) = text_view->justify;
2097       break;
2098
2099     case ARG_LEFT_MARGIN:
2100       GTK_VALUE_INT (*arg) = text_view->left_margin;
2101       break;
2102
2103     case ARG_RIGHT_MARGIN:
2104       GTK_VALUE_INT (*arg) = text_view->right_margin;
2105       break;
2106
2107     case ARG_INDENT:
2108       GTK_VALUE_INT (*arg) = text_view->indent;
2109       break;
2110
2111     case ARG_TABS:
2112       GTK_VALUE_POINTER (*arg) = gtk_text_view_get_tabs (text_view);
2113       break;
2114
2115     default:
2116       arg->type = GTK_TYPE_INVALID;
2117       break;
2118     }
2119 }
2120
2121 static void
2122 gtk_text_view_size_request (GtkWidget      *widget,
2123                             GtkRequisition *requisition)
2124 {
2125   GtkTextView *text_view;
2126   GSList *tmp_list;
2127
2128   text_view = GTK_TEXT_VIEW (widget);
2129
2130   requisition->width = text_view->text_window->requisition.width + FOCUS_EDGE_WIDTH * 2;
2131   requisition->height = text_view->text_window->requisition.height + FOCUS_EDGE_WIDTH * 2;
2132
2133   if (text_view->left_window)
2134     requisition->width += text_view->left_window->requisition.width;
2135
2136   if (text_view->right_window)
2137     requisition->width += text_view->right_window->requisition.width;
2138
2139   if (text_view->top_window)
2140     requisition->height += text_view->top_window->requisition.height;
2141
2142   if (text_view->bottom_window)
2143     requisition->height += text_view->bottom_window->requisition.height;
2144
2145   tmp_list = text_view->children;
2146   while (tmp_list != NULL)
2147     {
2148       GtkTextViewChild *child = tmp_list->data;
2149
2150       if (child->anchor)
2151         {
2152           GtkRequisition child_req;
2153           GtkRequisition old_req;
2154
2155           old_req = child->widget->requisition;
2156
2157           gtk_widget_size_request (child->widget, &child_req);
2158
2159           if (text_view->layout &&
2160               (old_req.width != child_req.width ||
2161                old_req.height != child_req.height))
2162             gtk_text_child_anchor_queue_resize (child->anchor,
2163                                                 text_view->layout);
2164         }
2165       else
2166         {
2167
2168         }
2169
2170       tmp_list = g_slist_next (tmp_list);
2171     }
2172 }
2173
2174 static void
2175 gtk_text_view_update_child_allocation (GtkTextView      *text_view,
2176                                        GtkTextViewChild *vc)
2177 {
2178   gint buffer_y;
2179   GtkTextIter iter;
2180   GtkAllocation allocation;
2181   
2182   gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2183                                             &iter,
2184                                             vc->anchor);
2185
2186   gtk_text_layout_get_line_yrange (text_view->layout, &iter,
2187                                    &buffer_y, NULL);
2188
2189   buffer_y += vc->from_top_of_line;
2190
2191   allocation.x = vc->from_left_of_buffer;
2192   allocation.y = buffer_y;
2193   allocation.width = vc->widget->requisition.width;
2194   allocation.height = vc->widget->requisition.height;
2195   
2196   gtk_widget_size_allocate (vc->widget, &allocation);
2197 }
2198
2199 static void
2200 gtk_text_view_child_allocated (GtkTextLayout *layout,
2201                                GtkWidget     *child,
2202                                gint           x,
2203                                gint           y,
2204                                gpointer       data)
2205 {
2206   GtkTextViewChild *vc = NULL;
2207   GtkTextView *text_view = data;
2208   
2209   /* x,y is the position of the child from the top of the line, and
2210    * from the left of the buffer. We have to translate that into text
2211    * window coordinates, then size_allocate the child.
2212    */
2213
2214   vc = g_object_get_data (G_OBJECT (child),
2215                             "gtk-text-view-child");
2216
2217   g_assert (vc != NULL);
2218
2219   g_print ("child allocated at %d,%d\n", x, y);
2220   
2221   vc->from_left_of_buffer = x;
2222   vc->from_top_of_line = y;
2223
2224   gtk_text_view_update_child_allocation (text_view, vc);
2225 }
2226
2227 static void
2228 gtk_text_view_validate_children (GtkTextView *text_view)
2229 {
2230   GSList *tmp_list;
2231
2232   DV(g_print(G_STRLOC"\n"));
2233   
2234   tmp_list = text_view->children;
2235   while (tmp_list != NULL)
2236     {
2237       GtkTextViewChild *child = tmp_list->data;
2238
2239       if (child->anchor)
2240         {
2241           /* We need to force-validate the regions containing
2242            * children.
2243            */
2244           GtkTextIter child_loc;
2245           gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2246                                                     &child_loc,
2247                                                     child->anchor);
2248
2249           gtk_text_layout_validate_yrange (text_view->layout,
2250                                            &child_loc,
2251                                            0, 1);
2252         }
2253       else
2254         {
2255
2256         }
2257
2258       tmp_list = g_slist_next (tmp_list);
2259     }
2260 }
2261
2262 static void
2263 gtk_text_view_size_allocate (GtkWidget *widget,
2264                              GtkAllocation *allocation)
2265 {
2266   GtkTextView *text_view;
2267   GtkTextIter first_para;
2268   gint y;
2269   GtkAdjustment *vadj;
2270   gboolean yoffset_changed = FALSE;
2271   gint width, height;
2272   GdkRectangle text_rect;
2273   GdkRectangle left_rect;
2274   GdkRectangle right_rect;
2275   GdkRectangle top_rect;
2276   GdkRectangle bottom_rect;
2277
2278   text_view = GTK_TEXT_VIEW (widget);
2279
2280   DV(g_print(G_STRLOC"\n"));
2281   
2282   widget->allocation = *allocation;
2283
2284   if (GTK_WIDGET_REALIZED (widget))
2285     {
2286       gdk_window_move_resize (widget->window,
2287                               allocation->x, allocation->y,
2288                               allocation->width, allocation->height);
2289     }
2290
2291   /* distribute width/height among child windows. Ensure all
2292    * windows get at least a 1x1 allocation.
2293    */
2294
2295   width = allocation->width - FOCUS_EDGE_WIDTH * 2;
2296
2297   if (text_view->left_window)
2298     left_rect.width = text_view->left_window->requisition.width;
2299   else
2300     left_rect.width = 1;
2301
2302   width -= left_rect.width;
2303
2304   if (text_view->right_window)
2305     right_rect.width = text_view->right_window->requisition.width;
2306   else
2307     right_rect.width = 1;
2308
2309   width -= right_rect.width;
2310
2311   text_rect.width = MAX (1, width);
2312
2313   top_rect.width = text_rect.width;
2314   bottom_rect.width = text_rect.width;
2315
2316
2317   height = allocation->height - FOCUS_EDGE_WIDTH * 2;
2318
2319   if (text_view->top_window)
2320     top_rect.height = text_view->top_window->requisition.height;
2321   else
2322     top_rect.height = 1;
2323
2324   height -= top_rect.height;
2325
2326   if (text_view->bottom_window)
2327     bottom_rect.height = text_view->bottom_window->requisition.height;
2328   else
2329     bottom_rect.height = 1;
2330
2331   height -= bottom_rect.height;
2332
2333   text_rect.height = MAX (1, height);
2334
2335   left_rect.height = text_rect.height;
2336   right_rect.height = text_rect.height;
2337
2338   /* Origins */
2339   left_rect.x = FOCUS_EDGE_WIDTH;
2340   top_rect.y = FOCUS_EDGE_WIDTH;
2341
2342   text_rect.x = left_rect.x + left_rect.width;
2343   text_rect.y = top_rect.y + top_rect.height;
2344
2345   left_rect.y = text_rect.y;
2346   right_rect.y = text_rect.y;
2347
2348   top_rect.x = text_rect.x;
2349   bottom_rect.x = text_rect.x;
2350
2351   right_rect.x = text_rect.x + text_rect.width;
2352   bottom_rect.y = text_rect.y + text_rect.height;
2353
2354   text_window_size_allocate (text_view->text_window,
2355                              &text_rect);
2356
2357   if (text_view->left_window)
2358     text_window_size_allocate (text_view->left_window,
2359                                &left_rect);
2360
2361   if (text_view->right_window)
2362     text_window_size_allocate (text_view->right_window,
2363                                &right_rect);
2364
2365   if (text_view->top_window)
2366     text_window_size_allocate (text_view->top_window,
2367                                &top_rect);
2368
2369   if (text_view->bottom_window)
2370     text_window_size_allocate (text_view->bottom_window,
2371                                &bottom_rect);
2372
2373   gtk_text_view_update_layout_width (text_view);
2374   
2375   /* This is because validating children ends up size allocating them. */
2376   gtk_text_view_validate_children (text_view);
2377
2378   /* Now adjust the value of the adjustment to keep the cursor at the
2379    * same place in the buffer
2380    */
2381   gtk_text_view_get_first_para_iter (text_view, &first_para);
2382   gtk_text_layout_get_line_yrange (text_view->layout, &first_para, &y, NULL);
2383
2384   y += text_view->first_para_pixels;
2385
2386   /* Ensure h/v adj exist */
2387   get_hadjustment (text_view);
2388   get_vadjustment (text_view);
2389
2390   vadj = text_view->vadjustment;
2391   if (y > vadj->upper - vadj->page_size)
2392     y = MAX (0, vadj->upper - vadj->page_size);
2393
2394   if (y != text_view->yoffset)
2395     {
2396       vadj->value = text_view->yoffset = y;
2397       yoffset_changed = TRUE;
2398     }
2399
2400   text_view->hadjustment->page_size = SCREEN_WIDTH (text_view);
2401   text_view->hadjustment->page_increment = SCREEN_WIDTH (text_view) / 2;
2402   text_view->hadjustment->lower = 0;
2403   text_view->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
2404                                        text_view->width);
2405   gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
2406
2407   text_view->vadjustment->page_size = SCREEN_HEIGHT (text_view);
2408   text_view->vadjustment->page_increment = SCREEN_HEIGHT (text_view) / 2;
2409   text_view->vadjustment->lower = 0;
2410   text_view->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
2411                                        text_view->height);
2412   gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
2413
2414   if (yoffset_changed)
2415     gtk_adjustment_value_changed (vadj);
2416
2417   if (text_view->first_validate_idle != 0)
2418     {
2419       /* The GTK resize loop processes all the pending exposes right
2420        * after doing the resize stuff, so the idle sizer won't have a
2421        * chance to run. So we do the work here. 
2422        */
2423
2424       g_source_remove (text_view->first_validate_idle);
2425       text_view->first_validate_idle = 0;
2426       
2427       if (!gtk_text_view_flush_scroll (text_view))
2428         gtk_text_view_validate_onscreen (text_view);
2429     }
2430 }
2431
2432 static void
2433 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
2434                                    GtkTextIter *iter)
2435 {
2436   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
2437                                     text_view->first_para_mark);
2438 }
2439
2440 static void
2441 gtk_text_view_validate_onscreen (GtkTextView *text_view)
2442 {
2443   GtkWidget *widget = GTK_WIDGET (text_view);
2444   
2445   DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
2446   
2447   if (SCREEN_HEIGHT (widget) > 0)
2448     {
2449       GtkTextIter first_para;
2450
2451       /* Be sure we've validated the stuff onscreen; if we
2452        * scrolled, these calls won't have any effect, because
2453        * they were called in the recursive validate_onscreen
2454        */
2455       gtk_text_view_get_first_para_iter (text_view, &first_para);
2456
2457       gtk_text_layout_validate_yrange (text_view->layout,
2458                                        &first_para,
2459                                        0,
2460                                        text_view->first_para_pixels +
2461                                        SCREEN_HEIGHT (widget));
2462     }
2463
2464   text_view->onscreen_validated = TRUE;
2465
2466   DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
2467   
2468   /* This can have the odd side effect of triggering a scroll, which should
2469    * flip "onscreen_validated" back to FALSE, but should also get us
2470    * back into this function to turn it on again.
2471    */
2472   gtk_text_view_update_adjustments (text_view);
2473
2474   g_assert (text_view->onscreen_validated);
2475 }
2476
2477 static gboolean
2478 first_validate_callback (gpointer data)
2479 {
2480   GtkTextView *text_view = data;
2481
2482   /* Note that some of this code is duplicated at the end of size_allocate,
2483    * keep in sync with that.
2484    */
2485   
2486   DV(g_print(G_STRLOC"\n"));
2487
2488   /* Do this first, which means that if an "invalidate"
2489    * occurs during any of this process, a new first_validate_callback
2490    * will be installed, and we'll start again.
2491    */
2492   text_view->first_validate_idle = 0;
2493   
2494   /* be sure we have up-to-date screen size set on the
2495    * layout.
2496    */
2497   gtk_text_view_update_layout_width (text_view);
2498
2499   /* Bail out if we invalidated stuff; scrolling right away will just
2500    * confuse the issue.
2501    */
2502   if (text_view->first_validate_idle != 0)
2503     {
2504       DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
2505       return FALSE;
2506     }
2507   
2508   /* scroll to any marks, if that's pending. This can
2509    * jump us to the validation codepath used for scrolling
2510    * onscreen, if so we bail out.
2511    */
2512   if (!gtk_text_view_flush_scroll (text_view))
2513     gtk_text_view_validate_onscreen (text_view);
2514
2515   DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
2516
2517   g_assert (text_view->onscreen_validated);
2518   
2519   return FALSE;
2520 }
2521
2522 static gboolean
2523 incremental_validate_callback (gpointer data)
2524 {
2525   GtkTextView *text_view = data;
2526
2527   DV(g_print(G_STRLOC"\n"));
2528   
2529   gtk_text_layout_validate (text_view->layout, 2000);
2530
2531   gtk_text_view_update_adjustments (text_view);
2532   
2533   if (gtk_text_layout_is_valid (text_view->layout))
2534     {
2535       text_view->incremental_validate_idle = 0;
2536       return FALSE;
2537     }
2538   else
2539     return TRUE;
2540 }
2541
2542 static void
2543 invalidated_handler (GtkTextLayout *layout,
2544                      gpointer       data)
2545 {
2546   GtkTextView *text_view;
2547
2548   text_view = GTK_TEXT_VIEW (data);
2549
2550   text_view->onscreen_validated = FALSE;
2551   
2552   DV(g_print(">Invalidate, onscreen_validated = FALSE ("G_STRLOC")\n"));
2553   
2554   if (!text_view->first_validate_idle)
2555     text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
2556
2557   if (!text_view->incremental_validate_idle)
2558     text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
2559 }
2560
2561 static void
2562 changed_handler (GtkTextLayout *layout,
2563                  gint           start_y,
2564                  gint           old_height,
2565                  gint           new_height,
2566                  gpointer       data)
2567 {
2568   GtkTextView *text_view;
2569   GtkWidget *widget;
2570   GdkRectangle visible_rect;
2571   GdkRectangle redraw_rect;
2572
2573   text_view = GTK_TEXT_VIEW (data);
2574   widget = GTK_WIDGET (data);
2575   
2576   DV(g_print(">Lines Validated ("G_STRLOC")\n"));
2577
2578   if (GTK_WIDGET_REALIZED (text_view))
2579     {      
2580       gtk_text_view_get_visible_rect (text_view, &visible_rect);
2581
2582       redraw_rect.x = visible_rect.x;
2583       redraw_rect.width = visible_rect.width;
2584       redraw_rect.y = start_y;
2585
2586       if (old_height == new_height)
2587         redraw_rect.height = old_height;
2588       else
2589         redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
2590
2591       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
2592         {
2593           /* text_window_invalidate_rect() takes buffer coordinates */
2594           text_window_invalidate_rect (text_view->text_window,
2595                                        &redraw_rect);
2596
2597           DV(g_print(" invalidated rect: %d,%d %d x %d\n",
2598                      redraw_rect.x,
2599                      redraw_rect.y,
2600                      redraw_rect.width,
2601                      redraw_rect.height));
2602           
2603           if (text_view->left_window)
2604             text_window_invalidate_rect (text_view->left_window,
2605                                          &redraw_rect);
2606           if (text_view->right_window)
2607             text_window_invalidate_rect (text_view->right_window,
2608                                          &redraw_rect);
2609           if (text_view->top_window)
2610             text_window_invalidate_rect (text_view->top_window,
2611                                          &redraw_rect);
2612           if (text_view->bottom_window)
2613             text_window_invalidate_rect (text_view->bottom_window,
2614                                          &redraw_rect);
2615         }
2616     }
2617   
2618   if (old_height != new_height)
2619     {
2620       gboolean yoffset_changed = FALSE;
2621       GSList *tmp_list;
2622       
2623       if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
2624         {
2625           text_view->yoffset += new_height - old_height;
2626           get_vadjustment (text_view)->value = text_view->yoffset;
2627           yoffset_changed = TRUE;
2628         }
2629
2630       if (yoffset_changed)
2631         gtk_adjustment_value_changed (get_vadjustment (text_view));
2632
2633       /* FIXME be smarter about which anchored widgets we update */
2634
2635       tmp_list = text_view->children;
2636       while (tmp_list != NULL)
2637         {
2638           GtkTextViewChild *child = tmp_list->data;
2639
2640           if (child->anchor)
2641             gtk_text_view_update_child_allocation (text_view, child);
2642
2643           tmp_list = g_slist_next (tmp_list);
2644         }
2645     }
2646 }
2647
2648 static void
2649 gtk_text_view_realize (GtkWidget *widget)
2650 {
2651   GtkTextView *text_view;
2652   GdkWindowAttr attributes;
2653   gint attributes_mask;
2654   GSList *tmp_list;
2655   
2656   text_view = GTK_TEXT_VIEW (widget);
2657   GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
2658
2659   attributes.window_type = GDK_WINDOW_CHILD;
2660   attributes.x = widget->allocation.x;
2661   attributes.y = widget->allocation.y;
2662   attributes.width = widget->allocation.width;
2663   attributes.height = widget->allocation.height;
2664   attributes.wclass = GDK_INPUT_OUTPUT;
2665   attributes.visual = gtk_widget_get_visual (widget);
2666   attributes.colormap = gtk_widget_get_colormap (widget);
2667   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
2668
2669   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2670
2671   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
2672                                    &attributes, attributes_mask);
2673   gdk_window_set_user_data (widget->window, widget);
2674
2675   /* must come before text_window_realize calls */
2676   widget->style = gtk_style_attach (widget->style, widget->window);
2677
2678   gdk_window_set_background (widget->window,
2679                              &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2680
2681   text_window_realize (text_view->text_window, widget->window);
2682
2683   if (text_view->left_window)
2684     text_window_realize (text_view->left_window,
2685                          widget->window);
2686
2687   if (text_view->top_window)
2688     text_window_realize (text_view->top_window,
2689                          widget->window);
2690
2691   if (text_view->right_window)
2692     text_window_realize (text_view->right_window,
2693                          widget->window);
2694
2695   if (text_view->bottom_window)
2696     text_window_realize (text_view->bottom_window,
2697                          widget->window);
2698
2699   gtk_text_view_ensure_layout (text_view);
2700 }
2701
2702 static void
2703 gtk_text_view_unrealize (GtkWidget *widget)
2704 {
2705   GtkTextView *text_view;
2706   GSList *tmp_list;
2707   
2708   text_view = GTK_TEXT_VIEW (widget);
2709
2710   if (text_view->first_validate_idle)
2711     {
2712       g_source_remove (text_view->first_validate_idle);
2713       text_view->first_validate_idle = 0;
2714     }
2715
2716   if (text_view->incremental_validate_idle)
2717     {
2718       g_source_remove (text_view->incremental_validate_idle);
2719       text_view->incremental_validate_idle = 0;
2720     }
2721
2722   if (text_view->popup_menu)
2723     {
2724       gtk_widget_destroy (text_view->popup_menu);
2725       text_view->popup_menu = NULL;
2726     }
2727
2728   text_window_unrealize (text_view->text_window);
2729
2730   if (text_view->left_window)
2731     text_window_unrealize (text_view->left_window);
2732
2733   if (text_view->top_window)
2734     text_window_unrealize (text_view->top_window);
2735
2736   if (text_view->right_window)
2737     text_window_unrealize (text_view->right_window);
2738
2739   if (text_view->bottom_window)
2740     text_window_unrealize (text_view->bottom_window);
2741
2742   gtk_text_view_destroy_layout (text_view);
2743   
2744   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2745 }
2746
2747 static void
2748 gtk_text_view_style_set (GtkWidget *widget,
2749                          GtkStyle  *previous_style)
2750 {
2751   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2752
2753   if (GTK_WIDGET_REALIZED (widget))
2754     {
2755       gdk_window_set_background (widget->window,
2756                                  &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2757
2758       gdk_window_set_background (text_view->text_window->bin_window,
2759                                  &widget->style->base[GTK_WIDGET_STATE (widget)]);
2760
2761       if (text_view->left_window)
2762         gdk_window_set_background (text_view->left_window->bin_window,
2763                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2764       if (text_view->right_window)
2765         gdk_window_set_background (text_view->right_window->bin_window,
2766                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2767
2768       if (text_view->top_window)
2769         gdk_window_set_background (text_view->top_window->bin_window,
2770                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2771
2772       if (text_view->bottom_window)
2773         gdk_window_set_background (text_view->bottom_window->bin_window,
2774                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2775
2776       gtk_text_view_set_attributes_from_style (text_view,
2777                                                text_view->layout->default_style,
2778                                                widget->style);
2779       gtk_text_layout_default_style_changed (text_view->layout);
2780     }
2781 }
2782
2783 static void
2784 gtk_text_view_direction_changed (GtkWidget        *widget,
2785                                  GtkTextDirection  previous_direction)
2786 {
2787   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2788
2789   if (text_view->layout)
2790     {
2791       text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
2792       gtk_text_layout_default_style_changed (text_view->layout);
2793     }
2794 }
2795
2796 /*
2797  * Events
2798  */
2799
2800 static gboolean
2801 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
2802 {
2803   if (event)
2804     switch (event->type)
2805       {
2806       case GDK_MOTION_NOTIFY:
2807         *x = event->motion.x;
2808         *y = event->motion.y;
2809         return TRUE;
2810         break;
2811
2812       case GDK_BUTTON_PRESS:
2813       case GDK_2BUTTON_PRESS:
2814       case GDK_3BUTTON_PRESS:
2815       case GDK_BUTTON_RELEASE:
2816         *x = event->button.x;
2817         *y = event->button.y;
2818         return TRUE;
2819         break;
2820
2821       case GDK_KEY_PRESS:
2822       case GDK_KEY_RELEASE:
2823       case GDK_ENTER_NOTIFY:
2824       case GDK_LEAVE_NOTIFY:
2825       case GDK_PROPERTY_NOTIFY:
2826       case GDK_SELECTION_CLEAR:
2827       case GDK_SELECTION_REQUEST:
2828       case GDK_SELECTION_NOTIFY:
2829       case GDK_PROXIMITY_IN:
2830       case GDK_PROXIMITY_OUT:
2831       case GDK_DRAG_ENTER:
2832       case GDK_DRAG_LEAVE:
2833       case GDK_DRAG_MOTION:
2834       case GDK_DRAG_STATUS:
2835       case GDK_DROP_START:
2836       case GDK_DROP_FINISHED:
2837       default:
2838         return FALSE;
2839         break;
2840       }
2841
2842   return FALSE;
2843 }
2844
2845 static gint
2846 emit_event_on_tags (GtkWidget   *widget,
2847                     GdkEvent    *event,
2848                     GtkTextIter *iter)
2849 {
2850   GSList *tags;
2851   GSList *tmp;
2852   gint retval = FALSE;
2853   GtkTextView *text_view;
2854
2855   text_view = GTK_TEXT_VIEW (widget);
2856
2857   tags = gtk_text_iter_get_tags (iter);
2858
2859   tmp = tags;
2860   while (tmp != NULL)
2861     {
2862       GtkTextTag *tag = tmp->data;
2863
2864       if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
2865         {
2866           retval = TRUE;
2867           break;
2868         }
2869
2870       tmp = g_slist_next (tmp);
2871     }
2872
2873   g_slist_free (tags);
2874
2875   return retval;
2876 }
2877
2878 static gint
2879 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
2880 {
2881   GtkTextView *text_view;
2882   gint x = 0, y = 0;
2883
2884   text_view = GTK_TEXT_VIEW (widget);
2885
2886   if (text_view->layout == NULL ||
2887       get_buffer (text_view) == NULL)
2888     return FALSE;
2889
2890   if (event->any.window != text_view->text_window->bin_window)
2891     return FALSE;
2892
2893   if (get_event_coordinates (event, &x, &y))
2894     {
2895       GtkTextIter iter;
2896
2897       x += text_view->xoffset;
2898       y += text_view->yoffset;
2899
2900       /* FIXME this is slow and we do it twice per event.
2901        * My favorite solution is to have GtkTextLayout cache
2902        * the last couple lookups.
2903        */
2904       gtk_text_layout_get_iter_at_pixel (text_view->layout,
2905                                          &iter,
2906                                          x, y);
2907
2908       return emit_event_on_tags (widget, event, &iter);
2909     }
2910   else if (event->type == GDK_KEY_PRESS ||
2911            event->type == GDK_KEY_RELEASE)
2912     {
2913       GtkTextMark *insert;
2914       GtkTextIter iter;
2915
2916       insert = gtk_text_buffer_get_mark (get_buffer (text_view),
2917                                          "insert");
2918
2919       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
2920
2921       return emit_event_on_tags (widget, event, &iter);
2922     }
2923   else
2924     return FALSE;
2925 }
2926
2927 static gint
2928 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
2929 {
2930   gint retval = FALSE;
2931   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2932
2933   if (text_view->layout == NULL ||
2934       get_buffer (text_view) == NULL)
2935     return FALSE;
2936
2937   if (gtk_im_context_filter_keypress (text_view->im_context, event))
2938     {
2939       text_view->need_im_reset = TRUE;
2940       retval = TRUE;
2941     }
2942   else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
2943            GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
2944     retval = TRUE;
2945   else if (event->keyval == GDK_Return)
2946     {
2947       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
2948                                                     text_view->editable);
2949       gtk_text_view_scroll_to_mark (text_view,
2950                                     gtk_text_buffer_get_mark (get_buffer (text_view),
2951                                                               "insert"),
2952                                     0.0, FALSE, 0.0, 0.0);
2953       retval = TRUE;
2954     }
2955   /* Pass through Tab as literal tab, unless Control is held down */
2956   else if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK))
2957     {
2958       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\t", 1,
2959                                                     text_view->editable);
2960       gtk_text_view_scroll_mark_onscreen (text_view,
2961                                           gtk_text_buffer_get_mark (get_buffer (text_view),
2962                                                                     "insert"));
2963       retval = TRUE;
2964     }
2965   else
2966     retval = FALSE;
2967
2968   gtk_text_view_start_cursor_blink (text_view, TRUE);
2969
2970   return retval;
2971 }
2972
2973 static gint
2974 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
2975 {
2976   return FALSE;
2977 }
2978
2979 static gint
2980 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
2981 {
2982   GtkTextView *text_view;
2983
2984   text_view = GTK_TEXT_VIEW (widget);
2985
2986   gtk_widget_grab_focus (widget);
2987
2988   if (event->window != text_view->text_window->bin_window)
2989     {
2990       /* Remove selection if any. */
2991       gtk_text_view_unselect (text_view);
2992       return FALSE;
2993     }
2994
2995 #if 0
2996   /* debug hack */
2997   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
2998     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
2999   else if (event->button == 3)
3000     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
3001 #endif
3002
3003   if (event->type == GDK_BUTTON_PRESS)
3004     {
3005       gtk_text_view_reset_im_context (text_view);
3006
3007       if (event->button == 1)
3008         {
3009           /* If we're in the selection, start a drag copy/move of the
3010            * selection; otherwise, start creating a new selection.
3011            */
3012           GtkTextIter iter;
3013           GtkTextIter start, end;
3014
3015           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3016                                              &iter,
3017                                              event->x + text_view->xoffset,
3018                                              event->y + text_view->yoffset);
3019
3020           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
3021                                                     &start, &end) &&
3022               gtk_text_iter_in_range (&iter, &start, &end))
3023             {
3024               text_view->drag_start_x = event->x;
3025               text_view->drag_start_y = event->y;
3026             }
3027           else
3028             {
3029               gtk_text_view_start_selection_drag (text_view, &iter, event);
3030             }
3031
3032           return TRUE;
3033         }
3034       else if (event->button == 2)
3035         {
3036           GtkTextIter iter;
3037
3038           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3039                                              &iter,
3040                                              event->x + text_view->xoffset,
3041                                              event->y + text_view->yoffset);
3042
3043           gtk_text_buffer_paste_primary (get_buffer (text_view),
3044                                          &iter,
3045                                          text_view->editable);
3046           return TRUE;
3047         }
3048       else if (event->button == 3)
3049         {
3050           gtk_text_view_popup_menu (text_view, event);
3051         }
3052     }
3053   else if ((event->type == GDK_2BUTTON_PRESS ||
3054             event->type == GDK_3BUTTON_PRESS) &&
3055            event->button == 1)
3056     {
3057       GtkTextIter start, end;
3058
3059       /* End the selection drag, otherwise we'd clear the new
3060        * word/line selection on button release
3061        */
3062       gtk_text_view_end_selection_drag (text_view, event);
3063
3064       gtk_text_layout_get_iter_at_pixel (text_view->layout,
3065                                          &start,
3066                                          event->x + text_view->xoffset,
3067                                          event->y + text_view->yoffset); 
3068
3069       end = start;
3070       
3071       if (event->type == GDK_2BUTTON_PRESS)
3072         {
3073           if (gtk_text_iter_inside_word (&start))
3074             {
3075               if (!gtk_text_iter_starts_word (&start))
3076                 gtk_text_iter_backward_word_start (&start);
3077               
3078               if (!gtk_text_iter_ends_word (&end))
3079                 gtk_text_iter_forward_word_end (&end);
3080             }
3081         }
3082       else if (event->type == GDK_3BUTTON_PRESS)
3083         {
3084           if (gtk_text_view_starts_display_line (text_view, &start))
3085             {
3086               /* If on a display line boundary, we assume the user
3087                * clicked off the end of a line and we therefore select
3088                * the line before the boundary.
3089                */
3090               gtk_text_view_backward_display_line_start (text_view, &start);
3091             }
3092           else
3093             {
3094               /* start isn't on the start of a line, so we move it to the
3095                * start, and move end to the end unless it's already there.
3096                */
3097               gtk_text_view_backward_display_line_start (text_view, &start);
3098
3099               if (!gtk_text_view_starts_display_line (text_view, &end))
3100                 gtk_text_view_forward_display_line_end (text_view, &end);
3101             }
3102         }
3103
3104       gtk_text_buffer_move_mark (get_buffer (text_view),
3105                                  gtk_text_buffer_get_selection_bound (get_buffer (text_view)),
3106                                  &start);
3107       gtk_text_buffer_move_mark (get_buffer (text_view),
3108                                  gtk_text_buffer_get_insert (get_buffer (text_view)),
3109                                  &end);
3110
3111       text_view->just_selected_element = TRUE;
3112       
3113       return TRUE;
3114     }
3115   
3116   return FALSE;
3117 }
3118
3119 static gint
3120 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
3121 {
3122   GtkTextView *text_view;
3123
3124   text_view = GTK_TEXT_VIEW (widget);
3125
3126   if (event->window != text_view->text_window->bin_window)
3127     return FALSE;
3128
3129   if (event->button == 1)
3130     {
3131       if (text_view->drag_start_x >= 0)
3132         {
3133           text_view->drag_start_x = -1;
3134           text_view->drag_start_y = -1;
3135         }
3136
3137       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
3138         return TRUE;
3139       else if (text_view->just_selected_element)
3140         {
3141           text_view->just_selected_element = FALSE;
3142           return FALSE;
3143         }
3144       else
3145         {
3146           /* Unselect everything; probably we were dragging, or clicked
3147            * outside the text.
3148            */
3149           gtk_text_view_unselect (text_view);
3150           return FALSE;
3151         }
3152     }
3153
3154   return FALSE;
3155 }
3156
3157 static gint
3158 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
3159 {
3160   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3161
3162   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3163   gtk_widget_draw_focus (widget);
3164
3165   if (text_view->cursor_visible && text_view->layout)
3166     {
3167       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3168       gtk_text_view_start_cursor_blink (text_view, FALSE);
3169     }
3170
3171   text_view->need_im_reset = TRUE;
3172   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
3173
3174   return FALSE;
3175 }
3176
3177 static gint
3178 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
3179 {
3180   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3181
3182   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3183   gtk_widget_draw_focus (widget);
3184
3185   if (text_view->cursor_visible && text_view->layout)
3186     {
3187       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
3188       gtk_text_view_stop_cursor_blink (text_view);
3189     }
3190
3191   text_view->need_im_reset = TRUE;
3192   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
3193
3194   return FALSE;
3195 }
3196
3197 static gint
3198 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
3199 {
3200   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3201
3202   if (event->window == text_view->text_window->bin_window &&
3203       text_view->drag_start_x >= 0)
3204     {
3205       gint x, y;
3206
3207       gdk_window_get_pointer (text_view->text_window->bin_window,
3208                               &x, &y, NULL);
3209
3210       if (gtk_drag_check_threshold (widget,
3211                                     text_view->drag_start_x, 
3212                                     text_view->drag_start_y,
3213                                     x, y))
3214         {
3215           GtkTextIter iter;
3216           gint buffer_x, buffer_y;
3217
3218           gtk_text_view_window_to_buffer_coords (text_view,
3219                                                  GTK_TEXT_WINDOW_TEXT,
3220                                                  text_view->drag_start_x,
3221                                                  text_view->drag_start_y,
3222                                                  &buffer_x,
3223                                                  &buffer_y);
3224
3225           gtk_text_layout_get_iter_at_pixel (text_view->layout,
3226                                              &iter,
3227                                              buffer_x, buffer_y);
3228
3229           gtk_text_view_start_selection_dnd (text_view, &iter, event);
3230           return TRUE;
3231         }
3232     }
3233
3234   return FALSE;
3235 }
3236
3237 static void
3238 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
3239 {
3240   GtkTextView *text_view;
3241
3242   text_view = GTK_TEXT_VIEW (widget);
3243
3244   g_return_if_fail (text_view->layout != NULL);
3245   g_return_if_fail (text_view->xoffset >= 0);
3246   g_return_if_fail (text_view->yoffset >= 0);
3247   
3248   if (!text_view->onscreen_validated)
3249     {
3250       G_BREAKPOINT ();
3251       g_warning (G_STRLOC ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen");
3252     }
3253   
3254 #if 0
3255   printf ("painting %d,%d  %d x %d\n",
3256           area->x, area->y,
3257           area->width, area->height);
3258 #endif
3259   
3260   gtk_text_layout_draw (text_view->layout,
3261                         widget,
3262                         text_view->text_window->bin_window,
3263                         text_view->xoffset,
3264                         text_view->yoffset,
3265                         area->x, area->y,
3266                         area->width, area->height);
3267 }
3268
3269 static gint
3270 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
3271 {
3272 #if 0
3273   {
3274     GdkWindow *win = event->window;
3275     GdkColor color = { 0, 0, 0, 65535 };
3276     GdkGC *gc = gdk_gc_new (win);
3277     gdk_gc_set_rgb_fg_color (gc, &color);
3278     gdk_draw_rectangle (win,
3279                         gc, TRUE,
3280                         event->area.x, event->area.y,
3281                         event->area.width, event->area.height);
3282     gdk_gc_unref (gc);
3283   }
3284 #endif
3285   
3286   if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
3287                                                  GTK_TEXT_WINDOW_TEXT))
3288     {
3289       DV(g_print (">Exposed ("G_STRLOC")\n"));
3290       gtk_text_view_paint (widget, &event->area);
3291     }
3292
3293   if (event->window == widget->window)
3294     gtk_widget_draw_focus (widget);
3295
3296   return TRUE;
3297 }
3298
3299 static void
3300 gtk_text_view_draw_focus (GtkWidget *widget)
3301 {
3302   if (GTK_WIDGET_DRAWABLE (widget))
3303     {
3304       if (GTK_WIDGET_HAS_FOCUS (widget))
3305         {
3306           gtk_paint_focus (widget->style, widget->window,
3307                            NULL, widget, "textview",
3308                            0, 0,
3309                            widget->allocation.width - 1,
3310                            widget->allocation.height - 1);
3311         }
3312       else
3313         {
3314           gdk_window_clear (widget->window);
3315         }
3316     }
3317 }
3318
3319 /*
3320  * Container
3321  */
3322
3323 static void
3324 gtk_text_view_add (GtkContainer *container,
3325                    GtkWidget    *child)
3326 {
3327   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3328   g_return_if_fail (GTK_IS_WIDGET (child));
3329
3330   /* This is pretty random. */
3331   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
3332                                      child,
3333                                      GTK_TEXT_WINDOW_WIDGET,
3334                                      0, 0);
3335 }
3336
3337 static void
3338 gtk_text_view_remove (GtkContainer *container,
3339                       GtkWidget    *child)
3340 {
3341   GSList *iter;
3342   GtkTextView *text_view;
3343   GtkTextViewChild *vc;
3344
3345   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3346   g_return_if_fail (GTK_IS_WIDGET (child));
3347   g_return_if_fail (child->parent == (GtkWidget*) container);
3348
3349   text_view = GTK_TEXT_VIEW (container);
3350
3351   vc = NULL;
3352   iter = text_view->children;
3353
3354   while (iter != NULL)
3355     {
3356       vc = iter->data;
3357
3358       if (vc->widget == child)
3359         break;
3360
3361       iter = g_slist_next (iter);
3362     }
3363
3364   g_assert (iter != NULL); /* be sure we had the child in the list */
3365
3366   text_view->children = g_slist_remove (text_view->children, vc);
3367
3368   gtk_widget_unparent (vc->widget);
3369
3370   text_view_child_free (vc);
3371 }
3372
3373 static void
3374 gtk_text_view_forall (GtkContainer *container,
3375                       gboolean      include_internals,
3376                       GtkCallback   callback,
3377                       gpointer      callback_data)
3378 {
3379   GSList *iter;
3380   GtkTextView *text_view;
3381
3382   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3383   g_return_if_fail (callback != NULL);
3384
3385   text_view = GTK_TEXT_VIEW (container);
3386
3387   iter = text_view->children;
3388
3389   while (iter != NULL)
3390     {
3391       GtkTextViewChild *vc = iter->data;
3392
3393       (* callback) (vc->widget, callback_data);
3394
3395       iter = g_slist_next (iter);
3396     }
3397 }
3398
3399 /* Note that CURSOR_ON_TIME is effectively added to PREBLINK_TIME
3400  * because blinking starts with the cursor turned on.
3401  */
3402 #define PREBLINK_TIME 300
3403 #define CURSOR_ON_TIME 800
3404 #define CURSOR_OFF_TIME 400
3405
3406 /*
3407  * preblink!
3408  */
3409
3410 static gint
3411 preblink_cb (gpointer data)
3412 {
3413   GtkTextView *text_view = GTK_TEXT_VIEW (data);
3414
3415   text_view->preblink_timeout = 0;
3416   gtk_text_view_start_cursor_blink (text_view, FALSE);
3417
3418   /* Remove ourselves */
3419   return FALSE;
3420 }
3421
3422 /*
3423  * Blink!
3424  */
3425
3426 static gint
3427 blink_cb (gpointer data)
3428 {
3429   GtkTextView *text_view = GTK_TEXT_VIEW (data);
3430   gboolean visible;
3431   
3432   g_assert (text_view->layout);
3433   g_assert (GTK_WIDGET_HAS_FOCUS (text_view));
3434   g_assert (text_view->cursor_visible);
3435
3436   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
3437
3438   if (visible)
3439     text_view->blink_timeout = gtk_timeout_add (CURSOR_OFF_TIME,
3440                                                 blink_cb,
3441                                                 text_view);
3442   else
3443     text_view->blink_timeout = gtk_timeout_add (CURSOR_ON_TIME,
3444                                                 blink_cb,
3445                                                 text_view);
3446   
3447   gtk_text_layout_set_cursor_visible (text_view->layout,
3448                                       !visible);
3449
3450   /* Remove ourselves */
3451   return FALSE;
3452 }
3453
3454 static void
3455 gtk_text_view_start_cursor_blink(GtkTextView *text_view,
3456                                  gboolean     with_delay)
3457 {
3458 #ifdef DEBUG_VALIDATION_AND_SCROLLING
3459   return;
3460 #endif
3461
3462   if (text_view->layout == NULL)
3463     return;
3464   
3465   if (!text_view->cursor_visible)
3466     return;
3467
3468   if (!GTK_WIDGET_HAS_FOCUS (text_view))
3469     return;
3470   
3471   if (text_view->preblink_timeout != 0)
3472     {
3473       gtk_timeout_remove (text_view->preblink_timeout);
3474       text_view->preblink_timeout = 0;
3475     }
3476   
3477   if (with_delay)
3478     {
3479       if (text_view->blink_timeout != 0)
3480         {
3481           gtk_timeout_remove (text_view->blink_timeout);
3482           text_view->blink_timeout = 0;
3483         }
3484       
3485       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3486       
3487       text_view->preblink_timeout = gtk_timeout_add (PREBLINK_TIME,
3488                                                      preblink_cb,
3489                                                      text_view);
3490     }
3491   else
3492     {
3493       if (text_view->blink_timeout == 0)
3494         {
3495           gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3496           
3497           text_view->blink_timeout = gtk_timeout_add (CURSOR_ON_TIME,
3498                                                       blink_cb,
3499                                                       text_view);
3500         }
3501     }
3502 }
3503
3504 static void
3505 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
3506 {
3507   if (text_view->preblink_timeout)
3508     {
3509       gtk_timeout_remove (text_view->preblink_timeout);
3510       text_view->preblink_timeout = 0;
3511     }
3512
3513   if (text_view->blink_timeout)  
3514     { 
3515       gtk_timeout_remove (text_view->blink_timeout);
3516       text_view->blink_timeout = 0;
3517     }
3518 }
3519
3520 /*
3521  * Key binding handlers
3522  */
3523
3524 static void
3525 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
3526                                   GtkTextIter *newplace,
3527                                   gint         count)
3528 {
3529   while (count < 0)
3530     {
3531       gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
3532       count++;
3533     }
3534
3535   while (count > 0)
3536     {
3537       gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
3538       count--;
3539     }
3540 }
3541
3542 static void
3543 gtk_text_view_move_cursor (GtkTextView     *text_view,
3544                            GtkMovementStep  step,
3545                            gint             count,
3546                            gboolean         extend_selection)
3547 {
3548   GtkTextIter insert;
3549   GtkTextIter newplace;
3550
3551   gint cursor_x_pos = 0;
3552
3553   gtk_text_view_reset_im_context (text_view);
3554
3555   if (step == GTK_MOVEMENT_PAGES)
3556     {
3557       gtk_text_view_scroll_pages (text_view, count);
3558       gtk_text_view_start_cursor_blink (text_view, TRUE);
3559       return;
3560     }
3561
3562   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3563                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3564                                                               "insert"));
3565   newplace = insert;
3566
3567   if (step == GTK_MOVEMENT_DISPLAY_LINES)
3568     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
3569
3570   switch (step)
3571     {
3572     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3573       gtk_text_iter_forward_cursor_positions (&newplace, count);
3574       break;
3575
3576     case GTK_MOVEMENT_VISUAL_POSITIONS:
3577       gtk_text_layout_move_iter_visually (text_view->layout,
3578                                           &newplace, count);
3579       break;
3580
3581     case GTK_MOVEMENT_WORDS:
3582       if (count < 0)
3583         gtk_text_iter_backward_word_starts (&newplace, -count);
3584       else if (count > 0)
3585         gtk_text_iter_forward_word_ends (&newplace, count);
3586       break;
3587
3588     case GTK_MOVEMENT_DISPLAY_LINES:
3589       gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
3590       gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
3591       break;
3592
3593     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3594       if (count > 1)
3595         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
3596       else if (count < -1)
3597         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
3598
3599       if (count != 0)
3600         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
3601       break;
3602
3603     case GTK_MOVEMENT_PARAGRAPHS:
3604       /* This should almost certainly instead be doing the parallel thing to WORD */
3605       /*       gtk_text_iter_down_lines (&newplace, count); */
3606       /* FIXME */
3607       break;
3608
3609     case GTK_MOVEMENT_PARAGRAPH_ENDS:
3610       if (count > 0)
3611         gtk_text_iter_forward_to_line_end (&newplace);
3612       else if (count < 0)
3613         gtk_text_iter_set_line_offset (&newplace, 0);
3614       break;
3615
3616     case GTK_MOVEMENT_BUFFER_ENDS:
3617       if (count > 0)
3618         gtk_text_buffer_get_last_iter (get_buffer (text_view), &newplace);
3619       else if (count < 0)
3620         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
3621       break;
3622
3623     default:
3624       break;
3625     }
3626
3627   if (!gtk_text_iter_equal (&insert, &newplace))
3628     {
3629       if (extend_selection)
3630         gtk_text_buffer_move_mark (get_buffer (text_view),
3631                                    gtk_text_buffer_get_mark (get_buffer (text_view),
3632                                                              "insert"),
3633                                    &newplace);
3634       else
3635         gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
3636
3637       gtk_text_view_scroll_mark_onscreen (text_view,
3638                                           gtk_text_buffer_get_mark (get_buffer (text_view),
3639                                                                     "insert"));
3640
3641       if (step == GTK_MOVEMENT_DISPLAY_LINES)
3642         {
3643           gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
3644         }
3645     }
3646
3647   gtk_text_view_start_cursor_blink (text_view, TRUE);
3648 }
3649
3650 static void
3651 gtk_text_view_set_anchor (GtkTextView *text_view)
3652 {
3653   GtkTextIter insert;
3654
3655   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3656                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3657                                                               "insert"));
3658
3659   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
3660 }
3661
3662 static void
3663 gtk_text_view_scroll_pages (GtkTextView *text_view,
3664                             gint         count)
3665 {
3666   gfloat newval;
3667   GtkAdjustment *adj;
3668   gint cursor_x_pos, cursor_y_pos;
3669   GtkTextIter new_insert;
3670   GtkTextIter anchor;
3671   gint y0, y1;
3672
3673   g_return_if_fail (text_view->vadjustment != NULL);
3674
3675   adj = text_view->vadjustment;
3676
3677   /* Validate the region that will be brought into view by the cursor motion
3678    */
3679   if (count < 0)
3680     {
3681       gtk_text_view_get_first_para_iter (text_view, &anchor);
3682       y0 = adj->page_size;
3683       y1 = adj->page_size + count * adj->page_increment;
3684     }
3685   else
3686     {
3687       gtk_text_view_get_first_para_iter (text_view, &anchor);
3688       y0 = count * adj->page_increment + adj->page_size;
3689       y1 = 0;
3690     }
3691
3692   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
3693
3694   gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
3695
3696   newval = adj->value;
3697
3698   newval += count * adj->page_increment;
3699
3700   cursor_y_pos += newval - adj->value;
3701   set_adjustment_clamped (adj, newval);
3702
3703   gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
3704   clamp_iter_onscreen (text_view, &new_insert);
3705   gtk_text_buffer_place_cursor (get_buffer (text_view), &new_insert);
3706
3707   gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
3708
3709   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
3710    * only guarantees 1 pixel onscreen.
3711    */
3712   gtk_text_view_scroll_mark_onscreen (text_view,
3713                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3714                                                                 "insert"));
3715 }
3716
3717 static gboolean
3718 whitespace (gunichar ch, gpointer user_data)
3719 {
3720   return (ch == ' ' || ch == '\t');
3721 }
3722
3723 static gboolean
3724 not_whitespace (gunichar ch, gpointer user_data)
3725 {
3726   return !whitespace (ch, user_data);
3727 }
3728
3729 static gboolean
3730 find_whitepace_region (const GtkTextIter *center,
3731                        GtkTextIter *start, GtkTextIter *end)
3732 {
3733   *start = *center;
3734   *end = *center;
3735
3736   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
3737     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
3738   if (whitespace (gtk_text_iter_get_char (end), NULL))
3739     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
3740
3741   return !gtk_text_iter_equal (start, end);
3742 }
3743
3744 static void
3745 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
3746                                 const gchar *str)
3747 {
3748   gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
3749                                                 text_view->editable);
3750 }
3751
3752 static void
3753 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
3754                                   GtkDeleteType  type,
3755                                   gint           count)
3756 {
3757   GtkTextIter insert;
3758   GtkTextIter start;
3759   GtkTextIter end;
3760   gboolean leave_one = FALSE;
3761
3762   gtk_text_view_reset_im_context (text_view);
3763
3764   if (type == GTK_DELETE_CHARS)
3765     {
3766       /* Char delete deletes the selection, if one exists */
3767       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
3768                                             text_view->editable))
3769         return;
3770     }
3771
3772   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3773                                     &insert,
3774                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3775                                                               "insert"));
3776
3777   start = insert;
3778   end = insert;
3779
3780   switch (type)
3781     {
3782     case GTK_DELETE_CHARS:
3783       gtk_text_iter_forward_cursor_positions (&end, count);
3784       break;
3785
3786     case GTK_DELETE_WORD_ENDS:
3787       if (count > 0)
3788         gtk_text_iter_forward_word_ends (&end, count);
3789       else if (count < 0)
3790         gtk_text_iter_backward_word_starts (&start, 0 - count);
3791       break;
3792
3793     case GTK_DELETE_WORDS:
3794       break;
3795
3796     case GTK_DELETE_DISPLAY_LINE_ENDS:
3797       break;
3798
3799     case GTK_DELETE_DISPLAY_LINES:
3800       break;
3801
3802     case GTK_DELETE_PARAGRAPH_ENDS:
3803       /* If we're already at a newline, we need to
3804        * simply delete that newline, instead of
3805        * moving to the next one.
3806        */
3807       if (gtk_text_iter_ends_line (&end))
3808         {
3809           gtk_text_iter_forward_line (&end);
3810           --count;
3811         }
3812
3813       while (count > 0)
3814         {
3815           if (!gtk_text_iter_forward_to_line_end (&end))
3816             break;
3817
3818           --count;
3819         }
3820
3821       /* FIXME figure out what a negative count means
3822          and support that */
3823       break;
3824
3825     case GTK_DELETE_PARAGRAPHS:
3826       if (count > 0)
3827         {
3828           gtk_text_iter_set_line_offset (&start, 0);
3829           gtk_text_iter_forward_to_line_end (&end);
3830
3831           /* Do the lines beyond the first. */
3832           while (count > 1)
3833             {
3834               gtk_text_iter_forward_to_line_end (&end);
3835
3836               --count;
3837             }
3838         }
3839
3840       /* FIXME negative count? */
3841
3842       break;
3843
3844     case GTK_DELETE_WHITESPACE:
3845       {
3846         find_whitepace_region (&insert, &start, &end);
3847       }
3848       break;
3849
3850     default:
3851       break;
3852     }
3853
3854   if (!gtk_text_iter_equal (&start, &end))
3855     {
3856       gtk_text_buffer_begin_user_action (get_buffer (text_view));
3857
3858       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
3859                                               text_view->editable))
3860         {
3861           if (leave_one)
3862             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
3863                                                           " ", 1,
3864                                                           text_view->editable);
3865         }
3866
3867       gtk_text_buffer_end_user_action (get_buffer (text_view));
3868       
3869       gtk_text_view_scroll_mark_onscreen (text_view,
3870                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
3871     }
3872 }
3873
3874 static void
3875 gtk_text_view_cut_clipboard (GtkTextView *text_view)
3876 {
3877   gtk_text_buffer_cut_clipboard (get_buffer (text_view), text_view->editable);
3878   gtk_text_view_scroll_mark_onscreen (text_view,
3879                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3880                                                                 "insert"));
3881 }
3882
3883 static void
3884 gtk_text_view_copy_clipboard (GtkTextView *text_view)
3885 {
3886   gtk_text_buffer_copy_clipboard (get_buffer (text_view));
3887   gtk_text_view_scroll_mark_onscreen (text_view,
3888                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3889                                                                 "insert"));
3890 }
3891
3892 static void
3893 gtk_text_view_paste_clipboard (GtkTextView *text_view)
3894 {
3895   gtk_text_buffer_paste_clipboard (get_buffer (text_view), text_view->editable);
3896   gtk_text_view_scroll_mark_onscreen (text_view,
3897                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3898                                                                 "insert"));
3899 }
3900
3901 static void
3902 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
3903 {
3904   text_view->overwrite_mode = !text_view->overwrite_mode;
3905 }
3906
3907 /*
3908  * Selections
3909  */
3910
3911 static void
3912 gtk_text_view_unselect (GtkTextView *text_view)
3913 {
3914   GtkTextIter insert;
3915
3916   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3917                                     &insert,
3918                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3919                                                               "insert"));
3920
3921   gtk_text_buffer_move_mark (get_buffer (text_view),
3922                              gtk_text_buffer_get_mark (get_buffer (text_view),
3923                                                        "selection_bound"),
3924                              &insert);
3925 }
3926
3927 static void
3928 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
3929                                  const gchar *mark_name)
3930 {
3931   gint x, y;
3932   GdkModifierType state;
3933   GtkTextIter newplace;
3934
3935   gdk_window_get_pointer (text_view->text_window->bin_window,
3936                           &x, &y, &state);
3937   
3938   gtk_text_layout_get_iter_at_pixel (text_view->layout,
3939                                      &newplace,
3940                                      x + text_view->xoffset,
3941                                      y + text_view->yoffset);
3942
3943   {
3944     GtkTextMark *mark =
3945       gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
3946
3947     gtk_text_buffer_move_mark (get_buffer (text_view),
3948                                mark,
3949                                &newplace);
3950
3951     gtk_text_view_scroll_mark_onscreen (text_view, mark);
3952   }
3953 }
3954
3955 static gint
3956 selection_scan_timeout (gpointer data)
3957 {
3958   GtkTextView *text_view;
3959
3960   text_view = GTK_TEXT_VIEW (data);
3961
3962   move_mark_to_pointer_and_scroll (text_view, "insert");
3963
3964   return TRUE; /* remain installed. */
3965 }
3966
3967 #define DND_SCROLL_MARGIN 0.20
3968
3969 static gint
3970 drag_scan_timeout (gpointer data)
3971 {
3972   GtkTextView *text_view;
3973   gint x, y;
3974   GdkModifierType state;
3975   GtkTextIter newplace;
3976   
3977   text_view = GTK_TEXT_VIEW (data);
3978
3979   gdk_window_get_pointer (text_view->text_window->bin_window,
3980                           &x, &y, &state);
3981   
3982   gtk_text_layout_get_iter_at_pixel (text_view->layout,
3983                                      &newplace,
3984                                      x + text_view->xoffset,
3985                                      y + text_view->yoffset);
3986   
3987   gtk_text_buffer_move_mark (get_buffer (text_view),
3988                              text_view->dnd_mark,
3989                              &newplace);
3990   
3991   gtk_text_view_scroll_to_mark (text_view,
3992                                 text_view->dnd_mark,
3993                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
3994
3995   return TRUE;
3996 }
3997
3998 static gint
3999 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
4000 {
4001   move_mark_to_pointer_and_scroll (text_view, "insert");
4002
4003   /* If we had to scroll offscreen, insert a timeout to do so
4004    * again. Note that in the timeout, even if the mouse doesn't
4005    * move, due to this scroll xoffset/yoffset will have changed
4006    * and we'll need to scroll again.
4007    */
4008   if (text_view->scroll_timeout != 0) /* reset on every motion event */
4009     gtk_timeout_remove (text_view->scroll_timeout);
4010   
4011   text_view->scroll_timeout =
4012     gtk_timeout_add (50, selection_scan_timeout, text_view);
4013
4014   return TRUE;
4015 }
4016
4017 static void
4018 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
4019                                     const GtkTextIter *iter,
4020                                     GdkEventButton    *button)
4021 {
4022   GtkTextIter newplace;
4023
4024   g_return_if_fail (text_view->selection_drag_handler == 0);
4025
4026   gtk_grab_add (GTK_WIDGET (text_view));
4027
4028   newplace = *iter;
4029
4030   gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
4031
4032   text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
4033                                                           "motion_notify_event",
4034                                                           GTK_SIGNAL_FUNC (selection_motion_event_handler),
4035                                                           NULL);
4036 }
4037
4038 /* returns whether we were really dragging */
4039 static gboolean
4040 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
4041 {
4042   if (text_view->selection_drag_handler == 0)
4043     return FALSE;
4044
4045   gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
4046   text_view->selection_drag_handler = 0;
4047
4048   if (text_view->scroll_timeout != 0)
4049     {
4050       gtk_timeout_remove (text_view->scroll_timeout);
4051       text_view->scroll_timeout = 0;
4052     }
4053
4054   /* one last update to current position */
4055   move_mark_to_pointer_and_scroll (text_view, "insert");
4056
4057   gtk_grab_remove (GTK_WIDGET (text_view));
4058
4059   return TRUE;
4060 }
4061
4062 /*
4063  * Layout utils
4064  */
4065
4066 static void
4067 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
4068                                          GtkTextAttributes *values,
4069                                          GtkStyle           *style)
4070 {
4071   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
4072   values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
4073
4074   if (values->font.family_name)
4075     g_free (values->font.family_name);
4076
4077   values->font = *style->font_desc;
4078   values->font.family_name = g_strdup (style->font_desc->family_name);
4079 }
4080
4081 static void
4082 gtk_text_view_ensure_layout (GtkTextView *text_view)
4083 {
4084   GtkWidget *widget;
4085
4086   widget = GTK_WIDGET (text_view);
4087
4088   if (text_view->layout == NULL)
4089     {
4090       GtkTextAttributes *style;
4091       PangoContext *ltr_context, *rtl_context;
4092       GSList *tmp_list;
4093
4094       DV(g_print(G_STRLOC"\n"));
4095       
4096       text_view->layout = gtk_text_layout_new ();
4097
4098       g_signal_connect_data (G_OBJECT (text_view->layout),
4099                              "invalidated",
4100                              invalidated_handler,
4101                              text_view,
4102                              NULL, FALSE, FALSE);
4103
4104       g_signal_connect_data (G_OBJECT (text_view->layout),
4105                              "changed",
4106                              changed_handler,
4107                              text_view,
4108                              NULL, FALSE, FALSE);
4109
4110       g_signal_connect_data (G_OBJECT (text_view->layout),
4111                              "allocate_child",
4112                              gtk_text_view_child_allocated,
4113                              text_view,
4114                              NULL, FALSE, FALSE);
4115       
4116       if (get_buffer (text_view))
4117         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
4118
4119       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
4120         gtk_text_view_start_cursor_blink (text_view, FALSE);
4121       else
4122         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4123
4124       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
4125       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
4126       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
4127       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
4128
4129       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
4130
4131       g_object_unref (G_OBJECT (ltr_context));
4132       g_object_unref (G_OBJECT (rtl_context));
4133
4134       style = gtk_text_attributes_new ();
4135
4136       gtk_widget_ensure_style (widget);
4137       gtk_text_view_set_attributes_from_style (text_view,
4138                                                style, widget->style);
4139
4140       style->pixels_above_lines = text_view->pixels_above_lines;
4141       style->pixels_below_lines = text_view->pixels_below_lines;
4142       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
4143       style->left_margin = text_view->left_margin;
4144       style->right_margin = text_view->right_margin;
4145       style->indent = text_view->indent;
4146       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
4147
4148       style->wrap_mode = text_view->wrap_mode;
4149       style->justification = text_view->justify;
4150       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
4151
4152       gtk_text_layout_set_default_style (text_view->layout, style);
4153
4154       gtk_text_attributes_unref (style);
4155
4156       /* Set layout for all anchored children */
4157
4158       tmp_list = text_view->children;
4159       while (tmp_list != NULL)
4160         {
4161           GtkTextViewChild *vc = tmp_list->data;
4162
4163           if (vc->anchor)
4164             {
4165               gtk_text_anchored_child_set_layout (vc->widget,
4166                                                   text_view->layout);
4167               /* vc may now be invalid! */
4168             }
4169
4170           tmp_list = g_slist_next (tmp_list);
4171         }
4172     }
4173 }
4174
4175 static void
4176 gtk_text_view_destroy_layout (GtkTextView *text_view)
4177 {
4178   if (text_view->layout)
4179     {
4180       /* Remove layout from all anchored children */
4181       GSList *tmp_list;
4182
4183       tmp_list = text_view->children;
4184       while (tmp_list != NULL)
4185         {
4186           GtkTextViewChild *vc = tmp_list->data;
4187
4188           if (vc->anchor)
4189             {
4190               gtk_text_anchored_child_set_layout (vc->widget, NULL);
4191               /* vc may now be invalid! */
4192             }
4193
4194           tmp_list = g_slist_next (tmp_list);
4195         }
4196       
4197       gtk_text_view_stop_cursor_blink (text_view);
4198       gtk_text_view_end_selection_drag (text_view, NULL);
4199
4200       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
4201                                             invalidated_handler, text_view);
4202       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
4203                                             changed_handler, text_view);
4204       g_object_unref (G_OBJECT (text_view->layout));
4205       text_view->layout = NULL;
4206     }
4207 }
4208
4209 static void
4210 gtk_text_view_reset_im_context (GtkTextView *text_view)
4211 {
4212   if (text_view->need_im_reset)
4213     {
4214       text_view->need_im_reset = FALSE;
4215       gtk_im_context_reset (text_view->im_context);
4216     }
4217 }
4218
4219 /*
4220  * DND feature
4221  */
4222
4223 static void
4224 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
4225                                    const GtkTextIter *iter,
4226                                    GdkEventMotion    *event)
4227 {
4228   GdkDragContext *context;
4229   GtkTargetList *target_list;
4230
4231   text_view->drag_start_x = -1;
4232   text_view->drag_start_y = -1;
4233
4234   target_list = gtk_target_list_new (target_table,
4235                                      G_N_ELEMENTS (target_table));
4236
4237   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
4238                             GDK_ACTION_COPY | GDK_ACTION_MOVE,
4239                             1, (GdkEvent*)event);
4240
4241   gtk_target_list_unref (target_list);
4242
4243   gtk_drag_set_icon_default (context);
4244 }
4245
4246 static void
4247 gtk_text_view_drag_begin (GtkWidget        *widget,
4248                           GdkDragContext   *context)
4249 {
4250   /* do nothing */
4251 }
4252
4253 static void
4254 gtk_text_view_drag_end (GtkWidget        *widget,
4255                         GdkDragContext   *context)
4256 {
4257   GtkTextView *text_view;
4258
4259   text_view = GTK_TEXT_VIEW (widget);
4260 }
4261
4262 static void
4263 gtk_text_view_drag_data_get (GtkWidget        *widget,
4264                              GdkDragContext   *context,
4265                              GtkSelectionData *selection_data,
4266                              guint             info,
4267                              guint             time)
4268 {
4269   GtkTextView *text_view;
4270
4271   text_view = GTK_TEXT_VIEW (widget);
4272
4273   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
4274     {
4275       GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
4276
4277       gtk_selection_data_set (selection_data,
4278                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
4279                               8, /* bytes */
4280                               (void*)&buffer,
4281                               sizeof (buffer));
4282     }
4283   else
4284     {
4285       gchar *str;
4286       GtkTextIter start;
4287       GtkTextIter end;
4288
4289       str = NULL;
4290
4291       if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4292                                                 &start, &end))
4293         {
4294           /* Extract the selected text */
4295           str = gtk_text_iter_get_visible_text (&start, &end);
4296         }
4297
4298       if (str)
4299         {
4300           gtk_selection_data_set_text (selection_data, str);
4301           g_free (str);
4302         }
4303     }
4304 }
4305
4306 static void
4307 gtk_text_view_drag_data_delete (GtkWidget        *widget,
4308                                 GdkDragContext   *context)
4309 {
4310   GtkTextView *text_view;
4311
4312   text_view = GTK_TEXT_VIEW (widget);
4313
4314   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
4315                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
4316 }
4317
4318 static void
4319 gtk_text_view_drag_leave (GtkWidget        *widget,
4320                           GdkDragContext   *context,
4321                           guint             time)
4322 {
4323   GtkTextView *text_view;
4324
4325   text_view = GTK_TEXT_VIEW (widget);
4326
4327   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4328   
4329   if (text_view->scroll_timeout != 0)
4330     gtk_timeout_remove (text_view->scroll_timeout);
4331
4332   text_view->scroll_timeout = 0;
4333 }
4334
4335 static gboolean
4336 gtk_text_view_drag_motion (GtkWidget        *widget,
4337                            GdkDragContext   *context,
4338                            gint              x,
4339                            gint              y,
4340                            guint             time)
4341 {
4342   GtkTextIter newplace;
4343   GtkTextView *text_view;
4344   GtkTextIter start;
4345   GtkTextIter end;
4346   GdkRectangle target_rect;
4347   gint bx, by;
4348   GdkDragAction suggested_action = 0;
4349   
4350   text_view = GTK_TEXT_VIEW (widget);
4351
4352   target_rect = text_view->text_window->allocation;
4353   
4354   if (x < target_rect.x ||
4355       y < target_rect.y ||
4356       x > (target_rect.x + target_rect.width) ||
4357       y > (target_rect.y + target_rect.height))
4358     return FALSE; /* outside the text window, allow parent widgets to handle event */
4359
4360   gtk_text_view_window_to_buffer_coords (text_view,
4361                                          GTK_TEXT_WINDOW_WIDGET,
4362                                          x, y,
4363                                          &bx, &by);
4364
4365   gtk_text_layout_get_iter_at_pixel (text_view->layout,
4366                                      &newplace,
4367                                      bx, by);  
4368
4369   if (gtk_drag_dest_find_target (widget, context,
4370                                  gtk_drag_dest_get_target_list (widget)) == GDK_NONE)
4371     {
4372       /* can't accept any of the offered targets */
4373     }                                 
4374   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4375                                             &start, &end) &&
4376            gtk_text_iter_in_range (&newplace, &start, &end))
4377     {
4378       /* We're inside the selection. */
4379     }
4380   else
4381     {      
4382       if (gtk_text_iter_editable (&newplace, text_view->editable))
4383         {
4384           GtkWidget *source_widget;
4385           
4386           suggested_action = context->suggested_action;
4387           
4388           source_widget = gtk_drag_get_source_widget (context);
4389           
4390           if (source_widget == widget)
4391             {
4392               /* Default to MOVE, unless the user has
4393                * pressed ctrl or alt to affect available actions
4394                */
4395               if ((context->actions & GDK_ACTION_MOVE) != 0)
4396                 suggested_action = GDK_ACTION_MOVE;
4397             }
4398         }
4399       else
4400         {
4401           /* Can't drop here. */
4402         }
4403     }
4404
4405   if (suggested_action != 0)
4406     {
4407       gtk_text_mark_set_visible (text_view->dnd_mark,
4408                                  text_view->cursor_visible);
4409       
4410       gdk_drag_status (context, suggested_action, time);
4411     }
4412   else
4413     {
4414       gdk_drag_status (context, 0, time);
4415       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4416     }
4417       
4418   gtk_text_buffer_move_mark (get_buffer (text_view),
4419                              text_view->dnd_mark,
4420                              &newplace);
4421
4422   gtk_text_view_scroll_to_mark (text_view,
4423                                 text_view->dnd_mark,
4424                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
4425   
4426   if (text_view->scroll_timeout != 0) /* reset on every motion event */
4427     gtk_timeout_remove (text_view->scroll_timeout);
4428       
4429   text_view->scroll_timeout =
4430     gtk_timeout_add (50, drag_scan_timeout, text_view);
4431
4432   /* TRUE return means don't propagate the drag motion to parent
4433    * widgets that may also be drop sites.
4434    */
4435   return TRUE;
4436 }
4437
4438 static gboolean
4439 gtk_text_view_drag_drop (GtkWidget        *widget,
4440                          GdkDragContext   *context,
4441                          gint              x,
4442                          gint              y,
4443                          guint             time)
4444 {
4445   GtkTextView *text_view;
4446   
4447   text_view = GTK_TEXT_VIEW (widget);
4448   
4449   if (text_view->scroll_timeout != 0)
4450     gtk_timeout_remove (text_view->scroll_timeout);
4451
4452   text_view->scroll_timeout = 0;
4453
4454   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4455   
4456   return TRUE;
4457 }
4458
4459 static void
4460 insert_text_data (GtkTextView      *text_view,
4461                   GtkTextIter      *drop_point,
4462                   GtkSelectionData *selection_data)
4463 {
4464   gchar *str;
4465
4466   str = gtk_selection_data_get_text (selection_data);
4467
4468   if (str)
4469     {
4470       gtk_text_buffer_insert_interactive (get_buffer (text_view),
4471                                           drop_point, str, -1,
4472                                           text_view->editable);
4473       g_free (str);
4474     }
4475 }
4476
4477 static void
4478 gtk_text_view_drag_data_received (GtkWidget        *widget,
4479                                   GdkDragContext   *context,
4480                                   gint              x,
4481                                   gint              y,
4482                                   GtkSelectionData *selection_data,
4483                                   guint             info,
4484                                   guint             time)
4485 {
4486   GtkTextIter drop_point;
4487   GtkTextView *text_view;
4488   GtkTextMark *drag_target_mark;
4489
4490   text_view = GTK_TEXT_VIEW (widget);
4491
4492   drag_target_mark = gtk_text_buffer_get_mark (get_buffer (text_view),
4493                                                "gtk_drag_target");
4494
4495   if (drag_target_mark == NULL)
4496     return;
4497
4498   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
4499                                     &drop_point,
4500                                     drag_target_mark);
4501
4502   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
4503     {
4504       GtkTextBuffer *src_buffer = NULL;
4505       GtkTextIter start, end;
4506       gboolean copy_tags = TRUE;
4507
4508       if (selection_data->length != sizeof (src_buffer))
4509         return;
4510
4511       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
4512
4513       if (src_buffer == NULL)
4514         return;
4515
4516       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
4517
4518       if (gtk_text_buffer_get_tag_table (src_buffer) !=
4519           gtk_text_buffer_get_tag_table (get_buffer (text_view)))
4520         copy_tags = FALSE;
4521
4522       if (gtk_text_buffer_get_selection_bounds (src_buffer,
4523                                                 &start,
4524                                                 &end))
4525         {
4526           if (copy_tags)
4527             gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
4528                                                       &drop_point,
4529                                                       &start,
4530                                                       &end,
4531                                                       text_view->editable);
4532           else
4533             {
4534               gchar *str;
4535
4536               str = gtk_text_iter_get_visible_text (&start, &end);
4537               gtk_text_buffer_insert_interactive (get_buffer (text_view),
4538                                                   &drop_point, str, -1,
4539                                                   text_view->editable);
4540               g_free (str);
4541             }
4542         }
4543     }
4544   else
4545     insert_text_data (text_view, &drop_point, selection_data);
4546 }
4547
4548 static GtkAdjustment*
4549 get_hadjustment (GtkTextView *text_view)
4550 {
4551   if (text_view->hadjustment == NULL)
4552     gtk_text_view_set_scroll_adjustments (text_view,
4553                                           NULL, /* forces creation */
4554                                           text_view->vadjustment);
4555
4556   return text_view->hadjustment;
4557 }
4558
4559 static GtkAdjustment*
4560 get_vadjustment (GtkTextView *text_view)
4561 {
4562   if (text_view->vadjustment == NULL)
4563     gtk_text_view_set_scroll_adjustments (text_view,
4564                                           text_view->hadjustment,
4565                                           NULL); /* forces creation */
4566   return text_view->vadjustment;
4567 }
4568
4569
4570 static void
4571 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
4572                                       GtkAdjustment *hadj,
4573                                       GtkAdjustment *vadj)
4574 {
4575   gboolean need_adjust = FALSE;
4576
4577   g_return_if_fail (text_view != NULL);
4578   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4579
4580   if (hadj)
4581     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4582   else
4583     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4584   if (vadj)
4585     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4586   else
4587     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4588
4589   if (text_view->hadjustment && (text_view->hadjustment != hadj))
4590     {
4591       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
4592       g_object_unref (G_OBJECT (text_view->hadjustment));
4593     }
4594
4595   if (text_view->vadjustment && (text_view->vadjustment != vadj))
4596     {
4597       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
4598       g_object_unref (G_OBJECT (text_view->vadjustment));
4599     }
4600
4601   if (text_view->hadjustment != hadj)
4602     {
4603       text_view->hadjustment = hadj;
4604       g_object_ref (G_OBJECT (text_view->hadjustment));
4605       gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
4606
4607       gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
4608                           (GtkSignalFunc) gtk_text_view_value_changed,
4609                           text_view);
4610       need_adjust = TRUE;
4611     }
4612
4613   if (text_view->vadjustment != vadj)
4614     {
4615       text_view->vadjustment = vadj;
4616       g_object_ref (G_OBJECT (text_view->vadjustment));
4617       gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
4618
4619       gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
4620                           (GtkSignalFunc) gtk_text_view_value_changed,
4621                           text_view);
4622       need_adjust = TRUE;
4623     }
4624
4625   if (need_adjust)
4626     gtk_text_view_value_changed (NULL, text_view);
4627 }
4628
4629 static void
4630 gtk_text_view_value_changed (GtkAdjustment *adj,
4631                              GtkTextView   *text_view)
4632 {
4633   GtkTextIter iter;
4634   gint line_top;
4635   gint dx = 0;
4636   gint dy = 0;
4637
4638   text_view->onscreen_validated = FALSE;
4639
4640   DV(g_print(">Scroll offset changed, onscreen_validated = FALSE ("G_STRLOC")\n"));
4641   
4642   if (adj == text_view->hadjustment)
4643     {
4644       dx = text_view->xoffset - (gint)adj->value;
4645       text_view->xoffset = adj->value;
4646     }
4647   else if (adj == text_view->vadjustment)
4648     {
4649       dy = text_view->yoffset - (gint)adj->value;
4650       text_view->yoffset = adj->value;
4651
4652       if (text_view->layout)
4653         {
4654           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
4655
4656           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
4657
4658           text_view->first_para_pixels = adj->value - line_top;
4659         }
4660     }
4661   
4662   if (GTK_WIDGET_REALIZED (text_view) && (dx != 0 || dy != 0))
4663     {
4664       if (dy != 0)
4665         {
4666           if (text_view->left_window)
4667             text_window_scroll (text_view->left_window, 0, dy);
4668           if (text_view->right_window)
4669             text_window_scroll (text_view->right_window, 0, dy);
4670         }
4671
4672       if (dx != 0)
4673         {
4674           if (text_view->top_window)
4675             text_window_scroll (text_view->top_window, dx, 0);
4676           if (text_view->bottom_window)
4677             text_window_scroll (text_view->bottom_window, dx, 0);
4678         }
4679
4680       /* It looks nicer to scroll the main area last, because
4681        * it takes a while, and making the side areas update
4682        * afterward emphasizes the slowness of scrolling the
4683        * main area.
4684        */
4685       text_window_scroll (text_view->text_window, dx, dy);
4686     }
4687
4688   /* This could result in invalidation, which would install the
4689    * first_validate_idle, which would validate onscreen;
4690    * but we're going to go ahead and validate here, so
4691    * first_validate_idle shouldn't have anything to do.
4692    */
4693   gtk_text_view_update_layout_width (text_view);
4694   
4695   /* note that validation of onscreen could invoke this function
4696    * recursively, by scrolling to maintain first_para, or in response
4697    * to updating the layout width, however there is no problem with
4698    * that, or shouldn't be.
4699    */
4700   gtk_text_view_validate_onscreen (text_view);
4701
4702   /* process exposes */
4703   if (GTK_WIDGET_REALIZED (text_view))
4704     {
4705       if (text_view->left_window)
4706         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
4707
4708       if (text_view->right_window)
4709         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
4710
4711       if (text_view->top_window)
4712         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
4713       
4714       if (text_view->bottom_window)
4715         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
4716   
4717       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
4718     }
4719
4720   /* If this got installed, get rid of it, it's just a waste of time. */
4721   if (text_view->first_validate_idle != 0)
4722     {
4723       g_source_remove (text_view->first_validate_idle);
4724       text_view->first_validate_idle = 0;
4725     }
4726   
4727   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
4728 }
4729
4730 static void
4731 gtk_text_view_commit_handler (GtkIMContext  *context,
4732                               const gchar   *str,
4733                               GtkTextView   *text_view)
4734 {
4735   gtk_text_buffer_begin_user_action (get_buffer (text_view));
4736
4737   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
4738                                     text_view->editable);
4739
4740   if (!strcmp (str, "\n"))
4741     {
4742       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
4743                                                     text_view->editable);
4744     }
4745   else
4746     {
4747       if (text_view->overwrite_mode)
4748         gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
4749       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
4750                                                     text_view->editable);
4751     }
4752
4753   gtk_text_buffer_end_user_action (get_buffer (text_view));
4754   
4755   gtk_text_view_scroll_mark_onscreen (text_view,
4756                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4757                                                                 "insert"));
4758 }
4759
4760 static void
4761 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
4762                                        GtkTextView  *text_view)
4763 {
4764   gchar *str;
4765   PangoAttrList *attrs;
4766   gint cursor_pos;
4767
4768   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
4769   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
4770
4771   pango_attr_list_unref (attrs);
4772   g_free (str);
4773 }
4774
4775 static void
4776 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
4777                                 const GtkTextIter *location,
4778                                 GtkTextMark       *mark,
4779                                 gpointer           data)
4780 {
4781   GtkTextView *text_view = GTK_TEXT_VIEW (data);
4782   gboolean need_reset = FALSE;
4783
4784   if (mark == gtk_text_buffer_get_insert (buffer))
4785     {
4786       text_view->virtual_cursor_x = -1;
4787       text_view->virtual_cursor_y = -1;
4788       need_reset = TRUE;
4789     }
4790   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
4791     {
4792       need_reset = TRUE;
4793     }
4794
4795   if (need_reset)
4796     gtk_text_view_reset_im_context (text_view);
4797 }
4798
4799 static void
4800 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
4801                                       gint        *x,
4802                                       gint        *y)
4803 {
4804   GdkRectangle strong_pos;
4805   GtkTextIter insert;
4806
4807   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4808                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4809                                                               "insert"));
4810
4811   if ((x && text_view->virtual_cursor_x == -1) ||
4812       (y && text_view->virtual_cursor_y == -1))
4813     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
4814
4815   if (x)
4816     {
4817       if (text_view->virtual_cursor_x != -1)
4818         *x = text_view->virtual_cursor_x;
4819       else
4820         *x = strong_pos.x;
4821     }
4822
4823   if (y)
4824     {
4825       if (text_view->virtual_cursor_x != -1)
4826         *y = text_view->virtual_cursor_y;
4827       else
4828         *y = strong_pos.y + strong_pos.height / 2;
4829     }
4830 }
4831
4832 static void
4833 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
4834                                       gint         x,
4835                                       gint         y)
4836 {
4837   GdkRectangle strong_pos;
4838   GtkTextIter insert;
4839
4840   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4841                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4842                                                               "insert"));
4843
4844   if (x == -1 || y == -1)
4845     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
4846
4847   text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
4848   text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
4849 }
4850
4851 /* Quick hack of a popup menu
4852  */
4853 static void
4854 activate_cb (GtkWidget   *menuitem,
4855              GtkTextView *text_view)
4856 {
4857   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
4858   gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal);
4859 }
4860
4861 static void
4862 append_action_signal (GtkTextView  *text_view,
4863                       GtkWidget    *menu,
4864                       const gchar  *label,
4865                       const gchar  *signal)
4866 {
4867   GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
4868
4869   g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
4870   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
4871                       activate_cb, text_view);
4872
4873   gtk_widget_show (menuitem);
4874   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
4875 }
4876
4877 static void
4878 popup_menu_detach (GtkWidget *attach_widget,
4879                    GtkMenu   *menu)
4880 {
4881   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
4882 }
4883
4884 static void
4885 gtk_text_view_popup_menu (GtkTextView    *text_view,
4886                           GdkEventButton *event)
4887 {
4888   if (!text_view->popup_menu)
4889     {
4890       GtkWidget *menuitem;
4891
4892       text_view->popup_menu = gtk_menu_new ();
4893
4894       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
4895                                  GTK_WIDGET (text_view),
4896                                  popup_menu_detach);
4897
4898       append_action_signal (text_view, text_view->popup_menu, _("Cut"), "cut_clipboard");
4899       append_action_signal (text_view, text_view->popup_menu, _("Copy"), "copy_clipboard");
4900       append_action_signal (text_view, text_view->popup_menu, _("Paste"), "paste_clipboard");
4901
4902       menuitem = gtk_menu_item_new (); /* Separator */
4903       gtk_widget_show (menuitem);
4904       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
4905
4906       gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
4907                                             GTK_MENU_SHELL (text_view->popup_menu));
4908     }
4909
4910   gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
4911                   NULL, NULL,
4912                   event->button, event->time);
4913 }
4914
4915
4916
4917 /* Child GdkWindows */
4918
4919
4920 static GtkTextWindow*
4921 text_window_new (GtkTextWindowType  type,
4922                  GtkWidget         *widget,
4923                  gint               width_request,
4924                  gint               height_request)
4925 {
4926   GtkTextWindow *win;
4927
4928   win = g_new (GtkTextWindow, 1);
4929
4930   win->type = type;
4931   win->widget = widget;
4932   win->window = NULL;
4933   win->bin_window = NULL;
4934   win->requisition.width = width_request;
4935   win->requisition.height = height_request;
4936   win->allocation.width = width_request;
4937   win->allocation.height = height_request;
4938   win->allocation.x = 0;
4939   win->allocation.y = 0;
4940
4941   return win;
4942 }
4943
4944 static void
4945 text_window_free (GtkTextWindow *win)
4946 {
4947   if (win->window)
4948     text_window_unrealize (win);
4949
4950   g_free (win);
4951 }
4952
4953 static void
4954 text_window_realize (GtkTextWindow *win,
4955                      GdkWindow     *parent)
4956 {
4957   GdkWindowAttr attributes;
4958   gint attributes_mask;
4959   GdkCursor *cursor;
4960
4961   attributes.window_type = GDK_WINDOW_CHILD;
4962   attributes.x = win->allocation.x;
4963   attributes.y = win->allocation.y;
4964   attributes.width = win->allocation.width;
4965   attributes.height = win->allocation.height;
4966   attributes.wclass = GDK_INPUT_OUTPUT;
4967   attributes.visual = gtk_widget_get_visual (win->widget);
4968   attributes.colormap = gtk_widget_get_colormap (win->widget);
4969   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
4970
4971   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
4972
4973   win->window = gdk_window_new (parent,
4974                                 &attributes,
4975                                 attributes_mask);
4976
4977   gdk_window_show (win->window);
4978   gdk_window_set_user_data (win->window, win->widget);
4979
4980   attributes.x = 0;
4981   attributes.y = 0;
4982   attributes.width = win->allocation.width;
4983   attributes.height = win->allocation.height;
4984   attributes.event_mask = (GDK_EXPOSURE_MASK            |
4985                            GDK_SCROLL_MASK              |
4986                            GDK_KEY_PRESS_MASK           |
4987                            GDK_BUTTON_PRESS_MASK        |
4988                            GDK_BUTTON_RELEASE_MASK      |
4989                            GDK_POINTER_MOTION_MASK      |
4990                            GDK_POINTER_MOTION_HINT_MASK |
4991                            gtk_widget_get_events (win->widget));
4992
4993   win->bin_window = gdk_window_new (win->window,
4994                                     &attributes,
4995                                     attributes_mask);
4996
4997   gdk_window_show (win->bin_window);
4998   gdk_window_set_user_data (win->bin_window, win->widget);
4999
5000   if (win->type == GTK_TEXT_WINDOW_TEXT)
5001     {
5002       /* I-beam cursor */
5003       cursor = gdk_cursor_new (GDK_XTERM);
5004       gdk_window_set_cursor (win->bin_window, cursor);
5005       gdk_cursor_destroy (cursor);
5006
5007       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
5008                                         win->window);
5009
5010
5011       gdk_window_set_background (win->bin_window,
5012                                  &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
5013     }
5014   else
5015     {
5016       gdk_window_set_background (win->bin_window,
5017                                  &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
5018     }
5019
5020   g_object_set_qdata (G_OBJECT (win->window),
5021                       g_quark_from_static_string ("gtk-text-view-text-window"),
5022                       win);
5023
5024   g_object_set_qdata (G_OBJECT (win->bin_window),
5025                       g_quark_from_static_string ("gtk-text-view-text-window"),
5026                       win);
5027 }
5028
5029 static void
5030 text_window_unrealize (GtkTextWindow *win)
5031 {
5032   if (win->type == GTK_TEXT_WINDOW_TEXT)
5033     {
5034       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
5035                                         NULL);
5036     }
5037
5038   gdk_window_set_user_data (win->window, NULL);
5039   gdk_window_set_user_data (win->bin_window, NULL);
5040   gdk_window_destroy (win->bin_window);
5041   gdk_window_destroy (win->window);
5042   win->window = NULL;
5043   win->bin_window = NULL;
5044 }
5045
5046 static void
5047 text_window_size_allocate (GtkTextWindow *win,
5048                            GdkRectangle  *rect)
5049 {
5050   win->allocation = *rect;
5051
5052   if (win->window)
5053     {
5054       gdk_window_move_resize (win->window,
5055                               rect->x, rect->y,
5056                               rect->width, rect->height);
5057
5058       gdk_window_resize (win->bin_window,
5059                          rect->width, rect->height);
5060     }
5061 }
5062
5063 static void
5064 text_window_scroll        (GtkTextWindow *win,
5065                            gint           dx,
5066                            gint           dy)
5067 {
5068   if (dx != 0 || dy != 0)
5069     {
5070       gdk_window_scroll (win->bin_window, dx, dy);
5071     }
5072 }
5073
5074 void
5075 text_window_invalidate_rect (GtkTextWindow *win,
5076                              GdkRectangle  *rect)
5077 {
5078   GdkRectangle window_rect;
5079
5080   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
5081                                          win->type,
5082                                          rect->x,
5083                                          rect->y,
5084                                          &window_rect.x,
5085                                          &window_rect.y);
5086
5087   window_rect.width = rect->width;
5088   window_rect.height = rect->height;
5089   
5090   /* Adjust the rect as appropriate */
5091   
5092   switch (win->type)
5093     {
5094     case GTK_TEXT_WINDOW_TEXT:
5095       break;
5096
5097     case GTK_TEXT_WINDOW_LEFT:
5098     case GTK_TEXT_WINDOW_RIGHT:
5099       window_rect.x = 0;
5100       window_rect.width = win->allocation.width;
5101       break;
5102
5103     case GTK_TEXT_WINDOW_TOP:
5104     case GTK_TEXT_WINDOW_BOTTOM:
5105       window_rect.y = 0;
5106       window_rect.height = win->allocation.height;
5107       break;
5108
5109     default:
5110       g_warning ("%s: bug!", G_STRLOC);
5111       return;
5112       break;
5113     }
5114           
5115   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
5116
5117 #if 0
5118   {
5119     GdkColor color = { 0, 65535, 0, 0 };
5120     GdkGC *gc = gdk_gc_new (win->bin_window);
5121     gdk_gc_set_rgb_fg_color (gc, &color);
5122     gdk_draw_rectangle (win->bin_window,
5123                         gc, TRUE, window_rect.x, window_rect.y,
5124                         window_rect.width, window_rect.height);
5125     gdk_gc_unref (gc);
5126   }
5127 #endif
5128 }
5129
5130 static gint
5131 text_window_get_width (GtkTextWindow *win)
5132 {
5133   return win->allocation.width;
5134 }
5135
5136 static gint
5137 text_window_get_height (GtkTextWindow *win)
5138 {
5139   return win->allocation.height;
5140 }
5141
5142 static void
5143 text_window_get_allocation (GtkTextWindow *win,
5144                             GdkRectangle  *rect)
5145 {
5146   *rect = win->allocation;
5147 }
5148
5149 /* Windows */
5150
5151
5152 /**
5153  * gtk_text_view_get_window:
5154  * @text_view: a #GtkTextView
5155  * @win: window to get
5156  *
5157  * Retrieves the #GdkWindow corresponding to an area of the text view;
5158  * possible windows include the overall widget window, child windows
5159  * on the left, right, top, bottom, and the window that displays the
5160  * text buffer. Windows are %NULL and nonexistent if their width or
5161  * height is 0, and are nonexistent before the widget has been
5162  * realized.
5163  *
5164  * Return value: a #GdkWindow, or %NULL
5165  **/
5166 GdkWindow*
5167 gtk_text_view_get_window (GtkTextView *text_view,
5168                           GtkTextWindowType win)
5169 {
5170   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
5171
5172   switch (win)
5173     {
5174     case GTK_TEXT_WINDOW_WIDGET:
5175       return GTK_WIDGET (text_view)->window;
5176       break;
5177
5178     case GTK_TEXT_WINDOW_TEXT:
5179       return text_view->text_window->bin_window;
5180       break;
5181
5182     case GTK_TEXT_WINDOW_LEFT:
5183       if (text_view->left_window)
5184         return text_view->left_window->bin_window;
5185       else
5186         return NULL;
5187       break;
5188
5189     case GTK_TEXT_WINDOW_RIGHT:
5190       if (text_view->right_window)
5191         return text_view->right_window->bin_window;
5192       else
5193         return NULL;
5194       break;
5195
5196     case GTK_TEXT_WINDOW_TOP:
5197       if (text_view->top_window)
5198         return text_view->top_window->bin_window;
5199       else
5200         return NULL;
5201       break;
5202
5203     case GTK_TEXT_WINDOW_BOTTOM:
5204       if (text_view->bottom_window)
5205         return text_view->bottom_window->bin_window;
5206       else
5207         return NULL;
5208       break;
5209
5210     default:
5211       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
5212       return NULL;
5213       break;
5214     }
5215 }
5216
5217 /**
5218  * gtk_text_view_get_window_type:
5219  * @text_view: a #GtkTextView
5220  * @window: a window type
5221  *
5222  * Usually used to find out which window an event corresponds to.
5223  * If you connect to an event signal on @text_view, this function
5224  * should be called on <literal>event-&gt;window</literal> to
5225  * see which window it was.
5226  *
5227  * Return value: the window type.
5228  **/
5229 GtkTextWindowType
5230 gtk_text_view_get_window_type (GtkTextView *text_view,
5231                                GdkWindow   *window)
5232 {
5233   GtkTextWindow *win;
5234
5235   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
5236   g_return_val_if_fail (GDK_IS_WINDOW (text_view), 0);
5237
5238   if (window == GTK_WIDGET (text_view)->window)
5239     return GTK_TEXT_WINDOW_WIDGET;
5240
5241   win = g_object_get_qdata (G_OBJECT (window),
5242                             g_quark_try_string ("gtk-text-view-text-window"));
5243
5244   if (win)
5245     return win->type;
5246   else
5247     {
5248       return GTK_TEXT_WINDOW_PRIVATE;
5249     }
5250 }
5251
5252 static void
5253 buffer_to_widget (GtkTextView      *text_view,
5254                   gint              buffer_x,
5255                   gint              buffer_y,
5256                   gint             *window_x,
5257                   gint             *window_y)
5258 {
5259   if (window_x)
5260     {
5261       *window_x = buffer_x - text_view->xoffset + FOCUS_EDGE_WIDTH;
5262       if (text_view->left_window)
5263         *window_x += text_view->left_window->allocation.width;
5264     }
5265
5266   if (window_y)
5267     {
5268       *window_y = buffer_y - text_view->yoffset + FOCUS_EDGE_WIDTH;
5269       if (text_view->top_window)
5270         *window_y += text_view->top_window->allocation.height;
5271     }
5272 }
5273
5274 static void
5275 widget_to_text_window (GtkTextWindow *win,
5276                        gint           widget_x,
5277                        gint           widget_y,
5278                        gint          *window_x,
5279                        gint          *window_y)
5280 {
5281   if (window_x)
5282     *window_x = widget_x - win->allocation.x;
5283
5284   if (window_y)
5285     *window_y = widget_y - win->allocation.y;
5286 }
5287
5288 static void
5289 buffer_to_text_window (GtkTextView   *text_view,
5290                        GtkTextWindow *win,
5291                        gint           buffer_x,
5292                        gint           buffer_y,
5293                        gint          *window_x,
5294                        gint          *window_y)
5295 {
5296   if (win == NULL)
5297     {
5298       g_warning ("Attempt to convert text buffer coordinates to coordinates "
5299                  "for a nonexistent or private child window of GtkTextView");
5300       return;
5301     }
5302
5303   buffer_to_widget (text_view,
5304                     buffer_x, buffer_y,
5305                     window_x, window_y);
5306
5307   widget_to_text_window (win,
5308                          window_x ? *window_x : 0,
5309                          window_y ? *window_y : 0,
5310                          window_x,
5311                          window_y);
5312 }
5313
5314 /**
5315  * gtk_text_view_buffer_to_window_coords:
5316  * @text_view: a #GtkTextView
5317  * @win: a #GtkTextWindowType
5318  * @buffer_x: buffer x coordinate
5319  * @buffer_y: buffer y coordinate
5320  * @window_x: window x coordinate return location
5321  * @window_y: window y coordinate return location
5322  *
5323  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
5324  * @win, and stores the result in (@window_x, @window_y).
5325  **/
5326 void
5327 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
5328                                        GtkTextWindowType win,
5329                                        gint              buffer_x,
5330                                        gint              buffer_y,
5331                                        gint             *window_x,
5332                                        gint             *window_y)
5333 {
5334   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5335
5336   switch (win)
5337     {
5338     case GTK_TEXT_WINDOW_WIDGET:
5339       buffer_to_widget (text_view,
5340                         buffer_x, buffer_y,
5341                         window_x, window_y);
5342       break;
5343
5344     case GTK_TEXT_WINDOW_TEXT:
5345       if (window_x)
5346         *window_x = buffer_x - text_view->xoffset;
5347       if (window_y)
5348         *window_y = buffer_y - text_view->yoffset;
5349       break;
5350
5351     case GTK_TEXT_WINDOW_LEFT:
5352       buffer_to_text_window (text_view,
5353                              text_view->left_window,
5354                              buffer_x, buffer_y,
5355                              window_x, window_y);
5356       break;
5357
5358     case GTK_TEXT_WINDOW_RIGHT:
5359       buffer_to_text_window (text_view,
5360                              text_view->right_window,
5361                              buffer_x, buffer_y,
5362                              window_x, window_y);
5363       break;
5364
5365     case GTK_TEXT_WINDOW_TOP:
5366       buffer_to_text_window (text_view,
5367                              text_view->top_window,
5368                              buffer_x, buffer_y,
5369                              window_x, window_y);
5370       break;
5371
5372     case GTK_TEXT_WINDOW_BOTTOM:
5373       buffer_to_text_window (text_view,
5374                              text_view->bottom_window,
5375                              buffer_x, buffer_y,
5376                              window_x, window_y);
5377       break;
5378
5379     case GTK_TEXT_WINDOW_PRIVATE:
5380       g_warning ("%s: can't get coords for private windows", G_STRLOC);
5381       break;
5382
5383     default:
5384       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
5385       break;
5386     }
5387 }
5388
5389 static void
5390 widget_to_buffer (GtkTextView *text_view,
5391                   gint         widget_x,
5392                   gint         widget_y,
5393                   gint        *buffer_x,
5394                   gint        *buffer_y)
5395 {
5396   if (buffer_x)
5397     {
5398       *buffer_x = widget_x - FOCUS_EDGE_WIDTH + text_view->xoffset;
5399       if (text_view->left_window)
5400         *buffer_x -= text_view->left_window->allocation.width;
5401     }
5402
5403   if (buffer_y)
5404     {
5405       *buffer_y = widget_y - FOCUS_EDGE_WIDTH + text_view->yoffset;
5406       if (text_view->top_window)
5407         *buffer_y -= text_view->top_window->allocation.height;
5408     }
5409 }
5410
5411 static void
5412 text_window_to_widget (GtkTextWindow *win,
5413                        gint           window_x,
5414                        gint           window_y,
5415                        gint          *widget_x,
5416                        gint          *widget_y)
5417 {
5418   if (widget_x)
5419     *widget_x = window_x + win->allocation.x;
5420
5421   if (widget_y)
5422     *widget_y = window_y + win->allocation.y;
5423 }
5424
5425 static void
5426 text_window_to_buffer (GtkTextView   *text_view,
5427                        GtkTextWindow *win,
5428                        gint           window_x,
5429                        gint           window_y,
5430                        gint          *buffer_x,
5431                        gint          *buffer_y)
5432 {
5433   if (win == NULL)
5434     {
5435       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
5436                  "coordinates for a nonexistent child window.");
5437       return;
5438     }
5439
5440   text_window_to_widget (win,
5441                          window_x,
5442                          window_y,
5443                          buffer_x,
5444                          buffer_y);
5445
5446   widget_to_buffer (text_view,
5447                     buffer_x ? *buffer_x : 0,
5448                     buffer_y ? *buffer_y : 0,
5449                     buffer_x,
5450                     buffer_y);
5451 }
5452
5453 /**
5454  * gtk_text_view_window_to_buffer_coords:
5455  * @text_view: a #GtkTextView
5456  * @win: a #GtkTextWindowType
5457  * @window_x: window x coordinate
5458  * @window_y: window y coordinate
5459  * @buffer_x: buffer x coordinate return location
5460  * @buffer_y: buffer y coordinate return location
5461  *
5462  * Converts coordinates on the window identified by @win to buffer
5463  * coordinates, storing the result in (@buffer_x,@buffer_y).
5464  **/
5465 void
5466 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
5467                                        GtkTextWindowType win,
5468                                        gint              window_x,
5469                                        gint              window_y,
5470                                        gint             *buffer_x,
5471                                        gint             *buffer_y)
5472 {
5473   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5474
5475   switch (win)
5476     {
5477     case GTK_TEXT_WINDOW_WIDGET:
5478       widget_to_buffer (text_view,
5479                         window_x, window_y,
5480                         buffer_x, buffer_y);
5481       break;
5482
5483     case GTK_TEXT_WINDOW_TEXT:
5484       if (buffer_x)
5485         *buffer_x = window_x + text_view->xoffset;
5486       if (buffer_y)
5487         *buffer_y = window_y + text_view->yoffset;
5488       break;
5489
5490     case GTK_TEXT_WINDOW_LEFT:
5491       text_window_to_buffer (text_view,
5492                              text_view->left_window,
5493                              window_x, window_y,
5494                              buffer_x, buffer_y);
5495       break;
5496
5497     case GTK_TEXT_WINDOW_RIGHT:
5498       text_window_to_buffer (text_view,
5499                              text_view->right_window,
5500                              window_x, window_y,
5501                              buffer_x, buffer_y);
5502       break;
5503
5504     case GTK_TEXT_WINDOW_TOP:
5505       text_window_to_buffer (text_view,
5506                              text_view->top_window,
5507                              window_x, window_y,
5508                              buffer_x, buffer_y);
5509       break;
5510
5511     case GTK_TEXT_WINDOW_BOTTOM:
5512       text_window_to_buffer (text_view,
5513                              text_view->bottom_window,
5514                              window_x, window_y,
5515                              buffer_x, buffer_y);
5516       break;
5517
5518     case GTK_TEXT_WINDOW_PRIVATE:
5519       g_warning ("%s: can't get coords for private windows", G_STRLOC);
5520       break;
5521
5522     default:
5523       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
5524       break;
5525     }
5526 }
5527
5528 static void
5529 set_window_width (GtkTextView      *text_view,
5530                   gint              width,
5531                   GtkTextWindowType type,
5532                   GtkTextWindow   **winp)
5533 {
5534   if (width == 0)
5535     {
5536       if (*winp)
5537         {
5538           text_window_free (*winp);
5539           *winp = NULL;
5540           gtk_widget_queue_resize (GTK_WIDGET (text_view));
5541         }
5542     }
5543   else
5544     {
5545       if (*winp == NULL)
5546         {
5547           *winp = text_window_new (type,
5548                                    GTK_WIDGET (text_view),
5549                                    width, 0);
5550         }
5551       else
5552         {
5553           if ((*winp)->requisition.width == width)
5554             return;
5555         }
5556
5557       gtk_widget_queue_resize (GTK_WIDGET (text_view));
5558     }
5559 }
5560
5561
5562 static void
5563 set_window_height (GtkTextView      *text_view,
5564                    gint              height,
5565                    GtkTextWindowType type,
5566                    GtkTextWindow   **winp)
5567 {
5568   if (height == 0)
5569     {
5570       if (*winp)
5571         {
5572           text_window_free (*winp);
5573           *winp = NULL;
5574           gtk_widget_queue_resize (GTK_WIDGET (text_view));
5575         }
5576     }
5577   else
5578     {
5579       if (*winp == NULL)
5580         {
5581           *winp = text_window_new (type,
5582                                    GTK_WIDGET (text_view),
5583                                    0, height);
5584         }
5585       else
5586         {
5587           if ((*winp)->requisition.height == height)
5588             return;
5589         }
5590
5591       gtk_widget_queue_resize (GTK_WIDGET (text_view));
5592     }
5593 }
5594
5595 /**
5596  * gtk_text_view_set_border_window_size:
5597  * @text_view: a #GtkTextView
5598  * @type: window to affect
5599  * @size: width or height of the window
5600  *
5601  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
5602  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
5603  * Automatically destroys the corresponding window if the size is set to 0,
5604  * and creates the window if the size is set to non-zero.
5605  **/
5606 void
5607 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
5608                                       GtkTextWindowType type,
5609                                       gint              size)
5610
5611 {
5612   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5613   g_return_if_fail (size >= 0);
5614   g_return_if_fail (type != GTK_TEXT_WINDOW_WIDGET);
5615   g_return_if_fail (type != GTK_TEXT_WINDOW_TEXT);
5616
5617   switch (type)
5618     {
5619     case GTK_TEXT_WINDOW_LEFT:
5620       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
5621                         &text_view->left_window);
5622       break;
5623
5624     case GTK_TEXT_WINDOW_RIGHT:
5625       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
5626                         &text_view->right_window);
5627       break;
5628
5629     case GTK_TEXT_WINDOW_TOP:
5630       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
5631                          &text_view->top_window);
5632       break;
5633
5634     case GTK_TEXT_WINDOW_BOTTOM:
5635       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
5636                          &text_view->bottom_window);
5637       break;
5638
5639     default:
5640       g_warning ("Can't set size of center or widget or private GtkTextWindowType in %s", G_STRLOC);
5641       break;
5642     }
5643 }
5644
5645 /**
5646  * gtk_text_view_set_text_window_size:
5647  * @text_view: a #GtkTextView
5648  * @width: a width in pixels
5649  * @height: a height in pixels
5650  *
5651  * Sets the size request for the main text window (%GTK_TEXT_WINDOW_TEXT).
5652  * If the widget gets more space than it requested, the main text window
5653  * will be larger than this.
5654  *
5655  **/
5656 void
5657 gtk_text_view_set_text_window_size (GtkTextView *text_view,
5658                                     gint         width,
5659                                     gint         height)
5660 {
5661   GtkTextWindow *win;
5662
5663   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5664   g_return_if_fail (width > 0);
5665   g_return_if_fail (height > 0);
5666
5667   win = text_view->text_window;
5668
5669   if (win->requisition.width == width &&
5670       win->requisition.height == height)
5671     return;
5672
5673   win->requisition.width = width;
5674   win->requisition.height = height;
5675
5676   gtk_widget_queue_resize (GTK_WIDGET (text_view));
5677 }
5678
5679 /*
5680  * Child widgets
5681  */
5682
5683 static GtkTextViewChild*
5684 text_view_child_new_anchored (GtkWidget          *child,
5685                               GtkTextChildAnchor *anchor,
5686                               GtkTextLayout      *layout)
5687 {
5688   GtkTextViewChild *vc;
5689
5690   vc = g_new (GtkTextViewChild, 1);
5691
5692   vc->widget = child;
5693   vc->anchor = anchor;
5694
5695   vc->from_top_of_line = 0;
5696   vc->from_left_of_buffer = 0;
5697   
5698   g_object_ref (G_OBJECT (vc->widget));
5699   g_object_ref (G_OBJECT (vc->anchor));
5700
5701   g_object_set_data (G_OBJECT (child),
5702                      "gtk-text-view-child",
5703                      vc);
5704
5705   gtk_text_child_anchor_register_child (anchor, child, layout);
5706   
5707   return vc;
5708 }
5709
5710 static GtkTextViewChild*
5711 text_view_child_new_window (GtkWidget          *child,
5712                             GtkTextWindowType   type,
5713                             gint                x,
5714                             gint                y)
5715 {
5716   GtkTextViewChild *vc;
5717
5718   vc = g_new (GtkTextViewChild, 1);
5719
5720   vc->widget = child;
5721   vc->anchor = NULL;
5722
5723   vc->from_top_of_line = 0;
5724   vc->from_left_of_buffer = 0;
5725   
5726   g_object_ref (G_OBJECT (vc->widget));
5727
5728   vc->type = type;
5729   vc->x = x;
5730   vc->y = y;
5731
5732   return vc;
5733 }
5734
5735 static void
5736 text_view_child_free (GtkTextViewChild *child)
5737 {
5738   g_object_set_data (G_OBJECT (child->widget),
5739                      "gtk-text-view-child", NULL);
5740
5741   if (child->anchor)
5742     {
5743       gtk_text_child_anchor_unregister_child (child->anchor,
5744                                               child->widget);
5745       g_object_unref (G_OBJECT (child->anchor));
5746     }
5747
5748   g_object_unref (G_OBJECT (child->widget));
5749
5750   g_free (child);
5751 }
5752
5753 static void
5754 text_view_child_realize (GtkTextView      *text_view,
5755                          GtkTextViewChild *vc)
5756 {
5757   if (vc->anchor)
5758     gtk_widget_set_parent_window (vc->widget,
5759                                   text_view->text_window->bin_window);
5760   else
5761     {
5762       GdkWindow *window;
5763       window = gtk_text_view_get_window (text_view,
5764                                          vc->type);
5765       gtk_widget_set_parent_window (vc->widget, window);
5766     }
5767
5768   gtk_widget_realize (vc->widget);
5769 }
5770
5771 static void
5772 add_child (GtkTextView      *text_view,
5773            GtkTextViewChild *vc)
5774 {
5775   text_view->children = g_slist_prepend (text_view->children,
5776                                          vc);
5777
5778   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
5779
5780   if (GTK_WIDGET_REALIZED (text_view))
5781     text_view_child_realize (text_view, vc);
5782
5783   if (GTK_WIDGET_VISIBLE (text_view) && GTK_WIDGET_VISIBLE (vc->widget))
5784     {
5785       if (GTK_WIDGET_MAPPED (text_view))
5786         gtk_widget_map (vc->widget);
5787
5788       gtk_widget_queue_resize (vc->widget);
5789     }
5790 }
5791
5792 void
5793 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
5794                                    GtkWidget            *child,
5795                                    GtkTextChildAnchor   *anchor)
5796 {
5797   GtkTextViewChild *vc;
5798
5799   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5800   g_return_if_fail (GTK_IS_WIDGET (child));
5801   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5802   g_return_if_fail (child->parent == NULL);
5803
5804   gtk_text_view_ensure_layout (text_view);
5805
5806   vc = text_view_child_new_anchored (child, anchor,
5807                                      text_view->layout);
5808
5809   add_child (text_view, vc);
5810 }
5811
5812 void
5813 gtk_text_view_add_child_in_window (GtkTextView          *text_view,
5814                                    GtkWidget            *child,
5815                                    GtkTextWindowType     which_window,
5816                                    gint                  xpos,
5817                                    gint                  ypos)
5818 {
5819   GtkTextViewChild *vc;
5820
5821   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5822   g_return_if_fail (GTK_IS_WIDGET (child));
5823   g_return_if_fail (xpos >= 0);
5824   g_return_if_fail (ypos >= 0);
5825   g_return_if_fail (child->parent == NULL);
5826
5827   vc = text_view_child_new_window (child, which_window,
5828                                    xpos, ypos);
5829
5830   add_child (text_view, vc);
5831 }
5832
5833 void
5834 gtk_text_view_move_child          (GtkTextView          *text_view,
5835                                    GtkWidget            *child,
5836                                    gint                  xpos,
5837                                    gint                  ypos)
5838 {
5839   GtkTextViewChild *vc;
5840
5841   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5842   g_return_if_fail (GTK_IS_WIDGET (child));
5843   g_return_if_fail (xpos >= 0);
5844   g_return_if_fail (ypos >= 0);
5845   g_return_if_fail (child->parent == (GtkWidget*) text_view);
5846
5847   vc = g_object_get_data (G_OBJECT (child),
5848                           "gtk-text-view-child");
5849
5850   g_assert (vc != NULL);
5851
5852   vc->x = xpos;
5853   vc->y = ypos;
5854
5855   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
5856     gtk_widget_queue_resize (child);
5857 }
5858
5859
5860
5861 /* Iterator operations */
5862
5863 gboolean
5864 gtk_text_view_forward_display_line (GtkTextView *text_view,
5865                                     GtkTextIter *iter)
5866 {
5867   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5868   g_return_val_if_fail (iter != NULL, FALSE);
5869
5870   gtk_text_view_ensure_layout (text_view);
5871
5872   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
5873 }
5874
5875 gboolean
5876 gtk_text_view_backward_display_line (GtkTextView *text_view,
5877                                      GtkTextIter *iter)
5878 {
5879   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5880   g_return_val_if_fail (iter != NULL, FALSE);
5881
5882   gtk_text_view_ensure_layout (text_view);
5883
5884   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
5885 }
5886
5887 gboolean
5888 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
5889                                         GtkTextIter *iter)
5890 {
5891   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5892   g_return_val_if_fail (iter != NULL, FALSE);
5893
5894   gtk_text_view_ensure_layout (text_view);
5895
5896   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
5897 }
5898
5899 gboolean
5900 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
5901                                            GtkTextIter *iter)
5902 {
5903   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5904   g_return_val_if_fail (iter != NULL, FALSE);
5905
5906   gtk_text_view_ensure_layout (text_view);
5907
5908   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
5909 }
5910
5911 gboolean
5912 gtk_text_view_starts_display_line (GtkTextView       *text_view,
5913                                    const GtkTextIter *iter)
5914 {
5915   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5916   g_return_val_if_fail (iter != NULL, FALSE);
5917
5918   gtk_text_view_ensure_layout (text_view);
5919
5920   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
5921 }
5922
5923 gboolean
5924 gtk_text_view_move_visually (GtkTextView *text_view,
5925                              GtkTextIter *iter,
5926                              gint         count)
5927 {
5928   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5929   g_return_val_if_fail (iter != NULL, FALSE);
5930
5931   gtk_text_view_ensure_layout (text_view);
5932
5933   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
5934 }
5935
5936