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