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