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