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