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