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