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