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