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