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