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