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