]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
5f8bf2ed64c8b0537826eddfb7fcd6cb92bb1565
[~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                                                      G_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                                                      G_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                                                      G_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                                                          G_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                                                       G_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                                                       G_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                                                      G_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                                                      G_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                                                      G_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                                                        G_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                                                          G_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                                                         G_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                                                          G_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                                                          G_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                                                                G_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 children not in the buffer. */
4268   tmp_list = GTK_TEXT_VIEW (widget)->children;
4269   while (tmp_list != NULL)
4270     {
4271       GtkTextViewChild *vc = tmp_list->data;
4272
4273       /* propagate_expose checks that event->window matches
4274        * child->window
4275        */
4276       if (vc->type != GTK_TEXT_WINDOW_TEXT)
4277         gtk_container_propagate_expose (GTK_CONTAINER (widget),
4278                                         vc->widget,
4279                                         event);
4280       
4281       tmp_list = tmp_list->next;
4282     }
4283   
4284   return FALSE;
4285 }
4286
4287 static void
4288 gtk_text_view_draw_focus (GtkWidget *widget)
4289 {
4290   gboolean interior_focus;
4291
4292   /* We clear the focus if we are in interior focus mode. */
4293   gtk_widget_style_get (widget,
4294                         "interior_focus", &interior_focus,
4295                         NULL);
4296   
4297   if (GTK_WIDGET_DRAWABLE (widget))
4298     {
4299       if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
4300         {          
4301           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
4302                            NULL, widget, "textview",
4303                            0, 0,
4304                            widget->allocation.width,
4305                            widget->allocation.height);
4306         }
4307       else
4308         {
4309           gdk_window_clear (widget->window);
4310         }
4311     }
4312 }
4313
4314 static gboolean
4315 gtk_text_view_focus (GtkWidget        *widget,
4316                      GtkDirectionType  direction)
4317 {
4318   GtkTextView *text_view;
4319   GtkContainer *container;
4320   gboolean result;
4321   
4322   text_view = GTK_TEXT_VIEW (widget);
4323   container = GTK_CONTAINER (widget);  
4324
4325   if (!gtk_widget_is_focus (widget) &&
4326       container->focus_child == NULL)
4327     {
4328       gtk_widget_grab_focus (widget);
4329       return TRUE;
4330     }
4331   else
4332     {
4333       /*
4334        * Unset CAN_FOCUS flag so that gtk_container_focus() allows
4335        * children to get the focus
4336        */
4337       GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS); 
4338       result = GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
4339       GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); 
4340
4341       return result;
4342     }
4343 }
4344
4345 /*
4346  * Container
4347  */
4348
4349 static void
4350 gtk_text_view_add (GtkContainer *container,
4351                    GtkWidget    *child)
4352 {
4353   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4354   g_return_if_fail (GTK_IS_WIDGET (child));
4355
4356   /* This is pretty random. */
4357   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
4358                                      child,
4359                                      GTK_TEXT_WINDOW_WIDGET,
4360                                      0, 0);
4361 }
4362
4363 static void
4364 gtk_text_view_remove (GtkContainer *container,
4365                       GtkWidget    *child)
4366 {
4367   GSList *iter;
4368   GtkTextView *text_view;
4369   GtkTextViewChild *vc;
4370
4371   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4372   g_return_if_fail (GTK_IS_WIDGET (child));
4373   g_return_if_fail (child->parent == (GtkWidget*) container);
4374
4375   text_view = GTK_TEXT_VIEW (container);
4376
4377   vc = NULL;
4378   iter = text_view->children;
4379
4380   while (iter != NULL)
4381     {
4382       vc = iter->data;
4383
4384       if (vc->widget == child)
4385         break;
4386
4387       iter = g_slist_next (iter);
4388     }
4389
4390   g_assert (iter != NULL); /* be sure we had the child in the list */
4391
4392   text_view->children = g_slist_remove (text_view->children, vc);
4393
4394   gtk_widget_unparent (vc->widget);
4395
4396   text_view_child_free (vc);
4397 }
4398
4399 static void
4400 gtk_text_view_forall (GtkContainer *container,
4401                       gboolean      include_internals,
4402                       GtkCallback   callback,
4403                       gpointer      callback_data)
4404 {
4405   GSList *iter;
4406   GtkTextView *text_view;
4407   GSList *copy;
4408
4409   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4410   g_return_if_fail (callback != NULL);
4411
4412   text_view = GTK_TEXT_VIEW (container);
4413
4414   copy = g_slist_copy (text_view->children);
4415   iter = copy;
4416
4417   while (iter != NULL)
4418     {
4419       GtkTextViewChild *vc = iter->data;
4420
4421       (* callback) (vc->widget, callback_data);
4422
4423       iter = g_slist_next (iter);
4424     }
4425
4426   g_slist_free (copy);
4427 }
4428
4429 #define CURSOR_ON_MULTIPLIER 0.66
4430 #define CURSOR_OFF_MULTIPLIER 0.34
4431 #define CURSOR_PEND_MULTIPLIER 1.0
4432
4433 static gboolean
4434 cursor_blinks (GtkTextView *text_view)
4435 {
4436   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4437   gboolean blink;
4438
4439 #ifdef DEBUG_VALIDATION_AND_SCROLLING
4440   return FALSE;
4441 #endif
4442   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
4443     return FALSE;
4444   
4445   g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
4446   return blink;
4447 }
4448
4449 static gint
4450 get_cursor_time (GtkTextView *text_view)
4451 {
4452   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4453   gint time;
4454
4455   g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
4456
4457   return time;
4458 }
4459
4460 /*
4461  * Blink!
4462  */
4463
4464 static gint
4465 blink_cb (gpointer data)
4466 {
4467   GtkTextView *text_view;
4468   gboolean visible;
4469
4470   GDK_THREADS_ENTER ();
4471
4472   text_view = GTK_TEXT_VIEW (data);
4473   
4474   if (!GTK_WIDGET_HAS_FOCUS (text_view))
4475     {
4476       g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
4477                  "connect a handler to this signal, it must return\n"
4478                  "FALSE so the entry gets the event as well");
4479     }
4480
4481   g_assert (text_view->layout);
4482   g_assert (GTK_WIDGET_HAS_FOCUS (text_view));
4483   g_assert (text_view->cursor_visible);
4484
4485   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
4486
4487   if (visible)
4488     text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
4489                                               blink_cb,
4490                                               text_view);
4491   else
4492     text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER,
4493                                               blink_cb,
4494                                               text_view);
4495   
4496   gtk_text_layout_set_cursor_visible (text_view->layout,
4497                                       !visible);
4498
4499   GDK_THREADS_LEAVE ();
4500
4501   /* Remove ourselves */
4502   return FALSE;
4503 }
4504
4505
4506 static void
4507 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
4508 {
4509   if (text_view->blink_timeout)  
4510     { 
4511       g_source_remove (text_view->blink_timeout);
4512       text_view->blink_timeout = 0;
4513     }
4514 }
4515
4516 static void
4517 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
4518 {
4519   if (text_view->layout != NULL &&
4520       text_view->cursor_visible &&
4521       GTK_WIDGET_HAS_FOCUS (text_view))
4522     {
4523       if (cursor_blinks (text_view))
4524         {
4525           if (text_view->blink_timeout == 0)
4526             {
4527               gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4528               
4529               text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
4530                                                         blink_cb,
4531                                                         text_view);
4532             }
4533         }
4534       else
4535         gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);   
4536     }
4537   else
4538     {
4539       gtk_text_view_stop_cursor_blink (text_view);
4540     }
4541 }
4542
4543 static void
4544 gtk_text_view_pend_cursor_blink(GtkTextView *text_view)
4545 {
4546   if (text_view->layout != NULL &&
4547       text_view->cursor_visible &&
4548       GTK_WIDGET_HAS_FOCUS (text_view) &&
4549       cursor_blinks (text_view))
4550     {
4551       if (text_view->blink_timeout != 0)
4552         {
4553           g_source_remove (text_view->blink_timeout);
4554           text_view->blink_timeout = 0;
4555         }
4556       
4557       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4558       
4559       text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER,
4560                                                 blink_cb,
4561                                                 text_view);
4562     }
4563 }
4564
4565
4566 /*
4567  * Key binding handlers
4568  */
4569
4570 static gboolean
4571 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
4572                                   GtkTextIter *newplace,
4573                                   gint         count)
4574 {
4575   gboolean ret = TRUE;
4576
4577   while (count < 0)
4578     {
4579       ret = gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
4580       count++;
4581     }
4582
4583   while (count > 0)
4584     {
4585       ret = gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
4586       count--;
4587     }
4588
4589   return ret;
4590 }
4591
4592 static void
4593 move_cursor (GtkTextView       *text_view,
4594              const GtkTextIter *new_location,
4595              gboolean           extend_selection)
4596 {
4597   if (extend_selection)
4598     gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
4599                                        "insert",
4600                                        new_location);
4601   else
4602     gtk_text_buffer_place_cursor (get_buffer (text_view),
4603                                   new_location);
4604 }
4605
4606 static void
4607 gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
4608                                     GtkMovementStep  step,
4609                                     gint             count,
4610                                     gboolean         extend_selection)
4611 {
4612   GtkTextIter insert;
4613   GtkTextIter newplace;
4614
4615   gint cursor_x_pos = 0;
4616
4617   if (!text_view->cursor_visible) 
4618     {
4619       GtkScrollStep scroll_step;
4620
4621       switch (step) 
4622         {
4623         case GTK_MOVEMENT_LOGICAL_POSITIONS:
4624         case GTK_MOVEMENT_VISUAL_POSITIONS:
4625         case GTK_MOVEMENT_WORDS:
4626           scroll_step = GTK_SCROLL_HORIZONTAL_STEPS;
4627           break;
4628         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4629           scroll_step = GTK_SCROLL_HORIZONTAL_ENDS;
4630           break;          
4631         case GTK_MOVEMENT_DISPLAY_LINES:
4632         case GTK_MOVEMENT_PARAGRAPHS:
4633         case GTK_MOVEMENT_PARAGRAPH_ENDS:
4634           scroll_step = GTK_SCROLL_STEPS;
4635           break;
4636         case GTK_MOVEMENT_PAGES:
4637           scroll_step = GTK_SCROLL_PAGES;
4638           break;
4639         case GTK_MOVEMENT_HORIZONTAL_PAGES:
4640           scroll_step = GTK_SCROLL_HORIZONTAL_PAGES;
4641           break;
4642         case GTK_MOVEMENT_BUFFER_ENDS:
4643           scroll_step = GTK_SCROLL_ENDS;
4644           break;
4645         default:
4646           scroll_step = GTK_SCROLL_PAGES;
4647           break;
4648         }
4649       
4650       gtk_text_view_move_viewport (text_view, scroll_step, count);
4651
4652       return;
4653     }
4654
4655   gtk_text_view_reset_im_context (text_view);
4656
4657   if (step == GTK_MOVEMENT_PAGES)
4658     {
4659       gtk_text_view_scroll_pages (text_view, count, extend_selection);
4660       gtk_text_view_pend_cursor_blink (text_view);
4661       return;
4662     }
4663   else if (step == GTK_MOVEMENT_HORIZONTAL_PAGES)
4664     {
4665       gtk_text_view_scroll_hpages (text_view, count, extend_selection);
4666       gtk_text_view_pend_cursor_blink (text_view);
4667       return;
4668     }
4669
4670   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4671                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4672                                                               "insert"));
4673   newplace = insert;
4674
4675   if (step == GTK_MOVEMENT_DISPLAY_LINES)
4676     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
4677
4678   switch (step)
4679     {
4680     case GTK_MOVEMENT_LOGICAL_POSITIONS:
4681       gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
4682       break;
4683
4684     case GTK_MOVEMENT_VISUAL_POSITIONS:
4685       gtk_text_layout_move_iter_visually (text_view->layout,
4686                                           &newplace, count);
4687       break;
4688
4689     case GTK_MOVEMENT_WORDS:
4690       if (count < 0)
4691         gtk_text_iter_backward_visible_word_starts (&newplace, -count);
4692       else if (count > 0) 
4693         {
4694           if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
4695             gtk_text_iter_forward_to_end (&newplace);
4696         }
4697       break;
4698
4699     case GTK_MOVEMENT_DISPLAY_LINES:
4700       if (count < 0)
4701       {
4702         if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
4703           gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
4704         else
4705           /* we currently do not have a backward_to_start, use offset */
4706           gtk_text_iter_set_offset (&newplace, 0);
4707       }
4708       if (count > 0)
4709       {
4710         if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
4711           gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
4712         else
4713           gtk_text_iter_forward_to_end (&newplace);
4714       }
4715       break;
4716
4717     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4718       if (count > 1)
4719         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
4720       else if (count < -1)
4721         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
4722
4723       if (count != 0)
4724         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
4725       break;
4726
4727     case GTK_MOVEMENT_PARAGRAPHS:
4728       if (count > 0)
4729         {
4730           if (!gtk_text_iter_ends_line (&newplace))
4731             {
4732               gtk_text_iter_forward_to_line_end (&newplace);
4733               --count;
4734             }
4735           gtk_text_iter_forward_lines (&newplace, count);
4736           gtk_text_iter_forward_to_line_end (&newplace);
4737         }
4738       else if (count < 0)
4739         {
4740           if (gtk_text_iter_get_line_offset (&newplace) > 0)
4741             {
4742               gtk_text_iter_set_line_offset (&newplace, 0);
4743               ++count;
4744             }
4745           gtk_text_iter_forward_lines (&newplace, count);
4746           gtk_text_iter_set_line_offset (&newplace, 0);
4747         }
4748       break;
4749
4750     case GTK_MOVEMENT_PARAGRAPH_ENDS:
4751       if (count > 0)
4752         {
4753           if (!gtk_text_iter_ends_line (&newplace))
4754             gtk_text_iter_forward_to_line_end (&newplace);
4755         }
4756       else if (count < 0)
4757         {
4758           gtk_text_iter_set_line_offset (&newplace, 0);
4759         }
4760       break;
4761
4762     case GTK_MOVEMENT_BUFFER_ENDS:
4763       if (count > 0)
4764         gtk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
4765       else if (count < 0)
4766         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
4767      break;
4768       
4769     default:
4770       break;
4771     }
4772
4773   /* call move_cursor() even if the cursor hasn't moved, since it 
4774      cancels the selection
4775   */
4776   move_cursor (text_view, &newplace, extend_selection);
4777
4778   if (!gtk_text_iter_equal (&insert, &newplace))
4779     {
4780       DV(g_print (G_STRLOC": scrolling onscreen\n"));
4781       gtk_text_view_scroll_mark_onscreen (text_view,
4782                                           gtk_text_buffer_get_mark (get_buffer (text_view),
4783                                                                     "insert"));
4784
4785       if (step == GTK_MOVEMENT_DISPLAY_LINES)
4786         {
4787           gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
4788         }
4789     }
4790
4791   gtk_text_view_pend_cursor_blink (text_view);
4792 }
4793
4794 static void
4795 gtk_text_view_move_cursor (GtkTextView     *text_view,
4796                            GtkMovementStep  step,
4797                            gint             count,
4798                            gboolean         extend_selection)
4799 {
4800   gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
4801 }
4802
4803 static void
4804 gtk_text_view_page_horizontally (GtkTextView     *text_view,
4805                                  gint             count,
4806                                  gboolean         extend_selection)
4807 {
4808   gtk_text_view_move_cursor_internal (text_view, GTK_MOVEMENT_HORIZONTAL_PAGES,
4809                                       count, extend_selection);
4810 }
4811
4812
4813 static void
4814 gtk_text_view_move_viewport (GtkTextView     *text_view,
4815                              GtkScrollStep    step,
4816                              gint             count)
4817 {
4818   GtkAdjustment *adjustment;
4819   gdouble increment;
4820   
4821   switch (step) 
4822     {
4823     case GTK_SCROLL_STEPS:
4824     case GTK_SCROLL_PAGES:
4825     case GTK_SCROLL_ENDS:
4826       adjustment = get_vadjustment (text_view);
4827       break;
4828     case GTK_SCROLL_HORIZONTAL_STEPS:
4829     case GTK_SCROLL_HORIZONTAL_PAGES:
4830     case GTK_SCROLL_HORIZONTAL_ENDS:
4831       adjustment = get_hadjustment (text_view);
4832       break;
4833     default:
4834       adjustment = get_vadjustment (text_view);
4835       break;
4836     }
4837
4838   switch (step) 
4839     {
4840     case GTK_SCROLL_STEPS:
4841     case GTK_SCROLL_HORIZONTAL_STEPS:
4842       increment = adjustment->step_increment;
4843       break;
4844     case GTK_SCROLL_PAGES:
4845     case GTK_SCROLL_HORIZONTAL_PAGES:
4846       increment = adjustment->page_increment;
4847       break;
4848     case GTK_SCROLL_ENDS:
4849     case GTK_SCROLL_HORIZONTAL_ENDS:
4850       increment = adjustment->upper - adjustment->lower;
4851       break;
4852     default:
4853       increment = 0.0;
4854       break;
4855     }
4856
4857   set_adjustment_clamped (adjustment, adjustment->value + count * increment);
4858 }
4859
4860 static void
4861 gtk_text_view_set_anchor (GtkTextView *text_view)
4862 {
4863   GtkTextIter insert;
4864
4865   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4866                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4867                                                               "insert"));
4868
4869   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
4870 }
4871
4872 static void
4873 gtk_text_view_scroll_pages (GtkTextView *text_view,
4874                             gint         count,
4875                             gboolean     extend_selection)
4876 {
4877   gdouble newval;
4878   gdouble oldval;
4879   GtkAdjustment *adj;
4880   gint cursor_x_pos, cursor_y_pos;
4881   GtkTextIter new_insert;
4882   GtkTextIter anchor;
4883   gint y0, y1;
4884
4885   g_return_if_fail (text_view->vadjustment != NULL);
4886   
4887   adj = text_view->vadjustment;
4888
4889   /* Make sure we start from the current cursor position, even
4890    * if it was offscreen, but don't queue more scrolls if we're
4891    * already behind.
4892    */
4893   if (text_view->pending_scroll)
4894     cancel_pending_scroll (text_view);
4895   else
4896     gtk_text_view_scroll_mark_onscreen (text_view,
4897                                         gtk_text_buffer_get_mark (get_buffer (text_view),
4898                                                                   "insert"));
4899   
4900 /* Validate the region that will be brought into view by the cursor motion
4901    */
4902   if (count < 0)
4903     {
4904       gtk_text_view_get_first_para_iter (text_view, &anchor);
4905       y0 = adj->page_size;
4906       y1 = adj->page_size + count * adj->page_increment;
4907     }
4908   else
4909     {
4910       gtk_text_view_get_first_para_iter (text_view, &anchor);
4911       y0 = count * adj->page_increment + adj->page_size;
4912       y1 = 0;
4913     }
4914
4915   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
4916   /* FIXME do we need to update the adjustment ranges here? */
4917
4918   if (count < 0 && adj->value <= (adj->lower + 1e-12))
4919     {
4920       /* already at top, just be sure we are at offset 0 */
4921       gtk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
4922       move_cursor (text_view, &new_insert, extend_selection);
4923     }
4924   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
4925     {
4926       /* already at bottom, just be sure we are at the end */
4927       gtk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
4928       move_cursor (text_view, &new_insert, extend_selection);
4929     }
4930   else
4931     {
4932       gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
4933
4934       newval = adj->value;
4935       oldval = adj->value;
4936   
4937       newval += count * adj->page_increment;
4938
4939       set_adjustment_clamped (adj, newval);
4940       cursor_y_pos += adj->value - oldval;
4941
4942       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
4943       clamp_iter_onscreen (text_view, &new_insert);
4944       move_cursor (text_view, &new_insert, extend_selection);
4945
4946       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
4947     }
4948   
4949   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
4950    * only guarantees 1 pixel onscreen.
4951    */
4952   DV(g_print (G_STRLOC": scrolling onscreen\n"));
4953   gtk_text_view_scroll_mark_onscreen (text_view,
4954                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4955                                                                 "insert"));
4956 }
4957
4958 static void
4959 gtk_text_view_scroll_hpages (GtkTextView *text_view,
4960                              gint         count,
4961                              gboolean     extend_selection)
4962 {
4963   gdouble newval;
4964   gdouble oldval;
4965   GtkAdjustment *adj;
4966   gint cursor_x_pos, cursor_y_pos;
4967   GtkTextIter new_insert;
4968   gint y, height;
4969   
4970   g_return_if_fail (text_view->hadjustment != NULL);
4971
4972   adj = text_view->hadjustment;
4973
4974   /* Make sure we start from the current cursor position, even
4975    * if it was offscreen, but don't queue more scrolls if we're
4976    * already behind.
4977    */
4978   if (text_view->pending_scroll)
4979     cancel_pending_scroll (text_view);
4980   else
4981     gtk_text_view_scroll_mark_onscreen (text_view,
4982                                         gtk_text_buffer_get_mark (get_buffer (text_view),
4983                                                                   "insert"));
4984   
4985   /* Validate the line that we're moving within.
4986    */
4987   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
4988                                     &new_insert,
4989                                     gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
4990   gtk_text_layout_get_line_yrange (text_view->layout, &new_insert, &y, &height);
4991   gtk_text_layout_validate_yrange (text_view->layout, &new_insert, y, y + height);
4992   /* FIXME do we need to update the adjustment ranges here? */
4993   
4994   if (count < 0 && adj->value <= (adj->lower + 1e-12))
4995     {
4996       /* already at far left, just be sure we are at offset 0 */
4997       gtk_text_iter_set_line_offset (&new_insert, 0);
4998       move_cursor (text_view, &new_insert, extend_selection);
4999     }
5000   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5001     {
5002       /* already at far right, just be sure we are at the end */
5003       gtk_text_iter_forward_to_line_end (&new_insert);
5004       move_cursor (text_view, &new_insert, extend_selection);
5005     }
5006   else
5007     {
5008       gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
5009
5010       newval = adj->value;
5011       oldval = adj->value;
5012   
5013       newval += count * adj->page_increment;
5014
5015       set_adjustment_clamped (adj, newval);
5016       cursor_x_pos += adj->value - oldval;
5017
5018       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5019       clamp_iter_onscreen (text_view, &new_insert);
5020       move_cursor (text_view, &new_insert, extend_selection);
5021
5022       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5023     }
5024
5025   /*  FIXME for lines shorter than the overall widget width, this results in a
5026    *  "bounce" effect as we scroll to the right of the widget, then scroll
5027    *  back to get the end of the line onscreen.
5028    *      http://bugzilla.gnome.org/show_bug.cgi?id=68963
5029    */
5030   
5031   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5032    * only guarantees 1 pixel onscreen.
5033    */
5034   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5035   gtk_text_view_scroll_mark_onscreen (text_view,
5036                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5037                                                                 "insert"));
5038 }
5039
5040 static gboolean
5041 whitespace (gunichar ch, gpointer user_data)
5042 {
5043   return (ch == ' ' || ch == '\t');
5044 }
5045
5046 static gboolean
5047 not_whitespace (gunichar ch, gpointer user_data)
5048 {
5049   return !whitespace (ch, user_data);
5050 }
5051
5052 static gboolean
5053 find_whitepace_region (const GtkTextIter *center,
5054                        GtkTextIter *start, GtkTextIter *end)
5055 {
5056   *start = *center;
5057   *end = *center;
5058
5059   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
5060     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
5061   if (whitespace (gtk_text_iter_get_char (end), NULL))
5062     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
5063
5064   return !gtk_text_iter_equal (start, end);
5065 }
5066
5067 static void
5068 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
5069                                 const gchar *str)
5070 {
5071   gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
5072                                                 text_view->editable);
5073 }
5074
5075 static void
5076 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
5077                                   GtkDeleteType  type,
5078                                   gint           count)
5079 {
5080   GtkTextIter insert;
5081   GtkTextIter start;
5082   GtkTextIter end;
5083   gboolean leave_one = FALSE;
5084
5085   gtk_text_view_reset_im_context (text_view);
5086
5087   if (type == GTK_DELETE_CHARS)
5088     {
5089       /* Char delete deletes the selection, if one exists */
5090       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5091                                             text_view->editable))
5092         return;
5093     }
5094
5095   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5096                                     &insert,
5097                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5098                                                               "insert"));
5099
5100   start = insert;
5101   end = insert;
5102
5103   switch (type)
5104     {
5105     case GTK_DELETE_CHARS:
5106       gtk_text_iter_forward_cursor_positions (&end, count);
5107       break;
5108
5109     case GTK_DELETE_WORD_ENDS:
5110       if (count > 0)
5111         gtk_text_iter_forward_word_ends (&end, count);
5112       else if (count < 0)
5113         gtk_text_iter_backward_word_starts (&start, 0 - count);
5114       break;
5115
5116     case GTK_DELETE_WORDS:
5117       break;
5118
5119     case GTK_DELETE_DISPLAY_LINE_ENDS:
5120       break;
5121
5122     case GTK_DELETE_DISPLAY_LINES:
5123       break;
5124
5125     case GTK_DELETE_PARAGRAPH_ENDS:
5126       /* If we're already at a newline, we need to
5127        * simply delete that newline, instead of
5128        * moving to the next one.
5129        */
5130       if (gtk_text_iter_ends_line (&end))
5131         {
5132           gtk_text_iter_forward_line (&end);
5133           --count;
5134         }
5135
5136       while (count > 0)
5137         {
5138           if (!gtk_text_iter_forward_to_line_end (&end))
5139             break;
5140
5141           --count;
5142         }
5143
5144       /* FIXME figure out what a negative count means
5145          and support that */
5146       break;
5147
5148     case GTK_DELETE_PARAGRAPHS:
5149       if (count > 0)
5150         {
5151           gtk_text_iter_set_line_offset (&start, 0);
5152           gtk_text_iter_forward_to_line_end (&end);
5153
5154           /* Do the lines beyond the first. */
5155           while (count > 1)
5156             {
5157               gtk_text_iter_forward_to_line_end (&end);
5158
5159               --count;
5160             }
5161         }
5162
5163       /* FIXME negative count? */
5164
5165       break;
5166
5167     case GTK_DELETE_WHITESPACE:
5168       {
5169         find_whitepace_region (&insert, &start, &end);
5170       }
5171       break;
5172
5173     default:
5174       break;
5175     }
5176
5177   if (!gtk_text_iter_equal (&start, &end))
5178     {
5179       gtk_text_buffer_begin_user_action (get_buffer (text_view));
5180
5181       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
5182                                               text_view->editable))
5183         {
5184           if (leave_one)
5185             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
5186                                                           " ", 1,
5187                                                           text_view->editable);
5188         }
5189
5190       gtk_text_buffer_end_user_action (get_buffer (text_view));
5191
5192       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5193       gtk_text_view_scroll_mark_onscreen (text_view,
5194                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
5195     }
5196 }
5197
5198 static void
5199 gtk_text_view_backspace (GtkTextView *text_view)
5200 {
5201   GtkTextIter insert;
5202
5203   gtk_text_view_reset_im_context (text_view);
5204
5205   /* Backspace deletes the selection, if one exists */
5206   if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5207                                         text_view->editable))
5208     return;
5209
5210   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5211                                     &insert,
5212                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5213                                                               "insert"));
5214
5215   if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
5216                                  TRUE, text_view->editable))
5217     {
5218       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5219       gtk_text_view_scroll_mark_onscreen (text_view,
5220                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
5221     }
5222 }
5223
5224 static void
5225 gtk_text_view_cut_clipboard (GtkTextView *text_view)
5226 {
5227   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5228                                                       GDK_SELECTION_CLIPBOARD);
5229   
5230   gtk_text_buffer_cut_clipboard (get_buffer (text_view),
5231                                  clipboard,
5232                                  text_view->editable);
5233   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5234   gtk_text_view_scroll_mark_onscreen (text_view,
5235                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5236                                                                 "insert"));
5237 }
5238
5239 static void
5240 gtk_text_view_copy_clipboard (GtkTextView *text_view)
5241 {
5242   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5243                                                       GDK_SELECTION_CLIPBOARD);
5244   
5245   gtk_text_buffer_copy_clipboard (get_buffer (text_view),
5246                                   clipboard);
5247   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5248   gtk_text_view_scroll_mark_onscreen (text_view,
5249                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5250                                                                 "insert"));
5251 }
5252
5253 static void
5254 gtk_text_view_paste_clipboard (GtkTextView *text_view)
5255 {
5256   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5257                                                       GDK_SELECTION_CLIPBOARD);
5258   
5259   gtk_text_buffer_paste_clipboard (get_buffer (text_view),
5260                                    clipboard,
5261                                    NULL,
5262                                    text_view->editable);
5263   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5264   gtk_text_view_scroll_mark_onscreen (text_view,
5265                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5266                                                                 "insert"));
5267 }
5268
5269 static void
5270 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
5271 {
5272   text_view->overwrite_mode = !text_view->overwrite_mode;
5273   g_object_notify (G_OBJECT (text_view), "overwrite");
5274 }
5275
5276 /**
5277  * gtk_text_view_get_overwrite:
5278  * @text_view: a #GtkTextView
5279  *
5280  * Returns whether the #GtkTextView is in overwrite mode or not.
5281  *
5282  * Return value: whether @text_view is in overwrite mode or not.
5283  * 
5284  * Since: 2.4
5285  **/
5286 gboolean
5287 gtk_text_view_get_overwrite (GtkTextView *text_view)
5288 {
5289   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5290
5291   return text_view->overwrite_mode;
5292 }
5293
5294 /**
5295  * gtk_text_view_set_overwrite:
5296  * @text_view: a #GtkTextView
5297  * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
5298  *
5299  * Changes the #GtkTextView overwrite mode.
5300  *
5301  * Since: 2.4
5302  **/
5303 void
5304 gtk_text_view_set_overwrite (GtkTextView *text_view,
5305                              gboolean     overwrite)
5306 {
5307   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5308   overwrite = overwrite != FALSE;
5309
5310   if (text_view->overwrite_mode != overwrite)
5311     {
5312       text_view->overwrite_mode = overwrite;
5313
5314       g_object_notify (G_OBJECT (text_view), "overwrite");
5315     }
5316 }
5317
5318 /**
5319  * gtk_text_view_set_accepts_tab:
5320  * @text_view: A #GtkTextView
5321  * @accepts_tab: %TRUE if pressing the Tab key should insert a tab character, %FALSE, if pressing the Tab key should move the keyboard focus.
5322  * 
5323  * Sets the behavior of the text widget when the Tab key is pressed. If @accepts_tab
5324  * is %TRUE a tab character is inserted. If @accepts_tab is %FALSE the keyboard focus
5325  * is moved to the next widget in the focus chain.
5326  * 
5327  * Since: 2.4
5328  **/
5329 void
5330 gtk_text_view_set_accepts_tab (GtkTextView *text_view,
5331                                gboolean     accepts_tab)
5332 {
5333   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5334
5335   accepts_tab = accepts_tab != FALSE;
5336
5337   if (text_view->accepts_tab != accepts_tab)
5338     {
5339       text_view->accepts_tab = accepts_tab;
5340
5341       g_object_notify (G_OBJECT (text_view), "accepts_tab");
5342     }
5343 }
5344
5345 /**
5346  * gtk_text_view_get_accepts_tab:
5347  * @text_view: A #GtkTextView
5348  * 
5349  * Returns whether pressing the Tab key inserts a tab characters.
5350  * gtk_text_view_set_accepts_tab().
5351  * 
5352  * Return value: %TRUE if pressing the Tab key inserts a tab character, %FALSE if pressing the Tab key moves the keyboard focus.
5353  * 
5354  * Since: 2.4
5355  **/
5356 gboolean
5357 gtk_text_view_get_accepts_tab (GtkTextView *text_view)
5358 {
5359   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5360
5361   return text_view->accepts_tab;
5362 }
5363
5364 static void
5365 gtk_text_view_move_focus (GtkTextView     *text_view,
5366                           GtkDirectionType direction_type)
5367 {
5368   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (text_view));
5369
5370   if (!GTK_WIDGET_TOPLEVEL (toplevel))
5371     return;
5372
5373   /* Propagate to toplevel */
5374   g_signal_emit_by_name (toplevel, "move_focus", direction_type);
5375 }
5376
5377 /*
5378  * Selections
5379  */
5380
5381 static void
5382 gtk_text_view_unselect (GtkTextView *text_view)
5383 {
5384   GtkTextIter insert;
5385
5386   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5387                                     &insert,
5388                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5389                                                               "insert"));
5390
5391   gtk_text_buffer_move_mark (get_buffer (text_view),
5392                              gtk_text_buffer_get_mark (get_buffer (text_view),
5393                                                        "selection_bound"),
5394                              &insert);
5395 }
5396
5397 static void
5398 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
5399                                  const gchar *mark_name)
5400 {
5401   gint x, y;
5402   GdkModifierType state;
5403   GtkTextIter newplace;
5404
5405   /*   DV(g_print (G_STRLOC": begin\n")); */
5406   
5407   gdk_window_get_pointer (text_view->text_window->bin_window,
5408                           &x, &y, &state);
5409
5410   /*   DV(g_print (G_STRLOC": get iter at pixel\n"); */
5411   gtk_text_layout_get_iter_at_pixel (text_view->layout,
5412                                      &newplace,
5413                                      x + text_view->xoffset,
5414                                      y + text_view->yoffset);
5415
5416   {
5417     GtkTextMark *mark =
5418       gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
5419
5420     /* This may invalidate the layout */
5421     DV(g_print (G_STRLOC": move mark\n"));
5422     gtk_text_buffer_move_mark (get_buffer (text_view),
5423                                mark,
5424                                &newplace);
5425
5426     DV(g_print (G_STRLOC": scrolling onscreen\n"));
5427     gtk_text_view_scroll_mark_onscreen (text_view, mark);
5428   }
5429
5430   DV (g_print ("first validate idle leaving %s is %d\n",
5431                G_STRLOC, text_view->first_validate_idle));
5432 }
5433
5434 static gint
5435 selection_scan_timeout (gpointer data)
5436 {
5437   GtkTextView *text_view;
5438
5439   GDK_THREADS_ENTER ();
5440   
5441   text_view = GTK_TEXT_VIEW (data);
5442
5443   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
5444   gtk_text_view_scroll_mark_onscreen (text_view, 
5445                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5446                                                                 "insert"));
5447
5448   GDK_THREADS_LEAVE ();
5449   
5450   return TRUE; /* remain installed. */
5451 }
5452
5453 #define DND_SCROLL_MARGIN 0.20
5454
5455 static gint
5456 drag_scan_timeout (gpointer data)
5457 {
5458   GtkTextView *text_view;
5459   gint x, y;
5460   GdkModifierType state;
5461   GtkTextIter newplace;
5462
5463   GDK_THREADS_ENTER ();
5464   
5465   text_view = GTK_TEXT_VIEW (data);
5466
5467   gdk_window_get_pointer (text_view->text_window->bin_window,
5468                           &x, &y, &state);
5469   
5470   gtk_text_layout_get_iter_at_pixel (text_view->layout,
5471                                      &newplace,
5472                                      x + text_view->xoffset,
5473                                      y + text_view->yoffset);
5474   
5475   gtk_text_buffer_move_mark (get_buffer (text_view),
5476                              text_view->dnd_mark,
5477                              &newplace);
5478
5479   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5480   gtk_text_view_scroll_to_mark (text_view,
5481                                 text_view->dnd_mark,
5482                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
5483
5484   GDK_THREADS_LEAVE ();
5485   
5486   return TRUE;
5487 }
5488
5489 typedef enum 
5490 {
5491   SELECT_CHARACTERS,
5492   SELECT_WORDS,
5493   SELECT_LINES
5494 } SelectionGranularity;
5495
5496 /*
5497  * Move @start and @end to the boundaries of the selection unit (indicated by 
5498  * @granularity) which contained @start initially. Return wether @start was
5499  * contained in a selection unit at all (which may not be the case for words).
5500  */
5501 static gboolean 
5502 extend_selection (GtkTextView *text_view, 
5503                   SelectionGranularity granularity, 
5504                   GtkTextIter *start, 
5505                   GtkTextIter *end)
5506 {
5507   gboolean extend = TRUE;
5508
5509   *end = *start;
5510
5511   if (granularity == SELECT_WORDS) 
5512     {
5513       if (gtk_text_iter_inside_word (start))
5514         {
5515           if (!gtk_text_iter_starts_word (start))
5516             gtk_text_iter_backward_visible_word_start (start);
5517           
5518           if (!gtk_text_iter_ends_word (end))
5519             {
5520               if (!gtk_text_iter_forward_visible_word_end (end))
5521                 gtk_text_iter_forward_to_end (end);
5522             }
5523         }
5524       else
5525         extend = FALSE;
5526     }
5527   else if (granularity == SELECT_LINES) 
5528     {
5529       if (gtk_text_view_starts_display_line (text_view, start))
5530         {
5531           /* If on a display line boundary, we assume the user
5532            * clicked off the end of a line and we therefore select
5533            * the line before the boundary.
5534            */
5535           gtk_text_view_backward_display_line_start (text_view, start);
5536         }
5537       else
5538         {
5539           /* start isn't on the start of a line, so we move it to the
5540            * start, and move end to the end unless it's already there.
5541            */
5542           gtk_text_view_backward_display_line_start (text_view, start);
5543           
5544           if (!gtk_text_view_starts_display_line (text_view, end))
5545             gtk_text_view_forward_display_line_end (text_view, end);
5546         }
5547     }
5548   
5549   return extend;
5550 }
5551  
5552 static gint
5553 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
5554 {
5555   SelectionGranularity granularity = GPOINTER_TO_INT (data);
5556
5557   if (granularity == SELECT_CHARACTERS) 
5558     {
5559       move_mark_to_pointer_and_scroll (text_view, "insert");
5560     }
5561   else 
5562     {
5563       gint x, y;
5564       GdkModifierType state;
5565       GtkTextIter start, end;
5566       GtkTextIter old_start, old_end;    
5567       GtkTextIter ins, bound;    
5568       GtkTextBuffer *buffer;
5569       
5570       buffer = get_buffer (text_view);
5571
5572       gdk_window_get_pointer (text_view->text_window->bin_window,
5573                               &x, &y, &state);
5574       
5575       gtk_text_layout_get_iter_at_pixel (text_view->layout,
5576                                          &start,
5577                                          event->x + text_view->xoffset,
5578                                          event->y + text_view->yoffset); 
5579       
5580       if (extend_selection (text_view, granularity, &start, &end)) 
5581         {
5582           /* Extend selection */
5583           gtk_text_buffer_get_iter_at_mark (buffer, 
5584                                             &ins, 
5585                                             gtk_text_buffer_get_insert (buffer));
5586           gtk_text_buffer_get_iter_at_mark (buffer, 
5587                                             &bound,
5588                                             gtk_text_buffer_get_selection_bound (buffer));
5589
5590           if (gtk_text_iter_compare (&ins, &bound) < 0) 
5591             {
5592               old_start = ins;
5593               old_end = bound;
5594             }
5595           else
5596             {
5597               old_start = bound;
5598               old_end = ins;
5599             }
5600
5601           if (gtk_text_iter_compare (&start, &old_start) < 0) 
5602             {
5603               /* newly selected unit before the current selection */
5604               ins = start;
5605               bound = old_end;
5606             }
5607           else if (gtk_text_iter_compare (&old_end, &end) < 0)
5608             {
5609               /* newly selected unit after the current selection */
5610               ins = end;
5611               bound = old_start;
5612             }
5613           else if (gtk_text_iter_equal (&ins, &old_start)) 
5614             {
5615               /* newly selected unit inside the current selection 
5616                  at the start */
5617               if (!gtk_text_iter_equal (&ins, &start)) 
5618                 ins = end;
5619             }
5620           else
5621             {
5622               /* newly selected unit inside the current selection 
5623                  at the end */
5624               if (!gtk_text_iter_equal (&ins, &end)) 
5625                   ins = start;
5626             }
5627
5628           gtk_text_buffer_select_range (buffer, &ins, &bound);
5629         }
5630
5631       gtk_text_view_scroll_mark_onscreen (text_view, 
5632                                           gtk_text_buffer_get_mark (buffer,
5633                                                                     "insert"));
5634     }
5635
5636   
5637   /* If we had to scroll offscreen, insert a timeout to do so
5638    * again. Note that in the timeout, even if the mouse doesn't
5639    * move, due to this scroll xoffset/yoffset will have changed
5640    * and we'll need to scroll again.
5641    */
5642   if (text_view->scroll_timeout != 0) /* reset on every motion event */
5643     g_source_remove (text_view->scroll_timeout);
5644   
5645   text_view->scroll_timeout =
5646     g_timeout_add (50, selection_scan_timeout, text_view);
5647
5648   return TRUE;
5649 }
5650
5651 static void
5652 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
5653                                     const GtkTextIter *iter,
5654                                     GdkEventButton    *button)
5655 {
5656   GtkTextIter start, end;
5657   GtkTextBuffer *buffer;
5658   SelectionGranularity granularity;
5659
5660   g_return_if_fail (text_view->selection_drag_handler == 0);
5661
5662   if (button->type == GDK_2BUTTON_PRESS)
5663     granularity = SELECT_WORDS;
5664   else if (button->type == GDK_3BUTTON_PRESS)
5665     granularity = SELECT_LINES;
5666   else 
5667     granularity = SELECT_CHARACTERS;
5668
5669   gtk_grab_add (GTK_WIDGET (text_view));
5670
5671   buffer = get_buffer (text_view);
5672   
5673   start = *iter;
5674   
5675   extend_selection (text_view, granularity, &start, &end);
5676
5677   if (button->state & GDK_SHIFT_MASK)
5678     {
5679       /* Extend selection */
5680       GtkTextIter old_start, old_end;
5681
5682       gtk_text_buffer_get_selection_bounds (buffer, &old_start, &old_end);
5683       
5684       gtk_text_iter_order (&start, &old_start);
5685       gtk_text_iter_order (&old_end, &end);
5686       
5687       /* Now start is the first of the starts, and end is the
5688        * last of the ends
5689        */
5690     }
5691
5692   gtk_text_buffer_select_range (buffer, &end, &start);
5693
5694   text_view->selection_drag_handler = g_signal_connect (text_view,
5695                                                         "motion_notify_event",
5696                                                         G_CALLBACK (selection_motion_event_handler),
5697                                                         GINT_TO_POINTER (granularity));
5698 }
5699
5700 /* returns whether we were really dragging */
5701 static gboolean
5702 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
5703 {
5704   if (text_view->selection_drag_handler == 0)
5705     return FALSE;
5706
5707   g_signal_handler_disconnect (text_view, text_view->selection_drag_handler);
5708   text_view->selection_drag_handler = 0;
5709
5710   if (text_view->scroll_timeout != 0)
5711     {
5712       g_source_remove (text_view->scroll_timeout);
5713       text_view->scroll_timeout = 0;
5714     }
5715
5716   gtk_grab_remove (GTK_WIDGET (text_view));
5717
5718   return TRUE;
5719 }
5720
5721 /*
5722  * Layout utils
5723  */
5724
5725 static void
5726 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
5727                                          GtkTextAttributes  *values,
5728                                          GtkStyle           *style)
5729 {
5730   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
5731   values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
5732
5733   if (values->font)
5734     pango_font_description_free (values->font);
5735
5736   values->font = pango_font_description_copy (style->font_desc);
5737 }
5738
5739 static void
5740 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
5741 {
5742   if (text_view->layout)
5743     {
5744       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
5745       GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
5746       GtkTextDirection new_cursor_dir;
5747       GtkTextDirection new_keyboard_dir;
5748       gboolean split_cursor;
5749
5750       g_object_get (settings,
5751                     "gtk-split-cursor", &split_cursor,
5752                     NULL);
5753       
5754       if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
5755         new_keyboard_dir = GTK_TEXT_DIR_RTL;
5756       else
5757         new_keyboard_dir  = GTK_TEXT_DIR_LTR;
5758   
5759       if (split_cursor)
5760         new_cursor_dir = GTK_TEXT_DIR_NONE;
5761       else
5762         new_cursor_dir = new_keyboard_dir;
5763       
5764       gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
5765       gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
5766     }
5767 }
5768
5769 static void
5770 gtk_text_view_ensure_layout (GtkTextView *text_view)
5771 {
5772   GtkWidget *widget;
5773
5774   widget = GTK_WIDGET (text_view);
5775
5776   if (text_view->layout == NULL)
5777     {
5778       GtkTextAttributes *style;
5779       PangoContext *ltr_context, *rtl_context;
5780       GSList *tmp_list;
5781
5782       DV(g_print(G_STRLOC"\n"));
5783       
5784       text_view->layout = gtk_text_layout_new ();
5785
5786       g_signal_connect (text_view->layout,
5787                         "invalidated",
5788                         G_CALLBACK (invalidated_handler),
5789                         text_view);
5790
5791       g_signal_connect (text_view->layout,
5792                         "changed",
5793                         G_CALLBACK (changed_handler),
5794                         text_view);
5795
5796       g_signal_connect (text_view->layout,
5797                         "allocate_child",
5798                         G_CALLBACK (gtk_text_view_child_allocated),
5799                         text_view);
5800       
5801       if (get_buffer (text_view))
5802         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
5803
5804       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
5805         gtk_text_view_pend_cursor_blink (text_view);
5806       else
5807         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
5808
5809       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
5810       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
5811       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
5812       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
5813
5814       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
5815
5816       g_object_unref (ltr_context);
5817       g_object_unref (rtl_context);
5818
5819       gtk_text_view_check_keymap_direction (text_view);
5820
5821       style = gtk_text_attributes_new ();
5822
5823       gtk_widget_ensure_style (widget);
5824       gtk_text_view_set_attributes_from_style (text_view,
5825                                                style, widget->style);
5826
5827       style->pixels_above_lines = text_view->pixels_above_lines;
5828       style->pixels_below_lines = text_view->pixels_below_lines;
5829       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
5830       style->left_margin = text_view->left_margin;
5831       style->right_margin = text_view->right_margin;
5832       style->indent = text_view->indent;
5833       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
5834
5835       style->wrap_mode = text_view->wrap_mode;
5836       style->justification = text_view->justify;
5837       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
5838
5839       gtk_text_layout_set_default_style (text_view->layout, style);
5840
5841       gtk_text_attributes_unref (style);
5842
5843       /* Set layout for all anchored children */
5844
5845       tmp_list = text_view->children;
5846       while (tmp_list != NULL)
5847         {
5848           GtkTextViewChild *vc = tmp_list->data;
5849
5850           if (vc->anchor)
5851             {
5852               gtk_text_anchored_child_set_layout (vc->widget,
5853                                                   text_view->layout);
5854               /* vc may now be invalid! */
5855             }
5856
5857           tmp_list = g_slist_next (tmp_list);
5858         }
5859
5860       gtk_text_view_invalidate (text_view);
5861     }
5862 }
5863
5864 /**
5865  * gtk_text_view_get_default_attributes:
5866  * @text_view: a #GtkTextView
5867  * 
5868  * Obtains a copy of the default text attributes. These are the
5869  * attributes used for text unless a tag overrides them.
5870  * You'd typically pass the default attributes in to
5871  * gtk_text_iter_get_attributes() in order to get the
5872  * attributes in effect at a given text position.
5873  *
5874  * The return value is a copy owned by the caller of this function,
5875  * and should be freed.
5876  * 
5877  * Return value: a new #GtkTextAttributes
5878  **/
5879 GtkTextAttributes*
5880 gtk_text_view_get_default_attributes (GtkTextView *text_view)
5881 {
5882   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
5883   
5884   gtk_text_view_ensure_layout (text_view);
5885
5886   return gtk_text_attributes_copy (text_view->layout->default_style);
5887 }
5888
5889 static void
5890 gtk_text_view_destroy_layout (GtkTextView *text_view)
5891 {
5892   if (text_view->layout)
5893     {
5894       GSList *tmp_list;
5895
5896       gtk_text_view_remove_validate_idles (text_view);
5897
5898       g_signal_handlers_disconnect_by_func (text_view->layout,
5899                                             invalidated_handler,
5900                                             text_view);
5901       g_signal_handlers_disconnect_by_func (text_view->layout,
5902                                             changed_handler, 
5903                                             text_view);
5904       
5905       /* Remove layout from all anchored children */
5906       tmp_list = text_view->children;
5907       while (tmp_list != NULL)
5908         {
5909           GtkTextViewChild *vc = tmp_list->data;
5910
5911           if (vc->anchor)
5912             {
5913               gtk_text_anchored_child_set_layout (vc->widget, NULL);
5914               /* vc may now be invalid! */
5915             }
5916
5917           tmp_list = g_slist_next (tmp_list);
5918         }
5919       
5920       gtk_text_view_stop_cursor_blink (text_view);
5921       gtk_text_view_end_selection_drag (text_view, NULL);
5922
5923       g_object_unref (text_view->layout);
5924       text_view->layout = NULL;
5925     }
5926 }
5927
5928 static void
5929 gtk_text_view_reset_im_context (GtkTextView *text_view)
5930 {
5931   if (text_view->need_im_reset)
5932     {
5933       text_view->need_im_reset = FALSE;
5934       gtk_im_context_reset (text_view->im_context);
5935     }
5936 }
5937
5938 /*
5939  * DND feature
5940  */
5941
5942 static void
5943 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
5944                                    const GtkTextIter *iter,
5945                                    GdkEventMotion    *event)
5946 {
5947   GdkDragContext *context;
5948   GtkTargetList *target_list;
5949
5950   text_view->drag_start_x = -1;
5951   text_view->drag_start_y = -1;
5952   text_view->pending_place_cursor_button = 0;
5953   
5954   target_list = gtk_target_list_new (target_table,
5955                                      G_N_ELEMENTS (target_table));
5956   gtk_target_list_add_text_targets (target_list, 0);
5957
5958   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
5959                             GDK_ACTION_COPY | GDK_ACTION_MOVE,
5960                             1, (GdkEvent*)event);
5961
5962   gtk_target_list_unref (target_list);
5963
5964   gtk_drag_set_icon_default (context);
5965 }
5966
5967 static void
5968 gtk_text_view_drag_begin (GtkWidget        *widget,
5969                           GdkDragContext   *context)
5970 {
5971   /* do nothing */
5972 }
5973
5974 static void
5975 gtk_text_view_drag_end (GtkWidget        *widget,
5976                         GdkDragContext   *context)
5977 {
5978   GtkTextView *text_view;
5979
5980   text_view = GTK_TEXT_VIEW (widget);
5981 }
5982
5983 static void
5984 gtk_text_view_drag_data_get (GtkWidget        *widget,
5985                              GdkDragContext   *context,
5986                              GtkSelectionData *selection_data,
5987                              guint             info,
5988                              guint             time)
5989 {
5990   GtkTextView *text_view;
5991
5992   text_view = GTK_TEXT_VIEW (widget);
5993
5994   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
5995     {
5996       GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
5997
5998       gtk_selection_data_set (selection_data,
5999                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
6000                               8, /* bytes */
6001                               (void*)&buffer,
6002                               sizeof (buffer));
6003     }
6004   else
6005     {
6006       gchar *str;
6007       GtkTextIter start;
6008       GtkTextIter end;
6009
6010       str = NULL;
6011
6012       if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6013                                                 &start, &end))
6014         {
6015           /* Extract the selected text */
6016           str = gtk_text_iter_get_visible_text (&start, &end);
6017         }
6018
6019       if (str)
6020         {
6021           gtk_selection_data_set_text (selection_data, str, -1);
6022           g_free (str);
6023         }
6024     }
6025 }
6026
6027 static void
6028 gtk_text_view_drag_data_delete (GtkWidget        *widget,
6029                                 GdkDragContext   *context)
6030 {
6031   GtkTextView *text_view;
6032
6033   text_view = GTK_TEXT_VIEW (widget);
6034
6035   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
6036                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
6037 }
6038
6039 static void
6040 gtk_text_view_drag_leave (GtkWidget        *widget,
6041                           GdkDragContext   *context,
6042                           guint             time)
6043 {
6044   GtkTextView *text_view;
6045
6046   text_view = GTK_TEXT_VIEW (widget);
6047
6048   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6049   
6050   if (text_view->scroll_timeout != 0)
6051     g_source_remove (text_view->scroll_timeout);
6052
6053   text_view->scroll_timeout = 0;
6054 }
6055
6056 static gboolean
6057 gtk_text_view_drag_motion (GtkWidget        *widget,
6058                            GdkDragContext   *context,
6059                            gint              x,
6060                            gint              y,
6061                            guint             time)
6062 {
6063   GtkTextIter newplace;
6064   GtkTextView *text_view;
6065   GtkTextIter start;
6066   GtkTextIter end;
6067   GdkRectangle target_rect;
6068   gint bx, by;
6069   GdkDragAction suggested_action = 0;
6070   
6071   text_view = GTK_TEXT_VIEW (widget);
6072
6073   target_rect = text_view->text_window->allocation;
6074   
6075   if (x < target_rect.x ||
6076       y < target_rect.y ||
6077       x > (target_rect.x + target_rect.width) ||
6078       y > (target_rect.y + target_rect.height))
6079     return FALSE; /* outside the text window, allow parent widgets to handle event */
6080
6081   gtk_text_view_window_to_buffer_coords (text_view,
6082                                          GTK_TEXT_WINDOW_WIDGET,
6083                                          x, y,
6084                                          &bx, &by);
6085
6086   gtk_text_layout_get_iter_at_pixel (text_view->layout,
6087                                      &newplace,
6088                                      bx, by);  
6089
6090   if (gtk_drag_dest_find_target (widget, context,
6091                                  gtk_drag_dest_get_target_list (widget)) == GDK_NONE)
6092     {
6093       /* can't accept any of the offered targets */
6094     }                                 
6095   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6096                                             &start, &end) &&
6097            gtk_text_iter_compare (&newplace, &start) >= 0 &&
6098            gtk_text_iter_compare (&newplace, &end) <= 0)
6099     {
6100       /* We're inside the selection. */
6101     }
6102   else
6103     {      
6104       if (gtk_text_iter_can_insert (&newplace, text_view->editable))
6105         {
6106           GtkWidget *source_widget;
6107           
6108           suggested_action = context->suggested_action;
6109           
6110           source_widget = gtk_drag_get_source_widget (context);
6111           
6112           if (source_widget == widget)
6113             {
6114               /* Default to MOVE, unless the user has
6115                * pressed ctrl or alt to affect available actions
6116                */
6117               if ((context->actions & GDK_ACTION_MOVE) != 0)
6118                 suggested_action = GDK_ACTION_MOVE;
6119             }
6120         }
6121       else
6122         {
6123           /* Can't drop here. */
6124         }
6125     }
6126
6127   if (suggested_action != 0)
6128     {
6129       gtk_text_mark_set_visible (text_view->dnd_mark,
6130                                  text_view->cursor_visible);
6131       
6132       gdk_drag_status (context, suggested_action, time);
6133     }
6134   else
6135     {
6136       gdk_drag_status (context, 0, time);
6137       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6138     }
6139       
6140   gtk_text_buffer_move_mark (get_buffer (text_view),
6141                              text_view->dnd_mark,
6142                              &newplace);
6143
6144   DV(g_print (G_STRLOC": scrolling to mark\n"));
6145   gtk_text_view_scroll_to_mark (text_view,
6146                                 text_view->dnd_mark,
6147                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
6148   
6149   if (text_view->scroll_timeout != 0) /* reset on every motion event */
6150     g_source_remove (text_view->scroll_timeout);
6151       
6152   text_view->scroll_timeout =
6153     g_timeout_add (50, drag_scan_timeout, text_view);
6154
6155   /* TRUE return means don't propagate the drag motion to parent
6156    * widgets that may also be drop sites.
6157    */
6158   return TRUE;
6159 }
6160
6161 static gboolean
6162 gtk_text_view_drag_drop (GtkWidget        *widget,
6163                          GdkDragContext   *context,
6164                          gint              x,
6165                          gint              y,
6166                          guint             time)
6167 {
6168   GtkTextView *text_view;
6169   GtkTextIter drop_point;
6170   GdkAtom target = GDK_NONE;
6171   
6172   text_view = GTK_TEXT_VIEW (widget);
6173   
6174   if (text_view->scroll_timeout != 0)
6175     g_source_remove (text_view->scroll_timeout);
6176
6177   text_view->scroll_timeout = 0;
6178
6179   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6180
6181   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6182                                     &drop_point,
6183                                     text_view->dnd_mark);
6184
6185   if (gtk_text_iter_can_insert (&drop_point, text_view->editable))
6186     target = gtk_drag_dest_find_target (widget, context, NULL);
6187
6188   if (target != GDK_NONE)
6189     gtk_drag_get_data (widget, context, target, time);
6190   else
6191     gtk_drag_finish (context, FALSE, FALSE, time);
6192
6193   return TRUE;
6194 }
6195
6196 static void
6197 insert_text_data (GtkTextView      *text_view,
6198                   GtkTextIter      *drop_point,
6199                   GtkSelectionData *selection_data)
6200 {
6201   gchar *str;
6202
6203   str = gtk_selection_data_get_text (selection_data);
6204
6205   if (str)
6206     {
6207       gtk_text_buffer_insert_interactive (get_buffer (text_view),
6208                                           drop_point, str, -1,
6209                                           text_view->editable);
6210       g_free (str);
6211     }
6212 }
6213
6214 static void
6215 gtk_text_view_drag_data_received (GtkWidget        *widget,
6216                                   GdkDragContext   *context,
6217                                   gint              x,
6218                                   gint              y,
6219                                   GtkSelectionData *selection_data,
6220                                   guint             info,
6221                                   guint             time)
6222 {
6223   GtkTextIter drop_point;
6224   GtkTextView *text_view;
6225   gboolean success = FALSE;
6226   GtkTextBuffer *buffer = NULL;
6227
6228   text_view = GTK_TEXT_VIEW (widget);
6229
6230   if (!text_view->dnd_mark)
6231     goto done;
6232
6233   buffer = get_buffer (text_view);
6234
6235   gtk_text_buffer_get_iter_at_mark (buffer,
6236                                     &drop_point,
6237                                     text_view->dnd_mark);
6238   
6239   if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
6240     goto done;
6241
6242   success = TRUE;
6243
6244   gtk_text_buffer_begin_user_action (buffer);
6245
6246   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
6247     {
6248       GtkTextBuffer *src_buffer = NULL;
6249       GtkTextIter start, end;
6250       gboolean copy_tags = TRUE;
6251
6252       if (selection_data->length != sizeof (src_buffer))
6253         return;
6254
6255       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
6256
6257       if (src_buffer == NULL)
6258         return;
6259
6260       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
6261
6262       if (gtk_text_buffer_get_tag_table (src_buffer) !=
6263           gtk_text_buffer_get_tag_table (buffer))
6264         copy_tags = FALSE;
6265
6266       if (gtk_text_buffer_get_selection_bounds (src_buffer,
6267                                                 &start,
6268                                                 &end))
6269         {
6270           if (copy_tags)
6271             gtk_text_buffer_insert_range_interactive (buffer,
6272                                                       &drop_point,
6273                                                       &start,
6274                                                       &end,
6275                                                       text_view->editable);
6276           else
6277             {
6278               gchar *str;
6279
6280               str = gtk_text_iter_get_visible_text (&start, &end);
6281               gtk_text_buffer_insert_interactive (buffer,
6282                                                   &drop_point, str, -1,
6283                                                   text_view->editable);
6284               g_free (str);
6285             }
6286         }
6287     }
6288   else
6289     insert_text_data (text_view, &drop_point, selection_data);
6290  
6291  done:
6292   gtk_drag_finish (context, success,
6293                    success && context->action == GDK_ACTION_MOVE,
6294                    time);
6295
6296   if (success)
6297     {
6298       gtk_text_buffer_get_iter_at_mark (buffer,
6299                                         &drop_point,
6300                                         text_view->dnd_mark);
6301       gtk_text_buffer_place_cursor (buffer, &drop_point);
6302
6303       gtk_text_buffer_end_user_action (buffer);
6304     }
6305 }
6306
6307 static GtkAdjustment*
6308 get_hadjustment (GtkTextView *text_view)
6309 {
6310   if (text_view->hadjustment == NULL)
6311     gtk_text_view_set_scroll_adjustments (text_view,
6312                                           NULL, /* forces creation */
6313                                           text_view->vadjustment);
6314
6315   return text_view->hadjustment;
6316 }
6317
6318 static GtkAdjustment*
6319 get_vadjustment (GtkTextView *text_view)
6320 {
6321   if (text_view->vadjustment == NULL)
6322     gtk_text_view_set_scroll_adjustments (text_view,
6323                                           text_view->hadjustment,
6324                                           NULL); /* forces creation */
6325   return text_view->vadjustment;
6326 }
6327
6328
6329 static void
6330 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
6331                                       GtkAdjustment *hadj,
6332                                       GtkAdjustment *vadj)
6333 {
6334   gboolean need_adjust = FALSE;
6335
6336   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6337
6338   if (hadj)
6339     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
6340   else
6341     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6342   if (vadj)
6343     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
6344   else
6345     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6346
6347   if (text_view->hadjustment && (text_view->hadjustment != hadj))
6348     {
6349       g_signal_handlers_disconnect_by_func (text_view->hadjustment,
6350                                             gtk_text_view_value_changed,
6351                                             text_view);
6352       g_object_unref (text_view->hadjustment);
6353     }
6354
6355   if (text_view->vadjustment && (text_view->vadjustment != vadj))
6356     {
6357       g_signal_handlers_disconnect_by_func (text_view->vadjustment,
6358                                             gtk_text_view_value_changed,
6359                                             text_view);
6360       g_object_unref (text_view->vadjustment);
6361     }
6362
6363   if (text_view->hadjustment != hadj)
6364     {
6365       text_view->hadjustment = hadj;
6366       g_object_ref (text_view->hadjustment);
6367       gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
6368       
6369       g_signal_connect (text_view->hadjustment, "value_changed",
6370                         G_CALLBACK (gtk_text_view_value_changed),
6371                         text_view);
6372       need_adjust = TRUE;
6373     }
6374
6375   if (text_view->vadjustment != vadj)
6376     {
6377       text_view->vadjustment = vadj;
6378       g_object_ref (text_view->vadjustment);
6379       gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
6380       
6381       g_signal_connect (text_view->vadjustment, "value_changed",
6382                         G_CALLBACK (gtk_text_view_value_changed),
6383                         text_view);
6384       need_adjust = TRUE;
6385     }
6386
6387   if (need_adjust)
6388     gtk_text_view_value_changed (NULL, text_view);
6389 }
6390
6391 /* FIXME this adjust_allocation is a big cut-and-paste from
6392  * GtkCList, needs to be some "official" way to do this
6393  * factored out.
6394  */
6395 typedef struct
6396 {
6397   GdkWindow *window;
6398   int dx;
6399   int dy;
6400 } ScrollData;
6401
6402 /* The window to which widget->window is relative */
6403 #define ALLOCATION_WINDOW(widget)               \
6404    (GTK_WIDGET_NO_WINDOW (widget) ?             \
6405     (widget)->window :                          \
6406      gdk_window_get_parent ((widget)->window))
6407
6408 static void
6409 adjust_allocation_recurse (GtkWidget *widget,
6410                            gpointer   data)
6411 {
6412   ScrollData *scroll_data = data;
6413
6414   /* Need to really size allocate instead of just poking
6415    * into widget->allocation if the widget is not realized.
6416    * FIXME someone figure out why this was.
6417    */
6418   if (!GTK_WIDGET_REALIZED (widget))
6419     {
6420       if (GTK_WIDGET_VISIBLE (widget))
6421         {
6422           GdkRectangle tmp_rectangle = widget->allocation;
6423           tmp_rectangle.x += scroll_data->dx;
6424           tmp_rectangle.y += scroll_data->dy;
6425           
6426           gtk_widget_size_allocate (widget, &tmp_rectangle);
6427         }
6428     }
6429   else
6430     {
6431       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
6432         {
6433           widget->allocation.x += scroll_data->dx;
6434           widget->allocation.y += scroll_data->dy;
6435           
6436           if (GTK_IS_CONTAINER (widget))
6437             gtk_container_forall (GTK_CONTAINER (widget),
6438                                   adjust_allocation_recurse,
6439                                   data);
6440         }
6441     }
6442 }
6443
6444 static void
6445 adjust_allocation (GtkWidget *widget,
6446                    int        dx,
6447                    int        dy)
6448 {
6449   ScrollData scroll_data;
6450
6451   if (GTK_WIDGET_REALIZED (widget))
6452     scroll_data.window = ALLOCATION_WINDOW (widget);
6453   else
6454     scroll_data.window = NULL;
6455     
6456   scroll_data.dx = dx;
6457   scroll_data.dy = dy;
6458   
6459   adjust_allocation_recurse (widget, &scroll_data);
6460 }
6461             
6462 static void
6463 gtk_text_view_value_changed (GtkAdjustment *adj,
6464                              GtkTextView   *text_view)
6465 {
6466   GtkTextIter iter;
6467   gint line_top;
6468   gint dx = 0;
6469   gint dy = 0;
6470   
6471   /* Note that we oddly call this function with adj == NULL
6472    * sometimes
6473    */
6474   
6475   text_view->onscreen_validated = FALSE;
6476
6477   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
6478              adj == text_view->hadjustment ? "hadj" : adj == text_view->vadjustment ? "vadj" : "none",
6479              adj ? adj->value : 0.0));
6480   
6481   if (adj == text_view->hadjustment)
6482     {
6483       dx = text_view->xoffset - (gint)adj->value;
6484       text_view->xoffset = adj->value;
6485     }
6486   else if (adj == text_view->vadjustment)
6487     {
6488       dy = text_view->yoffset - (gint)adj->value;
6489       text_view->yoffset = adj->value;
6490
6491       if (text_view->layout)
6492         {
6493           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
6494
6495           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
6496
6497           text_view->first_para_pixels = adj->value - line_top;
6498         }
6499     }
6500   
6501   if (dx != 0 || dy != 0)
6502     {
6503       GSList *tmp_list;
6504
6505       if (GTK_WIDGET_REALIZED (text_view))
6506         {
6507           if (dy != 0)
6508             {
6509               if (text_view->left_window)
6510                 text_window_scroll (text_view->left_window, 0, dy);
6511               if (text_view->right_window)
6512                 text_window_scroll (text_view->right_window, 0, dy);
6513             }
6514       
6515           if (dx != 0)
6516             {
6517               if (text_view->top_window)
6518                 text_window_scroll (text_view->top_window, dx, 0);
6519               if (text_view->bottom_window)
6520                 text_window_scroll (text_view->bottom_window, dx, 0);
6521             }
6522       
6523           /* It looks nicer to scroll the main area last, because
6524            * it takes a while, and making the side areas update
6525            * afterward emphasizes the slowness of scrolling the
6526            * main area.
6527            */
6528           text_window_scroll (text_view->text_window, dx, dy);
6529         }
6530       
6531       /* Children are now "moved" in the text window, poke
6532        * into widget->allocation for each child
6533        */
6534       tmp_list = text_view->children;
6535       while (tmp_list != NULL)
6536         {
6537           GtkTextViewChild *child = tmp_list->data;
6538           
6539           if (child->anchor)
6540             adjust_allocation (child->widget, dx, dy);
6541           
6542           tmp_list = g_slist_next (tmp_list);
6543         }
6544     }
6545
6546   /* This could result in invalidation, which would install the
6547    * first_validate_idle, which would validate onscreen;
6548    * but we're going to go ahead and validate here, so
6549    * first_validate_idle shouldn't have anything to do.
6550    */
6551   gtk_text_view_update_layout_width (text_view);
6552   
6553   /* note that validation of onscreen could invoke this function
6554    * recursively, by scrolling to maintain first_para, or in response
6555    * to updating the layout width, however there is no problem with
6556    * that, or shouldn't be.
6557    */
6558   gtk_text_view_validate_onscreen (text_view);
6559   
6560   /* process exposes */
6561   if (GTK_WIDGET_REALIZED (text_view))
6562     {
6563       DV (g_print ("Processing updates (%s)\n", G_STRLOC));
6564       
6565       if (text_view->left_window)
6566         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
6567
6568       if (text_view->right_window)
6569         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
6570
6571       if (text_view->top_window)
6572         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
6573       
6574       if (text_view->bottom_window)
6575         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
6576   
6577       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
6578     }
6579
6580   /* If this got installed, get rid of it, it's just a waste of time. */
6581   if (text_view->first_validate_idle != 0)
6582     {
6583       g_source_remove (text_view->first_validate_idle);
6584       text_view->first_validate_idle = 0;
6585     }
6586
6587   gtk_text_view_update_im_spot_location (text_view);
6588   
6589   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
6590 }
6591
6592 static void
6593 gtk_text_view_commit_handler (GtkIMContext  *context,
6594                               const gchar   *str,
6595                               GtkTextView   *text_view)
6596 {
6597   gtk_text_view_commit_text (text_view, str);
6598 }
6599
6600 static void
6601 gtk_text_view_commit_text (GtkTextView   *text_view,
6602                            const gchar   *str)
6603 {
6604   gboolean had_selection;
6605   
6606   gtk_text_buffer_begin_user_action (get_buffer (text_view));
6607
6608   had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6609                                                         NULL, NULL);
6610   
6611   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
6612                                     text_view->editable);
6613
6614   if (!strcmp (str, "\n"))
6615     {
6616       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
6617                                                     text_view->editable);
6618     }
6619   else
6620     {
6621       if (!had_selection && text_view->overwrite_mode)
6622         {
6623           GtkTextIter insert;
6624           
6625           gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6626                                             &insert,
6627                                             gtk_text_buffer_get_mark (get_buffer (text_view),
6628                                                                       "insert"));
6629           if (!gtk_text_iter_ends_line (&insert))
6630             gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
6631         }
6632       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
6633                                                     text_view->editable);
6634     }
6635
6636   gtk_text_buffer_end_user_action (get_buffer (text_view));
6637
6638   DV(g_print (G_STRLOC": scrolling onscreen\n"));
6639   gtk_text_view_scroll_mark_onscreen (text_view,
6640                                       gtk_text_buffer_get_mark (get_buffer (text_view),
6641                                                                 "insert"));
6642 }
6643
6644 static void
6645 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
6646                                        GtkTextView  *text_view)
6647 {
6648   gchar *str;
6649   PangoAttrList *attrs;
6650   gint cursor_pos;
6651
6652   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
6653   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
6654   pango_attr_list_unref (attrs);
6655   g_free (str);
6656
6657   gtk_text_view_scroll_mark_onscreen (text_view,
6658                                       gtk_text_buffer_get_mark (get_buffer (text_view),
6659                                                                 "insert"));
6660 }
6661
6662 static gboolean
6663 gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
6664                                             GtkTextView   *text_view)
6665 {
6666   GtkTextIter start;
6667   GtkTextIter end;
6668   gint pos;
6669   gchar *text;
6670
6671   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
6672                                     gtk_text_buffer_get_insert (text_view->buffer));
6673   end = start;
6674
6675   pos = gtk_text_iter_get_line_index (&start);
6676   gtk_text_iter_set_line_offset (&start, 0);
6677   gtk_text_iter_forward_to_line_end (&end);
6678
6679   text = gtk_text_iter_get_slice (&start, &end);
6680   gtk_im_context_set_surrounding (context, text, -1, pos);
6681   g_free (text);
6682
6683   return TRUE;
6684 }
6685
6686 static gboolean
6687 gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
6688                                           gint           offset,
6689                                           gint           n_chars,
6690                                           GtkTextView   *text_view)
6691 {
6692   GtkTextIter start;
6693   GtkTextIter end;
6694
6695   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
6696                                     gtk_text_buffer_get_insert (text_view->buffer));
6697   end = start;
6698
6699   gtk_text_iter_forward_chars (&start, offset);
6700   gtk_text_iter_forward_chars (&end, offset + n_chars);
6701
6702   gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
6703                                       text_view->editable);
6704
6705   return TRUE;
6706 }
6707
6708 static void
6709 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
6710                                 const GtkTextIter *location,
6711                                 GtkTextMark       *mark,
6712                                 gpointer           data)
6713 {
6714   GtkTextView *text_view = GTK_TEXT_VIEW (data);
6715   gboolean need_reset = FALSE;
6716
6717   if (mark == gtk_text_buffer_get_insert (buffer))
6718     {
6719       text_view->virtual_cursor_x = -1;
6720       text_view->virtual_cursor_y = -1;
6721       gtk_text_view_update_im_spot_location (text_view);
6722       need_reset = TRUE;
6723     }
6724   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
6725     {
6726       need_reset = TRUE;
6727     }
6728
6729   if (need_reset)
6730     gtk_text_view_reset_im_context (text_view);
6731 }
6732
6733 static void
6734 gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
6735                                     GdkRectangle  *pos)
6736 {
6737   GtkTextIter insert;
6738   
6739   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
6740                                     gtk_text_buffer_get_mark (get_buffer (text_view),
6741                                                               "insert"));
6742
6743   gtk_text_layout_get_cursor_locations (text_view->layout, &insert, pos, NULL);
6744 }
6745
6746 static void
6747 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
6748                                       gint        *x,
6749                                       gint        *y)
6750 {
6751   GdkRectangle pos;
6752
6753   if ((x && text_view->virtual_cursor_x == -1) ||
6754       (y && text_view->virtual_cursor_y == -1))
6755     gtk_text_view_get_cursor_location (text_view, &pos);
6756
6757   if (x)
6758     {
6759       if (text_view->virtual_cursor_x != -1)
6760         *x = text_view->virtual_cursor_x;
6761       else
6762         *x = pos.x;
6763     }
6764
6765   if (y)
6766     {
6767       if (text_view->virtual_cursor_x != -1)
6768         *y = text_view->virtual_cursor_y;
6769       else
6770         *y = pos.y + pos.height / 2;
6771     }
6772 }
6773
6774 static void
6775 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
6776                                       gint         x,
6777                                       gint         y)
6778 {
6779   GdkRectangle pos;
6780
6781   if (x == -1 || y == -1)
6782     gtk_text_view_get_cursor_location (text_view, &pos);
6783
6784   text_view->virtual_cursor_x = (x == -1) ? pos.x : x;
6785   text_view->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
6786 }
6787
6788 /* Quick hack of a popup menu
6789  */
6790 static void
6791 activate_cb (GtkWidget   *menuitem,
6792              GtkTextView *text_view)
6793 {
6794   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
6795   g_signal_emit_by_name (text_view, signal);
6796 }
6797
6798 static void
6799 append_action_signal (GtkTextView  *text_view,
6800                       GtkWidget    *menu,
6801                       const gchar  *stock_id,
6802                       const gchar  *signal,
6803                       gboolean      sensitive)
6804 {
6805   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
6806
6807   g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
6808   g_signal_connect (menuitem, "activate",
6809                     G_CALLBACK (activate_cb), text_view);
6810
6811   gtk_widget_set_sensitive (menuitem, sensitive);
6812   
6813   gtk_widget_show (menuitem);
6814   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6815 }
6816
6817 static void
6818 gtk_text_view_select_all (GtkWidget *widget,
6819                           gboolean select)
6820 {
6821   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6822   GtkTextBuffer *buffer;
6823   GtkTextIter start_iter, end_iter, insert;
6824
6825   buffer = text_view->buffer;
6826   if (select) 
6827     {
6828       gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
6829       gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
6830     }
6831   else 
6832     {
6833       gtk_text_buffer_get_iter_at_mark (buffer, &insert,
6834                                         gtk_text_buffer_get_insert (buffer));
6835       gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
6836     }
6837 }
6838
6839 static void
6840 select_all_cb (GtkWidget   *menuitem,
6841                GtkTextView *text_view)
6842 {
6843   gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
6844 }
6845
6846 static void
6847 delete_cb (GtkTextView *text_view)
6848 {
6849   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
6850                                     text_view->editable);
6851 }
6852
6853 static void
6854 popup_menu_detach (GtkWidget *attach_widget,
6855                    GtkMenu   *menu)
6856 {
6857   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
6858 }
6859
6860 static void
6861 popup_position_func (GtkMenu   *menu,
6862                      gint      *x,
6863                      gint      *y,
6864                      gboolean  *push_in,
6865                      gpointer   user_data)
6866 {
6867   GtkTextView *text_view;
6868   GtkWidget *widget;
6869   GdkRectangle cursor_rect;
6870   GdkRectangle onscreen_rect;
6871   gint root_x, root_y;
6872   GtkTextIter iter;
6873   GtkRequisition req;      
6874   GdkScreen *screen;
6875   gint monitor_num;
6876   GdkRectangle monitor;
6877       
6878   text_view = GTK_TEXT_VIEW (user_data);
6879   widget = GTK_WIDGET (text_view);
6880   
6881   g_return_if_fail (GTK_WIDGET_REALIZED (text_view));
6882   
6883   screen = gtk_widget_get_screen (widget);
6884
6885   gdk_window_get_origin (widget->window, &root_x, &root_y);
6886
6887   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6888                                     &iter,
6889                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
6890
6891   gtk_text_view_get_iter_location (text_view,
6892                                    &iter,
6893                                    &cursor_rect);
6894
6895   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
6896   
6897   gtk_widget_size_request (text_view->popup_menu, &req);
6898
6899   /* can't use rectangle_intersect since cursor rect can have 0 width */
6900   if (cursor_rect.x >= onscreen_rect.x &&
6901       cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
6902       cursor_rect.y >= onscreen_rect.y &&
6903       cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
6904     {    
6905       gtk_text_view_buffer_to_window_coords (text_view,
6906                                              GTK_TEXT_WINDOW_WIDGET,
6907                                              cursor_rect.x, cursor_rect.y,
6908                                              &cursor_rect.x, &cursor_rect.y);
6909
6910       *x = root_x + cursor_rect.x + cursor_rect.width;
6911       *y = root_y + cursor_rect.y + cursor_rect.height;
6912     }
6913   else
6914     {
6915       /* Just center the menu, since cursor is offscreen. */      
6916       *x = root_x + (widget->allocation.width / 2 - req.width / 2);
6917       *y = root_y + (widget->allocation.height / 2 - req.height / 2);      
6918     }
6919   
6920   /* Ensure sanity */
6921   *x = CLAMP (*x, root_x, (root_x + widget->allocation.width));
6922   *y = CLAMP (*y, root_y, (root_y + widget->allocation.height));
6923
6924   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
6925   gtk_menu_set_monitor (menu, monitor_num);
6926   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
6927
6928   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
6929   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
6930
6931   *push_in = FALSE;
6932 }
6933
6934 typedef struct
6935 {
6936   GtkTextView *text_view;
6937   gint button;
6938   guint time;
6939 } PopupInfo;
6940
6941 static gboolean
6942 range_contains_editable_text (const GtkTextIter *start,
6943                               const GtkTextIter *end,
6944                               gboolean default_editability)
6945 {
6946   GtkTextIter iter = *start;
6947
6948   while (gtk_text_iter_compare (&iter, end) < 0)
6949     {
6950       if (gtk_text_iter_editable (&iter, default_editability))
6951         return TRUE;
6952       
6953       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
6954     }
6955
6956   return FALSE;
6957 }                             
6958
6959 static void
6960 unichar_chosen_func (const char *text,
6961                      gpointer    data)
6962 {
6963   GtkTextView *text_view = GTK_TEXT_VIEW (data);
6964
6965   gtk_text_view_commit_text (text_view, text);
6966 }
6967
6968 static void
6969 popup_targets_received (GtkClipboard     *clipboard,
6970                         GtkSelectionData *data,
6971                         gpointer          user_data)
6972 {
6973   PopupInfo *info = user_data;
6974   GtkTextView *text_view = info->text_view;
6975   
6976   if (GTK_WIDGET_REALIZED (text_view))
6977     {
6978       /* We implicitely rely here on the fact that if we are pasting ourself, we'll
6979        * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
6980        */
6981       gboolean clipboard_contains_text = gtk_selection_data_targets_include_text (data);
6982       GtkWidget *menuitem;
6983       GtkWidget *submenu;
6984       gboolean have_selection;
6985       gboolean can_insert;
6986       GtkTextIter iter;
6987       GtkTextIter sel_start, sel_end;
6988       
6989       if (text_view->popup_menu)
6990         gtk_widget_destroy (text_view->popup_menu);
6991
6992       text_view->popup_menu = gtk_menu_new ();
6993       
6994       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
6995                                  GTK_WIDGET (text_view),
6996                                  popup_menu_detach);
6997       
6998       have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6999                                                              &sel_start, &sel_end);
7000       
7001       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7002                                         &iter,
7003                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
7004       
7005       can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
7006       
7007       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
7008                             have_selection &&
7009                             range_contains_editable_text (&sel_start, &sel_end,
7010                                                           text_view->editable));
7011       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
7012                             have_selection);
7013       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
7014                             can_insert && clipboard_contains_text);
7015       
7016       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7017       gtk_widget_set_sensitive (menuitem, 
7018                                 have_selection &&
7019                                 range_contains_editable_text (&sel_start, &sel_end,
7020                                                               text_view->editable));
7021       g_signal_connect_swapped (menuitem, "activate",
7022                                 G_CALLBACK (delete_cb), text_view);
7023       gtk_widget_show (menuitem);
7024       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7025
7026       menuitem = gtk_separator_menu_item_new ();
7027       gtk_widget_show (menuitem);
7028       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7029
7030       menuitem = gtk_menu_item_new_with_mnemonic (_("Select _All"));
7031       g_signal_connect (menuitem, "activate",
7032                         G_CALLBACK (select_all_cb), text_view);
7033       gtk_widget_show (menuitem);
7034       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7035
7036       menuitem = gtk_separator_menu_item_new ();
7037       gtk_widget_show (menuitem);
7038       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7039       
7040       menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
7041       gtk_widget_show (menuitem);
7042       gtk_widget_set_sensitive (menuitem, can_insert);
7043
7044       submenu = gtk_menu_new ();
7045       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7046       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7047       
7048       gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
7049                                             GTK_MENU_SHELL (submenu));
7050
7051       menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
7052       gtk_widget_show (menuitem);
7053       gtk_widget_set_sensitive (menuitem, can_insert);
7054       
7055       submenu = gtk_menu_new ();
7056       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7057       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);      
7058
7059       _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
7060                                                     unichar_chosen_func,
7061                                                     text_view);
7062       
7063       g_signal_emit (text_view,
7064                      signals[POPULATE_POPUP],
7065                      0,
7066                      text_view->popup_menu);
7067       
7068       if (info->button)
7069         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7070                         NULL, NULL,
7071                         info->button, info->time);
7072       else
7073         {
7074           gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7075                           popup_position_func, text_view,
7076                           0, gtk_get_current_event_time ());
7077           gtk_menu_shell_select_first (GTK_MENU_SHELL (text_view->popup_menu), FALSE);
7078         }
7079     }
7080
7081   g_object_unref (text_view);
7082   g_free (info);
7083 }
7084
7085 static void
7086 gtk_text_view_do_popup (GtkTextView    *text_view,
7087                         GdkEventButton *event)
7088 {
7089   PopupInfo *info = g_new (PopupInfo, 1);
7090
7091   /* should not need this, see http://bugzilla.gnome.org/show_bug.cgi?id=74620 */
7092   gtk_text_view_end_selection_drag (text_view, event);
7093   
7094   /* In order to know what entries we should make sensitive, we
7095    * ask for the current targets of the clipboard, and when
7096    * we get them, then we actually pop up the menu.
7097    */
7098   info->text_view = g_object_ref (text_view);
7099   
7100   if (event)
7101     {
7102       info->button = event->button;
7103       info->time = event->time;
7104     }
7105   else
7106     {
7107       info->button = 0;
7108       info->time = gtk_get_current_event_time ();
7109     }
7110
7111   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
7112                                                             GDK_SELECTION_CLIPBOARD),
7113                                   gdk_atom_intern ("TARGETS", FALSE),
7114                                   popup_targets_received,
7115                                   info);
7116 }
7117
7118 static gboolean
7119 gtk_text_view_popup_menu (GtkWidget *widget)
7120 {
7121   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
7122   return TRUE;
7123 }
7124
7125 /* Child GdkWindows */
7126
7127
7128 static GtkTextWindow*
7129 text_window_new (GtkTextWindowType  type,
7130                  GtkWidget         *widget,
7131                  gint               width_request,
7132                  gint               height_request)
7133 {
7134   GtkTextWindow *win;
7135
7136   win = g_new (GtkTextWindow, 1);
7137
7138   win->type = type;
7139   win->widget = widget;
7140   win->window = NULL;
7141   win->bin_window = NULL;
7142   win->requisition.width = width_request;
7143   win->requisition.height = height_request;
7144   win->allocation.width = width_request;
7145   win->allocation.height = height_request;
7146   win->allocation.x = 0;
7147   win->allocation.y = 0;
7148
7149   return win;
7150 }
7151
7152 static void
7153 text_window_free (GtkTextWindow *win)
7154 {
7155   if (win->window)
7156     text_window_unrealize (win);
7157
7158   g_free (win);
7159 }
7160
7161 static void
7162 text_window_realize (GtkTextWindow *win,
7163                      GdkWindow     *parent)
7164 {
7165   GdkWindowAttr attributes;
7166   gint attributes_mask;
7167   GdkCursor *cursor;
7168
7169   attributes.window_type = GDK_WINDOW_CHILD;
7170   attributes.x = win->allocation.x;
7171   attributes.y = win->allocation.y;
7172   attributes.width = win->allocation.width;
7173   attributes.height = win->allocation.height;
7174   attributes.wclass = GDK_INPUT_OUTPUT;
7175   attributes.visual = gtk_widget_get_visual (win->widget);
7176   attributes.colormap = gtk_widget_get_colormap (win->widget);
7177   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
7178
7179   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
7180
7181   win->window = gdk_window_new (parent,
7182                                 &attributes,
7183                                 attributes_mask);
7184
7185   gdk_window_set_back_pixmap (win->window, NULL, FALSE);
7186   
7187   gdk_window_show (win->window);
7188   gdk_window_set_user_data (win->window, win->widget);
7189
7190   attributes.x = 0;
7191   attributes.y = 0;
7192   attributes.width = win->allocation.width;
7193   attributes.height = win->allocation.height;
7194   attributes.event_mask = (GDK_EXPOSURE_MASK            |
7195                            GDK_SCROLL_MASK              |
7196                            GDK_KEY_PRESS_MASK           |
7197                            GDK_BUTTON_PRESS_MASK        |
7198                            GDK_BUTTON_RELEASE_MASK      |
7199                            GDK_POINTER_MOTION_MASK      |
7200                            GDK_POINTER_MOTION_HINT_MASK |
7201                            gtk_widget_get_events (win->widget));
7202
7203   win->bin_window = gdk_window_new (win->window,
7204                                     &attributes,
7205                                     attributes_mask);
7206
7207   gdk_window_show (win->bin_window);
7208   gdk_window_set_user_data (win->bin_window, win->widget);
7209
7210   if (win->type == GTK_TEXT_WINDOW_TEXT)
7211     {
7212       /* I-beam cursor */
7213       cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (parent),
7214                                            GDK_XTERM);
7215       gdk_window_set_cursor (win->bin_window, cursor);
7216       gdk_cursor_unref (cursor);
7217
7218       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
7219                                         win->window);
7220
7221
7222       gdk_window_set_background (win->bin_window,
7223                                  &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
7224     }
7225   else
7226     {
7227       gdk_window_set_background (win->bin_window,
7228                                  &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
7229     }
7230
7231   g_object_set_qdata (G_OBJECT (win->window),
7232                       g_quark_from_static_string ("gtk-text-view-text-window"),
7233                       win);
7234
7235   g_object_set_qdata (G_OBJECT (win->bin_window),
7236                       g_quark_from_static_string ("gtk-text-view-text-window"),
7237                       win);
7238 }
7239
7240 static void
7241 text_window_unrealize (GtkTextWindow *win)
7242 {
7243   if (win->type == GTK_TEXT_WINDOW_TEXT)
7244     {
7245       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
7246                                         NULL);
7247     }
7248
7249   gdk_window_set_user_data (win->window, NULL);
7250   gdk_window_set_user_data (win->bin_window, NULL);
7251   gdk_window_destroy (win->bin_window);
7252   gdk_window_destroy (win->window);
7253   win->window = NULL;
7254   win->bin_window = NULL;
7255 }
7256
7257 static void
7258 text_window_size_allocate (GtkTextWindow *win,
7259                            GdkRectangle  *rect)
7260 {
7261   win->allocation = *rect;
7262
7263   if (win->window)
7264     {
7265       gdk_window_move_resize (win->window,
7266                               rect->x, rect->y,
7267                               rect->width, rect->height);
7268
7269       gdk_window_resize (win->bin_window,
7270                          rect->width, rect->height);
7271     }
7272 }
7273
7274 static void
7275 text_window_scroll        (GtkTextWindow *win,
7276                            gint           dx,
7277                            gint           dy)
7278 {
7279   if (dx != 0 || dy != 0)
7280     {
7281       gdk_window_scroll (win->bin_window, dx, dy);
7282     }
7283 }
7284
7285 static void
7286 text_window_invalidate_rect (GtkTextWindow *win,
7287                              GdkRectangle  *rect)
7288 {
7289   GdkRectangle window_rect;
7290
7291   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
7292                                          win->type,
7293                                          rect->x,
7294                                          rect->y,
7295                                          &window_rect.x,
7296                                          &window_rect.y);
7297
7298   window_rect.width = rect->width;
7299   window_rect.height = rect->height;
7300   
7301   /* Adjust the rect as appropriate */
7302   
7303   switch (win->type)
7304     {
7305     case GTK_TEXT_WINDOW_TEXT:
7306       break;
7307
7308     case GTK_TEXT_WINDOW_LEFT:
7309     case GTK_TEXT_WINDOW_RIGHT:
7310       window_rect.x = 0;
7311       window_rect.width = win->allocation.width;
7312       break;
7313
7314     case GTK_TEXT_WINDOW_TOP:
7315     case GTK_TEXT_WINDOW_BOTTOM:
7316       window_rect.y = 0;
7317       window_rect.height = win->allocation.height;
7318       break;
7319
7320     default:
7321       g_warning ("%s: bug!", G_STRLOC);
7322       return;
7323       break;
7324     }
7325           
7326   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
7327
7328 #if 0
7329   {
7330     GdkColor color = { 0, 65535, 0, 0 };
7331     GdkGC *gc = gdk_gc_new (win->bin_window);
7332     gdk_gc_set_rgb_fg_color (gc, &color);
7333     gdk_draw_rectangle (win->bin_window,
7334                         gc, TRUE, window_rect.x, window_rect.y,
7335                         window_rect.width, window_rect.height);
7336     g_object_unref (gc);
7337   }
7338 #endif
7339 }
7340
7341 static gint
7342 text_window_get_width (GtkTextWindow *win)
7343 {
7344   return win->allocation.width;
7345 }
7346
7347 static gint
7348 text_window_get_height (GtkTextWindow *win)
7349 {
7350   return win->allocation.height;
7351 }
7352
7353 /* Windows */
7354
7355
7356 /**
7357  * gtk_text_view_get_window:
7358  * @text_view: a #GtkTextView
7359  * @win: window to get
7360  *
7361  * Retrieves the #GdkWindow corresponding to an area of the text view;
7362  * possible windows include the overall widget window, child windows
7363  * on the left, right, top, bottom, and the window that displays the
7364  * text buffer. Windows are %NULL and nonexistent if their width or
7365  * height is 0, and are nonexistent before the widget has been
7366  * realized.
7367  *
7368  * Return value: a #GdkWindow, or %NULL
7369  **/
7370 GdkWindow*
7371 gtk_text_view_get_window (GtkTextView *text_view,
7372                           GtkTextWindowType win)
7373 {
7374   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7375
7376   switch (win)
7377     {
7378     case GTK_TEXT_WINDOW_WIDGET:
7379       return GTK_WIDGET (text_view)->window;
7380       break;
7381
7382     case GTK_TEXT_WINDOW_TEXT:
7383       return text_view->text_window->bin_window;
7384       break;
7385
7386     case GTK_TEXT_WINDOW_LEFT:
7387       if (text_view->left_window)
7388         return text_view->left_window->bin_window;
7389       else
7390         return NULL;
7391       break;
7392
7393     case GTK_TEXT_WINDOW_RIGHT:
7394       if (text_view->right_window)
7395         return text_view->right_window->bin_window;
7396       else
7397         return NULL;
7398       break;
7399
7400     case GTK_TEXT_WINDOW_TOP:
7401       if (text_view->top_window)
7402         return text_view->top_window->bin_window;
7403       else
7404         return NULL;
7405       break;
7406
7407     case GTK_TEXT_WINDOW_BOTTOM:
7408       if (text_view->bottom_window)
7409         return text_view->bottom_window->bin_window;
7410       else
7411         return NULL;
7412       break;
7413
7414     case GTK_TEXT_WINDOW_PRIVATE:
7415       g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_GNUC_FUNCTION);
7416       return NULL;
7417       break;
7418     }
7419
7420   g_warning ("%s: Unknown GtkTextWindowType", G_GNUC_FUNCTION);
7421   return NULL;
7422 }
7423
7424 /**
7425  * gtk_text_view_get_window_type:
7426  * @text_view: a #GtkTextView
7427  * @window: a window type
7428  *
7429  * Usually used to find out which window an event corresponds to.
7430  * If you connect to an event signal on @text_view, this function
7431  * should be called on <literal>event-&gt;window</literal> to
7432  * see which window it was.
7433  *
7434  * Return value: the window type.
7435  **/
7436 GtkTextWindowType
7437 gtk_text_view_get_window_type (GtkTextView *text_view,
7438                                GdkWindow   *window)
7439 {
7440   GtkTextWindow *win;
7441
7442   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
7443   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
7444
7445   if (window == GTK_WIDGET (text_view)->window)
7446     return GTK_TEXT_WINDOW_WIDGET;
7447
7448   win = g_object_get_qdata (G_OBJECT (window),
7449                             g_quark_try_string ("gtk-text-view-text-window"));
7450
7451   if (win)
7452     return win->type;
7453   else
7454     {
7455       return GTK_TEXT_WINDOW_PRIVATE;
7456     }
7457 }
7458
7459 static void
7460 buffer_to_widget (GtkTextView      *text_view,
7461                   gint              buffer_x,
7462                   gint              buffer_y,
7463                   gint             *window_x,
7464                   gint             *window_y)
7465 {  
7466   if (window_x)
7467     {
7468       *window_x = buffer_x - text_view->xoffset;
7469       *window_x += text_view->text_window->allocation.x;
7470     }
7471
7472   if (window_y)
7473     {
7474       *window_y = buffer_y - text_view->yoffset;
7475       *window_y += text_view->text_window->allocation.y;
7476     }
7477 }
7478
7479 static void
7480 widget_to_text_window (GtkTextWindow *win,
7481                        gint           widget_x,
7482                        gint           widget_y,
7483                        gint          *window_x,
7484                        gint          *window_y)
7485 {
7486   if (window_x)
7487     *window_x = widget_x - win->allocation.x;
7488
7489   if (window_y)
7490     *window_y = widget_y - win->allocation.y;
7491 }
7492
7493 static void
7494 buffer_to_text_window (GtkTextView   *text_view,
7495                        GtkTextWindow *win,
7496                        gint           buffer_x,
7497                        gint           buffer_y,
7498                        gint          *window_x,
7499                        gint          *window_y)
7500 {
7501   if (win == NULL)
7502     {
7503       g_warning ("Attempt to convert text buffer coordinates to coordinates "
7504                  "for a nonexistent or private child window of GtkTextView");
7505       return;
7506     }
7507
7508   buffer_to_widget (text_view,
7509                     buffer_x, buffer_y,
7510                     window_x, window_y);
7511
7512   widget_to_text_window (win,
7513                          window_x ? *window_x : 0,
7514                          window_y ? *window_y : 0,
7515                          window_x,
7516                          window_y);
7517 }
7518
7519 /**
7520  * gtk_text_view_buffer_to_window_coords:
7521  * @text_view: a #GtkTextView
7522  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
7523  * @buffer_x: buffer x coordinate
7524  * @buffer_y: buffer y coordinate
7525  * @window_x: window x coordinate return location
7526  * @window_y: window y coordinate return location
7527  *
7528  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
7529  * @win, and stores the result in (@window_x, @window_y). 
7530  *
7531  * Note that you can't convert coordinates for a nonexisting window (see 
7532  * gtk_text_view_set_border_window_size()).
7533  **/
7534 void
7535 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
7536                                        GtkTextWindowType win,
7537                                        gint              buffer_x,
7538                                        gint              buffer_y,
7539                                        gint             *window_x,
7540                                        gint             *window_y)
7541 {
7542   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7543
7544   switch (win)
7545     {
7546     case GTK_TEXT_WINDOW_WIDGET:
7547       buffer_to_widget (text_view,
7548                         buffer_x, buffer_y,
7549                         window_x, window_y);
7550       break;
7551
7552     case GTK_TEXT_WINDOW_TEXT:
7553       if (window_x)
7554         *window_x = buffer_x - text_view->xoffset;
7555       if (window_y)
7556         *window_y = buffer_y - text_view->yoffset;
7557       break;
7558
7559     case GTK_TEXT_WINDOW_LEFT:
7560       buffer_to_text_window (text_view,
7561                              text_view->left_window,
7562                              buffer_x, buffer_y,
7563                              window_x, window_y);
7564       break;
7565
7566     case GTK_TEXT_WINDOW_RIGHT:
7567       buffer_to_text_window (text_view,
7568                              text_view->right_window,
7569                              buffer_x, buffer_y,
7570                              window_x, window_y);
7571       break;
7572
7573     case GTK_TEXT_WINDOW_TOP:
7574       buffer_to_text_window (text_view,
7575                              text_view->top_window,
7576                              buffer_x, buffer_y,
7577                              window_x, window_y);
7578       break;
7579
7580     case GTK_TEXT_WINDOW_BOTTOM:
7581       buffer_to_text_window (text_view,
7582                              text_view->bottom_window,
7583                              buffer_x, buffer_y,
7584                              window_x, window_y);
7585       break;
7586
7587     case GTK_TEXT_WINDOW_PRIVATE:
7588       g_warning ("%s: can't get coords for private windows", G_STRLOC);
7589       break;
7590
7591     default:
7592       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
7593       break;
7594     }
7595 }
7596
7597 static void
7598 widget_to_buffer (GtkTextView *text_view,
7599                   gint         widget_x,
7600                   gint         widget_y,
7601                   gint        *buffer_x,
7602                   gint        *buffer_y)
7603 {  
7604   if (buffer_x)
7605     {
7606       *buffer_x = widget_x + text_view->xoffset;
7607       *buffer_x -= text_view->text_window->allocation.x;
7608     }
7609
7610   if (buffer_y)
7611     {
7612       *buffer_y = widget_y + text_view->yoffset;
7613       *buffer_y -= text_view->text_window->allocation.y;
7614     }
7615 }
7616
7617 static void
7618 text_window_to_widget (GtkTextWindow *win,
7619                        gint           window_x,
7620                        gint           window_y,
7621                        gint          *widget_x,
7622                        gint          *widget_y)
7623 {
7624   if (widget_x)
7625     *widget_x = window_x + win->allocation.x;
7626
7627   if (widget_y)
7628     *widget_y = window_y + win->allocation.y;
7629 }
7630
7631 static void
7632 text_window_to_buffer (GtkTextView   *text_view,
7633                        GtkTextWindow *win,
7634                        gint           window_x,
7635                        gint           window_y,
7636                        gint          *buffer_x,
7637                        gint          *buffer_y)
7638 {
7639   if (win == NULL)
7640     {
7641       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
7642                  "coordinates for a nonexistent child window.");
7643       return;
7644     }
7645
7646   text_window_to_widget (win,
7647                          window_x,
7648                          window_y,
7649                          buffer_x,
7650                          buffer_y);
7651
7652   widget_to_buffer (text_view,
7653                     buffer_x ? *buffer_x : 0,
7654                     buffer_y ? *buffer_y : 0,
7655                     buffer_x,
7656                     buffer_y);
7657 }
7658
7659 /**
7660  * gtk_text_view_window_to_buffer_coords:
7661  * @text_view: a #GtkTextView
7662  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
7663  * @window_x: window x coordinate
7664  * @window_y: window y coordinate
7665  * @buffer_x: buffer x coordinate return location
7666  * @buffer_y: buffer y coordinate return location
7667  *
7668  * Converts coordinates on the window identified by @win to buffer
7669  * coordinates, storing the result in (@buffer_x,@buffer_y).
7670  *
7671  * Note that you can't convert coordinates for a nonexisting window (see 
7672  * gtk_text_view_set_border_window_size()).
7673  **/
7674 void
7675 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
7676                                        GtkTextWindowType win,
7677                                        gint              window_x,
7678                                        gint              window_y,
7679                                        gint             *buffer_x,
7680                                        gint             *buffer_y)
7681 {
7682   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7683
7684   switch (win)
7685     {
7686     case GTK_TEXT_WINDOW_WIDGET:
7687       widget_to_buffer (text_view,
7688                         window_x, window_y,
7689                         buffer_x, buffer_y);
7690       break;
7691
7692     case GTK_TEXT_WINDOW_TEXT:
7693       if (buffer_x)
7694         *buffer_x = window_x + text_view->xoffset;
7695       if (buffer_y)
7696         *buffer_y = window_y + text_view->yoffset;
7697       break;
7698
7699     case GTK_TEXT_WINDOW_LEFT:
7700       text_window_to_buffer (text_view,
7701                              text_view->left_window,
7702                              window_x, window_y,
7703                              buffer_x, buffer_y);
7704       break;
7705
7706     case GTK_TEXT_WINDOW_RIGHT:
7707       text_window_to_buffer (text_view,
7708                              text_view->right_window,
7709                              window_x, window_y,
7710                              buffer_x, buffer_y);
7711       break;
7712
7713     case GTK_TEXT_WINDOW_TOP:
7714       text_window_to_buffer (text_view,
7715                              text_view->top_window,
7716                              window_x, window_y,
7717                              buffer_x, buffer_y);
7718       break;
7719
7720     case GTK_TEXT_WINDOW_BOTTOM:
7721       text_window_to_buffer (text_view,
7722                              text_view->bottom_window,
7723                              window_x, window_y,
7724                              buffer_x, buffer_y);
7725       break;
7726
7727     case GTK_TEXT_WINDOW_PRIVATE:
7728       g_warning ("%s: can't get coords for private windows", G_STRLOC);
7729       break;
7730
7731     default:
7732       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
7733       break;
7734     }
7735 }
7736
7737 static void
7738 set_window_width (GtkTextView      *text_view,
7739                   gint              width,
7740                   GtkTextWindowType type,
7741                   GtkTextWindow   **winp)
7742 {
7743   if (width == 0)
7744     {
7745       if (*winp)
7746         {
7747           text_window_free (*winp);
7748           *winp = NULL;
7749           gtk_widget_queue_resize (GTK_WIDGET (text_view));
7750         }
7751     }
7752   else
7753     {
7754       if (*winp == NULL)
7755         {
7756           *winp = text_window_new (type,
7757                                    GTK_WIDGET (text_view),
7758                                    width, 0);
7759           /* if the widget is already realized we need to realize the child manually */
7760           if (GTK_WIDGET_REALIZED (text_view))
7761             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
7762         }
7763       else
7764         {
7765           if ((*winp)->requisition.width == width)
7766             return;
7767
7768           (*winp)->requisition.width = width;
7769         }
7770
7771       gtk_widget_queue_resize (GTK_WIDGET (text_view));
7772     }
7773 }
7774
7775
7776 static void
7777 set_window_height (GtkTextView      *text_view,
7778                    gint              height,
7779                    GtkTextWindowType type,
7780                    GtkTextWindow   **winp)
7781 {
7782   if (height == 0)
7783     {
7784       if (*winp)
7785         {
7786           text_window_free (*winp);
7787           *winp = NULL;
7788           gtk_widget_queue_resize (GTK_WIDGET (text_view));
7789         }
7790     }
7791   else
7792     {
7793       if (*winp == NULL)
7794         {
7795           *winp = text_window_new (type,
7796                                    GTK_WIDGET (text_view),
7797                                    0, height);
7798
7799           /* if the widget is already realized we need to realize the child manually */
7800           if (GTK_WIDGET_REALIZED (text_view))
7801             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
7802         }
7803       else
7804         {
7805           if ((*winp)->requisition.height == height)
7806             return;
7807
7808           (*winp)->requisition.height = height;
7809         }
7810
7811       gtk_widget_queue_resize (GTK_WIDGET (text_view));
7812     }
7813 }
7814
7815 /**
7816  * gtk_text_view_set_border_window_size:
7817  * @text_view: a #GtkTextView
7818  * @type: window to affect
7819  * @size: width or height of the window
7820  *
7821  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
7822  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
7823  * Automatically destroys the corresponding window if the size is set
7824  * to 0, and creates the window if the size is set to non-zero.  This
7825  * function can only be used for the "border windows," it doesn't work
7826  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
7827  * #GTK_TEXT_WINDOW_PRIVATE.
7828  **/
7829 void
7830 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
7831                                       GtkTextWindowType type,
7832                                       gint              size)
7833
7834 {
7835   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7836   g_return_if_fail (size >= 0);
7837
7838   switch (type)
7839     {
7840     case GTK_TEXT_WINDOW_LEFT:
7841       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
7842                         &text_view->left_window);
7843       break;
7844
7845     case GTK_TEXT_WINDOW_RIGHT:
7846       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
7847                         &text_view->right_window);
7848       break;
7849
7850     case GTK_TEXT_WINDOW_TOP:
7851       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
7852                          &text_view->top_window);
7853       break;
7854
7855     case GTK_TEXT_WINDOW_BOTTOM:
7856       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
7857                          &text_view->bottom_window);
7858       break;
7859
7860     default:
7861       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
7862       break;
7863     }
7864 }
7865
7866 /**
7867  * gtk_text_view_get_border_window_size:
7868  * @text_view: a #GtkTextView
7869  * @type: window to return size from
7870  *
7871  * Gets the width of the specified border window. See
7872  * gtk_text_view_set_border_window_size().
7873  *
7874  * Return value: width of window
7875  **/
7876 gint
7877 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
7878                                       GtkTextWindowType  type)
7879 {
7880   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
7881   
7882   switch (type)
7883     {
7884     case GTK_TEXT_WINDOW_LEFT:
7885       if (text_view->left_window)
7886         return text_view->left_window->requisition.width;
7887       
7888     case GTK_TEXT_WINDOW_RIGHT:
7889       if (text_view->right_window)
7890         return text_view->right_window->requisition.width;
7891       
7892     case GTK_TEXT_WINDOW_TOP:
7893       if (text_view->top_window)
7894         return text_view->top_window->requisition.height;
7895
7896     case GTK_TEXT_WINDOW_BOTTOM:
7897       if (text_view->bottom_window)
7898         return text_view->bottom_window->requisition.height;
7899       
7900     default:
7901       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
7902       break;
7903     }
7904
7905   return 0;
7906 }
7907
7908 /*
7909  * Child widgets
7910  */
7911
7912 static GtkTextViewChild*
7913 text_view_child_new_anchored (GtkWidget          *child,
7914                               GtkTextChildAnchor *anchor,
7915                               GtkTextLayout      *layout)
7916 {
7917   GtkTextViewChild *vc;
7918
7919   vc = g_new (GtkTextViewChild, 1);
7920
7921   vc->type = GTK_TEXT_WINDOW_PRIVATE;
7922   vc->widget = child;
7923   vc->anchor = anchor;
7924
7925   vc->from_top_of_line = 0;
7926   vc->from_left_of_buffer = 0;
7927   
7928   g_object_ref (vc->widget);
7929   g_object_ref (vc->anchor);
7930
7931   g_object_set_data (G_OBJECT (child),
7932                      "gtk-text-view-child",
7933                      vc);
7934
7935   gtk_text_child_anchor_register_child (anchor, child, layout);
7936   
7937   return vc;
7938 }
7939
7940 static GtkTextViewChild*
7941 text_view_child_new_window (GtkWidget          *child,
7942                             GtkTextWindowType   type,
7943                             gint                x,
7944                             gint                y)
7945 {
7946   GtkTextViewChild *vc;
7947
7948   vc = g_new (GtkTextViewChild, 1);
7949
7950   vc->widget = child;
7951   vc->anchor = NULL;
7952
7953   vc->from_top_of_line = 0;
7954   vc->from_left_of_buffer = 0;
7955  
7956   g_object_ref (vc->widget);
7957
7958   vc->type = type;
7959   vc->x = x;
7960   vc->y = y;
7961
7962   g_object_set_data (G_OBJECT (child),
7963                      "gtk-text-view-child",
7964                      vc);
7965   
7966   return vc;
7967 }
7968
7969 static void
7970 text_view_child_free (GtkTextViewChild *child)
7971 {
7972   g_object_set_data (G_OBJECT (child->widget),
7973                      "gtk-text-view-child", NULL);
7974
7975   if (child->anchor)
7976     {
7977       gtk_text_child_anchor_unregister_child (child->anchor,
7978                                               child->widget);
7979       g_object_unref (child->anchor);
7980     }
7981
7982   g_object_unref (child->widget);
7983
7984   g_free (child);
7985 }
7986
7987 static void
7988 text_view_child_set_parent_window (GtkTextView      *text_view,
7989                                    GtkTextViewChild *vc)
7990 {
7991   if (vc->anchor)
7992     gtk_widget_set_parent_window (vc->widget,
7993                                   text_view->text_window->bin_window);
7994   else
7995     {
7996       GdkWindow *window;
7997       window = gtk_text_view_get_window (text_view,
7998                                          vc->type);
7999       gtk_widget_set_parent_window (vc->widget, window);
8000     }
8001 }
8002
8003 static void
8004 add_child (GtkTextView      *text_view,
8005            GtkTextViewChild *vc)
8006 {
8007   text_view->children = g_slist_prepend (text_view->children,
8008                                          vc);
8009
8010   if (GTK_WIDGET_REALIZED (text_view))
8011     text_view_child_set_parent_window (text_view, vc);
8012   
8013   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
8014 }
8015
8016 /**
8017  * gtk_text_view_add_child_at_anchor:
8018  * @text_view: a #GtkTextView
8019  * @child: a #GtkWidget
8020  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
8021  * 
8022  * Adds a child widget in the text buffer, at the given @anchor.
8023  * 
8024  **/
8025 void
8026 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
8027                                    GtkWidget            *child,
8028                                    GtkTextChildAnchor   *anchor)
8029 {
8030   GtkTextViewChild *vc;
8031
8032   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8033   g_return_if_fail (GTK_IS_WIDGET (child));
8034   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
8035   g_return_if_fail (child->parent == NULL);
8036
8037   gtk_text_view_ensure_layout (text_view);
8038
8039   vc = text_view_child_new_anchored (child, anchor,
8040                                      text_view->layout);
8041
8042   add_child (text_view, vc);
8043
8044   g_assert (vc->widget == child);
8045   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8046 }
8047
8048 /**
8049  * gtk_text_view_add_child_in_window:
8050  * @text_view: a #GtkTextView
8051  * @child: a #GtkWidget
8052  * @which_window: which window the child should appear in
8053  * @xpos: X position of child in window coordinates
8054  * @ypos: Y position of child in window coordinates
8055  *
8056  * Adds a child at fixed coordinates in one of the text widget's
8057  * windows.  The window must have nonzero size (see
8058  * gtk_text_view_set_border_window_size()).  Note that the child
8059  * coordinates are given relative to the #GdkWindow in question, and
8060  * that these coordinates have no sane relationship to scrolling. When
8061  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
8062  * irrelevant, the child floats above all scrollable areas. But when
8063  * placing a child in one of the scrollable windows (border windows or
8064  * text window), you'll need to compute the child's correct position
8065  * in buffer coordinates any time scrolling occurs or buffer changes
8066  * occur, and then call gtk_text_view_move_child() to update the
8067  * child's position. Unfortunately there's no good way to detect that
8068  * scrolling has occurred, using the current API; a possible hack
8069  * would be to update all child positions when the scroll adjustments
8070  * change or the text buffer changes. See bug 64518 on
8071  * bugzilla.gnome.org for status of fixing this issue.
8072  *
8073  **/
8074 void
8075 gtk_text_view_add_child_in_window (GtkTextView          *text_view,
8076                                    GtkWidget            *child,
8077                                    GtkTextWindowType     which_window,
8078                                    gint                  xpos,
8079                                    gint                  ypos)
8080 {
8081   GtkTextViewChild *vc;
8082
8083   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8084   g_return_if_fail (GTK_IS_WIDGET (child));
8085   g_return_if_fail (child->parent == NULL);
8086
8087   vc = text_view_child_new_window (child, which_window,
8088                                    xpos, ypos);
8089
8090   add_child (text_view, vc);
8091
8092   g_assert (vc->widget == child);
8093   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8094 }
8095
8096 /**
8097  * gtk_text_view_move_child:
8098  * @text_view: a #GtkTextView
8099  * @child: child widget already added to the text view
8100  * @xpos: new X position in window coordinates
8101  * @ypos: new Y position in window coordinates
8102  *
8103  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
8104  * 
8105  **/
8106 void
8107 gtk_text_view_move_child          (GtkTextView          *text_view,
8108                                    GtkWidget            *child,
8109                                    gint                  xpos,
8110                                    gint                  ypos)
8111 {
8112   GtkTextViewChild *vc;
8113
8114   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8115   g_return_if_fail (GTK_IS_WIDGET (child));
8116   g_return_if_fail (child->parent == (GtkWidget*) text_view);
8117
8118   vc = g_object_get_data (G_OBJECT (child),
8119                           "gtk-text-view-child");
8120
8121   g_assert (vc != NULL);
8122
8123   if (vc->x == xpos &&
8124       vc->y == ypos)
8125     return;
8126   
8127   vc->x = xpos;
8128   vc->y = ypos;
8129
8130   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
8131     gtk_widget_queue_resize (child);
8132 }
8133
8134
8135 /* Iterator operations */
8136
8137 /**
8138  * gtk_text_view_forward_display_line:
8139  * @text_view: a #GtkTextView
8140  * @iter: a #GtkTextIter
8141  * 
8142  * Moves the given @iter forward by one display (wrapped) line.  A
8143  * display line is different from a paragraph. Paragraphs are
8144  * separated by newlines or other paragraph separator characters.
8145  * Display lines are created by line-wrapping a paragraph.  If
8146  * wrapping is turned off, display lines and paragraphs will be the
8147  * same. Display lines are divided differently for each view, since
8148  * they depend on the view's width; paragraphs are the same in all
8149  * views, since they depend on the contents of the #GtkTextBuffer.
8150  * 
8151  * Return value: %TRUE if @iter was moved and is not on the end iterator
8152  **/
8153 gboolean
8154 gtk_text_view_forward_display_line (GtkTextView *text_view,
8155                                     GtkTextIter *iter)
8156 {
8157   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8158   g_return_val_if_fail (iter != NULL, FALSE);
8159
8160   gtk_text_view_ensure_layout (text_view);
8161
8162   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
8163 }
8164
8165 /**
8166  * gtk_text_view_backward_display_line:
8167  * @text_view: a #GtkTextView
8168  * @iter: a #GtkTextIter
8169  * 
8170  * Moves the given @iter backward by one display (wrapped) line.  A
8171  * display line is different from a paragraph. Paragraphs are
8172  * separated by newlines or other paragraph separator characters.
8173  * Display lines are created by line-wrapping a paragraph.  If
8174  * wrapping is turned off, display lines and paragraphs will be the
8175  * same. Display lines are divided differently for each view, since
8176  * they depend on the view's width; paragraphs are the same in all
8177  * views, since they depend on the contents of the #GtkTextBuffer.
8178  * 
8179  * Return value: %TRUE if @iter was moved and is not on the end iterator
8180  **/
8181 gboolean
8182 gtk_text_view_backward_display_line (GtkTextView *text_view,
8183                                      GtkTextIter *iter)
8184 {
8185   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8186   g_return_val_if_fail (iter != NULL, FALSE);
8187
8188   gtk_text_view_ensure_layout (text_view);
8189
8190   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
8191 }
8192
8193 /**
8194  * gtk_text_view_forward_display_line_end:
8195  * @text_view: a #GtkTextView
8196  * @iter: a #GtkTextIter
8197  * 
8198  * Moves the given @iter forward to the next display line end.  A
8199  * display line is different from a paragraph. Paragraphs are
8200  * separated by newlines or other paragraph separator characters.
8201  * Display lines are created by line-wrapping a paragraph.  If
8202  * wrapping is turned off, display lines and paragraphs will be the
8203  * same. Display lines are divided differently for each view, since
8204  * they depend on the view's width; paragraphs are the same in all
8205  * views, since they depend on the contents of the #GtkTextBuffer.
8206  * 
8207  * Return value: %TRUE if @iter was moved and is not on the end iterator
8208  **/
8209 gboolean
8210 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
8211                                         GtkTextIter *iter)
8212 {
8213   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8214   g_return_val_if_fail (iter != NULL, FALSE);
8215
8216   gtk_text_view_ensure_layout (text_view);
8217
8218   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
8219 }
8220
8221 /**
8222  * gtk_text_view_backward_display_line_start:
8223  * @text_view: a #GtkTextView
8224  * @iter: a #GtkTextIter
8225  * 
8226  * Moves the given @iter backward to the next display line start.  A
8227  * display line is different from a paragraph. Paragraphs are
8228  * separated by newlines or other paragraph separator characters.
8229  * Display lines are created by line-wrapping a paragraph.  If
8230  * wrapping is turned off, display lines and paragraphs will be the
8231  * same. Display lines are divided differently for each view, since
8232  * they depend on the view's width; paragraphs are the same in all
8233  * views, since they depend on the contents of the #GtkTextBuffer.
8234  * 
8235  * Return value: %TRUE if @iter was moved and is not on the end iterator
8236  **/
8237 gboolean
8238 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
8239                                            GtkTextIter *iter)
8240 {
8241   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8242   g_return_val_if_fail (iter != NULL, FALSE);
8243
8244   gtk_text_view_ensure_layout (text_view);
8245
8246   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
8247 }
8248
8249 /**
8250  * gtk_text_view_starts_display_line:
8251  * @text_view: a #GtkTextView
8252  * @iter: a #GtkTextIter
8253  * 
8254  * Determines whether @iter is at the start of a display line.
8255  * See gtk_text_view_forward_display_line() for an explanation of
8256  * display lines vs. paragraphs.
8257  * 
8258  * Return value: %TRUE if @iter begins a wrapped line
8259  **/
8260 gboolean
8261 gtk_text_view_starts_display_line (GtkTextView       *text_view,
8262                                    const GtkTextIter *iter)
8263 {
8264   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8265   g_return_val_if_fail (iter != NULL, FALSE);
8266
8267   gtk_text_view_ensure_layout (text_view);
8268
8269   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
8270 }
8271
8272 /**
8273  * gtk_text_view_move_visually:
8274  * @text_view: a #GtkTextView
8275  * @iter: a #GtkTextIter
8276  * @count:   number of characters to move (negative moves left, positive moves right)
8277  *
8278  * Move the iterator a given number of characters visually, treating
8279  * it as the strong cursor position. If @count is positive, then the
8280  * new strong cursor position will be @count positions to the right of
8281  * the old cursor position. If @count is negative then the new strong
8282  * cursor position will be @count positions to the left of the old
8283  * cursor position.
8284  *
8285  * In the presence of bidirection text, the correspondence
8286  * between logical and visual order will depend on the direction
8287  * of the current run, and there may be jumps when the cursor
8288  * is moved off of the end of a run.
8289  * 
8290  * Return value: %TRUE if @iter moved and is not on the end iterator
8291  **/
8292 gboolean
8293 gtk_text_view_move_visually (GtkTextView *text_view,
8294                              GtkTextIter *iter,
8295                              gint         count)
8296 {
8297   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8298   g_return_val_if_fail (iter != NULL, FALSE);
8299
8300   gtk_text_view_ensure_layout (text_view);
8301
8302   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
8303 }
8304
8305 #define __GTK_TEXT_VIEW_C__
8306 #include "gtkaliasdef.c"