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