]> Pileus Git - ~andy/gtk/blob - gtk/gtktextview.c
Make this compile without framebuffer enabled
[~andy/gtk] / gtk / gtktextview.c
1 /* gtktext.c - A "view" widget for the GtkTextBuffer object
2  * 
3  * Copyright (c) 1992-1994 The Regents of the University of California.
4  * Copyright (c) 1994-1996 Sun Microsystems, Inc.
5  * Copyright (c) 1999 by Scriptics Corporation.
6  * Copyright (c) 2000      Red Hat, Inc.
7  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
8  *
9  * This software is copyrighted by the Regents of the University of
10  * California, Sun Microsystems, Inc., and other parties.  The
11  * following terms apply to all files associated with the software
12  * unless explicitly disclaimed in individual files.
13  * 
14  * The authors hereby grant permission to use, copy, modify,
15  * distribute, and license this software and its documentation for any
16  * purpose, provided that existing copyright notices are retained in
17  * all copies and that this notice is included verbatim in any
18  * distributions. No written agreement, license, or royalty fee is
19  * required for any of the authorized uses.  Modifications to this
20  * software may be copyrighted by their authors and need not follow
21  * the licensing terms described here, provided that the new terms are
22  * clearly indicated on the first page of each file where they apply.
23  * 
24  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
25  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
26  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
27  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  * 
30  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
31  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
33  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
34  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
35  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
36  *
37  * GOVERNMENT USE: If you are acquiring this software on behalf of the
38  * U.S. government, the Government shall have only "Restricted Rights"
39  * in the software and related documentation as defined in the Federal
40  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
41  * are acquiring the software on behalf of the Department of Defense,
42  * the software shall be classified as "Commercial Computer Software"
43  * and the Government shall have only "Restricted Rights" as defined
44  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
45  * foregoing, the authors grant the U.S. Government and others acting
46  * in its behalf permission to use and distribute the software in
47  * accordance with the terms specified in this license.
48  * 
49  */
50
51 #include "gtkbindings.h"
52 #include "gtkdnd.h"
53 #include "gtkmain.h"
54 #include "gtksignal.h"
55 #include "gtktext.h"
56 #include "gtktextdisplay.h"
57 #include "gtktextview.h"
58 #include "gtkimmulticontext.h"
59 #include "gdk/gdkkeysyms.h"
60
61 enum {
62   MOVE_INSERT,
63   SET_ANCHOR,
64   SCROLL_TEXT,
65   DELETE_TEXT,
66   CUT_TEXT,
67   COPY_TEXT,
68   PASTE_TEXT,
69   TOGGLE_OVERWRITE,
70   SET_SCROLL_ADJUSTMENTS,
71   LAST_SIGNAL
72 };
73
74 enum {
75   ARG_0,
76   ARG_HEIGHT_LINES,
77   ARG_WIDTH_COLUMNS,
78   ARG_PIXELS_ABOVE_LINES,
79   ARG_PIXELS_BELOW_LINES,
80   ARG_PIXELS_INSIDE_WRAP,
81   ARG_EDITABLE,
82   ARG_WRAP_MODE,
83   LAST_ARG
84 };
85
86 static void gtk_text_view_init                 (GtkTextView      *text_view);
87 static void gtk_text_view_class_init           (GtkTextViewClass *klass);
88 static void gtk_text_view_destroy              (GtkObject        *object);
89 static void gtk_text_view_finalize             (GObject          *object);
90 static void gtk_text_view_set_arg              (GtkObject        *object,
91                                                 GtkArg           *arg,
92                                                 guint             arg_id);
93 static void gtk_text_view_get_arg              (GtkObject        *object,
94                                                 GtkArg           *arg,
95                                                 guint             arg_id);
96 static void gtk_text_view_size_request         (GtkWidget        *widget,
97                                                 GtkRequisition   *requisition);
98 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
99                                                 GtkAllocation    *allocation);
100 static void gtk_text_view_realize              (GtkWidget        *widget);
101 static void gtk_text_view_unrealize            (GtkWidget        *widget);
102 static void gtk_text_view_style_set            (GtkWidget        *widget,
103                                                 GtkStyle         *previous_style);
104 static gint gtk_text_view_event                (GtkWidget        *widget,
105                                                 GdkEvent         *event);
106 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
107                                                 GdkEventKey      *event);
108 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
109                                                 GdkEventKey      *event);
110 static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
111                                                 GdkEventButton   *event);
112 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
113                                                 GdkEventButton   *event);
114 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
115                                                 GdkEventFocus    *event);
116 static gint gtk_text_view_focus_out_event      (GtkWidget        *widget,
117                                                 GdkEventFocus    *event);
118 static gint gtk_text_view_motion_event         (GtkWidget        *widget,
119                                                 GdkEventMotion   *event);
120 static void gtk_text_view_draw                 (GtkWidget        *widget,
121                                                 GdkRectangle     *area);
122 static gint gtk_text_view_expose_event         (GtkWidget        *widget,
123                                                 GdkEventExpose   *expose);
124
125
126 /* Source side drag signals */
127 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
128                                             GdkDragContext   *context);
129 static void gtk_text_view_drag_end         (GtkWidget        *widget,
130                                             GdkDragContext   *context);
131 static void gtk_text_view_drag_data_get    (GtkWidget        *widget,
132                                             GdkDragContext   *context,
133                                             GtkSelectionData *selection_data,
134                                             guint             info,
135                                             guint             time);
136 static void gtk_text_view_drag_data_delete (GtkWidget        *widget,
137                                             GdkDragContext   *context);
138
139 /* Target side drag signals */
140 static void     gtk_text_view_drag_leave         (GtkWidget        *widget,
141                                                   GdkDragContext   *context,
142                                                   guint             time);
143 static gboolean gtk_text_view_drag_motion        (GtkWidget        *widget,
144                                                   GdkDragContext   *context,
145                                                   gint              x,
146                                                   gint              y,
147                                                   guint             time);
148 static gboolean gtk_text_view_drag_drop          (GtkWidget        *widget,
149                                                   GdkDragContext   *context,
150                                                   gint              x,
151                                                   gint              y,
152                                                   guint             time);
153 static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
154                                                   GdkDragContext   *context,
155                                                   gint              x,
156                                                   gint              y,
157                                                   GtkSelectionData *selection_data,
158                                                   guint             info,
159                                                   guint             time);
160
161 static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
162                                                   GtkAdjustment *hadj,
163                                                   GtkAdjustment *vadj);
164
165 static void gtk_text_view_move_insert      (GtkTextView             *text_view,
166                                             GtkTextViewMovementStep  step,
167                                             gint                     count,
168                                             gboolean                 extend_selection);
169 static void gtk_text_view_set_anchor       (GtkTextView             *text_view);
170 static void gtk_text_view_scroll_text      (GtkTextView             *text_view,
171                                             GtkTextViewScrollType    type);
172 static void gtk_text_view_delete_text      (GtkTextView             *text_view,
173                                             GtkTextViewDeleteType    type,
174                                             gint                     count);
175 static void gtk_text_view_cut_text         (GtkTextView             *text_view);
176 static void gtk_text_view_copy_text        (GtkTextView             *text_view);
177 static void gtk_text_view_paste_text       (GtkTextView             *text_view);
178 static void gtk_text_view_toggle_overwrite (GtkTextView             *text_view);
179
180
181 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
182 static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_view,
183                                                      GtkTextIter        *iter);
184 static void     gtk_text_view_scroll_calc_now       (GtkTextView        *text_view);
185 static void     gtk_text_view_set_values_from_style (GtkTextView        *text_view,
186                                                      GtkTextStyleValues *values,
187                                                      GtkStyle           *style);
188 static void     gtk_text_view_ensure_layout         (GtkTextView        *text_view);
189 static void     gtk_text_view_destroy_layout        (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                                                      GdkEventButton     *event);
198 static void     gtk_text_view_start_cursor_blink    (GtkTextView        *text_view);
199 static void     gtk_text_view_stop_cursor_blink     (GtkTextView        *text_view);
200
201 static void gtk_text_view_value_changed (GtkAdjustment *adj,
202                                          GtkTextView   *view);
203 static void gtk_text_view_commit_handler            (GtkIMContext  *context,
204                                                      const gchar   *str,
205                                                      GtkTextView   *text_view);
206
207 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
208                                                   const GtkTextIter *location,
209                                                   const char        *mark_name,
210                                                   gpointer           data);
211 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
212                                                   gint              *x,
213                                                   gint              *y);
214 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
215                                                   gint               x,
216                                                   gint               y);
217
218 enum {
219   TARGET_STRING,
220   TARGET_TEXT,
221   TARGET_COMPOUND_TEXT,
222   TARGET_UTF8_STRING
223 };
224
225 static GdkAtom clipboard_atom = GDK_NONE;
226 static GdkAtom text_atom = GDK_NONE;
227 static GdkAtom ctext_atom = GDK_NONE;
228 static GdkAtom utf8_atom = GDK_NONE;
229
230
231 static GtkTargetEntry target_table[] = {
232   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
233   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
234   { "TEXT", 0, TARGET_TEXT },
235   { "text/plain", 0, TARGET_STRING },
236   { "STRING",     0, TARGET_STRING }
237 };
238
239 static guint n_targets = sizeof (target_table) / sizeof (target_table[0]);
240
241 static GtkContainerClass *parent_class = NULL;
242 static guint signals[LAST_SIGNAL] = { 0 };
243
244 GtkType
245 gtk_text_view_get_type (void)
246 {
247   static GtkType our_type = 0;
248
249   if (our_type == 0)
250     {
251       static const GtkTypeInfo our_info =
252       {
253         "GtkTextView",
254         sizeof (GtkTextView),
255         sizeof (GtkTextViewClass),
256         (GtkClassInitFunc) gtk_text_view_class_init,
257         (GtkObjectInitFunc) gtk_text_view_init,
258         /* reserved_1 */ NULL,
259         /* reserved_2 */ NULL,
260         (GtkClassInitFunc) NULL
261       };
262
263     our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
264   }
265
266   return our_type;
267 }
268
269 static void
270 add_move_insert_binding (GtkBindingSet *binding_set,
271                          guint keyval,
272                          guint modmask,
273                          GtkTextViewMovementStep step,
274                          gint count)
275 {
276   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
277   
278   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
279                                 "move_insert", 3,
280                                 GTK_TYPE_ENUM, step,
281                                 GTK_TYPE_INT, count,
282                                 GTK_TYPE_BOOL, FALSE);
283
284   /* Selection-extending version */
285   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
286                                 "move_insert", 3,
287                                 GTK_TYPE_ENUM, step,
288                                 GTK_TYPE_INT, count,
289                                 GTK_TYPE_BOOL, TRUE);
290 }
291
292 static void
293 gtk_text_view_class_init (GtkTextViewClass *klass)
294 {
295   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
296   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
297   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
298   GtkBindingSet *binding_set;
299   
300   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
301
302   /*
303    * Arguments
304    */
305   gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
306                            GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
307   gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
308                            GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
309   gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
310                            GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
311   gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
312                            GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
313   gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
314                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
315   gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
316                            GTK_ARG_READWRITE, ARG_EDITABLE);
317   gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
318                            GTK_ARG_READWRITE, ARG_WRAP_MODE);
319
320
321   /*
322    * Signals
323    */
324
325   signals[MOVE_INSERT] = 
326       gtk_signal_new ("move_insert",
327                       GTK_RUN_LAST | GTK_RUN_ACTION,
328                       GTK_CLASS_TYPE (object_class),
329                       GTK_SIGNAL_OFFSET (GtkTextViewClass, move_insert),
330                       gtk_marshal_NONE__INT_INT_INT,
331                       GTK_TYPE_NONE, 3, GTK_TYPE_ENUM, GTK_TYPE_INT, GTK_TYPE_BOOL);
332
333   signals[SET_ANCHOR] = 
334       gtk_signal_new ("set_anchor",
335                       GTK_RUN_LAST | GTK_RUN_ACTION,
336                       GTK_CLASS_TYPE (object_class),
337                       GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
338                       gtk_marshal_NONE__NONE,
339                       GTK_TYPE_NONE, 0);
340
341   signals[SCROLL_TEXT] = 
342       gtk_signal_new ("scroll_text",
343                       GTK_RUN_LAST | GTK_RUN_ACTION,
344                       GTK_CLASS_TYPE (object_class),
345                       GTK_SIGNAL_OFFSET (GtkTextViewClass, scroll_text),
346                       gtk_marshal_NONE__INT,
347                       GTK_TYPE_NONE, 1, GTK_TYPE_ENUM);
348
349   signals[DELETE_TEXT] = 
350       gtk_signal_new ("delete_text",
351                       GTK_RUN_LAST | GTK_RUN_ACTION,
352                       GTK_CLASS_TYPE (object_class),
353                       GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_text),
354                       gtk_marshal_NONE__INT_INT,
355                       GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_INT);
356
357   signals[CUT_TEXT] =
358     gtk_signal_new ("cut_text",
359                     GTK_RUN_LAST | GTK_RUN_ACTION,
360                     GTK_CLASS_TYPE (object_class),
361                     GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_text),
362                     gtk_marshal_NONE__NONE,
363                     GTK_TYPE_NONE, 0);
364
365   signals[COPY_TEXT] =
366     gtk_signal_new ("copy_text",
367                     GTK_RUN_LAST | GTK_RUN_ACTION,
368                     GTK_CLASS_TYPE (object_class),
369                     GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_text),
370                     gtk_marshal_NONE__NONE,
371                     GTK_TYPE_NONE, 0);
372
373   signals[PASTE_TEXT] =
374     gtk_signal_new ("paste_text",
375                     GTK_RUN_LAST | GTK_RUN_ACTION,
376                     GTK_CLASS_TYPE (object_class),
377                     GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_text),
378                     gtk_marshal_NONE__NONE,
379                     GTK_TYPE_NONE, 0);
380
381   signals[TOGGLE_OVERWRITE] =
382     gtk_signal_new ("toggle_overwrite",
383                     GTK_RUN_LAST | GTK_RUN_ACTION,
384                     GTK_CLASS_TYPE (object_class),
385                     GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
386                     gtk_marshal_NONE__NONE,
387                     GTK_TYPE_NONE, 0);
388
389   signals[SET_SCROLL_ADJUSTMENTS] = widget_class->set_scroll_adjustments_signal =
390     gtk_signal_new ("set_scroll_adjustments",
391                     GTK_RUN_LAST,
392                     GTK_CLASS_TYPE (object_class),
393                     GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
394                     gtk_marshal_NONE__POINTER_POINTER,
395                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
396   
397   gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
398
399   /*
400    * Key bindings
401    */
402
403   binding_set = gtk_binding_set_by_class (klass);
404
405   /* Moving the insertion point */
406   add_move_insert_binding (binding_set, GDK_Right, 0,
407                           GTK_TEXT_MOVEMENT_POSITIONS, 1);
408   
409   add_move_insert_binding (binding_set, GDK_Left, 0,
410                           GTK_TEXT_MOVEMENT_POSITIONS, -1);
411
412   add_move_insert_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
413                           GTK_TEXT_MOVEMENT_CHAR, 1);
414   
415   add_move_insert_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
416                           GTK_TEXT_MOVEMENT_CHAR, -1);
417   
418   add_move_insert_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
419                           GTK_TEXT_MOVEMENT_WORD, 1);
420
421   add_move_insert_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
422                           GTK_TEXT_MOVEMENT_WORD, -1);
423   
424   /* Eventually we want to move by display lines, not paragraphs */
425   add_move_insert_binding (binding_set, GDK_Up, 0,
426                           GTK_TEXT_MOVEMENT_LINE, -1);
427   
428   add_move_insert_binding (binding_set, GDK_Down, 0,
429                           GTK_TEXT_MOVEMENT_LINE, 1);
430
431   add_move_insert_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
432                           GTK_TEXT_MOVEMENT_LINE, -1);
433   
434   add_move_insert_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
435                           GTK_TEXT_MOVEMENT_LINE, 1);
436   
437   add_move_insert_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
438                           GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, -1);
439
440   add_move_insert_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
441                           GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, 1);
442
443   add_move_insert_binding (binding_set, GDK_f, GDK_MOD1_MASK,
444                           GTK_TEXT_MOVEMENT_WORD, 1);
445
446   add_move_insert_binding (binding_set, GDK_b, GDK_MOD1_MASK,
447                           GTK_TEXT_MOVEMENT_WORD, -1);
448
449   add_move_insert_binding (binding_set, GDK_Home, 0,
450                           GTK_TEXT_MOVEMENT_BUFFER_ENDS, -1);
451
452   add_move_insert_binding (binding_set, GDK_End, 0,
453                           GTK_TEXT_MOVEMENT_BUFFER_ENDS, 1);
454   
455   /* Setting the cut/paste/copy anchor */
456   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
457                                 "set_anchor", 0);
458
459   
460   /* Scrolling around */
461   gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
462                                 "scroll_text", 1,
463                                 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_UP);
464
465   gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
466                                 "scroll_text", 1,
467                                 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_DOWN);
468
469   /* Deleting text */
470   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
471                                 "delete_text", 2,
472                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
473                                 GTK_TYPE_INT, 1);
474
475   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
476                                 "delete_text", 2,
477                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
478                                 GTK_TYPE_INT, -1);
479
480   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
481                                 "delete_text", 2,
482                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
483                                 GTK_TYPE_INT, 1);
484
485   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
486                                 "delete_text", 2,
487                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
488                                 GTK_TYPE_INT, -1);
489
490   gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
491                                 "delete_text", 2,
492                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_PARAGRAPH,
493                                 GTK_TYPE_INT, 1);
494
495   gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
496                                 "delete_text", 2,
497                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHOLE_PARAGRAPH,
498                                 GTK_TYPE_INT, 1);
499
500   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
501                                 "delete_text", 2,
502                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE,
503                                 GTK_TYPE_INT, 1);
504
505   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
506                                 "delete_text", 2,
507                                 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE,
508                                 GTK_TYPE_INT, 1);
509   
510   /* Cut/copy/paste */
511
512   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
513                                 "cut_text", 0);
514
515   gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
516                                 "cut_text", 0);
517   
518   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
519                                 "copy_text", 0);
520   
521   gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
522                                 "paste_text", 0);
523
524   /* Overwrite */
525   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
526                                 "toggle_overwrite", 0);
527   
528   /*
529    * Default handlers and virtual methods
530    */
531   object_class->set_arg = gtk_text_view_set_arg;
532   object_class->get_arg = gtk_text_view_get_arg;
533
534   object_class->destroy = gtk_text_view_destroy;
535   gobject_class->finalize = gtk_text_view_finalize;
536
537   widget_class->realize = gtk_text_view_realize;
538   widget_class->unrealize = gtk_text_view_unrealize;
539   widget_class->style_set = gtk_text_view_style_set;
540   widget_class->size_request = gtk_text_view_size_request;
541   widget_class->size_allocate = gtk_text_view_size_allocate;
542   widget_class->event = gtk_text_view_event;
543   widget_class->key_press_event = gtk_text_view_key_press_event;
544   widget_class->key_release_event = gtk_text_view_key_release_event;
545   widget_class->button_press_event = gtk_text_view_button_press_event;
546   widget_class->button_release_event = gtk_text_view_button_release_event;
547   widget_class->focus_in_event = gtk_text_view_focus_in_event;
548   widget_class->focus_out_event = gtk_text_view_focus_out_event;
549   widget_class->motion_notify_event = gtk_text_view_motion_event;
550   widget_class->expose_event = gtk_text_view_expose_event;
551   widget_class->draw = gtk_text_view_draw;
552
553   widget_class->drag_begin = gtk_text_view_drag_begin;
554   widget_class->drag_end = gtk_text_view_drag_end;
555   widget_class->drag_data_get = gtk_text_view_drag_data_get;
556   widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
557
558   widget_class->drag_leave = gtk_text_view_drag_leave;
559   widget_class->drag_motion = gtk_text_view_drag_motion;
560   widget_class->drag_drop = gtk_text_view_drag_drop;
561   widget_class->drag_data_received = gtk_text_view_drag_data_received;
562
563   klass->move_insert = gtk_text_view_move_insert;
564   klass->set_anchor = gtk_text_view_set_anchor;
565   klass->scroll_text = gtk_text_view_scroll_text;
566   klass->delete_text = gtk_text_view_delete_text;
567   klass->cut_text = gtk_text_view_cut_text;
568   klass->copy_text = gtk_text_view_copy_text;
569   klass->paste_text = gtk_text_view_paste_text;
570   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
571   klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
572 }
573
574 void
575 gtk_text_view_init (GtkTextView *text_view)
576 {
577   GtkWidget *widget;
578   
579   widget = GTK_WIDGET (text_view);
580
581   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
582
583   text_view->wrap_mode = GTK_WRAPMODE_NONE;
584
585   if (!clipboard_atom)
586     clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
587
588   if (!text_atom)
589     text_atom = gdk_atom_intern ("TEXT", FALSE);
590
591   if (!ctext_atom)
592     ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
593
594   if (!utf8_atom)
595     utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
596   
597   gtk_drag_dest_set (widget,
598                     GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION,
599                     target_table, n_targets,
600                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
601
602   text_view->virtual_cursor_x = -1;
603   text_view->virtual_cursor_y = -1;
604
605   /* This object is completely private. No external entity can gain a reference
606    * to it; so we create it here and destroy it in finalize().
607    */
608   text_view->im_context = gtk_im_multicontext_new ();
609   
610   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
611                       GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
612 }
613
614 GtkWidget*
615 gtk_text_view_new (void)
616 {
617   return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
618 }
619
620 GtkWidget*
621 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
622 {
623   GtkTextView *text_view;
624
625   text_view = (GtkTextView*)gtk_text_view_new ();
626
627   gtk_text_view_set_buffer (text_view, buffer);
628
629   return GTK_WIDGET (text_view);
630 }
631
632 void
633 gtk_text_view_set_buffer (GtkTextView *text_view,
634                           GtkTextBuffer *buffer)
635 {
636   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
637   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
638   
639   if (text_view->buffer == buffer)
640     return;
641
642   if (text_view->buffer != NULL)
643     {
644       gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer),
645                                      gtk_text_view_mark_set_handler, text_view);
646       gtk_object_unref (GTK_OBJECT (text_view->buffer));
647       text_view->dnd_mark = NULL;
648     }
649
650   text_view->buffer = buffer;
651   
652   if (buffer != NULL)
653     {
654       char *mark_name;
655       
656       GtkTextIter start;
657       
658       gtk_object_ref (GTK_OBJECT (buffer));
659       gtk_object_sink (GTK_OBJECT (buffer));
660
661       if (text_view->layout)
662         gtk_text_layout_set_buffer (text_view->layout, buffer);
663
664       gtk_text_buffer_get_iter_at_char (text_view->buffer, &start, 0);
665       
666       text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
667                                                          "__drag_target",
668                                                          &start, FALSE);
669
670       /* Initialize. FIXME: Allow anonymous marks and use one here
671        */
672       mark_name = g_strdup_printf ("__first_para_%p", text_view);
673       text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
674                                                                 mark_name,
675                                                                 &start, TRUE);
676       g_free (mark_name);
677       text_view->first_para_pixels = 0;
678       
679       gtk_signal_connect (GTK_OBJECT (text_view->buffer), "mark_set",
680                           gtk_text_view_mark_set_handler, text_view);
681     }
682
683   if (GTK_WIDGET_VISIBLE (text_view))    
684     gtk_widget_queue_draw (GTK_WIDGET (text_view));
685 }
686
687 GtkTextBuffer*
688 gtk_text_view_get_buffer (GtkTextView *text_view)
689 {
690   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
691   
692   return text_view->buffer;
693 }
694
695 void
696 gtk_text_view_get_iter_at_pixel (GtkTextView *text_view,
697                                  GtkTextIter *iter,
698                                  gint x, gint y)
699 {
700   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
701   g_return_if_fail (iter != NULL);
702   g_return_if_fail (text_view->layout != NULL);
703
704   gtk_text_layout_get_iter_at_pixel (text_view->layout,
705                                      iter,
706                                      x + text_view->xoffset,
707                                      y + text_view->yoffset);
708 }
709
710
711 static void
712 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
713 {
714   /* We don't really want to clamp to upper; we want to clamp to
715      upper - page_size which is the highest value the scrollbar
716      will let us reach. */
717   if (val > (adj->upper - adj->page_size))
718     val = adj->upper - adj->page_size;
719
720   if (val < adj->lower)
721     val = adj->lower;
722   
723   gtk_adjustment_set_value (adj, val);
724 }
725
726 gboolean
727 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
728                                        GtkTextMark *mark,
729                                        gint margin,
730                                        gfloat percentage)
731 {
732   GtkTextIter iter;
733   GdkRectangle rect;
734   GdkRectangle screen;
735   gint screen_bottom;
736   gint screen_right;
737   GtkWidget *widget;
738   gboolean retval = FALSE;
739   gint scroll_inc;
740
741   gint current_x_scroll, current_y_scroll;
742   
743   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
744   g_return_val_if_fail (mark != NULL, FALSE);
745
746   widget = GTK_WIDGET (text_view);
747   
748   if (!GTK_WIDGET_MAPPED (widget))
749     {
750       g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
751       return FALSE;
752     }
753
754   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
755   
756   gtk_text_layout_get_iter_location (text_view->layout,
757                                      &iter,
758                                      &rect);
759   
760   /* Be sure the scroll region is up-to-date */
761   gtk_text_view_scroll_calc_now (text_view);
762   
763   current_x_scroll = text_view->xoffset;
764   current_y_scroll = text_view->yoffset;
765
766   screen.x = current_x_scroll;
767   screen.y = current_y_scroll;
768   screen.width = widget->allocation.width;
769   screen.height = widget->allocation.height;
770
771   {
772     /* Clamp margin so it's not too large. */
773     gint small_dimension = MIN (screen.width, screen.height);
774     gint max_rect_dim;
775     
776     if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
777       margin = (small_dimension/2 - 5);
778
779     if (margin < 0)
780       margin = 0;
781     
782     /* make sure rectangle fits in the leftover space */
783
784     max_rect_dim = MAX (rect.width, rect.height);
785     
786     if (max_rect_dim > (small_dimension - margin*2))
787       margin -= max_rect_dim - (small_dimension - margin*2);
788                  
789     if (margin < 0)
790       margin = 0;
791   }
792
793   g_assert (margin >= 0);
794   
795   screen.x += margin;
796   screen.y += margin;
797
798   screen.width -= margin*2;
799   screen.height -= margin*2;
800
801   screen_bottom = screen.y + screen.height;
802   screen_right = screen.x + screen.width;
803   
804   /* Vertical scroll (only vertical gets adjusted) */
805
806   scroll_inc = 0;
807   if (rect.y < screen.y)
808     {
809       gint scroll_dest = rect.y;
810       scroll_inc = (scroll_dest - screen.y) * percentage;
811     }
812   else if ((rect.y + rect.height) > screen_bottom)
813     {
814       gint scroll_dest = rect.y + rect.height;
815       scroll_inc = (scroll_dest - screen_bottom) * percentage;
816     }
817
818   if (scroll_inc != 0)
819     {
820       set_adjustment_clamped (text_view->vadjustment,
821                               current_y_scroll + scroll_inc);
822       retval = TRUE;
823     }
824   
825   /* Horizontal scroll */
826
827   scroll_inc = 0;
828   if (rect.x < screen.x)
829     {
830       gint scroll_dest = rect.x;
831       scroll_inc = scroll_dest - screen.x;
832     }
833   else if ((rect.x + rect.width) > screen_right)
834     {
835       gint scroll_dest = rect.x + rect.width;
836       scroll_inc = scroll_dest - screen_right;
837     }
838
839   if (scroll_inc != 0)
840     {
841       set_adjustment_clamped (text_view->hadjustment,
842                               current_x_scroll + scroll_inc);
843       retval = TRUE;
844     }
845
846   return retval;
847 }
848
849 gboolean
850 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
851                               GtkTextMark *mark,
852                               gint mark_within_margin)
853 {
854   g_return_val_if_fail (mark_within_margin >= 0, FALSE);
855   
856   return gtk_text_view_scroll_to_mark_adjusted (text_view, mark,
857                                                 mark_within_margin, 1.0);
858 }
859
860 static gboolean
861 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
862 {
863   GdkRectangle visible_rect;
864   gtk_text_view_get_visible_rect (text_view, &visible_rect);
865
866   return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
867                                                visible_rect.y,
868                                                visible_rect.y + visible_rect.height);
869 }
870
871 gboolean
872 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
873                                   GtkTextMark *mark)
874 {
875   GtkTextIter iter;
876   
877   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
878   g_return_val_if_fail (mark != NULL, FALSE);
879   
880   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
881   
882   if (clamp_iter_onscreen (text_view, &iter))
883     {
884       gtk_text_buffer_move_mark (text_view->buffer, mark, &iter);
885       return TRUE;
886     }
887   else
888     return FALSE;
889 }
890
891 void
892 gtk_text_view_get_visible_rect (GtkTextView  *text_view,
893                                 GdkRectangle *visible_rect)
894 {
895   GtkWidget *widget;
896
897   g_return_if_fail (text_view != NULL);
898   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
899
900   widget = GTK_WIDGET (text_view);
901   
902   if (visible_rect)
903     {
904       visible_rect->x = text_view->xoffset;
905       visible_rect->y = text_view->yoffset;
906       visible_rect->width = widget->allocation.width;
907       visible_rect->height = widget->allocation.height;
908     }
909 }
910
911 void
912 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
913                              GtkWrapMode  wrap_mode)
914 {
915   g_return_if_fail (text_view != NULL);
916   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
917
918   if (text_view->wrap_mode != wrap_mode)
919     {
920       text_view->wrap_mode = wrap_mode;
921
922       if (text_view->layout)
923         {
924           text_view->layout->default_style->wrap_mode = wrap_mode;
925           gtk_text_layout_default_style_changed (text_view->layout);
926         }
927     }
928 }
929
930 GtkWrapMode
931 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
932 {
933   g_return_val_if_fail (text_view != NULL, GTK_WRAPMODE_NONE);
934   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAPMODE_NONE);
935
936   return text_view->wrap_mode;
937 }
938
939 gboolean
940 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
941 {
942   GtkTextIter insert;
943   
944   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
945   
946   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
947                                     gtk_text_buffer_get_mark (text_view->buffer,
948                                                               "insert"));
949   
950   if (clamp_iter_onscreen (text_view, &insert))
951     {
952       gtk_text_buffer_place_cursor (text_view->buffer, &insert);
953       return TRUE;
954     }
955   else
956     return FALSE;
957 }
958
959 static void
960 gtk_text_view_destroy (GtkObject *object)
961 {
962   GtkTextView *text_view;
963
964   text_view = GTK_TEXT_VIEW (object);
965
966   gtk_text_view_destroy_layout (text_view);
967   gtk_text_view_set_buffer (text_view, NULL);
968   
969   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
970 }
971
972 static void
973 gtk_text_view_finalize (GObject *object)
974 {
975   GtkTextView *text_view;
976
977   text_view = GTK_TEXT_VIEW (object);  
978
979   gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
980   gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
981   gtk_object_unref (GTK_OBJECT (text_view->im_context));
982
983   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
984 }
985
986 static void
987 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
988 {
989   GtkTextView *text_view;
990
991   text_view = GTK_TEXT_VIEW (object);
992
993   switch (arg_id)
994     {
995     case ARG_HEIGHT_LINES:
996       break;
997
998     case ARG_WIDTH_COLUMNS:
999       break;
1000
1001     case ARG_PIXELS_ABOVE_LINES:
1002       break;
1003
1004     case ARG_PIXELS_BELOW_LINES:
1005       break;
1006
1007     case ARG_PIXELS_INSIDE_WRAP:
1008       break;
1009
1010     case ARG_EDITABLE:
1011       break;
1012
1013     case ARG_WRAP_MODE:
1014       break;
1015
1016     default:
1017       g_assert_not_reached ();
1018       break;
1019     }
1020 }
1021
1022 static void
1023 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1024 {
1025   GtkTextView *text_view;
1026
1027   text_view = GTK_TEXT_VIEW (object);
1028
1029   switch (arg_id)
1030     {
1031     case ARG_HEIGHT_LINES:
1032       break;
1033
1034     case ARG_WIDTH_COLUMNS:
1035       break;
1036
1037     case ARG_PIXELS_ABOVE_LINES:
1038       break;
1039
1040     case ARG_PIXELS_BELOW_LINES:
1041       break;
1042
1043     case ARG_PIXELS_INSIDE_WRAP:
1044       break;
1045
1046     case ARG_EDITABLE:
1047       break;
1048
1049     case ARG_WRAP_MODE:
1050       break;
1051
1052     default:
1053       arg->type = GTK_TYPE_INVALID;
1054       break;
1055     }
1056 }
1057
1058 static void
1059 gtk_text_view_size_request (GtkWidget      *widget,
1060                             GtkRequisition *requisition)
1061 {
1062   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1063   
1064   /* Hrm */
1065   requisition->width = 1;
1066   requisition->height = 1;
1067
1068   /* Check to see if the widget direction has changed */
1069
1070   if (text_view->layout)
1071     {
1072       GtkTextDirection direction = gtk_widget_get_direction (widget);
1073       if (direction != text_view->layout->default_style->direction)
1074         {
1075           text_view->layout->default_style->direction = direction;
1076           gtk_text_layout_default_style_changed (text_view->layout);      
1077         }
1078     }
1079 }
1080
1081 static void
1082 gtk_text_view_size_allocate (GtkWidget *widget,
1083                              GtkAllocation *allocation)
1084 {
1085   GtkTextView *text_view;
1086   GtkTextIter first_para;
1087   gint y;
1088   GtkAdjustment *vadj;
1089   gboolean yoffset_changed = FALSE;
1090
1091   text_view = GTK_TEXT_VIEW (widget);
1092   
1093   widget->allocation = *allocation;
1094   
1095   if (GTK_WIDGET_REALIZED (widget))
1096     {
1097       gdk_window_move_resize (widget->window,
1098                               allocation->x, allocation->y,
1099                               allocation->width, allocation->height);
1100
1101       gdk_window_resize (text_view->bin_window,
1102                          allocation->width, allocation->height);
1103     }
1104
1105   gtk_text_view_ensure_layout (text_view);
1106   gtk_text_layout_set_screen_width (text_view->layout,
1107                                     GTK_WIDGET (text_view)->allocation.width);
1108       
1109   gtk_text_view_validate_onscreen (text_view);
1110   gtk_text_view_scroll_calc_now (text_view);
1111
1112   /* Now adjust the value of the adjustment to keep the cursor at the same place in
1113    * the buffer 
1114   */
1115   gtk_text_view_get_first_para_iter (text_view, &first_para);
1116   y = gtk_text_layout_get_line_y (text_view->layout, &first_para) + text_view->first_para_pixels;
1117
1118   vadj = text_view->vadjustment;
1119   if (y > vadj->upper - vadj->page_size)
1120     y = MAX (0, vadj->upper - vadj->page_size);
1121
1122   if (y != text_view->yoffset)
1123     {
1124       vadj->value = text_view->yoffset = y;
1125       yoffset_changed = TRUE;
1126     }
1127
1128   text_view->hadjustment->page_size = allocation->width;
1129   text_view->hadjustment->page_increment = allocation->width / 2;
1130   text_view->hadjustment->lower = 0;
1131   text_view->hadjustment->upper = MAX (allocation->width, text_view->width);
1132   gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
1133
1134   text_view->vadjustment->page_size = allocation->height;
1135   text_view->vadjustment->page_increment = allocation->height / 2;
1136   text_view->vadjustment->lower = 0;
1137   text_view->vadjustment->upper = MAX (allocation->height, text_view->height);
1138   gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
1139
1140   if (yoffset_changed)
1141     gtk_adjustment_value_changed (vadj);
1142 }
1143
1144 static void
1145 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
1146                                    GtkTextIter *iter)
1147 {
1148   gtk_text_buffer_get_iter_at_mark (text_view->buffer, iter,
1149                                     text_view->first_para_mark);
1150 }
1151
1152 static void
1153 gtk_text_view_validate_onscreen (GtkTextView *text_view)
1154 {
1155   GtkWidget *widget = GTK_WIDGET (text_view);
1156   
1157   if (widget->allocation.height > 0)
1158     {
1159       GtkTextIter first_para;
1160       gtk_text_view_get_first_para_iter (text_view, &first_para);
1161       gtk_text_layout_validate_yrange (text_view->layout,
1162                                        &first_para,
1163                                        0, text_view->first_para_pixels + widget->allocation.height);
1164     }
1165 }
1166
1167 static gboolean
1168 first_validate_callback (gpointer data)
1169 {
1170   GtkTextView *text_view = data;
1171
1172   gtk_text_view_validate_onscreen (text_view);
1173   
1174   text_view->first_validate_idle = 0;
1175   return FALSE;
1176 }
1177
1178 static gboolean
1179 incremental_validate_callback (gpointer data)
1180 {
1181   GtkTextView *text_view = data;
1182
1183   gtk_text_layout_validate (text_view->layout, 2000);
1184   if (gtk_text_layout_is_valid (text_view->layout))
1185     {
1186       text_view->incremental_validate_idle = 0;
1187       return FALSE;
1188     }
1189   else
1190     return TRUE;
1191 }
1192
1193 static void
1194 invalidated_handler (GtkTextLayout *layout,
1195                      gpointer       data)
1196 {
1197   GtkTextView *text_view;
1198
1199   text_view = GTK_TEXT_VIEW (data);
1200
1201   if (!text_view->first_validate_idle)
1202     text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
1203
1204   if (!text_view->incremental_validate_idle)
1205     text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
1206 }
1207
1208 static void
1209 changed_handler (GtkTextLayout *layout,
1210                  gint           start_y,
1211                  gint           old_height,
1212                  gint           new_height,
1213                  gpointer       data)
1214 {
1215   GtkTextView *text_view;
1216   GtkWidget *widget;
1217   GdkRectangle visible_rect;
1218   GdkRectangle redraw_rect;
1219   
1220   text_view = GTK_TEXT_VIEW (data);
1221   widget = GTK_WIDGET (data);
1222
1223   if (GTK_WIDGET_REALIZED (text_view))
1224     {
1225       gtk_text_view_get_visible_rect (text_view, &visible_rect);
1226       
1227       redraw_rect.x = visible_rect.x;
1228       redraw_rect.width = visible_rect.width;
1229       redraw_rect.y = start_y;
1230       redraw_rect.height = MAX (old_height, new_height);
1231       
1232       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
1233         {
1234           redraw_rect.y -= text_view->yoffset;
1235           gdk_window_invalidate_rect (text_view->bin_window, &redraw_rect, FALSE);
1236         }
1237     }
1238
1239   if (old_height != new_height)
1240     {
1241       gboolean yoffset_changed = FALSE;
1242
1243       if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
1244         {
1245           text_view->yoffset += new_height - old_height;
1246           text_view->vadjustment->value = text_view->yoffset;
1247           yoffset_changed = TRUE;
1248         }
1249
1250       gtk_text_view_scroll_calc_now (text_view);
1251
1252       if (yoffset_changed)
1253         gtk_adjustment_value_changed (text_view->vadjustment);
1254         
1255     }
1256 }
1257
1258 static void
1259 gtk_text_view_realize (GtkWidget *widget)
1260 {
1261   GtkTextView *text_view;
1262   GdkCursor *cursor;
1263   GdkWindowAttr attributes;
1264   gint attributes_mask;
1265     
1266   text_view = GTK_TEXT_VIEW (widget);
1267   GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
1268   
1269   attributes.window_type = GDK_WINDOW_CHILD;
1270   attributes.x = widget->allocation.x;
1271   attributes.y = widget->allocation.y;
1272   attributes.width = widget->allocation.width;
1273   attributes.height = widget->allocation.height;
1274   attributes.wclass = GDK_INPUT_OUTPUT;
1275   attributes.visual = gtk_widget_get_visual (widget);
1276   attributes.colormap = gtk_widget_get_colormap (widget);
1277   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1278
1279   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1280
1281   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1282                                    &attributes, attributes_mask);
1283   gdk_window_set_user_data (widget->window, widget);
1284
1285   attributes.x = 0;
1286   attributes.y = 0;
1287   attributes.width = widget->allocation.width;
1288   attributes.height = widget->allocation.height;
1289   attributes.event_mask = (GDK_EXPOSURE_MASK            |
1290                            GDK_SCROLL_MASK              |
1291                            GDK_KEY_PRESS_MASK           |
1292                            GDK_BUTTON_PRESS_MASK        |
1293                            GDK_BUTTON_RELEASE_MASK      |
1294                            GDK_POINTER_MOTION_MASK      |
1295                            GDK_POINTER_MOTION_HINT_MASK |
1296                            gtk_widget_get_events (widget));
1297
1298   text_view->bin_window = gdk_window_new (widget->window,
1299                                         &attributes, attributes_mask);
1300   gdk_window_show (text_view->bin_window);
1301   gdk_window_set_user_data (text_view->bin_window, widget);
1302
1303   widget->style = gtk_style_attach (widget->style, widget->window);
1304
1305   gdk_window_set_background (text_view->bin_window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1306
1307   gtk_text_view_ensure_layout (text_view);
1308
1309   /* I-beam cursor */
1310   cursor = gdk_cursor_new (GDK_XTERM);
1311   gdk_window_set_cursor (text_view->bin_window, cursor);
1312   gdk_cursor_destroy (cursor);
1313
1314   gtk_im_context_set_client_window (text_view->im_context, widget->window);
1315 }
1316
1317 static void
1318 gtk_text_view_unrealize (GtkWidget *widget)
1319 {
1320   GtkTextView *text_view;
1321
1322   text_view = GTK_TEXT_VIEW (widget);
1323
1324   if (text_view->first_validate_idle)
1325     {
1326       g_source_remove (text_view->first_validate_idle);
1327       text_view->first_validate_idle = 0;
1328     }
1329     
1330   if (text_view->incremental_validate_idle)
1331     {
1332       g_source_remove (text_view->incremental_validate_idle);
1333       text_view->incremental_validate_idle = 0;
1334     }
1335     
1336   gtk_text_view_destroy_layout (text_view);
1337   
1338   gtk_im_context_set_client_window (text_view->im_context, NULL);
1339
1340   gdk_window_set_user_data (text_view->bin_window, NULL);
1341   gdk_window_destroy (text_view->bin_window);
1342   text_view->bin_window = NULL;
1343
1344   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1345 }
1346
1347 static void 
1348 gtk_text_view_style_set (GtkWidget *widget,
1349                          GtkStyle  *previous_style)
1350 {
1351   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1352
1353   if (GTK_WIDGET_REALIZED (widget))
1354     {
1355       gdk_window_set_background (text_view->bin_window,
1356                                  &widget->style->base[GTK_WIDGET_STATE (widget)]);
1357
1358       gtk_text_view_set_values_from_style (text_view, text_view->layout->default_style, widget->style);
1359       gtk_text_layout_default_style_changed (text_view->layout);
1360     }
1361 }
1362
1363 /*
1364  * Events
1365  */
1366
1367 static gboolean
1368 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
1369 {
1370   if (event)
1371     switch (event->type)
1372       {
1373       case GDK_MOTION_NOTIFY:
1374         *x = event->motion.x;
1375         *y = event->motion.y;
1376         return TRUE;
1377         break;
1378         
1379       case GDK_BUTTON_PRESS:
1380       case GDK_2BUTTON_PRESS:
1381       case GDK_3BUTTON_PRESS:
1382       case GDK_BUTTON_RELEASE:
1383         *x = event->button.x;
1384         *y = event->button.y;
1385         return TRUE;
1386         break;
1387         
1388       case GDK_KEY_PRESS:
1389       case GDK_KEY_RELEASE:
1390       case GDK_ENTER_NOTIFY:
1391       case GDK_LEAVE_NOTIFY:
1392       case GDK_PROPERTY_NOTIFY:
1393       case GDK_SELECTION_CLEAR:
1394       case GDK_SELECTION_REQUEST:
1395       case GDK_SELECTION_NOTIFY:
1396       case GDK_PROXIMITY_IN:
1397       case GDK_PROXIMITY_OUT:
1398       case GDK_DRAG_ENTER:
1399       case GDK_DRAG_LEAVE:
1400       case GDK_DRAG_MOTION:
1401       case GDK_DRAG_STATUS:
1402       case GDK_DROP_START:
1403       case GDK_DROP_FINISHED:
1404       default:
1405         return FALSE;
1406         break;
1407       }
1408
1409   return FALSE;
1410 }
1411
1412 static gint
1413 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
1414 {
1415   GtkTextView *text_view;
1416   gint x = 0, y = 0;
1417   
1418   text_view = GTK_TEXT_VIEW (widget);
1419   
1420   if (text_view->layout == NULL ||
1421       text_view->buffer == NULL)
1422     return FALSE;
1423
1424   /* FIXME eventually we really want to synthesize enter/leave
1425      events here as the canvas does for canvas items */
1426   
1427   if (get_event_coordinates (event, &x, &y))
1428     {
1429       GtkTextIter iter;
1430       gint retval = FALSE;
1431
1432       x += text_view->xoffset;
1433       y += text_view->yoffset;
1434
1435       /* FIXME this is slow and we do it twice per event.
1436          My favorite solution is to have GtkTextLayout cache
1437          the last couple lookups. */
1438       gtk_text_layout_get_iter_at_pixel (text_view->layout,
1439                                          &iter,
1440                                          x, y);
1441
1442         {
1443           GSList *tags;
1444           GSList *tmp;
1445           
1446           tags = gtk_text_buffer_get_tags (text_view->buffer, &iter);
1447           
1448           tmp = tags;
1449           while (tmp != NULL)
1450             {
1451               GtkTextTag *tag = tmp->data;
1452
1453               if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, &iter))
1454                 {
1455                   retval = TRUE;
1456                   break;
1457                 }
1458
1459               tmp = g_slist_next (tmp);
1460             }
1461
1462           g_slist_free (tags);
1463         }
1464         
1465       return retval;
1466     }
1467
1468   return FALSE;
1469 }
1470
1471 static gint
1472 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
1473 {
1474   GtkTextView *text_view;
1475
1476   text_view = GTK_TEXT_VIEW (widget);
1477
1478   if (text_view->layout == NULL ||
1479       text_view->buffer == NULL)
1480     return FALSE;
1481
1482   if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
1483       GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
1484     return TRUE;
1485
1486   if (gtk_im_context_filter_keypress (text_view->im_context, event))
1487     return TRUE;
1488   else if (event->keyval == GDK_Return)
1489     {
1490       gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1);
1491       gtk_text_view_scroll_to_mark (text_view,
1492                                     gtk_text_buffer_get_mark (text_view->buffer,
1493                                                               "insert"),
1494                                     0);
1495       return TRUE;
1496     }
1497   else
1498     return FALSE;
1499 }
1500
1501 static gint
1502 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
1503 {
1504   return FALSE;
1505 }
1506
1507 static gint
1508 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
1509 {
1510   GtkTextView *text_view;
1511
1512   text_view = GTK_TEXT_VIEW (widget);
1513   
1514   gtk_widget_grab_focus (widget);
1515
1516   /* debug hack */
1517   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
1518     gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
1519   else if (event->button == 3)
1520     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
1521
1522   if (event->type == GDK_BUTTON_PRESS)
1523     {
1524       if (event->button == 1)
1525         {
1526           /* If we're in the selection, start a drag copy/move of the
1527              selection; otherwise, start creating a new selection. */
1528           GtkTextIter iter;
1529           GtkTextIter start, end;
1530
1531           gtk_text_layout_get_iter_at_pixel (text_view->layout,
1532                                              &iter,
1533                                              event->x + text_view->xoffset,
1534                                              event->y + text_view->yoffset);
1535           
1536           if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
1537                                                     &start, &end) &&
1538               gtk_text_iter_in_region (&iter, &start, &end))
1539             {
1540               gtk_text_view_start_selection_dnd (text_view, &iter, event);
1541             }
1542           else
1543             {
1544               gtk_text_view_start_selection_drag (text_view, &iter, event);
1545             }
1546           
1547           return TRUE;
1548         }
1549       else if (event->button == 2)
1550         {
1551           GtkTextIter iter;
1552
1553           gtk_text_layout_get_iter_at_pixel (text_view->layout,
1554                                              &iter,
1555                                              event->x + text_view->xoffset,
1556                                              event->y + text_view->yoffset);
1557           
1558           gtk_text_buffer_paste_primary_selection (text_view->buffer,
1559                                                    &iter,
1560                                                    event->time);
1561           return TRUE;
1562         }
1563       else if (event->button == 3)
1564         {
1565           if (gtk_text_view_end_selection_drag (text_view, event))
1566             return TRUE;
1567           else
1568             return FALSE;
1569         }
1570     }
1571   
1572   return FALSE;
1573 }
1574
1575 static gint
1576 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
1577 {
1578   if (event->button == 1)
1579     {
1580       gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event);
1581       return TRUE;
1582     }
1583
1584   return FALSE;
1585 }
1586
1587 static gint
1588 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1589 {
1590   GtkTextMark *insert;
1591   
1592   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1593
1594   insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1595                                      "insert");
1596   gtk_text_mark_set_visible (insert, TRUE);
1597
1598   gtk_text_view_start_cursor_blink (GTK_TEXT_VIEW (widget));
1599
1600   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
1601   
1602   return FALSE;
1603 }
1604
1605 static gint
1606 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1607 {
1608   GtkTextMark *insert;
1609   
1610   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1611
1612   insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1613                                      "insert");
1614   gtk_text_mark_set_visible (insert, FALSE);
1615
1616   gtk_text_view_stop_cursor_blink (GTK_TEXT_VIEW (widget));
1617
1618   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
1619   
1620   return FALSE;
1621 }
1622
1623 static gint
1624 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
1625 {
1626   
1627   return FALSE;
1628 }
1629
1630 static void
1631 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
1632 {
1633   GtkTextView *text_view;
1634   
1635   text_view = GTK_TEXT_VIEW (widget);
1636
1637   g_return_if_fail (text_view->layout != NULL);
1638   g_return_if_fail (text_view->xoffset >= 0);
1639   g_return_if_fail (text_view->yoffset >= 0);
1640
1641   gtk_text_view_validate_onscreen (text_view);
1642
1643 #if 0
1644   printf ("painting %d,%d  %d x %d\n",
1645          area->x, area->y,
1646          area->width, area->height);
1647 #endif  
1648
1649   gtk_text_layout_draw (text_view->layout,
1650                         widget,
1651                         text_view->bin_window,
1652                         text_view->xoffset, text_view->yoffset,
1653                         area->x, area->y,
1654                         area->width, area->height);
1655 }
1656
1657 static void
1658 gtk_text_view_draw (GtkWidget *widget, GdkRectangle *area)
1659 {  
1660   gtk_text_view_paint (widget, area);
1661 }
1662
1663 static gint
1664 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
1665 {
1666   if (event->window == GTK_TEXT_VIEW (widget)->bin_window)
1667     gtk_text_view_paint (widget, &event->area);
1668   
1669   return TRUE;
1670 }
1671
1672 /*
1673  * Blink!
1674  */
1675
1676 static gint
1677 blink_cb (gpointer data)
1678 {
1679   GtkTextView *text_view;
1680   GtkTextMark *insert;
1681   
1682   text_view = GTK_TEXT_VIEW (data);
1683
1684   insert = gtk_text_buffer_get_mark (text_view->buffer,
1685                                      "insert");
1686   
1687   if (!GTK_WIDGET_HAS_FOCUS (text_view))
1688     {
1689       /* paranoia, in case the user somehow mangles our
1690          focus_in/focus_out pairing. */
1691       gtk_text_mark_set_visible (insert, FALSE);
1692       text_view->blink_timeout = 0;
1693       return FALSE;
1694     }
1695   else
1696     {
1697       gtk_text_mark_set_visible (insert,
1698                                  !gtk_text_mark_is_visible (insert));
1699       return TRUE;
1700     }
1701 }
1702
1703 static void
1704 gtk_text_view_start_cursor_blink (GtkTextView *text_view)
1705 {
1706   return;
1707   if (text_view->blink_timeout != 0)
1708     return;
1709
1710   text_view->blink_timeout = gtk_timeout_add (500, blink_cb, text_view);
1711 }
1712
1713 static void
1714 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
1715 {
1716   return;
1717   if (text_view->blink_timeout == 0)
1718     return;
1719
1720   gtk_timeout_remove (text_view->blink_timeout);
1721   text_view->blink_timeout = 0;
1722 }
1723
1724 /*
1725  * Key binding handlers
1726  */
1727
1728 static void
1729 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
1730                                   GtkTextIter *newplace,
1731                                   gint         count)
1732 {
1733   while (count < 0)
1734     {
1735       gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
1736       count++;
1737     }
1738
1739   while (count > 0)
1740     {
1741       gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
1742       count--;
1743     }
1744 }
1745
1746 static void
1747 gtk_text_view_move_insert (GtkTextView *text_view,
1748                            GtkTextViewMovementStep step,
1749                            gint count,
1750                            gboolean extend_selection)
1751 {
1752   GtkTextIter insert;
1753   GtkTextIter newplace;
1754   
1755   gint cursor_x_pos = 0;
1756
1757   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1758                                     gtk_text_buffer_get_mark (text_view->buffer,
1759                                                               "insert"));
1760   newplace = insert;
1761
1762   if (step == GTK_TEXT_MOVEMENT_LINE)
1763     gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
1764
1765   switch (step)
1766     {
1767     case GTK_TEXT_MOVEMENT_CHAR:
1768       gtk_text_iter_forward_chars (&newplace, count);
1769       break;
1770
1771     case GTK_TEXT_MOVEMENT_POSITIONS:
1772       gtk_text_layout_move_iter_visually (text_view->layout,
1773                                           &newplace, count);
1774       break;
1775
1776     case GTK_TEXT_MOVEMENT_WORD:
1777       if (count < 0)
1778         gtk_text_iter_backward_word_starts (&newplace, -count);
1779       else if (count > 0)
1780         gtk_text_iter_forward_word_ends (&newplace, count);
1781       break;
1782
1783     case GTK_TEXT_MOVEMENT_LINE:
1784       gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
1785       gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
1786       break;
1787       
1788     case GTK_TEXT_MOVEMENT_PARAGRAPH:
1789       /* This should almost certainly instead be doing the parallel thing to WORD */
1790       gtk_text_iter_down_lines (&newplace, count);
1791       break;
1792       
1793     case GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS:
1794       if (count > 0)
1795         gtk_text_iter_forward_to_newline (&newplace);
1796       else if (count < 0)
1797         gtk_text_iter_set_line_char (&newplace, 0);
1798       break;
1799       
1800     case GTK_TEXT_MOVEMENT_BUFFER_ENDS:
1801       if (count > 0)
1802         gtk_text_buffer_get_last_iter (text_view->buffer, &newplace);
1803       else if (count < 0)
1804         gtk_text_buffer_get_iter_at_char (text_view->buffer, &newplace, 0);
1805       break;
1806       
1807     default:
1808       break;
1809     }
1810   
1811   if (!gtk_text_iter_equal (&insert, &newplace))
1812     {
1813       if (extend_selection)
1814         gtk_text_buffer_move_mark (text_view->buffer,
1815                                    gtk_text_buffer_get_mark (text_view->buffer,
1816                                                              "insert"),
1817                                    &newplace);
1818       else
1819         gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
1820       
1821       gtk_text_view_scroll_to_mark (text_view,
1822                                     gtk_text_buffer_get_mark (text_view->buffer,
1823                                                               "insert"), 0);
1824
1825       if (step == GTK_TEXT_MOVEMENT_LINE)
1826         {
1827           gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
1828         }
1829     }
1830 }
1831
1832 static void
1833 gtk_text_view_set_anchor (GtkTextView *text_view)
1834 {
1835   GtkTextIter insert;
1836   
1837   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1838                                     gtk_text_buffer_get_mark (text_view->buffer,
1839                                                               "insert"));
1840
1841   gtk_text_buffer_create_mark (text_view->buffer, "anchor", &insert, TRUE);
1842 }
1843
1844 static void
1845 gtk_text_view_scroll_text (GtkTextView *text_view,
1846                            GtkTextViewScrollType type)
1847 {
1848   gfloat newval;
1849   GtkAdjustment *adj;
1850   gint cursor_x_pos, cursor_y_pos;
1851   GtkTextIter new_insert;
1852   GtkTextIter anchor;
1853   gint y0, y1;
1854   
1855   g_return_if_fail (text_view->vadjustment != NULL);
1856
1857   adj = text_view->vadjustment;
1858
1859   /* Validate the region that will be brought into view by the cursor motion
1860    */
1861   switch (type)
1862     {
1863     default:
1864     case GTK_TEXT_SCROLL_TO_TOP:
1865       gtk_text_buffer_get_iter_at_char (text_view->buffer, &anchor, 0);
1866       y0 = 0;
1867       y1 = adj->page_size;
1868       break;
1869
1870     case GTK_TEXT_SCROLL_TO_BOTTOM:
1871       gtk_text_buffer_get_last_iter (text_view->buffer, &anchor);
1872       y0 = -adj->page_size;
1873       y1 = adj->page_size;
1874       break;
1875
1876     case GTK_TEXT_SCROLL_PAGE_DOWN:
1877       gtk_text_view_get_first_para_iter (text_view, &anchor);
1878       y0 = adj->page_size;
1879       y1 = adj->page_size + adj->page_increment;
1880       break;
1881
1882     case GTK_TEXT_SCROLL_PAGE_UP:
1883       gtk_text_view_get_first_para_iter (text_view, &anchor);
1884       y0 = - adj->page_increment + adj->page_size;
1885       y1 = 0;
1886       break;
1887     }
1888   gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
1889
1890
1891   gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
1892
1893   newval = adj->value;
1894   switch (type)
1895     {
1896     case GTK_TEXT_SCROLL_TO_TOP:
1897       newval = adj->lower;
1898       break;
1899
1900     case GTK_TEXT_SCROLL_TO_BOTTOM:
1901       newval = adj->upper;
1902       break;
1903
1904     case GTK_TEXT_SCROLL_PAGE_DOWN:
1905       newval += adj->page_increment;
1906       break;
1907
1908     case GTK_TEXT_SCROLL_PAGE_UP:
1909       newval -= adj->page_increment;
1910       break;
1911       
1912     default:
1913       break;
1914     }
1915
1916   cursor_y_pos += newval - adj->value;
1917   set_adjustment_clamped (adj, newval);
1918
1919   gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
1920   clamp_iter_onscreen (text_view, &new_insert);
1921   gtk_text_buffer_place_cursor (text_view->buffer, &new_insert);
1922
1923   gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
1924
1925   /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
1926    * only guarantees 1 pixel onscreen.
1927    */
1928   gtk_text_view_scroll_to_mark (text_view,
1929                                 gtk_text_buffer_get_mark (text_view->buffer,
1930                                                           "insert"),
1931                                 0);
1932 }
1933
1934 static gboolean
1935 whitespace (GtkTextUniChar ch, gpointer user_data)
1936 {
1937   return (ch == ' ' || ch == '\t');
1938 }
1939
1940 static gboolean
1941 not_whitespace (GtkTextUniChar ch, gpointer user_data)
1942 {
1943   return !whitespace (ch, user_data);
1944 }
1945
1946 static gboolean
1947 find_whitepace_region (const GtkTextIter *center,
1948                       GtkTextIter *start, GtkTextIter *end)
1949 {
1950   *start = *center;
1951   *end = *center;
1952
1953   if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL))
1954     gtk_text_iter_forward_char (start); /* we want the first whitespace... */
1955   if (whitespace (gtk_text_iter_get_char (end), NULL))
1956     gtk_text_iter_forward_find_char (end, not_whitespace, NULL);
1957   
1958   return !gtk_text_iter_equal (start, end);
1959 }
1960
1961 static void
1962 gtk_text_view_delete_text (GtkTextView *text_view,
1963                        GtkTextViewDeleteType type,
1964                        gint count)
1965 {
1966   GtkTextIter insert;
1967   GtkTextIter start;
1968   GtkTextIter end;
1969   gboolean leave_one = FALSE;
1970   
1971   if (type == GTK_TEXT_DELETE_CHAR)
1972     {
1973       /* Char delete deletes the selection, if one exists */
1974       if (gtk_text_buffer_delete_selection (text_view->buffer))
1975         return;
1976     }
1977   
1978   gtk_text_buffer_get_iter_at_mark (text_view->buffer,
1979                                     &insert,
1980                                     gtk_text_buffer_get_mark (text_view->buffer,
1981                                                               "insert"));
1982
1983   start = insert;
1984   end = insert;
1985   
1986   switch (type)
1987     {
1988     case GTK_TEXT_DELETE_CHAR:
1989       gtk_text_iter_forward_chars (&end, count);
1990       break;
1991       
1992     case GTK_TEXT_DELETE_HALF_WORD:
1993       if (count > 0)
1994         gtk_text_iter_forward_word_ends (&end, count);
1995       else if (count < 0)
1996         gtk_text_iter_backward_word_starts (&start, 0 - count);
1997       break;
1998       
1999     case GTK_TEXT_DELETE_WHOLE_WORD:
2000       break;
2001       
2002     case GTK_TEXT_DELETE_HALF_LINE:
2003       break;
2004
2005     case GTK_TEXT_DELETE_WHOLE_LINE:
2006       break;
2007
2008     case GTK_TEXT_DELETE_HALF_PARAGRAPH:
2009       while (count > 0)
2010         {
2011           if (!gtk_text_iter_forward_to_newline (&end))
2012             break;
2013
2014           --count;
2015         }
2016
2017       /* FIXME figure out what a negative count means
2018          and support that */
2019       break;
2020       
2021     case GTK_TEXT_DELETE_WHOLE_PARAGRAPH:
2022       if (count > 0)
2023         {
2024           gtk_text_iter_set_line_char (&start, 0);
2025           gtk_text_iter_forward_to_newline (&end);
2026
2027           /* Do the lines beyond the first. */
2028           while (count > 1)
2029             {
2030               gtk_text_iter_forward_to_newline (&end);
2031               
2032               --count;
2033             }
2034         }
2035
2036       /* FIXME negative count? */
2037       
2038       break;
2039
2040     case GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE:
2041       leave_one = TRUE; /* FALL THRU */
2042     case GTK_TEXT_DELETE_WHITESPACE:
2043       {
2044         find_whitepace_region (&insert, &start, &end);
2045       }
2046       break;
2047       
2048     default:
2049       break;
2050     }
2051
2052   if (!gtk_text_iter_equal (&start, &end))
2053     {
2054       gtk_text_buffer_delete (text_view->buffer, &start, &end);
2055       
2056       if (leave_one)
2057         gtk_text_buffer_insert_at_cursor (text_view->buffer, " ", 1);
2058       
2059       gtk_text_view_scroll_to_mark (text_view,
2060                                     gtk_text_buffer_get_mark (text_view->buffer, "insert"),
2061                                     0);
2062     }
2063 }
2064
2065 static void
2066 gtk_text_view_cut_text (GtkTextView *text_view)
2067 {
2068   gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME);
2069   gtk_text_view_scroll_to_mark (text_view,
2070                                 gtk_text_buffer_get_mark (text_view->buffer,
2071                                                           "insert"),
2072                                 0);
2073 }
2074
2075 static void
2076 gtk_text_view_copy_text (GtkTextView *text_view)
2077 {
2078   gtk_text_buffer_copy (text_view->buffer, GDK_CURRENT_TIME);
2079   gtk_text_view_scroll_to_mark (text_view,
2080                                 gtk_text_buffer_get_mark (text_view->buffer,
2081                                                           "insert"),
2082                                 0);
2083 }
2084
2085 static void
2086 gtk_text_view_paste_text (GtkTextView *text_view)
2087 {
2088   gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME);
2089   gtk_text_view_scroll_to_mark (text_view,
2090                                 gtk_text_buffer_get_mark (text_view->buffer,
2091                                                           "insert"),
2092                                 0);
2093 }
2094
2095 static void
2096 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
2097 {
2098   text_view->overwrite_mode = !text_view->overwrite_mode;
2099 }
2100
2101 /*
2102  * Selections
2103  */
2104
2105 static gboolean
2106 move_insert_to_pointer_and_scroll (GtkTextView *text_view, gboolean partial_scroll)
2107 {
2108   gint x, y;
2109   GdkModifierType state;
2110   GtkTextIter newplace;
2111   gint adjust = 0;
2112   gboolean in_threshold = FALSE;
2113   
2114   gdk_window_get_pointer (text_view->bin_window, &x, &y, &state);
2115
2116   /* Adjust movement by how long we've been selecting, to
2117      get an acceleration effect. The exact numbers are
2118      pretty arbitrary. We have a threshold before we
2119      start to accelerate. */
2120   /* uncommenting this printf helps visualize how it works. */     
2121   /*   printf ("%d\n", text_view->scrolling_accel_factor); */
2122        
2123   if (text_view->scrolling_accel_factor > 10)
2124     adjust = (text_view->scrolling_accel_factor - 10) * 75;
2125   
2126   if (y < 0) /* scrolling upward */
2127     adjust = -adjust; 
2128
2129   /* No adjust if the pointer has moved back inside the window for sure.
2130      Also I'm adding a small threshold where no adjust is added,
2131      in case you want to do a continuous slow scroll. */
2132 #define SLOW_SCROLL_TH 7
2133   if (x >= (0 - SLOW_SCROLL_TH) &&
2134       x < (GTK_WIDGET (text_view)->allocation.width + SLOW_SCROLL_TH) &&
2135       y >= (0 - SLOW_SCROLL_TH) &&
2136       y < (GTK_WIDGET (text_view)->allocation.height + SLOW_SCROLL_TH))
2137     {
2138       adjust = 0;
2139       in_threshold = TRUE;
2140     }
2141   
2142   gtk_text_layout_get_iter_at_pixel (text_view->layout,
2143                                      &newplace,
2144                                      x + text_view->xoffset,
2145                                      y + text_view->yoffset + adjust);
2146   
2147   {
2148       gboolean scrolled = FALSE;
2149       GtkTextMark *insert_mark =
2150         gtk_text_buffer_get_mark (text_view->buffer, "insert");
2151
2152       gtk_text_buffer_move_mark (text_view->buffer,
2153                                  insert_mark,
2154                                  &newplace);
2155       
2156       if (partial_scroll)
2157         scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 0.7);
2158       else
2159         scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 1.0);
2160
2161       if (scrolled)
2162         {
2163           /* We want to avoid rapid jump to super-accelerated when you
2164              leave the slow scroll threshold after scrolling for a
2165              while. So we slowly decrease accel when scrolling inside
2166              the threshold.
2167           */
2168           if (in_threshold)
2169             {
2170               if (text_view->scrolling_accel_factor > 1)
2171                 text_view->scrolling_accel_factor -= 2;
2172             }
2173           else
2174             text_view->scrolling_accel_factor += 1;
2175         }
2176       else
2177         {
2178           /* If we don't scroll we're probably inside the window, but
2179              potentially just a bit outside. We decrease acceleration
2180              while the user is fooling around inside the window.
2181              Acceleration decreases faster than it increases. */
2182           if (text_view->scrolling_accel_factor > 4)
2183             text_view->scrolling_accel_factor -= 5;
2184         }
2185       
2186       return scrolled;
2187   }
2188 }
2189
2190 static gint
2191 selection_scan_timeout (gpointer data)
2192 {
2193   GtkTextView *text_view;
2194
2195   text_view = GTK_TEXT_VIEW (data);
2196
2197   if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2198     {
2199       return TRUE; /* remain installed. */
2200     }
2201   else
2202     {
2203       text_view->selection_drag_scan_timeout = 0;
2204       return FALSE; /* remove ourselves */
2205     }
2206 }
2207
2208 static gint
2209 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
2210 {
2211   if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2212     {
2213       /* If we had to scroll offscreen, insert a timeout to do so
2214          again. Note that in the timeout, even if the mouse doesn't
2215          move, due to this scroll xoffset/yoffset will have changed
2216          and we'll need to scroll again. */
2217       if (text_view->selection_drag_scan_timeout != 0) /* reset on every motion event */
2218         gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2219       
2220       text_view->selection_drag_scan_timeout =
2221         gtk_timeout_add (50, selection_scan_timeout, text_view);
2222     }
2223   
2224   return TRUE;
2225 }
2226
2227 static void
2228 gtk_text_view_start_selection_drag (GtkTextView *text_view,
2229                                const GtkTextIter *iter,
2230                                GdkEventButton *event)
2231 {
2232   GtkTextIter newplace;
2233
2234   g_return_if_fail (text_view->selection_drag_handler == 0);
2235   
2236   gtk_grab_add (GTK_WIDGET (text_view));
2237
2238   text_view->scrolling_accel_factor = 0;
2239
2240   newplace = *iter;
2241   
2242   gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
2243
2244   text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
2245                                                           "motion_notify_event",
2246                                                           GTK_SIGNAL_FUNC (selection_motion_event_handler),
2247                                                           NULL);
2248 }
2249
2250 /* returns whether we were really dragging */
2251 static gboolean
2252 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
2253 {
2254   if (text_view->selection_drag_handler == 0)
2255     return FALSE;
2256
2257   gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
2258   text_view->selection_drag_handler = 0;
2259
2260   text_view->scrolling_accel_factor = 0;
2261   
2262   if (text_view->selection_drag_scan_timeout != 0)
2263     {
2264       gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2265       text_view->selection_drag_scan_timeout = 0;
2266     }
2267
2268   /* one last update to current position */
2269   move_insert_to_pointer_and_scroll (text_view, FALSE);
2270   
2271   gtk_grab_remove (GTK_WIDGET (text_view));
2272   
2273   return TRUE;
2274 }
2275
2276 /*
2277  * Layout utils
2278  */
2279
2280 static void
2281 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
2282 {
2283   if (upper != adj->upper)
2284     {
2285       gfloat min = MAX (0., upper - adj->page_size);
2286       gboolean value_changed = FALSE;
2287       
2288       adj->upper = upper;
2289       
2290       if (adj->value > min)
2291         {
2292           adj->value = min;
2293           value_changed = TRUE;
2294         }
2295       
2296       gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
2297       if (value_changed)
2298         gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2299     }
2300 }
2301
2302 static void
2303 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
2304 {
2305   gint width = 0, height = 0;
2306   GtkWidget *widget = GTK_WIDGET (text_view);
2307   
2308   gtk_text_view_ensure_layout (text_view);
2309
2310       
2311   gtk_text_layout_set_screen_width (text_view->layout,
2312                                     widget->allocation.width);
2313       
2314   gtk_text_layout_get_size (text_view->layout, &width, &height);
2315
2316 #if 0
2317   /* If the width is less than the screen width (likely
2318      if we have wrapping turned on for the whole widget),
2319      then we want to set the scroll region to the screen
2320      width. If the width is greater (wrapping off) then we
2321      probably want to set the scroll region to the width
2322      of the layout. I guess.
2323   */
2324
2325   width = MAX (text_view->layout->screen_width, width);
2326   height = height;
2327 #endif
2328
2329   if (text_view->width != width || text_view->height != height)
2330     {
2331 #if 0
2332       printf ("layout size set, widget width is %d\n",
2333               GTK_WIDGET (text_view)->allocation.width);
2334 #endif
2335       text_view->width = width;
2336       text_view->height = height;
2337       
2338       gtk_text_view_set_adjustment_upper (text_view->hadjustment,
2339                                           MAX (widget->allocation.width, width));
2340       gtk_text_view_set_adjustment_upper (text_view->vadjustment, 
2341                                           MAX (widget->allocation.height, height));
2342
2343       /* Set up the step sizes; we'll say that a page is
2344          our allocation minus one step, and a step is
2345          1/10 of our allocation. */
2346       text_view->hadjustment->step_increment =
2347         GTK_WIDGET (text_view)->allocation.width/10.0;
2348       text_view->hadjustment->page_increment =
2349         GTK_WIDGET (text_view)->allocation.width  *0.9;
2350
2351       text_view->vadjustment->step_increment =
2352         GTK_WIDGET (text_view)->allocation.height/10.0;
2353       text_view->vadjustment->page_increment =
2354         GTK_WIDGET (text_view)->allocation.height  *0.9;
2355     } 
2356 }
2357
2358 static void
2359 gtk_text_view_set_values_from_style (GtkTextView        *text_view,
2360                                      GtkTextStyleValues *values,
2361                                      GtkStyle           *style)
2362 {
2363   values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
2364   values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
2365       
2366   if (values->font_desc)
2367     pango_font_description_free (values->font_desc);
2368
2369   values->font_desc = pango_font_description_copy (style->font_desc);
2370 }
2371
2372 static void
2373 gtk_text_view_ensure_layout (GtkTextView *text_view)
2374 {
2375   GtkWidget *widget;
2376
2377   widget = GTK_WIDGET (text_view);
2378   
2379   if (text_view->layout == NULL)
2380     {
2381       GtkTextStyleValues *style;
2382       PangoContext *ltr_context, *rtl_context;
2383       
2384       text_view->layout = gtk_text_layout_new ();
2385
2386       gtk_signal_connect (GTK_OBJECT (text_view->layout),
2387                           "invalidated",
2388                           GTK_SIGNAL_FUNC (invalidated_handler),
2389                           text_view);
2390
2391       gtk_signal_connect (GTK_OBJECT (text_view->layout),
2392                           "changed",
2393                           GTK_SIGNAL_FUNC (changed_handler),
2394                           text_view);
2395       
2396       if (text_view->buffer)
2397         gtk_text_layout_set_buffer (text_view->layout, text_view->buffer);
2398
2399       ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2400       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
2401       rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2402       pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
2403
2404       gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
2405
2406       g_object_unref (G_OBJECT (ltr_context));
2407       g_object_unref (G_OBJECT (rtl_context));
2408
2409       style = gtk_text_view_style_values_new ();
2410
2411       gtk_widget_ensure_style (widget);
2412       gtk_text_view_set_values_from_style (text_view, style, widget->style);
2413       
2414       style->pixels_above_lines = 2;
2415       style->pixels_below_lines = 2;
2416       style->pixels_inside_wrap = 1;
2417       
2418       style->wrap_mode = text_view->wrap_mode;
2419       style->justify = GTK_JUSTIFY_LEFT;
2420       style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
2421       
2422       gtk_text_layout_set_default_style (text_view->layout, style);
2423       
2424       gtk_text_view_style_values_unref (style);
2425     }
2426 }
2427
2428 static void
2429 gtk_text_view_destroy_layout (GtkTextView *text_view)
2430 {
2431   if (text_view->layout)
2432     {
2433       gtk_text_view_end_selection_drag (text_view, NULL);
2434       
2435       gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2436                                      invalidated_handler, text_view);
2437       gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2438                                      changed_handler, text_view);
2439       gtk_object_unref (GTK_OBJECT (text_view->layout));
2440       text_view->layout = NULL;
2441     }
2442 }
2443
2444
2445 /*
2446  * DND feature
2447  */
2448
2449 static void
2450 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
2451                               const GtkTextIter *iter,
2452                               GdkEventButton *event)
2453 {
2454   GdkDragContext *context;
2455   GtkTargetList *target_list;
2456   
2457   /* FIXME we have to handle more formats for the selection,
2458      and do the conversions to/from UTF8 */
2459   
2460   /* FIXME not sure how this is memory-managed. */
2461   target_list = gtk_target_list_new (target_table, n_targets);
2462   
2463   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
2464                            GDK_ACTION_COPY | GDK_ACTION_MOVE,
2465                            1, (GdkEvent*)event);
2466
2467   gtk_drag_set_icon_default (context);
2468
2469   /* We're inside the selection, so start without being able
2470      to accept the drag. */
2471   gdk_drag_status (context, 0, event->time);
2472   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2473 }
2474
2475 static void
2476 gtk_text_view_drag_begin (GtkWidget        *widget,
2477                       GdkDragContext   *context)
2478 {
2479   
2480 }
2481
2482 static void
2483 gtk_text_view_drag_end (GtkWidget        *widget,
2484                     GdkDragContext   *context)
2485 {
2486   GtkTextView *text_view;
2487
2488   text_view = GTK_TEXT_VIEW (widget);
2489
2490   gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2491 }
2492
2493 static void
2494 gtk_text_view_drag_data_get (GtkWidget        *widget,
2495                          GdkDragContext   *context,
2496                          GtkSelectionData *selection_data,
2497                          guint             info,
2498                          guint             time)
2499 {
2500   gchar *str;
2501   gint length;
2502   GtkTextIter start;
2503   GtkTextIter end;
2504   GtkTextView *text_view;
2505
2506   text_view = GTK_TEXT_VIEW (widget);
2507   
2508   str = NULL;
2509   length = 0;
2510   
2511   if (gtk_text_buffer_get_selection_bounds (text_view->buffer, &start, &end))
2512     {
2513       /* Extract the selected text */
2514       str = gtk_text_iter_get_visible_text (&start, &end);
2515       
2516       length = strlen (str);
2517     }
2518
2519   if (str)
2520     {
2521       if (info == TARGET_UTF8_STRING)
2522         {
2523           /* Pass raw UTF8 */
2524           gtk_selection_data_set (selection_data,
2525                                   utf8_atom,
2526                                   8*sizeof (gchar), (guchar *)str, length);
2527
2528         }
2529       else if (info == TARGET_STRING ||
2530                info == TARGET_TEXT)
2531         {
2532           gchar *latin1;
2533
2534           latin1 = gtk_text_utf_to_latin1(str, length);
2535           
2536           gtk_selection_data_set (selection_data,
2537                                   GDK_SELECTION_TYPE_STRING,
2538                                   8*sizeof (gchar), latin1, strlen (latin1));
2539           g_free (latin1);
2540         }
2541       else if (info == TARGET_COMPOUND_TEXT)
2542         {
2543           /* FIXME convert UTF8 directly to current locale, not via
2544              latin1 */
2545           
2546           guchar *text;
2547           GdkAtom encoding;
2548           gint format;
2549           gint new_length;
2550           gchar *latin1;
2551
2552           latin1 = gtk_text_utf_to_latin1(str, length);
2553           
2554           gdk_string_to_compound_text (latin1, &encoding, &format, &text, &new_length);
2555           gtk_selection_data_set (selection_data, encoding, format, text, new_length);
2556           gdk_free_compound_text (text);
2557
2558           g_free (latin1);
2559         }
2560
2561       g_free (str);
2562     }
2563 }
2564
2565 static void
2566 gtk_text_view_drag_data_delete (GtkWidget        *widget,
2567                             GdkDragContext   *context)
2568 {
2569   gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer);
2570 }
2571
2572 static void
2573 gtk_text_view_drag_leave (GtkWidget        *widget,
2574                       GdkDragContext   *context,
2575                       guint             time)
2576 {
2577
2578
2579 }
2580
2581 static gboolean
2582 gtk_text_view_drag_motion (GtkWidget        *widget,
2583                            GdkDragContext   *context,
2584                            gint              x,
2585                            gint              y,
2586                            guint             time)
2587 {
2588   GtkTextIter newplace;
2589   GtkTextView *text_view;
2590   GtkTextIter start;
2591   GtkTextIter end;
2592   
2593   text_view = GTK_TEXT_VIEW (widget);
2594
2595   gtk_text_layout_get_iter_at_pixel (text_view->layout,
2596                                      &newplace, 
2597                                      x + text_view->xoffset,
2598                                      y + text_view->yoffset);
2599
2600   if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
2601                                             &start, &end) &&
2602       gtk_text_iter_in_region (&newplace, &start, &end))
2603     {
2604       /* We're inside the selection. */
2605       gdk_drag_status (context, 0, time);
2606       gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2607     }
2608   else
2609     {
2610       gtk_text_mark_set_visible (text_view->dnd_mark, TRUE);
2611       
2612       gdk_drag_status (context, context->suggested_action, time);
2613     }
2614
2615   gtk_text_buffer_move_mark (text_view->buffer,
2616                              gtk_text_buffer_get_mark (text_view->buffer,
2617                                                        "__drag_target"),
2618                              &newplace);
2619
2620   {
2621     /* The effect of this is that the text scrolls if you're near
2622        the edge. We have to scroll whether or not we're inside
2623        the selection. */
2624     gint margin;
2625     
2626     margin = MIN (widget->allocation.width, widget->allocation.height);
2627     margin /= 5;
2628     
2629     gtk_text_view_scroll_to_mark_adjusted (text_view,
2630                                            gtk_text_buffer_get_mark (text_view->buffer,
2631                                                                      "__drag_target"),
2632                                            margin, 1.0);
2633   }
2634   
2635   return TRUE;
2636 }
2637
2638 static gboolean
2639 gtk_text_view_drag_drop (GtkWidget        *widget,
2640                          GdkDragContext   *context,
2641                          gint              x,
2642                          gint              y,
2643                          guint             time)
2644 {
2645 #if 0
2646   /* called automatically. */
2647   if (context->targets)
2648     {
2649       gtk_drag_get_data (widget, context, 
2650                          GPOINTER_TO_INT (context->targets->data), 
2651                          time);
2652       return TRUE;
2653     }
2654   else
2655     return FALSE;
2656 #endif
2657   return TRUE;
2658 }
2659
2660 static void
2661 gtk_text_view_drag_data_received (GtkWidget        *widget,
2662                                   GdkDragContext   *context,
2663                                   gint              x,
2664                                   gint              y,
2665                                   GtkSelectionData *selection_data,
2666                                   guint             info,
2667                                   guint             time)
2668 {
2669   GtkTextIter drop_point;
2670   GtkTextView *text_view;
2671   GtkTextMark *drag_target_mark;
2672   
2673   enum {INVALID, STRING, CTEXT, UTF8} type;
2674
2675   text_view = GTK_TEXT_VIEW (widget);
2676   
2677   if (selection_data->type == GDK_TARGET_STRING)
2678     type = STRING;
2679   else if (selection_data->type == ctext_atom)
2680     type = CTEXT;
2681   else if (selection_data->type == utf8_atom)
2682     type = UTF8;
2683   else
2684     type = INVALID;
2685
2686   if (type == INVALID || selection_data->length < 0)
2687     {
2688       /* I think the DND code automatically tries asking
2689          for the various formats. */
2690       return;
2691     }
2692
2693   drag_target_mark = gtk_text_buffer_get_mark (text_view->buffer,
2694                                                "__drag_target");
2695   
2696   if (drag_target_mark == NULL)
2697     return;
2698
2699   gtk_text_buffer_get_iter_at_mark (text_view->buffer,
2700                                     &drop_point,
2701                                     drag_target_mark);
2702
2703   
2704   switch (type)
2705     {
2706     case STRING:
2707       {
2708         gchar *utf;
2709
2710         utf = gtk_text_latin1_to_utf ((const gchar*)selection_data->data,
2711                                       selection_data->length);
2712         gtk_text_buffer_insert (text_view->buffer, &drop_point,
2713                                  utf, -1);
2714         g_free (utf);
2715       }
2716       break;
2717       
2718     case UTF8:
2719       gtk_text_buffer_insert (text_view->buffer, &drop_point,
2720                                (const gchar *)selection_data->data,
2721                                selection_data->length);
2722       break;
2723       
2724     case CTEXT:
2725       {
2726         gchar **list;
2727         gint count;
2728         gint i;
2729
2730         count = gdk_text_property_to_text_list (selection_data->type,
2731                                                 selection_data->format, 
2732                                                 selection_data->data,
2733                                                 selection_data->length,
2734                                                 &list);
2735         for (i=0; i<count; i++)
2736           {
2737             /* FIXME this is broken, it assumes the CTEXT is latin1
2738                when it probably isn't. */
2739             gchar *utf;
2740
2741             utf = gtk_text_latin1_to_utf (list[i], strlen (list[i]));
2742             
2743             gtk_text_buffer_insert (text_view->buffer, &drop_point, utf, -1);
2744
2745             g_free (utf);
2746           }
2747
2748         if (count > 0)
2749           gdk_free_text_list (list);
2750       }
2751       break;
2752       
2753     case INVALID:               /* quiet compiler */
2754       break;
2755     }
2756 }
2757
2758 static void
2759 gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
2760                                       GtkAdjustment *hadj,
2761                                       GtkAdjustment *vadj)
2762 {
2763   gboolean need_adjust = FALSE;
2764
2765   g_return_if_fail (text_view != NULL);
2766   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2767
2768   if (hadj)
2769     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2770   else
2771     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2772   if (vadj)
2773     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2774   else
2775     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2776   
2777   if (text_view->hadjustment && (text_view->hadjustment != hadj))
2778     {
2779       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
2780       gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
2781     }
2782   
2783   if (text_view->vadjustment && (text_view->vadjustment != vadj))
2784     {
2785       gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
2786       gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
2787     }
2788   
2789   if (text_view->hadjustment != hadj)
2790     {
2791       text_view->hadjustment = hadj;
2792       gtk_object_ref (GTK_OBJECT (text_view->hadjustment));
2793       gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
2794       
2795       gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
2796                           (GtkSignalFunc) gtk_text_view_value_changed,
2797                           text_view);
2798       need_adjust = TRUE;
2799     }
2800   
2801   if (text_view->vadjustment != vadj)
2802     {
2803       text_view->vadjustment = vadj;
2804       gtk_object_ref (GTK_OBJECT (text_view->vadjustment));
2805       gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
2806       
2807       gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
2808                           (GtkSignalFunc) gtk_text_view_value_changed,
2809                           text_view);
2810       need_adjust = TRUE;
2811     }
2812
2813   if (need_adjust)
2814     gtk_text_view_value_changed (NULL, text_view);
2815 }
2816
2817 static void
2818 gtk_text_view_value_changed (GtkAdjustment *adj,
2819                              GtkTextView   *text_view)
2820 {
2821   GtkTextIter iter;
2822   gint line_top;
2823   gint dx = 0;
2824   gint dy = 0;
2825
2826   if (adj == text_view->hadjustment)
2827     {
2828       dx = text_view->xoffset - (gint)adj->value;
2829       text_view->xoffset = adj->value;
2830     }
2831   else if (adj == text_view->vadjustment)
2832     {
2833       dy = text_view->yoffset - (gint)adj->value;
2834       text_view->yoffset = adj->value;
2835
2836       if (text_view->layout)
2837         {
2838           gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
2839           
2840           gtk_text_buffer_move_mark (text_view->buffer, text_view->first_para_mark, &iter);
2841           
2842           text_view->first_para_pixels = adj->value - line_top;
2843         }
2844     }
2845
2846   if (dx != 0 || dy != 0)
2847     {
2848       gdk_window_scroll (text_view->bin_window, dx, dy);
2849       gdk_window_process_updates (text_view->bin_window, TRUE);
2850     }
2851 }
2852
2853 static void
2854 gtk_text_view_commit_handler (GtkIMContext  *context,
2855                               const gchar   *str,
2856                               GtkTextView   *text_view)
2857 {
2858   gtk_text_buffer_delete_selection (text_view->buffer);
2859
2860   if (!strcmp (str, "\n"))
2861     {
2862       gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1);
2863     }
2864   else
2865     {
2866       if (text_view->overwrite_mode)
2867         gtk_text_view_delete_text (text_view, GTK_TEXT_DELETE_CHAR, 1);
2868       gtk_text_buffer_insert_at_cursor (text_view->buffer, str, strlen (str));
2869     }
2870   
2871   gtk_text_view_scroll_to_mark (text_view,
2872                                 gtk_text_buffer_get_mark (text_view->buffer,
2873                                                           "insert"),
2874                                 0);
2875 }
2876
2877 static void
2878 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
2879                                 const GtkTextIter *location,
2880                                 const char        *mark_name,
2881                                 gpointer           data)
2882 {
2883   GtkTextView *text_view = GTK_TEXT_VIEW (data);
2884   
2885   if (!strcmp (mark_name, "insert"))
2886     {
2887       text_view->virtual_cursor_x = -1;
2888       text_view->virtual_cursor_y = -1;
2889     }
2890 }
2891
2892 static void
2893 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
2894                                       gint        *x,
2895                                       gint        *y)
2896 {
2897   GdkRectangle strong_pos;
2898   GtkTextIter insert;
2899
2900   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
2901                                     gtk_text_buffer_get_mark (text_view->buffer,
2902                                                               "insert"));
2903   
2904   if ((x && text_view->virtual_cursor_x == -1) ||
2905       (y && text_view->virtual_cursor_y == -1))
2906     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
2907
2908   if (x)
2909     {
2910       if (text_view->virtual_cursor_x != -1)
2911         *x = text_view->virtual_cursor_x;
2912       else
2913         *x = strong_pos.x;
2914     }
2915
2916   if (y)
2917     {
2918       if (text_view->virtual_cursor_x != -1)
2919         *y = text_view->virtual_cursor_y;
2920       else
2921         *y = strong_pos.y + strong_pos.height / 2;
2922     }
2923 }
2924
2925 static void
2926 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
2927                                       gint         x,
2928                                       gint         y)
2929 {
2930   GdkRectangle strong_pos;
2931   GtkTextIter insert;
2932
2933   gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
2934                                     gtk_text_buffer_get_mark (text_view->buffer,
2935                                                               "insert"));
2936   
2937   if (x == -1 || y == -1)
2938     gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
2939
2940   text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
2941   text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
2942 }