]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
do not scroll on copy. Bug #329604.
[~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_insert (get_buffer (text_view)));
5234
5235   if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
5236                                  TRUE, text_view->editable))
5237     {
5238       gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5239       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5240       gtk_text_view_scroll_mark_onscreen (text_view,
5241                                           gtk_text_buffer_get_insert (get_buffer (text_view)));
5242     }
5243 }
5244
5245 static void
5246 gtk_text_view_cut_clipboard (GtkTextView *text_view)
5247 {
5248   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5249                                                       GDK_SELECTION_CLIPBOARD);
5250   
5251   gtk_text_buffer_cut_clipboard (get_buffer (text_view),
5252                                  clipboard,
5253                                  text_view->editable);
5254   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5255   gtk_text_view_scroll_mark_onscreen (text_view,
5256                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
5257 }
5258
5259 static void
5260 gtk_text_view_copy_clipboard (GtkTextView *text_view)
5261 {
5262   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5263                                                       GDK_SELECTION_CLIPBOARD);
5264   
5265   gtk_text_buffer_copy_clipboard (get_buffer (text_view),
5266                                   clipboard);
5267
5268   /* on copy do not scroll, we are already onscreen */
5269 }
5270
5271 static void
5272 gtk_text_view_paste_clipboard (GtkTextView *text_view)
5273 {
5274   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5275                                                       GDK_SELECTION_CLIPBOARD);
5276   
5277   gtk_text_buffer_paste_clipboard (get_buffer (text_view),
5278                                    clipboard,
5279                                    NULL,
5280                                    text_view->editable);
5281   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5282   gtk_text_view_scroll_mark_onscreen (text_view,
5283                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
5284 }
5285
5286 static void
5287 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
5288 {
5289   text_view->overwrite_mode = !text_view->overwrite_mode;
5290   g_object_notify (G_OBJECT (text_view), "overwrite");
5291 }
5292
5293 /**
5294  * gtk_text_view_get_overwrite:
5295  * @text_view: a #GtkTextView
5296  *
5297  * Returns whether the #GtkTextView is in overwrite mode or not.
5298  *
5299  * Return value: whether @text_view is in overwrite mode or not.
5300  * 
5301  * Since: 2.4
5302  **/
5303 gboolean
5304 gtk_text_view_get_overwrite (GtkTextView *text_view)
5305 {
5306   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5307
5308   return text_view->overwrite_mode;
5309 }
5310
5311 /**
5312  * gtk_text_view_set_overwrite:
5313  * @text_view: a #GtkTextView
5314  * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
5315  *
5316  * Changes the #GtkTextView overwrite mode.
5317  *
5318  * Since: 2.4
5319  **/
5320 void
5321 gtk_text_view_set_overwrite (GtkTextView *text_view,
5322                              gboolean     overwrite)
5323 {
5324   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5325   overwrite = overwrite != FALSE;
5326
5327   if (text_view->overwrite_mode != overwrite)
5328     {
5329       text_view->overwrite_mode = overwrite;
5330
5331       g_object_notify (G_OBJECT (text_view), "overwrite");
5332     }
5333 }
5334
5335 /**
5336  * gtk_text_view_set_accepts_tab:
5337  * @text_view: A #GtkTextView
5338  * @accepts_tab: %TRUE if pressing the Tab key should insert a tab character, %FALSE, if pressing the Tab key should move the keyboard focus.
5339  * 
5340  * Sets the behavior of the text widget when the Tab key is pressed. If @accepts_tab
5341  * is %TRUE a tab character is inserted. If @accepts_tab is %FALSE the keyboard focus
5342  * is moved to the next widget in the focus chain.
5343  * 
5344  * Since: 2.4
5345  **/
5346 void
5347 gtk_text_view_set_accepts_tab (GtkTextView *text_view,
5348                                gboolean     accepts_tab)
5349 {
5350   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5351
5352   accepts_tab = accepts_tab != FALSE;
5353
5354   if (text_view->accepts_tab != accepts_tab)
5355     {
5356       text_view->accepts_tab = accepts_tab;
5357
5358       g_object_notify (G_OBJECT (text_view), "accepts-tab");
5359     }
5360 }
5361
5362 /**
5363  * gtk_text_view_get_accepts_tab:
5364  * @text_view: A #GtkTextView
5365  * 
5366  * Returns whether pressing the Tab key inserts a tab characters.
5367  * gtk_text_view_set_accepts_tab().
5368  * 
5369  * Return value: %TRUE if pressing the Tab key inserts a tab character, %FALSE if pressing the Tab key moves the keyboard focus.
5370  * 
5371  * Since: 2.4
5372  **/
5373 gboolean
5374 gtk_text_view_get_accepts_tab (GtkTextView *text_view)
5375 {
5376   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5377
5378   return text_view->accepts_tab;
5379 }
5380
5381 static void
5382 gtk_text_view_move_focus (GtkTextView     *text_view,
5383                           GtkDirectionType direction_type)
5384 {
5385   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (text_view));
5386
5387   if (!GTK_WIDGET_TOPLEVEL (toplevel))
5388     return;
5389
5390   /* Propagate to toplevel */
5391   g_signal_emit_by_name (toplevel, "move_focus", direction_type);
5392 }
5393
5394 /*
5395  * Selections
5396  */
5397
5398 static void
5399 gtk_text_view_unselect (GtkTextView *text_view)
5400 {
5401   GtkTextIter insert;
5402
5403   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5404                                     &insert,
5405                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5406                                                               "insert"));
5407
5408   gtk_text_buffer_move_mark (get_buffer (text_view),
5409                              gtk_text_buffer_get_mark (get_buffer (text_view),
5410                                                        "selection_bound"),
5411                              &insert);
5412 }
5413
5414 static void
5415 get_iter_at_pointer (GtkTextView *text_view,
5416                      GtkTextIter *iter)
5417 {
5418   gint x, y;
5419   GdkModifierType state;
5420
5421   gdk_window_get_pointer (text_view->text_window->bin_window,
5422                           &x, &y, &state);
5423   
5424   gtk_text_layout_get_iter_at_pixel (text_view->layout,
5425                                      iter,
5426                                      x + text_view->xoffset,
5427                                      y + text_view->yoffset);
5428 }
5429
5430 static void
5431 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
5432                                  const gchar *mark_name)
5433 {
5434   GtkTextIter newplace;
5435   GtkTextMark *mark;
5436
5437   get_iter_at_pointer (text_view, &newplace);
5438   
5439   mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
5440   
5441   /* This may invalidate the layout */
5442   DV(g_print (G_STRLOC": move mark\n"));
5443   
5444   gtk_text_buffer_move_mark (get_buffer (text_view),
5445                              mark,
5446                              &newplace);
5447   
5448   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5449   gtk_text_view_scroll_mark_onscreen (text_view, mark);
5450
5451   DV (g_print ("first validate idle leaving %s is %d\n",
5452                G_STRLOC, text_view->first_validate_idle));
5453 }
5454
5455 static gint
5456 selection_scan_timeout (gpointer data)
5457 {
5458   GtkTextView *text_view;
5459
5460   GDK_THREADS_ENTER ();
5461   
5462   text_view = GTK_TEXT_VIEW (data);
5463
5464   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
5465   gtk_text_view_scroll_mark_onscreen (text_view, 
5466                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5467                                                                 "insert"));
5468
5469   GDK_THREADS_LEAVE ();
5470   
5471   return TRUE; /* remain installed. */
5472 }
5473
5474 #define DND_SCROLL_MARGIN 0.20
5475
5476 static gint
5477 drag_scan_timeout (gpointer data)
5478 {
5479   GtkTextView *text_view;
5480   GtkTextIter newplace;
5481
5482   GDK_THREADS_ENTER ();
5483   
5484   text_view = GTK_TEXT_VIEW (data);
5485
5486   get_iter_at_pointer (text_view, &newplace);
5487
5488   gtk_text_buffer_move_mark (get_buffer (text_view),
5489                              text_view->dnd_mark,
5490                              &newplace);
5491
5492   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5493   gtk_text_view_scroll_to_mark (text_view,
5494                                 text_view->dnd_mark,
5495                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
5496
5497   GDK_THREADS_LEAVE ();
5498   
5499   return TRUE;
5500 }
5501
5502 typedef enum 
5503 {
5504   SELECT_CHARACTERS,
5505   SELECT_WORDS,
5506   SELECT_LINES
5507 } SelectionGranularity;
5508
5509 /*
5510  * Move @start and @end to the boundaries of the selection unit (indicated by 
5511  * @granularity) which contained @start initially.
5512  * If the selction unit is SELECT_WORDS and @start is not contained in a word
5513  * the selection is extended to all the white spaces between the end of the 
5514  * word preceding @start and the start of the one following.
5515  */
5516 static void
5517 extend_selection (GtkTextView *text_view, 
5518                   SelectionGranularity granularity, 
5519                   GtkTextIter *start, 
5520                   GtkTextIter *end)
5521 {
5522   *end = *start;
5523
5524   if (granularity == SELECT_WORDS) 
5525     {
5526       if (gtk_text_iter_inside_word (start))
5527         {
5528           if (!gtk_text_iter_starts_word (start))
5529             gtk_text_iter_backward_visible_word_start (start);
5530           
5531           if (!gtk_text_iter_ends_word (end))
5532             {
5533               if (!gtk_text_iter_forward_visible_word_end (end))
5534                 gtk_text_iter_forward_to_end (end);
5535             }
5536         }
5537       else
5538         {
5539           GtkTextIter tmp;
5540
5541           tmp = *start;
5542           if (gtk_text_iter_backward_visible_word_start (&tmp))
5543             gtk_text_iter_forward_visible_word_end (&tmp);
5544
5545           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
5546             *start = tmp;
5547           else
5548             gtk_text_iter_set_line_offset (start, 0);
5549
5550           tmp = *end;
5551           if (!gtk_text_iter_forward_visible_word_end (&tmp))
5552             gtk_text_iter_forward_to_end (&tmp);
5553
5554           if (gtk_text_iter_ends_word (&tmp))
5555             gtk_text_iter_backward_visible_word_start (&tmp);
5556
5557           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
5558             *end = tmp;
5559           else
5560             gtk_text_iter_forward_to_line_end (end);
5561         }
5562     }
5563   else if (granularity == SELECT_LINES) 
5564     {
5565       if (gtk_text_view_starts_display_line (text_view, start))
5566         {
5567           /* If on a display line boundary, we assume the user
5568            * clicked off the end of a line and we therefore select
5569            * the line before the boundary.
5570            */
5571           gtk_text_view_backward_display_line_start (text_view, start);
5572         }
5573       else
5574         {
5575           /* start isn't on the start of a line, so we move it to the
5576            * start, and move end to the end unless it's already there.
5577            */
5578           gtk_text_view_backward_display_line_start (text_view, start);
5579           
5580           if (!gtk_text_view_starts_display_line (text_view, end))
5581             gtk_text_view_forward_display_line_end (text_view, end);
5582         }
5583     }
5584 }
5585  
5586
5587 typedef struct
5588 {
5589   SelectionGranularity granularity;
5590   GtkTextMark *orig_start;
5591   GtkTextMark *orig_end;
5592 } SelectionData;
5593
5594 static void
5595 selection_data_free (SelectionData *data)
5596 {
5597   if (data->orig_start != NULL)
5598     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_start),
5599                                  data->orig_start);
5600   if (data->orig_end != NULL)
5601     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_end),
5602                                  data->orig_end);
5603   g_free (data);
5604 }
5605
5606 static gint
5607 selection_motion_event_handler (GtkTextView    *text_view, 
5608                                 GdkEventMotion *event, 
5609                                 SelectionData  *data)
5610 {
5611   if (data->granularity == SELECT_CHARACTERS) 
5612     {
5613       move_mark_to_pointer_and_scroll (text_view, "insert");
5614     }
5615   else 
5616     {
5617       GtkTextIter cursor, start, end;
5618       GtkTextIter orig_start, orig_end;
5619       GtkTextBuffer *buffer;
5620       
5621       buffer = get_buffer (text_view);
5622
5623       gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
5624       gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
5625
5626       get_iter_at_pointer (text_view, &cursor);
5627       
5628       start = cursor;
5629       extend_selection (text_view, data->granularity, &start, &end);
5630
5631       /* either the selection extends to the front, or end (or not) */
5632       if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
5633         gtk_text_buffer_select_range (buffer, &start, &orig_end);
5634       else
5635         gtk_text_buffer_select_range (buffer, &end, &orig_start);
5636
5637       gtk_text_view_scroll_mark_onscreen (text_view, 
5638                                           gtk_text_buffer_get_insert (buffer));
5639     }
5640
5641   /* If we had to scroll offscreen, insert a timeout to do so
5642    * again. Note that in the timeout, even if the mouse doesn't
5643    * move, due to this scroll xoffset/yoffset will have changed
5644    * and we'll need to scroll again.
5645    */
5646   if (text_view->scroll_timeout != 0) /* reset on every motion event */
5647     g_source_remove (text_view->scroll_timeout);
5648   
5649   text_view->scroll_timeout =
5650     g_timeout_add (50, selection_scan_timeout, text_view);
5651
5652   return TRUE;
5653 }
5654
5655 static void
5656 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
5657                                     const GtkTextIter *iter,
5658                                     GdkEventButton    *button)
5659 {
5660   GtkTextIter cursor, ins, bound;
5661   GtkTextIter orig_start, orig_end;
5662   GtkTextBuffer *buffer;
5663   SelectionData *data;
5664
5665   g_assert (text_view->selection_drag_handler == 0);
5666   
5667   data = g_new0 (SelectionData, 1);
5668
5669   if (button->type == GDK_2BUTTON_PRESS)
5670     data->granularity = SELECT_WORDS;
5671   else if (button->type == GDK_3BUTTON_PRESS)
5672     data->granularity = SELECT_LINES;
5673   else 
5674     data->granularity = SELECT_CHARACTERS;
5675
5676   gtk_grab_add (GTK_WIDGET (text_view));
5677
5678   buffer = get_buffer (text_view);
5679   
5680   cursor = *iter;
5681   ins = cursor;
5682   
5683   extend_selection (text_view, data->granularity, &ins, &bound);
5684   orig_start = ins;
5685   orig_end = bound;
5686
5687   if (button->state & GDK_SHIFT_MASK)
5688     {
5689       /* Extend selection */
5690       GtkTextIter old_ins, old_bound;
5691       GtkTextIter old_start, old_end;
5692
5693       gtk_text_buffer_get_iter_at_mark (buffer, &old_ins, gtk_text_buffer_get_insert (buffer));
5694       gtk_text_buffer_get_iter_at_mark (buffer, &old_bound, gtk_text_buffer_get_selection_bound (buffer));
5695       old_start = old_ins;
5696       old_end = old_bound;
5697       gtk_text_iter_order (&old_start, &old_end);
5698       
5699       /* move the front cursor, if the mouse is in front of the selection. Should the
5700        * cursor however be inside the selection (this happens on tripple click) then we
5701        * move the side which was last moved (current insert mark) */
5702       if (gtk_text_iter_compare (&cursor, &old_start) <= 0 ||
5703           (gtk_text_iter_compare (&cursor, &old_end) < 0 && 
5704            gtk_text_iter_compare (&old_ins, &old_bound) <= 0))
5705         {
5706           bound = old_end;
5707           orig_start = old_end;
5708           orig_end = old_end;
5709         }
5710       else
5711         {
5712           ins = bound;
5713           bound = old_start;
5714           orig_end = bound;
5715           orig_start = bound;
5716         }
5717     }
5718
5719   gtk_text_buffer_select_range (buffer, &ins, &bound);
5720
5721   gtk_text_iter_order (&orig_start, &orig_end);
5722   data->orig_start = gtk_text_buffer_create_mark (buffer, NULL,
5723                                                   &orig_start, TRUE);
5724   data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
5725                                                 &orig_end, TRUE);
5726
5727   gtk_text_view_check_cursor_blink (text_view);
5728
5729   text_view->selection_drag_handler = g_signal_connect_data (text_view,
5730                                                              "motion_notify_event",
5731                                                              G_CALLBACK (selection_motion_event_handler),
5732                                                              data,
5733                                                              (GClosureNotify) selection_data_free, 0);  
5734 }
5735
5736 /* returns whether we were really dragging */
5737 static gboolean
5738 gtk_text_view_end_selection_drag (GtkTextView    *text_view, 
5739                                   GdkEventButton *event)
5740 {
5741   if (text_view->selection_drag_handler == 0)
5742     return FALSE;
5743
5744   g_signal_handler_disconnect (text_view, text_view->selection_drag_handler);
5745   text_view->selection_drag_handler = 0;
5746
5747   if (text_view->scroll_timeout != 0)
5748     {
5749       g_source_remove (text_view->scroll_timeout);
5750       text_view->scroll_timeout = 0;
5751     }
5752
5753   gtk_grab_remove (GTK_WIDGET (text_view));
5754
5755   return TRUE;
5756 }
5757
5758 /*
5759  * Layout utils
5760  */
5761
5762 static void
5763 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
5764                                          GtkTextAttributes  *values,
5765                                          GtkStyle           *style)
5766 {
5767   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
5768   values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
5769
5770   if (values->font)
5771     pango_font_description_free (values->font);
5772
5773   values->font = pango_font_description_copy (style->font_desc);
5774 }
5775
5776 static void
5777 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
5778 {
5779   if (text_view->layout)
5780     {
5781       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
5782       GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
5783       GtkTextDirection new_cursor_dir;
5784       GtkTextDirection new_keyboard_dir;
5785       gboolean split_cursor;
5786
5787       g_object_get (settings,
5788                     "gtk-split-cursor", &split_cursor,
5789                     NULL);
5790       
5791       if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
5792         new_keyboard_dir = GTK_TEXT_DIR_RTL;
5793       else
5794         new_keyboard_dir  = GTK_TEXT_DIR_LTR;
5795   
5796       if (split_cursor)
5797         new_cursor_dir = GTK_TEXT_DIR_NONE;
5798       else
5799         new_cursor_dir = new_keyboard_dir;
5800       
5801       gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
5802       gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
5803     }
5804 }
5805
5806 static void
5807 gtk_text_view_ensure_layout (GtkTextView *text_view)
5808 {
5809   GtkWidget *widget;
5810
5811   widget = GTK_WIDGET (text_view);
5812
5813   if (text_view->layout == NULL)
5814     {
5815       GtkTextAttributes *style;
5816       PangoContext *ltr_context, *rtl_context;
5817       GSList *tmp_list;
5818
5819       DV(g_print(G_STRLOC"\n"));
5820       
5821       text_view->layout = gtk_text_layout_new ();
5822
5823       g_signal_connect (text_view->layout,
5824                         "invalidated",
5825                         G_CALLBACK (invalidated_handler),
5826                         text_view);
5827
5828       g_signal_connect (text_view->layout,
5829                         "changed",
5830                         G_CALLBACK (changed_handler),
5831                         text_view);
5832
5833       g_signal_connect (text_view->layout,
5834                         "allocate_child",
5835                         G_CALLBACK (gtk_text_view_child_allocated),
5836                         text_view);
5837       
5838       if (get_buffer (text_view))
5839         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
5840
5841       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
5842         gtk_text_view_pend_cursor_blink (text_view);
5843       else
5844         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
5845
5846       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
5847       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
5848       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
5849       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
5850
5851       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
5852
5853       g_object_unref (ltr_context);
5854       g_object_unref (rtl_context);
5855
5856       gtk_text_view_check_keymap_direction (text_view);
5857
5858       style = gtk_text_attributes_new ();
5859
5860       gtk_widget_ensure_style (widget);
5861       gtk_text_view_set_attributes_from_style (text_view,
5862                                                style, widget->style);
5863
5864       style->pixels_above_lines = text_view->pixels_above_lines;
5865       style->pixels_below_lines = text_view->pixels_below_lines;
5866       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
5867       style->left_margin = text_view->left_margin;
5868       style->right_margin = text_view->right_margin;
5869       style->indent = text_view->indent;
5870       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
5871
5872       style->wrap_mode = text_view->wrap_mode;
5873       style->justification = text_view->justify;
5874       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
5875
5876       gtk_text_layout_set_default_style (text_view->layout, style);
5877
5878       gtk_text_attributes_unref (style);
5879
5880       /* Set layout for all anchored children */
5881
5882       tmp_list = text_view->children;
5883       while (tmp_list != NULL)
5884         {
5885           GtkTextViewChild *vc = tmp_list->data;
5886
5887           if (vc->anchor)
5888             {
5889               gtk_text_anchored_child_set_layout (vc->widget,
5890                                                   text_view->layout);
5891               /* vc may now be invalid! */
5892             }
5893
5894           tmp_list = g_slist_next (tmp_list);
5895         }
5896
5897       gtk_text_view_invalidate (text_view);
5898     }
5899 }
5900
5901 /**
5902  * gtk_text_view_get_default_attributes:
5903  * @text_view: a #GtkTextView
5904  * 
5905  * Obtains a copy of the default text attributes. These are the
5906  * attributes used for text unless a tag overrides them.
5907  * You'd typically pass the default attributes in to
5908  * gtk_text_iter_get_attributes() in order to get the
5909  * attributes in effect at a given text position.
5910  *
5911  * The return value is a copy owned by the caller of this function,
5912  * and should be freed.
5913  * 
5914  * Return value: a new #GtkTextAttributes
5915  **/
5916 GtkTextAttributes*
5917 gtk_text_view_get_default_attributes (GtkTextView *text_view)
5918 {
5919   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
5920   
5921   gtk_text_view_ensure_layout (text_view);
5922
5923   return gtk_text_attributes_copy (text_view->layout->default_style);
5924 }
5925
5926 static void
5927 gtk_text_view_destroy_layout (GtkTextView *text_view)
5928 {
5929   if (text_view->layout)
5930     {
5931       GSList *tmp_list;
5932
5933       gtk_text_view_remove_validate_idles (text_view);
5934
5935       g_signal_handlers_disconnect_by_func (text_view->layout,
5936                                             invalidated_handler,
5937                                             text_view);
5938       g_signal_handlers_disconnect_by_func (text_view->layout,
5939                                             changed_handler, 
5940                                             text_view);
5941       
5942       /* Remove layout from all anchored children */
5943       tmp_list = text_view->children;
5944       while (tmp_list != NULL)
5945         {
5946           GtkTextViewChild *vc = tmp_list->data;
5947
5948           if (vc->anchor)
5949             {
5950               gtk_text_anchored_child_set_layout (vc->widget, NULL);
5951               /* vc may now be invalid! */
5952             }
5953
5954           tmp_list = g_slist_next (tmp_list);
5955         }
5956       
5957       gtk_text_view_stop_cursor_blink (text_view);
5958       gtk_text_view_end_selection_drag (text_view, NULL);
5959
5960       g_object_unref (text_view->layout);
5961       text_view->layout = NULL;
5962     }
5963 }
5964
5965 static void
5966 gtk_text_view_reset_im_context (GtkTextView *text_view)
5967 {
5968   if (text_view->need_im_reset)
5969     {
5970       text_view->need_im_reset = FALSE;
5971       gtk_im_context_reset (text_view->im_context);
5972     }
5973 }
5974
5975 /*
5976  * DND feature
5977  */
5978
5979 static void
5980 drag_begin_cb (GtkWidget      *widget,
5981                GdkDragContext *context,
5982                gpointer        data)
5983 {
5984   GtkTextView   *text_view = GTK_TEXT_VIEW (widget);
5985   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
5986   GtkTextIter    start;
5987   GtkTextIter    end;
5988   GdkPixmap     *pixmap = NULL;
5989
5990   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
5991
5992   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
5993     pixmap = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
5994
5995   if (pixmap)
5996     {
5997       gtk_drag_set_icon_pixmap (context,
5998                                 gdk_drawable_get_colormap (pixmap),
5999                                 pixmap,
6000                                 NULL,
6001                                 -2, -2);
6002       g_object_unref (pixmap);
6003     }
6004   else
6005     {
6006       gtk_drag_set_icon_default (context);
6007     }
6008 }
6009
6010 static void
6011 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
6012                                    const GtkTextIter *iter,
6013                                    GdkEventMotion    *event)
6014 {
6015   GtkTargetList *target_list;
6016
6017   text_view->drag_start_x = -1;
6018   text_view->drag_start_y = -1;
6019   text_view->pending_place_cursor_button = 0;
6020
6021   target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
6022
6023   g_signal_connect (text_view, "drag_begin",
6024                     G_CALLBACK (drag_begin_cb), NULL);
6025   gtk_drag_begin (GTK_WIDGET (text_view), target_list,
6026                   GDK_ACTION_COPY | GDK_ACTION_MOVE,
6027                   1, (GdkEvent*)event);
6028 }
6029
6030 static void
6031 gtk_text_view_drag_begin (GtkWidget        *widget,
6032                           GdkDragContext   *context)
6033 {
6034   /* do nothing */
6035 }
6036
6037 static void
6038 gtk_text_view_drag_end (GtkWidget        *widget,
6039                         GdkDragContext   *context)
6040 {
6041 }
6042
6043 static void
6044 gtk_text_view_drag_data_get (GtkWidget        *widget,
6045                              GdkDragContext   *context,
6046                              GtkSelectionData *selection_data,
6047                              guint             info,
6048                              guint             time)
6049 {
6050   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6051   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6052
6053   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6054     {
6055       gtk_selection_data_set (selection_data,
6056                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
6057                               8, /* bytes */
6058                               (void*)&buffer,
6059                               sizeof (buffer));
6060     }
6061   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6062     {
6063       GtkTextIter start;
6064       GtkTextIter end;
6065       guint8 *str = NULL;
6066       gsize len;
6067
6068       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6069         {
6070           /* Extract the selected text */
6071           str = gtk_text_buffer_serialize (buffer, buffer,
6072                                            selection_data->target,
6073                                            &start, &end,
6074                                            &len);
6075         }
6076
6077       if (str)
6078         {
6079           gtk_selection_data_set (selection_data,
6080                                   selection_data->target,
6081                                   8, /* bytes */
6082                                   (guchar *) str, len);
6083           g_free (str);
6084         }
6085     }
6086   else
6087     {
6088       GtkTextIter start;
6089       GtkTextIter end;
6090       gchar *str = NULL;
6091
6092       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6093         {
6094           /* Extract the selected text */
6095           str = gtk_text_iter_get_visible_text (&start, &end);
6096         }
6097
6098       if (str)
6099         {
6100           gtk_selection_data_set_text (selection_data, str, -1);
6101           g_free (str);
6102         }
6103     }
6104 }
6105
6106 static void
6107 gtk_text_view_drag_data_delete (GtkWidget        *widget,
6108                                 GdkDragContext   *context)
6109 {
6110   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
6111                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
6112 }
6113
6114 static void
6115 gtk_text_view_drag_leave (GtkWidget        *widget,
6116                           GdkDragContext   *context,
6117                           guint             time)
6118 {
6119   GtkTextView *text_view;
6120
6121   text_view = GTK_TEXT_VIEW (widget);
6122
6123   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6124   
6125   if (text_view->scroll_timeout != 0)
6126     g_source_remove (text_view->scroll_timeout);
6127
6128   text_view->scroll_timeout = 0;
6129 }
6130
6131 static gboolean
6132 gtk_text_view_drag_motion (GtkWidget        *widget,
6133                            GdkDragContext   *context,
6134                            gint              x,
6135                            gint              y,
6136                            guint             time)
6137 {
6138   GtkTextIter newplace;
6139   GtkTextView *text_view;
6140   GtkTextIter start;
6141   GtkTextIter end;
6142   GdkRectangle target_rect;
6143   gint bx, by;
6144   GdkAtom target;
6145   GdkDragAction suggested_action = 0;
6146   
6147   text_view = GTK_TEXT_VIEW (widget);
6148
6149   target_rect = text_view->text_window->allocation;
6150   
6151   if (x < target_rect.x ||
6152       y < target_rect.y ||
6153       x > (target_rect.x + target_rect.width) ||
6154       y > (target_rect.y + target_rect.height))
6155     return FALSE; /* outside the text window, allow parent widgets to handle event */
6156
6157   gtk_text_view_window_to_buffer_coords (text_view,
6158                                          GTK_TEXT_WINDOW_WIDGET,
6159                                          x, y,
6160                                          &bx, &by);
6161
6162   gtk_text_layout_get_iter_at_pixel (text_view->layout,
6163                                      &newplace,
6164                                      bx, by);  
6165
6166   target = gtk_drag_dest_find_target (widget, context,
6167                                       gtk_drag_dest_get_target_list (widget));
6168
6169   if (target == GDK_NONE)
6170     {
6171       /* can't accept any of the offered targets */
6172     }                                 
6173   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6174                                                  &start, &end) &&
6175            gtk_text_iter_compare (&newplace, &start) >= 0 &&
6176            gtk_text_iter_compare (&newplace, &end) <= 0)
6177     {
6178       /* We're inside the selection. */
6179     }
6180   else
6181     {      
6182       if (gtk_text_iter_can_insert (&newplace, text_view->editable))
6183         {
6184           GtkWidget *source_widget;
6185           
6186           suggested_action = context->suggested_action;
6187           
6188           source_widget = gtk_drag_get_source_widget (context);
6189           
6190           if (source_widget == widget)
6191             {
6192               /* Default to MOVE, unless the user has
6193                * pressed ctrl or alt to affect available actions
6194                */
6195               if ((context->actions & GDK_ACTION_MOVE) != 0)
6196                 suggested_action = GDK_ACTION_MOVE;
6197             }
6198         }
6199       else
6200         {
6201           /* Can't drop here. */
6202         }
6203     }
6204
6205   if (suggested_action != 0)
6206     {
6207       gtk_text_mark_set_visible (text_view->dnd_mark,
6208                                  text_view->cursor_visible);
6209       
6210       gdk_drag_status (context, suggested_action, time);
6211     }
6212   else
6213     {
6214       gdk_drag_status (context, 0, time);
6215       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6216     }
6217       
6218   gtk_text_buffer_move_mark (get_buffer (text_view),
6219                              text_view->dnd_mark,
6220                              &newplace);
6221
6222   DV(g_print (G_STRLOC": scrolling to mark\n"));
6223   gtk_text_view_scroll_to_mark (text_view,
6224                                 text_view->dnd_mark,
6225                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
6226   
6227   if (text_view->scroll_timeout != 0) /* reset on every motion event */
6228     g_source_remove (text_view->scroll_timeout);
6229       
6230   text_view->scroll_timeout =
6231     g_timeout_add (50, drag_scan_timeout, text_view);
6232
6233   /* TRUE return means don't propagate the drag motion to parent
6234    * widgets that may also be drop sites.
6235    */
6236   return TRUE;
6237 }
6238
6239 static gboolean
6240 gtk_text_view_drag_drop (GtkWidget        *widget,
6241                          GdkDragContext   *context,
6242                          gint              x,
6243                          gint              y,
6244                          guint             time)
6245 {
6246   GtkTextView *text_view;
6247   GtkTextIter drop_point;
6248   GdkAtom target = GDK_NONE;
6249   
6250   text_view = GTK_TEXT_VIEW (widget);
6251   
6252   if (text_view->scroll_timeout != 0)
6253     g_source_remove (text_view->scroll_timeout);
6254
6255   text_view->scroll_timeout = 0;
6256
6257   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6258
6259   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6260                                     &drop_point,
6261                                     text_view->dnd_mark);
6262
6263   if (gtk_text_iter_can_insert (&drop_point, text_view->editable))
6264     target = gtk_drag_dest_find_target (widget, context, NULL);
6265
6266   if (target != GDK_NONE)
6267     gtk_drag_get_data (widget, context, target, time);
6268   else
6269     gtk_drag_finish (context, FALSE, FALSE, time);
6270
6271   return TRUE;
6272 }
6273
6274 static void
6275 insert_text_data (GtkTextView      *text_view,
6276                   GtkTextIter      *drop_point,
6277                   GtkSelectionData *selection_data)
6278 {
6279   guchar *str;
6280
6281   str = gtk_selection_data_get_text (selection_data);
6282
6283   if (str)
6284     {
6285       gtk_text_buffer_insert_interactive (get_buffer (text_view),
6286                                           drop_point, (gchar *) str, -1,
6287                                           text_view->editable);
6288       g_free (str);
6289     }
6290 }
6291
6292 static void
6293 gtk_text_view_drag_data_received (GtkWidget        *widget,
6294                                   GdkDragContext   *context,
6295                                   gint              x,
6296                                   gint              y,
6297                                   GtkSelectionData *selection_data,
6298                                   guint             info,
6299                                   guint             time)
6300 {
6301   GtkTextIter drop_point;
6302   GtkTextView *text_view;
6303   gboolean success = FALSE;
6304   GtkTextBuffer *buffer = NULL;
6305
6306   text_view = GTK_TEXT_VIEW (widget);
6307
6308   if (!text_view->dnd_mark)
6309     goto done;
6310
6311   buffer = get_buffer (text_view);
6312
6313   gtk_text_buffer_get_iter_at_mark (buffer,
6314                                     &drop_point,
6315                                     text_view->dnd_mark);
6316   
6317   if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
6318     goto done;
6319
6320   success = TRUE;
6321
6322   gtk_text_buffer_begin_user_action (buffer);
6323
6324   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6325     {
6326       GtkTextBuffer *src_buffer = NULL;
6327       GtkTextIter start, end;
6328       gboolean copy_tags = TRUE;
6329
6330       if (selection_data->length != sizeof (src_buffer))
6331         return;
6332
6333       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
6334
6335       if (src_buffer == NULL)
6336         return;
6337
6338       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
6339
6340       if (gtk_text_buffer_get_tag_table (src_buffer) !=
6341           gtk_text_buffer_get_tag_table (buffer))
6342         {
6343           /*  try to find a suitable rich text target instead  */
6344           GdkAtom *atoms;
6345           gint     n_atoms;
6346           GList   *list;
6347           GdkAtom  target = GDK_NONE;
6348
6349           copy_tags = FALSE;
6350
6351           atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
6352
6353           for (list = context->targets; list; list = g_list_next (list))
6354             {
6355               gint i;
6356
6357               for (i = 0; i < n_atoms; i++)
6358                 if (GUINT_TO_POINTER (atoms[i]) == list->data)
6359                   {
6360                     target = atoms[i];
6361                     break;
6362                   }
6363             }
6364
6365           g_free (atoms);
6366
6367           if (target != GDK_NONE)
6368             {
6369               gtk_drag_get_data (widget, context, target, time);
6370               gtk_text_buffer_end_user_action (buffer);
6371               return;
6372             }
6373         }
6374
6375       if (gtk_text_buffer_get_selection_bounds (src_buffer,
6376                                                 &start,
6377                                                 &end))
6378         {
6379           if (copy_tags)
6380             gtk_text_buffer_insert_range_interactive (buffer,
6381                                                       &drop_point,
6382                                                       &start,
6383                                                       &end,
6384                                                       text_view->editable);
6385           else
6386             {
6387               gchar *str;
6388
6389               str = gtk_text_iter_get_visible_text (&start, &end);
6390               gtk_text_buffer_insert_interactive (buffer,
6391                                                   &drop_point, str, -1,
6392                                                   text_view->editable);
6393               g_free (str);
6394             }
6395         }
6396     }
6397   else if (selection_data->length > 0 &&
6398            info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6399     {
6400       gboolean retval;
6401       GError *error = NULL;
6402
6403       retval = gtk_text_buffer_deserialize (buffer, buffer,
6404                                             selection_data->target,
6405                                             &drop_point,
6406                                             (guint8 *) selection_data->data,
6407                                             selection_data->length,
6408                                             &error);
6409
6410       if (!retval)
6411         {
6412           g_warning ("error pasting: %s\n", error->message);
6413           g_clear_error (&error);
6414         }
6415     }
6416   else
6417     insert_text_data (text_view, &drop_point, selection_data);
6418
6419  done:
6420   gtk_drag_finish (context, success,
6421                    success && context->action == GDK_ACTION_MOVE,
6422                    time);
6423
6424   if (success)
6425     {
6426       gtk_text_buffer_get_iter_at_mark (buffer,
6427                                         &drop_point,
6428                                         text_view->dnd_mark);
6429       gtk_text_buffer_place_cursor (buffer, &drop_point);
6430
6431       gtk_text_buffer_end_user_action (buffer);
6432     }
6433 }
6434
6435 static GtkAdjustment*
6436 get_hadjustment (GtkTextView *text_view)
6437 {
6438   if (text_view->hadjustment == NULL)
6439     gtk_text_view_set_scroll_adjustments (text_view,
6440                                           NULL, /* forces creation */
6441                                           text_view->vadjustment);
6442
6443   return text_view->hadjustment;
6444 }
6445
6446 static GtkAdjustment*
6447 get_vadjustment (GtkTextView *text_view)
6448 {
6449   if (text_view->vadjustment == NULL)
6450     gtk_text_view_set_scroll_adjustments (text_view,
6451                                           text_view->hadjustment,
6452                                           NULL); /* forces creation */
6453   return text_view->vadjustment;
6454 }
6455
6456
6457 static void
6458 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
6459                                       GtkAdjustment *hadj,
6460                                       GtkAdjustment *vadj)
6461 {
6462   gboolean need_adjust = FALSE;
6463
6464   if (hadj)
6465     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
6466   else
6467     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6468   if (vadj)
6469     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
6470   else
6471     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6472
6473   if (text_view->hadjustment && (text_view->hadjustment != hadj))
6474     {
6475       g_signal_handlers_disconnect_by_func (text_view->hadjustment,
6476                                             gtk_text_view_value_changed,
6477                                             text_view);
6478       g_object_unref (text_view->hadjustment);
6479     }
6480
6481   if (text_view->vadjustment && (text_view->vadjustment != vadj))
6482     {
6483       g_signal_handlers_disconnect_by_func (text_view->vadjustment,
6484                                             gtk_text_view_value_changed,
6485                                             text_view);
6486       g_object_unref (text_view->vadjustment);
6487     }
6488
6489   if (text_view->hadjustment != hadj)
6490     {
6491       text_view->hadjustment = hadj;
6492       g_object_ref_sink (text_view->hadjustment);
6493       
6494       g_signal_connect (text_view->hadjustment, "value_changed",
6495                         G_CALLBACK (gtk_text_view_value_changed),
6496                         text_view);
6497       need_adjust = TRUE;
6498     }
6499
6500   if (text_view->vadjustment != vadj)
6501     {
6502       text_view->vadjustment = vadj;
6503       g_object_ref_sink (text_view->vadjustment);
6504       
6505       g_signal_connect (text_view->vadjustment, "value_changed",
6506                         G_CALLBACK (gtk_text_view_value_changed),
6507                         text_view);
6508       need_adjust = TRUE;
6509     }
6510
6511   if (need_adjust)
6512     gtk_text_view_value_changed (NULL, text_view);
6513 }
6514
6515 /* FIXME this adjust_allocation is a big cut-and-paste from
6516  * GtkCList, needs to be some "official" way to do this
6517  * factored out.
6518  */
6519 typedef struct
6520 {
6521   GdkWindow *window;
6522   int dx;
6523   int dy;
6524 } ScrollData;
6525
6526 /* The window to which widget->window is relative */
6527 #define ALLOCATION_WINDOW(widget)               \
6528    (GTK_WIDGET_NO_WINDOW (widget) ?             \
6529     (widget)->window :                          \
6530      gdk_window_get_parent ((widget)->window))
6531
6532 static void
6533 adjust_allocation_recurse (GtkWidget *widget,
6534                            gpointer   data)
6535 {
6536   ScrollData *scroll_data = data;
6537
6538   /* Need to really size allocate instead of just poking
6539    * into widget->allocation if the widget is not realized.
6540    * FIXME someone figure out why this was.
6541    */
6542   if (!GTK_WIDGET_REALIZED (widget))
6543     {
6544       if (GTK_WIDGET_VISIBLE (widget))
6545         {
6546           GdkRectangle tmp_rectangle = widget->allocation;
6547           tmp_rectangle.x += scroll_data->dx;
6548           tmp_rectangle.y += scroll_data->dy;
6549           
6550           gtk_widget_size_allocate (widget, &tmp_rectangle);
6551         }
6552     }
6553   else
6554     {
6555       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
6556         {
6557           widget->allocation.x += scroll_data->dx;
6558           widget->allocation.y += scroll_data->dy;
6559           
6560           if (GTK_IS_CONTAINER (widget))
6561             gtk_container_forall (GTK_CONTAINER (widget),
6562                                   adjust_allocation_recurse,
6563                                   data);
6564         }
6565     }
6566 }
6567
6568 static void
6569 adjust_allocation (GtkWidget *widget,
6570                    int        dx,
6571                    int        dy)
6572 {
6573   ScrollData scroll_data;
6574
6575   if (GTK_WIDGET_REALIZED (widget))
6576     scroll_data.window = ALLOCATION_WINDOW (widget);
6577   else
6578     scroll_data.window = NULL;
6579     
6580   scroll_data.dx = dx;
6581   scroll_data.dy = dy;
6582   
6583   adjust_allocation_recurse (widget, &scroll_data);
6584 }
6585             
6586 static void
6587 gtk_text_view_value_changed (GtkAdjustment *adj,
6588                              GtkTextView   *text_view)
6589 {
6590   GtkTextIter iter;
6591   gint line_top;
6592   gint dx = 0;
6593   gint dy = 0;
6594   
6595   /* Note that we oddly call this function with adj == NULL
6596    * sometimes
6597    */
6598   
6599   text_view->onscreen_validated = FALSE;
6600
6601   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
6602              adj == text_view->hadjustment ? "hadj" : adj == text_view->vadjustment ? "vadj" : "none",
6603              adj ? adj->value : 0.0));
6604   
6605   if (adj == text_view->hadjustment)
6606     {
6607       dx = text_view->xoffset - (gint)adj->value;
6608       text_view->xoffset = adj->value;
6609
6610       /* If the change is due to a size change we need 
6611        * to invalidate the entire text window because there might be
6612        * right-aligned or centered text 
6613        */
6614       if (text_view->width_changed)
6615         {
6616           if (GTK_WIDGET_REALIZED (text_view))
6617             gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
6618           
6619           text_view->width_changed = FALSE;
6620         }
6621     }
6622   else if (adj == text_view->vadjustment)
6623     {
6624       dy = text_view->yoffset - (gint)adj->value;
6625       text_view->yoffset = adj->value;
6626
6627       if (text_view->layout)
6628         {
6629           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
6630
6631           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
6632
6633           text_view->first_para_pixels = adj->value - line_top;
6634         }
6635     }
6636   
6637   if (dx != 0 || dy != 0)
6638     {
6639       GSList *tmp_list;
6640
6641       if (GTK_WIDGET_REALIZED (text_view))
6642         {
6643           if (dy != 0)
6644             {
6645               if (text_view->left_window)
6646                 text_window_scroll (text_view->left_window, 0, dy);
6647               if (text_view->right_window)
6648                 text_window_scroll (text_view->right_window, 0, dy);
6649             }
6650       
6651           if (dx != 0)
6652             {
6653               if (text_view->top_window)
6654                 text_window_scroll (text_view->top_window, dx, 0);
6655               if (text_view->bottom_window)
6656                 text_window_scroll (text_view->bottom_window, dx, 0);
6657             }
6658       
6659           /* It looks nicer to scroll the main area last, because
6660            * it takes a while, and making the side areas update
6661            * afterward emphasizes the slowness of scrolling the
6662            * main area.
6663            */
6664           text_window_scroll (text_view->text_window, dx, dy);
6665         }
6666       
6667       /* Children are now "moved" in the text window, poke
6668        * into widget->allocation for each child
6669        */
6670       tmp_list = text_view->children;
6671       while (tmp_list != NULL)
6672         {
6673           GtkTextViewChild *child = tmp_list->data;
6674           
6675           if (child->anchor)
6676             adjust_allocation (child->widget, dx, dy);
6677           
6678           tmp_list = g_slist_next (tmp_list);
6679         }
6680     }
6681
6682   /* This could result in invalidation, which would install the
6683    * first_validate_idle, which would validate onscreen;
6684    * but we're going to go ahead and validate here, so
6685    * first_validate_idle shouldn't have anything to do.
6686    */
6687   gtk_text_view_update_layout_width (text_view);
6688   
6689   /* note that validation of onscreen could invoke this function
6690    * recursively, by scrolling to maintain first_para, or in response
6691    * to updating the layout width, however there is no problem with
6692    * that, or shouldn't be.
6693    */
6694   gtk_text_view_validate_onscreen (text_view);
6695   
6696   /* process exposes */
6697   if (GTK_WIDGET_REALIZED (text_view))
6698     {
6699       DV (g_print ("Processing updates (%s)\n", G_STRLOC));
6700       
6701       if (text_view->left_window)
6702         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
6703
6704       if (text_view->right_window)
6705         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
6706
6707       if (text_view->top_window)
6708         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
6709       
6710       if (text_view->bottom_window)
6711         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
6712   
6713       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
6714     }
6715
6716   /* If this got installed, get rid of it, it's just a waste of time. */
6717   if (text_view->first_validate_idle != 0)
6718     {
6719       g_source_remove (text_view->first_validate_idle);
6720       text_view->first_validate_idle = 0;
6721     }
6722
6723   gtk_text_view_update_im_spot_location (text_view);
6724   
6725   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
6726 }
6727
6728 static void
6729 gtk_text_view_commit_handler (GtkIMContext  *context,
6730                               const gchar   *str,
6731                               GtkTextView   *text_view)
6732 {
6733   gtk_text_view_commit_text (text_view, str);
6734 }
6735
6736 static void
6737 gtk_text_view_commit_text (GtkTextView   *text_view,
6738                            const gchar   *str)
6739 {
6740   gboolean had_selection;
6741   
6742   gtk_text_buffer_begin_user_action (get_buffer (text_view));
6743
6744   had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6745                                                         NULL, NULL);
6746   
6747   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
6748                                     text_view->editable);
6749
6750   if (!strcmp (str, "\n"))
6751     {
6752       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
6753                                                     text_view->editable);
6754     }
6755   else
6756     {
6757       if (!had_selection && text_view->overwrite_mode)
6758         {
6759           GtkTextIter insert;
6760           
6761           gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6762                                             &insert,
6763                                             gtk_text_buffer_get_mark (get_buffer (text_view),
6764                                                                       "insert"));
6765           if (!gtk_text_iter_ends_line (&insert))
6766             gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
6767         }
6768       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
6769                                                     text_view->editable);
6770     }
6771
6772   gtk_text_buffer_end_user_action (get_buffer (text_view));
6773
6774   gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
6775   DV(g_print (G_STRLOC": scrolling onscreen\n"));
6776   gtk_text_view_scroll_mark_onscreen (text_view,
6777                                       gtk_text_buffer_get_mark (get_buffer (text_view),
6778                                                                 "insert"));
6779 }
6780
6781 static void
6782 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
6783                                        GtkTextView  *text_view)
6784 {
6785   gchar *str;
6786   PangoAttrList *attrs;
6787   gint cursor_pos;
6788
6789   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
6790   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
6791   pango_attr_list_unref (attrs);
6792   g_free (str);
6793
6794   if (GTK_WIDGET_HAS_FOCUS (text_view))
6795     gtk_text_view_scroll_mark_onscreen (text_view,
6796                                         gtk_text_buffer_get_mark (get_buffer (text_view),
6797                                                                   "insert"));
6798 }
6799
6800 static gboolean
6801 gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
6802                                             GtkTextView   *text_view)
6803 {
6804   GtkTextIter start;
6805   GtkTextIter end;
6806   gint pos;
6807   gchar *text;
6808
6809   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
6810                                     gtk_text_buffer_get_insert (text_view->buffer));
6811   end = start;
6812
6813   pos = gtk_text_iter_get_line_index (&start);
6814   gtk_text_iter_set_line_offset (&start, 0);
6815   gtk_text_iter_forward_to_line_end (&end);
6816
6817   text = gtk_text_iter_get_slice (&start, &end);
6818   gtk_im_context_set_surrounding (context, text, -1, pos);
6819   g_free (text);
6820
6821   return TRUE;
6822 }
6823
6824 static gboolean
6825 gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
6826                                           gint           offset,
6827                                           gint           n_chars,
6828                                           GtkTextView   *text_view)
6829 {
6830   GtkTextIter start;
6831   GtkTextIter end;
6832
6833   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
6834                                     gtk_text_buffer_get_insert (text_view->buffer));
6835   end = start;
6836
6837   gtk_text_iter_forward_chars (&start, offset);
6838   gtk_text_iter_forward_chars (&end, offset + n_chars);
6839
6840   gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
6841                                       text_view->editable);
6842
6843   return TRUE;
6844 }
6845
6846 static void
6847 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
6848                                 const GtkTextIter *location,
6849                                 GtkTextMark       *mark,
6850                                 gpointer           data)
6851 {
6852   GtkTextView *text_view = GTK_TEXT_VIEW (data);
6853   gboolean need_reset = FALSE;
6854
6855   if (mark == gtk_text_buffer_get_insert (buffer))
6856     {
6857       text_view->virtual_cursor_x = -1;
6858       text_view->virtual_cursor_y = -1;
6859       gtk_text_view_update_im_spot_location (text_view);
6860       need_reset = TRUE;
6861     }
6862   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
6863     {
6864       need_reset = TRUE;
6865     }
6866
6867   if (need_reset)
6868     gtk_text_view_reset_im_context (text_view);
6869 }
6870
6871 static void
6872 gtk_text_view_target_list_notify (GtkTextBuffer    *buffer,
6873                                   const GParamSpec *pspec,
6874                                   gpointer          data)
6875 {
6876   GtkWidget     *widget = GTK_WIDGET (data);
6877   GtkTargetList *view_list;
6878   GtkTargetList *buffer_list;
6879   GList         *list;
6880
6881   view_list = gtk_drag_dest_get_target_list (widget);
6882   buffer_list = gtk_text_buffer_get_paste_target_list (buffer);
6883
6884   if (view_list)
6885     gtk_target_list_ref (view_list);
6886   else
6887     view_list = gtk_target_list_new (NULL, 0);
6888
6889   list = view_list->list;
6890   while (list)
6891     {
6892       GtkTargetPair *pair = list->data;
6893
6894       list = g_list_next (list); /* get next element before removing */
6895
6896       if (pair->info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
6897           pair->info <= GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6898         {
6899           gtk_target_list_remove (view_list, pair->target);
6900         }
6901     }
6902
6903   for (list = buffer_list->list; list; list = g_list_next (list))
6904     {
6905       GtkTargetPair *pair = list->data;
6906
6907       gtk_target_list_add (view_list, pair->target, pair->flags, pair->info);
6908     }
6909
6910   gtk_drag_dest_set_target_list (widget, view_list);
6911   gtk_target_list_unref (view_list);
6912 }
6913
6914 static void
6915 gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
6916                                     GdkRectangle  *pos)
6917 {
6918   GtkTextIter insert;
6919   
6920   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
6921                                     gtk_text_buffer_get_mark (get_buffer (text_view),
6922                                                               "insert"));
6923
6924   gtk_text_layout_get_cursor_locations (text_view->layout, &insert, pos, NULL);
6925 }
6926
6927 static void
6928 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
6929                                       gint        *x,
6930                                       gint        *y)
6931 {
6932   GdkRectangle pos;
6933
6934   if ((x && text_view->virtual_cursor_x == -1) ||
6935       (y && text_view->virtual_cursor_y == -1))
6936     gtk_text_view_get_cursor_location (text_view, &pos);
6937
6938   if (x)
6939     {
6940       if (text_view->virtual_cursor_x != -1)
6941         *x = text_view->virtual_cursor_x;
6942       else
6943         *x = pos.x;
6944     }
6945
6946   if (y)
6947     {
6948       if (text_view->virtual_cursor_x != -1)
6949         *y = text_view->virtual_cursor_y;
6950       else
6951         *y = pos.y + pos.height / 2;
6952     }
6953 }
6954
6955 static void
6956 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
6957                                       gint         x,
6958                                       gint         y)
6959 {
6960   GdkRectangle pos;
6961
6962   if (!text_view->layout)
6963     return;
6964
6965   if (x == -1 || y == -1)
6966     gtk_text_view_get_cursor_location (text_view, &pos);
6967
6968   text_view->virtual_cursor_x = (x == -1) ? pos.x : x;
6969   text_view->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
6970 }
6971
6972 /* Quick hack of a popup menu
6973  */
6974 static void
6975 activate_cb (GtkWidget   *menuitem,
6976              GtkTextView *text_view)
6977 {
6978   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
6979   g_signal_emit_by_name (text_view, signal);
6980 }
6981
6982 static void
6983 append_action_signal (GtkTextView  *text_view,
6984                       GtkWidget    *menu,
6985                       const gchar  *stock_id,
6986                       const gchar  *signal,
6987                       gboolean      sensitive)
6988 {
6989   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
6990
6991   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
6992   g_signal_connect (menuitem, "activate",
6993                     G_CALLBACK (activate_cb), text_view);
6994
6995   gtk_widget_set_sensitive (menuitem, sensitive);
6996   
6997   gtk_widget_show (menuitem);
6998   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
6999 }
7000
7001 static void
7002 gtk_text_view_select_all (GtkWidget *widget,
7003                           gboolean select)
7004 {
7005   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
7006   GtkTextBuffer *buffer;
7007   GtkTextIter start_iter, end_iter, insert;
7008
7009   buffer = text_view->buffer;
7010   if (select) 
7011     {
7012       gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
7013       gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
7014     }
7015   else 
7016     {
7017       gtk_text_buffer_get_iter_at_mark (buffer, &insert,
7018                                         gtk_text_buffer_get_insert (buffer));
7019       gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
7020     }
7021 }
7022
7023 static void
7024 select_all_cb (GtkWidget   *menuitem,
7025                GtkTextView *text_view)
7026 {
7027   gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
7028 }
7029
7030 static void
7031 delete_cb (GtkTextView *text_view)
7032 {
7033   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7034                                     text_view->editable);
7035 }
7036
7037 static void
7038 popup_menu_detach (GtkWidget *attach_widget,
7039                    GtkMenu   *menu)
7040 {
7041   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
7042 }
7043
7044 static void
7045 popup_position_func (GtkMenu   *menu,
7046                      gint      *x,
7047                      gint      *y,
7048                      gboolean  *push_in,
7049                      gpointer   user_data)
7050 {
7051   GtkTextView *text_view;
7052   GtkWidget *widget;
7053   GdkRectangle cursor_rect;
7054   GdkRectangle onscreen_rect;
7055   gint root_x, root_y;
7056   GtkTextIter iter;
7057   GtkRequisition req;      
7058   GdkScreen *screen;
7059   gint monitor_num;
7060   GdkRectangle monitor;
7061       
7062   text_view = GTK_TEXT_VIEW (user_data);
7063   widget = GTK_WIDGET (text_view);
7064   
7065   g_return_if_fail (GTK_WIDGET_REALIZED (text_view));
7066   
7067   screen = gtk_widget_get_screen (widget);
7068
7069   gdk_window_get_origin (widget->window, &root_x, &root_y);
7070
7071   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7072                                     &iter,
7073                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
7074
7075   gtk_text_view_get_iter_location (text_view,
7076                                    &iter,
7077                                    &cursor_rect);
7078
7079   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
7080   
7081   gtk_widget_size_request (text_view->popup_menu, &req);
7082
7083   /* can't use rectangle_intersect since cursor rect can have 0 width */
7084   if (cursor_rect.x >= onscreen_rect.x &&
7085       cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
7086       cursor_rect.y >= onscreen_rect.y &&
7087       cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
7088     {    
7089       gtk_text_view_buffer_to_window_coords (text_view,
7090                                              GTK_TEXT_WINDOW_WIDGET,
7091                                              cursor_rect.x, cursor_rect.y,
7092                                              &cursor_rect.x, &cursor_rect.y);
7093
7094       *x = root_x + cursor_rect.x + cursor_rect.width;
7095       *y = root_y + cursor_rect.y + cursor_rect.height;
7096     }
7097   else
7098     {
7099       /* Just center the menu, since cursor is offscreen. */      
7100       *x = root_x + (widget->allocation.width / 2 - req.width / 2);
7101       *y = root_y + (widget->allocation.height / 2 - req.height / 2);      
7102     }
7103   
7104   /* Ensure sanity */
7105   *x = CLAMP (*x, root_x, (root_x + widget->allocation.width));
7106   *y = CLAMP (*y, root_y, (root_y + widget->allocation.height));
7107
7108   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
7109   gtk_menu_set_monitor (menu, monitor_num);
7110   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
7111
7112   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
7113   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
7114
7115   *push_in = FALSE;
7116 }
7117
7118 typedef struct
7119 {
7120   GtkTextView *text_view;
7121   gint button;
7122   guint time;
7123 } PopupInfo;
7124
7125 static gboolean
7126 range_contains_editable_text (const GtkTextIter *start,
7127                               const GtkTextIter *end,
7128                               gboolean default_editability)
7129 {
7130   GtkTextIter iter = *start;
7131
7132   while (gtk_text_iter_compare (&iter, end) < 0)
7133     {
7134       if (gtk_text_iter_editable (&iter, default_editability))
7135         return TRUE;
7136       
7137       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
7138     }
7139
7140   return FALSE;
7141 }                             
7142
7143 static void
7144 unichar_chosen_func (const char *text,
7145                      gpointer    data)
7146 {
7147   GtkTextView *text_view = GTK_TEXT_VIEW (data);
7148
7149   gtk_text_view_commit_text (text_view, text);
7150 }
7151
7152 static void
7153 popup_targets_received (GtkClipboard     *clipboard,
7154                         GtkSelectionData *data,
7155                         gpointer          user_data)
7156 {
7157   PopupInfo *info = user_data;
7158   GtkTextView *text_view = info->text_view;
7159   
7160   if (GTK_WIDGET_REALIZED (text_view))
7161     {
7162       /* We implicitely rely here on the fact that if we are pasting ourself, we'll
7163        * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
7164        */
7165       gboolean clipboard_contains_text;
7166       GtkWidget *menuitem;
7167       GtkWidget *submenu;
7168       gboolean have_selection;
7169       gboolean can_insert;
7170       GtkTextIter iter;
7171       GtkTextIter sel_start, sel_end;
7172       gboolean show_input_method_menu;
7173       gboolean show_unicode_menu;
7174       
7175       clipboard_contains_text = gtk_selection_data_targets_include_text (data);
7176
7177       if (text_view->popup_menu)
7178         gtk_widget_destroy (text_view->popup_menu);
7179
7180       text_view->popup_menu = gtk_menu_new ();
7181       
7182       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
7183                                  GTK_WIDGET (text_view),
7184                                  popup_menu_detach);
7185       
7186       have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7187                                                              &sel_start, &sel_end);
7188       
7189       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7190                                         &iter,
7191                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
7192       
7193       can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
7194       
7195       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
7196                             have_selection &&
7197                             range_contains_editable_text (&sel_start, &sel_end,
7198                                                           text_view->editable));
7199       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
7200                             have_selection);
7201       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
7202                             can_insert && clipboard_contains_text);
7203       
7204       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7205       gtk_widget_set_sensitive (menuitem, 
7206                                 have_selection &&
7207                                 range_contains_editable_text (&sel_start, &sel_end,
7208                                                               text_view->editable));
7209       g_signal_connect_swapped (menuitem, "activate",
7210                                 G_CALLBACK (delete_cb), text_view);
7211       gtk_widget_show (menuitem);
7212       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7213
7214       menuitem = gtk_separator_menu_item_new ();
7215       gtk_widget_show (menuitem);
7216       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7217
7218       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
7219       g_signal_connect (menuitem, "activate",
7220                         G_CALLBACK (select_all_cb), text_view);
7221       gtk_widget_show (menuitem);
7222       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7223
7224       g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
7225                     "gtk-show-input-method-menu", &show_input_method_menu,
7226                     "gtk-show-unicode-menu", &show_unicode_menu,
7227                     NULL);
7228       
7229       if (show_input_method_menu || show_unicode_menu)
7230         {
7231           menuitem = gtk_separator_menu_item_new ();
7232           gtk_widget_show (menuitem);
7233           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7234         }
7235
7236       if (show_input_method_menu)
7237         {
7238           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
7239           gtk_widget_show (menuitem);
7240           gtk_widget_set_sensitive (menuitem, can_insert);
7241
7242           submenu = gtk_menu_new ();
7243           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7244           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7245           
7246           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
7247                                                 GTK_MENU_SHELL (submenu));
7248         }
7249
7250       if (show_unicode_menu)
7251         {
7252           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
7253           gtk_widget_show (menuitem);
7254           gtk_widget_set_sensitive (menuitem, can_insert);
7255       
7256           submenu = gtk_menu_new ();
7257           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7258           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);      
7259           
7260           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
7261                                                         unichar_chosen_func,
7262                                                         text_view);
7263         }
7264           
7265       g_signal_emit (text_view,
7266                      signals[POPULATE_POPUP],
7267                      0,
7268                      text_view->popup_menu);
7269       
7270       if (info->button)
7271         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7272                         NULL, NULL,
7273                         info->button, info->time);
7274       else
7275         {
7276           gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7277                           popup_position_func, text_view,
7278                           0, gtk_get_current_event_time ());
7279           gtk_menu_shell_select_first (GTK_MENU_SHELL (text_view->popup_menu), FALSE);
7280         }
7281     }
7282
7283   g_object_unref (text_view);
7284   g_free (info);
7285 }
7286
7287 static void
7288 gtk_text_view_do_popup (GtkTextView    *text_view,
7289                         GdkEventButton *event)
7290 {
7291   PopupInfo *info = g_new (PopupInfo, 1);
7292
7293   /* In order to know what entries we should make sensitive, we
7294    * ask for the current targets of the clipboard, and when
7295    * we get them, then we actually pop up the menu.
7296    */
7297   info->text_view = g_object_ref (text_view);
7298   
7299   if (event)
7300     {
7301       info->button = event->button;
7302       info->time = event->time;
7303     }
7304   else
7305     {
7306       info->button = 0;
7307       info->time = gtk_get_current_event_time ();
7308     }
7309
7310   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
7311                                                             GDK_SELECTION_CLIPBOARD),
7312                                   gdk_atom_intern_static_string ("TARGETS"),
7313                                   popup_targets_received,
7314                                   info);
7315 }
7316
7317 static gboolean
7318 gtk_text_view_popup_menu (GtkWidget *widget)
7319 {
7320   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
7321   return TRUE;
7322 }
7323
7324 /* Child GdkWindows */
7325
7326
7327 static GtkTextWindow*
7328 text_window_new (GtkTextWindowType  type,
7329                  GtkWidget         *widget,
7330                  gint               width_request,
7331                  gint               height_request)
7332 {
7333   GtkTextWindow *win;
7334
7335   win = g_new (GtkTextWindow, 1);
7336
7337   win->type = type;
7338   win->widget = widget;
7339   win->window = NULL;
7340   win->bin_window = NULL;
7341   win->requisition.width = width_request;
7342   win->requisition.height = height_request;
7343   win->allocation.width = width_request;
7344   win->allocation.height = height_request;
7345   win->allocation.x = 0;
7346   win->allocation.y = 0;
7347
7348   return win;
7349 }
7350
7351 static void
7352 text_window_free (GtkTextWindow *win)
7353 {
7354   if (win->window)
7355     text_window_unrealize (win);
7356
7357   g_free (win);
7358 }
7359
7360 static void
7361 text_window_realize (GtkTextWindow *win,
7362                      GdkWindow     *parent)
7363 {
7364   GdkWindowAttr attributes;
7365   gint attributes_mask;
7366   GdkCursor *cursor;
7367
7368   attributes.window_type = GDK_WINDOW_CHILD;
7369   attributes.x = win->allocation.x;
7370   attributes.y = win->allocation.y;
7371   attributes.width = win->allocation.width;
7372   attributes.height = win->allocation.height;
7373   attributes.wclass = GDK_INPUT_OUTPUT;
7374   attributes.visual = gtk_widget_get_visual (win->widget);
7375   attributes.colormap = gtk_widget_get_colormap (win->widget);
7376   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
7377
7378   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
7379
7380   win->window = gdk_window_new (parent,
7381                                 &attributes,
7382                                 attributes_mask);
7383
7384   gdk_window_set_back_pixmap (win->window, NULL, FALSE);
7385   
7386   gdk_window_show (win->window);
7387   gdk_window_set_user_data (win->window, win->widget);
7388   gdk_window_lower (win->window);
7389
7390   attributes.x = 0;
7391   attributes.y = 0;
7392   attributes.width = win->allocation.width;
7393   attributes.height = win->allocation.height;
7394   attributes.event_mask = (GDK_EXPOSURE_MASK            |
7395                            GDK_SCROLL_MASK              |
7396                            GDK_KEY_PRESS_MASK           |
7397                            GDK_BUTTON_PRESS_MASK        |
7398                            GDK_BUTTON_RELEASE_MASK      |
7399                            GDK_POINTER_MOTION_MASK      |
7400                            GDK_POINTER_MOTION_HINT_MASK |
7401                            gtk_widget_get_events (win->widget));
7402
7403   win->bin_window = gdk_window_new (win->window,
7404                                     &attributes,
7405                                     attributes_mask);
7406
7407   gdk_window_show (win->bin_window);
7408   gdk_window_set_user_data (win->bin_window, win->widget);
7409
7410   if (win->type == GTK_TEXT_WINDOW_TEXT)
7411     {
7412       /* I-beam cursor */
7413       cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (parent),
7414                                            GDK_XTERM);
7415       gdk_window_set_cursor (win->bin_window, cursor);
7416       gdk_cursor_unref (cursor);
7417
7418       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
7419                                         win->window);
7420
7421
7422       gdk_window_set_background (win->bin_window,
7423                                  &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
7424     }
7425   else
7426     {
7427       gdk_window_set_background (win->bin_window,
7428                                  &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
7429     }
7430
7431   g_object_set_qdata (G_OBJECT (win->window),
7432                       g_quark_from_static_string ("gtk-text-view-text-window"),
7433                       win);
7434
7435   g_object_set_qdata (G_OBJECT (win->bin_window),
7436                       g_quark_from_static_string ("gtk-text-view-text-window"),
7437                       win);
7438 }
7439
7440 static void
7441 text_window_unrealize (GtkTextWindow *win)
7442 {
7443   if (win->type == GTK_TEXT_WINDOW_TEXT)
7444     {
7445       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
7446                                         NULL);
7447     }
7448
7449   gdk_window_set_user_data (win->window, NULL);
7450   gdk_window_set_user_data (win->bin_window, NULL);
7451   gdk_window_destroy (win->bin_window);
7452   gdk_window_destroy (win->window);
7453   win->window = NULL;
7454   win->bin_window = NULL;
7455 }
7456
7457 static void
7458 text_window_size_allocate (GtkTextWindow *win,
7459                            GdkRectangle  *rect)
7460 {
7461   win->allocation = *rect;
7462
7463   if (win->window)
7464     {
7465       gdk_window_move_resize (win->window,
7466                               rect->x, rect->y,
7467                               rect->width, rect->height);
7468
7469       gdk_window_resize (win->bin_window,
7470                          rect->width, rect->height);
7471     }
7472 }
7473
7474 static void
7475 text_window_scroll        (GtkTextWindow *win,
7476                            gint           dx,
7477                            gint           dy)
7478 {
7479   if (dx != 0 || dy != 0)
7480     {
7481       gdk_window_scroll (win->bin_window, dx, dy);
7482     }
7483 }
7484
7485 static void
7486 text_window_invalidate_rect (GtkTextWindow *win,
7487                              GdkRectangle  *rect)
7488 {
7489   GdkRectangle window_rect;
7490
7491   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
7492                                          win->type,
7493                                          rect->x,
7494                                          rect->y,
7495                                          &window_rect.x,
7496                                          &window_rect.y);
7497
7498   window_rect.width = rect->width;
7499   window_rect.height = rect->height;
7500   
7501   /* Adjust the rect as appropriate */
7502   
7503   switch (win->type)
7504     {
7505     case GTK_TEXT_WINDOW_TEXT:
7506       break;
7507
7508     case GTK_TEXT_WINDOW_LEFT:
7509     case GTK_TEXT_WINDOW_RIGHT:
7510       window_rect.x = 0;
7511       window_rect.width = win->allocation.width;
7512       break;
7513
7514     case GTK_TEXT_WINDOW_TOP:
7515     case GTK_TEXT_WINDOW_BOTTOM:
7516       window_rect.y = 0;
7517       window_rect.height = win->allocation.height;
7518       break;
7519
7520     default:
7521       g_warning ("%s: bug!", G_STRLOC);
7522       return;
7523       break;
7524     }
7525           
7526   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
7527
7528 #if 0
7529   {
7530     cairo_t *cr = gdk_cairo_create (win->bin_window);
7531     gdk_cairo_rectangle (cr, &window_rect);
7532     cairo_set_source_rgb  (cr, 1.0, 0.0, 0.0);  /* red */
7533     cairo_fill (cr);
7534     cairo_destroy (cr);
7535   }
7536 #endif
7537 }
7538
7539 static void
7540 text_window_invalidate_cursors (GtkTextWindow *win)
7541 {
7542   GtkTextView *text_view = GTK_TEXT_VIEW (win->widget);
7543   GtkTextIter  iter;
7544   GdkRectangle strong;
7545   GdkRectangle weak;
7546   gboolean     draw_arrow;
7547   gfloat       cursor_aspect_ratio;
7548   gint         stem_width;
7549   gint         arrow_width;
7550
7551   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
7552                                     gtk_text_buffer_get_insert (text_view->buffer));
7553
7554   gtk_text_layout_get_cursor_locations (text_view->layout, &iter,
7555                                         &strong, &weak);
7556
7557   /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
7558    * ignoring the text direction be exposing both sides of the cursor
7559    */
7560
7561   draw_arrow = (strong.x != weak.x || strong.y != weak.y);
7562
7563   gtk_widget_style_get (win->widget,
7564                         "cursor-aspect-ratio", &cursor_aspect_ratio,
7565                         NULL);
7566   
7567   stem_width = strong.height * cursor_aspect_ratio + 1;
7568   arrow_width = stem_width + 1;
7569
7570   strong.width = stem_width;
7571
7572   /* round up to the next even number */
7573   if (stem_width & 1)
7574     stem_width++;
7575
7576   strong.x     -= stem_width / 2;
7577   strong.width += stem_width;
7578
7579   if (draw_arrow)
7580     {
7581       strong.x     -= arrow_width;
7582       strong.width += arrow_width * 2;
7583     }
7584
7585   text_window_invalidate_rect (win, &strong);
7586
7587   if (draw_arrow) /* == have weak */
7588     {
7589       stem_width = weak.height * cursor_aspect_ratio + 1;
7590       arrow_width = stem_width + 1;
7591
7592       weak.width = stem_width;
7593
7594       /* round up to the next even number */
7595       if (stem_width & 1)
7596         stem_width++;
7597
7598       weak.x     -= stem_width / 2;
7599       weak.width += stem_width;
7600
7601       weak.x     -= arrow_width;
7602       weak.width += arrow_width * 2;
7603
7604       text_window_invalidate_rect (win, &weak);
7605     }
7606 }
7607
7608 static gint
7609 text_window_get_width (GtkTextWindow *win)
7610 {
7611   return win->allocation.width;
7612 }
7613
7614 static gint
7615 text_window_get_height (GtkTextWindow *win)
7616 {
7617   return win->allocation.height;
7618 }
7619
7620 /* Windows */
7621
7622
7623 /**
7624  * gtk_text_view_get_window:
7625  * @text_view: a #GtkTextView
7626  * @win: window to get
7627  *
7628  * Retrieves the #GdkWindow corresponding to an area of the text view;
7629  * possible windows include the overall widget window, child windows
7630  * on the left, right, top, bottom, and the window that displays the
7631  * text buffer. Windows are %NULL and nonexistent if their width or
7632  * height is 0, and are nonexistent before the widget has been
7633  * realized.
7634  *
7635  * Return value: a #GdkWindow, or %NULL
7636  **/
7637 GdkWindow*
7638 gtk_text_view_get_window (GtkTextView *text_view,
7639                           GtkTextWindowType win)
7640 {
7641   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7642
7643   switch (win)
7644     {
7645     case GTK_TEXT_WINDOW_WIDGET:
7646       return GTK_WIDGET (text_view)->window;
7647       break;
7648
7649     case GTK_TEXT_WINDOW_TEXT:
7650       return text_view->text_window->bin_window;
7651       break;
7652
7653     case GTK_TEXT_WINDOW_LEFT:
7654       if (text_view->left_window)
7655         return text_view->left_window->bin_window;
7656       else
7657         return NULL;
7658       break;
7659
7660     case GTK_TEXT_WINDOW_RIGHT:
7661       if (text_view->right_window)
7662         return text_view->right_window->bin_window;
7663       else
7664         return NULL;
7665       break;
7666
7667     case GTK_TEXT_WINDOW_TOP:
7668       if (text_view->top_window)
7669         return text_view->top_window->bin_window;
7670       else
7671         return NULL;
7672       break;
7673
7674     case GTK_TEXT_WINDOW_BOTTOM:
7675       if (text_view->bottom_window)
7676         return text_view->bottom_window->bin_window;
7677       else
7678         return NULL;
7679       break;
7680
7681     case GTK_TEXT_WINDOW_PRIVATE:
7682       g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_GNUC_FUNCTION);
7683       return NULL;
7684       break;
7685     }
7686
7687   g_warning ("%s: Unknown GtkTextWindowType", G_GNUC_FUNCTION);
7688   return NULL;
7689 }
7690
7691 /**
7692  * gtk_text_view_get_window_type:
7693  * @text_view: a #GtkTextView
7694  * @window: a window type
7695  *
7696  * Usually used to find out which window an event corresponds to.
7697  * If you connect to an event signal on @text_view, this function
7698  * should be called on <literal>event-&gt;window</literal> to
7699  * see which window it was.
7700  *
7701  * Return value: the window type.
7702  **/
7703 GtkTextWindowType
7704 gtk_text_view_get_window_type (GtkTextView *text_view,
7705                                GdkWindow   *window)
7706 {
7707   GtkTextWindow *win;
7708
7709   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
7710   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
7711
7712   if (window == GTK_WIDGET (text_view)->window)
7713     return GTK_TEXT_WINDOW_WIDGET;
7714
7715   win = g_object_get_qdata (G_OBJECT (window),
7716                             g_quark_try_string ("gtk-text-view-text-window"));
7717
7718   if (win)
7719     return win->type;
7720   else
7721     {
7722       return GTK_TEXT_WINDOW_PRIVATE;
7723     }
7724 }
7725
7726 static void
7727 buffer_to_widget (GtkTextView      *text_view,
7728                   gint              buffer_x,
7729                   gint              buffer_y,
7730                   gint             *window_x,
7731                   gint             *window_y)
7732 {  
7733   if (window_x)
7734     {
7735       *window_x = buffer_x - text_view->xoffset;
7736       *window_x += text_view->text_window->allocation.x;
7737     }
7738
7739   if (window_y)
7740     {
7741       *window_y = buffer_y - text_view->yoffset;
7742       *window_y += text_view->text_window->allocation.y;
7743     }
7744 }
7745
7746 static void
7747 widget_to_text_window (GtkTextWindow *win,
7748                        gint           widget_x,
7749                        gint           widget_y,
7750                        gint          *window_x,
7751                        gint          *window_y)
7752 {
7753   if (window_x)
7754     *window_x = widget_x - win->allocation.x;
7755
7756   if (window_y)
7757     *window_y = widget_y - win->allocation.y;
7758 }
7759
7760 static void
7761 buffer_to_text_window (GtkTextView   *text_view,
7762                        GtkTextWindow *win,
7763                        gint           buffer_x,
7764                        gint           buffer_y,
7765                        gint          *window_x,
7766                        gint          *window_y)
7767 {
7768   if (win == NULL)
7769     {
7770       g_warning ("Attempt to convert text buffer coordinates to coordinates "
7771                  "for a nonexistent or private child window of GtkTextView");
7772       return;
7773     }
7774
7775   buffer_to_widget (text_view,
7776                     buffer_x, buffer_y,
7777                     window_x, window_y);
7778
7779   widget_to_text_window (win,
7780                          window_x ? *window_x : 0,
7781                          window_y ? *window_y : 0,
7782                          window_x,
7783                          window_y);
7784 }
7785
7786 /**
7787  * gtk_text_view_buffer_to_window_coords:
7788  * @text_view: a #GtkTextView
7789  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
7790  * @buffer_x: buffer x coordinate
7791  * @buffer_y: buffer y coordinate
7792  * @window_x: window x coordinate return location
7793  * @window_y: window y coordinate return location
7794  *
7795  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
7796  * @win, and stores the result in (@window_x, @window_y). 
7797  *
7798  * Note that you can't convert coordinates for a nonexisting window (see 
7799  * gtk_text_view_set_border_window_size()).
7800  **/
7801 void
7802 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
7803                                        GtkTextWindowType win,
7804                                        gint              buffer_x,
7805                                        gint              buffer_y,
7806                                        gint             *window_x,
7807                                        gint             *window_y)
7808 {
7809   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7810
7811   switch (win)
7812     {
7813     case GTK_TEXT_WINDOW_WIDGET:
7814       buffer_to_widget (text_view,
7815                         buffer_x, buffer_y,
7816                         window_x, window_y);
7817       break;
7818
7819     case GTK_TEXT_WINDOW_TEXT:
7820       if (window_x)
7821         *window_x = buffer_x - text_view->xoffset;
7822       if (window_y)
7823         *window_y = buffer_y - text_view->yoffset;
7824       break;
7825
7826     case GTK_TEXT_WINDOW_LEFT:
7827       buffer_to_text_window (text_view,
7828                              text_view->left_window,
7829                              buffer_x, buffer_y,
7830                              window_x, window_y);
7831       break;
7832
7833     case GTK_TEXT_WINDOW_RIGHT:
7834       buffer_to_text_window (text_view,
7835                              text_view->right_window,
7836                              buffer_x, buffer_y,
7837                              window_x, window_y);
7838       break;
7839
7840     case GTK_TEXT_WINDOW_TOP:
7841       buffer_to_text_window (text_view,
7842                              text_view->top_window,
7843                              buffer_x, buffer_y,
7844                              window_x, window_y);
7845       break;
7846
7847     case GTK_TEXT_WINDOW_BOTTOM:
7848       buffer_to_text_window (text_view,
7849                              text_view->bottom_window,
7850                              buffer_x, buffer_y,
7851                              window_x, window_y);
7852       break;
7853
7854     case GTK_TEXT_WINDOW_PRIVATE:
7855       g_warning ("%s: can't get coords for private windows", G_STRLOC);
7856       break;
7857
7858     default:
7859       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
7860       break;
7861     }
7862 }
7863
7864 static void
7865 widget_to_buffer (GtkTextView *text_view,
7866                   gint         widget_x,
7867                   gint         widget_y,
7868                   gint        *buffer_x,
7869                   gint        *buffer_y)
7870 {  
7871   if (buffer_x)
7872     {
7873       *buffer_x = widget_x + text_view->xoffset;
7874       *buffer_x -= text_view->text_window->allocation.x;
7875     }
7876
7877   if (buffer_y)
7878     {
7879       *buffer_y = widget_y + text_view->yoffset;
7880       *buffer_y -= text_view->text_window->allocation.y;
7881     }
7882 }
7883
7884 static void
7885 text_window_to_widget (GtkTextWindow *win,
7886                        gint           window_x,
7887                        gint           window_y,
7888                        gint          *widget_x,
7889                        gint          *widget_y)
7890 {
7891   if (widget_x)
7892     *widget_x = window_x + win->allocation.x;
7893
7894   if (widget_y)
7895     *widget_y = window_y + win->allocation.y;
7896 }
7897
7898 static void
7899 text_window_to_buffer (GtkTextView   *text_view,
7900                        GtkTextWindow *win,
7901                        gint           window_x,
7902                        gint           window_y,
7903                        gint          *buffer_x,
7904                        gint          *buffer_y)
7905 {
7906   if (win == NULL)
7907     {
7908       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
7909                  "coordinates for a nonexistent child window.");
7910       return;
7911     }
7912
7913   text_window_to_widget (win,
7914                          window_x,
7915                          window_y,
7916                          buffer_x,
7917                          buffer_y);
7918
7919   widget_to_buffer (text_view,
7920                     buffer_x ? *buffer_x : 0,
7921                     buffer_y ? *buffer_y : 0,
7922                     buffer_x,
7923                     buffer_y);
7924 }
7925
7926 /**
7927  * gtk_text_view_window_to_buffer_coords:
7928  * @text_view: a #GtkTextView
7929  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
7930  * @window_x: window x coordinate
7931  * @window_y: window y coordinate
7932  * @buffer_x: buffer x coordinate return location
7933  * @buffer_y: buffer y coordinate return location
7934  *
7935  * Converts coordinates on the window identified by @win to buffer
7936  * coordinates, storing the result in (@buffer_x,@buffer_y).
7937  *
7938  * Note that you can't convert coordinates for a nonexisting window (see 
7939  * gtk_text_view_set_border_window_size()).
7940  **/
7941 void
7942 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
7943                                        GtkTextWindowType win,
7944                                        gint              window_x,
7945                                        gint              window_y,
7946                                        gint             *buffer_x,
7947                                        gint             *buffer_y)
7948 {
7949   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
7950
7951   switch (win)
7952     {
7953     case GTK_TEXT_WINDOW_WIDGET:
7954       widget_to_buffer (text_view,
7955                         window_x, window_y,
7956                         buffer_x, buffer_y);
7957       break;
7958
7959     case GTK_TEXT_WINDOW_TEXT:
7960       if (buffer_x)
7961         *buffer_x = window_x + text_view->xoffset;
7962       if (buffer_y)
7963         *buffer_y = window_y + text_view->yoffset;
7964       break;
7965
7966     case GTK_TEXT_WINDOW_LEFT:
7967       text_window_to_buffer (text_view,
7968                              text_view->left_window,
7969                              window_x, window_y,
7970                              buffer_x, buffer_y);
7971       break;
7972
7973     case GTK_TEXT_WINDOW_RIGHT:
7974       text_window_to_buffer (text_view,
7975                              text_view->right_window,
7976                              window_x, window_y,
7977                              buffer_x, buffer_y);
7978       break;
7979
7980     case GTK_TEXT_WINDOW_TOP:
7981       text_window_to_buffer (text_view,
7982                              text_view->top_window,
7983                              window_x, window_y,
7984                              buffer_x, buffer_y);
7985       break;
7986
7987     case GTK_TEXT_WINDOW_BOTTOM:
7988       text_window_to_buffer (text_view,
7989                              text_view->bottom_window,
7990                              window_x, window_y,
7991                              buffer_x, buffer_y);
7992       break;
7993
7994     case GTK_TEXT_WINDOW_PRIVATE:
7995       g_warning ("%s: can't get coords for private windows", G_STRLOC);
7996       break;
7997
7998     default:
7999       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
8000       break;
8001     }
8002 }
8003
8004 static void
8005 set_window_width (GtkTextView      *text_view,
8006                   gint              width,
8007                   GtkTextWindowType type,
8008                   GtkTextWindow   **winp)
8009 {
8010   if (width == 0)
8011     {
8012       if (*winp)
8013         {
8014           text_window_free (*winp);
8015           *winp = NULL;
8016           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8017         }
8018     }
8019   else
8020     {
8021       if (*winp == NULL)
8022         {
8023           *winp = text_window_new (type,
8024                                    GTK_WIDGET (text_view),
8025                                    width, 0);
8026           /* if the widget is already realized we need to realize the child manually */
8027           if (GTK_WIDGET_REALIZED (text_view))
8028             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
8029         }
8030       else
8031         {
8032           if ((*winp)->requisition.width == width)
8033             return;
8034
8035           (*winp)->requisition.width = width;
8036         }
8037
8038       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8039     }
8040 }
8041
8042
8043 static void
8044 set_window_height (GtkTextView      *text_view,
8045                    gint              height,
8046                    GtkTextWindowType type,
8047                    GtkTextWindow   **winp)
8048 {
8049   if (height == 0)
8050     {
8051       if (*winp)
8052         {
8053           text_window_free (*winp);
8054           *winp = NULL;
8055           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8056         }
8057     }
8058   else
8059     {
8060       if (*winp == NULL)
8061         {
8062           *winp = text_window_new (type,
8063                                    GTK_WIDGET (text_view),
8064                                    0, height);
8065
8066           /* if the widget is already realized we need to realize the child manually */
8067           if (GTK_WIDGET_REALIZED (text_view))
8068             text_window_realize (*winp, GTK_WIDGET (text_view)->window);
8069         }
8070       else
8071         {
8072           if ((*winp)->requisition.height == height)
8073             return;
8074
8075           (*winp)->requisition.height = height;
8076         }
8077
8078       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8079     }
8080 }
8081
8082 /**
8083  * gtk_text_view_set_border_window_size:
8084  * @text_view: a #GtkTextView
8085  * @type: window to affect
8086  * @size: width or height of the window
8087  *
8088  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
8089  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
8090  * Automatically destroys the corresponding window if the size is set
8091  * to 0, and creates the window if the size is set to non-zero.  This
8092  * function can only be used for the "border windows," it doesn't work
8093  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
8094  * #GTK_TEXT_WINDOW_PRIVATE.
8095  **/
8096 void
8097 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
8098                                       GtkTextWindowType type,
8099                                       gint              size)
8100
8101 {
8102   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8103   g_return_if_fail (size >= 0);
8104
8105   switch (type)
8106     {
8107     case GTK_TEXT_WINDOW_LEFT:
8108       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
8109                         &text_view->left_window);
8110       break;
8111
8112     case GTK_TEXT_WINDOW_RIGHT:
8113       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
8114                         &text_view->right_window);
8115       break;
8116
8117     case GTK_TEXT_WINDOW_TOP:
8118       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
8119                          &text_view->top_window);
8120       break;
8121
8122     case GTK_TEXT_WINDOW_BOTTOM:
8123       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
8124                          &text_view->bottom_window);
8125       break;
8126
8127     default:
8128       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
8129       break;
8130     }
8131 }
8132
8133 /**
8134  * gtk_text_view_get_border_window_size:
8135  * @text_view: a #GtkTextView
8136  * @type: window to return size from
8137  *
8138  * Gets the width of the specified border window. See
8139  * gtk_text_view_set_border_window_size().
8140  *
8141  * Return value: width of window
8142  **/
8143 gint
8144 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
8145                                       GtkTextWindowType  type)
8146 {
8147   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8148   
8149   switch (type)
8150     {
8151     case GTK_TEXT_WINDOW_LEFT:
8152       if (text_view->left_window)
8153         return text_view->left_window->requisition.width;
8154       break;
8155       
8156     case GTK_TEXT_WINDOW_RIGHT:
8157       if (text_view->right_window)
8158         return text_view->right_window->requisition.width;
8159       break;
8160       
8161     case GTK_TEXT_WINDOW_TOP:
8162       if (text_view->top_window)
8163         return text_view->top_window->requisition.height;
8164       break;
8165
8166     case GTK_TEXT_WINDOW_BOTTOM:
8167       if (text_view->bottom_window)
8168         return text_view->bottom_window->requisition.height;
8169       break;
8170       
8171     default:
8172       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
8173       break;
8174     }
8175
8176   return 0;
8177 }
8178
8179 /*
8180  * Child widgets
8181  */
8182
8183 static GtkTextViewChild*
8184 text_view_child_new_anchored (GtkWidget          *child,
8185                               GtkTextChildAnchor *anchor,
8186                               GtkTextLayout      *layout)
8187 {
8188   GtkTextViewChild *vc;
8189
8190   vc = g_new (GtkTextViewChild, 1);
8191
8192   vc->type = GTK_TEXT_WINDOW_PRIVATE;
8193   vc->widget = child;
8194   vc->anchor = anchor;
8195
8196   vc->from_top_of_line = 0;
8197   vc->from_left_of_buffer = 0;
8198   
8199   g_object_ref (vc->widget);
8200   g_object_ref (vc->anchor);
8201
8202   g_object_set_data (G_OBJECT (child),
8203                      I_("gtk-text-view-child"),
8204                      vc);
8205
8206   gtk_text_child_anchor_register_child (anchor, child, layout);
8207   
8208   return vc;
8209 }
8210
8211 static GtkTextViewChild*
8212 text_view_child_new_window (GtkWidget          *child,
8213                             GtkTextWindowType   type,
8214                             gint                x,
8215                             gint                y)
8216 {
8217   GtkTextViewChild *vc;
8218
8219   vc = g_new (GtkTextViewChild, 1);
8220
8221   vc->widget = child;
8222   vc->anchor = NULL;
8223
8224   vc->from_top_of_line = 0;
8225   vc->from_left_of_buffer = 0;
8226  
8227   g_object_ref (vc->widget);
8228
8229   vc->type = type;
8230   vc->x = x;
8231   vc->y = y;
8232
8233   g_object_set_data (G_OBJECT (child),
8234                      I_("gtk-text-view-child"),
8235                      vc);
8236   
8237   return vc;
8238 }
8239
8240 static void
8241 text_view_child_free (GtkTextViewChild *child)
8242 {
8243   g_object_set_data (G_OBJECT (child->widget),
8244                      I_("gtk-text-view-child"), NULL);
8245
8246   if (child->anchor)
8247     {
8248       gtk_text_child_anchor_unregister_child (child->anchor,
8249                                               child->widget);
8250       g_object_unref (child->anchor);
8251     }
8252
8253   g_object_unref (child->widget);
8254
8255   g_free (child);
8256 }
8257
8258 static void
8259 text_view_child_set_parent_window (GtkTextView      *text_view,
8260                                    GtkTextViewChild *vc)
8261 {
8262   if (vc->anchor)
8263     gtk_widget_set_parent_window (vc->widget,
8264                                   text_view->text_window->bin_window);
8265   else
8266     {
8267       GdkWindow *window;
8268       window = gtk_text_view_get_window (text_view,
8269                                          vc->type);
8270       gtk_widget_set_parent_window (vc->widget, window);
8271     }
8272 }
8273
8274 static void
8275 add_child (GtkTextView      *text_view,
8276            GtkTextViewChild *vc)
8277 {
8278   text_view->children = g_slist_prepend (text_view->children,
8279                                          vc);
8280
8281   if (GTK_WIDGET_REALIZED (text_view))
8282     text_view_child_set_parent_window (text_view, vc);
8283   
8284   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
8285 }
8286
8287 /**
8288  * gtk_text_view_add_child_at_anchor:
8289  * @text_view: a #GtkTextView
8290  * @child: a #GtkWidget
8291  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
8292  * 
8293  * Adds a child widget in the text buffer, at the given @anchor.
8294  * 
8295  **/
8296 void
8297 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
8298                                    GtkWidget            *child,
8299                                    GtkTextChildAnchor   *anchor)
8300 {
8301   GtkTextViewChild *vc;
8302
8303   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8304   g_return_if_fail (GTK_IS_WIDGET (child));
8305   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
8306   g_return_if_fail (child->parent == NULL);
8307
8308   gtk_text_view_ensure_layout (text_view);
8309
8310   vc = text_view_child_new_anchored (child, anchor,
8311                                      text_view->layout);
8312
8313   add_child (text_view, vc);
8314
8315   g_assert (vc->widget == child);
8316   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8317 }
8318
8319 /**
8320  * gtk_text_view_add_child_in_window:
8321  * @text_view: a #GtkTextView
8322  * @child: a #GtkWidget
8323  * @which_window: which window the child should appear in
8324  * @xpos: X position of child in window coordinates
8325  * @ypos: Y position of child in window coordinates
8326  *
8327  * Adds a child at fixed coordinates in one of the text widget's
8328  * windows.  The window must have nonzero size (see
8329  * gtk_text_view_set_border_window_size()).  Note that the child
8330  * coordinates are given relative to the #GdkWindow in question, and
8331  * that these coordinates have no sane relationship to scrolling. When
8332  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
8333  * irrelevant, the child floats above all scrollable areas. But when
8334  * placing a child in one of the scrollable windows (border windows or
8335  * text window), you'll need to compute the child's correct position
8336  * in buffer coordinates any time scrolling occurs or buffer changes
8337  * occur, and then call gtk_text_view_move_child() to update the
8338  * child's position. Unfortunately there's no good way to detect that
8339  * scrolling has occurred, using the current API; a possible hack
8340  * would be to update all child positions when the scroll adjustments
8341  * change or the text buffer changes. See bug 64518 on
8342  * bugzilla.gnome.org for status of fixing this issue.
8343  *
8344  **/
8345 void
8346 gtk_text_view_add_child_in_window (GtkTextView          *text_view,
8347                                    GtkWidget            *child,
8348                                    GtkTextWindowType     which_window,
8349                                    gint                  xpos,
8350                                    gint                  ypos)
8351 {
8352   GtkTextViewChild *vc;
8353
8354   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8355   g_return_if_fail (GTK_IS_WIDGET (child));
8356   g_return_if_fail (child->parent == NULL);
8357
8358   vc = text_view_child_new_window (child, which_window,
8359                                    xpos, ypos);
8360
8361   add_child (text_view, vc);
8362
8363   g_assert (vc->widget == child);
8364   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8365 }
8366
8367 /**
8368  * gtk_text_view_move_child:
8369  * @text_view: a #GtkTextView
8370  * @child: child widget already added to the text view
8371  * @xpos: new X position in window coordinates
8372  * @ypos: new Y position in window coordinates
8373  *
8374  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
8375  * 
8376  **/
8377 void
8378 gtk_text_view_move_child          (GtkTextView          *text_view,
8379                                    GtkWidget            *child,
8380                                    gint                  xpos,
8381                                    gint                  ypos)
8382 {
8383   GtkTextViewChild *vc;
8384
8385   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8386   g_return_if_fail (GTK_IS_WIDGET (child));
8387   g_return_if_fail (child->parent == (GtkWidget*) text_view);
8388
8389   vc = g_object_get_data (G_OBJECT (child),
8390                           "gtk-text-view-child");
8391
8392   g_assert (vc != NULL);
8393
8394   if (vc->x == xpos &&
8395       vc->y == ypos)
8396     return;
8397   
8398   vc->x = xpos;
8399   vc->y = ypos;
8400
8401   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
8402     gtk_widget_queue_resize (child);
8403 }
8404
8405
8406 /* Iterator operations */
8407
8408 /**
8409  * gtk_text_view_forward_display_line:
8410  * @text_view: a #GtkTextView
8411  * @iter: a #GtkTextIter
8412  * 
8413  * Moves the given @iter forward by one display (wrapped) line.  A
8414  * display line is different from a paragraph. Paragraphs are
8415  * separated by newlines or other paragraph separator characters.
8416  * Display lines are created by line-wrapping a paragraph.  If
8417  * wrapping is turned off, display lines and paragraphs will be the
8418  * same. Display lines are divided differently for each view, since
8419  * they depend on the view's width; paragraphs are the same in all
8420  * views, since they depend on the contents of the #GtkTextBuffer.
8421  * 
8422  * Return value: %TRUE if @iter was moved and is not on the end iterator
8423  **/
8424 gboolean
8425 gtk_text_view_forward_display_line (GtkTextView *text_view,
8426                                     GtkTextIter *iter)
8427 {
8428   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8429   g_return_val_if_fail (iter != NULL, FALSE);
8430
8431   gtk_text_view_ensure_layout (text_view);
8432
8433   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
8434 }
8435
8436 /**
8437  * gtk_text_view_backward_display_line:
8438  * @text_view: a #GtkTextView
8439  * @iter: a #GtkTextIter
8440  * 
8441  * Moves the given @iter backward by one display (wrapped) line.  A
8442  * display line is different from a paragraph. Paragraphs are
8443  * separated by newlines or other paragraph separator characters.
8444  * Display lines are created by line-wrapping a paragraph.  If
8445  * wrapping is turned off, display lines and paragraphs will be the
8446  * same. Display lines are divided differently for each view, since
8447  * they depend on the view's width; paragraphs are the same in all
8448  * views, since they depend on the contents of the #GtkTextBuffer.
8449  * 
8450  * Return value: %TRUE if @iter was moved and is not on the end iterator
8451  **/
8452 gboolean
8453 gtk_text_view_backward_display_line (GtkTextView *text_view,
8454                                      GtkTextIter *iter)
8455 {
8456   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8457   g_return_val_if_fail (iter != NULL, FALSE);
8458
8459   gtk_text_view_ensure_layout (text_view);
8460
8461   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
8462 }
8463
8464 /**
8465  * gtk_text_view_forward_display_line_end:
8466  * @text_view: a #GtkTextView
8467  * @iter: a #GtkTextIter
8468  * 
8469  * Moves the given @iter forward to the next display line end.  A
8470  * display line is different from a paragraph. Paragraphs are
8471  * separated by newlines or other paragraph separator characters.
8472  * Display lines are created by line-wrapping a paragraph.  If
8473  * wrapping is turned off, display lines and paragraphs will be the
8474  * same. Display lines are divided differently for each view, since
8475  * they depend on the view's width; paragraphs are the same in all
8476  * views, since they depend on the contents of the #GtkTextBuffer.
8477  * 
8478  * Return value: %TRUE if @iter was moved and is not on the end iterator
8479  **/
8480 gboolean
8481 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
8482                                         GtkTextIter *iter)
8483 {
8484   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8485   g_return_val_if_fail (iter != NULL, FALSE);
8486
8487   gtk_text_view_ensure_layout (text_view);
8488
8489   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
8490 }
8491
8492 /**
8493  * gtk_text_view_backward_display_line_start:
8494  * @text_view: a #GtkTextView
8495  * @iter: a #GtkTextIter
8496  * 
8497  * Moves the given @iter backward to the next display line start.  A
8498  * display line is different from a paragraph. Paragraphs are
8499  * separated by newlines or other paragraph separator characters.
8500  * Display lines are created by line-wrapping a paragraph.  If
8501  * wrapping is turned off, display lines and paragraphs will be the
8502  * same. Display lines are divided differently for each view, since
8503  * they depend on the view's width; paragraphs are the same in all
8504  * views, since they depend on the contents of the #GtkTextBuffer.
8505  * 
8506  * Return value: %TRUE if @iter was moved and is not on the end iterator
8507  **/
8508 gboolean
8509 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
8510                                            GtkTextIter *iter)
8511 {
8512   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8513   g_return_val_if_fail (iter != NULL, FALSE);
8514
8515   gtk_text_view_ensure_layout (text_view);
8516
8517   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
8518 }
8519
8520 /**
8521  * gtk_text_view_starts_display_line:
8522  * @text_view: a #GtkTextView
8523  * @iter: a #GtkTextIter
8524  * 
8525  * Determines whether @iter is at the start of a display line.
8526  * See gtk_text_view_forward_display_line() for an explanation of
8527  * display lines vs. paragraphs.
8528  * 
8529  * Return value: %TRUE if @iter begins a wrapped line
8530  **/
8531 gboolean
8532 gtk_text_view_starts_display_line (GtkTextView       *text_view,
8533                                    const GtkTextIter *iter)
8534 {
8535   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8536   g_return_val_if_fail (iter != NULL, FALSE);
8537
8538   gtk_text_view_ensure_layout (text_view);
8539
8540   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
8541 }
8542
8543 /**
8544  * gtk_text_view_move_visually:
8545  * @text_view: a #GtkTextView
8546  * @iter: a #GtkTextIter
8547  * @count:   number of characters to move (negative moves left, positive moves right)
8548  *
8549  * Move the iterator a given number of characters visually, treating
8550  * it as the strong cursor position. If @count is positive, then the
8551  * new strong cursor position will be @count positions to the right of
8552  * the old cursor position. If @count is negative then the new strong
8553  * cursor position will be @count positions to the left of the old
8554  * cursor position.
8555  *
8556  * In the presence of bidirection text, the correspondence
8557  * between logical and visual order will depend on the direction
8558  * of the current run, and there may be jumps when the cursor
8559  * is moved off of the end of a run.
8560  * 
8561  * Return value: %TRUE if @iter moved and is not on the end iterator
8562  **/
8563 gboolean
8564 gtk_text_view_move_visually (GtkTextView *text_view,
8565                              GtkTextIter *iter,
8566                              gint         count)
8567 {
8568   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8569   g_return_val_if_fail (iter != NULL, FALSE);
8570
8571   gtk_text_view_ensure_layout (text_view);
8572
8573   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
8574 }
8575
8576 #define __GTK_TEXT_VIEW_C__
8577 #include "gtkaliasdef.c"