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