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