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