]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
Fix bug #486369, by passing the selection info along when pasting.
[~andy/gtk] / gtk / gtktextview.c
1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3  * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26  */
27
28 #include <config.h>
29 #include <string.h>
30
31 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
32 #include "gtkbindings.h"
33 #include "gtkdnd.h"
34 #include "gtkimagemenuitem.h"
35 #include "gtkintl.h"
36 #include "gtkmain.h"
37 #include "gtkmarshalers.h"
38 #include "gtkmenu.h"
39 #include "gtkmenuitem.h"
40 #include "gtkseparatormenuitem.h"
41 #include "gtksettings.h"
42 #include "gtkstock.h"
43 #include "gtktextbufferrichtext.h"
44 #include "gtktextdisplay.h"
45 #include "gtktextview.h"
46 #include "gtkimmulticontext.h"
47 #include "gdk/gdkkeysyms.h"
48 #include "gtkprivate.h"
49 #include "gtktextutil.h"
50 #include "gtkwindow.h"
51 #include "gtkalias.h"
52
53 /* How scrolling, validation, exposes, etc. work.
54  *
55  * The expose_event handler has the invariant that the onscreen lines
56  * have been validated.
57  *
58  * There are two ways that onscreen lines can become invalid. The first
59  * is to change which lines are onscreen. This happens when the value
60  * of a scroll adjustment changes. So the code path begins in
61  * gtk_text_view_value_changed() and goes like this:
62  *   - gdk_window_scroll() to reflect the new adjustment value
63  *   - validate the lines that were moved onscreen
64  *   - gdk_window_process_updates() to handle the exposes immediately
65  *
66  * The second way is that you get the "invalidated" signal from the layout,
67  * indicating that lines have become invalid. This code path begins in
68  * invalidated_handler() and goes like this:
69  *   - install high-priority idle which does the rest of the steps
70  *   - if a scroll is pending from scroll_to_mark(), do the scroll,
71  *     jumping to the gtk_text_view_value_changed() code path
72  *   - otherwise, validate the onscreen lines
73  *   - DO NOT process updates
74  *
75  * In both cases, validating the onscreen lines can trigger a scroll
76  * due to maintaining the first_para on the top of the screen.
77  * If validation triggers a scroll, we jump to the top of the code path
78  * for value_changed, and bail out of the current code path.
79  *
80  * Also, in size_allocate, if we invalidate some lines from changing
81  * the layout width, we need to go ahead and run the high-priority idle,
82  * because GTK sends exposes right after doing the size allocates without
83  * returning to the main loop. This is also why the high-priority idle
84  * is at a higher priority than resizing.
85  *
86  */
87
88 #if 0
89 #define DEBUG_VALIDATION_AND_SCROLLING
90 #endif
91
92 #ifdef DEBUG_VALIDATION_AND_SCROLLING
93 #define DV(x) (x)
94 #else
95 #define DV(x)
96 #endif
97
98 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
99 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
100
101 #define SPACE_FOR_CURSOR 1
102
103 typedef struct _GtkTextViewPrivate GtkTextViewPrivate;
104
105 #define GTK_TEXT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_VIEW, GtkTextViewPrivate))
106
107 struct _GtkTextViewPrivate 
108 {
109   guint blink_time;  /* time in msec the cursor has blinked since last user event */
110 };
111
112
113 struct _GtkTextPendingScroll
114 {
115   GtkTextMark   *mark;
116   gdouble        within_margin;
117   gboolean       use_align;
118   gdouble        xalign;
119   gdouble        yalign;
120 };
121   
122 enum
123 {
124   SET_SCROLL_ADJUSTMENTS,
125   POPULATE_POPUP,
126   MOVE_CURSOR,
127   PAGE_HORIZONTALLY,
128   SET_ANCHOR,
129   INSERT_AT_CURSOR,
130   DELETE_FROM_CURSOR,
131   BACKSPACE,
132   CUT_CLIPBOARD,
133   COPY_CLIPBOARD,
134   PASTE_CLIPBOARD,
135   TOGGLE_OVERWRITE,
136   MOVE_VIEWPORT,
137   SELECT_ALL,
138   TOGGLE_CURSOR_VISIBLE,
139   LAST_SIGNAL
140 };
141
142 enum
143 {
144   PROP_0,
145   PROP_PIXELS_ABOVE_LINES,
146   PROP_PIXELS_BELOW_LINES,
147   PROP_PIXELS_INSIDE_WRAP,
148   PROP_EDITABLE,
149   PROP_WRAP_MODE,
150   PROP_JUSTIFICATION,
151   PROP_LEFT_MARGIN,
152   PROP_RIGHT_MARGIN,
153   PROP_INDENT,
154   PROP_TABS,
155   PROP_CURSOR_VISIBLE,
156   PROP_BUFFER,
157   PROP_OVERWRITE,
158   PROP_ACCEPTS_TAB,
159   LAST_PROP
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 /**
1995  * gtk_text_view_scroll_to_mark:
1996  * @text_view: a #GtkTextView
1997  * @mark: a #GtkTextMark
1998  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1999  * @use_align: whether to use alignment arguments (if %FALSE, just 
2000  *    get the mark onscreen)
2001  * @xalign: horizontal alignment of mark within visible area
2002  * @yalign: vertical alignment of mark within visible area
2003  *
2004  * Scrolls @text_view so that @mark is on the screen in the position
2005  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
2006  * left or top, 1.0 indicates right or bottom, 0.5 means center. 
2007  * If @use_align is %FALSE, the text scrolls the minimal distance to 
2008  * get the mark onscreen, possibly not scrolling at all. The effective 
2009  * screen for purposes of this function is reduced by a margin of size 
2010  * @within_margin.
2011  **/
2012 void
2013 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
2014                               GtkTextMark *mark,
2015                               gdouble      within_margin,
2016                               gboolean     use_align,
2017                               gdouble      xalign,
2018                               gdouble      yalign)
2019 {  
2020   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2021   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2022   g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5);
2023   g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
2024   g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
2025
2026   gtk_text_view_queue_scroll (text_view, mark,
2027                               within_margin,
2028                               use_align,
2029                               xalign,
2030                               yalign);
2031
2032   /* If no validation is pending, we need to go ahead and force an
2033    * immediate scroll.
2034    */
2035   if (text_view->layout &&
2036       gtk_text_layout_is_valid (text_view->layout))
2037     gtk_text_view_flush_scroll (text_view);
2038 }
2039
2040 /**
2041  * gtk_text_view_scroll_mark_onscreen:
2042  * @text_view: a #GtkTextView
2043  * @mark: a mark in the buffer for @text_view
2044  * 
2045  * Scrolls @text_view the minimum distance such that @mark is contained
2046  * within the visible area of the widget.
2047  **/
2048 void
2049 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
2050                                     GtkTextMark *mark)
2051 {
2052   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2053   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2054
2055   gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
2056 }
2057
2058 static gboolean
2059 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
2060 {
2061   GdkRectangle visible_rect;
2062   gtk_text_view_get_visible_rect (text_view, &visible_rect);
2063
2064   return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
2065                                                visible_rect.y,
2066                                                visible_rect.y + visible_rect.height);
2067 }
2068
2069 /**
2070  * gtk_text_view_move_mark_onscreen:
2071  * @text_view: a #GtkTextView
2072  * @mark: a #GtkTextMark
2073  *
2074  * Moves a mark within the buffer so that it's
2075  * located within the currently-visible text area.
2076  *
2077  * Return value: %TRUE if the mark moved (wasn't already onscreen)
2078  **/
2079 gboolean
2080 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
2081                                   GtkTextMark *mark)
2082 {
2083   GtkTextIter iter;
2084
2085   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2086   g_return_val_if_fail (mark != NULL, FALSE);
2087
2088   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2089
2090   if (clamp_iter_onscreen (text_view, &iter))
2091     {
2092       gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
2093       return TRUE;
2094     }
2095   else
2096     return FALSE;
2097 }
2098
2099 /**
2100  * gtk_text_view_get_visible_rect:
2101  * @text_view: a #GtkTextView
2102  * @visible_rect: rectangle to fill
2103  *
2104  * Fills @visible_rect with the currently-visible
2105  * region of the buffer, in buffer coordinates. Convert to window coordinates
2106  * with gtk_text_view_buffer_to_window_coords().
2107  **/
2108 void
2109 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
2110                                 GdkRectangle *visible_rect)
2111 {
2112   GtkWidget *widget;
2113
2114   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2115
2116   widget = GTK_WIDGET (text_view);
2117
2118   if (visible_rect)
2119     {
2120       visible_rect->x = text_view->xoffset;
2121       visible_rect->y = text_view->yoffset;
2122       visible_rect->width = SCREEN_WIDTH (widget);
2123       visible_rect->height = SCREEN_HEIGHT (widget);
2124
2125       DV(g_print(" visible rect: %d,%d %d x %d\n",
2126                  visible_rect->x,
2127                  visible_rect->y,
2128                  visible_rect->width,
2129                  visible_rect->height));
2130     }
2131 }
2132
2133 /**
2134  * gtk_text_view_set_wrap_mode:
2135  * @text_view: a #GtkTextView
2136  * @wrap_mode: a #GtkWrapMode
2137  *
2138  * Sets the line wrapping for the view.
2139  **/
2140 void
2141 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
2142                              GtkWrapMode  wrap_mode)
2143 {
2144   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2145
2146   if (text_view->wrap_mode != wrap_mode)
2147     {
2148       text_view->wrap_mode = wrap_mode;
2149
2150       if (text_view->layout)
2151         {
2152           text_view->layout->default_style->wrap_mode = wrap_mode;
2153           gtk_text_layout_default_style_changed (text_view->layout);
2154         }
2155     }
2156
2157   g_object_notify (G_OBJECT (text_view), "wrap-mode");
2158 }
2159
2160 /**
2161  * gtk_text_view_get_wrap_mode:
2162  * @text_view: a #GtkTextView
2163  *
2164  * Gets the line wrapping for the view.
2165  *
2166  * Return value: the line wrap setting
2167  **/
2168 GtkWrapMode
2169 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
2170 {
2171   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAP_NONE);
2172
2173   return text_view->wrap_mode;
2174 }
2175
2176 /**
2177  * gtk_text_view_set_editable:
2178  * @text_view: a #GtkTextView
2179  * @setting: whether it's editable
2180  *
2181  * Sets the default editability of the #GtkTextView. You can override
2182  * this default setting with tags in the buffer, using the "editable"
2183  * attribute of tags.
2184  **/
2185 void
2186 gtk_text_view_set_editable (GtkTextView *text_view,
2187                             gboolean     setting)
2188 {
2189   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2190   setting = setting != FALSE;
2191
2192   if (text_view->editable != setting)
2193     {
2194       text_view->editable = setting;
2195
2196       if (text_view->layout)
2197         {
2198           gtk_text_layout_set_overwrite_mode (text_view->layout,
2199                                               text_view->overwrite_mode && text_view->editable);
2200           text_view->layout->default_style->editable = text_view->editable;
2201           gtk_text_layout_default_style_changed (text_view->layout);
2202         }
2203
2204       g_object_notify (G_OBJECT (text_view), "editable");
2205     }
2206 }
2207
2208 /**
2209  * gtk_text_view_get_editable:
2210  * @text_view: a #GtkTextView
2211  *
2212  * Returns the default editability of the #GtkTextView. Tags in the
2213  * buffer may override this setting for some ranges of text.
2214  *
2215  * Return value: whether text is editable by default
2216  **/
2217 gboolean
2218 gtk_text_view_get_editable (GtkTextView *text_view)
2219 {
2220   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2221
2222   return text_view->editable;
2223 }
2224
2225 /**
2226  * gtk_text_view_set_pixels_above_lines:
2227  * @text_view: a #GtkTextView
2228  * @pixels_above_lines: pixels above paragraphs
2229  * 
2230  * Sets the default number of blank pixels above paragraphs in @text_view.
2231  * Tags in the buffer for @text_view may override the defaults.
2232  **/
2233 void
2234 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
2235                                       gint         pixels_above_lines)
2236 {
2237   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2238
2239   if (text_view->pixels_above_lines != pixels_above_lines)
2240     {
2241       text_view->pixels_above_lines = pixels_above_lines;
2242
2243       if (text_view->layout)
2244         {
2245           text_view->layout->default_style->pixels_above_lines = pixels_above_lines;
2246           gtk_text_layout_default_style_changed (text_view->layout);
2247         }
2248
2249       g_object_notify (G_OBJECT (text_view), "pixels-above-lines");
2250     }
2251 }
2252
2253 /**
2254  * gtk_text_view_get_pixels_above_lines:
2255  * @text_view: a #GtkTextView
2256  * 
2257  * Gets the default number of pixels to put above paragraphs.
2258  * 
2259  * Return value: default number of pixels above paragraphs
2260  **/
2261 gint
2262 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
2263 {
2264   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2265
2266   return text_view->pixels_above_lines;
2267 }
2268
2269 /**
2270  * gtk_text_view_set_pixels_below_lines:
2271  * @text_view: a #GtkTextView
2272  * @pixels_below_lines: pixels below paragraphs 
2273  *
2274  * Sets the default number of pixels of blank space
2275  * to put below paragraphs in @text_view. May be overridden
2276  * by tags applied to @text_view's buffer. 
2277  **/
2278 void
2279 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
2280                                       gint         pixels_below_lines)
2281 {
2282   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2283
2284   if (text_view->pixels_below_lines != pixels_below_lines)
2285     {
2286       text_view->pixels_below_lines = pixels_below_lines;
2287
2288       if (text_view->layout)
2289         {
2290           text_view->layout->default_style->pixels_below_lines = pixels_below_lines;
2291           gtk_text_layout_default_style_changed (text_view->layout);
2292         }
2293
2294       g_object_notify (G_OBJECT (text_view), "pixels-below-lines");
2295     }
2296 }
2297
2298 /**
2299  * gtk_text_view_get_pixels_below_lines:
2300  * @text_view: a #GtkTextView
2301  * 
2302  * Gets the value set by gtk_text_view_set_pixels_below_lines().
2303  * 
2304  * Return value: default number of blank pixels below paragraphs
2305  **/
2306 gint
2307 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
2308 {
2309   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2310
2311   return text_view->pixels_below_lines;
2312 }
2313
2314 /**
2315  * gtk_text_view_set_pixels_inside_wrap:
2316  * @text_view: a #GtkTextView
2317  * @pixels_inside_wrap: default number of pixels between wrapped lines
2318  *
2319  * Sets the default number of pixels of blank space to leave between
2320  * display/wrapped lines within a paragraph. May be overridden by
2321  * tags in @text_view's buffer.
2322  **/
2323 void
2324 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
2325                                       gint         pixels_inside_wrap)
2326 {
2327   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2328
2329   if (text_view->pixels_inside_wrap != pixels_inside_wrap)
2330     {
2331       text_view->pixels_inside_wrap = pixels_inside_wrap;
2332
2333       if (text_view->layout)
2334         {
2335           text_view->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
2336           gtk_text_layout_default_style_changed (text_view->layout);
2337         }
2338
2339       g_object_notify (G_OBJECT (text_view), "pixels-inside-wrap");
2340     }
2341 }
2342
2343 /**
2344  * gtk_text_view_get_pixels_inside_wrap:
2345  * @text_view: a #GtkTextView
2346  * 
2347  * Gets the value set by gtk_text_view_set_pixels_inside_wrap().
2348  * 
2349  * Return value: default number of pixels of blank space between wrapped lines
2350  **/
2351 gint
2352 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
2353 {
2354   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2355
2356   return text_view->pixels_inside_wrap;
2357 }
2358
2359 /**
2360  * gtk_text_view_set_justification:
2361  * @text_view: a #GtkTextView
2362  * @justification: justification
2363  *
2364  * Sets the default justification of text in @text_view.
2365  * Tags in the view's buffer may override the default.
2366  * 
2367  **/
2368 void
2369 gtk_text_view_set_justification (GtkTextView     *text_view,
2370                                  GtkJustification justification)
2371 {
2372   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2373
2374   if (text_view->justify != justification)
2375     {
2376       text_view->justify = justification;
2377
2378       if (text_view->layout)
2379         {
2380           text_view->layout->default_style->justification = justification;
2381           gtk_text_layout_default_style_changed (text_view->layout);
2382         }
2383
2384       g_object_notify (G_OBJECT (text_view), "justification");
2385     }
2386 }
2387
2388 /**
2389  * gtk_text_view_get_justification:
2390  * @text_view: a #GtkTextView
2391  * 
2392  * Gets the default justification of paragraphs in @text_view.
2393  * Tags in the buffer may override the default.
2394  * 
2395  * Return value: default justification
2396  **/
2397 GtkJustification
2398 gtk_text_view_get_justification (GtkTextView *text_view)
2399 {
2400   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
2401
2402   return text_view->justify;
2403 }
2404
2405 /**
2406  * gtk_text_view_set_left_margin:
2407  * @text_view: a #GtkTextView
2408  * @left_margin: left margin in pixels
2409  * 
2410  * Sets the default left margin for text in @text_view.
2411  * Tags in the buffer may override the default.
2412  **/
2413 void
2414 gtk_text_view_set_left_margin (GtkTextView *text_view,
2415                                gint         left_margin)
2416 {
2417   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2418
2419   if (text_view->left_margin != left_margin)
2420     {
2421       text_view->left_margin = left_margin;
2422
2423       if (text_view->layout)
2424         {
2425           text_view->layout->default_style->left_margin = left_margin;
2426           gtk_text_layout_default_style_changed (text_view->layout);
2427         }
2428
2429       g_object_notify (G_OBJECT (text_view), "left-margin");
2430     }
2431 }
2432
2433 /**
2434  * gtk_text_view_get_left_margin:
2435  * @text_view: a #GtkTextView
2436  * 
2437  * Gets the default left margin size of paragraphs in the @text_view.
2438  * Tags in the buffer may override the default.
2439  * 
2440  * Return value: left margin in pixels
2441  **/
2442 gint
2443 gtk_text_view_get_left_margin (GtkTextView *text_view)
2444 {
2445   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2446
2447   return text_view->left_margin;
2448 }
2449
2450 /**
2451  * gtk_text_view_set_right_margin:
2452  * @text_view: a #GtkTextView
2453  * @right_margin: right margin in pixels
2454  *
2455  * Sets the default right margin for text in the text view.
2456  * Tags in the buffer may override the default.
2457  **/
2458 void
2459 gtk_text_view_set_right_margin (GtkTextView *text_view,
2460                                 gint         right_margin)
2461 {
2462   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2463
2464   if (text_view->right_margin != right_margin)
2465     {
2466       text_view->right_margin = right_margin;
2467
2468       if (text_view->layout)
2469         {
2470           text_view->layout->default_style->right_margin = right_margin;
2471           gtk_text_layout_default_style_changed (text_view->layout);
2472         }
2473
2474       g_object_notify (G_OBJECT (text_view), "right-margin");
2475     }
2476 }
2477
2478 /**
2479  * gtk_text_view_get_right_margin:
2480  * @text_view: a #GtkTextView
2481  * 
2482  * Gets the default right margin for text in @text_view. Tags
2483  * in the buffer may override the default.
2484  * 
2485  * Return value: right margin in pixels
2486  **/
2487 gint
2488 gtk_text_view_get_right_margin (GtkTextView *text_view)
2489 {
2490   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2491
2492   return text_view->right_margin;
2493 }
2494
2495 /**
2496  * gtk_text_view_set_indent:
2497  * @text_view: a #GtkTextView
2498  * @indent: indentation in pixels
2499  *
2500  * Sets the default indentation for paragraphs in @text_view.
2501  * Tags in the buffer may override the default.
2502  **/
2503 void
2504 gtk_text_view_set_indent (GtkTextView *text_view,
2505                           gint         indent)
2506 {
2507   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2508
2509   if (text_view->indent != indent)
2510     {
2511       text_view->indent = indent;
2512
2513       if (text_view->layout)
2514         {
2515           text_view->layout->default_style->indent = indent;
2516           gtk_text_layout_default_style_changed (text_view->layout);
2517         }
2518
2519       g_object_notify (G_OBJECT (text_view), "indent");
2520     }
2521 }
2522
2523 /**
2524  * gtk_text_view_get_indent:
2525  * @text_view: a #GtkTextView
2526  * 
2527  * Gets the default indentation of paragraphs in @text_view.
2528  * Tags in the view's buffer may override the default.
2529  * The indentation may be negative.
2530  * 
2531  * Return value: number of pixels of indentation
2532  **/
2533 gint
2534 gtk_text_view_get_indent (GtkTextView *text_view)
2535 {
2536   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2537
2538   return text_view->indent;
2539 }
2540
2541 /**
2542  * gtk_text_view_set_tabs:
2543  * @text_view: a #GtkTextView
2544  * @tabs: tabs as a #PangoTabArray
2545  *
2546  * Sets the default tab stops for paragraphs in @text_view.
2547  * Tags in the buffer may override the default.
2548  **/
2549 void
2550 gtk_text_view_set_tabs (GtkTextView   *text_view,
2551                         PangoTabArray *tabs)
2552 {
2553   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2554
2555   if (text_view->tabs)
2556     pango_tab_array_free (text_view->tabs);
2557
2558   text_view->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
2559
2560   if (text_view->layout)
2561     {
2562       /* some unkosher futzing in internal struct details... */
2563       if (text_view->layout->default_style->tabs)
2564         pango_tab_array_free (text_view->layout->default_style->tabs);
2565
2566       text_view->layout->default_style->tabs =
2567         text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
2568
2569       gtk_text_layout_default_style_changed (text_view->layout);
2570     }
2571
2572   g_object_notify (G_OBJECT (text_view), "tabs");
2573 }
2574
2575 /**
2576  * gtk_text_view_get_tabs:
2577  * @text_view: a #GtkTextView
2578  * 
2579  * Gets the default tabs for @text_view. Tags in the buffer may
2580  * override the defaults. The returned array will be %NULL if
2581  * "standard" (8-space) tabs are used. Free the return value
2582  * with pango_tab_array_free().
2583  * 
2584  * Return value: copy of default tab array, or %NULL if "standard" 
2585  *    tabs are used; must be freed with pango_tab_array_free().
2586  **/
2587 PangoTabArray*
2588 gtk_text_view_get_tabs (GtkTextView *text_view)
2589 {
2590   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
2591
2592   return text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
2593 }
2594
2595 static void
2596 gtk_text_view_toggle_cursor_visible (GtkTextView *text_view)
2597 {
2598   gtk_text_view_set_cursor_visible (text_view, !text_view->cursor_visible);
2599 }
2600
2601 /**
2602  * gtk_text_view_set_cursor_visible:
2603  * @text_view: a #GtkTextView
2604  * @setting: whether to show the insertion cursor
2605  *
2606  * Toggles whether the insertion point is displayed. A buffer with no editable
2607  * text probably shouldn't have a visible cursor, so you may want to turn
2608  * the cursor off.
2609  **/
2610 void
2611 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
2612                                   gboolean     setting)
2613 {
2614   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2615
2616   setting = (setting != FALSE);
2617
2618   if (text_view->cursor_visible != setting)
2619     {
2620       text_view->cursor_visible = setting;
2621
2622       if (GTK_WIDGET_HAS_FOCUS (text_view))
2623         {
2624           if (text_view->layout)
2625             {
2626               gtk_text_layout_set_cursor_visible (text_view->layout, setting);
2627               gtk_text_view_check_cursor_blink (text_view);
2628             }
2629         }
2630
2631       g_object_notify (G_OBJECT (text_view), "cursor-visible");
2632     }
2633 }
2634
2635 /**
2636  * gtk_text_view_get_cursor_visible:
2637  * @text_view: a #GtkTextView
2638  *
2639  * Find out whether the cursor is being displayed.
2640  *
2641  * Return value: whether the insertion mark is visible
2642  **/
2643 gboolean
2644 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
2645 {
2646   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2647
2648   return text_view->cursor_visible;
2649 }
2650
2651
2652 /**
2653  * gtk_text_view_place_cursor_onscreen:
2654  * @text_view: a #GtkTextView
2655  *
2656  * Moves the cursor to the currently visible region of the
2657  * buffer, it it isn't there already.
2658  *
2659  * Return value: %TRUE if the cursor had to be moved.
2660  **/
2661 gboolean
2662 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
2663 {
2664   GtkTextIter insert;
2665
2666   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2667
2668   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2669                                     gtk_text_buffer_get_mark (get_buffer (text_view),
2670                                                               "insert"));
2671
2672   if (clamp_iter_onscreen (text_view, &insert))
2673     {
2674       gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
2675       return TRUE;
2676     }
2677   else
2678     return FALSE;
2679 }
2680
2681 static void
2682 gtk_text_view_remove_validate_idles (GtkTextView *text_view)
2683 {
2684   if (text_view->first_validate_idle != 0)
2685     {
2686       DV (g_print ("Removing first validate idle: %s\n", G_STRLOC));
2687       g_source_remove (text_view->first_validate_idle);
2688       text_view->first_validate_idle = 0;
2689     }
2690
2691   if (text_view->incremental_validate_idle != 0)
2692     {
2693       g_source_remove (text_view->incremental_validate_idle);
2694       text_view->incremental_validate_idle = 0;
2695     }
2696 }
2697
2698 static void
2699 gtk_text_view_destroy (GtkObject *object)
2700 {
2701   GtkTextView *text_view;
2702   
2703   text_view = GTK_TEXT_VIEW (object);
2704
2705   gtk_text_view_remove_validate_idles (text_view);
2706   gtk_text_view_set_buffer (text_view, NULL);
2707   gtk_text_view_destroy_layout (text_view);
2708
2709   if (text_view->scroll_timeout)
2710     {
2711       g_source_remove (text_view->scroll_timeout);
2712       text_view->scroll_timeout = 0;
2713     }
2714
2715   (* GTK_OBJECT_CLASS (gtk_text_view_parent_class)->destroy) (object);
2716 }
2717
2718 static void
2719 gtk_text_view_finalize (GObject *object)
2720 {
2721   GtkTextView *text_view;
2722
2723   text_view = GTK_TEXT_VIEW (object);
2724
2725   g_assert (text_view->buffer == NULL);
2726
2727   gtk_text_view_destroy_layout (text_view);
2728   gtk_text_view_set_buffer (text_view, NULL);
2729   
2730   cancel_pending_scroll (text_view);
2731
2732   if (text_view->tabs)
2733     pango_tab_array_free (text_view->tabs);
2734   
2735   if (text_view->hadjustment)
2736     g_object_unref (text_view->hadjustment);
2737   if (text_view->vadjustment)
2738     g_object_unref (text_view->vadjustment);
2739
2740   text_window_free (text_view->text_window);
2741
2742   if (text_view->left_window)
2743     text_window_free (text_view->left_window);
2744
2745   if (text_view->top_window)
2746     text_window_free (text_view->top_window);
2747
2748   if (text_view->right_window)
2749     text_window_free (text_view->right_window);
2750
2751   if (text_view->bottom_window)
2752     text_window_free (text_view->bottom_window);
2753
2754   g_object_unref (text_view->im_context);
2755   
2756   (* G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize) (object);
2757 }
2758
2759 static void
2760 gtk_text_view_set_property (GObject         *object,
2761                             guint            prop_id,
2762                             const GValue    *value,
2763                             GParamSpec      *pspec)
2764 {
2765   GtkTextView *text_view;
2766
2767   text_view = GTK_TEXT_VIEW (object);
2768
2769   switch (prop_id)
2770     {
2771     case PROP_PIXELS_ABOVE_LINES:
2772       gtk_text_view_set_pixels_above_lines (text_view, g_value_get_int (value));
2773       break;
2774
2775     case PROP_PIXELS_BELOW_LINES:
2776       gtk_text_view_set_pixels_below_lines (text_view, g_value_get_int (value));
2777       break;
2778
2779     case PROP_PIXELS_INSIDE_WRAP:
2780       gtk_text_view_set_pixels_inside_wrap (text_view, g_value_get_int (value));
2781       break;
2782
2783     case PROP_EDITABLE:
2784       gtk_text_view_set_editable (text_view, g_value_get_boolean (value));
2785       break;
2786
2787     case PROP_WRAP_MODE:
2788       gtk_text_view_set_wrap_mode (text_view, g_value_get_enum (value));
2789       break;
2790       
2791     case PROP_JUSTIFICATION:
2792       gtk_text_view_set_justification (text_view, g_value_get_enum (value));
2793       break;
2794
2795     case PROP_LEFT_MARGIN:
2796       gtk_text_view_set_left_margin (text_view, g_value_get_int (value));
2797       break;
2798
2799     case PROP_RIGHT_MARGIN:
2800       gtk_text_view_set_right_margin (text_view, g_value_get_int (value));
2801       break;
2802
2803     case PROP_INDENT:
2804       gtk_text_view_set_indent (text_view, g_value_get_int (value));
2805       break;
2806
2807     case PROP_TABS:
2808       gtk_text_view_set_tabs (text_view, g_value_get_boxed (value));
2809       break;
2810
2811     case PROP_CURSOR_VISIBLE:
2812       gtk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
2813       break;
2814
2815     case PROP_OVERWRITE:
2816       gtk_text_view_set_overwrite (text_view, g_value_get_boolean (value));
2817       break;
2818
2819     case PROP_BUFFER:
2820       gtk_text_view_set_buffer (text_view, GTK_TEXT_BUFFER (g_value_get_object (value)));
2821       break;
2822
2823     case PROP_ACCEPTS_TAB:
2824       gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
2825       break;
2826       
2827     default:
2828       g_assert_not_reached ();
2829       break;
2830     }
2831 }
2832
2833 static void
2834 gtk_text_view_get_property (GObject         *object,
2835                             guint            prop_id,
2836                             GValue          *value,
2837                             GParamSpec      *pspec)
2838 {
2839   GtkTextView *text_view;
2840
2841   text_view = GTK_TEXT_VIEW (object);
2842
2843   switch (prop_id)
2844     {
2845     case PROP_PIXELS_ABOVE_LINES:
2846       g_value_set_int (value, text_view->pixels_above_lines);
2847       break;
2848
2849     case PROP_PIXELS_BELOW_LINES:
2850       g_value_set_int (value, text_view->pixels_below_lines);
2851       break;
2852
2853     case PROP_PIXELS_INSIDE_WRAP:
2854       g_value_set_int (value, text_view->pixels_inside_wrap);
2855       break;
2856
2857     case PROP_EDITABLE:
2858       g_value_set_boolean (value, text_view->editable);
2859       break;
2860       
2861     case PROP_WRAP_MODE:
2862       g_value_set_enum (value, text_view->wrap_mode);
2863       break;
2864
2865     case PROP_JUSTIFICATION:
2866       g_value_set_enum (value, text_view->justify);
2867       break;
2868
2869     case PROP_LEFT_MARGIN:
2870       g_value_set_int (value, text_view->left_margin);
2871       break;
2872
2873     case PROP_RIGHT_MARGIN:
2874       g_value_set_int (value, text_view->right_margin);
2875       break;
2876
2877     case PROP_INDENT:
2878       g_value_set_int (value, text_view->indent);
2879       break;
2880
2881     case PROP_TABS:
2882       g_value_set_boxed (value, text_view->tabs);
2883       break;
2884
2885     case PROP_CURSOR_VISIBLE:
2886       g_value_set_boolean (value, text_view->cursor_visible);
2887       break;
2888
2889     case PROP_BUFFER:
2890       g_value_set_object (value, get_buffer (text_view));
2891       break;
2892
2893     case PROP_OVERWRITE:
2894       g_value_set_boolean (value, text_view->overwrite_mode);
2895       break;
2896
2897     case PROP_ACCEPTS_TAB:
2898       g_value_set_boolean (value, text_view->accepts_tab);
2899       break;
2900       
2901     default:
2902       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2903       break;
2904     }
2905 }
2906
2907 static void
2908 gtk_text_view_size_request (GtkWidget      *widget,
2909                             GtkRequisition *requisition)
2910 {
2911   GtkTextView *text_view;
2912   GSList *tmp_list;
2913   gint focus_edge_width;
2914   gint focus_width;
2915   gboolean interior_focus;
2916   
2917   text_view = GTK_TEXT_VIEW (widget);
2918
2919   gtk_widget_style_get (widget,
2920                         "interior-focus", &interior_focus,
2921                         "focus-line-width", &focus_width,
2922                         NULL);
2923
2924   if (interior_focus)
2925     focus_edge_width = 0;
2926   else
2927     focus_edge_width = focus_width;
2928
2929   if (text_view->layout)
2930     {
2931       text_view->text_window->requisition.width = text_view->layout->width;
2932       text_view->text_window->requisition.height = text_view->layout->height;
2933     }
2934   else
2935     {
2936       text_view->text_window->requisition.width = 0;
2937       text_view->text_window->requisition.height = 0;
2938     }
2939   
2940   requisition->width = text_view->text_window->requisition.width + focus_edge_width * 2;
2941   requisition->height = text_view->text_window->requisition.height + focus_edge_width * 2;
2942
2943   if (text_view->left_window)
2944     requisition->width += text_view->left_window->requisition.width;
2945
2946   if (text_view->right_window)
2947     requisition->width += text_view->right_window->requisition.width;
2948
2949   if (text_view->top_window)
2950     requisition->height += text_view->top_window->requisition.height;
2951
2952   if (text_view->bottom_window)
2953     requisition->height += text_view->bottom_window->requisition.height;
2954
2955   requisition->width += GTK_CONTAINER (text_view)->border_width * 2;
2956   requisition->height += GTK_CONTAINER (text_view)->border_width * 2;
2957   
2958   tmp_list = text_view->children;
2959   while (tmp_list != NULL)
2960     {
2961       GtkTextViewChild *child = tmp_list->data;
2962
2963       if (child->anchor)
2964         {
2965           GtkRequisition child_req;
2966           GtkRequisition old_req;
2967
2968           gtk_widget_get_child_requisition (child->widget, &old_req);
2969           
2970           gtk_widget_size_request (child->widget, &child_req);
2971
2972           gtk_widget_get_child_requisition (child->widget, &child_req);
2973
2974           /* Invalidate layout lines if required */
2975           if (text_view->layout &&
2976               (old_req.width != child_req.width ||
2977                old_req.height != child_req.height))
2978             gtk_text_child_anchor_queue_resize (child->anchor,
2979                                                 text_view->layout);
2980         }
2981       else
2982         {
2983           GtkRequisition child_req;
2984           
2985           gtk_widget_size_request (child->widget, &child_req);
2986         }
2987
2988       tmp_list = g_slist_next (tmp_list);
2989     }
2990 }
2991
2992 static void
2993 gtk_text_view_compute_child_allocation (GtkTextView      *text_view,
2994                                         GtkTextViewChild *vc,
2995                                         GtkAllocation    *allocation)
2996 {
2997   gint buffer_y;
2998   GtkTextIter iter;
2999   GtkRequisition req;
3000   
3001   gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3002                                             &iter,
3003                                             vc->anchor);
3004
3005   gtk_text_layout_get_line_yrange (text_view->layout, &iter,
3006                                    &buffer_y, NULL);
3007
3008   buffer_y += vc->from_top_of_line;
3009
3010   allocation->x = vc->from_left_of_buffer - text_view->xoffset;
3011   allocation->y = buffer_y - text_view->yoffset;
3012
3013   gtk_widget_get_child_requisition (vc->widget, &req);
3014   allocation->width = req.width;
3015   allocation->height = req.height;
3016 }
3017
3018 static void
3019 gtk_text_view_update_child_allocation (GtkTextView      *text_view,
3020                                        GtkTextViewChild *vc)
3021 {
3022   GtkAllocation allocation;
3023
3024   gtk_text_view_compute_child_allocation (text_view, vc, &allocation);
3025   
3026   gtk_widget_size_allocate (vc->widget, &allocation);
3027
3028 #if 0
3029   g_print ("allocation for %p allocated to %d,%d yoffset = %d\n",
3030            vc->widget,
3031            vc->widget->allocation.x,
3032            vc->widget->allocation.y,
3033            text_view->yoffset);
3034 #endif
3035 }
3036
3037 static void
3038 gtk_text_view_child_allocated (GtkTextLayout *layout,
3039                                GtkWidget     *child,
3040                                gint           x,
3041                                gint           y,
3042                                gpointer       data)
3043 {
3044   GtkTextViewChild *vc = NULL;
3045   GtkTextView *text_view = data;
3046   
3047   /* x,y is the position of the child from the top of the line, and
3048    * from the left of the buffer. We have to translate that into text
3049    * window coordinates, then size_allocate the child.
3050    */
3051
3052   vc = g_object_get_data (G_OBJECT (child),
3053                           "gtk-text-view-child");
3054
3055   g_assert (vc != NULL);
3056
3057   DV (g_print ("child allocated at %d,%d\n", x, y));
3058   
3059   vc->from_left_of_buffer = x;
3060   vc->from_top_of_line = y;
3061
3062   gtk_text_view_update_child_allocation (text_view, vc);
3063 }
3064
3065 static void
3066 gtk_text_view_allocate_children (GtkTextView *text_view)
3067 {
3068   GSList *tmp_list;
3069
3070   DV(g_print(G_STRLOC"\n"));
3071   
3072   tmp_list = text_view->children;
3073   while (tmp_list != NULL)
3074     {
3075       GtkTextViewChild *child = tmp_list->data;
3076
3077       g_assert (child != NULL);
3078           
3079       if (child->anchor)
3080         {
3081           /* We need to force-validate the regions containing
3082            * children.
3083            */
3084           GtkTextIter child_loc;
3085           gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3086                                                     &child_loc,
3087                                                     child->anchor);
3088
3089           /* Since anchored children are only ever allocated from
3090            * gtk_text_layout_get_line_display() we have to make sure
3091            * that the display line caching in the layout doesn't 
3092            * get in the way. Invalidating the layout around the anchor
3093            * achieves this.
3094            */ 
3095           if (GTK_WIDGET_ALLOC_NEEDED (child->widget))
3096             {
3097               GtkTextIter end = child_loc;
3098               gtk_text_iter_forward_char (&end);
3099               gtk_text_layout_invalidate (text_view->layout, &child_loc, &end);
3100             }
3101
3102           gtk_text_layout_validate_yrange (text_view->layout,
3103                                            &child_loc,
3104                                            0, 1);
3105         }
3106       else
3107         {
3108           GtkAllocation allocation;          
3109           GtkRequisition child_req;
3110              
3111           allocation.x = child->x;
3112           allocation.y = child->y;
3113
3114           gtk_widget_get_child_requisition (child->widget, &child_req);
3115           
3116           allocation.width = child_req.width;
3117           allocation.height = child_req.height;
3118           
3119           gtk_widget_size_allocate (child->widget, &allocation);          
3120         }
3121
3122       tmp_list = g_slist_next (tmp_list);
3123     }
3124 }
3125
3126 static void
3127 gtk_text_view_size_allocate (GtkWidget *widget,
3128                              GtkAllocation *allocation)
3129 {
3130   GtkTextView *text_view;
3131   GtkTextIter first_para;
3132   gint y;
3133   gint width, height;
3134   GdkRectangle text_rect;
3135   GdkRectangle left_rect;
3136   GdkRectangle right_rect;
3137   GdkRectangle top_rect;
3138   GdkRectangle bottom_rect;
3139   gint focus_edge_width;
3140   gint focus_width;
3141   gboolean interior_focus;
3142   gboolean size_changed;
3143   
3144   text_view = GTK_TEXT_VIEW (widget);
3145
3146   DV(g_print(G_STRLOC"\n"));
3147
3148   size_changed =
3149     widget->allocation.width != allocation->width ||
3150     widget->allocation.height != allocation->height;
3151   
3152   widget->allocation = *allocation;
3153
3154   if (GTK_WIDGET_REALIZED (widget))
3155     {
3156       gdk_window_move_resize (widget->window,
3157                               allocation->x, allocation->y,
3158                               allocation->width, allocation->height);
3159     }
3160
3161   /* distribute width/height among child windows. Ensure all
3162    * windows get at least a 1x1 allocation.
3163    */
3164
3165   gtk_widget_style_get (widget,
3166                         "interior-focus", &interior_focus,
3167                         "focus-line-width", &focus_width,
3168                         NULL);
3169
3170   if (interior_focus)
3171     focus_edge_width = 0;
3172   else
3173     focus_edge_width = focus_width;
3174   
3175   width = allocation->width - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
3176
3177   if (text_view->left_window)
3178     left_rect.width = text_view->left_window->requisition.width;
3179   else
3180     left_rect.width = 0;
3181
3182   width -= left_rect.width;
3183
3184   if (text_view->right_window)
3185     right_rect.width = text_view->right_window->requisition.width;
3186   else
3187     right_rect.width = 0;
3188
3189   width -= right_rect.width;
3190
3191   text_rect.width = MAX (1, width);
3192
3193   top_rect.width = text_rect.width;
3194   bottom_rect.width = text_rect.width;
3195
3196
3197   height = allocation->height - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
3198
3199   if (text_view->top_window)
3200     top_rect.height = text_view->top_window->requisition.height;
3201   else
3202     top_rect.height = 0;
3203
3204   height -= top_rect.height;
3205
3206   if (text_view->bottom_window)
3207     bottom_rect.height = text_view->bottom_window->requisition.height;
3208   else
3209     bottom_rect.height = 0;
3210
3211   height -= bottom_rect.height;
3212
3213   text_rect.height = MAX (1, height);
3214
3215   left_rect.height = text_rect.height;
3216   right_rect.height = text_rect.height;
3217
3218   /* Origins */
3219   left_rect.x = focus_edge_width + GTK_CONTAINER (text_view)->border_width;
3220   top_rect.y = focus_edge_width + GTK_CONTAINER (text_view)->border_width;
3221
3222   text_rect.x = left_rect.x + left_rect.width;
3223   text_rect.y = top_rect.y + top_rect.height;
3224
3225   left_rect.y = text_rect.y;
3226   right_rect.y = text_rect.y;
3227
3228   top_rect.x = text_rect.x;
3229   bottom_rect.x = text_rect.x;
3230
3231   right_rect.x = text_rect.x + text_rect.width;
3232   bottom_rect.y = text_rect.y + text_rect.height;
3233
3234   text_window_size_allocate (text_view->text_window,
3235                              &text_rect);
3236
3237   if (text_view->left_window)
3238     text_window_size_allocate (text_view->left_window,
3239                                &left_rect);
3240
3241   if (text_view->right_window)
3242     text_window_size_allocate (text_view->right_window,
3243                                &right_rect);
3244
3245   if (text_view->top_window)
3246     text_window_size_allocate (text_view->top_window,
3247                                &top_rect);
3248
3249   if (text_view->bottom_window)
3250     text_window_size_allocate (text_view->bottom_window,
3251                                &bottom_rect);
3252
3253   gtk_text_view_update_layout_width (text_view);
3254   
3255   /* Note that this will do some layout validation */
3256   gtk_text_view_allocate_children (text_view);
3257
3258   /* Ensure h/v adj exist */
3259   get_hadjustment (text_view);
3260   get_vadjustment (text_view);
3261
3262   text_view->hadjustment->page_size = SCREEN_WIDTH (text_view);
3263   text_view->hadjustment->page_increment = SCREEN_WIDTH (text_view) * 0.9;
3264   text_view->hadjustment->step_increment = SCREEN_WIDTH (text_view) * 0.1;
3265   text_view->hadjustment->lower = 0;
3266   text_view->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
3267                                        text_view->width);
3268
3269   if (text_view->hadjustment->value > text_view->hadjustment->upper - text_view->hadjustment->page_size)
3270     gtk_adjustment_set_value (text_view->hadjustment, MAX (0, text_view->hadjustment->upper - text_view->hadjustment->page_size));
3271
3272   gtk_adjustment_changed (text_view->hadjustment);
3273
3274   text_view->vadjustment->page_size = SCREEN_HEIGHT (text_view);
3275   text_view->vadjustment->page_increment = SCREEN_HEIGHT (text_view) * 0.9;
3276   text_view->vadjustment->step_increment = SCREEN_HEIGHT (text_view) * 0.1;
3277   text_view->vadjustment->lower = 0;
3278   text_view->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
3279                                        text_view->height);
3280
3281   /* Now adjust the value of the adjustment to keep the cursor at the
3282    * same place in the buffer
3283    */
3284   gtk_text_view_get_first_para_iter (text_view, &first_para);
3285   gtk_text_layout_get_line_yrange (text_view->layout, &first_para, &y, NULL);
3286
3287   y += text_view->first_para_pixels;
3288
3289   if (y > text_view->vadjustment->upper - text_view->vadjustment->page_size)
3290     y = MAX (0, text_view->vadjustment->upper - text_view->vadjustment->page_size);
3291
3292   if (y != text_view->yoffset)
3293     gtk_adjustment_set_value (text_view->vadjustment, y);
3294
3295   gtk_adjustment_changed (text_view->vadjustment);
3296
3297   /* The GTK resize loop processes all the pending exposes right
3298    * after doing the resize stuff, so the idle sizer won't have a
3299    * chance to run. So we do the work here. 
3300    */
3301   gtk_text_view_flush_first_validate (text_view);
3302
3303   /* widget->window doesn't get auto-redrawn as the layout is computed, so has to
3304    * be invalidated
3305    */
3306   if (size_changed && GTK_WIDGET_REALIZED (widget))
3307     gdk_window_invalidate_rect (widget->window, NULL, FALSE);
3308 }
3309
3310 static void
3311 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
3312                                    GtkTextIter *iter)
3313 {
3314   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
3315                                     text_view->first_para_mark);
3316 }
3317
3318 static void
3319 gtk_text_view_validate_onscreen (GtkTextView *text_view)
3320 {
3321   GtkWidget *widget = GTK_WIDGET (text_view);
3322   
3323   DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
3324   
3325   if (SCREEN_HEIGHT (widget) > 0)
3326     {
3327       GtkTextIter first_para;
3328
3329       /* Be sure we've validated the stuff onscreen; if we
3330        * scrolled, these calls won't have any effect, because
3331        * they were called in the recursive validate_onscreen
3332        */
3333       gtk_text_view_get_first_para_iter (text_view, &first_para);
3334
3335       gtk_text_layout_validate_yrange (text_view->layout,
3336                                        &first_para,
3337                                        0,
3338                                        text_view->first_para_pixels +
3339                                        SCREEN_HEIGHT (widget));
3340     }
3341
3342   text_view->onscreen_validated = TRUE;
3343
3344   DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
3345   
3346   /* This can have the odd side effect of triggering a scroll, which should
3347    * flip "onscreen_validated" back to FALSE, but should also get us
3348    * back into this function to turn it on again.
3349    */
3350   gtk_text_view_update_adjustments (text_view);
3351
3352   g_assert (text_view->onscreen_validated);
3353 }
3354
3355 static void
3356 gtk_text_view_flush_first_validate (GtkTextView *text_view)
3357 {
3358   if (text_view->first_validate_idle == 0)
3359     return;
3360
3361   /* Do this first, which means that if an "invalidate"
3362    * occurs during any of this process, a new first_validate_callback
3363    * will be installed, and we'll start again.
3364    */
3365   DV (g_print ("removing first validate in %s\n", G_STRLOC));
3366   g_source_remove (text_view->first_validate_idle);
3367   text_view->first_validate_idle = 0;
3368   
3369   /* be sure we have up-to-date screen size set on the
3370    * layout.
3371    */
3372   gtk_text_view_update_layout_width (text_view);
3373
3374   /* Bail out if we invalidated stuff; scrolling right away will just
3375    * confuse the issue.
3376    */
3377   if (text_view->first_validate_idle != 0)
3378     {
3379       DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
3380     }
3381   else
3382     {
3383       /* scroll to any marks, if that's pending. This can jump us to
3384        * the validation codepath used for scrolling onscreen, if so we
3385        * bail out.  It won't jump if already in that codepath since
3386        * value_changed is not recursive, so also validate if
3387        * necessary.
3388        */
3389       if (!gtk_text_view_flush_scroll (text_view) ||
3390           !text_view->onscreen_validated)
3391         gtk_text_view_validate_onscreen (text_view);
3392       
3393       DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
3394       
3395       g_assert (text_view->onscreen_validated);
3396     }
3397 }
3398
3399 static gboolean
3400 first_validate_callback (gpointer data)
3401 {
3402   GtkTextView *text_view = data;
3403
3404   /* Note that some of this code is duplicated at the end of size_allocate,
3405    * keep in sync with that.
3406    */
3407   
3408   DV(g_print(G_STRLOC"\n"));
3409
3410   gtk_text_view_flush_first_validate (text_view);
3411   
3412   return FALSE;
3413 }
3414
3415 static gboolean
3416 incremental_validate_callback (gpointer data)
3417 {
3418   GtkTextView *text_view = data;
3419   gboolean result = TRUE;
3420
3421   DV(g_print(G_STRLOC"\n"));
3422   
3423   gtk_text_layout_validate (text_view->layout, 2000);
3424
3425   gtk_text_view_update_adjustments (text_view);
3426   
3427   if (gtk_text_layout_is_valid (text_view->layout))
3428     {
3429       text_view->incremental_validate_idle = 0;
3430       result = FALSE;
3431     }
3432
3433   return result;
3434 }
3435
3436 static void
3437 gtk_text_view_invalidate (GtkTextView *text_view)
3438 {  
3439   DV (g_print (">Invalidate, onscreen_validated = %d now FALSE ("G_STRLOC")\n",
3440                text_view->onscreen_validated));
3441
3442   text_view->onscreen_validated = FALSE;
3443
3444   /* We'll invalidate when the layout is created */
3445   if (text_view->layout == NULL)
3446     return;
3447   
3448   if (!text_view->first_validate_idle)
3449     {
3450       text_view->first_validate_idle = gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
3451       DV (g_print (G_STRLOC": adding first validate idle %d\n",
3452                    text_view->first_validate_idle));
3453     }
3454       
3455   if (!text_view->incremental_validate_idle)
3456     {
3457       text_view->incremental_validate_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
3458       DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
3459                    text_view->incremental_validate_idle));
3460     }
3461 }
3462
3463 static void
3464 invalidated_handler (GtkTextLayout *layout,
3465                      gpointer       data)
3466 {
3467   GtkTextView *text_view;
3468
3469   text_view = GTK_TEXT_VIEW (data);
3470
3471   DV (g_print ("Invalidating due to layout invalidate signal\n"));
3472   gtk_text_view_invalidate (text_view);
3473 }
3474
3475 static void
3476 changed_handler (GtkTextLayout     *layout,
3477                  gint               start_y,
3478                  gint               old_height,
3479                  gint               new_height,
3480                  gpointer           data)
3481 {
3482   GtkTextView *text_view;
3483   GtkWidget *widget;
3484   GdkRectangle visible_rect;
3485   GdkRectangle redraw_rect;
3486   
3487   text_view = GTK_TEXT_VIEW (data);
3488   widget = GTK_WIDGET (data);
3489   
3490   DV(g_print(">Lines Validated ("G_STRLOC")\n"));
3491
3492   if (GTK_WIDGET_REALIZED (text_view))
3493     {      
3494       gtk_text_view_get_visible_rect (text_view, &visible_rect);
3495
3496       redraw_rect.x = visible_rect.x;
3497       redraw_rect.width = visible_rect.width;
3498       redraw_rect.y = start_y;
3499
3500       if (old_height == new_height)
3501         redraw_rect.height = old_height;
3502       else if (start_y + old_height > visible_rect.y)
3503         redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
3504       else
3505         redraw_rect.height = 0;
3506         
3507       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
3508         {
3509           /* text_window_invalidate_rect() takes buffer coordinates */
3510           text_window_invalidate_rect (text_view->text_window,
3511                                        &redraw_rect);
3512
3513           DV(g_print(" invalidated rect: %d,%d %d x %d\n",
3514                      redraw_rect.x,
3515                      redraw_rect.y,
3516                      redraw_rect.width,
3517                      redraw_rect.height));
3518           
3519           if (text_view->left_window)
3520             text_window_invalidate_rect (text_view->left_window,
3521                                          &redraw_rect);
3522           if (text_view->right_window)
3523             text_window_invalidate_rect (text_view->right_window,
3524                                          &redraw_rect);
3525           if (text_view->top_window)
3526             text_window_invalidate_rect (text_view->top_window,
3527                                          &redraw_rect);
3528           if (text_view->bottom_window)
3529             text_window_invalidate_rect (text_view->bottom_window,
3530                                          &redraw_rect);
3531
3532           gtk_text_view_update_im_spot_location (text_view);
3533         }
3534     }
3535   
3536   if (old_height != new_height)
3537     {
3538       gboolean yoffset_changed = FALSE;
3539       GSList *tmp_list;
3540       int new_first_para_top;
3541       int old_first_para_top;
3542       GtkTextIter first;
3543       
3544       /* If the bottom of the old area was above the top of the
3545        * screen, we need to scroll to keep the current top of the
3546        * screen in place.  Remember that first_para_pixels is the
3547        * position of the top of the screen in coordinates relative to
3548        * the first paragraph onscreen.
3549        *
3550        * In short we are adding the height delta of the portion of the
3551        * changed region above first_para_mark to text_view->yoffset.
3552        */
3553       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &first,
3554                                         text_view->first_para_mark);
3555
3556       gtk_text_layout_get_line_yrange (layout, &first, &new_first_para_top, NULL);
3557
3558       old_first_para_top = text_view->yoffset - text_view->first_para_pixels;
3559
3560       if (new_first_para_top != old_first_para_top)
3561         {
3562           text_view->yoffset += new_first_para_top - old_first_para_top;
3563           
3564           get_vadjustment (text_view)->value = text_view->yoffset;
3565           yoffset_changed = TRUE;
3566         }
3567
3568       if (yoffset_changed)
3569         {
3570           DV(g_print ("Changing scroll position (%s)\n", G_STRLOC));
3571           gtk_adjustment_value_changed (get_vadjustment (text_view));
3572         }
3573
3574       /* FIXME be smarter about which anchored widgets we update */
3575
3576       tmp_list = text_view->children;
3577       while (tmp_list != NULL)
3578         {
3579           GtkTextViewChild *child = tmp_list->data;
3580
3581           if (child->anchor)
3582             gtk_text_view_update_child_allocation (text_view, child);
3583
3584           tmp_list = g_slist_next (tmp_list);
3585         }
3586     }
3587
3588   {
3589     GtkRequisition old_req;
3590     GtkRequisition new_req;
3591
3592     old_req = widget->requisition;
3593
3594     /* Use this instead of gtk_widget_size_request wrapper
3595      * to avoid the optimization which just returns widget->requisition
3596      * if a resize hasn't been queued.
3597      */
3598     GTK_WIDGET_GET_CLASS (widget)->size_request (widget, &new_req);
3599
3600     if (old_req.width != new_req.width ||
3601         old_req.height != new_req.height)
3602       {
3603         gtk_widget_queue_resize_no_redraw (widget);
3604       }
3605   }
3606 }
3607
3608 static void
3609 gtk_text_view_realize (GtkWidget *widget)
3610 {
3611   GtkTextView *text_view;
3612   GdkWindowAttr attributes;
3613   gint attributes_mask;
3614   GSList *tmp_list;
3615   
3616   text_view = GTK_TEXT_VIEW (widget);
3617   GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
3618
3619   attributes.window_type = GDK_WINDOW_CHILD;
3620   attributes.x = widget->allocation.x;
3621   attributes.y = widget->allocation.y;
3622   attributes.width = widget->allocation.width;
3623   attributes.height = widget->allocation.height;
3624   attributes.wclass = GDK_INPUT_OUTPUT;
3625   attributes.visual = gtk_widget_get_visual (widget);
3626   attributes.colormap = gtk_widget_get_colormap (widget);
3627   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
3628
3629   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3630
3631   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
3632                                    &attributes, attributes_mask);
3633   gdk_window_set_user_data (widget->window, widget);
3634
3635   /* must come before text_window_realize calls */
3636   widget->style = gtk_style_attach (widget->style, widget->window);
3637
3638   gdk_window_set_background (widget->window,
3639                              &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3640
3641   text_window_realize (text_view->text_window, widget);
3642
3643   if (text_view->left_window)
3644     text_window_realize (text_view->left_window, widget);
3645
3646   if (text_view->top_window)
3647     text_window_realize (text_view->top_window, widget);
3648
3649   if (text_view->right_window)
3650     text_window_realize (text_view->right_window, widget);
3651
3652   if (text_view->bottom_window)
3653     text_window_realize (text_view->bottom_window, widget);
3654
3655   gtk_text_view_ensure_layout (text_view);
3656
3657   if (text_view->buffer)
3658     {
3659       GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
3660                                                           GDK_SELECTION_PRIMARY);
3661       gtk_text_buffer_add_selection_clipboard (text_view->buffer, clipboard);
3662     }
3663
3664   tmp_list = text_view->children;
3665   while (tmp_list != NULL)
3666     {
3667       GtkTextViewChild *vc = tmp_list->data;
3668       
3669       text_view_child_set_parent_window (text_view, vc);
3670       
3671       tmp_list = tmp_list->next;
3672     }
3673 }
3674
3675 static void
3676 gtk_text_view_unrealize (GtkWidget *widget)
3677 {
3678   GtkTextView *text_view;
3679   
3680   text_view = GTK_TEXT_VIEW (widget);
3681
3682   if (text_view->buffer)
3683     {
3684       GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
3685                                                           GDK_SELECTION_PRIMARY);
3686       gtk_text_buffer_remove_selection_clipboard (text_view->buffer, clipboard);
3687     }
3688
3689   gtk_text_view_remove_validate_idles (text_view);
3690
3691   if (text_view->popup_menu)
3692     {
3693       gtk_widget_destroy (text_view->popup_menu);
3694       text_view->popup_menu = NULL;
3695     }
3696
3697   text_window_unrealize (text_view->text_window);
3698
3699   if (text_view->left_window)
3700     text_window_unrealize (text_view->left_window);
3701
3702   if (text_view->top_window)
3703     text_window_unrealize (text_view->top_window);
3704
3705   if (text_view->right_window)
3706     text_window_unrealize (text_view->right_window);
3707
3708   if (text_view->bottom_window)
3709     text_window_unrealize (text_view->bottom_window);
3710
3711   gtk_text_view_destroy_layout (text_view);
3712   
3713   (* GTK_WIDGET_CLASS (gtk_text_view_parent_class)->unrealize) (widget);
3714 }
3715
3716 static void 
3717 gtk_text_view_set_background (GtkTextView *text_view)
3718 {
3719   GtkWidget *widget = GTK_WIDGET (text_view);
3720
3721   gdk_window_set_background (widget->window,
3722                              &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3723   
3724   gdk_window_set_background (text_view->text_window->bin_window,
3725                              &widget->style->base[GTK_WIDGET_STATE (widget)]);
3726   
3727   if (text_view->left_window)
3728     gdk_window_set_background (text_view->left_window->bin_window,
3729                                &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3730   if (text_view->right_window)
3731     gdk_window_set_background (text_view->right_window->bin_window,
3732                                &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3733   
3734   if (text_view->top_window)
3735     gdk_window_set_background (text_view->top_window->bin_window,
3736                                &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3737   
3738   if (text_view->bottom_window)
3739     gdk_window_set_background (text_view->bottom_window->bin_window,
3740                                &widget->style->bg[GTK_WIDGET_STATE (widget)]);
3741 }
3742
3743 static void
3744 gtk_text_view_style_set (GtkWidget *widget,
3745                          GtkStyle  *previous_style)
3746 {
3747   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3748   PangoContext *ltr_context, *rtl_context;
3749
3750   if (GTK_WIDGET_REALIZED (widget))
3751     {
3752       gtk_text_view_set_background (text_view);
3753     }
3754
3755   if (text_view->layout && previous_style)
3756     {
3757       gtk_text_view_set_attributes_from_style (text_view,
3758                                                text_view->layout->default_style,
3759                                                widget->style);
3760       
3761       
3762       ltr_context = gtk_widget_create_pango_context (widget);
3763       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
3764       rtl_context = gtk_widget_create_pango_context (widget);
3765       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
3766
3767       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
3768
3769       g_object_unref (ltr_context);
3770       g_object_unref (rtl_context);
3771     }
3772 }
3773
3774 static void
3775 gtk_text_view_direction_changed (GtkWidget        *widget,
3776                                  GtkTextDirection  previous_direction)
3777 {
3778   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3779
3780   if (text_view->layout)
3781     {
3782       text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
3783
3784       gtk_text_layout_default_style_changed (text_view->layout);
3785     }
3786 }
3787
3788 static void
3789 gtk_text_view_state_changed (GtkWidget      *widget,
3790                              GtkStateType    previous_state)
3791 {
3792   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
3793   GdkCursor *cursor;
3794
3795   if (GTK_WIDGET_REALIZED (widget))
3796     {
3797       gtk_text_view_set_background (text_view);
3798
3799       if (GTK_WIDGET_IS_SENSITIVE (widget))
3800         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
3801       else
3802         cursor = NULL;
3803
3804       gdk_window_set_cursor (text_view->text_window->bin_window, cursor);
3805
3806       if (cursor)
3807       gdk_cursor_unref (cursor);
3808
3809       text_view->mouse_cursor_obscured = FALSE;
3810     }
3811
3812   if (!GTK_WIDGET_IS_SENSITIVE (widget))
3813     {
3814       /* Clear any selection */
3815       gtk_text_view_unselect (text_view);
3816     }
3817   
3818   gtk_widget_queue_draw (widget);
3819 }
3820
3821 static void
3822 set_invisible_cursor (GdkWindow *window)
3823 {
3824   GdkBitmap *empty_bitmap;
3825   GdkCursor *cursor;
3826   GdkColor useless;
3827   char invisible_cursor_bits[] = { 0x0 };       
3828         
3829   useless.red = useless.green = useless.blue = 0;
3830   useless.pixel = 0;
3831   
3832   empty_bitmap = gdk_bitmap_create_from_data (window,
3833                                               invisible_cursor_bits,
3834                                               1, 1);
3835   
3836   cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
3837                                        empty_bitmap,
3838                                        &useless,
3839                                        &useless, 0, 0);
3840   
3841   gdk_window_set_cursor (window, cursor);
3842   
3843   gdk_cursor_unref (cursor);
3844   
3845   g_object_unref (empty_bitmap);
3846 }
3847
3848 static void
3849 gtk_text_view_obscure_mouse_cursor (GtkTextView *text_view)
3850 {
3851   if (text_view->mouse_cursor_obscured)
3852     return;
3853
3854   set_invisible_cursor (text_view->text_window->bin_window);
3855   
3856   text_view->mouse_cursor_obscured = TRUE;  
3857 }
3858
3859 static void
3860 gtk_text_view_unobscure_mouse_cursor (GtkTextView *text_view)
3861 {
3862   if (text_view->mouse_cursor_obscured)
3863     {
3864       GdkCursor *cursor;
3865       
3866       cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)),
3867                                            GDK_XTERM);
3868       gdk_window_set_cursor (text_view->text_window->bin_window, cursor);
3869       gdk_cursor_unref (cursor);
3870       text_view->mouse_cursor_obscured = FALSE;
3871     }
3872 }
3873
3874 static void
3875 gtk_text_view_grab_notify (GtkWidget *widget,
3876                            gboolean   was_grabbed)
3877 {
3878   if (!was_grabbed)
3879     {
3880       gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
3881       gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
3882     }
3883 }
3884
3885
3886 /*
3887  * Events
3888  */
3889
3890 static gboolean
3891 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
3892 {
3893   if (event)
3894     switch (event->type)
3895       {
3896       case GDK_MOTION_NOTIFY:
3897         *x = event->motion.x;
3898         *y = event->motion.y;
3899         return TRUE;
3900         break;
3901
3902       case GDK_BUTTON_PRESS:
3903       case GDK_2BUTTON_PRESS:
3904       case GDK_3BUTTON_PRESS:
3905       case GDK_BUTTON_RELEASE:
3906         *x = event->button.x;
3907         *y = event->button.y;
3908         return TRUE;
3909         break;
3910
3911       case GDK_KEY_PRESS:
3912       case GDK_KEY_RELEASE:
3913       case GDK_ENTER_NOTIFY:
3914       case GDK_LEAVE_NOTIFY:
3915       case GDK_PROPERTY_NOTIFY:
3916       case GDK_SELECTION_CLEAR:
3917       case GDK_SELECTION_REQUEST:
3918       case GDK_SELECTION_NOTIFY:
3919       case GDK_PROXIMITY_IN:
3920       case GDK_PROXIMITY_OUT:
3921       case GDK_DRAG_ENTER:
3922       case GDK_DRAG_LEAVE:
3923       case GDK_DRAG_MOTION:
3924       case GDK_DRAG_STATUS:
3925       case GDK_DROP_START:
3926       case GDK_DROP_FINISHED:
3927       default:
3928         return FALSE;
3929         break;
3930       }
3931
3932   return FALSE;
3933 }
3934
3935 static gint
3936 emit_event_on_tags (GtkWidget   *widget,
3937                     GdkEvent    *event,
3938                     GtkTextIter *iter)
3939 {
3940   GSList *tags;
3941   GSList *tmp;
3942   gboolean retval = FALSE;
3943
3944   tags = gtk_text_iter_get_tags (iter);
3945
3946   tmp = tags;
3947   while (tmp != NULL)
3948     {
3949       GtkTextTag *tag = tmp->data;
3950
3951       if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
3952         {
3953           retval = TRUE;
3954           break;
3955         }
3956
3957       tmp = g_slist_next (tmp);
3958     }
3959
3960   g_slist_free (tags);
3961
3962   return retval;
3963 }
3964
3965 static gint
3966 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
3967 {
3968   GtkTextView *text_view;
3969   gint x = 0, y = 0;
3970
3971   text_view = GTK_TEXT_VIEW (widget);
3972
3973   if (text_view->layout == NULL ||
3974       get_buffer (text_view) == NULL)
3975     return FALSE;
3976
3977   if (event->any.window != text_view->text_window->bin_window)
3978     return FALSE;
3979
3980   if (get_event_coordinates (event, &x, &y))
3981     {
3982       GtkTextIter iter;
3983
3984       x += text_view->xoffset;
3985       y += text_view->yoffset;
3986
3987       /* FIXME this is slow and we do it twice per event.
3988        * My favorite solution is to have GtkTextLayout cache
3989        * the last couple lookups.
3990        */
3991       gtk_text_layout_get_iter_at_pixel (text_view->layout,
3992                                          &iter,
3993                                          x, y);
3994
3995       return emit_event_on_tags (widget, event, &iter);
3996     }
3997   else if (event->type == GDK_KEY_PRESS ||
3998            event->type == GDK_KEY_RELEASE)
3999     {
4000       GtkTextMark *insert;
4001       GtkTextIter iter;
4002
4003       insert = gtk_text_buffer_get_mark (get_buffer (text_view),
4004                                          "insert");
4005
4006       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4007
4008       return emit_event_on_tags (widget, event, &iter);
4009     }
4010   else
4011     return FALSE;
4012 }
4013
4014 static gint
4015 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
4016 {
4017   gboolean retval = FALSE;
4018   gboolean obscure = FALSE;
4019   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4020   GtkTextMark *insert;
4021   GtkTextIter iter;
4022   gboolean can_insert;
4023   
4024   if (text_view->layout == NULL ||
4025       get_buffer (text_view) == NULL)
4026     return FALSE;
4027
4028   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4029   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4030   can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
4031   if (gtk_im_context_filter_keypress (text_view->im_context, event))
4032     {
4033       text_view->need_im_reset = TRUE;
4034       if (!can_insert)
4035         gtk_text_view_reset_im_context (text_view);
4036       obscure = can_insert;
4037       retval = TRUE;
4038     }
4039   /* Binding set */
4040   else if (GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event &&
4041            GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event (widget, event))
4042     retval = TRUE;
4043   /* use overall editability not can_insert, more predictable for users */
4044   else if (text_view->editable &&
4045            (event->keyval == GDK_Return ||
4046             event->keyval == GDK_KP_Enter))
4047     {
4048       /* this won't actually insert the newline if the cursor isn't
4049        * editable
4050        */
4051       gtk_text_view_reset_im_context (text_view);
4052       gtk_text_view_commit_text (text_view, "\n");
4053
4054       obscure = TRUE;
4055       retval = TRUE;
4056     }
4057   /* Pass through Tab as literal tab, unless Control is held down */
4058   else if ((event->keyval == GDK_Tab ||
4059             event->keyval == GDK_KP_Tab ||
4060             event->keyval == GDK_ISO_Left_Tab) &&
4061            !(event->state & GDK_CONTROL_MASK))
4062     {
4063       /* If the text widget isn't editable overall, or if the application
4064        * has turned off "accepts_tab", move the focus instead
4065        */
4066       if (text_view->accepts_tab && text_view->editable)
4067         {
4068           gtk_text_view_reset_im_context (text_view);
4069           gtk_text_view_commit_text (text_view, "\t");
4070           obscure = TRUE;
4071         }
4072       else
4073         g_signal_emit_by_name (text_view, "move-focus",
4074                                (event->state & GDK_SHIFT_MASK) ?
4075                                GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
4076
4077       retval = TRUE;
4078     }
4079   else
4080     retval = FALSE;
4081
4082   if (obscure)
4083     gtk_text_view_obscure_mouse_cursor (text_view);
4084   
4085   gtk_text_view_reset_blink_time (text_view);
4086   gtk_text_view_pend_cursor_blink (text_view);
4087
4088   return retval;
4089 }
4090
4091 static gint
4092 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
4093 {
4094   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4095   GtkTextMark *insert;
4096   GtkTextIter iter;
4097
4098   if (text_view->layout == NULL || get_buffer (text_view) == NULL)
4099     return FALSE;
4100       
4101   insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4102   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4103   if (gtk_text_iter_can_insert (&iter, text_view->editable) &&
4104       gtk_im_context_filter_keypress (text_view->im_context, event))
4105     {
4106       text_view->need_im_reset = TRUE;
4107       return TRUE;
4108     }
4109   else
4110     return GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_release_event (widget, event);
4111 }
4112
4113 static gint
4114 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
4115 {
4116   GtkTextView *text_view;
4117
4118   text_view = GTK_TEXT_VIEW (widget);
4119
4120   gtk_widget_grab_focus (widget);
4121
4122   if (event->window != text_view->text_window->bin_window)
4123     {
4124       /* Remove selection if any. */
4125       gtk_text_view_unselect (text_view);
4126       return FALSE;
4127     }
4128
4129   gtk_text_view_reset_blink_time (text_view);
4130
4131 #if 0
4132   /* debug hack */
4133   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
4134     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
4135   else if (event->button == 3)
4136     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
4137 #endif
4138
4139   if (event->type == GDK_BUTTON_PRESS)
4140     {
4141       gtk_text_view_reset_im_context (text_view);
4142
4143       if (event->button == 1)
4144         {
4145           /* If we're in the selection, start a drag copy/move of the
4146            * selection; otherwise, start creating a new selection.
4147            */
4148           GtkTextIter iter;
4149           GtkTextIter start, end;
4150
4151           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4152                                              &iter,
4153                                              event->x + text_view->xoffset,
4154                                              event->y + text_view->yoffset);
4155
4156           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4157                                                     &start, &end) &&
4158               gtk_text_iter_in_range (&iter, &start, &end))
4159             {
4160               text_view->drag_start_x = event->x;
4161               text_view->drag_start_y = event->y;
4162               text_view->pending_place_cursor_button = event->button;
4163             }
4164           else
4165             {
4166               gtk_text_view_start_selection_drag (text_view, &iter, event);
4167             }
4168
4169           return TRUE;
4170         }
4171       else if (event->button == 2)
4172         {
4173           GtkTextIter iter;
4174
4175           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4176                                              &iter,
4177                                              event->x + text_view->xoffset,
4178                                              event->y + text_view->yoffset);
4179
4180           gtk_text_buffer_paste_clipboard (get_buffer (text_view),
4181                                            gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY),
4182                                            &iter,
4183                                            text_view->editable);
4184           return TRUE;
4185         }
4186       else if (event->button == 3)
4187         {
4188           gtk_text_view_do_popup (text_view, event);
4189           return TRUE;
4190         }
4191     }
4192   else if ((event->type == GDK_2BUTTON_PRESS ||
4193             event->type == GDK_3BUTTON_PRESS) &&
4194            event->button == 1) 
4195     {
4196       GtkTextIter iter;
4197
4198       gtk_text_view_end_selection_drag (text_view);
4199
4200       gtk_text_layout_get_iter_at_pixel (text_view->layout,
4201                                          &iter,
4202                                          event->x + text_view->xoffset,
4203                                          event->y + text_view->yoffset);
4204       
4205       gtk_text_view_start_selection_drag (text_view, &iter, event);
4206       return TRUE;
4207     }
4208   
4209   return FALSE;
4210 }
4211
4212 static gint
4213 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
4214 {
4215   GtkTextView *text_view;
4216
4217   text_view = GTK_TEXT_VIEW (widget);
4218
4219   if (event->window != text_view->text_window->bin_window)
4220     return FALSE;
4221
4222   if (event->button == 1)
4223     {
4224       if (text_view->drag_start_x >= 0)
4225         {
4226           text_view->drag_start_x = -1;
4227           text_view->drag_start_y = -1;
4228         }
4229
4230       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget)))
4231         return TRUE;
4232       else if (text_view->pending_place_cursor_button == event->button)
4233         {
4234           GtkTextIter iter;
4235
4236           /* Unselect everything; we clicked inside selection, but
4237            * didn't move by the drag threshold, so just clear selection
4238            * and place cursor.
4239            */
4240           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4241                                              &iter,
4242                                              event->x + text_view->xoffset,
4243                                              event->y + text_view->yoffset);
4244
4245           gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
4246           gtk_text_view_check_cursor_blink (text_view);
4247           
4248           text_view->pending_place_cursor_button = 0;
4249           
4250           return FALSE;
4251         }
4252     }
4253
4254   return FALSE;
4255 }
4256
4257 static void
4258 keymap_direction_changed (GdkKeymap   *keymap,
4259                           GtkTextView *text_view)
4260 {
4261   gtk_text_view_check_keymap_direction (text_view);
4262 }
4263
4264 static gint
4265 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
4266 {
4267   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4268
4269   gtk_widget_queue_draw (widget);
4270
4271   DV(g_print (G_STRLOC": focus_in_event\n"));
4272
4273   gtk_text_view_reset_blink_time (text_view);
4274
4275   if (text_view->cursor_visible && text_view->layout)
4276     {
4277       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4278       gtk_text_view_check_cursor_blink (text_view);
4279     }
4280
4281   g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4282                     "direction_changed",
4283                     G_CALLBACK (keymap_direction_changed), text_view);
4284   gtk_text_view_check_keymap_direction (text_view);
4285   
4286   text_view->need_im_reset = TRUE;
4287   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
4288
4289   return FALSE;
4290 }
4291
4292 static gint
4293 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
4294 {
4295   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4296
4297   gtk_text_view_end_selection_drag (text_view);
4298
4299   gtk_widget_queue_draw (widget);
4300
4301   DV(g_print (G_STRLOC": focus_out_event\n"));
4302   
4303   if (text_view->cursor_visible && text_view->layout)
4304     {
4305       gtk_text_view_check_cursor_blink (text_view);
4306       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4307     }
4308
4309   g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4310                                         keymap_direction_changed,
4311                                         text_view);
4312
4313   text_view->need_im_reset = TRUE;
4314   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
4315
4316   return FALSE;
4317 }
4318
4319 static gint
4320 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
4321 {
4322   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4323
4324   gtk_text_view_unobscure_mouse_cursor (text_view);
4325
4326   if (event->window == text_view->text_window->bin_window &&
4327       text_view->drag_start_x >= 0)
4328     {
4329       gint x = event->x;
4330       gint y = event->y;
4331
4332       gdk_event_request_motions (event);
4333
4334       if (gtk_drag_check_threshold (widget,
4335                                     text_view->drag_start_x, 
4336                                     text_view->drag_start_y,
4337                                     x, y))
4338         {
4339           GtkTextIter iter;
4340           gint buffer_x, buffer_y;
4341
4342           gtk_text_view_window_to_buffer_coords (text_view,
4343                                                  GTK_TEXT_WINDOW_TEXT,
4344                                                  text_view->drag_start_x,
4345                                                  text_view->drag_start_y,
4346                                                  &buffer_x,
4347                                                  &buffer_y);
4348
4349           gtk_text_layout_get_iter_at_pixel (text_view->layout,
4350                                              &iter,
4351                                              buffer_x, buffer_y);
4352
4353           gtk_text_view_start_selection_dnd (text_view, &iter, event);
4354           return TRUE;
4355         }
4356     }
4357
4358   return FALSE;
4359 }
4360
4361 static void
4362 gtk_text_view_paint (GtkWidget      *widget,
4363                      GdkRectangle   *area,
4364                      GdkEventExpose *event)
4365 {
4366   GtkTextView *text_view;
4367   GList *child_exposes;
4368   GList *tmp_list;
4369   GdkRegion *updates;
4370   
4371   text_view = GTK_TEXT_VIEW (widget);
4372
4373   g_return_if_fail (text_view->layout != NULL);
4374   g_return_if_fail (text_view->xoffset >= 0);
4375   g_return_if_fail (text_view->yoffset >= 0);
4376
4377   while (text_view->first_validate_idle != 0)
4378     {
4379       DV (g_print (G_STRLOC": first_validate_idle: %d\n",
4380                    text_view->first_validate_idle));
4381       gtk_text_view_flush_first_validate (text_view);
4382     }
4383
4384   /* More regions could have become invalid in the above loop */
4385   updates = gdk_window_get_update_area (text_view->text_window->bin_window);
4386   if (updates)
4387     {
4388       GdkRectangle rect;
4389       
4390       gdk_region_get_clipbox (updates, &rect);
4391
4392       gdk_rectangle_union (area, &rect, area);
4393       
4394       gdk_region_destroy (updates);
4395     }
4396   
4397   if (!text_view->onscreen_validated)
4398     {
4399       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.");
4400       g_assert_not_reached ();
4401     }
4402   
4403 #if 0
4404   printf ("painting %d,%d  %d x %d\n",
4405           area->x, area->y,
4406           area->width, area->height);
4407 #endif
4408
4409   child_exposes = NULL;
4410   gtk_text_layout_draw (text_view->layout,
4411                         widget,
4412                         text_view->text_window->bin_window,
4413                         NULL,
4414                         text_view->xoffset,
4415                         text_view->yoffset,
4416                         area->x, area->y,
4417                         area->width, area->height,
4418                         &child_exposes);
4419
4420   tmp_list = child_exposes;
4421   while (tmp_list != NULL)
4422     {
4423       GtkWidget *child = tmp_list->data;
4424   
4425       gtk_container_propagate_expose (GTK_CONTAINER (text_view),
4426                                       child,
4427                                       event);
4428
4429       g_object_unref (child);
4430       
4431       tmp_list = tmp_list->next;
4432     }
4433
4434   g_list_free (child_exposes);
4435 }
4436
4437 static gint
4438 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
4439 {
4440   GSList *tmp_list;
4441   
4442   if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
4443                                                  GTK_TEXT_WINDOW_TEXT))
4444     {
4445       DV(g_print (">Exposed ("G_STRLOC")\n"));
4446       gtk_text_view_paint (widget, &event->area, event);
4447     }
4448
4449   if (event->window == widget->window)
4450     gtk_text_view_draw_focus (widget);
4451
4452   /* Propagate exposes to all unanchored children. 
4453    * Anchored children are handled in gtk_text_view_paint(). 
4454    */
4455   tmp_list = GTK_TEXT_VIEW (widget)->children;
4456   while (tmp_list != NULL)
4457     {
4458       GtkTextViewChild *vc = tmp_list->data;
4459
4460       /* propagate_expose checks that event->window matches
4461        * child->window
4462        */
4463       if (!vc->anchor)
4464         gtk_container_propagate_expose (GTK_CONTAINER (widget),
4465                                         vc->widget,
4466                                         event);
4467       
4468       tmp_list = tmp_list->next;
4469     }
4470   
4471   return FALSE;
4472 }
4473
4474 static void
4475 gtk_text_view_draw_focus (GtkWidget *widget)
4476 {
4477   gboolean interior_focus;
4478
4479   /* We clear the focus if we are in interior focus mode. */
4480   gtk_widget_style_get (widget,
4481                         "interior-focus", &interior_focus,
4482                         NULL);
4483   
4484   if (GTK_WIDGET_DRAWABLE (widget))
4485     {
4486       if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
4487         {          
4488           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
4489                            NULL, widget, "textview",
4490                            0, 0,
4491                            widget->allocation.width,
4492                            widget->allocation.height);
4493         }
4494       else
4495         {
4496           gdk_window_clear (widget->window);
4497         }
4498     }
4499 }
4500
4501 static gboolean
4502 gtk_text_view_focus (GtkWidget        *widget,
4503                      GtkDirectionType  direction)
4504 {
4505   GtkContainer *container;
4506   gboolean result;
4507   
4508   container = GTK_CONTAINER (widget);  
4509
4510   if (!gtk_widget_is_focus (widget) &&
4511       container->focus_child == NULL)
4512     {
4513       gtk_widget_grab_focus (widget);
4514       return TRUE;
4515     }
4516   else
4517     {
4518       /*
4519        * Unset CAN_FOCUS flag so that gtk_container_focus() allows
4520        * children to get the focus
4521        */
4522       GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS); 
4523       result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
4524       GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); 
4525
4526       return result;
4527     }
4528 }
4529
4530 static void
4531 gtk_text_view_move_focus (GtkWidget        *widget,
4532                           GtkDirectionType  direction_type)
4533 {
4534   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4535
4536   if (GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus)
4537     GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus (text_view,
4538                                                      direction_type);
4539 }
4540
4541 /*
4542  * Container
4543  */
4544
4545 static void
4546 gtk_text_view_add (GtkContainer *container,
4547                    GtkWidget    *child)
4548 {
4549   /* This is pretty random. */
4550   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
4551                                      child,
4552                                      GTK_TEXT_WINDOW_WIDGET,
4553                                      0, 0);
4554 }
4555
4556 static void
4557 gtk_text_view_remove (GtkContainer *container,
4558                       GtkWidget    *child)
4559 {
4560   GSList *iter;
4561   GtkTextView *text_view;
4562   GtkTextViewChild *vc;
4563
4564   text_view = GTK_TEXT_VIEW (container);
4565
4566   vc = NULL;
4567   iter = text_view->children;
4568
4569   while (iter != NULL)
4570     {
4571       vc = iter->data;
4572
4573       if (vc->widget == child)
4574         break;
4575
4576       iter = g_slist_next (iter);
4577     }
4578
4579   g_assert (iter != NULL); /* be sure we had the child in the list */
4580
4581   text_view->children = g_slist_remove (text_view->children, vc);
4582
4583   gtk_widget_unparent (vc->widget);
4584
4585   text_view_child_free (vc);
4586 }
4587
4588 static void
4589 gtk_text_view_forall (GtkContainer *container,
4590                       gboolean      include_internals,
4591                       GtkCallback   callback,
4592                       gpointer      callback_data)
4593 {
4594   GSList *iter;
4595   GtkTextView *text_view;
4596   GSList *copy;
4597
4598   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4599   g_return_if_fail (callback != NULL);
4600
4601   text_view = GTK_TEXT_VIEW (container);
4602
4603   copy = g_slist_copy (text_view->children);
4604   iter = copy;
4605
4606   while (iter != NULL)
4607     {
4608       GtkTextViewChild *vc = iter->data;
4609
4610       (* callback) (vc->widget, callback_data);
4611
4612       iter = g_slist_next (iter);
4613     }
4614
4615   g_slist_free (copy);
4616 }
4617
4618 #define CURSOR_ON_MULTIPLIER 2
4619 #define CURSOR_OFF_MULTIPLIER 1
4620 #define CURSOR_PEND_MULTIPLIER 3
4621 #define CURSOR_DIVIDER 3
4622
4623 static gboolean
4624 cursor_blinks (GtkTextView *text_view)
4625 {
4626   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4627   gboolean blink;
4628
4629 #ifdef DEBUG_VALIDATION_AND_SCROLLING
4630   return FALSE;
4631 #endif
4632   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
4633     return FALSE;
4634
4635   g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
4636
4637   if (!blink)
4638     return FALSE;
4639
4640   if (text_view->editable)
4641     {
4642       GtkTextMark *insert;
4643       GtkTextIter iter;
4644       
4645       insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4646       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4647       
4648       if (gtk_text_iter_editable (&iter, text_view->editable))
4649         return blink;
4650     }
4651
4652   return FALSE;
4653 }
4654
4655 static gint
4656 get_cursor_time (GtkTextView *text_view)
4657 {
4658   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4659   gint time;
4660
4661   g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
4662
4663   return time;
4664 }
4665
4666 static gint
4667 get_cursor_blink_timeout (GtkTextView *text_view)
4668 {
4669   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4670   gint time;
4671
4672   g_object_get (settings, "gtk-cursor-blink-timeout", &time, NULL);
4673
4674   return time;
4675 }
4676
4677
4678 /*
4679  * Blink!
4680  */
4681
4682 static gint
4683 blink_cb (gpointer data)
4684 {
4685   GtkTextView *text_view;
4686   GtkTextViewPrivate *priv;
4687   gboolean visible;
4688   gint blink_timeout;
4689
4690   text_view = GTK_TEXT_VIEW (data);
4691   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
4692
4693   if (!GTK_WIDGET_HAS_FOCUS (text_view))
4694     {
4695       g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
4696                  "connect a handler to this signal, it must return\n"
4697                  "FALSE so the text view gets the event as well");
4698
4699       gtk_text_view_check_cursor_blink (text_view);
4700
4701       return FALSE;
4702     }
4703
4704   g_assert (text_view->layout);
4705   g_assert (text_view->cursor_visible);
4706
4707   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
4708
4709   blink_timeout = get_cursor_blink_timeout (text_view);
4710   if (priv->blink_time > 1000 * blink_timeout &&
4711       blink_timeout < G_MAXINT/1000) 
4712     {
4713       /* we've blinked enough without the user doing anything, stop blinking */
4714       visible = 0;
4715       text_view->blink_timeout = 0;
4716     } 
4717   else if (visible)
4718     text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
4719                                               blink_cb,
4720                                               text_view);
4721   else 
4722     {
4723       text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
4724                                                 blink_cb,
4725                                                 text_view);
4726       priv->blink_time += get_cursor_time (text_view);
4727     }
4728
4729   /* Block changed_handler while changing the layout's cursor visibility
4730    * because it would expose the whole paragraph. Instead, we expose
4731    * the cursor's area(s) manually below.
4732    */
4733   g_signal_handlers_block_by_func (text_view->layout,
4734                                    changed_handler,
4735                                    text_view);
4736   gtk_text_layout_set_cursor_visible (text_view->layout, !visible);
4737   g_signal_handlers_unblock_by_func (text_view->layout,
4738                                      changed_handler,
4739                                      text_view);
4740
4741   text_window_invalidate_cursors (text_view->text_window);
4742
4743   /* Remove ourselves */
4744   return FALSE;
4745 }
4746
4747
4748 static void
4749 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
4750 {
4751   if (text_view->blink_timeout)  
4752     { 
4753       g_source_remove (text_view->blink_timeout);
4754       text_view->blink_timeout = 0;
4755     }
4756 }
4757
4758 static void
4759 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
4760 {
4761   if (text_view->layout != NULL &&
4762       text_view->cursor_visible &&
4763       GTK_WIDGET_HAS_FOCUS (text_view))
4764     {
4765       if (cursor_blinks (text_view))
4766         {
4767           if (text_view->blink_timeout == 0)
4768             {
4769               gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4770               
4771               text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
4772                                                         blink_cb,
4773                                                         text_view);
4774             }
4775         }
4776       else
4777         {
4778           gtk_text_view_stop_cursor_blink (text_view);
4779           gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4780         }
4781     }
4782   else
4783     {
4784       gtk_text_view_stop_cursor_blink (text_view);
4785       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
4786     }
4787 }
4788
4789 static void
4790 gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
4791 {
4792   if (text_view->layout != NULL &&
4793       text_view->cursor_visible &&
4794       GTK_WIDGET_HAS_FOCUS (text_view) &&
4795       cursor_blinks (text_view))
4796     {
4797       gtk_text_view_stop_cursor_blink (text_view);
4798       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
4799       
4800       text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
4801                                                 blink_cb,
4802                                                 text_view);
4803     }
4804 }
4805
4806 static void
4807 gtk_text_view_reset_blink_time (GtkTextView *text_view)
4808 {
4809   GtkTextViewPrivate *priv;
4810
4811   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
4812
4813   priv->blink_time = 0;
4814 }
4815
4816
4817 /*
4818  * Key binding handlers
4819  */
4820
4821 static gboolean
4822 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
4823                                   GtkTextIter *newplace,
4824                                   gint         count)
4825 {
4826   gboolean ret = TRUE;
4827
4828   while (count < 0)
4829     {
4830       ret = gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
4831       count++;
4832     }
4833
4834   while (count > 0)
4835     {
4836       ret = gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
4837       count--;
4838     }
4839
4840   return ret;
4841 }
4842
4843 static void
4844 move_cursor (GtkTextView       *text_view,
4845              const GtkTextIter *new_location,
4846              gboolean           extend_selection)
4847 {
4848   if (extend_selection)
4849     gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
4850                                        "insert",
4851                                        new_location);
4852   else
4853       gtk_text_buffer_place_cursor (get_buffer (text_view),
4854                                     new_location);
4855   gtk_text_view_check_cursor_blink (text_view);
4856 }
4857
4858 static void
4859 gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
4860                                     GtkMovementStep  step,
4861                                     gint             count,
4862                                     gboolean         extend_selection)
4863 {
4864   GtkTextIter insert;
4865   GtkTextIter newplace;
4866   gint cursor_x_pos = 0;
4867   GtkDirectionType leave_direction = -1;
4868
4869   if (!text_view->cursor_visible) 
4870     {
4871       GtkScrollStep scroll_step;
4872
4873       switch (step) 
4874         {
4875         case GTK_MOVEMENT_VISUAL_POSITIONS:
4876           leave_direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
4877           /* fall through */
4878         case GTK_MOVEMENT_LOGICAL_POSITIONS:
4879         case GTK_MOVEMENT_WORDS:
4880           scroll_step = GTK_SCROLL_HORIZONTAL_STEPS;
4881           break;
4882         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4883           scroll_step = GTK_SCROLL_HORIZONTAL_ENDS;
4884           break;          
4885         case GTK_MOVEMENT_DISPLAY_LINES:
4886           leave_direction = count > 0 ? GTK_DIR_DOWN : GTK_DIR_UP;
4887           /* fall through */
4888         case GTK_MOVEMENT_PARAGRAPHS:
4889         case GTK_MOVEMENT_PARAGRAPH_ENDS:
4890           scroll_step = GTK_SCROLL_STEPS;
4891           break;
4892         case GTK_MOVEMENT_PAGES:
4893           scroll_step = GTK_SCROLL_PAGES;
4894           break;
4895         case GTK_MOVEMENT_HORIZONTAL_PAGES:
4896           scroll_step = GTK_SCROLL_HORIZONTAL_PAGES;
4897           break;
4898         case GTK_MOVEMENT_BUFFER_ENDS:
4899           scroll_step = GTK_SCROLL_ENDS;
4900           break;
4901         default:
4902           scroll_step = GTK_SCROLL_PAGES;
4903           break;
4904         }
4905
4906       if (!gtk_text_view_move_viewport (text_view, scroll_step, count))
4907         {
4908           if (leave_direction != -1 &&
4909               !gtk_widget_keynav_failed (GTK_WIDGET (text_view),
4910                                          leave_direction))
4911             {
4912               g_signal_emit_by_name (text_view, "move-focus", leave_direction);
4913             }
4914         }
4915
4916       return;
4917     }
4918
4919   gtk_text_view_reset_im_context (text_view);
4920
4921   if (step == GTK_MOVEMENT_PAGES)
4922     {
4923       if (!gtk_text_view_scroll_pages (text_view, count, extend_selection))
4924         gtk_widget_error_bell (GTK_WIDGET (text_view));
4925
4926       gtk_text_view_check_cursor_blink (text_view);
4927       gtk_text_view_pend_cursor_blink (text_view);
4928       return;
4929     }
4930   else if (step == GTK_MOVEMENT_HORIZONTAL_PAGES)
4931     {
4932       if (!gtk_text_view_scroll_hpages (text_view, count, extend_selection))
4933         gtk_widget_error_bell (GTK_WIDGET (text_view));
4934
4935       gtk_text_view_check_cursor_blink (text_view);
4936       gtk_text_view_pend_cursor_blink (text_view);
4937       return;
4938     }
4939
4940   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4941                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4942                                                               "insert"));
4943   newplace = insert;
4944
4945   if (step == GTK_MOVEMENT_DISPLAY_LINES)
4946     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
4947
4948   switch (step)
4949     {
4950     case GTK_MOVEMENT_LOGICAL_POSITIONS:
4951       gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
4952       break;
4953
4954     case GTK_MOVEMENT_VISUAL_POSITIONS:
4955       gtk_text_layout_move_iter_visually (text_view->layout,
4956                                           &newplace, count);
4957       break;
4958
4959     case GTK_MOVEMENT_WORDS:
4960       if (count < 0)
4961         gtk_text_iter_backward_visible_word_starts (&newplace, -count);
4962       else if (count > 0) 
4963         {
4964           if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
4965             gtk_text_iter_forward_to_line_end (&newplace);
4966         }
4967       break;
4968
4969     case GTK_MOVEMENT_DISPLAY_LINES:
4970       if (count < 0)
4971         {
4972           leave_direction = GTK_DIR_UP;
4973
4974           if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
4975             gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
4976           else
4977             gtk_text_iter_set_line_offset (&newplace, 0);
4978         }
4979       if (count > 0)
4980         {
4981           leave_direction = GTK_DIR_DOWN;
4982
4983           if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
4984             gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
4985           else
4986             gtk_text_iter_forward_to_line_end (&newplace);
4987         }
4988       break;
4989
4990     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4991       if (count > 1)
4992         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
4993       else if (count < -1)
4994         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
4995
4996       if (count != 0)
4997         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
4998       break;
4999
5000     case GTK_MOVEMENT_PARAGRAPHS:
5001       if (count > 0)
5002         {
5003           if (!gtk_text_iter_ends_line (&newplace))
5004             {
5005               gtk_text_iter_forward_to_line_end (&newplace);
5006               --count;
5007             }
5008           gtk_text_iter_forward_visible_lines (&newplace, count);
5009           gtk_text_iter_forward_to_line_end (&newplace);
5010         }
5011       else if (count < 0)
5012         {
5013           if (gtk_text_iter_get_line_offset (&newplace) > 0)
5014             gtk_text_iter_set_line_offset (&newplace, 0);
5015           gtk_text_iter_forward_visible_lines (&newplace, count);
5016           gtk_text_iter_set_line_offset (&newplace, 0);
5017         }
5018       break;
5019
5020     case GTK_MOVEMENT_PARAGRAPH_ENDS:
5021       if (count > 0)
5022         {
5023           if (!gtk_text_iter_ends_line (&newplace))
5024             gtk_text_iter_forward_to_line_end (&newplace);
5025         }
5026       else if (count < 0)
5027         {
5028           gtk_text_iter_set_line_offset (&newplace, 0);
5029         }
5030       break;
5031
5032     case GTK_MOVEMENT_BUFFER_ENDS:
5033       if (count > 0)
5034         gtk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
5035       else if (count < 0)
5036         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
5037      break;
5038       
5039     default:
5040       break;
5041     }
5042
5043   /* call move_cursor() even if the cursor hasn't moved, since it 
5044      cancels the selection
5045   */
5046   move_cursor (text_view, &newplace, extend_selection);
5047
5048   if (!gtk_text_iter_equal (&insert, &newplace))
5049     {
5050       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5051       gtk_text_view_scroll_mark_onscreen (text_view,
5052                                           gtk_text_buffer_get_mark (get_buffer (text_view),
5053                                                                     "insert"));
5054
5055       if (step == GTK_MOVEMENT_DISPLAY_LINES)
5056         gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
5057     }
5058   else if (leave_direction != -1)
5059     {
5060       if (!gtk_widget_keynav_failed (GTK_WIDGET (text_view),
5061                                      leave_direction))
5062         {
5063           g_signal_emit_by_name (text_view, "move-focus", leave_direction);
5064         }
5065     }
5066   else
5067     {
5068       gtk_widget_error_bell (GTK_WIDGET (text_view));
5069     }
5070
5071   gtk_text_view_check_cursor_blink (text_view);
5072   gtk_text_view_pend_cursor_blink (text_view);
5073 }
5074
5075 static void
5076 gtk_text_view_move_cursor (GtkTextView     *text_view,
5077                            GtkMovementStep  step,
5078                            gint             count,
5079                            gboolean         extend_selection)
5080 {
5081   gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
5082 }
5083
5084 static void
5085 gtk_text_view_page_horizontally (GtkTextView     *text_view,
5086                                  gint             count,
5087                                  gboolean         extend_selection)
5088 {
5089   gtk_text_view_move_cursor_internal (text_view, GTK_MOVEMENT_HORIZONTAL_PAGES,
5090                                       count, extend_selection);
5091 }
5092
5093
5094 static gboolean
5095 gtk_text_view_move_viewport (GtkTextView     *text_view,
5096                              GtkScrollStep    step,
5097                              gint             count)
5098 {
5099   GtkAdjustment *adjustment;
5100   gdouble increment;
5101   
5102   switch (step) 
5103     {
5104     case GTK_SCROLL_STEPS:
5105     case GTK_SCROLL_PAGES:
5106     case GTK_SCROLL_ENDS:
5107       adjustment = get_vadjustment (text_view);
5108       break;
5109     case GTK_SCROLL_HORIZONTAL_STEPS:
5110     case GTK_SCROLL_HORIZONTAL_PAGES:
5111     case GTK_SCROLL_HORIZONTAL_ENDS:
5112       adjustment = get_hadjustment (text_view);
5113       break;
5114     default:
5115       adjustment = get_vadjustment (text_view);
5116       break;
5117     }
5118
5119   switch (step) 
5120     {
5121     case GTK_SCROLL_STEPS:
5122     case GTK_SCROLL_HORIZONTAL_STEPS:
5123       increment = adjustment->step_increment;
5124       break;
5125     case GTK_SCROLL_PAGES:
5126     case GTK_SCROLL_HORIZONTAL_PAGES:
5127       increment = adjustment->page_increment;
5128       break;
5129     case GTK_SCROLL_ENDS:
5130     case GTK_SCROLL_HORIZONTAL_ENDS:
5131       increment = adjustment->upper - adjustment->lower;
5132       break;
5133     default:
5134       increment = 0.0;
5135       break;
5136     }
5137
5138   return set_adjustment_clamped (adjustment, adjustment->value + count * increment);
5139 }
5140
5141 static void
5142 gtk_text_view_set_anchor (GtkTextView *text_view)
5143 {
5144   GtkTextIter insert;
5145
5146   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5147                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5148                                                               "insert"));
5149
5150   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
5151 }
5152
5153 static gboolean
5154 gtk_text_view_scroll_pages (GtkTextView *text_view,
5155                             gint         count,
5156                             gboolean     extend_selection)
5157 {
5158   gdouble newval;
5159   gdouble oldval;
5160   GtkAdjustment *adj;
5161   gint cursor_x_pos, cursor_y_pos;
5162   GtkTextIter old_insert;
5163   GtkTextIter new_insert;
5164   GtkTextIter anchor;
5165   gint y0, y1;
5166
5167   g_return_val_if_fail (text_view->vadjustment != NULL, FALSE);
5168   
5169   adj = text_view->vadjustment;
5170
5171   /* Make sure we start from the current cursor position, even
5172    * if it was offscreen, but don't queue more scrolls if we're
5173    * already behind.
5174    */
5175   if (text_view->pending_scroll)
5176     cancel_pending_scroll (text_view);
5177   else
5178     gtk_text_view_scroll_mark_onscreen (text_view,
5179                                         gtk_text_buffer_get_mark (get_buffer (text_view),
5180                                                                   "insert"));
5181
5182   /* Validate the region that will be brought into view by the cursor motion
5183    */
5184   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5185                                     &old_insert,
5186                                     gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
5187
5188   if (count < 0)
5189     {
5190       gtk_text_view_get_first_para_iter (text_view, &anchor);
5191       y0 = adj->page_size;
5192       y1 = adj->page_size + count * adj->page_increment;
5193     }
5194   else
5195     {
5196       gtk_text_view_get_first_para_iter (text_view, &anchor);
5197       y0 = count * adj->page_increment + adj->page_size;
5198       y1 = 0;
5199     }
5200
5201   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
5202   /* FIXME do we need to update the adjustment ranges here? */
5203
5204   new_insert = old_insert;
5205
5206   if (count < 0 && adj->value <= (adj->lower + 1e-12))
5207     {
5208       /* already at top, just be sure we are at offset 0 */
5209       gtk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
5210       move_cursor (text_view, &new_insert, extend_selection);
5211     }
5212   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5213     {
5214       /* already at bottom, just be sure we are at the end */
5215       gtk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
5216       move_cursor (text_view, &new_insert, extend_selection);
5217     }
5218   else
5219     {
5220       gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
5221
5222       oldval = adj->value;
5223       newval = adj->value;
5224
5225       newval += count * adj->page_increment;
5226
5227       set_adjustment_clamped (adj, newval);
5228       cursor_y_pos += adj->value - oldval;
5229
5230       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5231       clamp_iter_onscreen (text_view, &new_insert);
5232       move_cursor (text_view, &new_insert, extend_selection);
5233
5234       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5235     }
5236   
5237   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5238    * only guarantees 1 pixel onscreen.
5239    */
5240   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5241   gtk_text_view_scroll_mark_onscreen (text_view,
5242                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5243                                                                 "insert"));
5244
5245   return !gtk_text_iter_equal (&old_insert, &new_insert);
5246 }
5247
5248 static gboolean
5249 gtk_text_view_scroll_hpages (GtkTextView *text_view,
5250                              gint         count,
5251                              gboolean     extend_selection)
5252 {
5253   gdouble newval;
5254   gdouble oldval;
5255   GtkAdjustment *adj;
5256   gint cursor_x_pos, cursor_y_pos;
5257   GtkTextIter old_insert;
5258   GtkTextIter new_insert;
5259   gint y, height;
5260   
5261   g_return_val_if_fail (text_view->hadjustment != NULL, FALSE);
5262
5263   adj = text_view->hadjustment;
5264
5265   /* Make sure we start from the current cursor position, even
5266    * if it was offscreen, but don't queue more scrolls if we're
5267    * already behind.
5268    */
5269   if (text_view->pending_scroll)
5270     cancel_pending_scroll (text_view);
5271   else
5272     gtk_text_view_scroll_mark_onscreen (text_view,
5273                                         gtk_text_buffer_get_mark (get_buffer (text_view),
5274                                                                   "insert"));
5275
5276   /* Validate the line that we're moving within.
5277    */
5278   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5279                                     &old_insert,
5280                                     gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
5281   gtk_text_layout_get_line_yrange (text_view->layout, &old_insert, &y, &height);
5282   gtk_text_layout_validate_yrange (text_view->layout, &old_insert, y, y + height);
5283   /* FIXME do we need to update the adjustment ranges here? */
5284
5285   new_insert = old_insert;
5286
5287   if (count < 0 && adj->value <= (adj->lower + 1e-12))
5288     {
5289       /* already at far left, just be sure we are at offset 0 */
5290       gtk_text_iter_set_line_offset (&new_insert, 0);
5291       move_cursor (text_view, &new_insert, extend_selection);
5292     }
5293   else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5294     {
5295       /* already at far right, just be sure we are at the end */
5296       if (!gtk_text_iter_ends_line (&new_insert))
5297           gtk_text_iter_forward_to_line_end (&new_insert);
5298       move_cursor (text_view, &new_insert, extend_selection);
5299     }
5300   else
5301     {
5302       gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
5303
5304       oldval = adj->value;
5305       newval = adj->value;
5306
5307       newval += count * adj->page_increment;
5308
5309       set_adjustment_clamped (adj, newval);
5310       cursor_x_pos += adj->value - oldval;
5311
5312       gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5313       clamp_iter_onscreen (text_view, &new_insert);
5314       move_cursor (text_view, &new_insert, extend_selection);
5315
5316       gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5317     }
5318
5319   /*  FIXME for lines shorter than the overall widget width, this results in a
5320    *  "bounce" effect as we scroll to the right of the widget, then scroll
5321    *  back to get the end of the line onscreen.
5322    *      http://bugzilla.gnome.org/show_bug.cgi?id=68963
5323    */
5324   
5325   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5326    * only guarantees 1 pixel onscreen.
5327    */
5328   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5329   gtk_text_view_scroll_mark_onscreen (text_view,
5330                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5331                                                                 "insert"));
5332
5333   return !gtk_text_iter_equal (&old_insert, &new_insert);
5334 }
5335
5336 static gboolean
5337 whitespace (gunichar ch, gpointer user_data)
5338 {
5339   return (ch == ' ' || ch == '\t');
5340 }
5341
5342 static gboolean
5343 not_whitespace (gunichar ch, gpointer user_data)
5344 {
5345   return !whitespace (ch, user_data);
5346 }
5347
5348 static gboolean
5349 find_whitepace_region (const GtkTextIter *center,
5350                        GtkTextIter *start, GtkTextIter *end)
5351 {
5352   *start = *center;
5353   *end = *center;
5354
5355   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
5356     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
5357   if (whitespace (gtk_text_iter_get_char (end), NULL))
5358     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
5359
5360   return !gtk_text_iter_equal (start, end);
5361 }
5362
5363 static void
5364 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
5365                                 const gchar *str)
5366 {
5367   if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
5368                                                      text_view->editable))
5369     {
5370       gtk_widget_error_bell (GTK_WIDGET (text_view));
5371     }
5372 }
5373
5374 static void
5375 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
5376                                   GtkDeleteType  type,
5377                                   gint           count)
5378 {
5379   GtkTextIter insert;
5380   GtkTextIter start;
5381   GtkTextIter end;
5382   gboolean leave_one = FALSE;
5383
5384   gtk_text_view_reset_im_context (text_view);
5385
5386   if (type == GTK_DELETE_CHARS)
5387     {
5388       /* Char delete deletes the selection, if one exists */
5389       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5390                                             text_view->editable))
5391         return;
5392     }
5393
5394   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5395                                     &insert,
5396                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5397                                                               "insert"));
5398
5399   start = insert;
5400   end = insert;
5401
5402   switch (type)
5403     {
5404     case GTK_DELETE_CHARS:
5405       gtk_text_iter_forward_cursor_positions (&end, count);
5406       break;
5407
5408     case GTK_DELETE_WORD_ENDS:
5409       if (count > 0)
5410         gtk_text_iter_forward_word_ends (&end, count);
5411       else if (count < 0)
5412         gtk_text_iter_backward_word_starts (&start, 0 - count);
5413       break;
5414
5415     case GTK_DELETE_WORDS:
5416       break;
5417
5418     case GTK_DELETE_DISPLAY_LINE_ENDS:
5419       break;
5420
5421     case GTK_DELETE_DISPLAY_LINES:
5422       break;
5423
5424     case GTK_DELETE_PARAGRAPH_ENDS:
5425       /* If we're already at a newline, we need to
5426        * simply delete that newline, instead of
5427        * moving to the next one.
5428        */
5429       if (gtk_text_iter_ends_line (&end))
5430         {
5431           gtk_text_iter_forward_line (&end);
5432           --count;
5433         }
5434
5435       while (count > 0)
5436         {
5437           if (!gtk_text_iter_forward_to_line_end (&end))
5438             break;
5439
5440           --count;
5441         }
5442
5443       /* FIXME figure out what a negative count means
5444          and support that */
5445       break;
5446
5447     case GTK_DELETE_PARAGRAPHS:
5448       if (count > 0)
5449         {
5450           gtk_text_iter_set_line_offset (&start, 0);
5451           gtk_text_iter_forward_to_line_end (&end);
5452
5453           /* Do the lines beyond the first. */
5454           while (count > 1)
5455             {
5456               gtk_text_iter_forward_to_line_end (&end);
5457
5458               --count;
5459             }
5460         }
5461
5462       /* FIXME negative count? */
5463
5464       break;
5465
5466     case GTK_DELETE_WHITESPACE:
5467       {
5468         find_whitepace_region (&insert, &start, &end);
5469       }
5470       break;
5471
5472     default:
5473       break;
5474     }
5475
5476   if (!gtk_text_iter_equal (&start, &end))
5477     {
5478       gtk_text_buffer_begin_user_action (get_buffer (text_view));
5479
5480       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
5481                                               text_view->editable))
5482         {
5483           if (leave_one)
5484             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
5485                                                           " ", 1,
5486                                                           text_view->editable);
5487         }
5488       else
5489         {
5490           gtk_widget_error_bell (GTK_WIDGET (text_view));
5491         }
5492
5493       gtk_text_buffer_end_user_action (get_buffer (text_view));
5494       gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5495
5496       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5497       gtk_text_view_scroll_mark_onscreen (text_view,
5498                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
5499     }
5500   else
5501     {
5502       gtk_widget_error_bell (GTK_WIDGET (text_view));
5503     }
5504 }
5505
5506 static void
5507 gtk_text_view_backspace (GtkTextView *text_view)
5508 {
5509   GtkTextIter insert;
5510
5511   gtk_text_view_reset_im_context (text_view);
5512
5513   /* Backspace deletes the selection, if one exists */
5514   if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5515                                         text_view->editable))
5516     return;
5517
5518   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5519                                     &insert,
5520                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
5521
5522   if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
5523                                  TRUE, text_view->editable))
5524     {
5525       gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5526       DV(g_print (G_STRLOC": scrolling onscreen\n"));
5527       gtk_text_view_scroll_mark_onscreen (text_view,
5528                                           gtk_text_buffer_get_insert (get_buffer (text_view)));
5529     }
5530   else
5531     {
5532       gtk_widget_error_bell (GTK_WIDGET (text_view));
5533     }
5534 }
5535
5536 static void
5537 gtk_text_view_cut_clipboard (GtkTextView *text_view)
5538 {
5539   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5540                                                       GDK_SELECTION_CLIPBOARD);
5541   
5542   gtk_text_buffer_cut_clipboard (get_buffer (text_view),
5543                                  clipboard,
5544                                  text_view->editable);
5545   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5546   gtk_text_view_scroll_mark_onscreen (text_view,
5547                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
5548 }
5549
5550 static void
5551 gtk_text_view_copy_clipboard (GtkTextView *text_view)
5552 {
5553   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5554                                                       GDK_SELECTION_CLIPBOARD);
5555   
5556   gtk_text_buffer_copy_clipboard (get_buffer (text_view),
5557                                   clipboard);
5558
5559   /* on copy do not scroll, we are already onscreen */
5560 }
5561
5562 static void
5563 gtk_text_view_paste_clipboard (GtkTextView *text_view)
5564 {
5565   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5566                                                       GDK_SELECTION_CLIPBOARD);
5567   
5568   gtk_text_buffer_paste_clipboard (get_buffer (text_view),
5569                                    clipboard,
5570                                    NULL,
5571                                    text_view->editable);
5572   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5573   gtk_text_view_scroll_mark_onscreen (text_view,
5574                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
5575 }
5576
5577 static void
5578 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
5579 {
5580   if (text_view->text_window)
5581     text_window_invalidate_cursors (text_view->text_window);
5582
5583   text_view->overwrite_mode = !text_view->overwrite_mode;
5584
5585   if (text_view->layout)
5586     gtk_text_layout_set_overwrite_mode (text_view->layout,
5587                                         text_view->overwrite_mode && text_view->editable);
5588
5589   if (text_view->text_window)
5590     text_window_invalidate_cursors (text_view->text_window);
5591
5592   gtk_text_view_pend_cursor_blink (text_view);
5593
5594   g_object_notify (G_OBJECT (text_view), "overwrite");
5595 }
5596
5597 /**
5598  * gtk_text_view_get_overwrite:
5599  * @text_view: a #GtkTextView
5600  *
5601  * Returns whether the #GtkTextView is in overwrite mode or not.
5602  *
5603  * Return value: whether @text_view is in overwrite mode or not.
5604  * 
5605  * Since: 2.4
5606  **/
5607 gboolean
5608 gtk_text_view_get_overwrite (GtkTextView *text_view)
5609 {
5610   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5611
5612   return text_view->overwrite_mode;
5613 }
5614
5615 /**
5616  * gtk_text_view_set_overwrite:
5617  * @text_view: a #GtkTextView
5618  * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
5619  *
5620  * Changes the #GtkTextView overwrite mode.
5621  *
5622  * Since: 2.4
5623  **/
5624 void
5625 gtk_text_view_set_overwrite (GtkTextView *text_view,
5626                              gboolean     overwrite)
5627 {
5628   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5629   overwrite = overwrite != FALSE;
5630
5631   if (text_view->overwrite_mode != overwrite)
5632     gtk_text_view_toggle_overwrite (text_view);
5633 }
5634
5635 /**
5636  * gtk_text_view_set_accepts_tab:
5637  * @text_view: A #GtkTextView
5638  * @accepts_tab: %TRUE if pressing the Tab key should insert a tab 
5639  *    character, %FALSE, if pressing the Tab key should move the 
5640  *    keyboard focus.
5641  * 
5642  * Sets the behavior of the text widget when the Tab key is pressed. 
5643  * If @accepts_tab is %TRUE, a tab character is inserted. If @accepts_tab 
5644  * is %FALSE the keyboard focus is moved to the next widget in the focus 
5645  * chain.
5646  * 
5647  * Since: 2.4
5648  **/
5649 void
5650 gtk_text_view_set_accepts_tab (GtkTextView *text_view,
5651                                gboolean     accepts_tab)
5652 {
5653   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5654
5655   accepts_tab = accepts_tab != FALSE;
5656
5657   if (text_view->accepts_tab != accepts_tab)
5658     {
5659       text_view->accepts_tab = accepts_tab;
5660
5661       g_object_notify (G_OBJECT (text_view), "accepts-tab");
5662     }
5663 }
5664
5665 /**
5666  * gtk_text_view_get_accepts_tab:
5667  * @text_view: A #GtkTextView
5668  * 
5669  * Returns whether pressing the Tab key inserts a tab characters.
5670  * gtk_text_view_set_accepts_tab().
5671  * 
5672  * Return value: %TRUE if pressing the Tab key inserts a tab character, 
5673  *   %FALSE if pressing the Tab key moves the keyboard focus.
5674  * 
5675  * Since: 2.4
5676  **/
5677 gboolean
5678 gtk_text_view_get_accepts_tab (GtkTextView *text_view)
5679 {
5680   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5681
5682   return text_view->accepts_tab;
5683 }
5684
5685 static void
5686 gtk_text_view_compat_move_focus (GtkTextView     *text_view,
5687                                  GtkDirectionType direction_type)
5688 {
5689   GSignalInvocationHint *hint = g_signal_get_invocation_hint (text_view);
5690
5691   /*  as of GTK+ 2.12, the "move-focus" signal has been moved to GtkWidget,
5692    *  the evil code below makes sure that both emitting the signal and
5693    *  calling the virtual function directly continue to work as expetcted
5694    */
5695
5696   if (hint->signal_id == g_signal_lookup ("move-focus", GTK_TYPE_WIDGET))
5697     {
5698       /*  if this is a signal emission, chain up  */
5699
5700       GValue instance_and_params[2] = { { 0, }, { 0, } };
5701       GValue return_value = { 0, };
5702
5703       g_value_init (&instance_and_params[0], GTK_TYPE_WIDGET);
5704       g_value_set_object (&instance_and_params[0], text_view);
5705
5706       g_value_init (&instance_and_params[1], GTK_TYPE_DIRECTION_TYPE);
5707       g_value_set_enum (&instance_and_params[1], direction_type);
5708
5709       g_value_init (&return_value, G_TYPE_BOOLEAN);
5710
5711       g_signal_chain_from_overridden (instance_and_params, &return_value);
5712
5713       g_value_unset (&instance_and_params[0]);
5714       g_value_unset (&instance_and_params[1]);
5715       g_value_unset (&return_value);
5716     }
5717   else
5718     {
5719       /*  otherwise emit the signal, since somebody called the virtual
5720        *  function directly
5721        */
5722
5723       g_signal_emit_by_name (text_view, "move-focus", direction_type);
5724     }
5725 }
5726
5727 /*
5728  * Selections
5729  */
5730
5731 static void
5732 gtk_text_view_unselect (GtkTextView *text_view)
5733 {
5734   GtkTextIter insert;
5735
5736   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5737                                     &insert,
5738                                     gtk_text_buffer_get_mark (get_buffer (text_view),
5739                                                               "insert"));
5740
5741   gtk_text_buffer_move_mark (get_buffer (text_view),
5742                              gtk_text_buffer_get_mark (get_buffer (text_view),
5743                                                        "selection_bound"),
5744                              &insert);
5745 }
5746
5747 static void
5748 get_iter_at_pointer (GtkTextView *text_view,
5749                      GtkTextIter *iter,
5750                      gint        *x,
5751                      gint        *y)
5752 {
5753   gint xcoord, ycoord;
5754   GdkModifierType state;
5755
5756   gdk_window_get_pointer (text_view->text_window->bin_window,
5757                           &xcoord, &ycoord, &state);
5758   
5759   gtk_text_layout_get_iter_at_pixel (text_view->layout,
5760                                      iter,
5761                                      xcoord + text_view->xoffset,
5762                                      ycoord + text_view->yoffset);
5763   if (x)
5764     *x = xcoord;
5765
5766   if (y)
5767     *y = ycoord;
5768 }
5769
5770 static void
5771 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
5772                                  const gchar *mark_name)
5773 {
5774   GtkTextIter newplace;
5775   GtkTextMark *mark;
5776
5777   get_iter_at_pointer (text_view, &newplace, NULL, NULL);
5778   
5779   mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
5780   
5781   /* This may invalidate the layout */
5782   DV(g_print (G_STRLOC": move mark\n"));
5783   
5784   gtk_text_buffer_move_mark (get_buffer (text_view),
5785                              mark,
5786                              &newplace);
5787   
5788   DV(g_print (G_STRLOC": scrolling onscreen\n"));
5789   gtk_text_view_scroll_mark_onscreen (text_view, mark);
5790
5791   DV (g_print ("first validate idle leaving %s is %d\n",
5792                G_STRLOC, text_view->first_validate_idle));
5793 }
5794
5795 static gboolean
5796 selection_scan_timeout (gpointer data)
5797 {
5798   GtkTextView *text_view;
5799
5800   text_view = GTK_TEXT_VIEW (data);
5801
5802   DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
5803   gtk_text_view_scroll_mark_onscreen (text_view, 
5804                                       gtk_text_buffer_get_mark (get_buffer (text_view),
5805                                                                 "insert"));
5806
5807   return TRUE; /* remain installed. */
5808 }
5809
5810 #define UPPER_OFFSET_ANCHOR 0.8
5811 #define LOWER_OFFSET_ANCHOR 0.2
5812
5813 static gboolean
5814 check_scroll (gdouble offset, GtkAdjustment *adj)
5815 {
5816   if ((offset > UPPER_OFFSET_ANCHOR &&
5817        adj->value + adj->page_size < adj->upper) ||
5818       (offset < LOWER_OFFSET_ANCHOR &&
5819        adj->value > adj->lower))
5820     return TRUE;
5821
5822   return FALSE;
5823 }
5824
5825 static gint
5826 drag_scan_timeout (gpointer data)
5827 {
5828   GtkTextView *text_view;
5829   GtkTextIter newplace;
5830   gint x, y, width, height;
5831   gdouble pointer_xoffset, pointer_yoffset;
5832
5833   text_view = GTK_TEXT_VIEW (data);
5834
5835   get_iter_at_pointer (text_view, &newplace, &x, &y);
5836   gdk_drawable_get_size (text_view->text_window->bin_window, &width, &height);
5837
5838   gtk_text_buffer_move_mark (get_buffer (text_view),
5839                              text_view->dnd_mark,
5840                              &newplace);
5841
5842   pointer_xoffset = (gdouble) x / width;
5843   pointer_yoffset = (gdouble) y / height;
5844
5845   if (check_scroll (pointer_xoffset, text_view->hadjustment) ||
5846       check_scroll (pointer_yoffset, text_view->vadjustment))
5847     {
5848       /* do not make offsets surpass lower nor upper anchors, this makes
5849        * scrolling speed relative to the distance of the pointer to the
5850        * anchors when it moves beyond them.
5851        */
5852       pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
5853       pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
5854
5855       gtk_text_view_scroll_to_mark (text_view,
5856                                     text_view->dnd_mark,
5857                                     0., TRUE, pointer_xoffset, pointer_yoffset);
5858     }
5859
5860   return TRUE;
5861 }
5862
5863 typedef enum 
5864 {
5865   SELECT_CHARACTERS,
5866   SELECT_WORDS,
5867   SELECT_LINES
5868 } SelectionGranularity;
5869
5870 /*
5871  * Move @start and @end to the boundaries of the selection unit (indicated by 
5872  * @granularity) which contained @start initially.
5873  * If the selction unit is SELECT_WORDS and @start is not contained in a word
5874  * the selection is extended to all the white spaces between the end of the 
5875  * word preceding @start and the start of the one following.
5876  */
5877 static void
5878 extend_selection (GtkTextView *text_view, 
5879                   SelectionGranularity granularity, 
5880                   GtkTextIter *start, 
5881                   GtkTextIter *end)
5882 {
5883   *end = *start;
5884
5885   if (granularity == SELECT_WORDS) 
5886     {
5887       if (gtk_text_iter_inside_word (start))
5888         {
5889           if (!gtk_text_iter_starts_word (start))
5890             gtk_text_iter_backward_visible_word_start (start);
5891           
5892           if (!gtk_text_iter_ends_word (end))
5893             {
5894               if (!gtk_text_iter_forward_visible_word_end (end))
5895                 gtk_text_iter_forward_to_end (end);
5896             }
5897         }
5898       else
5899         {
5900           GtkTextIter tmp;
5901
5902           tmp = *start;
5903           if (gtk_text_iter_backward_visible_word_start (&tmp))
5904             gtk_text_iter_forward_visible_word_end (&tmp);
5905
5906           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
5907             *start = tmp;
5908           else
5909             gtk_text_iter_set_line_offset (start, 0);
5910
5911           tmp = *end;
5912           if (!gtk_text_iter_forward_visible_word_end (&tmp))
5913             gtk_text_iter_forward_to_end (&tmp);
5914
5915           if (gtk_text_iter_ends_word (&tmp))
5916             gtk_text_iter_backward_visible_word_start (&tmp);
5917
5918           if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
5919             *end = tmp;
5920           else
5921             gtk_text_iter_forward_to_line_end (end);
5922         }
5923     }
5924   else if (granularity == SELECT_LINES) 
5925     {
5926       if (gtk_text_view_starts_display_line (text_view, start))
5927         {
5928           /* If on a display line boundary, we assume the user
5929            * clicked off the end of a line and we therefore select
5930            * the line before the boundary.
5931            */
5932           gtk_text_view_backward_display_line_start (text_view, start);
5933         }
5934       else
5935         {
5936           /* start isn't on the start of a line, so we move it to the
5937            * start, and move end to the end unless it's already there.
5938            */
5939           gtk_text_view_backward_display_line_start (text_view, start);
5940           
5941           if (!gtk_text_view_starts_display_line (text_view, end))
5942             gtk_text_view_forward_display_line_end (text_view, end);
5943         }
5944     }
5945 }
5946  
5947
5948 typedef struct
5949 {
5950   SelectionGranularity granularity;
5951   GtkTextMark *orig_start;
5952   GtkTextMark *orig_end;
5953 } SelectionData;
5954
5955 static void
5956 selection_data_free (SelectionData *data)
5957 {
5958   if (data->orig_start != NULL)
5959     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_start),
5960                                  data->orig_start);
5961   if (data->orig_end != NULL)
5962     gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_end),
5963                                  data->orig_end);
5964   g_free (data);
5965 }
5966
5967 static gint
5968 selection_motion_event_handler (GtkTextView    *text_view, 
5969                                 GdkEventMotion *event, 
5970                                 SelectionData  *data)
5971 {
5972   gdk_event_request_motions (event);
5973
5974   if (data->granularity == SELECT_CHARACTERS) 
5975     {
5976       move_mark_to_pointer_and_scroll (text_view, "insert");
5977     }
5978   else 
5979     {
5980       GtkTextIter cursor, start, end;
5981       GtkTextIter orig_start, orig_end;
5982       GtkTextBuffer *buffer;
5983       
5984       buffer = get_buffer (text_view);
5985
5986       gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
5987       gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
5988
5989       get_iter_at_pointer (text_view, &cursor, NULL, NULL);
5990       
5991       start = cursor;
5992       extend_selection (text_view, data->granularity, &start, &end);
5993
5994       /* either the selection extends to the front, or end (or not) */
5995       if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
5996         gtk_text_buffer_select_range (buffer, &start, &orig_end);
5997       else
5998         gtk_text_buffer_select_range (buffer, &end, &orig_start);
5999
6000       gtk_text_view_scroll_mark_onscreen (text_view, 
6001                                           gtk_text_buffer_get_insert (buffer));
6002     }
6003
6004   /* If we had to scroll offscreen, insert a timeout to do so
6005    * again. Note that in the timeout, even if the mouse doesn't
6006    * move, due to this scroll xoffset/yoffset will have changed
6007    * and we'll need to scroll again.
6008    */
6009   if (text_view->scroll_timeout != 0) /* reset on every motion event */
6010     g_source_remove (text_view->scroll_timeout);
6011   
6012   text_view->scroll_timeout =
6013     gdk_threads_add_timeout (50, selection_scan_timeout, text_view);
6014
6015   return TRUE;
6016 }
6017
6018 static void
6019 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
6020                                     const GtkTextIter *iter,
6021                                     GdkEventButton    *button)
6022 {
6023   GtkTextIter cursor, ins, bound;
6024   GtkTextIter orig_start, orig_end;
6025   GtkTextBuffer *buffer;
6026   SelectionData *data;
6027
6028   if (text_view->selection_drag_handler != 0)
6029     return;
6030   
6031   data = g_new0 (SelectionData, 1);
6032
6033   if (button->type == GDK_2BUTTON_PRESS)
6034     data->granularity = SELECT_WORDS;
6035   else if (button->type == GDK_3BUTTON_PRESS)
6036     data->granularity = SELECT_LINES;
6037   else 
6038     data->granularity = SELECT_CHARACTERS;
6039
6040   gtk_grab_add (GTK_WIDGET (text_view));
6041
6042   buffer = get_buffer (text_view);
6043   
6044   cursor = *iter;
6045   ins = cursor;
6046   
6047   extend_selection (text_view, data->granularity, &ins, &bound);
6048   orig_start = ins;
6049   orig_end = bound;
6050
6051   if (button->state & GDK_SHIFT_MASK)
6052     {
6053       /* Extend selection */
6054       GtkTextIter old_ins, old_bound;
6055       GtkTextIter old_start, old_end;
6056
6057       gtk_text_buffer_get_iter_at_mark (buffer, &old_ins, gtk_text_buffer_get_insert (buffer));
6058       gtk_text_buffer_get_iter_at_mark (buffer, &old_bound, gtk_text_buffer_get_selection_bound (buffer));
6059       old_start = old_ins;
6060       old_end = old_bound;
6061       gtk_text_iter_order (&old_start, &old_end);
6062       
6063       /* move the front cursor, if the mouse is in front of the selection. Should the
6064        * cursor however be inside the selection (this happens on tripple click) then we
6065        * move the side which was last moved (current insert mark) */
6066       if (gtk_text_iter_compare (&cursor, &old_start) <= 0 ||
6067           (gtk_text_iter_compare (&cursor, &old_end) < 0 && 
6068            gtk_text_iter_compare (&old_ins, &old_bound) <= 0))
6069         {
6070           bound = old_end;
6071           orig_start = old_end;
6072           orig_end = old_end;
6073         }
6074       else
6075         {
6076           ins = bound;
6077           bound = old_start;
6078           orig_end = bound;
6079           orig_start = bound;
6080         }
6081     }
6082
6083   gtk_text_buffer_select_range (buffer, &ins, &bound);
6084
6085   gtk_text_iter_order (&orig_start, &orig_end);
6086   data->orig_start = gtk_text_buffer_create_mark (buffer, NULL,
6087                                                   &orig_start, TRUE);
6088   data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
6089                                                 &orig_end, TRUE);
6090
6091   gtk_text_view_check_cursor_blink (text_view);
6092
6093   text_view->selection_drag_handler = g_signal_connect_data (text_view,
6094                                                              "motion_notify_event",
6095                                                              G_CALLBACK (selection_motion_event_handler),
6096                                                              data,
6097                                                              (GClosureNotify) selection_data_free, 0);  
6098 }
6099
6100 /* returns whether we were really dragging */
6101 static gboolean
6102 gtk_text_view_end_selection_drag (GtkTextView    *text_view) 
6103 {
6104   if (text_view->selection_drag_handler == 0)
6105     return FALSE;
6106
6107   g_signal_handler_disconnect (text_view, text_view->selection_drag_handler);
6108   text_view->selection_drag_handler = 0;
6109
6110   if (text_view->scroll_timeout != 0)
6111     {
6112       g_source_remove (text_view->scroll_timeout);
6113       text_view->scroll_timeout = 0;
6114     }
6115
6116   gtk_grab_remove (GTK_WIDGET (text_view));
6117
6118   return TRUE;
6119 }
6120
6121 /*
6122  * Layout utils
6123  */
6124
6125 static void
6126 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
6127                                          GtkTextAttributes  *values,
6128                                          GtkStyle           *style)
6129 {
6130   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
6131   values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
6132
6133   if (values->font)
6134     pango_font_description_free (values->font);
6135
6136   values->font = pango_font_description_copy (style->font_desc);
6137 }
6138
6139 static void
6140 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
6141 {
6142   if (text_view->layout)
6143     {
6144       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
6145       GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
6146       GtkTextDirection new_cursor_dir;
6147       GtkTextDirection new_keyboard_dir;
6148       gboolean split_cursor;
6149
6150       g_object_get (settings,
6151                     "gtk-split-cursor", &split_cursor,
6152                     NULL);
6153       
6154       if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
6155         new_keyboard_dir = GTK_TEXT_DIR_RTL;
6156       else
6157         new_keyboard_dir  = GTK_TEXT_DIR_LTR;
6158   
6159       if (split_cursor)
6160         new_cursor_dir = GTK_TEXT_DIR_NONE;
6161       else
6162         new_cursor_dir = new_keyboard_dir;
6163       
6164       gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
6165       gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
6166     }
6167 }
6168
6169 static void
6170 gtk_text_view_ensure_layout (GtkTextView *text_view)
6171 {
6172   GtkWidget *widget;
6173
6174   widget = GTK_WIDGET (text_view);
6175
6176   if (text_view->layout == NULL)
6177     {
6178       GtkTextAttributes *style;
6179       PangoContext *ltr_context, *rtl_context;
6180       GSList *tmp_list;
6181
6182       DV(g_print(G_STRLOC"\n"));
6183       
6184       text_view->layout = gtk_text_layout_new ();
6185
6186       g_signal_connect (text_view->layout,
6187                         "invalidated",
6188                         G_CALLBACK (invalidated_handler),
6189                         text_view);
6190
6191       g_signal_connect (text_view->layout,
6192                         "changed",
6193                         G_CALLBACK (changed_handler),
6194                         text_view);
6195
6196       g_signal_connect (text_view->layout,
6197                         "allocate_child",
6198                         G_CALLBACK (gtk_text_view_child_allocated),
6199                         text_view);
6200       
6201       if (get_buffer (text_view))
6202         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
6203
6204       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
6205         gtk_text_view_pend_cursor_blink (text_view);
6206       else
6207         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
6208
6209       gtk_text_layout_set_overwrite_mode (text_view->layout,
6210                                           text_view->overwrite_mode && text_view->editable);
6211
6212       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6213       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
6214       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6215       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
6216
6217       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
6218
6219       g_object_unref (ltr_context);
6220       g_object_unref (rtl_context);
6221
6222       gtk_text_view_check_keymap_direction (text_view);
6223
6224       style = gtk_text_attributes_new ();
6225
6226       gtk_widget_ensure_style (widget);
6227       gtk_text_view_set_attributes_from_style (text_view,
6228                                                style, widget->style);
6229
6230       style->pixels_above_lines = text_view->pixels_above_lines;
6231       style->pixels_below_lines = text_view->pixels_below_lines;
6232       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
6233       style->left_margin = text_view->left_margin;
6234       style->right_margin = text_view->right_margin;
6235       style->indent = text_view->indent;
6236       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
6237
6238       style->wrap_mode = text_view->wrap_mode;
6239       style->justification = text_view->justify;
6240       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
6241
6242       gtk_text_layout_set_default_style (text_view->layout, style);
6243
6244       gtk_text_attributes_unref (style);
6245
6246       /* Set layout for all anchored children */
6247
6248       tmp_list = text_view->children;
6249       while (tmp_list != NULL)
6250         {
6251           GtkTextViewChild *vc = tmp_list->data;
6252
6253           if (vc->anchor)
6254             {
6255               gtk_text_anchored_child_set_layout (vc->widget,
6256                                                   text_view->layout);
6257               /* vc may now be invalid! */
6258             }
6259
6260           tmp_list = g_slist_next (tmp_list);
6261         }
6262
6263       gtk_text_view_invalidate (text_view);
6264     }
6265 }
6266
6267 /**
6268  * gtk_text_view_get_default_attributes:
6269  * @text_view: a #GtkTextView
6270  * 
6271  * Obtains a copy of the default text attributes. These are the
6272  * attributes used for text unless a tag overrides them.
6273  * You'd typically pass the default attributes in to
6274  * gtk_text_iter_get_attributes() in order to get the
6275  * attributes in effect at a given text position.
6276  *
6277  * The return value is a copy owned by the caller of this function,
6278  * and should be freed.
6279  * 
6280  * Return value: a new #GtkTextAttributes
6281  **/
6282 GtkTextAttributes*
6283 gtk_text_view_get_default_attributes (GtkTextView *text_view)
6284 {
6285   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
6286   
6287   gtk_text_view_ensure_layout (text_view);
6288
6289   return gtk_text_attributes_copy (text_view->layout->default_style);
6290 }
6291
6292 static void
6293 gtk_text_view_destroy_layout (GtkTextView *text_view)
6294 {
6295   if (text_view->layout)
6296     {
6297       GSList *tmp_list;
6298
6299       gtk_text_view_remove_validate_idles (text_view);
6300
6301       g_signal_handlers_disconnect_by_func (text_view->layout,
6302                                             invalidated_handler,
6303                                             text_view);
6304       g_signal_handlers_disconnect_by_func (text_view->layout,
6305                                             changed_handler, 
6306                                             text_view);
6307       
6308       /* Remove layout from all anchored children */
6309       tmp_list = text_view->children;
6310       while (tmp_list != NULL)
6311         {
6312           GtkTextViewChild *vc = tmp_list->data;
6313
6314           if (vc->anchor)
6315             {
6316               gtk_text_anchored_child_set_layout (vc->widget, NULL);
6317               /* vc may now be invalid! */
6318             }
6319
6320           tmp_list = g_slist_next (tmp_list);
6321         }
6322       
6323       gtk_text_view_stop_cursor_blink (text_view);
6324       gtk_text_view_end_selection_drag (text_view);
6325
6326       g_object_unref (text_view->layout);
6327       text_view->layout = NULL;
6328     }
6329 }
6330
6331 static void
6332 gtk_text_view_reset_im_context (GtkTextView *text_view)
6333 {
6334   if (text_view->need_im_reset)
6335     {
6336       text_view->need_im_reset = FALSE;
6337       gtk_im_context_reset (text_view->im_context);
6338     }
6339 }
6340
6341 /*
6342  * DND feature
6343  */
6344
6345 static void
6346 drag_begin_cb (GtkWidget      *widget,
6347                GdkDragContext *context,
6348                gpointer        data)
6349 {
6350   GtkTextView   *text_view = GTK_TEXT_VIEW (widget);
6351   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6352   GtkTextIter    start;
6353   GtkTextIter    end;
6354   GdkPixmap     *pixmap = NULL;
6355
6356   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
6357
6358   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6359     pixmap = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
6360
6361   if (pixmap)
6362     {
6363       gtk_drag_set_icon_pixmap (context,
6364                                 gdk_drawable_get_colormap (pixmap),
6365                                 pixmap,
6366                                 NULL,
6367                                 -2, -2);
6368       g_object_unref (pixmap);
6369     }
6370   else
6371     {
6372       gtk_drag_set_icon_default (context);
6373     }
6374 }
6375
6376 static void
6377 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
6378                                    const GtkTextIter *iter,
6379                                    GdkEventMotion    *event)
6380 {
6381   GtkTargetList *target_list;
6382
6383   text_view->drag_start_x = -1;
6384   text_view->drag_start_y = -1;
6385   text_view->pending_place_cursor_button = 0;
6386
6387   target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
6388
6389   g_signal_connect (text_view, "drag_begin",
6390                     G_CALLBACK (drag_begin_cb), NULL);
6391   gtk_drag_begin (GTK_WIDGET (text_view), target_list,
6392                   GDK_ACTION_COPY | GDK_ACTION_MOVE,
6393                   1, (GdkEvent*)event);
6394 }
6395
6396 static void
6397 gtk_text_view_drag_begin (GtkWidget        *widget,
6398                           GdkDragContext   *context)
6399 {
6400   /* do nothing */
6401 }
6402
6403 static void
6404 gtk_text_view_drag_end (GtkWidget        *widget,
6405                         GdkDragContext   *context)
6406 {
6407 }
6408
6409 static void
6410 gtk_text_view_drag_data_get (GtkWidget        *widget,
6411                              GdkDragContext   *context,
6412                              GtkSelectionData *selection_data,
6413                              guint             info,
6414                              guint             time)
6415 {
6416   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6417   GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6418
6419   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6420     {
6421       gtk_selection_data_set (selection_data,
6422                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
6423                               8, /* bytes */
6424                               (void*)&buffer,
6425                               sizeof (buffer));
6426     }
6427   else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6428     {
6429       GtkTextIter start;
6430       GtkTextIter end;
6431       guint8 *str = NULL;
6432       gsize len;
6433
6434       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6435         {
6436           /* Extract the selected text */
6437           str = gtk_text_buffer_serialize (buffer, buffer,
6438                                            selection_data->target,
6439                                            &start, &end,
6440                                            &len);
6441         }
6442
6443       if (str)
6444         {
6445           gtk_selection_data_set (selection_data,
6446                                   selection_data->target,
6447                                   8, /* bytes */
6448                                   (guchar *) str, len);
6449           g_free (str);
6450         }
6451     }
6452   else
6453     {
6454       GtkTextIter start;
6455       GtkTextIter end;
6456       gchar *str = NULL;
6457
6458       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6459         {
6460           /* Extract the selected text */
6461           str = gtk_text_iter_get_visible_text (&start, &end);
6462         }
6463
6464       if (str)
6465         {
6466           gtk_selection_data_set_text (selection_data, str, -1);
6467           g_free (str);
6468         }
6469     }
6470 }
6471
6472 static void
6473 gtk_text_view_drag_data_delete (GtkWidget        *widget,
6474                                 GdkDragContext   *context)
6475 {
6476   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
6477                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
6478 }
6479
6480 static void
6481 gtk_text_view_drag_leave (GtkWidget        *widget,
6482                           GdkDragContext   *context,
6483                           guint             time)
6484 {
6485   GtkTextView *text_view;
6486
6487   text_view = GTK_TEXT_VIEW (widget);
6488
6489   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6490   
6491   if (text_view->scroll_timeout != 0)
6492     g_source_remove (text_view->scroll_timeout);
6493
6494   text_view->scroll_timeout = 0;
6495 }
6496
6497 static gboolean
6498 gtk_text_view_drag_motion (GtkWidget        *widget,
6499                            GdkDragContext   *context,
6500                            gint              x,
6501                            gint              y,
6502                            guint             time)
6503 {
6504   GtkTextIter newplace;
6505   GtkTextView *text_view;
6506   GtkTextIter start;
6507   GtkTextIter end;
6508   GdkRectangle target_rect;
6509   gint bx, by;
6510   GdkAtom target;
6511   GdkDragAction suggested_action = 0;
6512   
6513   text_view = GTK_TEXT_VIEW (widget);
6514
6515   target_rect = text_view->text_window->allocation;
6516   
6517   if (x < target_rect.x ||
6518       y < target_rect.y ||
6519       x > (target_rect.x + target_rect.width) ||
6520       y > (target_rect.y + target_rect.height))
6521     return FALSE; /* outside the text window, allow parent widgets to handle event */
6522
6523   gtk_text_view_window_to_buffer_coords (text_view,
6524                                          GTK_TEXT_WINDOW_WIDGET,
6525                                          x, y,
6526                                          &bx, &by);
6527
6528   gtk_text_layout_get_iter_at_pixel (text_view->layout,
6529                                      &newplace,
6530                                      bx, by);  
6531
6532   target = gtk_drag_dest_find_target (widget, context,
6533                                       gtk_drag_dest_get_target_list (widget));
6534
6535   if (target == GDK_NONE)
6536     {
6537       /* can't accept any of the offered targets */
6538     }                                 
6539   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
6540                                                  &start, &end) &&
6541            gtk_text_iter_compare (&newplace, &start) >= 0 &&
6542            gtk_text_iter_compare (&newplace, &end) <= 0)
6543     {
6544       /* We're inside the selection. */
6545     }
6546   else
6547     {      
6548       if (gtk_text_iter_can_insert (&newplace, text_view->editable))
6549         {
6550           GtkWidget *source_widget;
6551           
6552           suggested_action = context->suggested_action;
6553           
6554           source_widget = gtk_drag_get_source_widget (context);
6555           
6556           if (source_widget == widget)
6557             {
6558               /* Default to MOVE, unless the user has
6559                * pressed ctrl or alt to affect available actions
6560                */
6561               if ((context->actions & GDK_ACTION_MOVE) != 0)
6562                 suggested_action = GDK_ACTION_MOVE;
6563             }
6564         }
6565       else
6566         {
6567           /* Can't drop here. */
6568         }
6569     }
6570
6571   if (suggested_action != 0)
6572     {
6573       gtk_text_mark_set_visible (text_view->dnd_mark,
6574                                  text_view->cursor_visible);
6575       
6576       gdk_drag_status (context, suggested_action, time);
6577     }
6578   else
6579     {
6580       gdk_drag_status (context, 0, time);
6581       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6582     }
6583       
6584   if (!text_view->scroll_timeout)
6585     text_view->scroll_timeout =
6586       gdk_threads_add_timeout (100, drag_scan_timeout, text_view);
6587
6588   /* TRUE return means don't propagate the drag motion to parent
6589    * widgets that may also be drop sites.
6590    */
6591   return TRUE;
6592 }
6593
6594 static gboolean
6595 gtk_text_view_drag_drop (GtkWidget        *widget,
6596                          GdkDragContext   *context,
6597                          gint              x,
6598                          gint              y,
6599                          guint             time)
6600 {
6601   GtkTextView *text_view;
6602   GtkTextIter drop_point;
6603   GdkAtom target = GDK_NONE;
6604   
6605   text_view = GTK_TEXT_VIEW (widget);
6606   
6607   if (text_view->scroll_timeout != 0)
6608     g_source_remove (text_view->scroll_timeout);
6609
6610   text_view->scroll_timeout = 0;
6611
6612   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
6613
6614   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
6615                                     &drop_point,
6616                                     text_view->dnd_mark);
6617
6618   if (gtk_text_iter_can_insert (&drop_point, text_view->editable))
6619     target = gtk_drag_dest_find_target (widget, context, NULL);
6620
6621   if (target != GDK_NONE)
6622     gtk_drag_get_data (widget, context, target, time);
6623   else
6624     gtk_drag_finish (context, FALSE, FALSE, time);
6625
6626   return TRUE;
6627 }
6628
6629 static void
6630 insert_text_data (GtkTextView      *text_view,
6631                   GtkTextIter      *drop_point,
6632                   GtkSelectionData *selection_data)
6633 {
6634   guchar *str;
6635
6636   str = gtk_selection_data_get_text (selection_data);
6637
6638   if (str)
6639     {
6640       if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
6641                                                drop_point, (gchar *) str, -1,
6642                                                text_view->editable))
6643         {
6644           gtk_widget_error_bell (GTK_WIDGET (text_view));
6645         }
6646
6647       g_free (str);
6648     }
6649 }
6650
6651 static void
6652 gtk_text_view_drag_data_received (GtkWidget        *widget,
6653                                   GdkDragContext   *context,
6654                                   gint              x,
6655                                   gint              y,
6656                                   GtkSelectionData *selection_data,
6657                                   guint             info,
6658                                   guint             time)
6659 {
6660   GtkTextIter drop_point;
6661   GtkTextView *text_view;
6662   gboolean success = FALSE;
6663   GtkTextBuffer *buffer = NULL;
6664
6665   text_view = GTK_TEXT_VIEW (widget);
6666
6667   if (!text_view->dnd_mark)
6668     goto done;
6669
6670   buffer = get_buffer (text_view);
6671
6672   gtk_text_buffer_get_iter_at_mark (buffer,
6673                                     &drop_point,
6674                                     text_view->dnd_mark);
6675   
6676   if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
6677     goto done;
6678
6679   success = TRUE;
6680
6681   gtk_text_buffer_begin_user_action (buffer);
6682
6683   if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6684     {
6685       GtkTextBuffer *src_buffer = NULL;
6686       GtkTextIter start, end;
6687       gboolean copy_tags = TRUE;
6688
6689       if (selection_data->length != sizeof (src_buffer))
6690         return;
6691
6692       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
6693
6694       if (src_buffer == NULL)
6695         return;
6696
6697       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
6698
6699       if (gtk_text_buffer_get_tag_table (src_buffer) !=
6700           gtk_text_buffer_get_tag_table (buffer))
6701         {
6702           /*  try to find a suitable rich text target instead  */
6703           GdkAtom *atoms;
6704           gint     n_atoms;
6705           GList   *list;
6706           GdkAtom  target = GDK_NONE;
6707
6708           copy_tags = FALSE;
6709
6710           atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
6711
6712           for (list = context->targets; list; list = g_list_next (list))
6713             {
6714               gint i;
6715
6716               for (i = 0; i < n_atoms; i++)
6717                 if (GUINT_TO_POINTER (atoms[i]) == list->data)
6718                   {
6719                     target = atoms[i];
6720                     break;
6721                   }
6722             }
6723
6724           g_free (atoms);
6725
6726           if (target != GDK_NONE)
6727             {
6728               gtk_drag_get_data (widget, context, target, time);
6729               gtk_text_buffer_end_user_action (buffer);
6730               return;
6731             }
6732         }
6733
6734       if (gtk_text_buffer_get_selection_bounds (src_buffer,
6735                                                 &start,
6736                                                 &end))
6737         {
6738           if (copy_tags)
6739             gtk_text_buffer_insert_range_interactive (buffer,
6740                                                       &drop_point,
6741                                                       &start,
6742                                                       &end,
6743                                                       text_view->editable);
6744           else
6745             {
6746               gchar *str;
6747
6748               str = gtk_text_iter_get_visible_text (&start, &end);
6749               gtk_text_buffer_insert_interactive (buffer,
6750                                                   &drop_point, str, -1,
6751                                                   text_view->editable);
6752               g_free (str);
6753             }
6754         }
6755     }
6756   else if (selection_data->length > 0 &&
6757            info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6758     {
6759       gboolean retval;
6760       GError *error = NULL;
6761
6762       retval = gtk_text_buffer_deserialize (buffer, buffer,
6763                                             selection_data->target,
6764                                             &drop_point,
6765                                             (guint8 *) selection_data->data,
6766                                             selection_data->length,
6767                                             &error);
6768
6769       if (!retval)
6770         {
6771           g_warning ("error pasting: %s\n", error->message);
6772           g_clear_error (&error);
6773         }
6774     }
6775   else
6776     insert_text_data (text_view, &drop_point, selection_data);
6777
6778  done:
6779   gtk_drag_finish (context, success,
6780                    success && context->action == GDK_ACTION_MOVE,
6781                    time);
6782
6783   if (success)
6784     {
6785       gtk_text_buffer_get_iter_at_mark (buffer,
6786                                         &drop_point,
6787                                         text_view->dnd_mark);
6788       gtk_text_buffer_place_cursor (buffer, &drop_point);
6789
6790       gtk_text_buffer_end_user_action (buffer);
6791     }
6792 }
6793
6794 static GtkAdjustment*
6795 get_hadjustment (GtkTextView *text_view)
6796 {
6797   if (text_view->hadjustment == NULL)
6798     gtk_text_view_set_scroll_adjustments (text_view,
6799                                           NULL, /* forces creation */
6800                                           text_view->vadjustment);
6801
6802   return text_view->hadjustment;
6803 }
6804
6805 static GtkAdjustment*
6806 get_vadjustment (GtkTextView *text_view)
6807 {
6808   if (text_view->vadjustment == NULL)
6809     gtk_text_view_set_scroll_adjustments (text_view,
6810                                           text_view->hadjustment,
6811                                           NULL); /* forces creation */
6812   return text_view->vadjustment;
6813 }
6814
6815
6816 static void
6817 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
6818                                       GtkAdjustment *hadj,
6819                                       GtkAdjustment *vadj)
6820 {
6821   gboolean need_adjust = FALSE;
6822
6823   if (hadj)
6824     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
6825   else
6826     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6827   if (vadj)
6828     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
6829   else
6830     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
6831
6832   if (text_view->hadjustment && (text_view->hadjustment != hadj))
6833     {
6834       g_signal_handlers_disconnect_by_func (text_view->hadjustment,
6835                                             gtk_text_view_value_changed,
6836                                             text_view);
6837       g_object_unref (text_view->hadjustment);
6838     }
6839
6840   if (text_view->vadjustment && (text_view->vadjustment != vadj))
6841     {
6842       g_signal_handlers_disconnect_by_func (text_view->vadjustment,
6843                                             gtk_text_view_value_changed,
6844                                             text_view);
6845       g_object_unref (text_view->vadjustment);
6846     }
6847
6848   if (text_view->hadjustment != hadj)
6849     {
6850       text_view->hadjustment = hadj;
6851       g_object_ref_sink (text_view->hadjustment);
6852       
6853       g_signal_connect (text_view->hadjustment, "value_changed",
6854                         G_CALLBACK (gtk_text_view_value_changed),
6855                         text_view);
6856       need_adjust = TRUE;
6857     }
6858
6859   if (text_view->vadjustment != vadj)
6860     {
6861       text_view->vadjustment = vadj;
6862       g_object_ref_sink (text_view->vadjustment);
6863       
6864       g_signal_connect (text_view->vadjustment, "value_changed",
6865                         G_CALLBACK (gtk_text_view_value_changed),
6866                         text_view);
6867       need_adjust = TRUE;
6868     }
6869
6870   if (need_adjust)
6871     gtk_text_view_value_changed (NULL, text_view);
6872 }
6873
6874 /* FIXME this adjust_allocation is a big cut-and-paste from
6875  * GtkCList, needs to be some "official" way to do this
6876  * factored out.
6877  */
6878 typedef struct
6879 {
6880   GdkWindow *window;
6881   int dx;
6882   int dy;
6883 } ScrollData;
6884
6885 /* The window to which widget->window is relative */
6886 #define ALLOCATION_WINDOW(widget)               \
6887    (GTK_WIDGET_NO_WINDOW (widget) ?             \
6888     (widget)->window :                          \
6889      gdk_window_get_parent ((widget)->window))
6890
6891 static void
6892 adjust_allocation_recurse (GtkWidget *widget,
6893                            gpointer   data)
6894 {
6895   ScrollData *scroll_data = data;
6896
6897   /* Need to really size allocate instead of just poking
6898    * into widget->allocation if the widget is not realized.
6899    * FIXME someone figure out why this was.
6900    */
6901   if (!GTK_WIDGET_REALIZED (widget))
6902     {
6903       if (GTK_WIDGET_VISIBLE (widget))
6904         {
6905           GdkRectangle tmp_rectangle = widget->allocation;
6906           tmp_rectangle.x += scroll_data->dx;
6907           tmp_rectangle.y += scroll_data->dy;
6908           
6909           gtk_widget_size_allocate (widget, &tmp_rectangle);
6910         }
6911     }
6912   else
6913     {
6914       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
6915         {
6916           widget->allocation.x += scroll_data->dx;
6917           widget->allocation.y += scroll_data->dy;
6918           
6919           if (GTK_IS_CONTAINER (widget))
6920             gtk_container_forall (GTK_CONTAINER (widget),
6921                                   adjust_allocation_recurse,
6922                                   data);
6923         }
6924     }
6925 }
6926
6927 static void
6928 adjust_allocation (GtkWidget *widget,
6929                    int        dx,
6930                    int        dy)
6931 {
6932   ScrollData scroll_data;
6933
6934   if (GTK_WIDGET_REALIZED (widget))
6935     scroll_data.window = ALLOCATION_WINDOW (widget);
6936   else
6937     scroll_data.window = NULL;
6938     
6939   scroll_data.dx = dx;
6940   scroll_data.dy = dy;
6941   
6942   adjust_allocation_recurse (widget, &scroll_data);
6943 }
6944             
6945 static void
6946 gtk_text_view_value_changed (GtkAdjustment *adj,
6947                              GtkTextView   *text_view)
6948 {
6949   GtkTextIter iter;
6950   gint line_top;
6951   gint dx = 0;
6952   gint dy = 0;
6953   
6954   /* Note that we oddly call this function with adj == NULL
6955    * sometimes
6956    */
6957   
6958   text_view->onscreen_validated = FALSE;
6959
6960   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
6961              adj == text_view->hadjustment ? "hadj" : adj == text_view->vadjustment ? "vadj" : "none",
6962              adj ? adj->value : 0.0));
6963   
6964   if (adj == text_view->hadjustment)
6965     {
6966       dx = text_view->xoffset - (gint)adj->value;
6967       text_view->xoffset = adj->value;
6968
6969       /* If the change is due to a size change we need 
6970        * to invalidate the entire text window because there might be
6971        * right-aligned or centered text 
6972        */
6973       if (text_view->width_changed)
6974         {
6975           if (GTK_WIDGET_REALIZED (text_view))
6976             gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
6977           
6978           text_view->width_changed = FALSE;
6979         }
6980     }
6981   else if (adj == text_view->vadjustment)
6982     {
6983       dy = text_view->yoffset - (gint)adj->value;
6984       text_view->yoffset = adj->value;
6985
6986       if (text_view->layout)
6987         {
6988           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
6989
6990           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
6991
6992           text_view->first_para_pixels = adj->value - line_top;
6993         }
6994     }
6995   
6996   if (dx != 0 || dy != 0)
6997     {
6998       GSList *tmp_list;
6999
7000       if (GTK_WIDGET_REALIZED (text_view))
7001         {
7002           if (dy != 0)
7003             {
7004               if (text_view->left_window)
7005                 text_window_scroll (text_view->left_window, 0, dy);
7006               if (text_view->right_window)
7007                 text_window_scroll (text_view->right_window, 0, dy);
7008             }
7009       
7010           if (dx != 0)
7011             {
7012               if (text_view->top_window)
7013                 text_window_scroll (text_view->top_window, dx, 0);
7014               if (text_view->bottom_window)
7015                 text_window_scroll (text_view->bottom_window, dx, 0);
7016             }
7017       
7018           /* It looks nicer to scroll the main area last, because
7019            * it takes a while, and making the side areas update
7020            * afterward emphasizes the slowness of scrolling the
7021            * main area.
7022            */
7023           text_window_scroll (text_view->text_window, dx, dy);
7024         }
7025       
7026       /* Children are now "moved" in the text window, poke
7027        * into widget->allocation for each child
7028        */
7029       tmp_list = text_view->children;
7030       while (tmp_list != NULL)
7031         {
7032           GtkTextViewChild *child = tmp_list->data;
7033           
7034           if (child->anchor)
7035             adjust_allocation (child->widget, dx, dy);
7036           
7037           tmp_list = g_slist_next (tmp_list);
7038         }
7039     }
7040
7041   /* This could result in invalidation, which would install the
7042    * first_validate_idle, which would validate onscreen;
7043    * but we're going to go ahead and validate here, so
7044    * first_validate_idle shouldn't have anything to do.
7045    */
7046   gtk_text_view_update_layout_width (text_view);
7047   
7048   /* note that validation of onscreen could invoke this function
7049    * recursively, by scrolling to maintain first_para, or in response
7050    * to updating the layout width, however there is no problem with
7051    * that, or shouldn't be.
7052    */
7053   gtk_text_view_validate_onscreen (text_view);
7054   
7055   /* process exposes */
7056   if (GTK_WIDGET_REALIZED (text_view))
7057     {
7058       DV (g_print ("Processing updates (%s)\n", G_STRLOC));
7059       
7060       if (text_view->left_window)
7061         gdk_window_process_updates (text_view->left_window->bin_window, TRUE);
7062
7063       if (text_view->right_window)
7064         gdk_window_process_updates (text_view->right_window->bin_window, TRUE);
7065
7066       if (text_view->top_window)
7067         gdk_window_process_updates (text_view->top_window->bin_window, TRUE);
7068       
7069       if (text_view->bottom_window)
7070         gdk_window_process_updates (text_view->bottom_window->bin_window, TRUE);
7071   
7072       gdk_window_process_updates (text_view->text_window->bin_window, TRUE);
7073     }
7074
7075   /* If this got installed, get rid of it, it's just a waste of time. */
7076   if (text_view->first_validate_idle != 0)
7077     {
7078       g_source_remove (text_view->first_validate_idle);
7079       text_view->first_validate_idle = 0;
7080     }
7081
7082   gtk_text_view_update_im_spot_location (text_view);
7083   
7084   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
7085 }
7086
7087 static void
7088 gtk_text_view_commit_handler (GtkIMContext  *context,
7089                               const gchar   *str,
7090                               GtkTextView   *text_view)
7091 {
7092   gtk_text_view_commit_text (text_view, str);
7093 }
7094
7095 static void
7096 gtk_text_view_commit_text (GtkTextView   *text_view,
7097                            const gchar   *str)
7098 {
7099   gboolean had_selection;
7100   
7101   gtk_text_buffer_begin_user_action (get_buffer (text_view));
7102
7103   had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7104                                                         NULL, NULL);
7105   
7106   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7107                                     text_view->editable);
7108
7109   if (!strcmp (str, "\n"))
7110     {
7111       if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
7112                                                          text_view->editable))
7113         {
7114           gtk_widget_error_bell (GTK_WIDGET (text_view));
7115         }
7116     }
7117   else
7118     {
7119       if (!had_selection && text_view->overwrite_mode)
7120         {
7121           GtkTextIter insert;
7122           
7123           gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7124                                             &insert,
7125                                             gtk_text_buffer_get_mark (get_buffer (text_view),
7126                                                                       "insert"));
7127           if (!gtk_text_iter_ends_line (&insert))
7128             gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
7129         }
7130
7131       if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
7132                                                          text_view->editable))
7133         {
7134           gtk_widget_error_bell (GTK_WIDGET (text_view));
7135         }
7136     }
7137
7138   gtk_text_buffer_end_user_action (get_buffer (text_view));
7139
7140   gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
7141   DV(g_print (G_STRLOC": scrolling onscreen\n"));
7142   gtk_text_view_scroll_mark_onscreen (text_view,
7143                                       gtk_text_buffer_get_mark (get_buffer (text_view),
7144                                                                 "insert"));
7145 }
7146
7147 static void
7148 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
7149                                        GtkTextView  *text_view)
7150 {
7151   gchar *str;
7152   PangoAttrList *attrs;
7153   gint cursor_pos;
7154   GtkTextIter iter;
7155
7156   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, 
7157                                     gtk_text_buffer_get_insert (text_view->buffer));
7158
7159   /* Keypress events are passed to input method even if cursor position is not editable;
7160    * so beep here if it's multi-key input sequence, input method will be reset in 
7161    * key-press-event handler. */
7162   if (!gtk_text_iter_can_insert (&iter, text_view->editable))
7163     {
7164       gtk_widget_error_bell (GTK_WIDGET (text_view));
7165       return;
7166     }
7167
7168   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
7169   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
7170   pango_attr_list_unref (attrs);
7171   g_free (str);
7172
7173   if (GTK_WIDGET_HAS_FOCUS (text_view))
7174     gtk_text_view_scroll_mark_onscreen (text_view,
7175                                         gtk_text_buffer_get_mark (get_buffer (text_view),
7176                                                                   "insert"));
7177 }
7178
7179 static gboolean
7180 gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
7181                                             GtkTextView   *text_view)
7182 {
7183   GtkTextIter start;
7184   GtkTextIter end;
7185   gint pos;
7186   gchar *text;
7187
7188   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
7189                                     gtk_text_buffer_get_insert (text_view->buffer));
7190   end = start;
7191
7192   pos = gtk_text_iter_get_line_index (&start);
7193   gtk_text_iter_set_line_offset (&start, 0);
7194   gtk_text_iter_forward_to_line_end (&end);
7195
7196   text = gtk_text_iter_get_slice (&start, &end);
7197   gtk_im_context_set_surrounding (context, text, -1, pos);
7198   g_free (text);
7199
7200   return TRUE;
7201 }
7202
7203 static gboolean
7204 gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
7205                                           gint           offset,
7206                                           gint           n_chars,
7207                                           GtkTextView   *text_view)
7208 {
7209   GtkTextIter start;
7210   GtkTextIter end;
7211
7212   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
7213                                     gtk_text_buffer_get_insert (text_view->buffer));
7214   end = start;
7215
7216   gtk_text_iter_forward_chars (&start, offset);
7217   gtk_text_iter_forward_chars (&end, offset + n_chars);
7218
7219   gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
7220                                       text_view->editable);
7221
7222   return TRUE;
7223 }
7224
7225 static void
7226 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
7227                                 const GtkTextIter *location,
7228                                 GtkTextMark       *mark,
7229                                 gpointer           data)
7230 {
7231   GtkTextView *text_view = GTK_TEXT_VIEW (data);
7232   gboolean need_reset = FALSE;
7233
7234   if (mark == gtk_text_buffer_get_insert (buffer))
7235     {
7236       text_view->virtual_cursor_x = -1;
7237       text_view->virtual_cursor_y = -1;
7238       gtk_text_view_update_im_spot_location (text_view);
7239       need_reset = TRUE;
7240     }
7241   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
7242     {
7243       need_reset = TRUE;
7244     }
7245
7246   if (need_reset)
7247     gtk_text_view_reset_im_context (text_view);
7248 }
7249
7250 static void
7251 gtk_text_view_target_list_notify (GtkTextBuffer    *buffer,
7252                                   const GParamSpec *pspec,
7253                                   gpointer          data)
7254 {
7255   GtkWidget     *widget = GTK_WIDGET (data);
7256   GtkTargetList *view_list;
7257   GtkTargetList *buffer_list;
7258   GList         *list;
7259
7260   view_list = gtk_drag_dest_get_target_list (widget);
7261   buffer_list = gtk_text_buffer_get_paste_target_list (buffer);
7262
7263   if (view_list)
7264     gtk_target_list_ref (view_list);
7265   else
7266     view_list = gtk_target_list_new (NULL, 0);
7267
7268   list = view_list->list;
7269   while (list)
7270     {
7271       GtkTargetPair *pair = list->data;
7272
7273       list = g_list_next (list); /* get next element before removing */
7274
7275       if (pair->info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
7276           pair->info <= GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
7277         {
7278           gtk_target_list_remove (view_list, pair->target);
7279         }
7280     }
7281
7282   for (list = buffer_list->list; list; list = g_list_next (list))
7283     {
7284       GtkTargetPair *pair = list->data;
7285
7286       gtk_target_list_add (view_list, pair->target, pair->flags, pair->info);
7287     }
7288
7289   gtk_drag_dest_set_target_list (widget, view_list);
7290   gtk_target_list_unref (view_list);
7291 }
7292
7293 static void
7294 gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
7295                                     GdkRectangle  *pos)
7296 {
7297   GtkTextIter insert;
7298   
7299   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7300                                     gtk_text_buffer_get_mark (get_buffer (text_view),
7301                                                               "insert"));
7302
7303   gtk_text_layout_get_cursor_locations (text_view->layout, &insert, pos, NULL);
7304 }
7305
7306 static void
7307 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
7308                                       gint        *x,
7309                                       gint        *y)
7310 {
7311   GdkRectangle pos;
7312
7313   if ((x && text_view->virtual_cursor_x == -1) ||
7314       (y && text_view->virtual_cursor_y == -1))
7315     gtk_text_view_get_cursor_location (text_view, &pos);
7316
7317   if (x)
7318     {
7319       if (text_view->virtual_cursor_x != -1)
7320         *x = text_view->virtual_cursor_x;
7321       else
7322         *x = pos.x;
7323     }
7324
7325   if (y)
7326     {
7327       if (text_view->virtual_cursor_x != -1)
7328         *y = text_view->virtual_cursor_y;
7329       else
7330         *y = pos.y + pos.height / 2;
7331     }
7332 }
7333
7334 static void
7335 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
7336                                       gint         x,
7337                                       gint         y)
7338 {
7339   GdkRectangle pos;
7340
7341   if (!text_view->layout)
7342     return;
7343
7344   if (x == -1 || y == -1)
7345     gtk_text_view_get_cursor_location (text_view, &pos);
7346
7347   text_view->virtual_cursor_x = (x == -1) ? pos.x : x;
7348   text_view->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
7349 }
7350
7351 /* Quick hack of a popup menu
7352  */
7353 static void
7354 activate_cb (GtkWidget   *menuitem,
7355              GtkTextView *text_view)
7356 {
7357   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
7358   g_signal_emit_by_name (text_view, signal);
7359 }
7360
7361 static void
7362 append_action_signal (GtkTextView  *text_view,
7363                       GtkWidget    *menu,
7364                       const gchar  *stock_id,
7365                       const gchar  *signal,
7366                       gboolean      sensitive)
7367 {
7368   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
7369
7370   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
7371   g_signal_connect (menuitem, "activate",
7372                     G_CALLBACK (activate_cb), text_view);
7373
7374   gtk_widget_set_sensitive (menuitem, sensitive);
7375   
7376   gtk_widget_show (menuitem);
7377   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
7378 }
7379
7380 static void
7381 gtk_text_view_select_all (GtkWidget *widget,
7382                           gboolean select)
7383 {
7384   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
7385   GtkTextBuffer *buffer;
7386   GtkTextIter start_iter, end_iter, insert;
7387
7388   buffer = text_view->buffer;
7389   if (select) 
7390     {
7391       gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
7392       gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
7393     }
7394   else 
7395     {
7396       gtk_text_buffer_get_iter_at_mark (buffer, &insert,
7397                                         gtk_text_buffer_get_insert (buffer));
7398       gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
7399     }
7400 }
7401
7402 static void
7403 select_all_cb (GtkWidget   *menuitem,
7404                GtkTextView *text_view)
7405 {
7406   gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
7407 }
7408
7409 static void
7410 delete_cb (GtkTextView *text_view)
7411 {
7412   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7413                                     text_view->editable);
7414 }
7415
7416 static void
7417 popup_menu_detach (GtkWidget *attach_widget,
7418                    GtkMenu   *menu)
7419 {
7420   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
7421 }
7422
7423 static void
7424 popup_position_func (GtkMenu   *menu,
7425                      gint      *x,
7426                      gint      *y,
7427                      gboolean  *push_in,
7428                      gpointer   user_data)
7429 {
7430   GtkTextView *text_view;
7431   GtkWidget *widget;
7432   GdkRectangle cursor_rect;
7433   GdkRectangle onscreen_rect;
7434   gint root_x, root_y;
7435   GtkTextIter iter;
7436   GtkRequisition req;      
7437   GdkScreen *screen;
7438   gint monitor_num;
7439   GdkRectangle monitor;
7440       
7441   text_view = GTK_TEXT_VIEW (user_data);
7442   widget = GTK_WIDGET (text_view);
7443   
7444   g_return_if_fail (GTK_WIDGET_REALIZED (text_view));
7445   
7446   screen = gtk_widget_get_screen (widget);
7447
7448   gdk_window_get_origin (widget->window, &root_x, &root_y);
7449
7450   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7451                                     &iter,
7452                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
7453
7454   gtk_text_view_get_iter_location (text_view,
7455                                    &iter,
7456                                    &cursor_rect);
7457
7458   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
7459   
7460   gtk_widget_size_request (text_view->popup_menu, &req);
7461
7462   /* can't use rectangle_intersect since cursor rect can have 0 width */
7463   if (cursor_rect.x >= onscreen_rect.x &&
7464       cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
7465       cursor_rect.y >= onscreen_rect.y &&
7466       cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
7467     {    
7468       gtk_text_view_buffer_to_window_coords (text_view,
7469                                              GTK_TEXT_WINDOW_WIDGET,
7470                                              cursor_rect.x, cursor_rect.y,
7471                                              &cursor_rect.x, &cursor_rect.y);
7472
7473       *x = root_x + cursor_rect.x + cursor_rect.width;
7474       *y = root_y + cursor_rect.y + cursor_rect.height;
7475     }
7476   else
7477     {
7478       /* Just center the menu, since cursor is offscreen. */      
7479       *x = root_x + (widget->allocation.width / 2 - req.width / 2);
7480       *y = root_y + (widget->allocation.height / 2 - req.height / 2);      
7481     }
7482   
7483   /* Ensure sanity */
7484   *x = CLAMP (*x, root_x, (root_x + widget->allocation.width));
7485   *y = CLAMP (*y, root_y, (root_y + widget->allocation.height));
7486
7487   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
7488   gtk_menu_set_monitor (menu, monitor_num);
7489   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
7490
7491   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
7492   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
7493
7494   *push_in = FALSE;
7495 }
7496
7497 typedef struct
7498 {
7499   GtkTextView *text_view;
7500   gint button;
7501   guint time;
7502 } PopupInfo;
7503
7504 static gboolean
7505 range_contains_editable_text (const GtkTextIter *start,
7506                               const GtkTextIter *end,
7507                               gboolean default_editability)
7508 {
7509   GtkTextIter iter = *start;
7510
7511   while (gtk_text_iter_compare (&iter, end) < 0)
7512     {
7513       if (gtk_text_iter_editable (&iter, default_editability))
7514         return TRUE;
7515       
7516       gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
7517     }
7518
7519   return FALSE;
7520 }                             
7521
7522 static void
7523 unichar_chosen_func (const char *text,
7524                      gpointer    data)
7525 {
7526   GtkTextView *text_view = GTK_TEXT_VIEW (data);
7527
7528   gtk_text_view_commit_text (text_view, text);
7529 }
7530
7531 static void
7532 popup_targets_received (GtkClipboard     *clipboard,
7533                         GtkSelectionData *data,
7534                         gpointer          user_data)
7535 {
7536   PopupInfo *info = user_data;
7537   GtkTextView *text_view = info->text_view;
7538   
7539   if (GTK_WIDGET_REALIZED (text_view))
7540     {
7541       /* We implicitely rely here on the fact that if we are pasting ourself, we'll
7542        * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
7543        */
7544       gboolean clipboard_contains_text;
7545       GtkWidget *menuitem;
7546       GtkWidget *submenu;
7547       gboolean have_selection;
7548       gboolean can_insert;
7549       GtkTextIter iter;
7550       GtkTextIter sel_start, sel_end;
7551       gboolean show_input_method_menu;
7552       gboolean show_unicode_menu;
7553       
7554       clipboard_contains_text = gtk_selection_data_targets_include_text (data);
7555
7556       if (text_view->popup_menu)
7557         gtk_widget_destroy (text_view->popup_menu);
7558
7559       text_view->popup_menu = gtk_menu_new ();
7560       
7561       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
7562                                  GTK_WIDGET (text_view),
7563                                  popup_menu_detach);
7564       
7565       have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7566                                                              &sel_start, &sel_end);
7567       
7568       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7569                                         &iter,
7570                                         gtk_text_buffer_get_insert (get_buffer (text_view)));
7571       
7572       can_insert = gtk_text_iter_can_insert (&iter, text_view->editable);
7573       
7574       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
7575                             have_selection &&
7576                             range_contains_editable_text (&sel_start, &sel_end,
7577                                                           text_view->editable));
7578       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
7579                             have_selection);
7580       append_action_signal (text_view, text_view->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
7581                             can_insert && clipboard_contains_text);
7582       
7583       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7584       gtk_widget_set_sensitive (menuitem, 
7585                                 have_selection &&
7586                                 range_contains_editable_text (&sel_start, &sel_end,
7587                                                               text_view->editable));
7588       g_signal_connect_swapped (menuitem, "activate",
7589                                 G_CALLBACK (delete_cb), text_view);
7590       gtk_widget_show (menuitem);
7591       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7592
7593       menuitem = gtk_separator_menu_item_new ();
7594       gtk_widget_show (menuitem);
7595       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7596
7597       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
7598       g_signal_connect (menuitem, "activate",
7599                         G_CALLBACK (select_all_cb), text_view);
7600       gtk_widget_show (menuitem);
7601       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7602
7603       g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
7604                     "gtk-show-input-method-menu", &show_input_method_menu,
7605                     "gtk-show-unicode-menu", &show_unicode_menu,
7606                     NULL);
7607       
7608       if (show_input_method_menu || show_unicode_menu)
7609         {
7610           menuitem = gtk_separator_menu_item_new ();
7611           gtk_widget_show (menuitem);
7612           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7613         }
7614
7615       if (show_input_method_menu)
7616         {
7617           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
7618           gtk_widget_show (menuitem);
7619           gtk_widget_set_sensitive (menuitem, can_insert);
7620
7621           submenu = gtk_menu_new ();
7622           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7623           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
7624           
7625           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
7626                                                 GTK_MENU_SHELL (submenu));
7627         }
7628
7629       if (show_unicode_menu)
7630         {
7631           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
7632           gtk_widget_show (menuitem);
7633           gtk_widget_set_sensitive (menuitem, can_insert);
7634       
7635           submenu = gtk_menu_new ();
7636           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7637           gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);      
7638           
7639           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
7640                                                         unichar_chosen_func,
7641                                                         text_view);
7642         }
7643           
7644       g_signal_emit (text_view,
7645                      signals[POPULATE_POPUP],
7646                      0,
7647                      text_view->popup_menu);
7648       
7649       if (info->button)
7650         gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7651                         NULL, NULL,
7652                         info->button, info->time);
7653       else
7654         {
7655           gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
7656                           popup_position_func, text_view,
7657                           0, gtk_get_current_event_time ());
7658           gtk_menu_shell_select_first (GTK_MENU_SHELL (text_view->popup_menu), FALSE);
7659         }
7660     }
7661
7662   g_object_unref (text_view);
7663   g_free (info);
7664 }
7665
7666 static void
7667 gtk_text_view_do_popup (GtkTextView    *text_view,
7668                         GdkEventButton *event)
7669 {
7670   PopupInfo *info = g_new (PopupInfo, 1);
7671
7672   /* In order to know what entries we should make sensitive, we
7673    * ask for the current targets of the clipboard, and when
7674    * we get them, then we actually pop up the menu.
7675    */
7676   info->text_view = g_object_ref (text_view);
7677   
7678   if (event)
7679     {
7680       info->button = event->button;
7681       info->time = event->time;
7682     }
7683   else
7684     {
7685       info->button = 0;
7686       info->time = gtk_get_current_event_time ();
7687     }
7688
7689   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
7690                                                             GDK_SELECTION_CLIPBOARD),
7691                                   gdk_atom_intern_static_string ("TARGETS"),
7692                                   popup_targets_received,
7693                                   info);
7694 }
7695
7696 static gboolean
7697 gtk_text_view_popup_menu (GtkWidget *widget)
7698 {
7699   gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);  
7700   return TRUE;
7701 }
7702
7703 /* Child GdkWindows */
7704
7705
7706 static GtkTextWindow*
7707 text_window_new (GtkTextWindowType  type,
7708                  GtkWidget         *widget,
7709                  gint               width_request,
7710                  gint               height_request)
7711 {
7712   GtkTextWindow *win;
7713
7714   win = g_new (GtkTextWindow, 1);
7715
7716   win->type = type;
7717   win->widget = widget;
7718   win->window = NULL;
7719   win->bin_window = NULL;
7720   win->requisition.width = width_request;
7721   win->requisition.height = height_request;
7722   win->allocation.width = width_request;
7723   win->allocation.height = height_request;
7724   win->allocation.x = 0;
7725   win->allocation.y = 0;
7726
7727   return win;
7728 }
7729
7730 static void
7731 text_window_free (GtkTextWindow *win)
7732 {
7733   if (win->window)
7734     text_window_unrealize (win);
7735
7736   g_free (win);
7737 }
7738
7739 static void
7740 text_window_realize (GtkTextWindow *win,
7741                      GtkWidget     *widget)
7742 {
7743   GdkWindowAttr attributes;
7744   gint attributes_mask;
7745   GdkCursor *cursor;
7746
7747   attributes.window_type = GDK_WINDOW_CHILD;
7748   attributes.x = win->allocation.x;
7749   attributes.y = win->allocation.y;
7750   attributes.width = win->allocation.width;
7751   attributes.height = win->allocation.height;
7752   attributes.wclass = GDK_INPUT_OUTPUT;
7753   attributes.visual = gtk_widget_get_visual (win->widget);
7754   attributes.colormap = gtk_widget_get_colormap (win->widget);
7755   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
7756
7757   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
7758
7759   win->window = gdk_window_new (widget->window,
7760                                 &attributes,
7761                                 attributes_mask);
7762
7763   gdk_window_set_back_pixmap (win->window, NULL, FALSE);
7764   
7765   gdk_window_show (win->window);
7766   gdk_window_set_user_data (win->window, win->widget);
7767   gdk_window_lower (win->window);
7768
7769   attributes.x = 0;
7770   attributes.y = 0;
7771   attributes.width = win->allocation.width;
7772   attributes.height = win->allocation.height;
7773   attributes.event_mask = (GDK_EXPOSURE_MASK            |
7774                            GDK_SCROLL_MASK              |
7775                            GDK_KEY_PRESS_MASK           |
7776                            GDK_BUTTON_PRESS_MASK        |
7777                            GDK_BUTTON_RELEASE_MASK      |
7778                            GDK_POINTER_MOTION_MASK      |
7779                            GDK_POINTER_MOTION_HINT_MASK |
7780                            gtk_widget_get_events (win->widget));
7781
7782   win->bin_window = gdk_window_new (win->window,
7783                                     &attributes,
7784                                     attributes_mask);
7785
7786   gdk_window_show (win->bin_window);
7787   gdk_window_set_user_data (win->bin_window, win->widget);
7788
7789   if (win->type == GTK_TEXT_WINDOW_TEXT)
7790     {
7791       if (GTK_WIDGET_IS_SENSITIVE (widget))
7792         {
7793           /* I-beam cursor */
7794           cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (widget->window),
7795                                                GDK_XTERM);
7796           gdk_window_set_cursor (win->bin_window, cursor);
7797           gdk_cursor_unref (cursor);
7798         } 
7799
7800       gtk_im_context_set_client_window (GTK_TEXT_VIEW (widget)->im_context,
7801                                         win->window);
7802
7803
7804       gdk_window_set_background (win->bin_window,
7805                                  &widget->style->base[GTK_WIDGET_STATE (widget)]);
7806     }
7807   else
7808     {
7809       gdk_window_set_background (win->bin_window,
7810                                  &widget->style->bg[GTK_WIDGET_STATE (widget)]);
7811     }
7812
7813   g_object_set_qdata (G_OBJECT (win->window),
7814                       g_quark_from_static_string ("gtk-text-view-text-window"),
7815                       win);
7816
7817   g_object_set_qdata (G_OBJECT (win->bin_window),
7818                       g_quark_from_static_string ("gtk-text-view-text-window"),
7819                       win);
7820 }
7821
7822 static void
7823 text_window_unrealize (GtkTextWindow *win)
7824 {
7825   if (win->type == GTK_TEXT_WINDOW_TEXT)
7826     {
7827       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
7828                                         NULL);
7829     }
7830
7831   gdk_window_set_user_data (win->window, NULL);
7832   gdk_window_set_user_data (win->bin_window, NULL);
7833   gdk_window_destroy (win->bin_window);
7834   gdk_window_destroy (win->window);
7835   win->window = NULL;
7836   win->bin_window = NULL;
7837 }
7838
7839 static void
7840 text_window_size_allocate (GtkTextWindow *win,
7841                            GdkRectangle  *rect)
7842 {
7843   win->allocation = *rect;
7844
7845   if (win->window)
7846     {
7847       gdk_window_move_resize (win->window,
7848                               rect->x, rect->y,
7849                               rect->width, rect->height);
7850
7851       gdk_window_resize (win->bin_window,
7852                          rect->width, rect->height);
7853     }
7854 }
7855
7856 static void
7857 text_window_scroll        (GtkTextWindow *win,
7858                            gint           dx,
7859                            gint           dy)
7860 {
7861   if (dx != 0 || dy != 0)
7862     {
7863       gdk_window_scroll (win->bin_window, dx, dy);
7864     }
7865 }
7866
7867 static void
7868 text_window_invalidate_rect (GtkTextWindow *win,
7869                              GdkRectangle  *rect)
7870 {
7871   GdkRectangle window_rect;
7872
7873   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
7874                                          win->type,
7875                                          rect->x,
7876                                          rect->y,
7877                                          &window_rect.x,
7878                                          &window_rect.y);
7879
7880   window_rect.width = rect->width;
7881   window_rect.height = rect->height;
7882   
7883   /* Adjust the rect as appropriate */
7884   
7885   switch (win->type)
7886     {
7887     case GTK_TEXT_WINDOW_TEXT:
7888       break;
7889
7890     case GTK_TEXT_WINDOW_LEFT:
7891     case GTK_TEXT_WINDOW_RIGHT:
7892       window_rect.x = 0;
7893       window_rect.width = win->allocation.width;
7894       break;
7895
7896     case GTK_TEXT_WINDOW_TOP:
7897     case GTK_TEXT_WINDOW_BOTTOM:
7898       window_rect.y = 0;
7899       window_rect.height = win->allocation.height;
7900       break;
7901
7902     default:
7903       g_warning ("%s: bug!", G_STRLOC);
7904       return;
7905       break;
7906     }
7907           
7908   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
7909
7910 #if 0
7911   {
7912     cairo_t *cr = gdk_cairo_create (win->bin_window);
7913     gdk_cairo_rectangle (cr, &window_rect);
7914     cairo_set_source_rgb  (cr, 1.0, 0.0, 0.0);  /* red */
7915     cairo_fill (cr);
7916     cairo_destroy (cr);
7917   }
7918 #endif
7919 }
7920
7921 static void
7922 text_window_invalidate_cursors (GtkTextWindow *win)
7923 {
7924   GtkTextView *text_view = GTK_TEXT_VIEW (win->widget);
7925   GtkTextIter  iter;
7926   GdkRectangle strong;
7927   GdkRectangle weak;
7928   gboolean     draw_arrow;
7929   gfloat       cursor_aspect_ratio;
7930   gint         stem_width;
7931   gint         arrow_width;
7932
7933   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
7934                                     gtk_text_buffer_get_insert (text_view->buffer));
7935
7936   if (_gtk_text_layout_get_block_cursor (text_view->layout, &strong))
7937     {
7938       text_window_invalidate_rect (win, &strong);
7939       return;
7940     }
7941
7942   gtk_text_layout_get_cursor_locations (text_view->layout, &iter,
7943                                         &strong, &weak);
7944
7945   /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
7946    * ignoring the text direction be exposing both sides of the cursor
7947    */
7948
7949   draw_arrow = (strong.x != weak.x || strong.y != weak.y);
7950
7951   gtk_widget_style_get (win->widget,
7952                         "cursor-aspect-ratio", &cursor_aspect_ratio,
7953                         NULL);
7954   
7955   stem_width = strong.height * cursor_aspect_ratio + 1;
7956   arrow_width = stem_width + 1;
7957
7958   strong.width = stem_width;
7959
7960   /* round up to the next even number */
7961   if (stem_width & 1)
7962     stem_width++;
7963
7964   strong.x     -= stem_width / 2;
7965   strong.width += stem_width;
7966
7967   if (draw_arrow)
7968     {
7969       strong.x     -= arrow_width;
7970       strong.width += arrow_width * 2;
7971     }
7972
7973   text_window_invalidate_rect (win, &strong);
7974
7975   if (draw_arrow) /* == have weak */
7976     {
7977       stem_width = weak.height * cursor_aspect_ratio + 1;
7978       arrow_width = stem_width + 1;
7979
7980       weak.width = stem_width;
7981
7982       /* round up to the next even number */
7983       if (stem_width & 1)
7984         stem_width++;
7985
7986       weak.x     -= stem_width / 2;
7987       weak.width += stem_width;
7988
7989       weak.x     -= arrow_width;
7990       weak.width += arrow_width * 2;
7991
7992       text_window_invalidate_rect (win, &weak);
7993     }
7994 }
7995
7996 static gint
7997 text_window_get_width (GtkTextWindow *win)
7998 {
7999   return win->allocation.width;
8000 }
8001
8002 static gint
8003 text_window_get_height (GtkTextWindow *win)
8004 {
8005   return win->allocation.height;
8006 }
8007
8008 /* Windows */
8009
8010
8011 /**
8012  * gtk_text_view_get_window:
8013  * @text_view: a #GtkTextView
8014  * @win: window to get
8015  *
8016  * Retrieves the #GdkWindow corresponding to an area of the text view;
8017  * possible windows include the overall widget window, child windows
8018  * on the left, right, top, bottom, and the window that displays the
8019  * text buffer. Windows are %NULL and nonexistent if their width or
8020  * height is 0, and are nonexistent before the widget has been
8021  * realized.
8022  *
8023  * Return value: a #GdkWindow, or %NULL
8024  **/
8025 GdkWindow*
8026 gtk_text_view_get_window (GtkTextView *text_view,
8027                           GtkTextWindowType win)
8028 {
8029   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
8030
8031   switch (win)
8032     {
8033     case GTK_TEXT_WINDOW_WIDGET:
8034       return GTK_WIDGET (text_view)->window;
8035       break;
8036
8037     case GTK_TEXT_WINDOW_TEXT:
8038       return text_view->text_window->bin_window;
8039       break;
8040
8041     case GTK_TEXT_WINDOW_LEFT:
8042       if (text_view->left_window)
8043         return text_view->left_window->bin_window;
8044       else
8045         return NULL;
8046       break;
8047
8048     case GTK_TEXT_WINDOW_RIGHT:
8049       if (text_view->right_window)
8050         return text_view->right_window->bin_window;
8051       else
8052         return NULL;
8053       break;
8054
8055     case GTK_TEXT_WINDOW_TOP:
8056       if (text_view->top_window)
8057         return text_view->top_window->bin_window;
8058       else
8059         return NULL;
8060       break;
8061
8062     case GTK_TEXT_WINDOW_BOTTOM:
8063       if (text_view->bottom_window)
8064         return text_view->bottom_window->bin_window;
8065       else
8066         return NULL;
8067       break;
8068
8069     case GTK_TEXT_WINDOW_PRIVATE:
8070       g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_GNUC_FUNCTION);
8071       return NULL;
8072       break;
8073     }
8074
8075   g_warning ("%s: Unknown GtkTextWindowType", G_GNUC_FUNCTION);
8076   return NULL;
8077 }
8078
8079 /**
8080  * gtk_text_view_get_window_type:
8081  * @text_view: a #GtkTextView
8082  * @window: a window type
8083  *
8084  * Usually used to find out which window an event corresponds to.
8085  * If you connect to an event signal on @text_view, this function
8086  * should be called on <literal>event-&gt;window</literal> to
8087  * see which window it was.
8088  *
8089  * Return value: the window type.
8090  **/
8091 GtkTextWindowType
8092 gtk_text_view_get_window_type (GtkTextView *text_view,
8093                                GdkWindow   *window)
8094 {
8095   GtkTextWindow *win;
8096
8097   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8098   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
8099
8100   if (window == GTK_WIDGET (text_view)->window)
8101     return GTK_TEXT_WINDOW_WIDGET;
8102
8103   win = g_object_get_qdata (G_OBJECT (window),
8104                             g_quark_try_string ("gtk-text-view-text-window"));
8105
8106   if (win)
8107     return win->type;
8108   else
8109     {
8110       return GTK_TEXT_WINDOW_PRIVATE;
8111     }
8112 }
8113
8114 static void
8115 buffer_to_widget (GtkTextView      *text_view,
8116                   gint              buffer_x,
8117                   gint              buffer_y,
8118                   gint             *window_x,
8119                   gint             *window_y)
8120 {  
8121   if (window_x)
8122     {
8123       *window_x = buffer_x - text_view->xoffset;
8124       *window_x += text_view->text_window->allocation.x;
8125     }
8126
8127   if (window_y)
8128     {
8129       *window_y = buffer_y - text_view->yoffset;
8130       *window_y += text_view->text_window->allocation.y;
8131     }
8132 }
8133
8134 static void
8135 widget_to_text_window (GtkTextWindow *win,
8136                        gint           widget_x,
8137                        gint           widget_y,
8138                        gint          *window_x,
8139                        gint          *window_y)
8140 {
8141   if (window_x)
8142     *window_x = widget_x - win->allocation.x;
8143
8144   if (window_y)
8145     *window_y = widget_y - win->allocation.y;
8146 }
8147
8148 static void
8149 buffer_to_text_window (GtkTextView   *text_view,
8150                        GtkTextWindow *win,
8151                        gint           buffer_x,
8152                        gint           buffer_y,
8153                        gint          *window_x,
8154                        gint          *window_y)
8155 {
8156   if (win == NULL)
8157     {
8158       g_warning ("Attempt to convert text buffer coordinates to coordinates "
8159                  "for a nonexistent or private child window of GtkTextView");
8160       return;
8161     }
8162
8163   buffer_to_widget (text_view,
8164                     buffer_x, buffer_y,
8165                     window_x, window_y);
8166
8167   widget_to_text_window (win,
8168                          window_x ? *window_x : 0,
8169                          window_y ? *window_y : 0,
8170                          window_x,
8171                          window_y);
8172 }
8173
8174 /**
8175  * gtk_text_view_buffer_to_window_coords:
8176  * @text_view: a #GtkTextView
8177  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8178  * @buffer_x: buffer x coordinate
8179  * @buffer_y: buffer y coordinate
8180  * @window_x: window x coordinate return location
8181  * @window_y: window y coordinate return location
8182  *
8183  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
8184  * @win, and stores the result in (@window_x, @window_y). 
8185  *
8186  * Note that you can't convert coordinates for a nonexisting window (see 
8187  * gtk_text_view_set_border_window_size()).
8188  **/
8189 void
8190 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
8191                                        GtkTextWindowType win,
8192                                        gint              buffer_x,
8193                                        gint              buffer_y,
8194                                        gint             *window_x,
8195                                        gint             *window_y)
8196 {
8197   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8198
8199   switch (win)
8200     {
8201     case GTK_TEXT_WINDOW_WIDGET:
8202       buffer_to_widget (text_view,
8203                         buffer_x, buffer_y,
8204                         window_x, window_y);
8205       break;
8206
8207     case GTK_TEXT_WINDOW_TEXT:
8208       if (window_x)
8209         *window_x = buffer_x - text_view->xoffset;
8210       if (window_y)
8211         *window_y = buffer_y - text_view->yoffset;
8212       break;
8213
8214     case GTK_TEXT_WINDOW_LEFT:
8215       buffer_to_text_window (text_view,
8216                              text_view->left_window,
8217                              buffer_x, buffer_y,
8218                              window_x, window_y);
8219       break;
8220
8221     case GTK_TEXT_WINDOW_RIGHT:
8222       buffer_to_text_window (text_view,
8223                              text_view->right_window,
8224                              buffer_x, buffer_y,
8225                              window_x, window_y);
8226       break;
8227
8228     case GTK_TEXT_WINDOW_TOP:
8229       buffer_to_text_window (text_view,
8230                              text_view->top_window,
8231                              buffer_x, buffer_y,
8232                              window_x, window_y);
8233       break;
8234
8235     case GTK_TEXT_WINDOW_BOTTOM:
8236       buffer_to_text_window (text_view,
8237                              text_view->bottom_window,
8238                              buffer_x, buffer_y,
8239                              window_x, window_y);
8240       break;
8241
8242     case GTK_TEXT_WINDOW_PRIVATE:
8243       g_warning ("%s: can't get coords for private windows", G_STRLOC);
8244       break;
8245
8246     default:
8247       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
8248       break;
8249     }
8250 }
8251
8252 static void
8253 widget_to_buffer (GtkTextView *text_view,
8254                   gint         widget_x,
8255                   gint         widget_y,
8256                   gint        *buffer_x,
8257                   gint        *buffer_y)
8258 {  
8259   if (buffer_x)
8260     {
8261       *buffer_x = widget_x + text_view->xoffset;
8262       *buffer_x -= text_view->text_window->allocation.x;
8263     }
8264
8265   if (buffer_y)
8266     {
8267       *buffer_y = widget_y + text_view->yoffset;
8268       *buffer_y -= text_view->text_window->allocation.y;
8269     }
8270 }
8271
8272 static void
8273 text_window_to_widget (GtkTextWindow *win,
8274                        gint           window_x,
8275                        gint           window_y,
8276                        gint          *widget_x,
8277                        gint          *widget_y)
8278 {
8279   if (widget_x)
8280     *widget_x = window_x + win->allocation.x;
8281
8282   if (widget_y)
8283     *widget_y = window_y + win->allocation.y;
8284 }
8285
8286 static void
8287 text_window_to_buffer (GtkTextView   *text_view,
8288                        GtkTextWindow *win,
8289                        gint           window_x,
8290                        gint           window_y,
8291                        gint          *buffer_x,
8292                        gint          *buffer_y)
8293 {
8294   if (win == NULL)
8295     {
8296       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
8297                  "coordinates for a nonexistent child window.");
8298       return;
8299     }
8300
8301   text_window_to_widget (win,
8302                          window_x,
8303                          window_y,
8304                          buffer_x,
8305                          buffer_y);
8306
8307   widget_to_buffer (text_view,
8308                     buffer_x ? *buffer_x : 0,
8309                     buffer_y ? *buffer_y : 0,
8310                     buffer_x,
8311                     buffer_y);
8312 }
8313
8314 /**
8315  * gtk_text_view_window_to_buffer_coords:
8316  * @text_view: a #GtkTextView
8317  * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8318  * @window_x: window x coordinate
8319  * @window_y: window y coordinate
8320  * @buffer_x: buffer x coordinate return location
8321  * @buffer_y: buffer y coordinate return location
8322  *
8323  * Converts coordinates on the window identified by @win to buffer
8324  * coordinates, storing the result in (@buffer_x,@buffer_y).
8325  *
8326  * Note that you can't convert coordinates for a nonexisting window (see 
8327  * gtk_text_view_set_border_window_size()).
8328  **/
8329 void
8330 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
8331                                        GtkTextWindowType win,
8332                                        gint              window_x,
8333                                        gint              window_y,
8334                                        gint             *buffer_x,
8335                                        gint             *buffer_y)
8336 {
8337   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8338
8339   switch (win)
8340     {
8341     case GTK_TEXT_WINDOW_WIDGET:
8342       widget_to_buffer (text_view,
8343                         window_x, window_y,
8344                         buffer_x, buffer_y);
8345       break;
8346
8347     case GTK_TEXT_WINDOW_TEXT:
8348       if (buffer_x)
8349         *buffer_x = window_x + text_view->xoffset;
8350       if (buffer_y)
8351         *buffer_y = window_y + text_view->yoffset;
8352       break;
8353
8354     case GTK_TEXT_WINDOW_LEFT:
8355       text_window_to_buffer (text_view,
8356                              text_view->left_window,
8357                              window_x, window_y,
8358                              buffer_x, buffer_y);
8359       break;
8360
8361     case GTK_TEXT_WINDOW_RIGHT:
8362       text_window_to_buffer (text_view,
8363                              text_view->right_window,
8364                              window_x, window_y,
8365                              buffer_x, buffer_y);
8366       break;
8367
8368     case GTK_TEXT_WINDOW_TOP:
8369       text_window_to_buffer (text_view,
8370                              text_view->top_window,
8371                              window_x, window_y,
8372                              buffer_x, buffer_y);
8373       break;
8374
8375     case GTK_TEXT_WINDOW_BOTTOM:
8376       text_window_to_buffer (text_view,
8377                              text_view->bottom_window,
8378                              window_x, window_y,
8379                              buffer_x, buffer_y);
8380       break;
8381
8382     case GTK_TEXT_WINDOW_PRIVATE:
8383       g_warning ("%s: can't get coords for private windows", G_STRLOC);
8384       break;
8385
8386     default:
8387       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
8388       break;
8389     }
8390 }
8391
8392 static void
8393 set_window_width (GtkTextView      *text_view,
8394                   gint              width,
8395                   GtkTextWindowType type,
8396                   GtkTextWindow   **winp)
8397 {
8398   if (width == 0)
8399     {
8400       if (*winp)
8401         {
8402           text_window_free (*winp);
8403           *winp = NULL;
8404           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8405         }
8406     }
8407   else
8408     {
8409       if (*winp == NULL)
8410         {
8411           *winp = text_window_new (type,
8412                                    GTK_WIDGET (text_view),
8413                                    width, 0);
8414           /* if the widget is already realized we need to realize the child manually */
8415           if (GTK_WIDGET_REALIZED (text_view))
8416             text_window_realize (*winp, GTK_WIDGET (text_view));
8417         }
8418       else
8419         {
8420           if ((*winp)->requisition.width == width)
8421             return;
8422
8423           (*winp)->requisition.width = width;
8424         }
8425
8426       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8427     }
8428 }
8429
8430
8431 static void
8432 set_window_height (GtkTextView      *text_view,
8433                    gint              height,
8434                    GtkTextWindowType type,
8435                    GtkTextWindow   **winp)
8436 {
8437   if (height == 0)
8438     {
8439       if (*winp)
8440         {
8441           text_window_free (*winp);
8442           *winp = NULL;
8443           gtk_widget_queue_resize (GTK_WIDGET (text_view));
8444         }
8445     }
8446   else
8447     {
8448       if (*winp == NULL)
8449         {
8450           *winp = text_window_new (type,
8451                                    GTK_WIDGET (text_view),
8452                                    0, height);
8453
8454           /* if the widget is already realized we need to realize the child manually */
8455           if (GTK_WIDGET_REALIZED (text_view))
8456             text_window_realize (*winp, GTK_WIDGET (text_view));
8457         }
8458       else
8459         {
8460           if ((*winp)->requisition.height == height)
8461             return;
8462
8463           (*winp)->requisition.height = height;
8464         }
8465
8466       gtk_widget_queue_resize (GTK_WIDGET (text_view));
8467     }
8468 }
8469
8470 /**
8471  * gtk_text_view_set_border_window_size:
8472  * @text_view: a #GtkTextView
8473  * @type: window to affect
8474  * @size: width or height of the window
8475  *
8476  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
8477  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
8478  * Automatically destroys the corresponding window if the size is set
8479  * to 0, and creates the window if the size is set to non-zero.  This
8480  * function can only be used for the "border windows," it doesn't work
8481  * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
8482  * #GTK_TEXT_WINDOW_PRIVATE.
8483  **/
8484 void
8485 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
8486                                       GtkTextWindowType type,
8487                                       gint              size)
8488
8489 {
8490   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8491   g_return_if_fail (size >= 0);
8492
8493   switch (type)
8494     {
8495     case GTK_TEXT_WINDOW_LEFT:
8496       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
8497                         &text_view->left_window);
8498       break;
8499
8500     case GTK_TEXT_WINDOW_RIGHT:
8501       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
8502                         &text_view->right_window);
8503       break;
8504
8505     case GTK_TEXT_WINDOW_TOP:
8506       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
8507                          &text_view->top_window);
8508       break;
8509
8510     case GTK_TEXT_WINDOW_BOTTOM:
8511       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
8512                          &text_view->bottom_window);
8513       break;
8514
8515     default:
8516       g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
8517       break;
8518     }
8519 }
8520
8521 /**
8522  * gtk_text_view_get_border_window_size:
8523  * @text_view: a #GtkTextView
8524  * @type: window to return size from
8525  *
8526  * Gets the width of the specified border window. See
8527  * gtk_text_view_set_border_window_size().
8528  *
8529  * Return value: width of window
8530  **/
8531 gint
8532 gtk_text_view_get_border_window_size (GtkTextView       *text_view,
8533                                       GtkTextWindowType  type)
8534 {
8535   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8536   
8537   switch (type)
8538     {
8539     case GTK_TEXT_WINDOW_LEFT:
8540       if (text_view->left_window)
8541         return text_view->left_window->requisition.width;
8542       break;
8543       
8544     case GTK_TEXT_WINDOW_RIGHT:
8545       if (text_view->right_window)
8546         return text_view->right_window->requisition.width;
8547       break;
8548       
8549     case GTK_TEXT_WINDOW_TOP:
8550       if (text_view->top_window)
8551         return text_view->top_window->requisition.height;
8552       break;
8553
8554     case GTK_TEXT_WINDOW_BOTTOM:
8555       if (text_view->bottom_window)
8556         return text_view->bottom_window->requisition.height;
8557       break;
8558       
8559     default:
8560       g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
8561       break;
8562     }
8563
8564   return 0;
8565 }
8566
8567 /*
8568  * Child widgets
8569  */
8570
8571 static GtkTextViewChild*
8572 text_view_child_new_anchored (GtkWidget          *child,
8573                               GtkTextChildAnchor *anchor,
8574                               GtkTextLayout      *layout)
8575 {
8576   GtkTextViewChild *vc;
8577
8578   vc = g_new (GtkTextViewChild, 1);
8579
8580   vc->type = GTK_TEXT_WINDOW_PRIVATE;
8581   vc->widget = child;
8582   vc->anchor = anchor;
8583
8584   vc->from_top_of_line = 0;
8585   vc->from_left_of_buffer = 0;
8586   
8587   g_object_ref (vc->widget);
8588   g_object_ref (vc->anchor);
8589
8590   g_object_set_data (G_OBJECT (child),
8591                      I_("gtk-text-view-child"),
8592                      vc);
8593
8594   gtk_text_child_anchor_register_child (anchor, child, layout);
8595   
8596   return vc;
8597 }
8598
8599 static GtkTextViewChild*
8600 text_view_child_new_window (GtkWidget          *child,
8601                             GtkTextWindowType   type,
8602                             gint                x,
8603                             gint                y)
8604 {
8605   GtkTextViewChild *vc;
8606
8607   vc = g_new (GtkTextViewChild, 1);
8608
8609   vc->widget = child;
8610   vc->anchor = NULL;
8611
8612   vc->from_top_of_line = 0;
8613   vc->from_left_of_buffer = 0;
8614  
8615   g_object_ref (vc->widget);
8616
8617   vc->type = type;
8618   vc->x = x;
8619   vc->y = y;
8620
8621   g_object_set_data (G_OBJECT (child),
8622                      I_("gtk-text-view-child"),
8623                      vc);
8624   
8625   return vc;
8626 }
8627
8628 static void
8629 text_view_child_free (GtkTextViewChild *child)
8630 {
8631   g_object_set_data (G_OBJECT (child->widget),
8632                      I_("gtk-text-view-child"), NULL);
8633
8634   if (child->anchor)
8635     {
8636       gtk_text_child_anchor_unregister_child (child->anchor,
8637                                               child->widget);
8638       g_object_unref (child->anchor);
8639     }
8640
8641   g_object_unref (child->widget);
8642
8643   g_free (child);
8644 }
8645
8646 static void
8647 text_view_child_set_parent_window (GtkTextView      *text_view,
8648                                    GtkTextViewChild *vc)
8649 {
8650   if (vc->anchor)
8651     gtk_widget_set_parent_window (vc->widget,
8652                                   text_view->text_window->bin_window);
8653   else
8654     {
8655       GdkWindow *window;
8656       window = gtk_text_view_get_window (text_view,
8657                                          vc->type);
8658       gtk_widget_set_parent_window (vc->widget, window);
8659     }
8660 }
8661
8662 static void
8663 add_child (GtkTextView      *text_view,
8664            GtkTextViewChild *vc)
8665 {
8666   text_view->children = g_slist_prepend (text_view->children,
8667                                          vc);
8668
8669   if (GTK_WIDGET_REALIZED (text_view))
8670     text_view_child_set_parent_window (text_view, vc);
8671   
8672   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
8673 }
8674
8675 /**
8676  * gtk_text_view_add_child_at_anchor:
8677  * @text_view: a #GtkTextView
8678  * @child: a #GtkWidget
8679  * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
8680  * 
8681  * Adds a child widget in the text buffer, at the given @anchor.
8682  **/
8683 void
8684 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
8685                                    GtkWidget            *child,
8686                                    GtkTextChildAnchor   *anchor)
8687 {
8688   GtkTextViewChild *vc;
8689
8690   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8691   g_return_if_fail (GTK_IS_WIDGET (child));
8692   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
8693   g_return_if_fail (child->parent == NULL);
8694
8695   gtk_text_view_ensure_layout (text_view);
8696
8697   vc = text_view_child_new_anchored (child, anchor,
8698                                      text_view->layout);
8699
8700   add_child (text_view, vc);
8701
8702   g_assert (vc->widget == child);
8703   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8704 }
8705
8706 /**
8707  * gtk_text_view_add_child_in_window:
8708  * @text_view: a #GtkTextView
8709  * @child: a #GtkWidget
8710  * @which_window: which window the child should appear in
8711  * @xpos: X position of child in window coordinates
8712  * @ypos: Y position of child in window coordinates
8713  *
8714  * Adds a child at fixed coordinates in one of the text widget's
8715  * windows. The window must have nonzero size (see
8716  * gtk_text_view_set_border_window_size()). Note that the child
8717  * coordinates are given relative to the #GdkWindow in question, and
8718  * that these coordinates have no sane relationship to scrolling. When
8719  * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
8720  * irrelevant, the child floats above all scrollable areas. But when
8721  * placing a child in one of the scrollable windows (border windows or
8722  * text window), you'll need to compute the child's correct position
8723  * in buffer coordinates any time scrolling occurs or buffer changes
8724  * occur, and then call gtk_text_view_move_child() to update the
8725  * child's position. Unfortunately there's no good way to detect that
8726  * scrolling has occurred, using the current API; a possible hack
8727  * would be to update all child positions when the scroll adjustments
8728  * change or the text buffer changes. See bug 64518 on
8729  * bugzilla.gnome.org for status of fixing this issue.
8730  **/
8731 void
8732 gtk_text_view_add_child_in_window (GtkTextView       *text_view,
8733                                    GtkWidget         *child,
8734                                    GtkTextWindowType  which_window,
8735                                    gint               xpos,
8736                                    gint               ypos)
8737 {
8738   GtkTextViewChild *vc;
8739
8740   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8741   g_return_if_fail (GTK_IS_WIDGET (child));
8742   g_return_if_fail (child->parent == NULL);
8743
8744   vc = text_view_child_new_window (child, which_window,
8745                                    xpos, ypos);
8746
8747   add_child (text_view, vc);
8748
8749   g_assert (vc->widget == child);
8750   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
8751 }
8752
8753 /**
8754  * gtk_text_view_move_child:
8755  * @text_view: a #GtkTextView
8756  * @child: child widget already added to the text view
8757  * @xpos: new X position in window coordinates
8758  * @ypos: new Y position in window coordinates
8759  *
8760  * Updates the position of a child, as for gtk_text_view_add_child_in_window().
8761  **/
8762 void
8763 gtk_text_view_move_child (GtkTextView *text_view,
8764                           GtkWidget   *child,
8765                           gint         xpos,
8766                           gint         ypos)
8767 {
8768   GtkTextViewChild *vc;
8769
8770   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8771   g_return_if_fail (GTK_IS_WIDGET (child));
8772   g_return_if_fail (child->parent == (GtkWidget*) text_view);
8773
8774   vc = g_object_get_data (G_OBJECT (child),
8775                           "gtk-text-view-child");
8776
8777   g_assert (vc != NULL);
8778
8779   if (vc->x == xpos &&
8780       vc->y == ypos)
8781     return;
8782   
8783   vc->x = xpos;
8784   vc->y = ypos;
8785
8786   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
8787     gtk_widget_queue_resize (child);
8788 }
8789
8790
8791 /* Iterator operations */
8792
8793 /**
8794  * gtk_text_view_forward_display_line:
8795  * @text_view: a #GtkTextView
8796  * @iter: a #GtkTextIter
8797  * 
8798  * Moves the given @iter forward by one display (wrapped) line.
8799  * A display line is different from a paragraph. Paragraphs are
8800  * separated by newlines or other paragraph separator characters.
8801  * Display lines are created by line-wrapping a paragraph. If
8802  * wrapping is turned off, display lines and paragraphs will be the
8803  * same. Display lines are divided differently for each view, since
8804  * they depend on the view's width; paragraphs are the same in all
8805  * views, since they depend on the contents of the #GtkTextBuffer.
8806  * 
8807  * Return value: %TRUE if @iter was moved and is not on the end iterator
8808  **/
8809 gboolean
8810 gtk_text_view_forward_display_line (GtkTextView *text_view,
8811                                     GtkTextIter *iter)
8812 {
8813   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8814   g_return_val_if_fail (iter != NULL, FALSE);
8815
8816   gtk_text_view_ensure_layout (text_view);
8817
8818   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
8819 }
8820
8821 /**
8822  * gtk_text_view_backward_display_line:
8823  * @text_view: a #GtkTextView
8824  * @iter: a #GtkTextIter
8825  * 
8826  * Moves the given @iter backward by one display (wrapped) line.
8827  * A display line is different from a paragraph. Paragraphs are
8828  * separated by newlines or other paragraph separator characters.
8829  * Display lines are created by line-wrapping a paragraph. If
8830  * wrapping is turned off, display lines and paragraphs will be the
8831  * same. Display lines are divided differently for each view, since
8832  * they depend on the view's width; paragraphs are the same in all
8833  * views, since they depend on the contents of the #GtkTextBuffer.
8834  * 
8835  * Return value: %TRUE if @iter was moved and is not on the end iterator
8836  **/
8837 gboolean
8838 gtk_text_view_backward_display_line (GtkTextView *text_view,
8839                                      GtkTextIter *iter)
8840 {
8841   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8842   g_return_val_if_fail (iter != NULL, FALSE);
8843
8844   gtk_text_view_ensure_layout (text_view);
8845
8846   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
8847 }
8848
8849 /**
8850  * gtk_text_view_forward_display_line_end:
8851  * @text_view: a #GtkTextView
8852  * @iter: a #GtkTextIter
8853  * 
8854  * Moves the given @iter forward to the next display line end.
8855  * A display line is different from a paragraph. Paragraphs are
8856  * separated by newlines or other paragraph separator characters.
8857  * Display lines are created by line-wrapping a paragraph. If
8858  * wrapping is turned off, display lines and paragraphs will be the
8859  * same. Display lines are divided differently for each view, since
8860  * they depend on the view's width; paragraphs are the same in all
8861  * views, since they depend on the contents of the #GtkTextBuffer.
8862  * 
8863  * Return value: %TRUE if @iter was moved and is not on the end iterator
8864  **/
8865 gboolean
8866 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
8867                                         GtkTextIter *iter)
8868 {
8869   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8870   g_return_val_if_fail (iter != NULL, FALSE);
8871
8872   gtk_text_view_ensure_layout (text_view);
8873
8874   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
8875 }
8876
8877 /**
8878  * gtk_text_view_backward_display_line_start:
8879  * @text_view: a #GtkTextView
8880  * @iter: a #GtkTextIter
8881  * 
8882  * Moves the given @iter backward to the next display line start.
8883  * A display line is different from a paragraph. Paragraphs are
8884  * separated by newlines or other paragraph separator characters.
8885  * Display lines are created by line-wrapping a paragraph. If
8886  * wrapping is turned off, display lines and paragraphs will be the
8887  * same. Display lines are divided differently for each view, since
8888  * they depend on the view's width; paragraphs are the same in all
8889  * views, since they depend on the contents of the #GtkTextBuffer.
8890  * 
8891  * Return value: %TRUE if @iter was moved and is not on the end iterator
8892  **/
8893 gboolean
8894 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
8895                                            GtkTextIter *iter)
8896 {
8897   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8898   g_return_val_if_fail (iter != NULL, FALSE);
8899
8900   gtk_text_view_ensure_layout (text_view);
8901
8902   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
8903 }
8904
8905 /**
8906  * gtk_text_view_starts_display_line:
8907  * @text_view: a #GtkTextView
8908  * @iter: a #GtkTextIter
8909  * 
8910  * Determines whether @iter is at the start of a display line.
8911  * See gtk_text_view_forward_display_line() for an explanation of
8912  * display lines vs. paragraphs.
8913  * 
8914  * Return value: %TRUE if @iter begins a wrapped line
8915  **/
8916 gboolean
8917 gtk_text_view_starts_display_line (GtkTextView       *text_view,
8918                                    const 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_iter_starts_line (text_view->layout, iter);
8926 }
8927
8928 /**
8929  * gtk_text_view_move_visually:
8930  * @text_view: a #GtkTextView
8931  * @iter: a #GtkTextIter
8932  * @count: number of characters to move (negative moves left, 
8933  *    positive moves right)
8934  *
8935  * Move the iterator a given number of characters visually, treating
8936  * it as the strong cursor position. If @count is positive, then the
8937  * new strong cursor position will be @count positions to the right of
8938  * the old cursor position. If @count is negative then the new strong
8939  * cursor position will be @count positions to the left of the old
8940  * cursor position.
8941  *
8942  * In the presence of bi-directional text, the correspondence
8943  * between logical and visual order will depend on the direction
8944  * of the current run, and there may be jumps when the cursor
8945  * is moved off of the end of a run.
8946  * 
8947  * Return value: %TRUE if @iter moved and is not on the end iterator
8948  **/
8949 gboolean
8950 gtk_text_view_move_visually (GtkTextView *text_view,
8951                              GtkTextIter *iter,
8952                              gint         count)
8953 {
8954   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
8955   g_return_val_if_fail (iter != NULL, FALSE);
8956
8957   gtk_text_view_ensure_layout (text_view);
8958
8959   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
8960 }
8961
8962 #define __GTK_TEXT_VIEW_C__
8963 #include "gtkaliasdef.c"