1 /* GTK - The GIMP Toolkit
2 * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
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.
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.
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.
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/.
29 #include "gtkbindings.h"
34 #include "gtkmenuitem.h"
35 #include "gtksignal.h"
37 #include "gtktextdisplay.h"
38 #include "gtktextview.h"
39 #include "gtkimmulticontext.h"
40 #include "gdk/gdkkeysyms.h"
43 #define FOCUS_EDGE_WIDTH 1
44 #define DRAG_THRESHOLD 8
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)
58 SET_SCROLL_ADJUSTMENTS,
66 ARG_PIXELS_ABOVE_LINES,
67 ARG_PIXELS_BELOW_LINES,
68 ARG_PIXELS_INSIDE_WRAP,
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,
81 static void gtk_text_view_get_arg (GtkObject *object,
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,
96 static gint gtk_text_view_key_press_event (GtkWidget *widget,
98 static gint gtk_text_view_key_release_event (GtkWidget *widget,
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,
112 static gint gtk_text_view_expose_event (GtkWidget *widget,
113 GdkEventExpose *expose);
114 static void gtk_text_view_draw_focus (GtkWidget *widget);
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,
126 static void gtk_text_view_drag_data_delete (GtkWidget *widget,
127 GdkDragContext *context);
129 /* Target side drag signals */
130 static void gtk_text_view_drag_leave (GtkWidget *widget,
131 GdkDragContext *context,
133 static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
134 GdkDragContext *context,
138 static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
139 GdkDragContext *context,
143 static void gtk_text_view_drag_data_received (GtkWidget *widget,
144 GdkDragContext *context,
147 GtkSelectionData *selection_data,
151 static void gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
153 GtkAdjustment *vadj);
155 static void gtk_text_view_move_cursor (GtkTextView *text_view,
156 GtkMovementStep step,
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,
162 static void gtk_text_view_insert_at_cursor (GtkTextView *text_view,
164 static void gtk_text_view_delete_from_cursor (GtkTextView *text_view,
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);
173 static void gtk_text_view_validate_onscreen (GtkTextView *text_view);
174 static void gtk_text_view_get_first_para_iter (GtkTextView *text_view,
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,
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);
194 static void gtk_text_view_value_changed (GtkAdjustment *adj,
196 static void gtk_text_view_commit_handler (GtkIMContext *context,
198 GtkTextView *text_view);
199 static void gtk_text_view_preedit_changed_handler (GtkIMContext *context,
200 GtkTextView *text_view);
202 static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
203 const GtkTextIter *location,
206 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
209 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
213 static GtkAdjustment* get_hadjustment (GtkTextView *text_view);
214 static GtkAdjustment* get_vadjustment (GtkTextView *text_view);
216 static void gtk_text_view_popup_menu (GtkTextView *text_view,
217 GdkEventButton *event);
219 /* Container methods */
220 static void gtk_text_view_add (GtkContainer *container,
222 static void gtk_text_view_remove (GtkContainer *container,
224 static void gtk_text_view_forall (GtkContainer *container,
225 gboolean include_internals,
226 GtkCallback callback,
227 gpointer callback_data);
229 /* FIXME probably need the focus methods. */
231 typedef struct _GtkTextViewChild GtkTextViewChild;
233 struct _GtkTextViewChild
237 GtkTextChildAnchor *anchor;
239 /* These are ignored if anchor != NULL */
240 GtkTextWindowType type;
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,
252 static void text_view_child_free (GtkTextViewChild *child);
254 static void text_view_child_realize (GtkTextView *text_view,
255 GtkTextViewChild *child);
257 struct _GtkTextWindow
259 GtkTextWindowType type;
262 GdkWindow *bin_window;
263 GtkRequisition requisition;
264 GdkRectangle allocation;
267 static GtkTextWindow *text_window_new (GtkTextWindowType type,
270 gint height_request);
271 static void text_window_free (GtkTextWindow *win);
272 static void text_window_realize (GtkTextWindow *win,
274 static void text_window_unrealize (GtkTextWindow *win);
275 static void text_window_size_allocate (GtkTextWindow *win,
277 static void text_window_scroll (GtkTextWindow *win,
280 static void text_window_invalidate_rect (GtkTextWindow *win,
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,
293 TARGET_COMPOUND_TEXT,
295 TARGET_TEXT_BUFFER_CONTENTS
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 }
308 static GtkContainerClass *parent_class = NULL;
309 static guint signals[LAST_SIGNAL] = { 0 };
312 gtk_text_view_get_type (void)
314 static GtkType our_type = 0;
318 static const GtkTypeInfo our_info =
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
330 our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
337 add_move_binding (GtkBindingSet *binding_set,
340 GtkMovementStep step,
343 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
345 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
349 GTK_TYPE_BOOL, FALSE);
351 /* Selection-extending version */
352 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
356 GTK_TYPE_BOOL, TRUE);
360 gtk_text_view_class_init (GtkTextViewClass *klass)
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;
368 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
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);
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);
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,
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);
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);
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,
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,
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,
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,
457 signals[SET_SCROLL_ADJUSTMENTS] = widget_class->set_scroll_adjustments_signal =
458 gtk_signal_new ("set_scroll_adjustments",
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);
465 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
471 binding_set = gtk_binding_set_by_class (klass);
473 /* Moving the insertion point */
474 add_move_binding (binding_set, GDK_Right, 0,
475 GTK_MOVEMENT_POSITIONS, 1);
477 add_move_binding (binding_set, GDK_Left, 0,
478 GTK_MOVEMENT_POSITIONS, -1);
480 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
481 GTK_MOVEMENT_CHARS, 1);
483 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
484 GTK_MOVEMENT_CHARS, -1);
486 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
487 GTK_MOVEMENT_WORDS, 1);
489 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
490 GTK_MOVEMENT_WORDS, -1);
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);
496 add_move_binding (binding_set, GDK_Down, 0,
497 GTK_MOVEMENT_DISPLAY_LINES, 1);
499 add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
500 GTK_MOVEMENT_DISPLAY_LINES, -1);
502 add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
503 GTK_MOVEMENT_DISPLAY_LINES, 1);
505 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
506 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
508 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
509 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
511 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
512 GTK_MOVEMENT_WORDS, 1);
514 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
515 GTK_MOVEMENT_WORDS, -1);
517 add_move_binding (binding_set, GDK_Home, 0,
518 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
520 add_move_binding (binding_set, GDK_End, 0,
521 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
523 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
524 GTK_MOVEMENT_BUFFER_ENDS, -1);
526 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
527 GTK_MOVEMENT_BUFFER_ENDS, 1);
529 add_move_binding (binding_set, GDK_Page_Up, 0,
530 GTK_MOVEMENT_PAGES, -1);
532 add_move_binding (binding_set, GDK_Page_Down, 0,
533 GTK_MOVEMENT_PAGES, 1);
536 /* Setting the cut/paste/copy anchor */
537 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
541 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
542 "delete_from_cursor", 2,
543 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
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,
551 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
552 "delete_from_cursor", 2,
553 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
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,
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,
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,
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,
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,
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,
585 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
586 "insert_at_cursor", 1,
587 GTK_TYPE_STRING, " ");
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,
596 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
599 gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
602 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
603 "copy_clipboard", 0);
605 gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
606 "paste_clipboard", 0);
608 gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
609 "paste_clipboard", 0);
612 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
613 "toggle_overwrite", 0);
616 * Default handlers and virtual methods
618 object_class->set_arg = gtk_text_view_set_arg;
619 object_class->get_arg = gtk_text_view_get_arg;
621 object_class->destroy = gtk_text_view_destroy;
622 gobject_class->finalize = gtk_text_view_finalize;
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;
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;
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;
652 container_class->add = gtk_text_view_add;
653 container_class->remove = gtk_text_view_remove;
654 container_class->forall = gtk_text_view_forall;
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;
668 gtk_text_view_init (GtkTextView *text_view)
672 widget = GTK_WIDGET (text_view);
674 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
676 text_view->wrap_mode = GTK_WRAPMODE_NONE;
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);
683 text_view->virtual_cursor_x = -1;
684 text_view->virtual_cursor_y = -1;
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 ().
689 text_view->im_context = gtk_im_multicontext_new ();
691 gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
692 GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
694 gtk_signal_connect (GTK_OBJECT (text_view->im_context), "preedit_changed",
695 GTK_SIGNAL_FUNC (gtk_text_view_preedit_changed_handler), text_view);
697 text_view->editable = TRUE;
698 text_view->cursor_visible = TRUE;
700 text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
703 text_view->drag_start_x = -1;
704 text_view->drag_start_y = -1;
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().
715 * Return value: a new #GtkTextView
718 gtk_text_view_new (void)
720 return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
724 * gtk_text_view_new_with_buffer:
725 * @buffer: a #GtkTextBuffer
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.
734 * Return value: a new #GtkTextView.
737 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
739 GtkTextView *text_view;
741 text_view = (GtkTextView*)gtk_text_view_new ();
743 gtk_text_view_set_buffer (text_view, buffer);
745 return GTK_WIDGET (text_view);
749 * gtk_text_view_set_buffer:
750 * @text_view: a #GtkTextView
751 * @buffer: a #GtkTextBuffer
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.
761 gtk_text_view_set_buffer (GtkTextView *text_view,
762 GtkTextBuffer *buffer)
764 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
765 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
767 if (text_view->buffer == buffer)
770 if (text_view->buffer != NULL)
772 /* Destroy all anchored children */
776 copy = g_slist_copy (text_view->children);
778 while (tmp_list != NULL)
780 GtkTextViewChild *vc = tmp_list->data;
784 gtk_widget_destroy (vc->widget);
785 /* vc may now be invalid! */
788 tmp_list = g_slist_next (tmp_list);
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;
799 text_view->buffer = buffer;
805 gtk_object_ref (GTK_OBJECT (buffer));
806 gtk_object_sink (GTK_OBJECT (buffer));
808 if (text_view->layout)
809 gtk_text_layout_set_buffer (text_view->layout, buffer);
811 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
813 text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
817 text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
821 text_view->first_para_pixels = 0;
823 gtk_signal_connect (GTK_OBJECT (text_view->buffer), "mark_set",
824 gtk_text_view_mark_set_handler, text_view);
827 if (GTK_WIDGET_VISIBLE (text_view))
828 gtk_widget_queue_draw (GTK_WIDGET (text_view));
831 static GtkTextBuffer*
832 get_buffer (GtkTextView *text_view)
834 if (text_view->buffer == NULL)
837 b = gtk_text_buffer_new (NULL);
838 gtk_text_view_set_buffer (text_view, b);
839 g_object_unref (G_OBJECT (b));
842 return text_view->buffer;
846 * gtk_text_view_get_buffer:
847 * @text_view: a #GtkTextView
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.
853 * Return value: a #GtkTextBuffer
856 gtk_text_view_get_buffer (GtkTextView *text_view)
858 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
860 return get_buffer (text_view);
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
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().
878 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
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);
887 gtk_text_layout_get_iter_at_pixel (text_view->layout,
894 * gtk_text_view_get_iter_location:
895 * @text_view: a #GtkTextView
896 * @iter: a #GtkTextIter
897 * @location: bounds of the character at @iter
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.
906 gtk_text_view_get_iter_location (GtkTextView *text_view,
907 const GtkTextIter *iter,
908 GdkRectangle *location)
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));
913 gtk_text_layout_get_iter_location (text_view->layout, iter, location);
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
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().
929 gtk_text_view_get_line_yrange (GtkTextView *text_view,
930 const GtkTextIter *iter,
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));
937 gtk_text_layout_get_line_yrange (text_view->layout,
944 * gtk_text_view_get_line_at_y:
945 * @text_view: a #GtkTextView
946 * @target_iter: a #GtkTextIter
948 * @line_top: return location for top coordinate of the line
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
957 gtk_text_view_get_line_at_y (GtkTextView *text_view,
958 GtkTextIter *target_iter,
962 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
964 gtk_text_layout_get_line_at_y (text_view->layout,
971 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
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;
979 if (val < adj->lower)
982 gtk_adjustment_set_value (adj, val);
986 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
997 gboolean retval = FALSE;
1000 gint current_x_scroll, current_y_scroll;
1002 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1003 g_return_val_if_fail (mark != NULL, FALSE);
1005 widget = GTK_WIDGET (text_view);
1007 if (!GTK_WIDGET_MAPPED (widget))
1009 g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
1013 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1015 gtk_text_layout_get_iter_location (text_view->layout,
1019 /* Be sure the scroll region is up-to-date */
1020 gtk_text_view_scroll_calc_now (text_view);
1022 current_x_scroll = text_view->xoffset;
1023 current_y_scroll = text_view->yoffset;
1025 screen.x = current_x_scroll;
1026 screen.y = current_y_scroll;
1027 screen.width = SCREEN_WIDTH (widget);
1028 screen.height = SCREEN_HEIGHT (widget);
1031 /* Clamp margin so it's not too large. */
1032 gint small_dimension = MIN (screen.width, screen.height);
1035 if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
1036 margin = (small_dimension/2 - 5);
1041 /* make sure rectangle fits in the leftover space */
1043 max_rect_dim = MAX (rect.width, rect.height);
1045 if (max_rect_dim > (small_dimension - margin*2))
1046 margin -= max_rect_dim - (small_dimension - margin*2);
1052 g_assert (margin >= 0);
1057 screen.width -= margin*2;
1058 screen.height -= margin*2;
1060 screen_bottom = screen.y + screen.height;
1061 screen_right = screen.x + screen.width;
1063 /* Vertical scroll (only vertical gets adjusted) */
1066 if (rect.y < screen.y)
1068 gint scroll_dest = rect.y;
1069 scroll_inc = (scroll_dest - screen.y) * percentage;
1071 else if ((rect.y + rect.height) > screen_bottom)
1073 gint scroll_dest = rect.y + rect.height;
1074 scroll_inc = (scroll_dest - screen_bottom) * percentage;
1077 if (scroll_inc != 0)
1079 set_adjustment_clamped (get_vadjustment (text_view),
1080 current_y_scroll + scroll_inc);
1084 /* Horizontal scroll */
1087 if (rect.x < screen.x)
1089 gint scroll_dest = rect.x;
1090 scroll_inc = scroll_dest - screen.x;
1092 else if ((rect.x + rect.width) > screen_right)
1094 gint scroll_dest = rect.x + rect.width;
1095 scroll_inc = scroll_dest - screen_right;
1098 if (scroll_inc != 0)
1100 set_adjustment_clamped (get_hadjustment (text_view),
1101 current_x_scroll + scroll_inc);
1109 * gtk_text_view_scroll_to_mark:
1110 * @text_view: a #GtkTextView
1111 * @mark: a #GtkTextMark
1112 * @mark_within_margin: a margin
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,
1120 * Return value: TRUE if scrolling occurred
1123 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
1125 gint mark_within_margin)
1127 g_return_val_if_fail (mark_within_margin >= 0, FALSE);
1129 return gtk_text_view_scroll_to_mark_adjusted (text_view, mark,
1130 mark_within_margin, 1.0);
1134 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
1136 GdkRectangle visible_rect;
1137 gtk_text_view_get_visible_rect (text_view, &visible_rect);
1139 return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
1141 visible_rect.y + visible_rect.height);
1145 * gtk_text_view_move_mark_onscreen:
1146 * @text_view: a #GtkTextView
1147 * @mark: a #GtkTextMark
1149 * Moves a mark within the buffer so that it's
1150 * located within the currently-visible text area.
1152 * Return value: %TRUE if scrolling occurred
1155 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
1160 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1161 g_return_val_if_fail (mark != NULL, FALSE);
1163 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
1165 if (clamp_iter_onscreen (text_view, &iter))
1167 gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
1175 * gtk_text_view_get_visible_rect:
1176 * @text_view: a #GtkTextView
1177 * @visible_rect: rectangle to fill
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().
1184 gtk_text_view_get_visible_rect (GtkTextView *text_view,
1185 GdkRectangle *visible_rect)
1189 g_return_if_fail (text_view != NULL);
1190 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1192 widget = GTK_WIDGET (text_view);
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);
1204 * gtk_text_view_set_wrap_mode:
1205 * @text_view: a #GtkTextView
1206 * @wrap_mode: a #GtkWrapMode
1208 * Sets the line wrapping for the view.
1211 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
1212 GtkWrapMode wrap_mode)
1214 g_return_if_fail (text_view != NULL);
1215 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1217 if (text_view->wrap_mode != wrap_mode)
1219 text_view->wrap_mode = wrap_mode;
1221 if (text_view->layout)
1223 text_view->layout->default_style->wrap_mode = wrap_mode;
1224 gtk_text_layout_default_style_changed (text_view->layout);
1230 * gtk_text_view_get_wrap_mode:
1231 * @text_view: a #GtkTextView
1233 * Gets the line wrapping for the view.
1235 * Return value: the line wrap setting
1238 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
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);
1243 return text_view->wrap_mode;
1247 * gtk_text_view_set_editable:
1248 * @text_view: a #GtkTextView
1249 * @setting: whether it's editable
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.
1256 gtk_text_view_set_editable (GtkTextView *text_view,
1259 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1261 if (text_view->editable != setting)
1263 text_view->editable = setting;
1265 if (text_view->layout)
1267 text_view->layout->default_style->editable = text_view->editable;
1268 gtk_text_layout_default_style_changed (text_view->layout);
1274 * gtk_text_view_get_editable:
1275 * @text_view: a #GtkTextView
1277 * Returns the default editability of the #GtkTextView. Tags in the
1278 * buffer may override this setting for some ranges of text.
1280 * Return value: whether text is editable by default
1283 gtk_text_view_get_editable (GtkTextView *text_view)
1285 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1287 return text_view->editable;
1291 * gtk_text_view_set_cursor_visible:
1292 * @text_view: a #GtkTextView
1293 * @setting: whether to show the insertion cursor
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
1300 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
1303 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1305 setting = (setting != FALSE);
1307 if (text_view->cursor_visible != setting)
1309 text_view->cursor_visible = setting;
1311 if (GTK_WIDGET_HAS_FOCUS (text_view))
1313 if (text_view->layout)
1315 gtk_text_layout_set_cursor_visible (text_view->layout, setting);
1318 gtk_text_view_start_cursor_blink (text_view);
1320 gtk_text_view_stop_cursor_blink (text_view);
1327 * gtk_text_view_get_cursor_visible:
1328 * @text_view: a #GtkTextView
1330 * Find out whether the cursor is being displayed.
1332 * Return value: whether the insertion mark is visible
1335 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
1337 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1339 return text_view->cursor_visible;
1344 * gtk_text_view_place_cursor_onscreen:
1345 * @text_view: a #GtkTextView
1347 * Moves the cursor to the currently visible region of the
1348 * buffer, it it isn't there already.
1350 * Return value: TRUE if the cursor had to be moved.
1353 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
1357 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1359 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
1360 gtk_text_buffer_get_mark (get_buffer (text_view),
1363 if (clamp_iter_onscreen (text_view, &insert))
1365 gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
1373 gtk_text_view_destroy (GtkObject *object)
1375 GtkTextView *text_view;
1377 text_view = GTK_TEXT_VIEW (object);
1379 gtk_text_view_destroy_layout (text_view);
1380 gtk_text_view_set_buffer (text_view, NULL);
1382 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1386 gtk_text_view_finalize (GObject *object)
1388 GtkTextView *text_view;
1390 text_view = GTK_TEXT_VIEW (object);
1392 g_return_if_fail (text_view->buffer == NULL);
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));
1399 text_window_free (text_view->text_window);
1401 if (text_view->left_window)
1402 text_window_free (text_view->left_window);
1404 if (text_view->top_window)
1405 text_window_free (text_view->top_window);
1407 if (text_view->right_window)
1408 text_window_free (text_view->right_window);
1410 if (text_view->bottom_window)
1411 text_window_free (text_view->bottom_window);
1413 gtk_object_unref (GTK_OBJECT (text_view->im_context));
1415 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1419 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1421 GtkTextView *text_view;
1423 text_view = GTK_TEXT_VIEW (object);
1427 case ARG_HEIGHT_LINES:
1430 case ARG_WIDTH_COLUMNS:
1433 case ARG_PIXELS_ABOVE_LINES:
1436 case ARG_PIXELS_BELOW_LINES:
1439 case ARG_PIXELS_INSIDE_WRAP:
1449 g_assert_not_reached ();
1455 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1457 GtkTextView *text_view;
1459 text_view = GTK_TEXT_VIEW (object);
1463 case ARG_HEIGHT_LINES:
1466 case ARG_WIDTH_COLUMNS:
1469 case ARG_PIXELS_ABOVE_LINES:
1472 case ARG_PIXELS_BELOW_LINES:
1475 case ARG_PIXELS_INSIDE_WRAP:
1485 arg->type = GTK_TYPE_INVALID;
1491 gtk_text_view_size_request (GtkWidget *widget,
1492 GtkRequisition *requisition)
1494 GtkTextView *text_view;
1497 text_view = GTK_TEXT_VIEW (widget);
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;
1502 if (text_view->left_window)
1503 requisition->width += text_view->left_window->requisition.width;
1505 if (text_view->right_window)
1506 requisition->width += text_view->right_window->requisition.width;
1508 if (text_view->top_window)
1509 requisition->height += text_view->top_window->requisition.height;
1511 if (text_view->bottom_window)
1512 requisition->height += text_view->bottom_window->requisition.height;
1514 tmp_list = text_view->children;
1515 while (tmp_list != NULL)
1517 GtkTextViewChild *child = tmp_list->data;
1521 GtkRequisition child_req;
1522 GtkRequisition old_req;
1524 old_req = child->widget->requisition;
1526 gtk_widget_size_request (child->widget, &child_req);
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,
1539 tmp_list = g_slist_next (tmp_list);
1544 gtk_text_view_allocate_children (GtkTextView *text_view)
1550 tmp_list = text_view->children;
1551 while (tmp_list != NULL)
1553 GtkTextViewChild *child = tmp_list->data;
1557 /* We need to force-validate the regions containing
1560 GtkTextIter child_loc;
1561 gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
1565 gtk_text_layout_validate_yrange (text_view->layout,
1574 tmp_list = g_slist_next (tmp_list);
1579 gtk_text_view_size_allocate (GtkWidget *widget,
1580 GtkAllocation *allocation)
1582 GtkTextView *text_view;
1583 GtkTextIter first_para;
1585 GtkAdjustment *vadj;
1586 gboolean yoffset_changed = FALSE;
1588 GdkRectangle text_rect;
1589 GdkRectangle left_rect;
1590 GdkRectangle right_rect;
1591 GdkRectangle top_rect;
1592 GdkRectangle bottom_rect;
1594 text_view = GTK_TEXT_VIEW (widget);
1596 widget->allocation = *allocation;
1598 if (GTK_WIDGET_REALIZED (widget))
1600 gdk_window_move_resize (widget->window,
1601 allocation->x, allocation->y,
1602 allocation->width, allocation->height);
1605 /* distribute width/height among child windows. Ensure all
1606 * windows get at least a 1x1 allocation.
1609 width = allocation->width - FOCUS_EDGE_WIDTH * 2;
1611 if (text_view->left_window)
1612 left_rect.width = text_view->left_window->requisition.width;
1614 left_rect.width = 1;
1616 width -= left_rect.width;
1618 if (text_view->right_window)
1619 right_rect.width = text_view->right_window->requisition.width;
1621 right_rect.width = 1;
1623 width -= right_rect.width;
1625 text_rect.width = MAX (1, width);
1627 top_rect.width = text_rect.width;
1628 bottom_rect.width = text_rect.width;
1631 height = allocation->height - FOCUS_EDGE_WIDTH * 2;
1633 if (text_view->top_window)
1634 top_rect.height = text_view->top_window->requisition.height;
1636 top_rect.height = 1;
1638 height -= top_rect.height;
1640 if (text_view->bottom_window)
1641 bottom_rect.height = text_view->bottom_window->requisition.height;
1643 bottom_rect.height = 1;
1645 height -= bottom_rect.height;
1647 text_rect.height = MAX (1, height);
1649 left_rect.height = text_rect.height;
1650 right_rect.height = text_rect.height;
1653 left_rect.x = FOCUS_EDGE_WIDTH;
1654 top_rect.y = FOCUS_EDGE_WIDTH;
1656 text_rect.x = left_rect.x + left_rect.width;
1657 text_rect.y = top_rect.y + top_rect.height;
1659 left_rect.y = text_rect.y;
1660 right_rect.y = text_rect.y;
1662 top_rect.x = text_rect.x;
1663 bottom_rect.x = text_rect.x;
1665 right_rect.x = text_rect.x + text_rect.width;
1666 bottom_rect.y = text_rect.y + text_rect.height;
1668 text_window_size_allocate (text_view->text_window,
1671 if (text_view->left_window)
1672 text_window_size_allocate (text_view->left_window,
1675 if (text_view->right_window)
1676 text_window_size_allocate (text_view->right_window,
1679 if (text_view->top_window)
1680 text_window_size_allocate (text_view->top_window,
1683 if (text_view->bottom_window)
1684 text_window_size_allocate (text_view->bottom_window,
1687 gtk_text_view_ensure_layout (text_view);
1688 gtk_text_layout_set_screen_width (text_view->layout,
1689 SCREEN_WIDTH (text_view));
1691 gtk_text_view_allocate_children (text_view);
1693 gtk_text_view_validate_onscreen (text_view);
1694 gtk_text_view_scroll_calc_now (text_view);
1696 /* Now adjust the value of the adjustment to keep the cursor at the
1697 * same place in the buffer
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);
1702 y += text_view->first_para_pixels;
1704 /* Ensure h/v adj exist */
1705 get_hadjustment (text_view);
1706 get_vadjustment (text_view);
1708 vadj = text_view->vadjustment;
1709 if (y > vadj->upper - vadj->page_size)
1710 y = MAX (0, vadj->upper - vadj->page_size);
1712 if (y != text_view->yoffset)
1714 vadj->value = text_view->yoffset = y;
1715 yoffset_changed = TRUE;
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),
1723 gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
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),
1730 gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
1732 if (yoffset_changed)
1733 gtk_adjustment_value_changed (vadj);
1737 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
1740 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
1741 text_view->first_para_mark);
1745 gtk_text_view_validate_onscreen (GtkTextView *text_view)
1747 GtkWidget *widget = GTK_WIDGET (text_view);
1749 if (SCREEN_HEIGHT (widget) > 0)
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,
1756 text_view->first_para_pixels +
1757 SCREEN_HEIGHT (widget));
1762 first_validate_callback (gpointer data)
1764 GtkTextView *text_view = data;
1766 gtk_text_view_validate_onscreen (text_view);
1768 text_view->first_validate_idle = 0;
1773 incremental_validate_callback (gpointer data)
1775 GtkTextView *text_view = data;
1777 gtk_text_layout_validate (text_view->layout, 2000);
1778 if (gtk_text_layout_is_valid (text_view->layout))
1780 text_view->incremental_validate_idle = 0;
1788 invalidated_handler (GtkTextLayout *layout,
1791 GtkTextView *text_view;
1793 text_view = GTK_TEXT_VIEW (data);
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);
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);
1803 changed_handler (GtkTextLayout *layout,
1809 GtkTextView *text_view;
1811 GdkRectangle visible_rect;
1812 GdkRectangle redraw_rect;
1814 text_view = GTK_TEXT_VIEW (data);
1815 widget = GTK_WIDGET (data);
1817 if (GTK_WIDGET_REALIZED (text_view))
1819 gtk_text_view_get_visible_rect (text_view, &visible_rect);
1821 redraw_rect.x = visible_rect.x;
1822 redraw_rect.width = visible_rect.width;
1823 redraw_rect.y = start_y;
1825 if (old_height == new_height)
1826 redraw_rect.height = old_height;
1828 redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
1830 if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
1832 redraw_rect.y -= text_view->yoffset;
1833 text_window_invalidate_rect (text_view->text_window,
1838 if (old_height != new_height)
1840 gboolean yoffset_changed = FALSE;
1842 if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
1844 text_view->yoffset += new_height - old_height;
1845 get_vadjustment (text_view)->value = text_view->yoffset;
1846 yoffset_changed = TRUE;
1849 gtk_text_view_scroll_calc_now (text_view);
1851 if (yoffset_changed)
1852 gtk_adjustment_value_changed (get_vadjustment (text_view));
1857 gtk_text_view_realize (GtkWidget *widget)
1859 GtkTextView *text_view;
1860 GdkWindowAttr attributes;
1861 gint attributes_mask;
1863 text_view = GTK_TEXT_VIEW (widget);
1864 GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
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;
1876 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
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);
1882 /* must come before text_window_realize calls */
1883 widget->style = gtk_style_attach (widget->style, widget->window);
1885 gdk_window_set_background (widget->window,
1886 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1888 text_window_realize (text_view->text_window, widget->window);
1890 if (text_view->left_window)
1891 text_window_realize (text_view->left_window,
1894 if (text_view->top_window)
1895 text_window_realize (text_view->top_window,
1898 if (text_view->right_window)
1899 text_window_realize (text_view->right_window,
1902 if (text_view->bottom_window)
1903 text_window_realize (text_view->bottom_window,
1906 gtk_text_view_ensure_layout (text_view);
1910 gtk_text_view_unrealize (GtkWidget *widget)
1912 GtkTextView *text_view;
1914 text_view = GTK_TEXT_VIEW (widget);
1916 if (text_view->first_validate_idle)
1918 g_source_remove (text_view->first_validate_idle);
1919 text_view->first_validate_idle = 0;
1922 if (text_view->incremental_validate_idle)
1924 g_source_remove (text_view->incremental_validate_idle);
1925 text_view->incremental_validate_idle = 0;
1928 if (text_view->popup_menu)
1930 gtk_widget_destroy (text_view->popup_menu);
1931 text_view->popup_menu = NULL;
1934 text_window_unrealize (text_view->text_window);
1936 if (text_view->left_window)
1937 text_window_unrealize (text_view->left_window);
1939 if (text_view->top_window)
1940 text_window_unrealize (text_view->top_window);
1942 if (text_view->right_window)
1943 text_window_unrealize (text_view->right_window);
1945 if (text_view->bottom_window)
1946 text_window_unrealize (text_view->bottom_window);
1948 gtk_text_view_destroy_layout (text_view);
1950 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1954 gtk_text_view_style_set (GtkWidget *widget,
1955 GtkStyle *previous_style)
1957 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1959 if (GTK_WIDGET_REALIZED (widget))
1961 gdk_window_set_background (widget->window,
1962 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1964 gdk_window_set_background (text_view->text_window->bin_window,
1965 &widget->style->base[GTK_WIDGET_STATE (widget)]);
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)]);
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)]);
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)]);
1982 gtk_text_view_set_attributes_from_style (text_view,
1983 text_view->layout->default_style,
1985 gtk_text_layout_default_style_changed (text_view->layout);
1990 gtk_text_view_direction_changed (GtkWidget *widget,
1991 GtkTextDirection previous_direction)
1993 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1995 if (text_view->layout)
1997 text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
1998 gtk_text_layout_default_style_changed (text_view->layout);
2007 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
2010 switch (event->type)
2012 case GDK_MOTION_NOTIFY:
2013 *x = event->motion.x;
2014 *y = event->motion.y;
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;
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:
2052 emit_event_on_tags (GtkWidget *widget,
2058 gint retval = FALSE;
2059 GtkTextView *text_view;
2061 text_view = GTK_TEXT_VIEW (widget);
2063 tags = gtk_text_iter_get_tags (iter);
2068 GtkTextTag *tag = tmp->data;
2070 if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
2076 tmp = g_slist_next (tmp);
2079 g_slist_free (tags);
2085 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
2087 GtkTextView *text_view;
2090 text_view = GTK_TEXT_VIEW (widget);
2092 if (text_view->layout == NULL ||
2093 get_buffer (text_view) == NULL)
2096 if (event->any.window != text_view->text_window->bin_window)
2099 if (get_event_coordinates (event, &x, &y))
2103 x += text_view->xoffset;
2104 y += text_view->yoffset;
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,
2113 return emit_event_on_tags (widget, event, &iter);
2115 else if (event->type == GDK_KEY_PRESS ||
2116 event->type == GDK_KEY_RELEASE)
2118 GtkTextMark *insert;
2121 insert = gtk_text_buffer_get_mark (get_buffer (text_view),
2124 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
2126 return emit_event_on_tags (widget, event, &iter);
2133 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
2135 GtkTextView *text_view;
2137 text_view = GTK_TEXT_VIEW (widget);
2139 if (text_view->layout == NULL ||
2140 get_buffer (text_view) == NULL)
2143 if (gtk_im_context_filter_keypress (text_view->im_context, event))
2145 text_view->need_im_reset = TRUE;
2148 else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
2149 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
2151 else if (event->keyval == GDK_Return)
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),
2161 /* Pass through Tab as literal tab, unless Control is held down */
2162 else if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK))
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),
2177 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
2183 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
2185 GtkTextView *text_view;
2187 text_view = GTK_TEXT_VIEW (widget);
2189 gtk_widget_grab_focus (widget);
2191 if (event->window != text_view->text_window->bin_window)
2193 /* Remove selection if any. */
2194 gtk_text_view_unselect (text_view);
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);
2206 if (event->type == GDK_BUTTON_PRESS)
2208 gtk_text_view_reset_im_context (text_view);
2210 if (event->button == 1)
2212 /* If we're in the selection, start a drag copy/move of the
2213 * selection; otherwise, start creating a new selection.
2216 GtkTextIter start, end;
2218 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2220 event->x + text_view->xoffset,
2221 event->y + text_view->yoffset);
2223 if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
2225 gtk_text_iter_in_range (&iter, &start, &end))
2227 text_view->drag_start_x = event->x;
2228 text_view->drag_start_y = event->y;
2232 gtk_text_view_start_selection_drag (text_view, &iter, event);
2237 else if (event->button == 2)
2241 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2243 event->x + text_view->xoffset,
2244 event->y + text_view->yoffset);
2246 gtk_text_buffer_paste_primary (get_buffer (text_view),
2248 text_view->editable);
2251 else if (event->button == 3)
2253 gtk_text_view_popup_menu (text_view, event);
2261 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
2263 GtkTextView *text_view;
2265 text_view = GTK_TEXT_VIEW (widget);
2267 if (event->window != text_view->text_window->bin_window)
2270 if (event->button == 1)
2272 if (text_view->drag_start_x >= 0)
2274 text_view->drag_start_x = -1;
2275 text_view->drag_start_y = -1;
2278 if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
2282 /* Unselect everything; probably we were dragging, or clicked
2285 gtk_text_view_unselect (text_view);
2294 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
2296 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2298 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2299 gtk_widget_draw_focus (widget);
2301 if (text_view->cursor_visible && text_view->layout)
2303 gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
2304 gtk_text_view_start_cursor_blink (text_view);
2307 text_view->need_im_reset = TRUE;
2308 gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
2314 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
2316 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2318 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2319 gtk_widget_draw_focus (widget);
2321 if (text_view->cursor_visible && text_view->layout)
2323 gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
2324 gtk_text_view_stop_cursor_blink (text_view);
2327 text_view->need_im_reset = TRUE;
2328 gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
2334 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
2336 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2338 if (event->window == text_view->text_window->bin_window &&
2339 text_view->drag_start_x >= 0)
2344 gdk_window_get_pointer (text_view->text_window->bin_window,
2347 dx = text_view->drag_start_x - x;
2348 dy = text_view->drag_start_y - y;
2350 if (ABS (dx) > DRAG_THRESHOLD ||
2351 ABS (dy) > DRAG_THRESHOLD)
2354 gint buffer_x, buffer_y;
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,
2363 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2365 buffer_x, buffer_y);
2367 gtk_text_view_start_selection_dnd (text_view, &iter, event);
2376 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
2378 GtkTextView *text_view;
2380 text_view = GTK_TEXT_VIEW (widget);
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);
2386 gtk_text_view_validate_onscreen (text_view);
2389 printf ("painting %d,%d %d x %d\n",
2391 area->width, area->height);
2394 gtk_text_layout_draw (text_view->layout,
2396 text_view->text_window->bin_window,
2400 area->width, area->height);
2404 send_expose (GtkTextView *text_view,
2408 GdkEventExpose event;
2410 event.type = GDK_EXPOSE;
2411 event.send_event = TRUE;
2412 event.window = win->bin_window;
2416 /* Fix coordinates (convert widget coords to window coords) */
2417 gtk_text_view_window_to_buffer_coords (text_view,
2418 GTK_TEXT_WINDOW_WIDGET,
2424 gtk_text_view_buffer_to_window_coords (text_view,
2432 gdk_window_ref (event.window);
2433 gtk_widget_event (GTK_WIDGET (text_view), (GdkEvent*) &event);
2434 gdk_window_unref (event.window);
2438 gtk_text_view_draw (GtkWidget *widget, GdkRectangle *area)
2440 GdkRectangle intersection;
2441 GtkTextView *text_view;
2443 text_view = GTK_TEXT_VIEW (widget);
2445 gtk_text_view_paint (widget, area);
2447 /* If the area overlaps the "edge" of the widget, draw the focus
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);
2456 /* Synthesize expose events for the user-drawn border windows,
2457 * just as we would for a drawing area.
2460 if (text_view->left_window &&
2461 gdk_rectangle_intersect (area, &text_view->left_window->allocation,
2463 send_expose (text_view, text_view->left_window, &intersection);
2465 if (text_view->right_window &&
2466 gdk_rectangle_intersect (area, &text_view->right_window->allocation,
2468 send_expose (text_view, text_view->right_window, &intersection);
2470 if (text_view->top_window &&
2471 gdk_rectangle_intersect (area, &text_view->top_window->allocation,
2473 send_expose (text_view, text_view->top_window, &intersection);
2475 if (text_view->bottom_window &&
2476 gdk_rectangle_intersect (area, &text_view->bottom_window->allocation,
2478 send_expose (text_view, text_view->bottom_window, &intersection);
2482 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
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);
2488 if (event->window == widget->window)
2489 gtk_widget_draw_focus (widget);
2495 gtk_text_view_draw_focus (GtkWidget *widget)
2497 if (GTK_WIDGET_DRAWABLE (widget))
2499 if (GTK_WIDGET_HAS_FOCUS (widget))
2501 gtk_paint_focus (widget->style, widget->window,
2502 NULL, widget, "textview",
2504 widget->allocation.width - 1,
2505 widget->allocation.height - 1);
2509 gdk_window_clear (widget->window);
2519 gtk_text_view_add (GtkContainer *container,
2522 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
2523 g_return_if_fail (GTK_IS_WIDGET (child));
2525 /* This is pretty random. */
2526 gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
2528 GTK_TEXT_WINDOW_WIDGET,
2533 gtk_text_view_remove (GtkContainer *container,
2537 GtkTextView *text_view;
2538 GtkTextViewChild *vc;
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);
2544 text_view = GTK_TEXT_VIEW (container);
2547 iter = text_view->children;
2549 while (iter != NULL)
2553 if (vc->widget == child)
2556 iter = g_slist_next (iter);
2559 g_assert (iter != NULL); /* be sure we had the child in the list */
2561 text_view->children = g_slist_remove (text_view->children, vc);
2563 gtk_widget_unparent (vc->widget);
2565 text_view_child_free (vc);
2569 gtk_text_view_forall (GtkContainer *container,
2570 gboolean include_internals,
2571 GtkCallback callback,
2572 gpointer callback_data)
2575 GtkTextView *text_view;
2577 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
2578 g_return_if_fail (callback != NULL);
2580 text_view = GTK_TEXT_VIEW (container);
2582 iter = text_view->children;
2584 while (iter != NULL)
2586 GtkTextViewChild *vc = iter->data;
2588 (* callback) (vc->widget, callback_data);
2590 iter = g_slist_next (iter);
2599 blink_cb (gpointer data)
2601 GtkTextView *text_view;
2603 text_view = GTK_TEXT_VIEW (data);
2605 g_assert (text_view->layout && GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible);
2607 gtk_text_layout_set_cursor_visible (text_view->layout,
2608 !gtk_text_layout_get_cursor_visible (text_view->layout));
2613 gtk_text_view_start_cursor_blink (GtkTextView *text_view)
2615 if (text_view->blink_timeout != 0)
2618 text_view->blink_timeout = gtk_timeout_add (500, blink_cb, text_view);
2622 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
2624 if (text_view->blink_timeout == 0)
2627 gtk_timeout_remove (text_view->blink_timeout);
2628 text_view->blink_timeout = 0;
2632 * Key binding handlers
2636 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
2637 GtkTextIter *newplace,
2642 gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
2648 gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
2654 gtk_text_view_move_cursor (GtkTextView *text_view,
2655 GtkMovementStep step,
2657 gboolean extend_selection)
2660 GtkTextIter newplace;
2662 gint cursor_x_pos = 0;
2664 gtk_text_view_reset_im_context (text_view);
2666 if (step == GTK_MOVEMENT_PAGES)
2668 gtk_text_view_scroll_pages (text_view, count);
2672 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2673 gtk_text_buffer_get_mark (get_buffer (text_view),
2677 if (step == GTK_MOVEMENT_DISPLAY_LINES)
2678 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
2682 case GTK_MOVEMENT_CHARS:
2683 gtk_text_iter_forward_chars (&newplace, count);
2686 case GTK_MOVEMENT_POSITIONS:
2687 gtk_text_layout_move_iter_visually (text_view->layout,
2691 case GTK_MOVEMENT_WORDS:
2693 gtk_text_iter_backward_word_starts (&newplace, -count);
2695 gtk_text_iter_forward_word_ends (&newplace, count);
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);
2703 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
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);
2710 gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
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); */
2719 case GTK_MOVEMENT_PARAGRAPH_ENDS:
2721 gtk_text_iter_forward_to_newline (&newplace);
2723 gtk_text_iter_set_line_offset (&newplace, 0);
2726 case GTK_MOVEMENT_BUFFER_ENDS:
2728 gtk_text_buffer_get_last_iter (get_buffer (text_view), &newplace);
2730 gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
2737 if (!gtk_text_iter_equal (&insert, &newplace))
2739 if (extend_selection)
2740 gtk_text_buffer_move_mark (get_buffer (text_view),
2741 gtk_text_buffer_get_mark (get_buffer (text_view),
2745 gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
2747 gtk_text_view_scroll_to_mark (text_view,
2748 gtk_text_buffer_get_mark (get_buffer (text_view),
2751 if (step == GTK_MOVEMENT_DISPLAY_LINES)
2753 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
2759 gtk_text_view_set_anchor (GtkTextView *text_view)
2763 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2764 gtk_text_buffer_get_mark (get_buffer (text_view),
2767 gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
2771 gtk_text_view_scroll_pages (GtkTextView *text_view,
2776 gint cursor_x_pos, cursor_y_pos;
2777 GtkTextIter new_insert;
2781 g_return_if_fail (text_view->vadjustment != NULL);
2783 adj = text_view->vadjustment;
2785 /* Validate the region that will be brought into view by the cursor motion
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;
2795 gtk_text_view_get_first_para_iter (text_view, &anchor);
2796 y0 = count * adj->page_increment + adj->page_size;
2800 gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
2802 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
2804 newval = adj->value;
2806 newval += count * adj->page_increment;
2808 cursor_y_pos += newval - adj->value;
2809 set_adjustment_clamped (adj, newval);
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);
2815 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
2817 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
2818 * only guarantees 1 pixel onscreen.
2820 gtk_text_view_scroll_to_mark (text_view,
2821 gtk_text_buffer_get_mark (get_buffer (text_view),
2827 whitespace (gunichar ch, gpointer user_data)
2829 return (ch == ' ' || ch == '\t');
2833 not_whitespace (gunichar ch, gpointer user_data)
2835 return !whitespace (ch, user_data);
2839 find_whitepace_region (const GtkTextIter *center,
2840 GtkTextIter *start, GtkTextIter *end)
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);
2850 return !gtk_text_iter_equal (start, end);
2854 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
2857 gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
2858 text_view->editable);
2862 gtk_text_view_delete_from_cursor (GtkTextView *text_view,
2869 gboolean leave_one = FALSE;
2871 gtk_text_view_reset_im_context (text_view);
2873 if (type == GTK_DELETE_CHARS)
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))
2881 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
2883 gtk_text_buffer_get_mark (get_buffer (text_view),
2891 case GTK_DELETE_CHARS:
2892 gtk_text_iter_forward_chars (&end, count);
2895 case GTK_DELETE_WORD_ENDS:
2897 gtk_text_iter_forward_word_ends (&end, count);
2899 gtk_text_iter_backward_word_starts (&start, 0 - count);
2902 case GTK_DELETE_WORDS:
2905 case GTK_DELETE_DISPLAY_LINE_ENDS:
2908 case GTK_DELETE_DISPLAY_LINES:
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.
2916 if (gtk_text_iter_get_char (&end) == '\n')
2918 gtk_text_iter_next_char (&end);
2924 if (!gtk_text_iter_forward_to_newline (&end))
2930 /* FIXME figure out what a negative count means
2934 case GTK_DELETE_PARAGRAPHS:
2937 gtk_text_iter_set_line_offset (&start, 0);
2938 gtk_text_iter_forward_to_newline (&end);
2940 /* Do the lines beyond the first. */
2943 gtk_text_iter_forward_to_newline (&end);
2949 /* FIXME negative count? */
2953 case GTK_DELETE_WHITESPACE:
2955 find_whitepace_region (&insert, &start, &end);
2963 if (!gtk_text_iter_equal (&start, &end))
2965 if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
2966 text_view->editable))
2969 gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
2971 text_view->editable);
2974 gtk_text_view_scroll_to_mark (text_view,
2975 gtk_text_buffer_get_mark (get_buffer (text_view), "insert"),
2981 gtk_text_view_cut_clipboard (GtkTextView *text_view)
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),
2991 gtk_text_view_copy_clipboard (GtkTextView *text_view)
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),
3001 gtk_text_view_paste_clipboard (GtkTextView *text_view)
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),
3011 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
3013 text_view->overwrite_mode = !text_view->overwrite_mode;
3021 gtk_text_view_unselect (GtkTextView *text_view)
3025 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3027 gtk_text_buffer_get_mark (get_buffer (text_view),
3030 gtk_text_buffer_move_mark (get_buffer (text_view),
3031 gtk_text_buffer_get_mark (get_buffer (text_view),
3037 move_insert_to_pointer_and_scroll (GtkTextView *text_view, gboolean partial_scroll)
3040 GdkModifierType state;
3041 GtkTextIter newplace;
3043 gboolean in_threshold = FALSE;
3045 gdk_window_get_pointer (text_view->text_window->bin_window,
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); */
3055 if (text_view->scrolling_accel_factor > 10)
3056 adjust = (text_view->scrolling_accel_factor - 10) * 75;
3058 if (y < 0) /* scrolling upward */
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))
3071 in_threshold = TRUE;
3074 gtk_text_layout_get_iter_at_pixel (text_view->layout,
3076 x + text_view->xoffset,
3077 y + text_view->yoffset + adjust);
3080 gboolean scrolled = FALSE;
3081 GtkTextMark *insert_mark =
3082 gtk_text_buffer_get_mark (get_buffer (text_view), "insert");
3084 gtk_text_buffer_move_mark (get_buffer (text_view),
3089 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 0.7);
3091 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 1.0);
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
3102 if (text_view->scrolling_accel_factor > 1)
3103 text_view->scrolling_accel_factor -= 2;
3106 text_view->scrolling_accel_factor += 1;
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;
3123 selection_scan_timeout (gpointer data)
3125 GtkTextView *text_view;
3127 text_view = GTK_TEXT_VIEW (data);
3129 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
3131 return TRUE; /* remain installed. */
3135 text_view->selection_drag_scan_timeout = 0;
3136 return FALSE; /* remove ourselves */
3141 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
3143 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
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);
3152 text_view->selection_drag_scan_timeout =
3153 gtk_timeout_add (50, selection_scan_timeout, text_view);
3160 gtk_text_view_start_selection_drag (GtkTextView *text_view,
3161 const GtkTextIter *iter,
3162 GdkEventButton *button)
3164 GtkTextIter newplace;
3166 g_return_if_fail (text_view->selection_drag_handler == 0);
3168 gtk_grab_add (GTK_WIDGET (text_view));
3170 text_view->scrolling_accel_factor = 0;
3174 gtk_text_buffer_place_cursor (get_buffer (text_view), &newplace);
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),
3182 /* returns whether we were really dragging */
3184 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
3186 if (text_view->selection_drag_handler == 0)
3189 gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
3190 text_view->selection_drag_handler = 0;
3192 text_view->scrolling_accel_factor = 0;
3194 if (text_view->selection_drag_scan_timeout != 0)
3196 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
3197 text_view->selection_drag_scan_timeout = 0;
3200 /* one last update to current position */
3201 move_insert_to_pointer_and_scroll (text_view, FALSE);
3203 gtk_grab_remove (GTK_WIDGET (text_view));
3213 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
3215 if (upper != adj->upper)
3217 gfloat min = MAX (0., upper - adj->page_size);
3218 gboolean value_changed = FALSE;
3222 if (adj->value > min)
3225 value_changed = TRUE;
3228 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
3230 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3235 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
3237 gint width = 0, height = 0;
3239 gtk_text_view_ensure_layout (text_view);
3242 gtk_text_layout_set_screen_width (text_view->layout,
3243 SCREEN_WIDTH (text_view));
3245 gtk_text_layout_get_size (text_view->layout, &width, &height);
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.
3256 width = MAX (text_view->layout->screen_width, width);
3260 if (text_view->width != width || text_view->height != height)
3263 printf ("layout size set, widget width is %d\n",
3264 GTK_WIDGET (text_view)->allocation.width);
3266 text_view->width = width;
3267 text_view->height = height;
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));
3274 /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
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;
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;
3292 gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
3293 GtkTextAttributes *values,
3296 values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
3297 values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
3299 if (values->font_desc)
3300 pango_font_description_free (values->font_desc);
3302 values->font_desc = pango_font_description_copy (style->font_desc);
3306 gtk_text_view_ensure_layout (GtkTextView *text_view)
3310 widget = GTK_WIDGET (text_view);
3312 if (text_view->layout == NULL)
3314 GtkTextAttributes *style;
3315 PangoContext *ltr_context, *rtl_context;
3317 text_view->layout = gtk_text_layout_new ();
3319 gtk_signal_connect (GTK_OBJECT (text_view->layout),
3321 GTK_SIGNAL_FUNC (invalidated_handler),
3324 gtk_signal_connect (GTK_OBJECT (text_view->layout),
3326 GTK_SIGNAL_FUNC (changed_handler),
3329 if (get_buffer (text_view))
3330 gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
3332 if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
3333 gtk_text_view_start_cursor_blink (text_view);
3335 gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
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);
3342 gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
3344 g_object_unref (G_OBJECT (ltr_context));
3345 g_object_unref (G_OBJECT (rtl_context));
3347 style = gtk_text_attributes_new ();
3349 gtk_widget_ensure_style (widget);
3350 gtk_text_view_set_attributes_from_style (text_view,
3351 style, widget->style);
3353 style->pixels_above_lines = 2;
3354 style->pixels_below_lines = 2;
3355 style->pixels_inside_wrap = 1;
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));
3361 gtk_text_layout_set_default_style (text_view->layout, style);
3363 gtk_text_attributes_unref (style);
3368 gtk_text_view_destroy_layout (GtkTextView *text_view)
3370 if (text_view->layout)
3372 gtk_text_view_stop_cursor_blink (text_view);
3373 gtk_text_view_end_selection_drag (text_view, NULL);
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;
3385 gtk_text_view_reset_im_context (GtkTextView *text_view)
3387 if (text_view->need_im_reset)
3388 text_view->need_im_reset = 0;
3390 gtk_im_context_reset (text_view->im_context);
3398 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
3399 const GtkTextIter *iter,
3400 GdkEventMotion *event)
3402 GdkDragContext *context;
3403 GtkTargetList *target_list;
3405 text_view->drag_start_x = -1;
3406 text_view->drag_start_y = -1;
3408 target_list = gtk_target_list_new (target_table,
3409 G_N_ELEMENTS (target_table));
3411 context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
3412 GDK_ACTION_COPY | GDK_ACTION_MOVE,
3413 1, (GdkEvent*)event);
3415 gtk_target_list_unref (target_list);
3417 gtk_drag_set_icon_default (context);
3419 /* We're inside the selection, so start without being able
3420 * to accept the drag.
3422 gdk_drag_status (context, 0, event->time);
3423 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3427 gtk_text_view_drag_begin (GtkWidget *widget,
3428 GdkDragContext *context)
3434 gtk_text_view_drag_end (GtkWidget *widget,
3435 GdkDragContext *context)
3437 GtkTextView *text_view;
3439 text_view = GTK_TEXT_VIEW (widget);
3441 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3445 gtk_text_view_drag_data_get (GtkWidget *widget,
3446 GdkDragContext *context,
3447 GtkSelectionData *selection_data,
3451 GtkTextView *text_view;
3453 text_view = GTK_TEXT_VIEW (widget);
3455 if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
3457 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
3459 gtk_selection_data_set (selection_data,
3460 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
3473 if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
3476 /* Extract the selected text */
3477 str = gtk_text_iter_get_visible_text (&start, &end);
3482 gtk_selection_data_set_text (selection_data, str);
3489 gtk_text_view_drag_data_delete (GtkWidget *widget,
3490 GdkDragContext *context)
3492 GtkTextView *text_view;
3494 text_view = GTK_TEXT_VIEW (widget);
3496 gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
3497 TRUE, GTK_TEXT_VIEW (widget)->editable);
3501 gtk_text_view_drag_leave (GtkWidget *widget,
3502 GdkDragContext *context,
3510 gtk_text_view_drag_motion (GtkWidget *widget,
3511 GdkDragContext *context,
3516 GtkTextIter newplace;
3517 GtkTextView *text_view;
3520 GdkRectangle target_rect;
3523 text_view = GTK_TEXT_VIEW (widget);
3525 target_rect = text_view->text_window->allocation;
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 */
3533 gtk_text_view_window_to_buffer_coords (text_view,
3534 GTK_TEXT_WINDOW_WIDGET,
3538 gtk_text_layout_get_iter_at_pixel (text_view->layout,
3542 if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
3544 gtk_text_iter_in_range (&newplace, &start, &end))
3546 /* We're inside the selection. */
3547 gdk_drag_status (context, 0, time);
3548 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3552 if (gtk_text_iter_editable (&newplace, text_view->editable))
3554 gtk_text_mark_set_visible (text_view->dnd_mark,
3555 text_view->cursor_visible);
3557 gdk_drag_status (context, context->suggested_action, time);
3561 /* Can't drop here. */
3562 gdk_drag_status (context, 0, time);
3563 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3567 gtk_text_buffer_move_mark (get_buffer (text_view),
3568 gtk_text_buffer_get_mark (get_buffer (text_view),
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
3578 margin = MIN (SCREEN_WIDTH (widget), SCREEN_HEIGHT (widget));
3581 gtk_text_view_scroll_to_mark_adjusted (text_view,
3582 gtk_text_buffer_get_mark (get_buffer (text_view),
3591 gtk_text_view_drag_drop (GtkWidget *widget,
3592 GdkDragContext *context,
3598 /* called automatically. */
3599 if (context->targets)
3601 gtk_drag_get_data (widget, context,
3602 GPOINTER_TO_INT (context->targets->data),
3613 insert_text_data (GtkTextView *text_view,
3614 GtkTextIter *drop_point,
3615 GtkSelectionData *selection_data)
3619 str = gtk_selection_data_get_text (selection_data);
3623 gtk_text_buffer_insert_interactive (get_buffer (text_view),
3624 drop_point, str, -1,
3625 text_view->editable);
3631 gtk_text_view_drag_data_received (GtkWidget *widget,
3632 GdkDragContext *context,
3635 GtkSelectionData *selection_data,
3639 GtkTextIter drop_point;
3640 GtkTextView *text_view;
3641 GtkTextMark *drag_target_mark;
3643 text_view = GTK_TEXT_VIEW (widget);
3645 drag_target_mark = gtk_text_buffer_get_mark (get_buffer (text_view),
3648 if (drag_target_mark == NULL)
3651 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
3655 if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
3657 GtkTextBuffer *src_buffer = NULL;
3658 GtkTextIter start, end;
3659 gboolean copy_tags = TRUE;
3661 if (selection_data->length != sizeof (src_buffer))
3664 memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
3666 if (src_buffer == NULL)
3669 g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
3671 if (gtk_text_buffer_get_tag_table (src_buffer) !=
3672 gtk_text_buffer_get_tag_table (get_buffer (text_view)))
3675 if (gtk_text_buffer_get_selection_bounds (src_buffer,
3680 gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
3684 text_view->editable);
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);
3698 insert_text_data (text_view, &drop_point, selection_data);
3701 static GtkAdjustment*
3702 get_hadjustment (GtkTextView *text_view)
3704 if (text_view->hadjustment == NULL)
3705 gtk_text_view_set_scroll_adjustments (text_view,
3707 gtk_adjustment_new (0.0, 0.0, 0.0,
3709 text_view->vadjustment);
3711 return text_view->hadjustment;
3714 static GtkAdjustment*
3715 get_vadjustment (GtkTextView *text_view)
3717 if (text_view->vadjustment == NULL)
3718 gtk_text_view_set_scroll_adjustments (text_view,
3719 text_view->hadjustment,
3721 gtk_adjustment_new (0.0, 0.0, 0.0,
3724 return text_view->vadjustment;
3729 gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
3730 GtkAdjustment *hadj,
3731 GtkAdjustment *vadj)
3733 gboolean need_adjust = FALSE;
3735 g_return_if_fail (text_view != NULL);
3736 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
3739 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
3741 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3743 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
3745 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3747 if (text_view->hadjustment && (text_view->hadjustment != hadj))
3749 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
3750 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
3753 if (text_view->vadjustment && (text_view->vadjustment != vadj))
3755 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
3756 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
3759 if (text_view->hadjustment != hadj)
3761 text_view->hadjustment = hadj;
3762 gtk_object_ref (GTK_OBJECT (text_view->hadjustment));
3763 gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
3765 gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
3766 (GtkSignalFunc) gtk_text_view_value_changed,
3771 if (text_view->vadjustment != vadj)
3773 text_view->vadjustment = vadj;
3774 gtk_object_ref (GTK_OBJECT (text_view->vadjustment));
3775 gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
3777 gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
3778 (GtkSignalFunc) gtk_text_view_value_changed,
3784 gtk_text_view_value_changed (NULL, text_view);
3788 gtk_text_view_value_changed (GtkAdjustment *adj,
3789 GtkTextView *text_view)
3796 if (adj == text_view->hadjustment)
3798 dx = text_view->xoffset - (gint)adj->value;
3799 text_view->xoffset = adj->value;
3801 else if (adj == text_view->vadjustment)
3803 dy = text_view->yoffset - (gint)adj->value;
3804 text_view->yoffset = adj->value;
3806 if (text_view->layout)
3808 gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
3810 gtk_text_buffer_move_mark (get_buffer (text_view), text_view->first_para_mark, &iter);
3812 text_view->first_para_pixels = adj->value - line_top;
3816 if (dx != 0 || dy != 0)
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);
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);
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
3839 text_window_scroll (text_view->text_window, dx, dy);
3844 gtk_text_view_commit_handler (GtkIMContext *context,
3846 GtkTextView *text_view)
3848 gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
3849 text_view->editable);
3851 if (!strcmp (str, "\n"))
3853 gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
3854 text_view->editable);
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);
3864 gtk_text_view_scroll_to_mark (text_view,
3865 gtk_text_buffer_get_mark (get_buffer (text_view),
3871 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
3872 GtkTextView *text_view)
3875 PangoAttrList *attrs;
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);
3881 pango_attr_list_unref (attrs);
3886 gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
3887 const GtkTextIter *location,
3891 GtkTextView *text_view = GTK_TEXT_VIEW (data);
3892 gboolean need_reset = FALSE;
3894 if (mark == gtk_text_buffer_get_insert (buffer))
3896 text_view->virtual_cursor_x = -1;
3897 text_view->virtual_cursor_y = -1;
3900 else if (mark == gtk_text_buffer_get_selection_bound (buffer))
3906 gtk_text_view_reset_im_context (text_view);
3910 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
3914 GdkRectangle strong_pos;
3917 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3918 gtk_text_buffer_get_mark (get_buffer (text_view),
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);
3927 if (text_view->virtual_cursor_x != -1)
3928 *x = text_view->virtual_cursor_x;
3935 if (text_view->virtual_cursor_x != -1)
3936 *y = text_view->virtual_cursor_y;
3938 *y = strong_pos.y + strong_pos.height / 2;
3943 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
3947 GdkRectangle strong_pos;
3950 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
3951 gtk_text_buffer_get_mark (get_buffer (text_view),
3954 if (x == -1 || y == -1)
3955 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
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;
3961 /* Quick hack of a popup menu
3964 activate_cb (GtkWidget *menuitem,
3965 GtkTextView *text_view)
3967 const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
3968 gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal);
3972 append_action_signal (GtkTextView *text_view,
3975 const gchar *signal)
3977 GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
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);
3983 gtk_widget_show (menuitem);
3984 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
3988 popup_menu_detach (GtkWidget *attach_widget,
3991 GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
3995 gtk_text_view_popup_menu (GtkTextView *text_view,
3996 GdkEventButton *event)
3998 if (!text_view->popup_menu)
4000 GtkWidget *menuitem;
4002 text_view->popup_menu = gtk_menu_new ();
4004 gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
4005 GTK_WIDGET (text_view),
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");
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);
4016 gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
4017 GTK_MENU_SHELL (text_view->popup_menu));
4020 gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
4022 event->button, event->time);
4027 /* Child GdkWindows */
4030 static GtkTextWindow*
4031 text_window_new (GtkTextWindowType type,
4034 gint height_request)
4038 win = g_new (GtkTextWindow, 1);
4041 win->widget = widget;
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;
4055 text_window_free (GtkTextWindow *win)
4058 text_window_unrealize (win);
4064 text_window_realize (GtkTextWindow *win,
4067 GdkWindowAttr attributes;
4068 gint attributes_mask;
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;
4081 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
4083 win->window = gdk_window_new (parent,
4087 gdk_window_show (win->window);
4088 gdk_window_set_user_data (win->window, win->widget);
4092 attributes.width = win->allocation.width;
4093 attributes.height = win->allocation.height;
4094 attributes.event_mask = (GDK_EXPOSURE_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));
4103 win->bin_window = gdk_window_new (win->window,
4107 gdk_window_show (win->bin_window);
4108 gdk_window_set_user_data (win->bin_window, win->widget);
4110 if (win->type == GTK_TEXT_WINDOW_TEXT)
4113 cursor = gdk_cursor_new (GDK_XTERM);
4114 gdk_window_set_cursor (win->bin_window, cursor);
4115 gdk_cursor_destroy (cursor);
4117 gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
4121 gdk_window_set_background (win->bin_window,
4122 &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
4126 gdk_window_set_background (win->bin_window,
4127 &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
4130 g_object_set_qdata (G_OBJECT (win->window),
4131 g_quark_from_static_string ("gtk-text-view-text-window"),
4134 g_object_set_qdata (G_OBJECT (win->bin_window),
4135 g_quark_from_static_string ("gtk-text-view-text-window"),
4140 text_window_unrealize (GtkTextWindow *win)
4142 if (win->type == GTK_TEXT_WINDOW_TEXT)
4144 gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
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);
4153 win->bin_window = NULL;
4157 text_window_size_allocate (GtkTextWindow *win,
4160 win->allocation = *rect;
4164 gdk_window_move_resize (win->window,
4166 rect->width, rect->height);
4168 gdk_window_resize (win->bin_window,
4169 rect->width, rect->height);
4174 text_window_scroll (GtkTextWindow *win,
4178 if (dx != 0 || dy != 0)
4180 gdk_window_scroll (win->bin_window, dx, dy);
4181 gdk_window_process_updates (win->bin_window, TRUE);
4186 text_window_invalidate_rect (GtkTextWindow *win,
4189 gdk_window_invalidate_rect (win->bin_window, rect, FALSE);
4193 text_window_get_width (GtkTextWindow *win)
4195 return win->allocation.width;
4199 text_window_get_height (GtkTextWindow *win)
4201 return win->allocation.height;
4205 text_window_get_allocation (GtkTextWindow *win,
4208 *rect = win->allocation;
4215 * gtk_text_view_get_window:
4216 * @text_view: a #GtkTextView
4217 * @win: window to get
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
4226 * Return value: a #GdkWindow, or %NULL
4229 gtk_text_view_get_window (GtkTextView *text_view,
4230 GtkTextWindowType win)
4232 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
4236 case GTK_TEXT_WINDOW_WIDGET:
4237 return GTK_WIDGET (text_view)->window;
4240 case GTK_TEXT_WINDOW_TEXT:
4241 return text_view->text_window->bin_window;
4244 case GTK_TEXT_WINDOW_LEFT:
4245 if (text_view->left_window)
4246 return text_view->left_window->bin_window;
4251 case GTK_TEXT_WINDOW_RIGHT:
4252 if (text_view->right_window)
4253 return text_view->right_window->bin_window;
4258 case GTK_TEXT_WINDOW_TOP:
4259 if (text_view->top_window)
4260 return text_view->top_window->bin_window;
4265 case GTK_TEXT_WINDOW_BOTTOM:
4266 if (text_view->bottom_window)
4267 return text_view->bottom_window->bin_window;
4273 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
4280 * gtk_text_view_get_window_type:
4281 * @text_view: a #GtkTextView
4282 * @window: a window type
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->window</literal> to
4287 * see which window it was.
4289 * Return value: the window type.
4292 gtk_text_view_get_window_type (GtkTextView *text_view,
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);
4300 if (window == GTK_WIDGET (text_view)->window)
4301 return GTK_TEXT_WINDOW_WIDGET;
4303 win = g_object_get_qdata (G_OBJECT (window),
4304 g_quark_try_string ("gtk-text-view-text-window"));
4310 return GTK_TEXT_WINDOW_PRIVATE;
4315 buffer_to_widget (GtkTextView *text_view,
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;
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;
4337 widget_to_text_window (GtkTextWindow *win,
4344 *window_x = widget_x - win->allocation.x;
4347 *window_y = widget_y - win->allocation.y;
4351 buffer_to_text_window (GtkTextView *text_view,
4360 g_warning ("Attempt to convert text buffer coordinates to coordinates "
4361 "for a nonexistent or private child window of GtkTextView");
4365 buffer_to_widget (text_view,
4367 window_x, window_y);
4369 widget_to_text_window (win,
4370 window_x ? *window_x : 0,
4371 window_y ? *window_y : 0,
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
4385 * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
4386 * @win, and stores the result in (@window_x, @window_y).
4389 gtk_text_view_buffer_to_window_coords (GtkTextView *text_view,
4390 GtkTextWindowType win,
4396 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4400 case GTK_TEXT_WINDOW_WIDGET:
4401 buffer_to_widget (text_view,
4403 window_x, window_y);
4406 case GTK_TEXT_WINDOW_TEXT:
4408 *window_x = buffer_x - text_view->xoffset;
4410 *window_y = buffer_y - text_view->yoffset;
4413 case GTK_TEXT_WINDOW_LEFT:
4414 buffer_to_text_window (text_view,
4415 text_view->left_window,
4417 window_x, window_y);
4420 case GTK_TEXT_WINDOW_RIGHT:
4421 buffer_to_text_window (text_view,
4422 text_view->right_window,
4424 window_x, window_y);
4427 case GTK_TEXT_WINDOW_TOP:
4428 buffer_to_text_window (text_view,
4429 text_view->top_window,
4431 window_x, window_y);
4434 case GTK_TEXT_WINDOW_BOTTOM:
4435 buffer_to_text_window (text_view,
4436 text_view->bottom_window,
4438 window_x, window_y);
4441 case GTK_TEXT_WINDOW_PRIVATE:
4442 g_warning ("%s: can't get coords for private windows", G_STRLOC);
4446 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
4452 widget_to_buffer (GtkTextView *text_view,
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;
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;
4474 text_window_to_widget (GtkTextWindow *win,
4481 *widget_x = window_x + win->allocation.x;
4484 *widget_y = window_y + win->allocation.y;
4488 text_window_to_buffer (GtkTextView *text_view,
4497 g_warning ("Attempt to convert GtkTextView buffer coordinates into "
4498 "coordinates for a nonexistent child window.");
4502 text_window_to_widget (win,
4508 widget_to_buffer (text_view,
4509 buffer_x ? *buffer_x : 0,
4510 buffer_y ? *buffer_y : 0,
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
4524 * Converts coordinates on the window identified by @win to buffer
4525 * coordinates, storing the result in (@buffer_x,@buffer_y).
4528 gtk_text_view_window_to_buffer_coords (GtkTextView *text_view,
4529 GtkTextWindowType win,
4535 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4539 case GTK_TEXT_WINDOW_WIDGET:
4540 widget_to_buffer (text_view,
4542 buffer_x, buffer_y);
4545 case GTK_TEXT_WINDOW_TEXT:
4547 *buffer_x = window_x + text_view->xoffset;
4549 *buffer_y = window_y + text_view->yoffset;
4552 case GTK_TEXT_WINDOW_LEFT:
4553 text_window_to_buffer (text_view,
4554 text_view->left_window,
4556 buffer_x, buffer_y);
4559 case GTK_TEXT_WINDOW_RIGHT:
4560 text_window_to_buffer (text_view,
4561 text_view->right_window,
4563 buffer_x, buffer_y);
4566 case GTK_TEXT_WINDOW_TOP:
4567 text_window_to_buffer (text_view,
4568 text_view->top_window,
4570 buffer_x, buffer_y);
4573 case GTK_TEXT_WINDOW_BOTTOM:
4574 text_window_to_buffer (text_view,
4575 text_view->bottom_window,
4577 buffer_x, buffer_y);
4580 case GTK_TEXT_WINDOW_PRIVATE:
4581 g_warning ("%s: can't get coords for private windows", G_STRLOC);
4585 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
4591 set_window_width (GtkTextView *text_view,
4593 GtkTextWindowType type,
4594 GtkTextWindow **winp)
4600 text_window_free (*winp);
4602 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4609 *winp = text_window_new (type,
4610 GTK_WIDGET (text_view),
4615 if ((*winp)->requisition.width == width)
4619 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4625 set_window_height (GtkTextView *text_view,
4627 GtkTextWindowType type,
4628 GtkTextWindow **winp)
4634 text_window_free (*winp);
4636 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4643 *winp = text_window_new (type,
4644 GTK_WIDGET (text_view),
4649 if ((*winp)->requisition.height == height)
4653 gtk_widget_queue_resize (GTK_WIDGET (text_view));
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
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.
4669 gtk_text_view_set_border_window_size (GtkTextView *text_view,
4670 GtkTextWindowType type,
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);
4681 case GTK_TEXT_WINDOW_LEFT:
4682 set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
4683 &text_view->left_window);
4686 case GTK_TEXT_WINDOW_RIGHT:
4687 set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
4688 &text_view->right_window);
4691 case GTK_TEXT_WINDOW_TOP:
4692 set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
4693 &text_view->top_window);
4696 case GTK_TEXT_WINDOW_BOTTOM:
4697 set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
4698 &text_view->bottom_window);
4702 g_warning ("Can't set size of center or widget or private GtkTextWindowType in %s", G_STRLOC);
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
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.
4719 gtk_text_view_set_text_window_size (GtkTextView *text_view,
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);
4729 win = text_view->text_window;
4731 if (win->requisition.width == width &&
4732 win->requisition.height == height)
4735 win->requisition.width = width;
4736 win->requisition.height = height;
4738 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4745 static GtkTextViewChild*
4746 text_view_child_new_anchored (GtkWidget *child,
4747 GtkTextChildAnchor *anchor,
4748 GtkTextLayout *layout)
4750 GtkTextViewChild *vc;
4752 vc = g_new (GtkTextViewChild, 1);
4755 vc->anchor = anchor;
4757 g_object_ref (G_OBJECT (vc->widget));
4758 g_object_ref (G_OBJECT (vc->anchor));
4760 gtk_object_set_data (GTK_OBJECT (child),
4761 "gtk-text-view-child",
4764 gtk_text_child_anchor_register_child (anchor, child, layout);
4769 static GtkTextViewChild*
4770 text_view_child_new_window (GtkWidget *child,
4771 GtkTextWindowType type,
4775 GtkTextViewChild *vc;
4777 vc = g_new (GtkTextViewChild, 1);
4782 g_object_ref (G_OBJECT (vc->widget));
4792 text_view_child_free (GtkTextViewChild *child)
4795 gtk_object_remove_data (GTK_OBJECT (child->widget),
4796 "gtk-text-view-child");
4800 gtk_text_child_anchor_unregister_child (child->anchor,
4802 g_object_unref (G_OBJECT (child->anchor));
4805 g_object_unref (G_OBJECT (child->widget));
4811 text_view_child_realize (GtkTextView *text_view,
4812 GtkTextViewChild *vc)
4815 gtk_widget_set_parent_window (vc->widget,
4816 text_view->text_window->bin_window);
4820 window = gtk_text_view_get_window (text_view,
4822 gtk_widget_set_parent_window (vc->widget, window);
4825 gtk_widget_realize (vc->widget);
4829 add_child (GtkTextView *text_view,
4830 GtkTextViewChild *vc)
4832 text_view->children = g_slist_prepend (text_view->children,
4835 gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
4837 if (GTK_WIDGET_REALIZED (text_view))
4838 text_view_child_realize (text_view, vc);
4840 if (GTK_WIDGET_VISIBLE (text_view) && GTK_WIDGET_VISIBLE (vc->widget))
4842 if (GTK_WIDGET_MAPPED (text_view))
4843 gtk_widget_map (vc->widget);
4845 gtk_widget_queue_resize (vc->widget);
4850 gtk_text_view_add_child_at_anchor (GtkTextView *text_view,
4852 GtkTextChildAnchor *anchor)
4854 GtkTextViewChild *vc;
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);
4861 gtk_text_view_ensure_layout (text_view);
4863 vc = text_view_child_new_anchored (child, anchor,
4866 add_child (text_view, vc);
4870 gtk_text_view_add_child_in_window (GtkTextView *text_view,
4872 GtkTextWindowType which_window,
4876 GtkTextViewChild *vc;
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);
4884 vc = text_view_child_new_window (child, which_window,
4887 add_child (text_view, vc);
4891 gtk_text_view_move_child (GtkTextView *text_view,
4896 GtkTextViewChild *vc;
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);
4904 vc = gtk_object_get_data (GTK_OBJECT (child),
4905 "gtk-text-view-child");
4907 g_assert (vc != NULL);
4912 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
4913 gtk_widget_queue_resize (child);