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