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