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