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