]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
Adapt to uscore-ification of gtktextiterprivate
[~andy/gtk] / gtk / gtktextview.c
1 /* GTK - The GIMP Toolkit
2  * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include <string.h>
28
29 #include "gtkbindings.h"
30 #include "gtkdnd.h"
31 #include "gtkintl.h"
32 #include "gtkmain.h"
33 #include "gtkmenu.h"
34 #include "gtkmenuitem.h"
35 #include "gtksignal.h"
36 #include "gtktext.h"
37 #include "gtktextdisplay.h"
38 #include "gtktextview.h"
39 #include "gtkimmulticontext.h"
40 #include "gdk/gdkkeysyms.h"
41 #include <string.h>
42
43 #define FOCUS_EDGE_WIDTH 1
44 #define DRAG_THRESHOLD 8
45
46 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
47 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
48
49 enum
50 {
51   MOVE_CURSOR,
52   SET_ANCHOR,
53   INSERT_AT_CURSOR,
54   DELETE_FROM_CURSOR,
55   CUT_CLIPBOARD,
56   COPY_CLIPBOARD,
57   PASTE_CLIPBOARD,
58   TOGGLE_OVERWRITE,
59   SET_SCROLL_ADJUSTMENTS,
60   LAST_SIGNAL
61 };
62
63 enum
64 {
65   ARG_0,
66   ARG_HEIGHT_LINES,
67   ARG_WIDTH_COLUMNS,
68   ARG_PIXELS_ABOVE_LINES,
69   ARG_PIXELS_BELOW_LINES,
70   ARG_PIXELS_INSIDE_WRAP,
71   ARG_EDITABLE,
72   ARG_WRAP_MODE,
73   ARG_JUSTIFY,
74   ARG_LEFT_MARGIN,
75   ARG_RIGHT_MARGIN,
76   ARG_INDENT,
77   ARG_TABS,
78   LAST_ARG
79 };
80
81 static void gtk_text_view_init                 (GtkTextView      *text_view);
82 static void gtk_text_view_class_init           (GtkTextViewClass *klass);
83 static void gtk_text_view_destroy              (GtkObject        *object);
84 static void gtk_text_view_finalize             (GObject          *object);
85 static void gtk_text_view_set_arg              (GtkObject        *object,
86                                                 GtkArg           *arg,
87                                                 guint             arg_id);
88 static void gtk_text_view_get_arg              (GtkObject        *object,
89                                                 GtkArg           *arg,
90                                                 guint             arg_id);
91 static void gtk_text_view_size_request         (GtkWidget        *widget,
92                                                 GtkRequisition   *requisition);
93 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
94                                                 GtkAllocation    *allocation);
95 static void gtk_text_view_realize              (GtkWidget        *widget);
96 static void gtk_text_view_unrealize            (GtkWidget        *widget);
97 static void gtk_text_view_style_set            (GtkWidget        *widget,
98                                                 GtkStyle         *previous_style);
99 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
100                                                 GtkTextDirection  previous_direction);
101 static gint gtk_text_view_event                (GtkWidget        *widget,
102                                                 GdkEvent         *event);
103 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
104                                                 GdkEventKey      *event);
105 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
106                                                 GdkEventKey      *event);
107 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
108                                                 GdkEventButton   *event);
109 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
110                                                 GdkEventButton   *event);
111 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
112                                                 GdkEventFocus    *event);
113 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
114                                                 GdkEventFocus    *event);
115 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
116                                                 GdkEventMotion   *event);
117 static gint gtk_text_view_expose_event         (GtkWidget        *widget,
118                                                 GdkEventExpose   *expose);
119 static void gtk_text_view_draw_focus           (GtkWidget        *widget);
120
121 /* Source side drag signals */
122 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
123                                             GdkDragContext   *context);
124 static void gtk_text_view_drag_end         (GtkWidget        *widget,
125                                             GdkDragContext   *context);
126 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
127                                             GdkDragContext   *context,
128                                             GtkSelectionData *selection_data,
129                                             guint             info,
130                                             guint             time);
131 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
132                                             GdkDragContext   *context);
133
134 /* Target side drag signals */
135 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
136                                                   GdkDragContext   *context,
137                                                   guint             time);
138 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
139                                                   GdkDragContext   *context,
140                                                   gint              x,
141                                                   gint              y,
142                                                   guint             time);
143 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
144                                                   GdkDragContext   *context,
145                                                   gint              x,
146                                                   gint              y,
147                                                   guint             time);
148 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
149                                                   GdkDragContext   *context,
150                                                   gint              x,
151                                                   gint              y,
152                                                   GtkSelectionData *selection_data,
153                                                   guint             info,
154                                                   guint             time);
155
156 static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
157                                                   GtkAdjustment *hadj,
158                                                   GtkAdjustment *vadj);
159
160 static void gtk_text_view_move_cursor      (GtkTextView           *text_view,
161                                             GtkMovementStep        step,
162                                             gint                   count,
163                                             gboolean               extend_selection);
164 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
165 static void gtk_text_view_scroll_pages     (GtkTextView           *text_view,
166                                             gint                   count);
167 static void gtk_text_view_insert_at_cursor (GtkTextView           *text_view,
168                                             const gchar           *str);
169 static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
170                                               GtkDeleteType          type,
171                                               gint                   count);
172 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
173 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
174 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
175 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
176 static void gtk_text_view_unselect         (GtkTextView           *text_view);
177
178 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
179 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
180                                                      GtkTextIter        *iter);
181 static void     gtk_text_view_scroll_calc_now       (GtkTextView        *text_view);
182 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
183                                                          GtkTextAttributes *values,
184                                                          GtkStyle           *style);
185 static void     gtk_text_view_ensure_layout         (GtkTextView        *text_view);
186 static void     gtk_text_view_destroy_layout        (GtkTextView        *text_view);
187 static void     gtk_text_view_reset_im_context      (GtkTextView        *text_view);
188 static void     gtk_text_view_start_selection_drag  (GtkTextView        *text_view,
189                                                      const GtkTextIter  *iter,
190                                                      GdkEventButton     *event);
191 static gboolean gtk_text_view_end_selection_drag    (GtkTextView        *text_view,
192                                                      GdkEventButton     *event);
193 static void     gtk_text_view_start_selection_dnd   (GtkTextView        *text_view,
194                                                      const GtkTextIter  *iter,
195                                                      GdkEventMotion     *event);
196 static void     gtk_text_view_start_cursor_blink    (GtkTextView        *text_view,
197                                                      gboolean            with_delay);
198 static void     gtk_text_view_stop_cursor_blink     (GtkTextView        *text_view);
199
200 static void gtk_text_view_value_changed           (GtkAdjustment *adj,
201                                                    GtkTextView   *view);
202 static void gtk_text_view_commit_handler          (GtkIMContext  *context,
203                                                    const gchar   *str,
204                                                    GtkTextView   *text_view);
205 static void gtk_text_view_preedit_changed_handler (GtkIMContext  *context,
206                                                    GtkTextView   *text_view);
207
208 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
209                                                   const GtkTextIter *location,
210                                                   GtkTextMark       *mark,
211                                                   gpointer           data);
212 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
213                                                   gint              *x,
214                                                   gint              *y);
215 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
216                                                   gint               x,
217                                                   gint               y);
218
219 static GtkAdjustment* get_hadjustment            (GtkTextView       *text_view);
220 static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
221
222 static void gtk_text_view_popup_menu             (GtkTextView       *text_view,
223                                                   GdkEventButton    *event);
224
225 /* Container methods */
226 static void gtk_text_view_add    (GtkContainer *container,
227                                   GtkWidget    *child);
228 static void gtk_text_view_remove (GtkContainer *container,
229                                   GtkWidget    *child);
230 static void gtk_text_view_forall (GtkContainer *container,
231                                   gboolean      include_internals,
232                                   GtkCallback   callback,
233                                   gpointer      callback_data);
234
235 /* FIXME probably need the focus methods. */
236
237 /* Hack-around */
238 #define g_signal_handlers_disconnect_by_func(obj, func, data) g_signal_handlers_disconnect_matched (obj, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, func, data)
239
240 typedef struct _GtkTextViewChild GtkTextViewChild;
241
242 struct _GtkTextViewChild
243 {
244   GtkWidget *widget;
245
246   GtkTextChildAnchor *anchor;
247
248   gint from_top_of_line;
249   gint from_left_of_buffer;
250   
251   /* These are ignored if anchor != NULL */
252   GtkTextWindowType type;
253   gint x;
254   gint y;
255 };
256
257 static GtkTextViewChild* text_view_child_new_anchored (GtkWidget          *child,
258                                                        GtkTextChildAnchor *anchor,
259                                                        GtkTextLayout      *layout);
260 static GtkTextViewChild* text_view_child_new_window   (GtkWidget          *child,
261                                                        GtkTextWindowType   type,
262                                                        gint                x,
263                                                        gint                y);
264 static void              text_view_child_free         (GtkTextViewChild   *child);
265
266 static void              text_view_child_realize      (GtkTextView      *text_view,
267                                                        GtkTextViewChild *child);
268
269 struct _GtkTextWindow
270 {
271   GtkTextWindowType type;
272   GtkWidget *widget;
273   GdkWindow *window;
274   GdkWindow *bin_window;
275   GtkRequisition requisition;
276   GdkRectangle allocation;
277 };
278
279 static GtkTextWindow *text_window_new             (GtkTextWindowType  type,
280                                                    GtkWidget         *widget,
281                                                    gint               width_request,
282                                                    gint               height_request);
283 static void           text_window_free            (GtkTextWindow     *win);
284 static void           text_window_realize         (GtkTextWindow     *win,
285                                                    GdkWindow         *parent);
286 static void           text_window_unrealize       (GtkTextWindow     *win);
287 static void           text_window_size_allocate   (GtkTextWindow     *win,
288                                                    GdkRectangle      *rect);
289 static void           text_window_scroll          (GtkTextWindow     *win,
290                                                    gint               dx,
291                                                    gint               dy);
292 static void           text_window_invalidate_rect (GtkTextWindow     *win,
293                                                    GdkRectangle      *rect);
294
295 static gint           text_window_get_width       (GtkTextWindow     *win);
296 static gint           text_window_get_height      (GtkTextWindow     *win);
297 static void           text_window_get_allocation  (GtkTextWindow     *win,
298                                                    GdkRectangle      *rect);
299
300
301 enum
302 {
303   TARGET_STRING,
304   TARGET_TEXT,
305   TARGET_COMPOUND_TEXT,
306   TARGET_UTF8_STRING,
307   TARGET_TEXT_BUFFER_CONTENTS
308 };
309
310 static GtkTargetEntry target_table[] = {
311   { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP,
312     TARGET_TEXT_BUFFER_CONTENTS },
313   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
314   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
315   { "TEXT", 0, TARGET_TEXT },
316   { "text/plain", 0, TARGET_STRING },
317   { "STRING",     0, TARGET_STRING }
318 };
319
320 static GtkContainerClass *parent_class = NULL;
321 static guint signals[LAST_SIGNAL] = { 0 };
322
323 GtkType
324 gtk_text_view_get_type (void)
325 {
326   static GtkType our_type = 0;
327
328   if (our_type == 0)
329     {
330       static const GtkTypeInfo our_info =
331       {
332         "GtkTextView",
333         sizeof (GtkTextView),
334         sizeof (GtkTextViewClass),
335         (GtkClassInitFunc) gtk_text_view_class_init,
336         (GtkObjectInitFunc) gtk_text_view_init,
337         /* reserved_1 */ NULL,
338         /* reserved_2 */ NULL,
339         (GtkClassInitFunc) NULL
340       };
341
342       our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
343     }
344
345   return our_type;
346 }
347
348 static void
349 add_move_binding (GtkBindingSet  *binding_set,
350                   guint           keyval,
351                   guint           modmask,
352                   GtkMovementStep step,
353                   gint            count)
354 {
355   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
356
357   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
358                                 "move_cursor", 3,
359                                 GTK_TYPE_ENUM, step,
360                                 GTK_TYPE_INT, count,
361                                 GTK_TYPE_BOOL, FALSE);
362
363   /* Selection-extending version */
364   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
365                                 "move_cursor", 3,
366                                 GTK_TYPE_ENUM, step,
367                                 GTK_TYPE_INT, count,
368                                 GTK_TYPE_BOOL, TRUE);
369 }
370
371 static void
372 gtk_text_view_class_init (GtkTextViewClass *klass)
373 {
374   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
375   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
376   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
377   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
378   GtkBindingSet *binding_set;
379
380   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
381
382   /* Default handlers and virtual methods
383    */
384   object_class->set_arg = gtk_text_view_set_arg;
385   object_class->get_arg = gtk_text_view_get_arg;
386
387   object_class->destroy = gtk_text_view_destroy;
388   gobject_class->finalize = gtk_text_view_finalize;
389
390   widget_class->realize = gtk_text_view_realize;
391   widget_class->unrealize = gtk_text_view_unrealize;
392   widget_class->style_set = gtk_text_view_style_set;
393   widget_class->direction_changed = gtk_text_view_direction_changed;
394   widget_class->size_request = gtk_text_view_size_request;
395   widget_class->size_allocate = gtk_text_view_size_allocate;
396   widget_class->event = gtk_text_view_event;
397   widget_class->key_press_event = gtk_text_view_key_press_event;
398   widget_class->key_release_event = gtk_text_view_key_release_event;
399   widget_class->button_press_event = gtk_text_view_button_press_event;
400   widget_class->button_release_event = gtk_text_view_button_release_event;
401   widget_class->focus_in_event = gtk_text_view_focus_in_event;
402   widget_class->focus_out_event = gtk_text_view_focus_out_event;
403   widget_class->motion_notify_event = gtk_text_view_motion_event;
404   widget_class->expose_event = gtk_text_view_expose_event;
405   widget_class->draw_focus = gtk_text_view_draw_focus;
406
407   widget_class->drag_begin = gtk_text_view_drag_begin;
408   widget_class->drag_end = gtk_text_view_drag_end;
409   widget_class->drag_data_get = gtk_text_view_drag_data_get;
410   widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
411
412   widget_class->drag_leave = gtk_text_view_drag_leave;
413   widget_class->drag_motion = gtk_text_view_drag_motion;
414   widget_class->drag_drop = gtk_text_view_drag_drop;
415   widget_class->drag_data_received = gtk_text_view_drag_data_received;
416
417   container_class->add = gtk_text_view_add;
418   container_class->remove = gtk_text_view_remove;
419   container_class->forall = gtk_text_view_forall;
420
421   klass->move_cursor = gtk_text_view_move_cursor;
422   klass->set_anchor = gtk_text_view_set_anchor;
423   klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
424   klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
425   klass->cut_clipboard = gtk_text_view_cut_clipboard;
426   klass->copy_clipboard = gtk_text_view_copy_clipboard;
427   klass->paste_clipboard = gtk_text_view_paste_clipboard;
428   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
429   klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
430
431   /*
432    * Arguments
433    */
434   gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
435                            GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
436   gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
437                            GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
438   gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
439                            GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
440   gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
441                            GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
442   gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
443                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
444   gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
445                            GTK_ARG_READWRITE, ARG_EDITABLE);
446   gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
447                            GTK_ARG_READWRITE, ARG_WRAP_MODE);
448   gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_ENUM,
449                            GTK_ARG_READWRITE, ARG_JUSTIFY);
450   gtk_object_add_arg_type ("GtkTextView::left_margin", GTK_TYPE_INT,
451                            GTK_ARG_READWRITE, ARG_LEFT_MARGIN);
452   gtk_object_add_arg_type ("GtkTextView::right_margin", GTK_TYPE_INT,
453                            GTK_ARG_READWRITE, ARG_RIGHT_MARGIN);
454   gtk_object_add_arg_type ("GtkTextView::indent", GTK_TYPE_INT,
455                            GTK_ARG_READWRITE, ARG_INDENT);
456   gtk_object_add_arg_type ("GtkTextView::tabs", GTK_TYPE_POINTER, /* FIXME */
457                            GTK_ARG_READWRITE, ARG_TABS);
458
459   /*
460    * Signals
461    */
462
463   signals[MOVE_CURSOR] =
464     gtk_signal_new ("move_cursor",
465                     GTK_RUN_LAST | GTK_RUN_ACTION,
466                     GTK_CLASS_TYPE (object_class),
467                     GTK_SIGNAL_OFFSET (GtkTextViewClass, move_cursor),
468                     gtk_marshal_VOID__ENUM_INT_BOOLEAN,
469                     GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
470
471   signals[SET_ANCHOR] =
472     gtk_signal_new ("set_anchor",
473                     GTK_RUN_LAST | GTK_RUN_ACTION,
474                     GTK_CLASS_TYPE (object_class),
475                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
476                     gtk_marshal_VOID__VOID,
477                     GTK_TYPE_NONE, 0);
478
479   signals[INSERT_AT_CURSOR] =
480     gtk_signal_new ("insert_at_cursor",
481                     GTK_RUN_LAST | GTK_RUN_ACTION,
482                     GTK_CLASS_TYPE (object_class),
483                     GTK_SIGNAL_OFFSET (GtkTextViewClass, insert_at_cursor),
484                     gtk_marshal_VOID__POINTER,
485                     GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
486
487   signals[DELETE_FROM_CURSOR] =
488     gtk_signal_new ("delete_from_cursor",
489                     GTK_RUN_LAST | GTK_RUN_ACTION,
490                     GTK_CLASS_TYPE (object_class),
491                     GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_from_cursor),
492                     gtk_marshal_VOID__ENUM_INT,
493                     GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
494
495   signals[CUT_CLIPBOARD] =
496     gtk_signal_new ("cut_clipboard",
497                     GTK_RUN_LAST | GTK_RUN_ACTION,
498                     GTK_CLASS_TYPE (object_class),
499                     GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_clipboard),
500                     gtk_marshal_VOID__VOID,
501                     GTK_TYPE_NONE, 0);
502
503   signals[COPY_CLIPBOARD] =
504     gtk_signal_new ("copy_clipboard",
505                     GTK_RUN_LAST | GTK_RUN_ACTION,
506                     GTK_CLASS_TYPE (object_class),
507                     GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_clipboard),
508                     gtk_marshal_VOID__VOID,
509                     GTK_TYPE_NONE, 0);
510
511   signals[PASTE_CLIPBOARD] =
512     gtk_signal_new ("paste_clipboard",
513                     GTK_RUN_LAST | GTK_RUN_ACTION,
514                     GTK_CLASS_TYPE (object_class),
515                     GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_clipboard),
516                     gtk_marshal_VOID__VOID,
517                     GTK_TYPE_NONE, 0);
518
519   signals[TOGGLE_OVERWRITE] =
520     gtk_signal_new ("toggle_overwrite",
521                     GTK_RUN_LAST | GTK_RUN_ACTION,
522                     GTK_CLASS_TYPE (object_class),
523                     GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
524                     gtk_marshal_VOID__VOID,
525                     GTK_TYPE_NONE, 0);
526
527   signals[SET_SCROLL_ADJUSTMENTS] =
528     gtk_signal_new ("set_scroll_adjustments",
529                     GTK_RUN_LAST,
530                     GTK_CLASS_TYPE (object_class),
531                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
532                     gtk_marshal_VOID__POINTER_POINTER,
533                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
534   widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
535
536   /*
537    * Key bindings
538    */
539
540   binding_set = gtk_binding_set_by_class (klass);
541
542   /* Moving the insertion point */
543   add_move_binding (binding_set, GDK_Right, 0,
544                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
545
546   add_move_binding (binding_set, GDK_Left, 0,
547                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
548
549   add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
550                     GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
551
552   add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
553                     GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
554
555   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
556                     GTK_MOVEMENT_WORDS, 1);
557
558   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
559                     GTK_MOVEMENT_WORDS, -1);
560
561   /* Eventually we want to move by display lines, not paragraphs */
562   add_move_binding (binding_set, GDK_Up, 0,
563                     GTK_MOVEMENT_DISPLAY_LINES, -1);
564
565   add_move_binding (binding_set, GDK_Down, 0,
566                     GTK_MOVEMENT_DISPLAY_LINES, 1);
567
568   add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
569                     GTK_MOVEMENT_DISPLAY_LINES, -1);
570
571   add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
572                     GTK_MOVEMENT_DISPLAY_LINES, 1);
573
574   add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
575                     GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
576
577   add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
578                     GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
579
580   add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
581                     GTK_MOVEMENT_WORDS, 1);
582
583   add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
584                     GTK_MOVEMENT_WORDS, -1);
585
586   add_move_binding (binding_set, GDK_Home, 0,
587                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
588
589   add_move_binding (binding_set, GDK_End, 0,
590                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
591
592   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
593                     GTK_MOVEMENT_BUFFER_ENDS, -1);
594
595   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
596                     GTK_MOVEMENT_BUFFER_ENDS, 1);
597
598   add_move_binding (binding_set, GDK_Page_Up, 0,
599                     GTK_MOVEMENT_PAGES, -1);
600
601   add_move_binding (binding_set, GDK_Page_Down, 0,
602                     GTK_MOVEMENT_PAGES, 1);
603
604
605   /* Setting the cut/paste/copy anchor */
606   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
607                                 "set_anchor", 0);
608
609   /* Deleting text */
610   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
611                                 "delete_from_cursor", 2,
612                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
613                                 GTK_TYPE_INT, 1);
614
615   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
616                                 "delete_from_cursor", 2,
617                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
618                                 GTK_TYPE_INT, 1);
619
620   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
621                                 "delete_from_cursor", 2,
622                                 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
623                                 GTK_TYPE_INT, -1);
624
625   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
626                                 "delete_from_cursor", 2,
627                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
628                                 GTK_TYPE_INT, 1);
629
630   gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
631                                 "delete_from_cursor", 2,
632                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
633                                 GTK_TYPE_INT, 1);
634
635   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
636                                 "delete_from_cursor", 2,
637                                 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
638                                 GTK_TYPE_INT, -1);
639
640   gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
641                                 "delete_from_cursor", 2,
642                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
643                                 GTK_TYPE_INT, 1);
644
645   gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
646                                 "delete_from_cursor", 2,
647                                 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
648                                 GTK_TYPE_INT, 1);
649
650   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
651                                 "delete_from_cursor", 2,
652                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
653                                 GTK_TYPE_INT, 1);
654   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
655                                 "insert_at_cursor", 1,
656                                 GTK_TYPE_STRING, " ");
657
658   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
659                                 "delete_from_cursor", 2,
660                                 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
661                                 GTK_TYPE_INT, 1);
662
663   /* Cut/copy/paste */
664
665   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
666                                 "cut_clipboard", 0);
667
668   gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
669                                 "cut_clipboard", 0);
670
671   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
672                                 "copy_clipboard", 0);
673
674   gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
675                                 "paste_clipboard", 0);
676
677   gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
678                                 "paste_clipboard", 0);
679
680   /* Overwrite */
681   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
682                                 "toggle_overwrite", 0);
683 }
684
685 void
686 gtk_text_view_init (GtkTextView *text_view)
687 {
688   GtkWidget *widget;
689
690   widget = GTK_WIDGET (text_view);
691
692   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
693
694   /* Set up default style */
695   text_view->wrap_mode = GTK_WRAPMODE_NONE;
696   text_view->pixels_above_lines = 0;
697   text_view->pixels_below_lines = 0;
698   text_view->pixels_inside_wrap = 0;
699   text_view->justify = GTK_JUSTIFY_LEFT;
700   text_view->left_margin = 0;
701   text_view->right_margin = 0;
702   text_view->indent = 0;
703   text_view->tabs = NULL;
704   text_view->editable = TRUE;
705
706   gtk_drag_dest_set (widget,
707                      GTK_DEST_DEFAULT_DROP,
708                      target_table, G_N_ELEMENTS (target_table),
709                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
710
711   text_view->virtual_cursor_x = -1;
712   text_view->virtual_cursor_y = -1;
713
714   /* This object is completely private. No external entity can gain a reference
715    * to it; so we create it here and destroy it in finalize ().
716    */
717   text_view->im_context = gtk_im_multicontext_new ();
718
719   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
720                       GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
721
722   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "preedit_changed",
723                       GTK_SIGNAL_FUNC (gtk_text_view_preedit_changed_handler), text_view);
724
725   text_view->cursor_visible = TRUE;
726
727   text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
728                                             widget, 200, 200);
729
730   text_view->drag_start_x = -1;
731   text_view->drag_start_y = -1;
732 }
733
734 /**
735  * gtk_text_view_new:
736  *
737  * Creates a new #GtkTextView. If you don't call gtk_text_view_set_buffer()
738  * before using the text view, an empty default buffer will be created
739  * for you. Get the buffer with gtk_text_view_get_buffer(). If you want
740  * to specify your own buffer, consider gtk_text_view_new_with_buffer().
741  *
742  * Return value: a new #GtkTextView
743  **/
744 GtkWidget*
745 gtk_text_view_new (void)
746 {
747   return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
748 }
749
750 /**
751  * gtk_text_view_new_with_buffer:
752  * @buffer: a #GtkTextBuffer
753  *
754  * Creates a new #GtkTextView widget displaying the buffer
755  * @buffer. One buffer can be shared among many widgets.
756  * @buffer may be NULL to create a default buffer, in which case
757  * this function is equivalent to gtk_text_view_new(). The
758  * text view adds its own reference count to the buffer; it does not
759  * take over an existing reference.
760  *
761  * Return value: a new #GtkTextView.
762  **/
763 GtkWidget*
764 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
765 {
766   GtkTextView *text_view;
767
768   text_view = (GtkTextView*)gtk_text_view_new ();
769
770   gtk_text_view_set_buffer (text_view, buffer);
771
772   return GTK_WIDGET (text_view);
773 }
774
775 /**
776  * gtk_text_view_set_buffer:
777  * @text_view: a #GtkTextView
778  * @buffer: a #GtkTextBuffer
779  *
780  * Sets @buffer as the buffer being displayed by @text_view. The previous
781  * buffer displayed by the text view is unreferenced, and a reference is
782  * added to @buffer. If you owned a reference to @buffer before passing it
783  * to this function, you must remove that reference yourself; #GtkTextView
784  * will not "adopt" it.
785  *
786  **/
787 void
788 gtk_text_view_set_buffer (GtkTextView   *text_view,
789                           GtkTextBuffer *buffer)
790 {
791   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
792   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
793
794   if (text_view->buffer == buffer)
795     return;
796
797   if (text_view->buffer != NULL)
798     {
799       /* Destroy all anchored children */
800       GSList *tmp_list;
801       GSList *copy;
802
803       copy = g_slist_copy (text_view->children);
804       tmp_list = copy;
805       while (tmp_list != NULL)
806         {
807           GtkTextViewChild *vc = tmp_list->data;
808
809           if (vc->anchor)
810             {
811               gtk_widget_destroy (vc->widget);
812               /* vc may now be invalid! */
813             }
814
815           tmp_list = g_slist_next (tmp_list);
816         }
817
818       g_slist_free (copy);
819
820       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->buffer),
821                                             gtk_text_view_mark_set_handler, text_view);
822       g_object_unref (G_OBJECT (text_view->buffer));
823       text_view->dnd_mark = NULL;
824     }
825
826   text_view->buffer = buffer;
827
828   if (buffer != NULL)
829     {
830       GtkTextIter start;
831
832       g_object_ref (G_OBJECT (buffer));
833
834       if (text_view->layout)
835         gtk_text_layout_set_buffer (text_view->layout, buffer);
836
837       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
838
839       text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
840                                                          "gtk_drag_target",
841                                                          &start, FALSE);
842
843       text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
844                                                                 NULL,
845                                                                 &start, TRUE);
846
847       text_view->first_para_pixels = 0;
848
849       g_signal_connect_data (G_OBJECT (text_view->buffer), "mark_set",
850                              gtk_text_view_mark_set_handler, text_view,
851                              NULL, FALSE, FALSE);
852     }
853
854   if (GTK_WIDGET_VISIBLE (text_view))
855     gtk_widget_queue_draw (GTK_WIDGET (text_view));
856 }
857
858 static GtkTextBuffer*
859 get_buffer (GtkTextView *text_view)
860 {
861   if (text_view->buffer == NULL)
862     {
863       GtkTextBuffer *b;
864       b = gtk_text_buffer_new (NULL);
865       gtk_text_view_set_buffer (text_view, b);
866       g_object_unref (G_OBJECT (b));
867     }
868
869   return text_view->buffer;
870 }
871
872 /**
873  * gtk_text_view_get_buffer:
874  * @text_view: a #GtkTextView
875  *
876  * Returns the #GtkTextBuffer being displayed by this text view.
877  * The reference count on the buffer is not incremented; the caller
878  * of this function won't own a new reference.
879  *
880  * Return value: a #GtkTextBuffer
881  **/
882 GtkTextBuffer*
883 gtk_text_view_get_buffer (GtkTextView *text_view)
884 {
885   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
886
887   return get_buffer (text_view);
888 }
889
890 /**
891  * gtk_text_view_get_iter_at_location:
892  * @text_view: a #GtkTextView
893  * @iter: a #GtkTextIter
894  * @x: x position, in buffer coordinates
895  * @y: y position, in buffer coordinates
896  *
897  * Retrieves the iterator at buffer coordinates @x and @y. Buffer
898  * coordinates are coordinates for the entire buffer, not just the
899  * currently-displayed portion.  If you have coordinates from an
900  * event, you have to convert those to buffer coordinates with
901  * gtk_text_view_window_to_buffer_coords().
902  *
903  **/
904 void
905 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
906                                     GtkTextIter *iter,
907                                     gint         x,
908                                     gint         y)
909 {
910   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
911   g_return_if_fail (iter != NULL);
912   g_return_if_fail (text_view->layout != NULL);
913
914   gtk_text_layout_get_iter_at_pixel (text_view->layout,
915                                      iter,
916                                      x,
917                                      y);
918 }
919
920 /**
921  * gtk_text_view_get_iter_location:
922  * @text_view: a #GtkTextView
923  * @iter: a #GtkTextIter
924  * @location: bounds of the character at @iter
925  *
926  * Gets a rectangle which roughly contains the character at @iter.
927  * The rectangle position is in buffer coordinates; use
928  * gtk_text_view_buffer_to_window_coords() to convert these
929  * coordinates to coordinates for one of the windows in the text view.
930  *
931  **/
932 void
933 gtk_text_view_get_iter_location (GtkTextView       *text_view,
934                                  const GtkTextIter *iter,
935                                  GdkRectangle      *location)
936 {
937   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
938   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
939
940   gtk_text_layout_get_iter_location (text_view->layout, iter, location);
941 }
942
943 /**
944  * gtk_text_view_get_line_yrange:
945  * @text_view: a #GtkTextView
946  * @iter: a #GtkTextIter
947  * @y: return location for a y coordinate
948  * @height: return location for a height
949  *
950  * Gets the y coordinate of the top of the line containing @iter,
951  * and the height of the line. The coordinate is a buffer coordinate;
952  * convert to window coordinates with gtk_text_view_buffer_to_window_coords().
953  *
954  **/
955 void
956 gtk_text_view_get_line_yrange (GtkTextView       *text_view,
957                                const GtkTextIter *iter,
958                                gint              *y,
959                                gint              *height)
960 {
961   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
962   g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
963
964   gtk_text_layout_get_line_yrange (text_view->layout,
965                                    iter,
966                                    y,
967                                    height);
968 }
969
970 /**
971  * gtk_text_view_get_line_at_y:
972  * @text_view: a #GtkTextView
973  * @target_iter: a #GtkTextIter
974  * @y: a y coordinate
975  * @line_top: return location for top coordinate of the line
976  *
977  * Gets the #GtkTextIter at the start of the line containing
978  * the coordinate @y. @y is in buffer coordinates, convert from
979  * window coordinates with gtk_text_view_window_to_buffer_coords().
980  * If non-%NULL, @line_top will be filled with the coordinate of the top
981  * edge of the line.
982  **/
983 void
984 gtk_text_view_get_line_at_y (GtkTextView *text_view,
985                              GtkTextIter *target_iter,
986                              gint         y,
987                              gint        *line_top)
988 {
989   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
990
991   gtk_text_layout_get_line_at_y (text_view->layout,
992                                  target_iter,
993                                  y,
994                                  line_top);
995 }
996
997 static void
998 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
999 {
1000   /* We don't really want to clamp to upper; we want to clamp to
1001      upper - page_size which is the highest value the scrollbar
1002      will let us reach. */
1003   if (val > (adj->upper - adj->page_size))
1004     val = adj->upper - adj->page_size;
1005
1006   if (val < adj->lower)
1007     val = adj->lower;
1008
1009   gtk_adjustment_set_value (adj, val);
1010 }
1011
1012 static gboolean
1013 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
1014                                        GtkTextMark *mark,
1015                                        gint margin,
1016                                        gfloat percentage)
1017 {
1018   GtkTextIter iter;
1019   GdkRectangle rect;
1020   GdkRectangle screen;
1021   gint screen_bottom;
1022   gint screen_right;
1023   GtkWidget *widget;
1024   gboolean retval = FALSE;
1025   gint scroll_inc;
1026
1027   gint current_x_scroll, current_y_scroll;
1028
1029   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1030   g_return_val_if_fail (mark != NULL, FALSE);
1031
1032   widget = GTK_WIDGET (text_view);
1033
1034   if (!GTK_WIDGET_MAPPED (widget))
1035     {
1036       g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
1037       return FALSE;
1038     }
1039
1040   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1041
1042   gtk_text_layout_get_iter_location (text_view->layout,
1043                                      &iter,
1044                                      &rect);
1045
1046   /* Be sure the scroll region is up-to-date */
1047   gtk_text_view_scroll_calc_now (text_view);
1048
1049   current_x_scroll = text_view->xoffset;
1050   current_y_scroll = text_view->yoffset;
1051
1052   screen.x = current_x_scroll;
1053   screen.y = current_y_scroll;
1054   screen.width = SCREEN_WIDTH (widget);
1055   screen.height = SCREEN_HEIGHT (widget);
1056
1057   {
1058     /* Clamp margin so it's not too large. */
1059     gint small_dimension = MIN (screen.width, screen.height);
1060     gint max_rect_dim;
1061
1062     if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
1063       margin = (small_dimension/2 - 5);
1064
1065     if (margin < 0)
1066       margin = 0;
1067
1068     /* make sure rectangle fits in the leftover space */
1069
1070     max_rect_dim = MAX (rect.width, rect.height);
1071
1072     if (max_rect_dim > (small_dimension - margin*2))
1073       margin -= max_rect_dim - (small_dimension - margin*2);
1074
1075     if (margin < 0)
1076       margin = 0;
1077   }
1078
1079   g_assert (margin >= 0);
1080
1081   screen.x += margin;
1082   screen.y += margin;
1083
1084   screen.width -= margin*2;
1085   screen.height -= margin*2;
1086
1087   screen_bottom = screen.y + screen.height;
1088   screen_right = screen.x + screen.width;
1089
1090   /* Vertical scroll (only vertical gets adjusted) */
1091
1092   scroll_inc = 0;
1093   if (rect.y < screen.y)
1094     {
1095       gint scroll_dest = rect.y;
1096       scroll_inc = (scroll_dest - screen.y) * percentage;
1097     }
1098   else if ((rect.y + rect.height) > screen_bottom)
1099     {
1100       gint scroll_dest = rect.y + rect.height;
1101       scroll_inc = (scroll_dest - screen_bottom) * percentage;
1102     }
1103
1104   if (scroll_inc != 0)
1105     {
1106       set_adjustment_clamped (get_vadjustment (text_view),
1107                               current_y_scroll + scroll_inc);
1108       retval = TRUE;
1109     }
1110
1111   /* Horizontal scroll */
1112
1113   scroll_inc = 0;
1114   if (rect.x < screen.x)
1115     {
1116       gint scroll_dest = rect.x;
1117       scroll_inc = scroll_dest - screen.x;
1118     }
1119   else if ((rect.x + rect.width) > screen_right)
1120     {
1121       gint scroll_dest = rect.x + rect.width;
1122       scroll_inc = scroll_dest - screen_right;
1123     }
1124
1125   if (scroll_inc != 0)
1126     {
1127       set_adjustment_clamped (get_hadjustment (text_view),
1128                               current_x_scroll + scroll_inc);
1129       retval = TRUE;
1130     }
1131
1132   return retval;
1133 }
1134
1135 /**
1136  * gtk_text_view_scroll_to_mark:
1137  * @text_view: a #GtkTextView
1138  * @mark: a #GtkTextMark
1139  * @within_margin: margin as a [0.0,0.5) fraction of screen size
1140  * @use_align: whether to use alignment arguments (if %FALSE, just get the mark onscreen)
1141  * @xalign: horizontal alignment of mark within visible area.
1142  * @yalign: vertical alignment of mark within visible area
1143  *
1144  * Scrolls @text_view so that @mark is on the screen in the position
1145  * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1146  * left or top, 1.0 indicates right or bottom, 0.5 means center. If @use_align
1147  * is %FALSE, the text scrolls the minimal distance to get the mark onscreen,
1148  * possibly not scrolling at all. The effective screen for purposes
1149  * of this function is reduced by a margin of size @within_margin.
1150  *
1151  * Return value: %TRUE if scrolling occurred
1152  **/
1153 gboolean
1154 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
1155                               GtkTextMark *mark,
1156                               gdouble      within_margin,
1157                               gboolean     use_align,
1158                               gdouble      xalign,
1159                               gdouble      yalign)
1160 {
1161   GtkTextIter iter;
1162   GdkRectangle rect;
1163   GdkRectangle screen;
1164   gint screen_bottom;
1165   gint screen_right;
1166   gint scroll_dest;
1167   GtkWidget *widget;
1168   gboolean retval = FALSE;
1169   gint scroll_inc;
1170   gint screen_xoffset, screen_yoffset;
1171   gint current_x_scroll, current_y_scroll;
1172
1173   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1174   g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
1175   g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE);
1176   g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE);
1177   g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE);
1178   
1179   widget = GTK_WIDGET (text_view);
1180
1181   if (!GTK_WIDGET_MAPPED (widget))
1182     {
1183       g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
1184       return FALSE;
1185     }
1186
1187   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1188
1189   gtk_text_layout_get_iter_location (text_view->layout,
1190                                      &iter,
1191                                      &rect);
1192
1193   /* Be sure the scroll region is up-to-date */
1194   gtk_text_view_scroll_calc_now (text_view);
1195
1196   current_x_scroll = text_view->xoffset;
1197   current_y_scroll = text_view->yoffset;
1198
1199   screen.x = current_x_scroll;
1200   screen.y = current_y_scroll;
1201   screen.width = SCREEN_WIDTH (widget);
1202   screen.height = SCREEN_HEIGHT (widget);
1203   
1204   screen_xoffset = screen.width * within_margin;
1205   screen_yoffset = screen.height * within_margin;
1206   
1207   screen.x += screen_xoffset;
1208   screen.y += screen_yoffset;
1209   screen.width -= screen_xoffset * 2;
1210   screen.height -= screen_yoffset * 2;
1211
1212   /* paranoia check */
1213   if (screen.width < 1)
1214     screen.width = 1;
1215   if (screen.height < 1)
1216     screen.height = 1;
1217   
1218   screen_right = screen.x + screen.width;
1219   screen_bottom = screen.y + screen.height;
1220   
1221   /* The alignment affects the point in the target character that we
1222    * choose to align. If we're doing right/bottom alignment, we align
1223    * the right/bottom edge of the character the mark is at; if we're
1224    * doing left/top we align the left/top edge of the character; if
1225    * we're doing center alignment we align the center of the
1226    * character.
1227    */
1228   
1229   /* Vertical scroll */
1230
1231   scroll_inc = 0;
1232   scroll_dest = current_y_scroll;
1233   
1234   if (use_align)
1235     {      
1236       scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
1237       
1238       /* if scroll_dest < screen.y, we move a negative increment (up),
1239        * else a positive increment (down)
1240        */
1241       scroll_inc = scroll_dest - screen.y + screen_yoffset;
1242     }
1243   else
1244     {
1245       /* move minimum to get onscreen */
1246       if (rect.y < screen.y)
1247         {
1248           scroll_dest = rect.y;
1249           scroll_inc = scroll_dest - screen.y - screen_yoffset;
1250         }
1251       else if ((rect.y + rect.height) > screen_bottom)
1252         {
1253           scroll_dest = rect.y + rect.height;
1254           scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
1255         }
1256     }  
1257   
1258   if (scroll_inc != 0)
1259     {
1260       set_adjustment_clamped (get_vadjustment (text_view),
1261                               current_y_scroll + scroll_inc);
1262       retval = TRUE;
1263     }
1264
1265   /* Horizontal scroll */
1266   
1267   scroll_inc = 0;
1268   scroll_dest = current_x_scroll;
1269   
1270   if (use_align)
1271     {      
1272       scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
1273
1274       /* if scroll_dest < screen.y, we move a negative increment (left),
1275        * else a positive increment (right)
1276        */
1277       scroll_inc = scroll_dest - screen.x + screen_xoffset;
1278     }
1279   else
1280     {
1281       /* move minimum to get onscreen */
1282       if (rect.x < screen.x)
1283         {
1284           scroll_dest = rect.x;
1285           scroll_inc = scroll_dest - screen.x - screen_xoffset;
1286         }
1287       else if ((rect.x + rect.width) > screen_right)
1288         {
1289           scroll_dest = rect.x + rect.width;
1290           scroll_inc = scroll_dest - screen_right + screen_xoffset;
1291         }
1292     }
1293   
1294   if (scroll_inc != 0)
1295     {
1296       set_adjustment_clamped (get_hadjustment (text_view),
1297                               current_x_scroll + scroll_inc);
1298       retval = TRUE;
1299     }
1300
1301   return retval;
1302 }
1303
1304 gboolean
1305 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
1306                                     GtkTextMark *mark)
1307 {
1308   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1309   g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
1310
1311   return gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
1312 }
1313
1314 static gboolean
1315 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
1316 {
1317   GdkRectangle visible_rect;
1318   gtk_text_view_get_visible_rect (text_view, &visible_rect);
1319
1320   return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
1321                                                visible_rect.y,
1322                                                visible_rect.y + visible_rect.height);
1323 }
1324
1325 /**
1326  * gtk_text_view_move_mark_onscreen:
1327  * @text_view: a #GtkTextView
1328  * @mark: a #GtkTextMark
1329  *
1330  * Moves a mark within the buffer so that it's
1331  * located within the currently-visible text area.
1332  *
1333  * Return value: %TRUE if the mark moved (wasn't already onscreen)
1334  **/
1335 gboolean
1336 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
1337                                   GtkTextMark *mark)
1338 {
1339   GtkTextIter iter;
1340
1341   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1342   g_return_val_if_fail (mark != NULL, FALSE);
1343
1344   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1345
1346   if (clamp_iter_onscreen (text_view, &iter))
1347     {
1348       gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
1349       return TRUE;
1350     }
1351   else
1352     return FALSE;
1353 }
1354
1355 /**
1356  * gtk_text_view_get_visible_rect:
1357  * @text_view: a #GtkTextView
1358  * @visible_rect: rectangle to fill
1359  *
1360  * Fills @visible_rect with the currently-visible
1361  * region of the buffer, in buffer coordinates. Convert to window coordinates
1362  * with gtk_text_view_buffer_to_window_coords().
1363  **/
1364 void
1365 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
1366                                 GdkRectangle *visible_rect)
1367 {
1368   GtkWidget *widget;
1369
1370   g_return_if_fail (text_view != NULL);
1371   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1372
1373   widget = GTK_WIDGET (text_view);
1374
1375   if (visible_rect)
1376     {
1377       visible_rect->x = text_view->xoffset;
1378       visible_rect->y = text_view->yoffset;
1379       visible_rect->width = SCREEN_WIDTH (widget);
1380       visible_rect->height = SCREEN_HEIGHT (widget);
1381     }
1382 }
1383
1384 /**
1385  * gtk_text_view_set_wrap_mode:
1386  * @text_view: a #GtkTextView
1387  * @wrap_mode: a #GtkWrapMode
1388  *
1389  * Sets the line wrapping for the view.
1390  **/
1391 void
1392 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
1393                              GtkWrapMode  wrap_mode)
1394 {
1395   g_return_if_fail (text_view != NULL);
1396   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1397
1398   if (text_view->wrap_mode != wrap_mode)
1399     {
1400       text_view->wrap_mode = wrap_mode;
1401
1402       if (text_view->layout)
1403         {
1404           text_view->layout->default_style->wrap_mode = wrap_mode;
1405           gtk_text_layout_default_style_changed (text_view->layout);
1406         }
1407     }
1408 }
1409
1410 /**
1411  * gtk_text_view_get_wrap_mode:
1412  * @text_view: a #GtkTextView
1413  *
1414  * Gets the line wrapping for the view.
1415  *
1416  * Return value: the line wrap setting
1417  **/
1418 GtkWrapMode
1419 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
1420 {
1421   g_return_val_if_fail (text_view != NULL, GTK_WRAPMODE_NONE);
1422   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAPMODE_NONE);
1423
1424   return text_view->wrap_mode;
1425 }
1426
1427 /**
1428  * gtk_text_view_set_editable:
1429  * @text_view: a #GtkTextView
1430  * @setting: whether it's editable
1431  *
1432  * Sets the default editability of the #GtkTextView. You can override
1433  * this default setting with tags in the buffer, using the "editable"
1434  * attribute of tags.
1435  **/
1436 void
1437 gtk_text_view_set_editable (GtkTextView *text_view,
1438                             gboolean     setting)
1439 {
1440   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1441
1442   if (text_view->editable != setting)
1443     {
1444       text_view->editable = setting;
1445
1446       if (text_view->layout)
1447         {
1448           text_view->layout->default_style->editable = text_view->editable;
1449           gtk_text_layout_default_style_changed (text_view->layout);
1450         }
1451     }
1452 }
1453
1454 /**
1455  * gtk_text_view_get_editable:
1456  * @text_view: a #GtkTextView
1457  *
1458  * Returns the default editability of the #GtkTextView. Tags in the
1459  * buffer may override this setting for some ranges of text.
1460  *
1461  * Return value: whether text is editable by default
1462  **/
1463 gboolean
1464 gtk_text_view_get_editable (GtkTextView *text_view)
1465 {
1466   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1467
1468   return text_view->editable;
1469 }
1470
1471 void
1472 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
1473                                       gint         pixels_above_lines)
1474 {
1475   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1476
1477   if (text_view->pixels_above_lines != pixels_above_lines)
1478     {
1479       text_view->pixels_above_lines = pixels_above_lines;
1480
1481       if (text_view->layout)
1482         {
1483           text_view->layout->default_style->pixels_above_lines = pixels_above_lines;
1484           gtk_text_layout_default_style_changed (text_view->layout);
1485         }
1486     }
1487 }
1488
1489 gint
1490 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
1491 {
1492   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1493
1494   return text_view->pixels_above_lines;
1495 }
1496
1497 void
1498 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
1499                                       gint         pixels_below_lines)
1500 {
1501   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1502
1503   if (text_view->pixels_below_lines != pixels_below_lines)
1504     {
1505       text_view->pixels_below_lines = pixels_below_lines;
1506
1507       if (text_view->layout)
1508         {
1509           text_view->layout->default_style->pixels_below_lines = pixels_below_lines;
1510           gtk_text_layout_default_style_changed (text_view->layout);
1511         }
1512     }
1513 }
1514
1515 gint
1516 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
1517 {
1518   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1519
1520   return text_view->pixels_below_lines;
1521 }
1522
1523 void
1524 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
1525                                       gint         pixels_inside_wrap)
1526 {
1527   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1528
1529   if (text_view->pixels_inside_wrap != pixels_inside_wrap)
1530     {
1531       text_view->pixels_inside_wrap = pixels_inside_wrap;
1532
1533       if (text_view->layout)
1534         {
1535           text_view->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
1536           gtk_text_layout_default_style_changed (text_view->layout);
1537         }
1538     }
1539 }
1540
1541 gint
1542 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
1543 {
1544   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1545
1546   return text_view->pixels_inside_wrap;
1547 }
1548
1549 void
1550 gtk_text_view_set_justification (GtkTextView     *text_view,
1551                                  GtkJustification justify)
1552 {
1553   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1554
1555   if (text_view->justify != justify)
1556     {
1557       text_view->justify = justify;
1558
1559       if (text_view->layout)
1560         {
1561           text_view->layout->default_style->justify = justify;
1562           gtk_text_layout_default_style_changed (text_view->layout);
1563         }
1564     }
1565 }
1566
1567 GtkJustification
1568 gtk_text_view_get_justification (GtkTextView *text_view)
1569 {
1570   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
1571
1572   return text_view->justify;
1573 }
1574
1575 void
1576 gtk_text_view_set_left_margin (GtkTextView *text_view,
1577                                gint         left_margin)
1578 {
1579   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1580
1581   if (text_view->left_margin != left_margin)
1582     {
1583       text_view->left_margin = left_margin;
1584
1585       if (text_view->layout)
1586         {
1587           text_view->layout->default_style->left_margin = left_margin;
1588           gtk_text_layout_default_style_changed (text_view->layout);
1589         }
1590     }
1591 }
1592
1593 gint
1594 gtk_text_view_get_left_margin (GtkTextView *text_view)
1595 {
1596   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1597
1598   return text_view->left_margin;
1599 }
1600
1601 void
1602 gtk_text_view_set_right_margin (GtkTextView *text_view,
1603                                 gint         right_margin)
1604 {
1605   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1606
1607   if (text_view->right_margin != right_margin)
1608     {
1609       text_view->right_margin = right_margin;
1610
1611       if (text_view->layout)
1612         {
1613           text_view->layout->default_style->right_margin = right_margin;
1614           gtk_text_layout_default_style_changed (text_view->layout);
1615         }
1616     }
1617 }
1618
1619 gint
1620 gtk_text_view_get_right_margin (GtkTextView *text_view)
1621 {
1622   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1623
1624   return text_view->right_margin;
1625 }
1626
1627 void
1628 gtk_text_view_set_indent (GtkTextView *text_view,
1629                           gint         indent)
1630 {
1631   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1632
1633   if (text_view->indent != indent)
1634     {
1635       text_view->indent = indent;
1636
1637       if (text_view->layout)
1638         {
1639           text_view->layout->default_style->indent = indent;
1640           gtk_text_layout_default_style_changed (text_view->layout);
1641         }
1642     }
1643 }
1644
1645 gint
1646 gtk_text_view_get_indent (GtkTextView *text_view)
1647 {
1648   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
1649
1650   return text_view->indent;
1651 }
1652
1653 void
1654 gtk_text_view_set_tabs (GtkTextView   *text_view,
1655                         PangoTabArray *tabs)
1656 {
1657   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1658
1659   if (text_view->tabs)
1660     pango_tab_array_free (text_view->tabs);
1661
1662   text_view->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
1663
1664   if (text_view->layout)
1665     {
1666       /* some unkosher futzing in internal struct details... */
1667       if (text_view->layout->default_style->tabs)
1668         pango_tab_array_free (text_view->layout->default_style->tabs);
1669
1670       text_view->layout->default_style->tabs =
1671         text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
1672
1673       gtk_text_layout_default_style_changed (text_view->layout);
1674     }
1675 }
1676
1677 PangoTabArray*
1678 gtk_text_view_get_tabs (GtkTextView *text_view)
1679 {
1680   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
1681
1682   return text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
1683 }
1684
1685 /**
1686  * gtk_text_view_set_cursor_visible:
1687  * @text_view: a #GtkTextView
1688  * @setting: whether to show the insertion cursor
1689  *
1690  * Toggles whether the insertion point is displayed. A buffer with no editable
1691  * text probably shouldn't have a visible cursor, so you may want to turn
1692  * the cursor off.
1693  **/
1694 void
1695 gtk_text_view_set_cursor_visible    (GtkTextView   *text_view,
1696                                      gboolean       setting)
1697 {
1698   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1699
1700   setting = (setting != FALSE);
1701
1702   if (text_view->cursor_visible != setting)
1703     {
1704       text_view->cursor_visible = setting;
1705
1706       if (GTK_WIDGET_HAS_FOCUS (text_view))
1707         {
1708           if (text_view->layout)
1709             {
1710               gtk_text_layout_set_cursor_visible (text_view->layout, setting);
1711
1712               if (setting)
1713                 gtk_text_view_start_cursor_blink (text_view, FALSE);
1714               else
1715                 gtk_text_view_stop_cursor_blink (text_view);
1716             }
1717         }
1718     }
1719 }
1720
1721 /**
1722  * gtk_text_view_get_cursor_visible:
1723  * @text_view: a #GtkTextView
1724  *
1725  * Find out whether the cursor is being displayed.
1726  *
1727  * Return value: whether the insertion mark is visible
1728  **/
1729 gboolean
1730 gtk_text_view_get_cursor_visible    (GtkTextView   *text_view)
1731 {
1732   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1733
1734   return text_view->cursor_visible;
1735 }
1736
1737
1738 /**
1739  * gtk_text_view_place_cursor_onscreen:
1740  * @text_view: a #GtkTextView
1741  *
1742  * Moves the cursor to the currently visible region of the
1743  * buffer, it it isn't there already.
1744  *
1745  * Return value: TRUE if the cursor had to be moved.
1746  **/
1747 gboolean
1748 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
1749 {
1750   GtkTextIter insert;
1751
1752   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1753
1754   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
1755                                     gtk_text_buffer_get_mark (get_buffer (text_view),
1756                                                               "insert"));
1757
1758   if (clamp_iter_onscreen (text_view, &insert))
1759     {
1760       gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
1761       return TRUE;
1762     }
1763   else
1764     return FALSE;
1765 }
1766
1767 static void
1768 gtk_text_view_destroy (GtkObject *object)
1769 {
1770   GtkTextView *text_view;
1771   GtkTextLayout *layout;
1772   
1773   text_view = GTK_TEXT_VIEW (object);
1774
1775   layout = text_view->layout;
1776   
1777   gtk_text_view_destroy_layout (text_view);
1778   gtk_text_view_set_buffer (text_view, NULL);
1779
1780   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1781 }
1782
1783 static void
1784 gtk_text_view_finalize (GObject *object)
1785 {
1786   GtkTextView *text_view;
1787
1788   text_view = GTK_TEXT_VIEW (object);
1789
1790   g_return_if_fail (text_view->buffer == NULL);
1791
1792   if (text_view->hadjustment)
1793     g_object_unref (G_OBJECT (text_view->hadjustment));
1794   if (text_view->vadjustment)
1795     g_object_unref (G_OBJECT (text_view->vadjustment));
1796
1797   text_window_free (text_view->text_window);
1798
1799   if (text_view->left_window)
1800     text_window_free (text_view->left_window);
1801
1802   if (text_view->top_window)
1803     text_window_free (text_view->top_window);
1804
1805   if (text_view->right_window)
1806     text_window_free (text_view->right_window);
1807
1808   if (text_view->bottom_window)
1809     text_window_free (text_view->bottom_window);
1810
1811   g_object_unref (G_OBJECT (text_view->im_context));
1812
1813   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1814 }
1815
1816 static void
1817 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1818 {
1819   GtkTextView *text_view;
1820
1821   text_view = GTK_TEXT_VIEW (object);
1822
1823   switch (arg_id)
1824     {
1825     case ARG_HEIGHT_LINES:
1826       g_warning ("FIXME");
1827       break;
1828
1829     case ARG_WIDTH_COLUMNS:
1830       g_warning ("FIXME");
1831       break;
1832
1833     case ARG_PIXELS_ABOVE_LINES:
1834       gtk_text_view_set_pixels_above_lines (text_view, GTK_VALUE_INT (*arg));
1835       break;
1836
1837     case ARG_PIXELS_BELOW_LINES:
1838       gtk_text_view_set_pixels_below_lines (text_view, GTK_VALUE_INT (*arg));
1839       break;
1840
1841     case ARG_PIXELS_INSIDE_WRAP:
1842       gtk_text_view_set_pixels_inside_wrap (text_view, GTK_VALUE_INT (*arg));
1843       break;
1844
1845     case ARG_EDITABLE:
1846       gtk_text_view_set_editable (text_view, GTK_VALUE_BOOL (*arg));
1847       break;
1848
1849     case ARG_WRAP_MODE:
1850       gtk_text_view_set_wrap_mode (text_view, GTK_VALUE_ENUM (*arg));
1851       break;
1852
1853     case ARG_JUSTIFY:
1854       gtk_text_view_set_justification (text_view, GTK_VALUE_ENUM (*arg));
1855       break;
1856
1857     case ARG_LEFT_MARGIN:
1858       gtk_text_view_set_left_margin (text_view, GTK_VALUE_INT (*arg));
1859       break;
1860
1861     case ARG_RIGHT_MARGIN:
1862       gtk_text_view_set_right_margin (text_view, GTK_VALUE_INT (*arg));
1863       break;
1864
1865     case ARG_INDENT:
1866       gtk_text_view_set_indent (text_view, GTK_VALUE_INT (*arg));
1867       break;
1868
1869     case ARG_TABS:
1870       gtk_text_view_set_tabs (text_view, GTK_VALUE_POINTER (*arg));
1871       break;
1872
1873     default:
1874       g_assert_not_reached ();
1875       break;
1876     }
1877 }
1878
1879 static void
1880 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1881 {
1882   GtkTextView *text_view;
1883
1884   text_view = GTK_TEXT_VIEW (object);
1885
1886   switch (arg_id)
1887     {
1888     case ARG_HEIGHT_LINES:
1889       g_warning ("FIXME");
1890       break;
1891
1892     case ARG_WIDTH_COLUMNS:
1893       g_warning ("FIXME");
1894       break;
1895
1896     case ARG_PIXELS_ABOVE_LINES:
1897       GTK_VALUE_INT (*arg) = text_view->pixels_above_lines;
1898       break;
1899
1900     case ARG_PIXELS_BELOW_LINES:
1901       GTK_VALUE_INT (*arg) = text_view->pixels_below_lines;
1902       break;
1903
1904     case ARG_PIXELS_INSIDE_WRAP:
1905       GTK_VALUE_INT (*arg) = text_view->pixels_inside_wrap;
1906       break;
1907
1908     case ARG_EDITABLE:
1909       GTK_VALUE_BOOL (*arg) = text_view->editable;
1910       break;
1911
1912     case ARG_WRAP_MODE:
1913       GTK_VALUE_ENUM (*arg) = text_view->wrap_mode;
1914       break;
1915
1916     case ARG_JUSTIFY:
1917       GTK_VALUE_ENUM (*arg) = text_view->justify;
1918       break;
1919
1920     case ARG_LEFT_MARGIN:
1921       GTK_VALUE_INT (*arg) = text_view->left_margin;
1922       break;
1923
1924     case ARG_RIGHT_MARGIN:
1925       GTK_VALUE_INT (*arg) = text_view->right_margin;
1926       break;
1927
1928     case ARG_INDENT:
1929       GTK_VALUE_INT (*arg) = text_view->indent;
1930       break;
1931
1932     case ARG_TABS:
1933       GTK_VALUE_POINTER (*arg) = gtk_text_view_get_tabs (text_view);
1934       break;
1935
1936     default:
1937       arg->type = GTK_TYPE_INVALID;
1938       break;
1939     }
1940 }
1941
1942 static void
1943 gtk_text_view_size_request (GtkWidget      *widget,
1944                             GtkRequisition *requisition)
1945 {
1946   GtkTextView *text_view;
1947   GSList *tmp_list;
1948
1949   text_view = GTK_TEXT_VIEW (widget);
1950
1951   requisition->width = text_view->text_window->requisition.width + FOCUS_EDGE_WIDTH * 2;
1952   requisition->height = text_view->text_window->requisition.height + FOCUS_EDGE_WIDTH * 2;
1953
1954   if (text_view->left_window)
1955     requisition->width += text_view->left_window->requisition.width;
1956
1957   if (text_view->right_window)
1958     requisition->width += text_view->right_window->requisition.width;
1959
1960   if (text_view->top_window)
1961     requisition->height += text_view->top_window->requisition.height;
1962
1963   if (text_view->bottom_window)
1964     requisition->height += text_view->bottom_window->requisition.height;
1965
1966   tmp_list = text_view->children;
1967   while (tmp_list != NULL)
1968     {
1969       GtkTextViewChild *child = tmp_list->data;
1970
1971       if (child->anchor)
1972         {
1973           GtkRequisition child_req;
1974           GtkRequisition old_req;
1975
1976           old_req = child->widget->requisition;
1977
1978           gtk_widget_size_request (child->widget, &child_req);
1979
1980           if (text_view->layout &&
1981               (old_req.width != child_req.width ||
1982                old_req.height != child_req.height))
1983             gtk_text_child_anchor_queue_resize (child->anchor,
1984                                                 text_view->layout);
1985         }
1986       else
1987         {
1988
1989         }
1990
1991       tmp_list = g_slist_next (tmp_list);
1992     }
1993 }
1994
1995 static void
1996 gtk_text_view_update_child_allocation (GtkTextView      *text_view,
1997                                        GtkTextViewChild *vc)
1998 {
1999   gint buffer_y;
2000   GtkTextIter iter;
2001   GtkAllocation allocation;
2002   
2003   gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2004                                             &iter,
2005                                             vc->anchor);
2006
2007   gtk_text_layout_get_line_yrange (text_view->layout, &iter,
2008                                    &buffer_y, NULL);
2009
2010   buffer_y += vc->from_top_of_line;
2011
2012   allocation.x = vc->from_left_of_buffer;
2013   allocation.y = buffer_y;
2014   allocation.width = vc->widget->requisition.width;
2015   allocation.height = vc->widget->requisition.height;
2016   
2017   gtk_widget_size_allocate (vc->widget, &allocation);
2018 }
2019
2020 static void
2021 gtk_text_view_child_allocated (GtkTextLayout *layout,
2022                                GtkWidget     *child,
2023                                gint           x,
2024                                gint           y,
2025                                gpointer       data)
2026 {
2027   GtkTextViewChild *vc = NULL;
2028   GtkTextView *text_view = data;
2029   
2030   /* x,y is the position of the child from the top of the line, and
2031    * from the left of the buffer. We have to translate that into text
2032    * window coordinates, then size_allocate the child.
2033    */
2034
2035   vc = g_object_get_data (G_OBJECT (child),
2036                             "gtk-text-view-child");
2037
2038   g_assert (vc != NULL);
2039
2040   g_print ("child allocated at %d,%d\n", x, y);
2041   
2042   vc->from_left_of_buffer = x;
2043   vc->from_top_of_line = y;
2044
2045   gtk_text_view_update_child_allocation (text_view, vc);
2046 }
2047
2048 static void
2049 gtk_text_view_validate_children (GtkTextView *text_view)
2050 {
2051   GSList *tmp_list;
2052
2053   tmp_list = text_view->children;
2054   while (tmp_list != NULL)
2055     {
2056       GtkTextViewChild *child = tmp_list->data;
2057
2058       if (child->anchor)
2059         {
2060           /* We need to force-validate the regions containing
2061            * children.
2062            */
2063           GtkTextIter child_loc;
2064           gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
2065                                                     &child_loc,
2066                                                     child->anchor);
2067
2068           gtk_text_layout_validate_yrange (text_view->layout,
2069                                            &child_loc,
2070                                            0, 1);
2071         }
2072       else
2073         {
2074
2075         }
2076
2077       tmp_list = g_slist_next (tmp_list);
2078     }
2079 }
2080
2081 static void
2082 gtk_text_view_size_allocate (GtkWidget *widget,
2083                              GtkAllocation *allocation)
2084 {
2085   GtkTextView *text_view;
2086   GtkTextIter first_para;
2087   gint y;
2088   GtkAdjustment *vadj;
2089   gboolean yoffset_changed = FALSE;
2090   gint width, height;
2091   GdkRectangle text_rect;
2092   GdkRectangle left_rect;
2093   GdkRectangle right_rect;
2094   GdkRectangle top_rect;
2095   GdkRectangle bottom_rect;
2096
2097   text_view = GTK_TEXT_VIEW (widget);
2098
2099   widget->allocation = *allocation;
2100
2101   if (GTK_WIDGET_REALIZED (widget))
2102     {
2103       gdk_window_move_resize (widget->window,
2104                               allocation->x, allocation->y,
2105                               allocation->width, allocation->height);
2106     }
2107
2108   /* distribute width/height among child windows. Ensure all
2109    * windows get at least a 1x1 allocation.
2110    */
2111
2112   width = allocation->width - FOCUS_EDGE_WIDTH * 2;
2113
2114   if (text_view->left_window)
2115     left_rect.width = text_view->left_window->requisition.width;
2116   else
2117     left_rect.width = 1;
2118
2119   width -= left_rect.width;
2120
2121   if (text_view->right_window)
2122     right_rect.width = text_view->right_window->requisition.width;
2123   else
2124     right_rect.width = 1;
2125
2126   width -= right_rect.width;
2127
2128   text_rect.width = MAX (1, width);
2129
2130   top_rect.width = text_rect.width;
2131   bottom_rect.width = text_rect.width;
2132
2133
2134   height = allocation->height - FOCUS_EDGE_WIDTH * 2;
2135
2136   if (text_view->top_window)
2137     top_rect.height = text_view->top_window->requisition.height;
2138   else
2139     top_rect.height = 1;
2140
2141   height -= top_rect.height;
2142
2143   if (text_view->bottom_window)
2144     bottom_rect.height = text_view->bottom_window->requisition.height;
2145   else
2146     bottom_rect.height = 1;
2147
2148   height -= bottom_rect.height;
2149
2150   text_rect.height = MAX (1, height);
2151
2152   left_rect.height = text_rect.height;
2153   right_rect.height = text_rect.height;
2154
2155   /* Origins */
2156   left_rect.x = FOCUS_EDGE_WIDTH;
2157   top_rect.y = FOCUS_EDGE_WIDTH;
2158
2159   text_rect.x = left_rect.x + left_rect.width;
2160   text_rect.y = top_rect.y + top_rect.height;
2161
2162   left_rect.y = text_rect.y;
2163   right_rect.y = text_rect.y;
2164
2165   top_rect.x = text_rect.x;
2166   bottom_rect.x = text_rect.x;
2167
2168   right_rect.x = text_rect.x + text_rect.width;
2169   bottom_rect.y = text_rect.y + text_rect.height;
2170
2171   text_window_size_allocate (text_view->text_window,
2172                              &text_rect);
2173
2174   if (text_view->left_window)
2175     text_window_size_allocate (text_view->left_window,
2176                                &left_rect);
2177
2178   if (text_view->right_window)
2179     text_window_size_allocate (text_view->right_window,
2180                                &right_rect);
2181
2182   if (text_view->top_window)
2183     text_window_size_allocate (text_view->top_window,
2184                                &top_rect);
2185
2186   if (text_view->bottom_window)
2187     text_window_size_allocate (text_view->bottom_window,
2188                                &bottom_rect);
2189
2190   gtk_text_view_ensure_layout (text_view);
2191   gtk_text_layout_set_screen_width (text_view->layout,
2192                                     SCREEN_WIDTH (text_view));
2193
2194   gtk_text_view_validate_children (text_view);
2195
2196   gtk_text_view_validate_onscreen (text_view);
2197   gtk_text_view_scroll_calc_now (text_view);
2198
2199   /* Now adjust the value of the adjustment to keep the cursor at the
2200    * same place in the buffer
2201    */
2202   gtk_text_view_get_first_para_iter (text_view, &first_para);
2203   gtk_text_layout_get_line_yrange (text_view->layout, &first_para, &y, NULL);
2204
2205   y += text_view->first_para_pixels;
2206
2207   /* Ensure h/v adj exist */
2208   get_hadjustment (text_view);
2209   get_vadjustment (text_view);
2210
2211   vadj = text_view->vadjustment;
2212   if (y > vadj->upper - vadj->page_size)
2213     y = MAX (0, vadj->upper - vadj->page_size);
2214
2215   if (y != text_view->yoffset)
2216     {
2217       vadj->value = text_view->yoffset = y;
2218       yoffset_changed = TRUE;
2219     }
2220
2221   text_view->hadjustment->page_size = SCREEN_WIDTH (text_view);
2222   text_view->hadjustment->page_increment = SCREEN_WIDTH (text_view) / 2;
2223   text_view->hadjustment->lower = 0;
2224   text_view->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
2225                                        text_view->width);
2226   gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
2227
2228   text_view->vadjustment->page_size = SCREEN_HEIGHT (text_view);
2229   text_view->vadjustment->page_increment = SCREEN_HEIGHT (text_view) / 2;
2230   text_view->vadjustment->lower = 0;
2231   text_view->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
2232                                        text_view->height);
2233   gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
2234
2235   if (yoffset_changed)
2236     gtk_adjustment_value_changed (vadj);
2237 }
2238
2239 static void
2240 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
2241                                    GtkTextIter *iter)
2242 {
2243   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
2244                                     text_view->first_para_mark);
2245 }
2246
2247 static void
2248 gtk_text_view_validate_onscreen (GtkTextView *text_view)
2249 {
2250   GtkWidget *widget = GTK_WIDGET (text_view);
2251
2252   if (SCREEN_HEIGHT (widget) > 0)
2253     {
2254       GtkTextIter first_para;
2255       gtk_text_view_get_first_para_iter (text_view, &first_para);
2256
2257       gtk_text_layout_validate_yrange (text_view->layout,
2258                                        &first_para,
2259                                        0,
2260                                        text_view->first_para_pixels +
2261                                        SCREEN_HEIGHT (widget));
2262     }
2263 }
2264
2265 static gboolean
2266 first_validate_callback (gpointer data)
2267 {
2268   GtkTextView *text_view = data;
2269
2270   gtk_text_view_validate_onscreen (text_view);
2271
2272   text_view->first_validate_idle = 0;
2273   return FALSE;
2274 }
2275
2276 static gboolean
2277 incremental_validate_callback (gpointer data)
2278 {
2279   GtkTextView *text_view = data;
2280
2281   gtk_text_layout_validate (text_view->layout, 2000);
2282   if (gtk_text_layout_is_valid (text_view->layout))
2283     {
2284       text_view->incremental_validate_idle = 0;
2285       return FALSE;
2286     }
2287   else
2288     return TRUE;
2289 }
2290
2291 static void
2292 invalidated_handler (GtkTextLayout *layout,
2293                      gpointer       data)
2294 {
2295   GtkTextView *text_view;
2296
2297   text_view = GTK_TEXT_VIEW (data);
2298
2299   if (!text_view->first_validate_idle)
2300     text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
2301
2302   if (!text_view->incremental_validate_idle)
2303     text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
2304 }
2305
2306 static void
2307 changed_handler (GtkTextLayout *layout,
2308                  gint           start_y,
2309                  gint           old_height,
2310                  gint           new_height,
2311                  gpointer       data)
2312 {
2313   GtkTextView *text_view;
2314   GtkWidget *widget;
2315   GdkRectangle visible_rect;
2316   GdkRectangle redraw_rect;
2317
2318   text_view = GTK_TEXT_VIEW (data);
2319   widget = GTK_WIDGET (data);
2320
2321   if (GTK_WIDGET_REALIZED (text_view))
2322     {      
2323       gtk_text_view_get_visible_rect (text_view, &visible_rect);
2324
2325       redraw_rect.x = visible_rect.x;
2326       redraw_rect.width = visible_rect.width;
2327       redraw_rect.y = start_y;
2328
2329       if (old_height == new_height)
2330         redraw_rect.height = old_height;
2331       else
2332         redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
2333
2334       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
2335         {
2336           /* text_window_invalidate_rect() takes buffer coordinates */
2337           text_window_invalidate_rect (text_view->text_window,
2338                                        &redraw_rect);
2339
2340           if (text_view->left_window)
2341             text_window_invalidate_rect (text_view->left_window,
2342                                          &redraw_rect);
2343           if (text_view->right_window)
2344             text_window_invalidate_rect (text_view->right_window,
2345                                          &redraw_rect);
2346           if (text_view->top_window)
2347             text_window_invalidate_rect (text_view->top_window,
2348                                          &redraw_rect);
2349           if (text_view->bottom_window)
2350             text_window_invalidate_rect (text_view->bottom_window,
2351                                          &redraw_rect);
2352         }
2353     }
2354
2355   if (old_height != new_height)
2356     {
2357       gboolean yoffset_changed = FALSE;
2358       GSList *tmp_list;
2359       
2360       if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
2361         {
2362           text_view->yoffset += new_height - old_height;
2363           get_vadjustment (text_view)->value = text_view->yoffset;
2364           yoffset_changed = TRUE;
2365         }
2366
2367       if (yoffset_changed)
2368         gtk_adjustment_value_changed (get_vadjustment (text_view));
2369
2370       /* FIXME be smarter about which anchored widgets we update */
2371
2372       tmp_list = text_view->children;
2373       while (tmp_list != NULL)
2374         {
2375           GtkTextViewChild *child = tmp_list->data;
2376
2377           if (child->anchor)
2378             gtk_text_view_update_child_allocation (text_view, child);
2379
2380           tmp_list = g_slist_next (tmp_list);
2381         }
2382     }
2383   
2384   gtk_text_view_scroll_calc_now (text_view);
2385 }
2386
2387 static void
2388 gtk_text_view_realize (GtkWidget *widget)
2389 {
2390   GtkTextView *text_view;
2391   GdkWindowAttr attributes;
2392   gint attributes_mask;
2393   GSList *tmp_list;
2394   
2395   text_view = GTK_TEXT_VIEW (widget);
2396   GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
2397
2398   attributes.window_type = GDK_WINDOW_CHILD;
2399   attributes.x = widget->allocation.x;
2400   attributes.y = widget->allocation.y;
2401   attributes.width = widget->allocation.width;
2402   attributes.height = widget->allocation.height;
2403   attributes.wclass = GDK_INPUT_OUTPUT;
2404   attributes.visual = gtk_widget_get_visual (widget);
2405   attributes.colormap = gtk_widget_get_colormap (widget);
2406   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
2407
2408   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2409
2410   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
2411                                    &attributes, attributes_mask);
2412   gdk_window_set_user_data (widget->window, widget);
2413
2414   /* must come before text_window_realize calls */
2415   widget->style = gtk_style_attach (widget->style, widget->window);
2416
2417   gdk_window_set_background (widget->window,
2418                              &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2419
2420   text_window_realize (text_view->text_window, widget->window);
2421
2422   if (text_view->left_window)
2423     text_window_realize (text_view->left_window,
2424                          widget->window);
2425
2426   if (text_view->top_window)
2427     text_window_realize (text_view->top_window,
2428                          widget->window);
2429
2430   if (text_view->right_window)
2431     text_window_realize (text_view->right_window,
2432                          widget->window);
2433
2434   if (text_view->bottom_window)
2435     text_window_realize (text_view->bottom_window,
2436                          widget->window);
2437
2438   gtk_text_view_ensure_layout (text_view);
2439 }
2440
2441 static void
2442 gtk_text_view_unrealize (GtkWidget *widget)
2443 {
2444   GtkTextView *text_view;
2445   GSList *tmp_list;
2446   
2447   text_view = GTK_TEXT_VIEW (widget);
2448
2449   if (text_view->first_validate_idle)
2450     {
2451       g_source_remove (text_view->first_validate_idle);
2452       text_view->first_validate_idle = 0;
2453     }
2454
2455   if (text_view->incremental_validate_idle)
2456     {
2457       g_source_remove (text_view->incremental_validate_idle);
2458       text_view->incremental_validate_idle = 0;
2459     }
2460
2461   if (text_view->popup_menu)
2462     {
2463       gtk_widget_destroy (text_view->popup_menu);
2464       text_view->popup_menu = NULL;
2465     }
2466
2467   text_window_unrealize (text_view->text_window);
2468
2469   if (text_view->left_window)
2470     text_window_unrealize (text_view->left_window);
2471
2472   if (text_view->top_window)
2473     text_window_unrealize (text_view->top_window);
2474
2475   if (text_view->right_window)
2476     text_window_unrealize (text_view->right_window);
2477
2478   if (text_view->bottom_window)
2479     text_window_unrealize (text_view->bottom_window);
2480
2481   gtk_text_view_destroy_layout (text_view);
2482   
2483   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2484 }
2485
2486 static void
2487 gtk_text_view_style_set (GtkWidget *widget,
2488                          GtkStyle  *previous_style)
2489 {
2490   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2491
2492   if (GTK_WIDGET_REALIZED (widget))
2493     {
2494       gdk_window_set_background (widget->window,
2495                                  &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2496
2497       gdk_window_set_background (text_view->text_window->bin_window,
2498                                  &widget->style->base[GTK_WIDGET_STATE (widget)]);
2499
2500       if (text_view->left_window)
2501         gdk_window_set_background (text_view->left_window->bin_window,
2502                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2503       if (text_view->right_window)
2504         gdk_window_set_background (text_view->right_window->bin_window,
2505                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2506
2507       if (text_view->top_window)
2508         gdk_window_set_background (text_view->top_window->bin_window,
2509                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2510
2511       if (text_view->bottom_window)
2512         gdk_window_set_background (text_view->bottom_window->bin_window,
2513                                    &widget->style->bg[GTK_WIDGET_STATE (widget)]);
2514
2515       gtk_text_view_set_attributes_from_style (text_view,
2516                                                text_view->layout->default_style,
2517                                                widget->style);
2518       gtk_text_layout_default_style_changed (text_view->layout);
2519     }
2520 }
2521
2522 static void
2523 gtk_text_view_direction_changed (GtkWidget        *widget,
2524                                  GtkTextDirection  previous_direction)
2525 {
2526   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2527
2528   if (text_view->layout)
2529     {
2530       text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
2531       gtk_text_layout_default_style_changed (text_view->layout);
2532     }
2533 }
2534
2535 /*
2536  * Events
2537  */
2538
2539 static gboolean
2540 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
2541 {
2542   if (event)
2543     switch (event->type)
2544       {
2545       case GDK_MOTION_NOTIFY:
2546         *x = event->motion.x;
2547         *y = event->motion.y;
2548         return TRUE;
2549         break;
2550
2551       case GDK_BUTTON_PRESS:
2552       case GDK_2BUTTON_PRESS:
2553       case GDK_3BUTTON_PRESS:
2554       case GDK_BUTTON_RELEASE:
2555         *x = event->button.x;
2556         *y = event->button.y;
2557         return TRUE;
2558         break;
2559
2560       case GDK_KEY_PRESS:
2561       case GDK_KEY_RELEASE:
2562       case GDK_ENTER_NOTIFY:
2563       case GDK_LEAVE_NOTIFY:
2564       case GDK_PROPERTY_NOTIFY:
2565       case GDK_SELECTION_CLEAR:
2566       case GDK_SELECTION_REQUEST:
2567       case GDK_SELECTION_NOTIFY:
2568       case GDK_PROXIMITY_IN:
2569       case GDK_PROXIMITY_OUT:
2570       case GDK_DRAG_ENTER:
2571       case GDK_DRAG_LEAVE:
2572       case GDK_DRAG_MOTION:
2573       case GDK_DRAG_STATUS:
2574       case GDK_DROP_START:
2575       case GDK_DROP_FINISHED:
2576       default:
2577         return FALSE;
2578         break;
2579       }
2580
2581   return FALSE;
2582 }
2583
2584 static gint
2585 emit_event_on_tags (GtkWidget   *widget,
2586                     GdkEvent    *event,
2587                     GtkTextIter *iter)
2588 {
2589   GSList *tags;
2590   GSList *tmp;
2591   gint retval = FALSE;
2592   GtkTextView *text_view;
2593
2594   text_view = GTK_TEXT_VIEW (widget);
2595
2596   tags = gtk_text_iter_get_tags (iter);
2597
2598   tmp = tags;
2599   while (tmp != NULL)
2600     {
2601       GtkTextTag *tag = tmp->data;
2602
2603       if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
2604         {
2605           retval = TRUE;
2606           break;
2607         }
2608
2609       tmp = g_slist_next (tmp);
2610     }
2611
2612   g_slist_free (tags);
2613
2614   return retval;
2615 }
2616
2617 static gint
2618 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
2619 {
2620   GtkTextView *text_view;
2621   gint x = 0, y = 0;
2622
2623   text_view = GTK_TEXT_VIEW (widget);
2624
2625   if (text_view->layout == NULL ||
2626       get_buffer (text_view) == NULL)
2627     return FALSE;
2628
2629   if (event->any.window != text_view->text_window->bin_window)
2630     return FALSE;
2631
2632   if (get_event_coordinates (event, &x, &y))
2633     {
2634       GtkTextIter iter;
2635
2636       x += text_view->xoffset;
2637       y += text_view->yoffset;
2638
2639       /* FIXME this is slow and we do it twice per event.
2640          My favorite solution is to have GtkTextLayout cache
2641          the last couple lookups. */
2642       gtk_text_layout_get_iter_at_pixel (text_view->layout,
2643                                          &iter,
2644                                          x, y);
2645
2646       return emit_event_on_tags (widget, event, &iter);
2647     }
2648   else if (event->type == GDK_KEY_PRESS ||
2649            event->type == GDK_KEY_RELEASE)
2650     {
2651       GtkTextMark *insert;
2652       GtkTextIter iter;
2653
2654       insert = gtk_text_buffer_get_mark (get_buffer (text_view),
2655                                          "insert");
2656
2657       gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
2658
2659       return emit_event_on_tags (widget, event, &iter);
2660     }
2661   else
2662     return FALSE;
2663 }
2664
2665 static gint
2666 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
2667 {
2668   gint retval = FALSE;
2669   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2670
2671   if (text_view->layout == NULL ||
2672       get_buffer (text_view) == NULL)
2673     return FALSE;
2674
2675   if (gtk_im_context_filter_keypress (text_view->im_context, event))
2676     {
2677       text_view->need_im_reset = TRUE;
2678       retval = TRUE;
2679     }
2680   else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
2681            GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
2682     retval = TRUE;
2683   else if (event->keyval == GDK_Return)
2684     {
2685       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
2686                                                     text_view->editable);
2687       gtk_text_view_scroll_to_mark (text_view,
2688                                     gtk_text_buffer_get_mark (get_buffer (text_view),
2689                                                               "insert"),
2690                                     0.0, FALSE, 0.0, 0.0);
2691       retval = TRUE;
2692     }
2693   /* Pass through Tab as literal tab, unless Control is held down */
2694   else if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK))
2695     {
2696       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\t", 1,
2697                                                     text_view->editable);
2698       gtk_text_view_scroll_mark_onscreen (text_view,
2699                                           gtk_text_buffer_get_mark (get_buffer (text_view),
2700                                                                     "insert"));
2701       retval = TRUE;
2702     }
2703   else
2704     retval = FALSE;
2705
2706   gtk_text_view_start_cursor_blink (text_view, TRUE);
2707
2708   return retval;
2709 }
2710
2711 static gint
2712 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
2713 {
2714   return FALSE;
2715 }
2716
2717 static gint
2718 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
2719 {
2720   GtkTextView *text_view;
2721
2722   text_view = GTK_TEXT_VIEW (widget);
2723
2724   gtk_widget_grab_focus (widget);
2725
2726   if (event->window != text_view->text_window->bin_window)
2727     {
2728       /* Remove selection if any. */
2729       gtk_text_view_unselect (text_view);
2730       return FALSE;
2731     }
2732
2733 #if 0
2734   /* debug hack */
2735   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
2736     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
2737   else if (event->button == 3)
2738     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
2739 #endif
2740
2741   if (event->type == GDK_BUTTON_PRESS)
2742     {
2743       gtk_text_view_reset_im_context (text_view);
2744
2745       if (event->button == 1)
2746         {
2747           /* If we're in the selection, start a drag copy/move of the
2748            * selection; otherwise, start creating a new selection.
2749            */
2750           GtkTextIter iter;
2751           GtkTextIter start, end;
2752
2753           gtk_text_layout_get_iter_at_pixel (text_view->layout,
2754                                              &iter,
2755                                              event->x + text_view->xoffset,
2756                                              event->y + text_view->yoffset);
2757
2758           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
2759                                                     &start, &end) &&
2760               gtk_text_iter_in_range (&iter, &start, &end))
2761             {
2762               text_view->drag_start_x = event->x;
2763               text_view->drag_start_y = event->y;
2764             }
2765           else
2766             {
2767               gtk_text_view_start_selection_drag (text_view, &iter, event);
2768             }
2769
2770           return TRUE;
2771         }
2772       else if (event->button == 2)
2773         {
2774           GtkTextIter iter;
2775
2776           gtk_text_layout_get_iter_at_pixel (text_view->layout,
2777                                              &iter,
2778                                              event->x + text_view->xoffset,
2779                                              event->y + text_view->yoffset);
2780
2781           gtk_text_buffer_paste_primary (get_buffer (text_view),
2782                                          &iter,
2783                                          text_view->editable);
2784           return TRUE;
2785         }
2786       else if (event->button == 3)
2787         {
2788           gtk_text_view_popup_menu (text_view, event);
2789         }
2790     }
2791   else if ((event->type == GDK_2BUTTON_PRESS ||
2792             event->type == GDK_3BUTTON_PRESS) &&
2793            event->button == 1)
2794     {
2795       GtkTextIter start, end;
2796
2797       /* End the selection drag, otherwise we'd clear the new
2798        * word/line selection on button release
2799        */
2800       gtk_text_view_end_selection_drag (text_view, event);
2801
2802       gtk_text_layout_get_iter_at_pixel (text_view->layout,
2803                                          &start,
2804                                          event->x + text_view->xoffset,
2805                                          event->y + text_view->yoffset); 
2806
2807       end = start;
2808       
2809       if (event->type == GDK_2BUTTON_PRESS)
2810         {
2811           if (gtk_text_iter_inside_word (&start))
2812             {
2813               if (!gtk_text_iter_starts_word (&start))
2814                 gtk_text_iter_backward_word_start (&start);
2815               
2816               if (!gtk_text_iter_ends_word (&end))
2817                 gtk_text_iter_forward_word_end (&end);
2818             }
2819         }
2820       else if (event->type == GDK_3BUTTON_PRESS)
2821         {
2822           if (gtk_text_view_starts_display_line (text_view, &start))
2823             {
2824               /* If on a display line boundary, we assume the user
2825                * clicked off the end of a line and we therefore select
2826                * the line before the boundary.
2827                */
2828               gtk_text_view_backward_display_line_start (text_view, &start);
2829             }
2830           else
2831             {
2832               /* start isn't on the start of a line, so we move it to the
2833                * start, and move end to the end unless it's already there.
2834                */
2835               gtk_text_view_backward_display_line_start (text_view, &start);
2836
2837               if (!gtk_text_view_starts_display_line (text_view, &end))
2838                 gtk_text_view_forward_display_line_end (text_view, &end);
2839             }
2840         }
2841
2842       gtk_text_buffer_move_mark (get_buffer (text_view),
2843                                  gtk_text_buffer_get_selection_bound (get_buffer (text_view)),
2844                                  &start);
2845       gtk_text_buffer_move_mark (get_buffer (text_view),
2846                                  gtk_text_buffer_get_insert (get_buffer (text_view)),
2847                                  &end);
2848
2849       text_view->just_selected_element = TRUE;
2850       
2851       return TRUE;
2852     }
2853   
2854   return FALSE;
2855 }
2856
2857 static gint
2858 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
2859 {
2860   GtkTextView *text_view;
2861
2862   text_view = GTK_TEXT_VIEW (widget);
2863
2864   if (event->window != text_view->text_window->bin_window)
2865     return FALSE;
2866
2867   if (event->button == 1)
2868     {
2869       if (text_view->drag_start_x >= 0)
2870         {
2871           text_view->drag_start_x = -1;
2872           text_view->drag_start_y = -1;
2873         }
2874
2875       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
2876         return TRUE;
2877       else if (text_view->just_selected_element)
2878         {
2879           text_view->just_selected_element = FALSE;
2880           return FALSE;
2881         }
2882       else
2883         {
2884           /* Unselect everything; probably we were dragging, or clicked
2885            * outside the text.
2886            */
2887           gtk_text_view_unselect (text_view);
2888           return FALSE;
2889         }
2890     }
2891
2892   return FALSE;
2893 }
2894
2895 static gint
2896 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
2897 {
2898   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2899
2900   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2901   gtk_widget_draw_focus (widget);
2902
2903   if (text_view->cursor_visible && text_view->layout)
2904     {
2905       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
2906       gtk_text_view_start_cursor_blink (text_view, FALSE);
2907     }
2908
2909   text_view->need_im_reset = TRUE;
2910   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
2911
2912   return FALSE;
2913 }
2914
2915 static gint
2916 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
2917 {
2918   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2919
2920   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2921   gtk_widget_draw_focus (widget);
2922
2923   if (text_view->cursor_visible && text_view->layout)
2924     {
2925       gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
2926       gtk_text_view_stop_cursor_blink (text_view);
2927     }
2928
2929   text_view->need_im_reset = TRUE;
2930   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
2931
2932   return FALSE;
2933 }
2934
2935 static gint
2936 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
2937 {
2938   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2939
2940   if (event->window == text_view->text_window->bin_window &&
2941       text_view->drag_start_x >= 0)
2942     {
2943       gint x, y;
2944       gint dx, dy;
2945
2946       gdk_window_get_pointer (text_view->text_window->bin_window,
2947                               &x, &y, NULL);
2948
2949       dx = text_view->drag_start_x - x;
2950       dy = text_view->drag_start_y - y;
2951
2952       if (ABS (dx) > DRAG_THRESHOLD ||
2953           ABS (dy) > DRAG_THRESHOLD)
2954         {
2955           GtkTextIter iter;
2956           gint buffer_x, buffer_y;
2957
2958           gtk_text_view_window_to_buffer_coords (text_view,
2959                                                  GTK_TEXT_WINDOW_TEXT,
2960                                                  text_view->drag_start_x,
2961                                                  text_view->drag_start_y,
2962                                                  &buffer_x,
2963                                                  &buffer_y);
2964
2965           gtk_text_layout_get_iter_at_pixel (text_view->layout,
2966                                              &iter,
2967                                              buffer_x, buffer_y);
2968
2969           gtk_text_view_start_selection_dnd (text_view, &iter, event);
2970           return TRUE;
2971         }
2972     }
2973
2974   return FALSE;
2975 }
2976
2977 static void
2978 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
2979 {
2980   GtkTextView *text_view;
2981
2982   text_view = GTK_TEXT_VIEW (widget);
2983
2984   g_return_if_fail (text_view->layout != NULL);
2985   g_return_if_fail (text_view->xoffset >= 0);
2986   g_return_if_fail (text_view->yoffset >= 0);
2987
2988   gtk_text_view_validate_onscreen (text_view);
2989
2990 #if 0
2991   printf ("painting %d,%d  %d x %d\n",
2992           area->x, area->y,
2993           area->width, area->height);
2994 #endif
2995
2996   gtk_text_layout_draw (text_view->layout,
2997                         widget,
2998                         text_view->text_window->bin_window,
2999                         text_view->xoffset,
3000                         text_view->yoffset,
3001                         area->x, area->y,
3002                         area->width, area->height);
3003 }
3004
3005 static gint
3006 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
3007 {
3008   if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
3009                                                  GTK_TEXT_WINDOW_TEXT))
3010     gtk_text_view_paint (widget, &event->area);
3011
3012   if (event->window == widget->window)
3013     gtk_widget_draw_focus (widget);
3014
3015   return TRUE;
3016 }
3017
3018 static void
3019 gtk_text_view_draw_focus (GtkWidget *widget)
3020 {
3021   if (GTK_WIDGET_DRAWABLE (widget))
3022     {
3023       if (GTK_WIDGET_HAS_FOCUS (widget))
3024         {
3025           gtk_paint_focus (widget->style, widget->window,
3026                            NULL, widget, "textview",
3027                            0, 0,
3028                            widget->allocation.width - 1,
3029                            widget->allocation.height - 1);
3030         }
3031       else
3032         {
3033           gdk_window_clear (widget->window);
3034         }
3035     }
3036 }
3037
3038 /*
3039  * Container
3040  */
3041
3042 static void
3043 gtk_text_view_add (GtkContainer *container,
3044                    GtkWidget    *child)
3045 {
3046   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3047   g_return_if_fail (GTK_IS_WIDGET (child));
3048
3049   /* This is pretty random. */
3050   gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
3051                                      child,
3052                                      GTK_TEXT_WINDOW_WIDGET,
3053                                      0, 0);
3054 }
3055
3056 static void
3057 gtk_text_view_remove (GtkContainer *container,
3058                       GtkWidget    *child)
3059 {
3060   GSList *iter;
3061   GtkTextView *text_view;
3062   GtkTextViewChild *vc;
3063
3064   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3065   g_return_if_fail (GTK_IS_WIDGET (child));
3066   g_return_if_fail (child->parent == (GtkWidget*) container);
3067
3068   text_view = GTK_TEXT_VIEW (container);
3069
3070   vc = NULL;
3071   iter = text_view->children;
3072
3073   while (iter != NULL)
3074     {
3075       vc = iter->data;
3076
3077       if (vc->widget == child)
3078         break;
3079
3080       iter = g_slist_next (iter);
3081     }
3082
3083   g_assert (iter != NULL); /* be sure we had the child in the list */
3084
3085   text_view->children = g_slist_remove (text_view->children, vc);
3086
3087   gtk_widget_unparent (vc->widget);
3088
3089   text_view_child_free (vc);
3090 }
3091
3092 static void
3093 gtk_text_view_forall (GtkContainer *container,
3094                       gboolean      include_internals,
3095                       GtkCallback   callback,
3096                       gpointer      callback_data)
3097 {
3098   GSList *iter;
3099   GtkTextView *text_view;
3100
3101   g_return_if_fail (GTK_IS_TEXT_VIEW (container));
3102   g_return_if_fail (callback != NULL);
3103
3104   text_view = GTK_TEXT_VIEW (container);
3105
3106   iter = text_view->children;
3107
3108   while (iter != NULL)
3109     {
3110       GtkTextViewChild *vc = iter->data;
3111
3112       (* callback) (vc->widget, callback_data);
3113
3114       iter = g_slist_next (iter);
3115     }
3116 }
3117
3118 /* Note that CURSOR_ON_TIME is effectively added to PREBLINK_TIME
3119  * because blinking starts with the cursor turned on.
3120  */
3121 #define PREBLINK_TIME 300
3122 #define CURSOR_ON_TIME 800
3123 #define CURSOR_OFF_TIME 400
3124
3125 /*
3126  * preblink!
3127  */
3128
3129 static gint
3130 preblink_cb (gpointer data)
3131 {
3132   GtkTextView *text_view = GTK_TEXT_VIEW (data);
3133
3134   text_view->preblink_timeout = 0;
3135   gtk_text_view_start_cursor_blink (text_view, FALSE);
3136
3137   /* Remove ourselves */
3138   return FALSE;
3139 }
3140
3141 /*
3142  * Blink!
3143  */
3144
3145 static gint
3146 blink_cb (gpointer data)
3147 {
3148   GtkTextView *text_view = GTK_TEXT_VIEW (data);
3149   gboolean visible;
3150   
3151   g_assert (text_view->layout);
3152   g_assert (GTK_WIDGET_HAS_FOCUS (text_view));
3153   g_assert (text_view->cursor_visible);
3154
3155   visible = gtk_text_layout_get_cursor_visible (text_view->layout);
3156
3157   if (visible)
3158     text_view->blink_timeout = gtk_timeout_add (CURSOR_OFF_TIME,
3159                                                 blink_cb,
3160                                                 text_view);
3161   else
3162     text_view->blink_timeout = gtk_timeout_add (CURSOR_ON_TIME,
3163                                                 blink_cb,
3164                                                 text_view);
3165   
3166   gtk_text_layout_set_cursor_visible (text_view->layout,
3167                                       !visible);
3168
3169   /* Remove ourselves */
3170   return FALSE;
3171 }
3172
3173 static void
3174 gtk_text_view_start_cursor_blink(GtkTextView *text_view,
3175                                  gboolean     with_delay)
3176 {
3177   if (!text_view->cursor_visible)
3178     return;
3179   
3180   if (text_view->preblink_timeout != 0)
3181     {
3182       gtk_timeout_remove (text_view->preblink_timeout);
3183       text_view->preblink_timeout = 0;
3184     }
3185   
3186   if (with_delay)
3187     {
3188       if (text_view->blink_timeout != 0)
3189         {
3190           gtk_timeout_remove (text_view->blink_timeout);
3191           text_view->blink_timeout = 0;
3192         }
3193       
3194       gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3195       
3196       text_view->preblink_timeout = gtk_timeout_add (PREBLINK_TIME,
3197                                                      preblink_cb,
3198                                                      text_view);
3199     }
3200   else
3201     {
3202       if (text_view->blink_timeout == 0)
3203         {
3204           gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
3205           
3206           text_view->blink_timeout = gtk_timeout_add (CURSOR_ON_TIME,
3207                                                       blink_cb,
3208                                                       text_view);
3209         }
3210     }
3211 }
3212
3213 static void
3214 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
3215 {
3216   if (text_view->preblink_timeout)
3217     {
3218       gtk_timeout_remove (text_view->preblink_timeout);
3219       text_view->preblink_timeout = 0;
3220     }
3221
3222   if (text_view->blink_timeout)  
3223     { 
3224       gtk_timeout_remove (text_view->blink_timeout);
3225       text_view->blink_timeout = 0;
3226     }
3227 }
3228
3229 /*
3230  * Key binding handlers
3231  */
3232
3233 static void
3234 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
3235                                   GtkTextIter *newplace,
3236                                   gint         count)
3237 {
3238   while (count < 0)
3239     {
3240       gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
3241       count++;
3242     }
3243
3244   while (count > 0)
3245     {
3246       gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
3247       count--;
3248     }
3249 }
3250
3251 static void
3252 gtk_text_view_move_cursor (GtkTextView     *text_view,
3253                            GtkMovementStep  step,
3254                            gint             count,
3255                            gboolean         extend_selection)
3256 {
3257   GtkTextIter insert;
3258   GtkTextIter newplace;
3259
3260   gint cursor_x_pos = 0;
3261
3262   gtk_text_view_reset_im_context (text_view);
3263
3264   if (step == GTK_MOVEMENT_PAGES)
3265     {
3266       gtk_text_view_scroll_pages (text_view, count);
3267       gtk_text_view_start_cursor_blink (text_view, TRUE);
3268       return;
3269     }
3270
3271   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3272                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3273                                                               "insert"));
3274   newplace = insert;
3275
3276   if (step == GTK_MOVEMENT_DISPLAY_LINES)
3277     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
3278
3279   switch (step)
3280     {
3281     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3282       gtk_text_iter_forward_cursor_positions (&newplace, count);
3283       break;
3284
3285     case GTK_MOVEMENT_VISUAL_POSITIONS:
3286       gtk_text_layout_move_iter_visually (text_view->layout,
3287                                           &newplace, count);
3288       break;
3289
3290     case GTK_MOVEMENT_WORDS:
3291       if (count < 0)
3292         gtk_text_iter_backward_word_starts (&newplace, -count);
3293       else if (count > 0)
3294         gtk_text_iter_forward_word_ends (&newplace, count);
3295       break;
3296
3297     case GTK_MOVEMENT_DISPLAY_LINES:
3298       gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
3299       gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
3300       break;
3301
3302     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
3303       if (count > 1)
3304         gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
3305       else if (count < -1)
3306         gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
3307
3308       if (count != 0)
3309         gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
3310       break;
3311
3312     case GTK_MOVEMENT_PARAGRAPHS:
3313       /* This should almost certainly instead be doing the parallel thing to WORD */
3314       /*       gtk_text_iter_down_lines (&newplace, count); */
3315       /* FIXME */
3316       break;
3317
3318     case GTK_MOVEMENT_PARAGRAPH_ENDS:
3319       if (count > 0)
3320         gtk_text_iter_forward_to_delimiters (&newplace);
3321       else if (count < 0)
3322         gtk_text_iter_set_line_offset (&newplace, 0);
3323       break;
3324
3325     case GTK_MOVEMENT_BUFFER_ENDS:
3326       if (count > 0)
3327         gtk_text_buffer_get_last_iter (get_buffer (text_view), &newplace);
3328       else if (count < 0)
3329         gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
3330       break;
3331
3332     default:
3333       break;
3334     }
3335
3336   if (!gtk_text_iter_equal (&insert, &newplace))
3337     {
3338       if (extend_selection)
3339         gtk_text_buffer_move_mark (get_buffer (text_view),
3340                                    gtk_text_buffer_get_mark (get_buffer (text_view),
3341                                                              "insert"),
3342                                    &newplace);
3343       else
3344         gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
3345
3346       gtk_text_view_scroll_mark_onscreen (text_view,
3347                                           gtk_text_buffer_get_mark (get_buffer (text_view),
3348                                                                     "insert"));
3349
3350       if (step == GTK_MOVEMENT_DISPLAY_LINES)
3351         {
3352           gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
3353         }
3354     }
3355
3356   gtk_text_view_start_cursor_blink (text_view, TRUE);
3357 }
3358
3359 static void
3360 gtk_text_view_set_anchor (GtkTextView *text_view)
3361 {
3362   GtkTextIter insert;
3363
3364   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3365                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3366                                                               "insert"));
3367
3368   gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
3369 }
3370
3371 static void
3372 gtk_text_view_scroll_pages (GtkTextView *text_view,
3373                             gint         count)
3374 {
3375   gfloat newval;
3376   GtkAdjustment *adj;
3377   gint cursor_x_pos, cursor_y_pos;
3378   GtkTextIter new_insert;
3379   GtkTextIter anchor;
3380   gint y0, y1;
3381
3382   g_return_if_fail (text_view->vadjustment != NULL);
3383
3384   adj = text_view->vadjustment;
3385
3386   /* Validate the region that will be brought into view by the cursor motion
3387    */
3388   if (count < 0)
3389     {
3390       gtk_text_view_get_first_para_iter (text_view, &anchor);
3391       y0 = adj->page_size;
3392       y1 = adj->page_size + count * adj->page_increment;
3393     }
3394   else
3395     {
3396       gtk_text_view_get_first_para_iter (text_view, &anchor);
3397       y0 = count * adj->page_increment + adj->page_size;
3398       y1 = 0;
3399     }
3400
3401   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
3402
3403   gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
3404
3405   newval = adj->value;
3406
3407   newval += count * adj->page_increment;
3408
3409   cursor_y_pos += newval - adj->value;
3410   set_adjustment_clamped (adj, newval);
3411
3412   gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
3413   clamp_iter_onscreen (text_view, &new_insert);
3414   gtk_text_buffer_place_cursor (get_buffer (text_view), &new_insert);
3415
3416   gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
3417
3418   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
3419    * only guarantees 1 pixel onscreen.
3420    */
3421   gtk_text_view_scroll_mark_onscreen (text_view,
3422                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3423                                                                 "insert"));
3424 }
3425
3426 static gboolean
3427 whitespace (gunichar ch, gpointer user_data)
3428 {
3429   return (ch == ' ' || ch == '\t');
3430 }
3431
3432 static gboolean
3433 not_whitespace (gunichar ch, gpointer user_data)
3434 {
3435   return !whitespace (ch, user_data);
3436 }
3437
3438 static gboolean
3439 find_whitepace_region (const GtkTextIter *center,
3440                        GtkTextIter *start, GtkTextIter *end)
3441 {
3442   *start = *center;
3443   *end = *center;
3444
3445   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
3446     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
3447   if (whitespace (gtk_text_iter_get_char (end), NULL))
3448     gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
3449
3450   return !gtk_text_iter_equal (start, end);
3451 }
3452
3453 static void
3454 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
3455                                 const gchar *str)
3456 {
3457   gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
3458                                                 text_view->editable);
3459 }
3460
3461 static void
3462 gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
3463                                   GtkDeleteType  type,
3464                                   gint           count)
3465 {
3466   GtkTextIter insert;
3467   GtkTextIter start;
3468   GtkTextIter end;
3469   gboolean leave_one = FALSE;
3470
3471   gtk_text_view_reset_im_context (text_view);
3472
3473   if (type == GTK_DELETE_CHARS)
3474     {
3475       /* Char delete deletes the selection, if one exists */
3476       if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
3477                                             text_view->editable))
3478         return;
3479     }
3480
3481   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3482                                     &insert,
3483                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3484                                                               "insert"));
3485
3486   start = insert;
3487   end = insert;
3488
3489   switch (type)
3490     {
3491     case GTK_DELETE_CHARS:
3492       gtk_text_iter_forward_cursor_positions (&end, count);
3493       break;
3494
3495     case GTK_DELETE_WORD_ENDS:
3496       if (count > 0)
3497         gtk_text_iter_forward_word_ends (&end, count);
3498       else if (count < 0)
3499         gtk_text_iter_backward_word_starts (&start, 0 - count);
3500       break;
3501
3502     case GTK_DELETE_WORDS:
3503       break;
3504
3505     case GTK_DELETE_DISPLAY_LINE_ENDS:
3506       break;
3507
3508     case GTK_DELETE_DISPLAY_LINES:
3509       break;
3510
3511     case GTK_DELETE_PARAGRAPH_ENDS:
3512       /* If we're already at a newline, we need to
3513        * simply delete that newline, instead of
3514        * moving to the next one.
3515        */
3516       if (gtk_text_iter_ends_line (&end))
3517         {
3518           gtk_text_iter_forward_line (&end);
3519           --count;
3520         }
3521
3522       while (count > 0)
3523         {
3524           if (!gtk_text_iter_forward_to_delimiters (&end))
3525             break;
3526
3527           --count;
3528         }
3529
3530       /* FIXME figure out what a negative count means
3531          and support that */
3532       break;
3533
3534     case GTK_DELETE_PARAGRAPHS:
3535       if (count > 0)
3536         {
3537           gtk_text_iter_set_line_offset (&start, 0);
3538           gtk_text_iter_forward_to_delimiters (&end);
3539
3540           /* Do the lines beyond the first. */
3541           while (count > 1)
3542             {
3543               gtk_text_iter_forward_to_delimiters (&end);
3544
3545               --count;
3546             }
3547         }
3548
3549       /* FIXME negative count? */
3550
3551       break;
3552
3553     case GTK_DELETE_WHITESPACE:
3554       {
3555         find_whitepace_region (&insert, &start, &end);
3556       }
3557       break;
3558
3559     default:
3560       break;
3561     }
3562
3563   if (!gtk_text_iter_equal (&start, &end))
3564     {
3565       gtk_text_buffer_begin_user_action (get_buffer (text_view));
3566
3567       if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
3568                                               text_view->editable))
3569         {
3570           if (leave_one)
3571             gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
3572                                                           " ", 1,
3573                                                           text_view->editable);
3574         }
3575
3576       gtk_text_buffer_end_user_action (get_buffer (text_view));
3577       
3578       gtk_text_view_scroll_mark_onscreen (text_view,
3579                                           gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
3580     }
3581 }
3582
3583 static void
3584 gtk_text_view_cut_clipboard (GtkTextView *text_view)
3585 {
3586   gtk_text_buffer_cut_clipboard (get_buffer (text_view), text_view->editable);
3587   gtk_text_view_scroll_mark_onscreen (text_view,
3588                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3589                                                                 "insert"));
3590 }
3591
3592 static void
3593 gtk_text_view_copy_clipboard (GtkTextView *text_view)
3594 {
3595   gtk_text_buffer_copy_clipboard (get_buffer (text_view));
3596   gtk_text_view_scroll_mark_onscreen (text_view,
3597                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3598                                                                 "insert"));
3599 }
3600
3601 static void
3602 gtk_text_view_paste_clipboard (GtkTextView *text_view)
3603 {
3604   gtk_text_buffer_paste_clipboard (get_buffer (text_view), text_view->editable);
3605   gtk_text_view_scroll_mark_onscreen (text_view,
3606                                       gtk_text_buffer_get_mark (get_buffer (text_view),
3607                                                                 "insert"));
3608 }
3609
3610 static void
3611 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
3612 {
3613   text_view->overwrite_mode = !text_view->overwrite_mode;
3614 }
3615
3616 /*
3617  * Selections
3618  */
3619
3620 static void
3621 gtk_text_view_unselect (GtkTextView *text_view)
3622 {
3623   GtkTextIter insert;
3624
3625   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3626                                     &insert,
3627                                     gtk_text_buffer_get_mark (get_buffer (text_view),
3628                                                               "insert"));
3629
3630   gtk_text_buffer_move_mark (get_buffer (text_view),
3631                              gtk_text_buffer_get_mark (get_buffer (text_view),
3632                                                        "selection_bound"),
3633                              &insert);
3634 }
3635
3636 static gboolean
3637 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
3638                                  const gchar *mark_name)
3639 {
3640   gint x, y;
3641   GdkModifierType state;
3642   GtkTextIter newplace;
3643
3644   gdk_window_get_pointer (text_view->text_window->bin_window,
3645                           &x, &y, &state);
3646   
3647   gtk_text_layout_get_iter_at_pixel (text_view->layout,
3648                                      &newplace,
3649                                      x + text_view->xoffset,
3650                                      y + text_view->yoffset);
3651
3652   {
3653     gboolean scrolled = FALSE;
3654     GtkTextMark *mark =
3655       gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
3656
3657     gtk_text_buffer_move_mark (get_buffer (text_view),
3658                                mark,
3659                                &newplace);
3660
3661     scrolled = gtk_text_view_scroll_mark_onscreen (text_view, mark);
3662
3663     return scrolled;
3664   }
3665 }
3666
3667 static gint
3668 selection_scan_timeout (gpointer data)
3669 {
3670   GtkTextView *text_view;
3671
3672   text_view = GTK_TEXT_VIEW (data);
3673
3674   move_mark_to_pointer_and_scroll (text_view, "insert");
3675
3676   return TRUE; /* remain installed. */
3677 }
3678
3679 #define DND_SCROLL_MARGIN 0.20
3680
3681 static gint
3682 drag_scan_timeout (gpointer data)
3683 {
3684   GtkTextView *text_view;
3685   gint x, y;
3686   GdkModifierType state;
3687   GtkTextIter newplace;
3688   
3689   text_view = GTK_TEXT_VIEW (data);
3690
3691   gdk_window_get_pointer (text_view->text_window->bin_window,
3692                           &x, &y, &state);
3693   
3694   gtk_text_layout_get_iter_at_pixel (text_view->layout,
3695                                      &newplace,
3696                                      x + text_view->xoffset,
3697                                      y + text_view->yoffset);
3698   
3699   gtk_text_buffer_move_mark (get_buffer (text_view),
3700                              text_view->dnd_mark,
3701                              &newplace);
3702   
3703   gtk_text_view_scroll_to_mark (text_view,
3704                                 text_view->dnd_mark,
3705                                 DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
3706
3707   return TRUE;
3708 }
3709
3710 static gint
3711 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
3712 {
3713   move_mark_to_pointer_and_scroll (text_view, "insert");
3714
3715   /* If we had to scroll offscreen, insert a timeout to do so
3716    * again. Note that in the timeout, even if the mouse doesn't
3717    * move, due to this scroll xoffset/yoffset will have changed
3718    * and we'll need to scroll again.
3719    */
3720   if (text_view->scroll_timeout != 0) /* reset on every motion event */
3721     gtk_timeout_remove (text_view->scroll_timeout);
3722   
3723   text_view->scroll_timeout =
3724     gtk_timeout_add (50, selection_scan_timeout, text_view);
3725
3726   return TRUE;
3727 }
3728
3729 static void
3730 gtk_text_view_start_selection_drag (GtkTextView       *text_view,
3731                                     const GtkTextIter *iter,
3732                                     GdkEventButton    *button)
3733 {
3734   GtkTextIter newplace;
3735
3736   g_return_if_fail (text_view->selection_drag_handler == 0);
3737
3738   gtk_grab_add (GTK_WIDGET (text_view));
3739
3740   newplace = *iter;
3741
3742   gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
3743
3744   text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
3745                                                           "motion_notify_event",
3746                                                           GTK_SIGNAL_FUNC (selection_motion_event_handler),
3747                                                           NULL);
3748 }
3749
3750 /* returns whether we were really dragging */
3751 static gboolean
3752 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
3753 {
3754   if (text_view->selection_drag_handler == 0)
3755     return FALSE;
3756
3757   gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
3758   text_view->selection_drag_handler = 0;
3759
3760   if (text_view->scroll_timeout != 0)
3761     {
3762       gtk_timeout_remove (text_view->scroll_timeout);
3763       text_view->scroll_timeout = 0;
3764     }
3765
3766   /* one last update to current position */
3767   move_mark_to_pointer_and_scroll (text_view, "insert");
3768
3769   gtk_grab_remove (GTK_WIDGET (text_view));
3770
3771   return TRUE;
3772 }
3773
3774 /*
3775  * Layout utils
3776  */
3777
3778 static void
3779 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
3780 {
3781   if (upper != adj->upper)
3782     {
3783       gfloat min = MAX (0., upper - adj->page_size);
3784       gboolean value_changed = FALSE;
3785
3786       adj->upper = upper;
3787
3788       if (adj->value > min)
3789         {
3790           adj->value = min;
3791           value_changed = TRUE;
3792         }
3793
3794       gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
3795       if (value_changed)
3796         gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3797     }
3798 }
3799
3800 static void
3801 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
3802 {
3803   gint width = 0, height = 0;
3804
3805   gtk_text_view_ensure_layout (text_view);
3806
3807
3808   gtk_text_layout_set_screen_width (text_view->layout,
3809                                     SCREEN_WIDTH (text_view));
3810
3811   gtk_text_layout_get_size (text_view->layout, &width, &height);
3812
3813   if (text_view->width != width || text_view->height != height)
3814     {
3815       text_view->width = width;
3816       text_view->height = height;
3817
3818       gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
3819                                           MAX (SCREEN_WIDTH (text_view), width));
3820       gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
3821                                           MAX (SCREEN_HEIGHT (text_view), height));
3822
3823       /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
3824
3825       /* Set up the step sizes; we'll say that a page is
3826          our allocation minus one step, and a step is
3827          1/10 of our allocation. */
3828       text_view->hadjustment->step_increment =
3829         SCREEN_WIDTH (text_view) / 10.0;
3830       text_view->hadjustment->page_increment =
3831         SCREEN_WIDTH (text_view) * 0.9;
3832
3833       text_view->vadjustment->step_increment =
3834         SCREEN_HEIGHT (text_view) / 10.0;
3835       text_view->vadjustment->page_increment =
3836         SCREEN_HEIGHT (text_view) * 0.9;
3837     }
3838 }
3839
3840 static void
3841 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
3842                                          GtkTextAttributes *values,
3843                                          GtkStyle           *style)
3844 {
3845   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
3846   values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
3847
3848   if (values->font.family_name)
3849     g_free (values->font.family_name);
3850
3851   values->font = *style->font_desc;
3852   values->font.family_name = g_strdup (style->font_desc->family_name);
3853 }
3854
3855 static void
3856 gtk_text_view_ensure_layout (GtkTextView *text_view)
3857 {
3858   GtkWidget *widget;
3859
3860   widget = GTK_WIDGET (text_view);
3861
3862   if (text_view->layout == NULL)
3863     {
3864       GtkTextAttributes *style;
3865       PangoContext *ltr_context, *rtl_context;
3866       GSList *tmp_list;
3867       
3868       text_view->layout = gtk_text_layout_new ();
3869
3870       g_signal_connect_data (G_OBJECT (text_view->layout),
3871                              "invalidated",
3872                              invalidated_handler,
3873                              text_view,
3874                              NULL, FALSE, FALSE);
3875
3876       g_signal_connect_data (G_OBJECT (text_view->layout),
3877                              "changed",
3878                              changed_handler,
3879                              text_view,
3880                              NULL, FALSE, FALSE);
3881
3882       g_signal_connect_data (G_OBJECT (text_view->layout),
3883                              "allocate_child",
3884                              gtk_text_view_child_allocated,
3885                              text_view,
3886                              NULL, FALSE, FALSE);
3887       
3888       if (get_buffer (text_view))
3889         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
3890
3891       if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
3892         gtk_text_view_start_cursor_blink (text_view, FALSE);
3893       else
3894         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
3895
3896       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
3897       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
3898       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
3899       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
3900
3901       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
3902
3903       g_object_unref (G_OBJECT (ltr_context));
3904       g_object_unref (G_OBJECT (rtl_context));
3905
3906       style = gtk_text_attributes_new ();
3907
3908       gtk_widget_ensure_style (widget);
3909       gtk_text_view_set_attributes_from_style (text_view,
3910                                                style, widget->style);
3911
3912       style->pixels_above_lines = text_view->pixels_above_lines;
3913       style->pixels_below_lines = text_view->pixels_below_lines;
3914       style->pixels_inside_wrap = text_view->pixels_inside_wrap;
3915       style->left_margin = text_view->left_margin;
3916       style->right_margin = text_view->right_margin;
3917       style->indent = text_view->indent;
3918       style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
3919
3920       style->wrap_mode = text_view->wrap_mode;
3921       style->justify = text_view->justify;
3922       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
3923
3924       gtk_text_layout_set_default_style (text_view->layout, style);
3925
3926       gtk_text_attributes_unref (style);
3927
3928       /* Set layout for all anchored children */
3929
3930       tmp_list = text_view->children;
3931       while (tmp_list != NULL)
3932         {
3933           GtkTextViewChild *vc = tmp_list->data;
3934
3935           if (vc->anchor)
3936             {
3937               gtk_text_anchored_child_set_layout (vc->widget,
3938                                                   text_view->layout);
3939               /* vc may now be invalid! */
3940             }
3941
3942           tmp_list = g_slist_next (tmp_list);
3943         }
3944     }
3945 }
3946
3947 static void
3948 gtk_text_view_destroy_layout (GtkTextView *text_view)
3949 {
3950   if (text_view->layout)
3951     {
3952       /* Remove layout from all anchored children */
3953       GSList *tmp_list;
3954
3955       tmp_list = text_view->children;
3956       while (tmp_list != NULL)
3957         {
3958           GtkTextViewChild *vc = tmp_list->data;
3959
3960           if (vc->anchor)
3961             {
3962               gtk_text_anchored_child_set_layout (vc->widget, NULL);
3963               /* vc may now be invalid! */
3964             }
3965
3966           tmp_list = g_slist_next (tmp_list);
3967         }
3968       
3969       gtk_text_view_stop_cursor_blink (text_view);
3970       gtk_text_view_end_selection_drag (text_view, NULL);
3971
3972       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
3973                                             invalidated_handler, text_view);
3974       g_signal_handlers_disconnect_by_func (G_OBJECT (text_view->layout),
3975                                             changed_handler, text_view);
3976       g_object_unref (G_OBJECT (text_view->layout));
3977       text_view->layout = NULL;
3978     }
3979 }
3980
3981 static void
3982 gtk_text_view_reset_im_context (GtkTextView *text_view)
3983 {
3984   if (text_view->need_im_reset)
3985     {
3986       text_view->need_im_reset = FALSE;
3987       gtk_im_context_reset (text_view->im_context);
3988     }
3989 }
3990
3991 /*
3992  * DND feature
3993  */
3994
3995 static void
3996 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
3997                                    const GtkTextIter *iter,
3998                                    GdkEventMotion    *event)
3999 {
4000   GdkDragContext *context;
4001   GtkTargetList *target_list;
4002
4003   text_view->drag_start_x = -1;
4004   text_view->drag_start_y = -1;
4005
4006   target_list = gtk_target_list_new (target_table,
4007                                      G_N_ELEMENTS (target_table));
4008
4009   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
4010                             GDK_ACTION_COPY | GDK_ACTION_MOVE,
4011                             1, (GdkEvent*)event);
4012
4013   gtk_target_list_unref (target_list);
4014
4015   gtk_drag_set_icon_default (context);
4016
4017   /* We're inside the selection, so start without being able
4018    * to accept the drag.
4019    */
4020   gdk_drag_status (context, 0, event->time);
4021   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4022 }
4023
4024 static void
4025 gtk_text_view_drag_begin (GtkWidget        *widget,
4026                           GdkDragContext   *context)
4027 {
4028
4029 }
4030
4031 static void
4032 gtk_text_view_drag_end (GtkWidget        *widget,
4033                         GdkDragContext   *context)
4034 {
4035   GtkTextView *text_view;
4036
4037   text_view = GTK_TEXT_VIEW (widget);
4038   
4039   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4040
4041   if (text_view->scroll_timeout != 0)
4042     {
4043       gtk_timeout_remove (text_view->scroll_timeout);
4044       text_view->scroll_timeout = 0;
4045     }
4046 }
4047
4048 static void
4049 gtk_text_view_drag_data_get (GtkWidget        *widget,
4050                              GdkDragContext   *context,
4051                              GtkSelectionData *selection_data,
4052                              guint             info,
4053                              guint             time)
4054 {
4055   GtkTextView *text_view;
4056
4057   text_view = GTK_TEXT_VIEW (widget);
4058
4059   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
4060     {
4061       GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
4062
4063       gtk_selection_data_set (selection_data,
4064                               gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
4065                               8, /* bytes */
4066                               (void*)&buffer,
4067                               sizeof (buffer));
4068     }
4069   else
4070     {
4071       gchar *str;
4072       GtkTextIter start;
4073       GtkTextIter end;
4074
4075       str = NULL;
4076
4077       if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4078                                                 &start, &end))
4079         {
4080           /* Extract the selected text */
4081           str = gtk_text_iter_get_visible_text (&start, &end);
4082         }
4083
4084       if (str)
4085         {
4086           gtk_selection_data_set_text (selection_data, str);
4087           g_free (str);
4088         }
4089     }
4090 }
4091
4092 static void
4093 gtk_text_view_drag_data_delete (GtkWidget        *widget,
4094                                 GdkDragContext   *context)
4095 {
4096   GtkTextView *text_view;
4097
4098   text_view = GTK_TEXT_VIEW (widget);
4099
4100   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
4101                                     TRUE, GTK_TEXT_VIEW (widget)->editable);
4102 }
4103
4104 static void
4105 gtk_text_view_drag_leave (GtkWidget        *widget,
4106                           GdkDragContext   *context,
4107                           guint             time)
4108 {
4109   GtkTextView *text_view;
4110
4111   text_view = GTK_TEXT_VIEW (widget);
4112
4113   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4114   
4115   if (text_view->scroll_timeout != 0)
4116     gtk_timeout_remove (text_view->scroll_timeout);
4117
4118   text_view->scroll_timeout = 0;
4119 }
4120
4121 static gboolean
4122 gtk_text_view_drag_motion (GtkWidget        *widget,
4123                            GdkDragContext   *context,
4124                            gint              x,
4125                            gint              y,
4126                            guint             time)
4127 {
4128   GtkTextIter newplace;
4129   GtkTextView *text_view;
4130   GtkTextIter start;
4131   GtkTextIter end;
4132   GdkRectangle target_rect;
4133   gint bx, by;
4134   gboolean scrolled;
4135   
4136   text_view = GTK_TEXT_VIEW (widget);
4137
4138   target_rect = text_view->text_window->allocation;
4139   
4140   if (x < target_rect.x ||
4141       y < target_rect.y ||
4142       x > (target_rect.x + target_rect.width) ||
4143       y > (target_rect.y + target_rect.height))
4144     return FALSE; /* outside the text window */
4145
4146   gtk_text_view_window_to_buffer_coords (text_view,
4147                                          GTK_TEXT_WINDOW_WIDGET,
4148                                          x, y,
4149                                          &bx, &by);
4150
4151   gtk_text_layout_get_iter_at_pixel (text_view->layout,
4152                                      &newplace,
4153                                      bx, by);  
4154   
4155   if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4156                                             &start, &end) &&
4157       gtk_text_iter_in_range (&newplace, &start, &end))
4158     {
4159       /* We're inside the selection. */
4160       gdk_drag_status (context, 0, time);
4161       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4162     }
4163   else
4164     {      
4165       if (gtk_text_iter_editable (&newplace, text_view->editable))
4166         {
4167           GtkWidget *source_widget;
4168           GdkDragAction suggested_action;
4169           
4170           suggested_action = context->suggested_action;
4171           
4172           source_widget = gtk_drag_get_source_widget (context);
4173           
4174           if (source_widget == widget)
4175             {
4176               /* Default to MOVE, unless the user has
4177                * pressed ctrl or alt to affect available actions
4178                */
4179               if ((context->actions & GDK_ACTION_MOVE) != 0)
4180                 suggested_action = GDK_ACTION_MOVE;
4181             }
4182           
4183           gtk_text_mark_set_visible (text_view->dnd_mark,
4184                                      text_view->cursor_visible);
4185
4186           gdk_drag_status (context, suggested_action, time);
4187         }
4188       else
4189         {
4190           /* Can't drop here. */
4191           gdk_drag_status (context, 0, time);
4192           gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
4193         }
4194     }
4195
4196   gtk_text_buffer_move_mark (get_buffer (text_view),
4197                              text_view->dnd_mark,
4198                              &newplace);
4199
4200   scrolled = gtk_text_view_scroll_to_mark (text_view,
4201                                            text_view->dnd_mark,
4202                                            DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
4203   
4204   if (text_view->scroll_timeout != 0) /* reset on every motion event */
4205     gtk_timeout_remove (text_view->scroll_timeout);
4206       
4207   text_view->scroll_timeout =
4208     gtk_timeout_add (50, drag_scan_timeout, text_view);
4209   
4210   return TRUE;
4211 }
4212
4213 static gboolean
4214 gtk_text_view_drag_drop (GtkWidget        *widget,
4215                          GdkDragContext   *context,
4216                          gint              x,
4217                          gint              y,
4218                          guint             time)
4219 {
4220 #if 0
4221   /* called automatically. */
4222   if (context->targets)
4223     {
4224       gtk_drag_get_data (widget, context,
4225                          GPOINTER_TO_INT (context->targets->data),
4226                          time);
4227       return TRUE;
4228     }
4229   else
4230     return FALSE;
4231 #endif
4232   return TRUE;
4233 }
4234
4235 static void
4236 insert_text_data (GtkTextView      *text_view,
4237                   GtkTextIter      *drop_point,
4238                   GtkSelectionData *selection_data)
4239 {
4240   gchar *str;
4241
4242   str = gtk_selection_data_get_text (selection_data);
4243
4244   if (str)
4245     {
4246       gtk_text_buffer_insert_interactive (get_buffer (text_view),
4247                                           drop_point, str, -1,
4248                                           text_view->editable);
4249       g_free (str);
4250     }
4251 }
4252
4253 static void
4254 gtk_text_view_drag_data_received (GtkWidget        *widget,
4255                                   GdkDragContext   *context,
4256                                   gint              x,
4257                                   gint              y,
4258                                   GtkSelectionData *selection_data,
4259                                   guint             info,
4260                                   guint             time)
4261 {
4262   GtkTextIter drop_point;
4263   GtkTextView *text_view;
4264   GtkTextMark *drag_target_mark;
4265
4266   text_view = GTK_TEXT_VIEW (widget);
4267
4268   drag_target_mark = gtk_text_buffer_get_mark (get_buffer (text_view),
4269                                                "gtk_drag_target");
4270
4271   if (drag_target_mark == NULL)
4272     return;
4273
4274   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
4275                                     &drop_point,
4276                                     drag_target_mark);
4277
4278   if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
4279     {
4280       GtkTextBuffer *src_buffer = NULL;
4281       GtkTextIter start, end;
4282       gboolean copy_tags = TRUE;
4283
4284       if (selection_data->length != sizeof (src_buffer))
4285         return;
4286
4287       memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
4288
4289       if (src_buffer == NULL)
4290         return;
4291
4292       g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
4293
4294       if (gtk_text_buffer_get_tag_table (src_buffer) !=
4295           gtk_text_buffer_get_tag_table (get_buffer (text_view)))
4296         copy_tags = FALSE;
4297
4298       if (gtk_text_buffer_get_selection_bounds (src_buffer,
4299                                                 &start,
4300                                                 &end))
4301         {
4302           if (copy_tags)
4303             gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
4304                                                       &drop_point,
4305                                                       &start,
4306                                                       &end,
4307                                                       text_view->editable);
4308           else
4309             {
4310               gchar *str;
4311
4312               str = gtk_text_iter_get_visible_text (&start, &end);
4313               gtk_text_buffer_insert_interactive (get_buffer (text_view),
4314                                                   &drop_point, str, -1,
4315                                                   text_view->editable);
4316               g_free (str);
4317             }
4318         }
4319     }
4320   else
4321     insert_text_data (text_view, &drop_point, selection_data);
4322 }
4323
4324 static GtkAdjustment*
4325 get_hadjustment (GtkTextView *text_view)
4326 {
4327   if (text_view->hadjustment == NULL)
4328     gtk_text_view_set_scroll_adjustments (text_view,
4329                                           NULL, /* forces creation */
4330                                           text_view->vadjustment);
4331
4332   return text_view->hadjustment;
4333 }
4334
4335 static GtkAdjustment*
4336 get_vadjustment (GtkTextView *text_view)
4337 {
4338   if (text_view->vadjustment == NULL)
4339     gtk_text_view_set_scroll_adjustments (text_view,
4340                                           text_view->hadjustment,
4341                                           NULL); /* forces creation */
4342   return text_view->vadjustment;
4343 }
4344
4345
4346 static void
4347 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
4348                                       GtkAdjustment *hadj,
4349                                       GtkAdjustment *vadj)
4350 {
4351   gboolean need_adjust = FALSE;
4352
4353   g_return_if_fail (text_view != NULL);
4354   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4355
4356   if (hadj)
4357     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4358   else
4359     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4360   if (vadj)
4361     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4362   else
4363     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4364
4365   if (text_view->hadjustment && (text_view->hadjustment != hadj))
4366     {
4367       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
4368       g_object_unref (G_OBJECT (text_view->hadjustment));
4369     }
4370
4371   if (text_view->vadjustment && (text_view->vadjustment != vadj))
4372     {
4373       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
4374       g_object_unref (G_OBJECT (text_view->vadjustment));
4375     }
4376
4377   if (text_view->hadjustment != hadj)
4378     {
4379       text_view->hadjustment = hadj;
4380       g_object_ref (G_OBJECT (text_view->hadjustment));
4381       gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
4382
4383       gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
4384                           (GtkSignalFunc) gtk_text_view_value_changed,
4385                           text_view);
4386       need_adjust = TRUE;
4387     }
4388
4389   if (text_view->vadjustment != vadj)
4390     {
4391       text_view->vadjustment = vadj;
4392       g_object_ref (G_OBJECT (text_view->vadjustment));
4393       gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
4394
4395       gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
4396                           (GtkSignalFunc) gtk_text_view_value_changed,
4397                           text_view);
4398       need_adjust = TRUE;
4399     }
4400
4401   if (need_adjust)
4402     gtk_text_view_value_changed (NULL, text_view);
4403 }
4404
4405 static void
4406 gtk_text_view_value_changed (GtkAdjustment *adj,
4407                              GtkTextView   *text_view)
4408 {
4409   GtkTextIter iter;
4410   gint line_top;
4411   gint dx = 0;
4412   gint dy = 0;
4413
4414   if (adj == text_view->hadjustment)
4415     {
4416       dx = text_view->xoffset - (gint)adj->value;
4417       text_view->xoffset = adj->value;
4418     }
4419   else if (adj == text_view->vadjustment)
4420     {
4421       dy = text_view->yoffset - (gint)adj->value;
4422       text_view->yoffset = adj->value;
4423
4424       if (text_view->layout)
4425         {
4426           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
4427
4428           gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
4429
4430           text_view->first_para_pixels = adj->value - line_top;
4431         }
4432     }
4433
4434   if (GTK_WIDGET_REALIZED (text_view) && (dx != 0 || dy != 0))
4435     {
4436       if (dy != 0)
4437         {
4438           if (text_view->left_window)
4439             text_window_scroll (text_view->left_window, 0, dy);
4440           if (text_view->right_window)
4441             text_window_scroll (text_view->right_window, 0, dy);
4442         }
4443
4444       if (dx != 0)
4445         {
4446           if (text_view->top_window)
4447             text_window_scroll (text_view->top_window, dx, 0);
4448           if (text_view->bottom_window)
4449             text_window_scroll (text_view->bottom_window, dx, 0);
4450         }
4451
4452       /* It looks nicer to scroll the main area last, because
4453        * it takes a while, and making the side areas update
4454        * afterward emphasizes the slowness of scrolling the
4455        * main area.
4456        */
4457       text_window_scroll (text_view->text_window, dx, dy);
4458     }
4459 }
4460
4461 static void
4462 gtk_text_view_commit_handler (GtkIMContext  *context,
4463                               const gchar   *str,
4464                               GtkTextView   *text_view)
4465 {
4466   gtk_text_buffer_begin_user_action (get_buffer (text_view));
4467
4468   gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
4469                                     text_view->editable);
4470
4471   if (!strcmp (str, "\n"))
4472     {
4473       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
4474                                                     text_view->editable);
4475     }
4476   else
4477     {
4478       if (text_view->overwrite_mode)
4479         gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
4480       gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
4481                                                     text_view->editable);
4482     }
4483
4484   gtk_text_buffer_end_user_action (get_buffer (text_view));
4485   
4486   gtk_text_view_scroll_mark_onscreen (text_view,
4487                                       gtk_text_buffer_get_mark (get_buffer (text_view),
4488                                                                 "insert"));
4489 }
4490
4491 static void
4492 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
4493                                        GtkTextView  *text_view)
4494 {
4495   gchar *str;
4496   PangoAttrList *attrs;
4497   gint cursor_pos;
4498
4499   gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
4500   gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
4501
4502   pango_attr_list_unref (attrs);
4503   g_free (str);
4504 }
4505
4506 static void
4507 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
4508                                 const GtkTextIter *location,
4509                                 GtkTextMark       *mark,
4510                                 gpointer           data)
4511 {
4512   GtkTextView *text_view = GTK_TEXT_VIEW (data);
4513   gboolean need_reset = FALSE;
4514
4515   if (mark == gtk_text_buffer_get_insert (buffer))
4516     {
4517       text_view->virtual_cursor_x = -1;
4518       text_view->virtual_cursor_y = -1;
4519       need_reset = TRUE;
4520     }
4521   else if (mark == gtk_text_buffer_get_selection_bound (buffer))
4522     {
4523       need_reset = TRUE;
4524     }
4525
4526   if (need_reset)
4527     gtk_text_view_reset_im_context (text_view);
4528 }
4529
4530 static void
4531 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
4532                                       gint        *x,
4533                                       gint        *y)
4534 {
4535   GdkRectangle strong_pos;
4536   GtkTextIter insert;
4537
4538   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4539                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4540                                                               "insert"));
4541
4542   if ((x && text_view->virtual_cursor_x == -1) ||
4543       (y && text_view->virtual_cursor_y == -1))
4544     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
4545
4546   if (x)
4547     {
4548       if (text_view->virtual_cursor_x != -1)
4549         *x = text_view->virtual_cursor_x;
4550       else
4551         *x = strong_pos.x;
4552     }
4553
4554   if (y)
4555     {
4556       if (text_view->virtual_cursor_x != -1)
4557         *y = text_view->virtual_cursor_y;
4558       else
4559         *y = strong_pos.y + strong_pos.height / 2;
4560     }
4561 }
4562
4563 static void
4564 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
4565                                       gint         x,
4566                                       gint         y)
4567 {
4568   GdkRectangle strong_pos;
4569   GtkTextIter insert;
4570
4571   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
4572                                     gtk_text_buffer_get_mark (get_buffer (text_view),
4573                                                               "insert"));
4574
4575   if (x == -1 || y == -1)
4576     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
4577
4578   text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
4579   text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
4580 }
4581
4582 /* Quick hack of a popup menu
4583  */
4584 static void
4585 activate_cb (GtkWidget   *menuitem,
4586              GtkTextView *text_view)
4587 {
4588   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
4589   gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal);
4590 }
4591
4592 static void
4593 append_action_signal (GtkTextView  *text_view,
4594                       GtkWidget    *menu,
4595                       const gchar  *label,
4596                       const gchar  *signal)
4597 {
4598   GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
4599
4600   g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
4601   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
4602                       activate_cb, text_view);
4603
4604   gtk_widget_show (menuitem);
4605   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
4606 }
4607
4608 static void
4609 popup_menu_detach (GtkWidget *attach_widget,
4610                    GtkMenu   *menu)
4611 {
4612   GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
4613 }
4614
4615 static void
4616 gtk_text_view_popup_menu (GtkTextView    *text_view,
4617                           GdkEventButton *event)
4618 {
4619   if (!text_view->popup_menu)
4620     {
4621       GtkWidget *menuitem;
4622
4623       text_view->popup_menu = gtk_menu_new ();
4624
4625       gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
4626                                  GTK_WIDGET (text_view),
4627                                  popup_menu_detach);
4628
4629       append_action_signal (text_view, text_view->popup_menu, _("Cut"), "cut_clipboard");
4630       append_action_signal (text_view, text_view->popup_menu, _("Copy"), "copy_clipboard");
4631       append_action_signal (text_view, text_view->popup_menu, _("Paste"), "paste_clipboard");
4632
4633       menuitem = gtk_menu_item_new (); /* Separator */
4634       gtk_widget_show (menuitem);
4635       gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
4636
4637       gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
4638                                             GTK_MENU_SHELL (text_view->popup_menu));
4639     }
4640
4641   gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
4642                   NULL, NULL,
4643                   event->button, event->time);
4644 }
4645
4646
4647
4648 /* Child GdkWindows */
4649
4650
4651 static GtkTextWindow*
4652 text_window_new (GtkTextWindowType  type,
4653                  GtkWidget         *widget,
4654                  gint               width_request,
4655                  gint               height_request)
4656 {
4657   GtkTextWindow *win;
4658
4659   win = g_new (GtkTextWindow, 1);
4660
4661   win->type = type;
4662   win->widget = widget;
4663   win->window = NULL;
4664   win->bin_window = NULL;
4665   win->requisition.width = width_request;
4666   win->requisition.height = height_request;
4667   win->allocation.width = width_request;
4668   win->allocation.height = height_request;
4669   win->allocation.x = 0;
4670   win->allocation.y = 0;
4671
4672   return win;
4673 }
4674
4675 static void
4676 text_window_free (GtkTextWindow *win)
4677 {
4678   if (win->window)
4679     text_window_unrealize (win);
4680
4681   g_free (win);
4682 }
4683
4684 static void
4685 text_window_realize (GtkTextWindow *win,
4686                      GdkWindow     *parent)
4687 {
4688   GdkWindowAttr attributes;
4689   gint attributes_mask;
4690   GdkCursor *cursor;
4691
4692   attributes.window_type = GDK_WINDOW_CHILD;
4693   attributes.x = win->allocation.x;
4694   attributes.y = win->allocation.y;
4695   attributes.width = win->allocation.width;
4696   attributes.height = win->allocation.height;
4697   attributes.wclass = GDK_INPUT_OUTPUT;
4698   attributes.visual = gtk_widget_get_visual (win->widget);
4699   attributes.colormap = gtk_widget_get_colormap (win->widget);
4700   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
4701
4702   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
4703
4704   win->window = gdk_window_new (parent,
4705                                 &attributes,
4706                                 attributes_mask);
4707
4708   gdk_window_show (win->window);
4709   gdk_window_set_user_data (win->window, win->widget);
4710
4711   attributes.x = 0;
4712   attributes.y = 0;
4713   attributes.width = win->allocation.width;
4714   attributes.height = win->allocation.height;
4715   attributes.event_mask = (GDK_EXPOSURE_MASK            |
4716                            GDK_SCROLL_MASK              |
4717                            GDK_KEY_PRESS_MASK           |
4718                            GDK_BUTTON_PRESS_MASK        |
4719                            GDK_BUTTON_RELEASE_MASK      |
4720                            GDK_POINTER_MOTION_MASK      |
4721                            GDK_POINTER_MOTION_HINT_MASK |
4722                            gtk_widget_get_events (win->widget));
4723
4724   win->bin_window = gdk_window_new (win->window,
4725                                     &attributes,
4726                                     attributes_mask);
4727
4728   gdk_window_show (win->bin_window);
4729   gdk_window_set_user_data (win->bin_window, win->widget);
4730
4731   if (win->type == GTK_TEXT_WINDOW_TEXT)
4732     {
4733       /* I-beam cursor */
4734       cursor = gdk_cursor_new (GDK_XTERM);
4735       gdk_window_set_cursor (win->bin_window, cursor);
4736       gdk_cursor_destroy (cursor);
4737
4738       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
4739                                         win->window);
4740
4741
4742       gdk_window_set_background (win->bin_window,
4743                                  &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
4744     }
4745   else
4746     {
4747       gdk_window_set_background (win->bin_window,
4748                                  &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
4749     }
4750
4751   g_object_set_qdata (G_OBJECT (win->window),
4752                       g_quark_from_static_string ("gtk-text-view-text-window"),
4753                       win);
4754
4755   g_object_set_qdata (G_OBJECT (win->bin_window),
4756                       g_quark_from_static_string ("gtk-text-view-text-window"),
4757                       win);
4758 }
4759
4760 static void
4761 text_window_unrealize (GtkTextWindow *win)
4762 {
4763   if (win->type == GTK_TEXT_WINDOW_TEXT)
4764     {
4765       gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
4766                                         NULL);
4767     }
4768
4769   gdk_window_set_user_data (win->window, NULL);
4770   gdk_window_set_user_data (win->bin_window, NULL);
4771   gdk_window_destroy (win->bin_window);
4772   gdk_window_destroy (win->window);
4773   win->window = NULL;
4774   win->bin_window = NULL;
4775 }
4776
4777 static void
4778 text_window_size_allocate (GtkTextWindow *win,
4779                            GdkRectangle  *rect)
4780 {
4781   win->allocation = *rect;
4782
4783   if (win->window)
4784     {
4785       gdk_window_move_resize (win->window,
4786                               rect->x, rect->y,
4787                               rect->width, rect->height);
4788
4789       gdk_window_resize (win->bin_window,
4790                          rect->width, rect->height);
4791     }
4792 }
4793
4794 static void
4795 text_window_scroll        (GtkTextWindow *win,
4796                            gint           dx,
4797                            gint           dy)
4798 {
4799   if (dx != 0 || dy != 0)
4800     {
4801       gdk_window_scroll (win->bin_window, dx, dy);
4802       gdk_window_process_updates (win->bin_window, TRUE);
4803     }
4804 }
4805
4806 static void
4807 text_window_invalidate_rect (GtkTextWindow *win,
4808                              GdkRectangle  *rect)
4809 {
4810   GdkRectangle window_rect;
4811
4812   gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
4813                                          win->type,
4814                                          rect->x,
4815                                          rect->y,
4816                                          &window_rect.x,
4817                                          &window_rect.y);
4818
4819   window_rect.width = rect->width;
4820   window_rect.height = rect->height;
4821   
4822   /* Adjust the rect as appropriate */
4823   
4824   switch (win->type)
4825     {
4826     case GTK_TEXT_WINDOW_TEXT:
4827       break;
4828
4829     case GTK_TEXT_WINDOW_LEFT:
4830     case GTK_TEXT_WINDOW_RIGHT:
4831       window_rect.x = 0;
4832       window_rect.width = win->allocation.width;
4833       break;
4834
4835     case GTK_TEXT_WINDOW_TOP:
4836     case GTK_TEXT_WINDOW_BOTTOM:
4837       window_rect.y = 0;
4838       window_rect.height = win->allocation.height;
4839       break;
4840
4841     default:
4842       g_warning ("%s: bug!", G_STRLOC);
4843       return;
4844       break;
4845     }
4846           
4847   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
4848 }
4849
4850 static gint
4851 text_window_get_width (GtkTextWindow *win)
4852 {
4853   return win->allocation.width;
4854 }
4855
4856 static gint
4857 text_window_get_height (GtkTextWindow *win)
4858 {
4859   return win->allocation.height;
4860 }
4861
4862 static void
4863 text_window_get_allocation (GtkTextWindow *win,
4864                             GdkRectangle  *rect)
4865 {
4866   *rect = win->allocation;
4867 }
4868
4869 /* Windows */
4870
4871
4872 /**
4873  * gtk_text_view_get_window:
4874  * @text_view: a #GtkTextView
4875  * @win: window to get
4876  *
4877  * Retrieves the #GdkWindow corresponding to an area of the text view;
4878  * possible windows include the overall widget window, child windows
4879  * on the left, right, top, bottom, and the window that displays the
4880  * text buffer. Windows are %NULL and nonexistent if their width or
4881  * height is 0, and are nonexistent before the widget has been
4882  * realized.
4883  *
4884  * Return value: a #GdkWindow, or %NULL
4885  **/
4886 GdkWindow*
4887 gtk_text_view_get_window (GtkTextView *text_view,
4888                           GtkTextWindowType win)
4889 {
4890   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
4891
4892   switch (win)
4893     {
4894     case GTK_TEXT_WINDOW_WIDGET:
4895       return GTK_WIDGET (text_view)->window;
4896       break;
4897
4898     case GTK_TEXT_WINDOW_TEXT:
4899       return text_view->text_window->bin_window;
4900       break;
4901
4902     case GTK_TEXT_WINDOW_LEFT:
4903       if (text_view->left_window)
4904         return text_view->left_window->bin_window;
4905       else
4906         return NULL;
4907       break;
4908
4909     case GTK_TEXT_WINDOW_RIGHT:
4910       if (text_view->right_window)
4911         return text_view->right_window->bin_window;
4912       else
4913         return NULL;
4914       break;
4915
4916     case GTK_TEXT_WINDOW_TOP:
4917       if (text_view->top_window)
4918         return text_view->top_window->bin_window;
4919       else
4920         return NULL;
4921       break;
4922
4923     case GTK_TEXT_WINDOW_BOTTOM:
4924       if (text_view->bottom_window)
4925         return text_view->bottom_window->bin_window;
4926       else
4927         return NULL;
4928       break;
4929
4930     default:
4931       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
4932       return NULL;
4933       break;
4934     }
4935 }
4936
4937 /**
4938  * gtk_text_view_get_window_type:
4939  * @text_view: a #GtkTextView
4940  * @window: a window type
4941  *
4942  * Usually used to find out which window an event corresponds to.
4943  * If you connect to an event signal on @text_view, this function
4944  * should be called on <literal>event-&gt;window</literal> to
4945  * see which window it was.
4946  *
4947  * Return value: the window type.
4948  **/
4949 GtkTextWindowType
4950 gtk_text_view_get_window_type (GtkTextView *text_view,
4951                                GdkWindow   *window)
4952 {
4953   GtkTextWindow *win;
4954
4955   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
4956   g_return_val_if_fail (GDK_IS_WINDOW (text_view), 0);
4957
4958   if (window == GTK_WIDGET (text_view)->window)
4959     return GTK_TEXT_WINDOW_WIDGET;
4960
4961   win = g_object_get_qdata (G_OBJECT (window),
4962                             g_quark_try_string ("gtk-text-view-text-window"));
4963
4964   if (win)
4965     return win->type;
4966   else
4967     {
4968       return GTK_TEXT_WINDOW_PRIVATE;
4969     }
4970 }
4971
4972 static void
4973 buffer_to_widget (GtkTextView      *text_view,
4974                   gint              buffer_x,
4975                   gint              buffer_y,
4976                   gint             *window_x,
4977                   gint             *window_y)
4978 {
4979   if (window_x)
4980     {
4981       *window_x = buffer_x - text_view->xoffset + FOCUS_EDGE_WIDTH;
4982       if (text_view->left_window)
4983         *window_x += text_view->left_window->allocation.width;
4984     }
4985
4986   if (window_y)
4987     {
4988       *window_y = buffer_y - text_view->yoffset + FOCUS_EDGE_WIDTH;
4989       if (text_view->top_window)
4990         *window_y += text_view->top_window->allocation.height;
4991     }
4992 }
4993
4994 static void
4995 widget_to_text_window (GtkTextWindow *win,
4996                        gint           widget_x,
4997                        gint           widget_y,
4998                        gint          *window_x,
4999                        gint          *window_y)
5000 {
5001   if (window_x)
5002     *window_x = widget_x - win->allocation.x;
5003
5004   if (window_y)
5005     *window_y = widget_y - win->allocation.y;
5006 }
5007
5008 static void
5009 buffer_to_text_window (GtkTextView   *text_view,
5010                        GtkTextWindow *win,
5011                        gint           buffer_x,
5012                        gint           buffer_y,
5013                        gint          *window_x,
5014                        gint          *window_y)
5015 {
5016   if (win == NULL)
5017     {
5018       g_warning ("Attempt to convert text buffer coordinates to coordinates "
5019                  "for a nonexistent or private child window of GtkTextView");
5020       return;
5021     }
5022
5023   buffer_to_widget (text_view,
5024                     buffer_x, buffer_y,
5025                     window_x, window_y);
5026
5027   widget_to_text_window (win,
5028                          window_x ? *window_x : 0,
5029                          window_y ? *window_y : 0,
5030                          window_x,
5031                          window_y);
5032 }
5033
5034 /**
5035  * gtk_text_view_buffer_to_window_coords:
5036  * @text_view: a #GtkTextView
5037  * @win: a #GtkTextWindowType
5038  * @buffer_x: buffer x coordinate
5039  * @buffer_y: buffer y coordinate
5040  * @window_x: window x coordinate return location
5041  * @window_y: window y coordinate return location
5042  *
5043  * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
5044  * @win, and stores the result in (@window_x, @window_y).
5045  **/
5046 void
5047 gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
5048                                        GtkTextWindowType win,
5049                                        gint              buffer_x,
5050                                        gint              buffer_y,
5051                                        gint             *window_x,
5052                                        gint             *window_y)
5053 {
5054   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5055
5056   switch (win)
5057     {
5058     case GTK_TEXT_WINDOW_WIDGET:
5059       buffer_to_widget (text_view,
5060                         buffer_x, buffer_y,
5061                         window_x, window_y);
5062       break;
5063
5064     case GTK_TEXT_WINDOW_TEXT:
5065       if (window_x)
5066         *window_x = buffer_x - text_view->xoffset;
5067       if (window_y)
5068         *window_y = buffer_y - text_view->yoffset;
5069       break;
5070
5071     case GTK_TEXT_WINDOW_LEFT:
5072       buffer_to_text_window (text_view,
5073                              text_view->left_window,
5074                              buffer_x, buffer_y,
5075                              window_x, window_y);
5076       break;
5077
5078     case GTK_TEXT_WINDOW_RIGHT:
5079       buffer_to_text_window (text_view,
5080                              text_view->right_window,
5081                              buffer_x, buffer_y,
5082                              window_x, window_y);
5083       break;
5084
5085     case GTK_TEXT_WINDOW_TOP:
5086       buffer_to_text_window (text_view,
5087                              text_view->top_window,
5088                              buffer_x, buffer_y,
5089                              window_x, window_y);
5090       break;
5091
5092     case GTK_TEXT_WINDOW_BOTTOM:
5093       buffer_to_text_window (text_view,
5094                              text_view->bottom_window,
5095                              buffer_x, buffer_y,
5096                              window_x, window_y);
5097       break;
5098
5099     case GTK_TEXT_WINDOW_PRIVATE:
5100       g_warning ("%s: can't get coords for private windows", G_STRLOC);
5101       break;
5102
5103     default:
5104       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
5105       break;
5106     }
5107 }
5108
5109 static void
5110 widget_to_buffer (GtkTextView *text_view,
5111                   gint         widget_x,
5112                   gint         widget_y,
5113                   gint        *buffer_x,
5114                   gint        *buffer_y)
5115 {
5116   if (buffer_x)
5117     {
5118       *buffer_x = widget_x - FOCUS_EDGE_WIDTH + text_view->xoffset;
5119       if (text_view->left_window)
5120         *buffer_x -= text_view->left_window->allocation.width;
5121     }
5122
5123   if (buffer_y)
5124     {
5125       *buffer_y = widget_y - FOCUS_EDGE_WIDTH + text_view->yoffset;
5126       if (text_view->top_window)
5127         *buffer_y -= text_view->top_window->allocation.height;
5128     }
5129 }
5130
5131 static void
5132 text_window_to_widget (GtkTextWindow *win,
5133                        gint           window_x,
5134                        gint           window_y,
5135                        gint          *widget_x,
5136                        gint          *widget_y)
5137 {
5138   if (widget_x)
5139     *widget_x = window_x + win->allocation.x;
5140
5141   if (widget_y)
5142     *widget_y = window_y + win->allocation.y;
5143 }
5144
5145 static void
5146 text_window_to_buffer (GtkTextView   *text_view,
5147                        GtkTextWindow *win,
5148                        gint           window_x,
5149                        gint           window_y,
5150                        gint          *buffer_x,
5151                        gint          *buffer_y)
5152 {
5153   if (win == NULL)
5154     {
5155       g_warning ("Attempt to convert GtkTextView buffer coordinates into "
5156                  "coordinates for a nonexistent child window.");
5157       return;
5158     }
5159
5160   text_window_to_widget (win,
5161                          window_x,
5162                          window_y,
5163                          buffer_x,
5164                          buffer_y);
5165
5166   widget_to_buffer (text_view,
5167                     buffer_x ? *buffer_x : 0,
5168                     buffer_y ? *buffer_y : 0,
5169                     buffer_x,
5170                     buffer_y);
5171 }
5172
5173 /**
5174  * gtk_text_view_window_to_buffer_coords:
5175  * @text_view: a #GtkTextView
5176  * @win: a #GtkTextWindowType
5177  * @window_x: window x coordinate
5178  * @window_y: window y coordinate
5179  * @buffer_x: buffer x coordinate return location
5180  * @buffer_y: buffer y coordinate return location
5181  *
5182  * Converts coordinates on the window identified by @win to buffer
5183  * coordinates, storing the result in (@buffer_x,@buffer_y).
5184  **/
5185 void
5186 gtk_text_view_window_to_buffer_coords (GtkTextView      *text_view,
5187                                        GtkTextWindowType win,
5188                                        gint              window_x,
5189                                        gint              window_y,
5190                                        gint             *buffer_x,
5191                                        gint             *buffer_y)
5192 {
5193   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5194
5195   switch (win)
5196     {
5197     case GTK_TEXT_WINDOW_WIDGET:
5198       widget_to_buffer (text_view,
5199                         window_x, window_y,
5200                         buffer_x, buffer_y);
5201       break;
5202
5203     case GTK_TEXT_WINDOW_TEXT:
5204       if (buffer_x)
5205         *buffer_x = window_x + text_view->xoffset;
5206       if (buffer_y)
5207         *buffer_y = window_y + text_view->yoffset;
5208       break;
5209
5210     case GTK_TEXT_WINDOW_LEFT:
5211       text_window_to_buffer (text_view,
5212                              text_view->left_window,
5213                              window_x, window_y,
5214                              buffer_x, buffer_y);
5215       break;
5216
5217     case GTK_TEXT_WINDOW_RIGHT:
5218       text_window_to_buffer (text_view,
5219                              text_view->right_window,
5220                              window_x, window_y,
5221                              buffer_x, buffer_y);
5222       break;
5223
5224     case GTK_TEXT_WINDOW_TOP:
5225       text_window_to_buffer (text_view,
5226                              text_view->top_window,
5227                              window_x, window_y,
5228                              buffer_x, buffer_y);
5229       break;
5230
5231     case GTK_TEXT_WINDOW_BOTTOM:
5232       text_window_to_buffer (text_view,
5233                              text_view->bottom_window,
5234                              window_x, window_y,
5235                              buffer_x, buffer_y);
5236       break;
5237
5238     case GTK_TEXT_WINDOW_PRIVATE:
5239       g_warning ("%s: can't get coords for private windows", G_STRLOC);
5240       break;
5241
5242     default:
5243       g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
5244       break;
5245     }
5246 }
5247
5248 static void
5249 set_window_width (GtkTextView      *text_view,
5250                   gint              width,
5251                   GtkTextWindowType type,
5252                   GtkTextWindow   **winp)
5253 {
5254   if (width == 0)
5255     {
5256       if (*winp)
5257         {
5258           text_window_free (*winp);
5259           *winp = NULL;
5260           gtk_widget_queue_resize (GTK_WIDGET (text_view));
5261         }
5262     }
5263   else
5264     {
5265       if (*winp == NULL)
5266         {
5267           *winp = text_window_new (type,
5268                                    GTK_WIDGET (text_view),
5269                                    width, 0);
5270         }
5271       else
5272         {
5273           if ((*winp)->requisition.width == width)
5274             return;
5275         }
5276
5277       gtk_widget_queue_resize (GTK_WIDGET (text_view));
5278     }
5279 }
5280
5281
5282 static void
5283 set_window_height (GtkTextView      *text_view,
5284                    gint              height,
5285                    GtkTextWindowType type,
5286                    GtkTextWindow   **winp)
5287 {
5288   if (height == 0)
5289     {
5290       if (*winp)
5291         {
5292           text_window_free (*winp);
5293           *winp = NULL;
5294           gtk_widget_queue_resize (GTK_WIDGET (text_view));
5295         }
5296     }
5297   else
5298     {
5299       if (*winp == NULL)
5300         {
5301           *winp = text_window_new (type,
5302                                    GTK_WIDGET (text_view),
5303                                    0, height);
5304         }
5305       else
5306         {
5307           if ((*winp)->requisition.height == height)
5308             return;
5309         }
5310
5311       gtk_widget_queue_resize (GTK_WIDGET (text_view));
5312     }
5313 }
5314
5315 /**
5316  * gtk_text_view_set_border_window_size:
5317  * @text_view: a #GtkTextView
5318  * @type: window to affect
5319  * @size: width or height of the window
5320  *
5321  * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
5322  * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
5323  * Automatically destroys the corresponding window if the size is set to 0,
5324  * and creates the window if the size is set to non-zero.
5325  **/
5326 void
5327 gtk_text_view_set_border_window_size (GtkTextView      *text_view,
5328                                       GtkTextWindowType type,
5329                                       gint              size)
5330
5331 {
5332   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5333   g_return_if_fail (size >= 0);
5334   g_return_if_fail (type != GTK_TEXT_WINDOW_WIDGET);
5335   g_return_if_fail (type != GTK_TEXT_WINDOW_TEXT);
5336
5337   switch (type)
5338     {
5339     case GTK_TEXT_WINDOW_LEFT:
5340       set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
5341                         &text_view->left_window);
5342       break;
5343
5344     case GTK_TEXT_WINDOW_RIGHT:
5345       set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
5346                         &text_view->right_window);
5347       break;
5348
5349     case GTK_TEXT_WINDOW_TOP:
5350       set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
5351                          &text_view->top_window);
5352       break;
5353
5354     case GTK_TEXT_WINDOW_BOTTOM:
5355       set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
5356                          &text_view->bottom_window);
5357       break;
5358
5359     default:
5360       g_warning ("Can't set size of center or widget or private GtkTextWindowType in %s", G_STRLOC);
5361       break;
5362     }
5363 }
5364
5365 /**
5366  * gtk_text_view_set_text_window_size:
5367  * @text_view: a #GtkTextView
5368  * @width: a width in pixels
5369  * @height: a height in pixels
5370  *
5371  * Sets the size request for the main text window (%GTK_TEXT_WINDOW_TEXT).
5372  * If the widget gets more space than it requested, the main text window
5373  * will be larger than this.
5374  *
5375  **/
5376 void
5377 gtk_text_view_set_text_window_size (GtkTextView *text_view,
5378                                     gint         width,
5379                                     gint         height)
5380 {
5381   GtkTextWindow *win;
5382
5383   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5384   g_return_if_fail (width > 0);
5385   g_return_if_fail (height > 0);
5386
5387   win = text_view->text_window;
5388
5389   if (win->requisition.width == width &&
5390       win->requisition.height == height)
5391     return;
5392
5393   win->requisition.width = width;
5394   win->requisition.height = height;
5395
5396   gtk_widget_queue_resize (GTK_WIDGET (text_view));
5397 }
5398
5399 /*
5400  * Child widgets
5401  */
5402
5403 static GtkTextViewChild*
5404 text_view_child_new_anchored (GtkWidget          *child,
5405                               GtkTextChildAnchor *anchor,
5406                               GtkTextLayout      *layout)
5407 {
5408   GtkTextViewChild *vc;
5409
5410   vc = g_new (GtkTextViewChild, 1);
5411
5412   vc->widget = child;
5413   vc->anchor = anchor;
5414
5415   vc->from_top_of_line = 0;
5416   vc->from_left_of_buffer = 0;
5417   
5418   g_object_ref (G_OBJECT (vc->widget));
5419   g_object_ref (G_OBJECT (vc->anchor));
5420
5421   g_object_set_data (G_OBJECT (child),
5422                      "gtk-text-view-child",
5423                      vc);
5424
5425   gtk_text_child_anchor_register_child (anchor, child, layout);
5426   
5427   return vc;
5428 }
5429
5430 static GtkTextViewChild*
5431 text_view_child_new_window (GtkWidget          *child,
5432                             GtkTextWindowType   type,
5433                             gint                x,
5434                             gint                y)
5435 {
5436   GtkTextViewChild *vc;
5437
5438   vc = g_new (GtkTextViewChild, 1);
5439
5440   vc->widget = child;
5441   vc->anchor = NULL;
5442
5443   vc->from_top_of_line = 0;
5444   vc->from_left_of_buffer = 0;
5445   
5446   g_object_ref (G_OBJECT (vc->widget));
5447
5448   vc->type = type;
5449   vc->x = x;
5450   vc->y = y;
5451
5452   return vc;
5453 }
5454
5455 static void
5456 text_view_child_free (GtkTextViewChild *child)
5457 {
5458   g_object_set_data (G_OBJECT (child->widget),
5459                      "gtk-text-view-child", NULL);
5460
5461   if (child->anchor)
5462     {
5463       gtk_text_child_anchor_unregister_child (child->anchor,
5464                                               child->widget);
5465       g_object_unref (G_OBJECT (child->anchor));
5466     }
5467
5468   g_object_unref (G_OBJECT (child->widget));
5469
5470   g_free (child);
5471 }
5472
5473 static void
5474 text_view_child_realize (GtkTextView      *text_view,
5475                          GtkTextViewChild *vc)
5476 {
5477   if (vc->anchor)
5478     gtk_widget_set_parent_window (vc->widget,
5479                                   text_view->text_window->bin_window);
5480   else
5481     {
5482       GdkWindow *window;
5483       window = gtk_text_view_get_window (text_view,
5484                                          vc->type);
5485       gtk_widget_set_parent_window (vc->widget, window);
5486     }
5487
5488   gtk_widget_realize (vc->widget);
5489 }
5490
5491 static void
5492 add_child (GtkTextView      *text_view,
5493            GtkTextViewChild *vc)
5494 {
5495   text_view->children = g_slist_prepend (text_view->children,
5496                                          vc);
5497
5498   gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
5499
5500   if (GTK_WIDGET_REALIZED (text_view))
5501     text_view_child_realize (text_view, vc);
5502
5503   if (GTK_WIDGET_VISIBLE (text_view) && GTK_WIDGET_VISIBLE (vc->widget))
5504     {
5505       if (GTK_WIDGET_MAPPED (text_view))
5506         gtk_widget_map (vc->widget);
5507
5508       gtk_widget_queue_resize (vc->widget);
5509     }
5510 }
5511
5512 void
5513 gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
5514                                    GtkWidget            *child,
5515                                    GtkTextChildAnchor   *anchor)
5516 {
5517   GtkTextViewChild *vc;
5518
5519   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5520   g_return_if_fail (GTK_IS_WIDGET (child));
5521   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5522   g_return_if_fail (child->parent == NULL);
5523
5524   gtk_text_view_ensure_layout (text_view);
5525
5526   vc = text_view_child_new_anchored (child, anchor,
5527                                      text_view->layout);
5528
5529   add_child (text_view, vc);
5530 }
5531
5532 void
5533 gtk_text_view_add_child_in_window (GtkTextView          *text_view,
5534                                    GtkWidget            *child,
5535                                    GtkTextWindowType     which_window,
5536                                    gint                  xpos,
5537                                    gint                  ypos)
5538 {
5539   GtkTextViewChild *vc;
5540
5541   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5542   g_return_if_fail (GTK_IS_WIDGET (child));
5543   g_return_if_fail (xpos >= 0);
5544   g_return_if_fail (ypos >= 0);
5545   g_return_if_fail (child->parent == NULL);
5546
5547   vc = text_view_child_new_window (child, which_window,
5548                                    xpos, ypos);
5549
5550   add_child (text_view, vc);
5551 }
5552
5553 void
5554 gtk_text_view_move_child          (GtkTextView          *text_view,
5555                                    GtkWidget            *child,
5556                                    gint                  xpos,
5557                                    gint                  ypos)
5558 {
5559   GtkTextViewChild *vc;
5560
5561   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
5562   g_return_if_fail (GTK_IS_WIDGET (child));
5563   g_return_if_fail (xpos >= 0);
5564   g_return_if_fail (ypos >= 0);
5565   g_return_if_fail (child->parent == (GtkWidget*) text_view);
5566
5567   vc = g_object_get_data (G_OBJECT (child),
5568                           "gtk-text-view-child");
5569
5570   g_assert (vc != NULL);
5571
5572   vc->x = xpos;
5573   vc->y = ypos;
5574
5575   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
5576     gtk_widget_queue_resize (child);
5577 }
5578
5579
5580
5581 /* Iterator operations */
5582
5583 gboolean
5584 gtk_text_view_forward_display_line (GtkTextView *text_view,
5585                                     GtkTextIter *iter)
5586 {
5587   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5588   g_return_val_if_fail (iter != NULL, FALSE);
5589
5590   gtk_text_view_ensure_layout (text_view);
5591
5592   return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
5593 }
5594
5595 gboolean
5596 gtk_text_view_backward_display_line (GtkTextView *text_view,
5597                                      GtkTextIter *iter)
5598 {
5599   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5600   g_return_val_if_fail (iter != NULL, FALSE);
5601
5602   gtk_text_view_ensure_layout (text_view);
5603
5604   return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
5605 }
5606
5607 gboolean
5608 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
5609                                         GtkTextIter *iter)
5610 {
5611   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5612   g_return_val_if_fail (iter != NULL, FALSE);
5613
5614   gtk_text_view_ensure_layout (text_view);
5615
5616   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
5617 }
5618
5619 gboolean
5620 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
5621                                            GtkTextIter *iter)
5622 {
5623   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5624   g_return_val_if_fail (iter != NULL, FALSE);
5625
5626   gtk_text_view_ensure_layout (text_view);
5627
5628   return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
5629 }
5630
5631 gboolean
5632 gtk_text_view_starts_display_line (GtkTextView       *text_view,
5633                                    const GtkTextIter *iter)
5634 {
5635   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5636   g_return_val_if_fail (iter != NULL, FALSE);
5637
5638   gtk_text_view_ensure_layout (text_view);
5639
5640   return gtk_text_layout_iter_starts_line (text_view->layout, iter);
5641 }
5642
5643 gboolean
5644 gtk_text_view_move_visually (GtkTextView *text_view,
5645                              GtkTextIter *iter,
5646                              gint         count)
5647 {
5648   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
5649   g_return_val_if_fail (iter != NULL, FALSE);
5650
5651   gtk_text_view_ensure_layout (text_view);
5652
5653   return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
5654 }
5655
5656