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