1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
32 #include "gtkbindings.h"
34 #include "gtkimagemenuitem.h"
37 #include "gtkmarshalers.h"
39 #include "gtkmenuitem.h"
40 #include "gtkseparatormenuitem.h"
41 #include "gtksettings.h"
43 #include "gtktextbufferrichtext.h"
44 #include "gtktextdisplay.h"
45 #include "gtktextview.h"
46 #include "gtkimmulticontext.h"
47 #include "gdk/gdkkeysyms.h"
48 #include "gtkprivate.h"
49 #include "gtktextutil.h"
50 #include "gtkwidgetprivate.h"
51 #include "gtkwindow.h"
52 #include "gtkscrollable.h"
55 /* How scrolling, validation, exposes, etc. work.
57 * The expose_event handler has the invariant that the onscreen lines
58 * have been validated.
60 * There are two ways that onscreen lines can become invalid. The first
61 * is to change which lines are onscreen. This happens when the value
62 * of a scroll adjustment changes. So the code path begins in
63 * gtk_text_view_value_changed() and goes like this:
64 * - gdk_window_scroll() to reflect the new adjustment value
65 * - validate the lines that were moved onscreen
66 * - gdk_window_process_updates() to handle the exposes immediately
68 * The second way is that you get the "invalidated" signal from the layout,
69 * indicating that lines have become invalid. This code path begins in
70 * invalidated_handler() and goes like this:
71 * - install high-priority idle which does the rest of the steps
72 * - if a scroll is pending from scroll_to_mark(), do the scroll,
73 * jumping to the gtk_text_view_value_changed() code path
74 * - otherwise, validate the onscreen lines
75 * - DO NOT process updates
77 * In both cases, validating the onscreen lines can trigger a scroll
78 * due to maintaining the first_para on the top of the screen.
79 * If validation triggers a scroll, we jump to the top of the code path
80 * for value_changed, and bail out of the current code path.
82 * Also, in size_allocate, if we invalidate some lines from changing
83 * the layout width, we need to go ahead and run the high-priority idle,
84 * because GTK sends exposes right after doing the size allocates without
85 * returning to the main loop. This is also why the high-priority idle
86 * is at a higher priority than resizing.
91 #define DEBUG_VALIDATION_AND_SCROLLING
94 #ifdef DEBUG_VALIDATION_AND_SCROLLING
100 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->priv->text_window)
101 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->priv->text_window)
103 #define SPACE_FOR_CURSOR 1
105 #define GTK_TEXT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_VIEW, GtkTextViewPrivate))
107 typedef struct _GtkTextWindow GtkTextWindow;
108 typedef struct _GtkTextPendingScroll GtkTextPendingScroll;
110 struct _GtkTextViewPrivate
112 GtkTextLayout *layout;
113 GtkTextBuffer *buffer;
115 guint blink_time; /* time in msec the cursor has blinked since last user event */
118 GdkDevice *grab_device;
119 GdkDevice *dnd_device;
121 gulong selection_drag_handler;
122 guint scroll_timeout;
124 GtkTextWindow *text_window;
125 GtkTextWindow *left_window;
126 GtkTextWindow *right_window;
127 GtkTextWindow *top_window;
128 GtkTextWindow *bottom_window;
130 GtkAdjustment *hadjustment;
131 GtkAdjustment *vadjustment;
133 gint xoffset; /* Offsets between widget coordinates and buffer coordinates */
135 gint width; /* Width and height of the buffer */
138 /* This is used to monitor the overall size request
139 * and decide whether we need to queue resizes when
140 * the buffer content changes.
142 * FIXME: This could be done in a simpler way by
143 * consulting the above width/height of the buffer + some
144 * padding values, however all of this request code needs
145 * to be changed to use GtkWidget Iface and deserves
148 GtkRequisition cached_size_request;
150 /* The virtual cursor position is normally the same as the
151 * actual (strong) cursor position, except in two circumstances:
153 * a) When the cursor is moved vertically with the keyboard
154 * b) When the text view is scrolled with the keyboard
156 * In case a), virtual_cursor_x is preserved, but not virtual_cursor_y
157 * In case b), both virtual_cursor_x and virtual_cursor_y are preserved.
159 gint virtual_cursor_x; /* -1 means use actual cursor position */
160 gint virtual_cursor_y; /* -1 means use actual cursor position */
162 GtkTextMark *first_para_mark; /* Mark at the beginning of the first onscreen paragraph */
163 gint first_para_pixels; /* Offset of top of screen in the first onscreen paragraph */
165 GtkTextMark *dnd_mark;
168 guint first_validate_idle; /* Idle to revalidate onscreen portion, runs before resize */
169 guint incremental_validate_idle; /* Idle to revalidate offscreen portions, runs after redraw */
171 GtkIMContext *im_context;
172 GtkWidget *popup_menu;
179 GtkTextPendingScroll *pending_scroll;
181 gint pending_place_cursor_button;
183 /* Default style settings */
184 gint pixels_above_lines;
185 gint pixels_below_lines;
186 gint pixels_inside_wrap;
187 GtkWrapMode wrap_mode;
188 GtkJustification justify;
195 guint overwrite_mode : 1;
196 guint cursor_visible : 1;
198 /* if we have reset the IM since the last character entered */
199 guint need_im_reset : 1;
201 guint accepts_tab : 1;
203 guint width_changed : 1;
205 /* debug flag - means that we've validated onscreen since the
206 * last "invalidate" signal from the layout
208 guint onscreen_validated : 1;
210 guint mouse_cursor_obscured : 1;
212 guint scroll_after_paste : 1;
214 /* GtkScrollablePolicy needs to be checked when
215 * driving the scrollable adjustment values */
216 guint hscroll_policy : 1;
217 guint vscroll_policy : 1;
220 struct _GtkTextPendingScroll
223 gdouble within_margin;
244 TOGGLE_CURSOR_VISIBLE,
252 PROP_PIXELS_ABOVE_LINES,
253 PROP_PIXELS_BELOW_LINES,
254 PROP_PIXELS_INSIDE_WRAP,
273 static void gtk_text_view_finalize (GObject *object);
274 static void gtk_text_view_set_property (GObject *object,
278 static void gtk_text_view_get_property (GObject *object,
282 static void gtk_text_view_destroy (GtkWidget *widget);
283 static void gtk_text_view_size_request (GtkWidget *widget,
284 GtkRequisition *requisition);
285 static void gtk_text_view_get_preferred_width (GtkWidget *widget,
288 static void gtk_text_view_get_preferred_height (GtkWidget *widget,
291 static void gtk_text_view_size_allocate (GtkWidget *widget,
292 GtkAllocation *allocation);
293 static void gtk_text_view_realize (GtkWidget *widget);
294 static void gtk_text_view_unrealize (GtkWidget *widget);
295 static void gtk_text_view_style_set (GtkWidget *widget,
296 GtkStyle *previous_style);
297 static void gtk_text_view_direction_changed (GtkWidget *widget,
298 GtkTextDirection previous_direction);
299 static void gtk_text_view_grab_notify (GtkWidget *widget,
300 gboolean was_grabbed);
301 static void gtk_text_view_state_changed (GtkWidget *widget,
302 GtkStateType previous_state);
304 static gint gtk_text_view_event (GtkWidget *widget,
306 static gint gtk_text_view_key_press_event (GtkWidget *widget,
308 static gint gtk_text_view_key_release_event (GtkWidget *widget,
310 static gint gtk_text_view_button_press_event (GtkWidget *widget,
311 GdkEventButton *event);
312 static gint gtk_text_view_button_release_event (GtkWidget *widget,
313 GdkEventButton *event);
314 static gint gtk_text_view_focus_in_event (GtkWidget *widget,
315 GdkEventFocus *event);
316 static gint gtk_text_view_focus_out_event (GtkWidget *widget,
317 GdkEventFocus *event);
318 static gint gtk_text_view_motion_event (GtkWidget *widget,
319 GdkEventMotion *event);
320 static gint gtk_text_view_draw (GtkWidget *widget,
322 static void gtk_text_view_draw_focus (GtkWidget *widget,
324 static gboolean gtk_text_view_focus (GtkWidget *widget,
325 GtkDirectionType direction);
326 static void gtk_text_view_select_all (GtkWidget *widget,
330 /* Source side drag signals */
331 static void gtk_text_view_drag_begin (GtkWidget *widget,
332 GdkDragContext *context);
333 static void gtk_text_view_drag_end (GtkWidget *widget,
334 GdkDragContext *context);
335 static void gtk_text_view_drag_data_get (GtkWidget *widget,
336 GdkDragContext *context,
337 GtkSelectionData *selection_data,
340 static void gtk_text_view_drag_data_delete (GtkWidget *widget,
341 GdkDragContext *context);
343 /* Target side drag signals */
344 static void gtk_text_view_drag_leave (GtkWidget *widget,
345 GdkDragContext *context,
347 static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
348 GdkDragContext *context,
352 static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
353 GdkDragContext *context,
357 static void gtk_text_view_drag_data_received (GtkWidget *widget,
358 GdkDragContext *context,
361 GtkSelectionData *selection_data,
365 static gboolean gtk_text_view_popup_menu (GtkWidget *widget);
367 static void gtk_text_view_move_cursor (GtkTextView *text_view,
368 GtkMovementStep step,
370 gboolean extend_selection);
371 static gboolean gtk_text_view_move_viewport (GtkTextView *text_view,
374 static void gtk_text_view_set_anchor (GtkTextView *text_view);
375 static gboolean gtk_text_view_scroll_pages (GtkTextView *text_view,
377 gboolean extend_selection);
378 static gboolean gtk_text_view_scroll_hpages(GtkTextView *text_view,
380 gboolean extend_selection);
381 static void gtk_text_view_insert_at_cursor (GtkTextView *text_view,
383 static void gtk_text_view_delete_from_cursor (GtkTextView *text_view,
386 static void gtk_text_view_backspace (GtkTextView *text_view);
387 static void gtk_text_view_cut_clipboard (GtkTextView *text_view);
388 static void gtk_text_view_copy_clipboard (GtkTextView *text_view);
389 static void gtk_text_view_paste_clipboard (GtkTextView *text_view);
390 static void gtk_text_view_toggle_overwrite (GtkTextView *text_view);
391 static void gtk_text_view_toggle_cursor_visible (GtkTextView *text_view);
393 static void gtk_text_view_unselect (GtkTextView *text_view);
395 static void gtk_text_view_validate_onscreen (GtkTextView *text_view);
396 static void gtk_text_view_get_first_para_iter (GtkTextView *text_view,
398 static void gtk_text_view_update_layout_width (GtkTextView *text_view);
399 static void gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
400 GtkTextAttributes *values,
402 static void gtk_text_view_ensure_layout (GtkTextView *text_view);
403 static void gtk_text_view_destroy_layout (GtkTextView *text_view);
404 static void gtk_text_view_check_keymap_direction (GtkTextView *text_view);
405 static void gtk_text_view_start_selection_drag (GtkTextView *text_view,
406 const GtkTextIter *iter,
407 GdkEventButton *event);
408 static gboolean gtk_text_view_end_selection_drag (GtkTextView *text_view);
409 static void gtk_text_view_start_selection_dnd (GtkTextView *text_view,
410 const GtkTextIter *iter,
411 GdkEventMotion *event);
412 static void gtk_text_view_check_cursor_blink (GtkTextView *text_view);
413 static void gtk_text_view_pend_cursor_blink (GtkTextView *text_view);
414 static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view);
415 static void gtk_text_view_reset_blink_time (GtkTextView *text_view);
417 static void gtk_text_view_value_changed (GtkAdjustment *adj,
419 static void gtk_text_view_commit_handler (GtkIMContext *context,
421 GtkTextView *text_view);
422 static void gtk_text_view_commit_text (GtkTextView *text_view,
424 static void gtk_text_view_preedit_changed_handler (GtkIMContext *context,
425 GtkTextView *text_view);
426 static gboolean gtk_text_view_retrieve_surrounding_handler (GtkIMContext *context,
427 GtkTextView *text_view);
428 static gboolean gtk_text_view_delete_surrounding_handler (GtkIMContext *context,
431 GtkTextView *text_view);
433 static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
434 const GtkTextIter *location,
437 static void gtk_text_view_target_list_notify (GtkTextBuffer *buffer,
438 const GParamSpec *pspec,
440 static void gtk_text_view_paste_done_handler (GtkTextBuffer *buffer,
441 GtkClipboard *clipboard,
443 static void gtk_text_view_get_cursor_location (GtkTextView *text_view,
445 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
449 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
453 static void gtk_text_view_do_popup (GtkTextView *text_view,
454 GdkEventButton *event);
456 static void cancel_pending_scroll (GtkTextView *text_view);
457 static void gtk_text_view_queue_scroll (GtkTextView *text_view,
459 gdouble within_margin,
464 static gboolean gtk_text_view_flush_scroll (GtkTextView *text_view);
465 static void gtk_text_view_update_adjustments (GtkTextView *text_view);
466 static void gtk_text_view_invalidate (GtkTextView *text_view);
467 static void gtk_text_view_flush_first_validate (GtkTextView *text_view);
469 static void gtk_text_view_set_hadjustment (GtkTextView *text_view,
470 GtkAdjustment *adjustment);
471 static void gtk_text_view_set_vadjustment (GtkTextView *text_view,
472 GtkAdjustment *adjustment);
473 static void gtk_text_view_set_hadjustment_values (GtkTextView *text_view);
474 static void gtk_text_view_set_vadjustment_values (GtkTextView *text_view);
476 static void gtk_text_view_update_im_spot_location (GtkTextView *text_view);
478 /* Container methods */
479 static void gtk_text_view_add (GtkContainer *container,
481 static void gtk_text_view_remove (GtkContainer *container,
483 static void gtk_text_view_forall (GtkContainer *container,
484 gboolean include_internals,
485 GtkCallback callback,
486 gpointer callback_data);
488 /* FIXME probably need the focus methods. */
490 typedef struct _GtkTextViewChild GtkTextViewChild;
492 struct _GtkTextViewChild
496 GtkTextChildAnchor *anchor;
498 gint from_top_of_line;
499 gint from_left_of_buffer;
501 /* These are ignored if anchor != NULL */
502 GtkTextWindowType type;
507 static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child,
508 GtkTextChildAnchor *anchor,
509 GtkTextLayout *layout);
510 static GtkTextViewChild* text_view_child_new_window (GtkWidget *child,
511 GtkTextWindowType type,
514 static void text_view_child_free (GtkTextViewChild *child);
515 static void text_view_child_set_parent_window (GtkTextView *text_view,
516 GtkTextViewChild *child);
518 struct _GtkTextWindow
520 GtkTextWindowType type;
523 GdkWindow *bin_window;
524 GtkRequisition requisition;
525 GdkRectangle allocation;
528 static GtkTextWindow *text_window_new (GtkTextWindowType type,
531 gint height_request);
532 static void text_window_free (GtkTextWindow *win);
533 static void text_window_realize (GtkTextWindow *win,
535 static void text_window_unrealize (GtkTextWindow *win);
536 static void text_window_size_allocate (GtkTextWindow *win,
538 static void text_window_scroll (GtkTextWindow *win,
541 static void text_window_invalidate_rect (GtkTextWindow *win,
543 static void text_window_invalidate_cursors (GtkTextWindow *win);
545 static gint text_window_get_width (GtkTextWindow *win);
546 static gint text_window_get_height (GtkTextWindow *win);
549 static guint signals[LAST_SIGNAL] = { 0 };
551 G_DEFINE_TYPE_WITH_CODE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER,
552 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
555 add_move_binding (GtkBindingSet *binding_set,
558 GtkMovementStep step,
561 g_assert ((modmask & GDK_SHIFT_MASK) == 0);
563 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
567 G_TYPE_BOOLEAN, FALSE);
569 /* Selection-extending version */
570 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
574 G_TYPE_BOOLEAN, TRUE);
578 gtk_text_view_class_init (GtkTextViewClass *klass)
580 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
581 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
582 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
583 GtkBindingSet *binding_set;
585 /* Default handlers and virtual methods
587 gobject_class->set_property = gtk_text_view_set_property;
588 gobject_class->get_property = gtk_text_view_get_property;
589 gobject_class->finalize = gtk_text_view_finalize;
591 widget_class->destroy = gtk_text_view_destroy;
592 widget_class->realize = gtk_text_view_realize;
593 widget_class->unrealize = gtk_text_view_unrealize;
594 widget_class->style_set = gtk_text_view_style_set;
595 widget_class->direction_changed = gtk_text_view_direction_changed;
596 widget_class->grab_notify = gtk_text_view_grab_notify;
597 widget_class->state_changed = gtk_text_view_state_changed;
598 widget_class->get_preferred_width = gtk_text_view_get_preferred_width;
599 widget_class->get_preferred_height = gtk_text_view_get_preferred_height;
600 widget_class->size_allocate = gtk_text_view_size_allocate;
601 widget_class->event = gtk_text_view_event;
602 widget_class->key_press_event = gtk_text_view_key_press_event;
603 widget_class->key_release_event = gtk_text_view_key_release_event;
604 widget_class->button_press_event = gtk_text_view_button_press_event;
605 widget_class->button_release_event = gtk_text_view_button_release_event;
606 widget_class->focus_in_event = gtk_text_view_focus_in_event;
607 widget_class->focus_out_event = gtk_text_view_focus_out_event;
608 widget_class->motion_notify_event = gtk_text_view_motion_event;
609 widget_class->draw = gtk_text_view_draw;
610 widget_class->focus = gtk_text_view_focus;
611 widget_class->drag_begin = gtk_text_view_drag_begin;
612 widget_class->drag_end = gtk_text_view_drag_end;
613 widget_class->drag_data_get = gtk_text_view_drag_data_get;
614 widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
616 widget_class->drag_leave = gtk_text_view_drag_leave;
617 widget_class->drag_motion = gtk_text_view_drag_motion;
618 widget_class->drag_drop = gtk_text_view_drag_drop;
619 widget_class->drag_data_received = gtk_text_view_drag_data_received;
621 widget_class->popup_menu = gtk_text_view_popup_menu;
623 container_class->add = gtk_text_view_add;
624 container_class->remove = gtk_text_view_remove;
625 container_class->forall = gtk_text_view_forall;
627 klass->move_cursor = gtk_text_view_move_cursor;
628 klass->set_anchor = gtk_text_view_set_anchor;
629 klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
630 klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
631 klass->backspace = gtk_text_view_backspace;
632 klass->cut_clipboard = gtk_text_view_cut_clipboard;
633 klass->copy_clipboard = gtk_text_view_copy_clipboard;
634 klass->paste_clipboard = gtk_text_view_paste_clipboard;
635 klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
641 g_object_class_install_property (gobject_class,
642 PROP_PIXELS_ABOVE_LINES,
643 g_param_spec_int ("pixels-above-lines",
644 P_("Pixels Above Lines"),
645 P_("Pixels of blank space above paragraphs"),
649 GTK_PARAM_READWRITE));
651 g_object_class_install_property (gobject_class,
652 PROP_PIXELS_BELOW_LINES,
653 g_param_spec_int ("pixels-below-lines",
654 P_("Pixels Below Lines"),
655 P_("Pixels of blank space below paragraphs"),
659 GTK_PARAM_READWRITE));
661 g_object_class_install_property (gobject_class,
662 PROP_PIXELS_INSIDE_WRAP,
663 g_param_spec_int ("pixels-inside-wrap",
664 P_("Pixels Inside Wrap"),
665 P_("Pixels of blank space between wrapped lines in a paragraph"),
669 GTK_PARAM_READWRITE));
671 g_object_class_install_property (gobject_class,
673 g_param_spec_boolean ("editable",
675 P_("Whether the text can be modified by the user"),
677 GTK_PARAM_READWRITE));
679 g_object_class_install_property (gobject_class,
681 g_param_spec_enum ("wrap-mode",
683 P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
686 GTK_PARAM_READWRITE));
688 g_object_class_install_property (gobject_class,
690 g_param_spec_enum ("justification",
692 P_("Left, right, or center justification"),
693 GTK_TYPE_JUSTIFICATION,
695 GTK_PARAM_READWRITE));
697 g_object_class_install_property (gobject_class,
699 g_param_spec_int ("left-margin",
701 P_("Width of the left margin in pixels"),
705 GTK_PARAM_READWRITE));
707 g_object_class_install_property (gobject_class,
709 g_param_spec_int ("right-margin",
711 P_("Width of the right margin in pixels"),
715 GTK_PARAM_READWRITE));
717 g_object_class_install_property (gobject_class,
719 g_param_spec_int ("indent",
721 P_("Amount to indent the paragraph, in pixels"),
725 GTK_PARAM_READWRITE));
727 g_object_class_install_property (gobject_class,
729 g_param_spec_boxed ("tabs",
731 P_("Custom tabs for this text"),
732 PANGO_TYPE_TAB_ARRAY,
733 GTK_PARAM_READWRITE));
735 g_object_class_install_property (gobject_class,
737 g_param_spec_boolean ("cursor-visible",
738 P_("Cursor Visible"),
739 P_("If the insertion cursor is shown"),
741 GTK_PARAM_READWRITE));
743 g_object_class_install_property (gobject_class,
745 g_param_spec_object ("buffer",
747 P_("The buffer which is displayed"),
748 GTK_TYPE_TEXT_BUFFER,
749 GTK_PARAM_READWRITE));
751 g_object_class_install_property (gobject_class,
753 g_param_spec_boolean ("overwrite",
754 P_("Overwrite mode"),
755 P_("Whether entered text overwrites existing contents"),
757 GTK_PARAM_READWRITE));
759 g_object_class_install_property (gobject_class,
761 g_param_spec_boolean ("accepts-tab",
763 P_("Whether Tab will result in a tab character being entered"),
765 GTK_PARAM_READWRITE));
768 * GtkTextView:im-module:
770 * Which IM (input method) module should be used for this entry.
773 * Setting this to a non-%NULL value overrides the
774 * system-wide IM module setting. See the GtkSettings
775 * #GtkSettings:gtk-im-module property.
779 g_object_class_install_property (gobject_class,
781 g_param_spec_string ("im-module",
783 P_("Which IM module should be used"),
785 GTK_PARAM_READWRITE));
787 /* GtkScrollable interface */
788 g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
789 g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
790 g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
791 g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
796 gtk_widget_class_install_style_property (widget_class,
797 g_param_spec_boxed ("error-underline-color",
798 P_("Error underline color"),
799 P_("Color with which to draw error-indication underlines"),
801 GTK_PARAM_READABLE));
808 * GtkTextView::move-cursor:
809 * @text_view: the object which received the signal
810 * @step: the granularity of the move, as a #GtkMovementStep
811 * @count: the number of @step units to move
812 * @extend_selection: %TRUE if the move should extend the selection
814 * The ::move-cursor signal is a
815 * <link linkend="keybinding-signals">keybinding signal</link>
816 * which gets emitted when the user initiates a cursor movement.
817 * If the cursor is not visible in @text_view, this signal causes
818 * the viewport to be moved instead.
820 * Applications should not connect to it, but may emit it with
821 * g_signal_emit_by_name() if they need to control the cursor
824 * The default bindings for this signal come in two variants,
825 * the variant with the Shift modifier extends the selection,
826 * the variant without the Shift modifer does not.
827 * There are too many key combinations to list them all here.
829 * <listitem>Arrow keys move by individual characters/lines</listitem>
830 * <listitem>Ctrl-arrow key combinations move by words/paragraphs</listitem>
831 * <listitem>Home/End keys move to the ends of the buffer</listitem>
832 * <listitem>PageUp/PageDown keys move vertically by pages</listitem>
833 * <listitem>Ctrl-PageUp/PageDown keys move horizontally by pages</listitem>
836 signals[MOVE_CURSOR] =
837 g_signal_new (I_("move-cursor"),
838 G_OBJECT_CLASS_TYPE (gobject_class),
839 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
840 G_STRUCT_OFFSET (GtkTextViewClass, move_cursor),
842 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
844 GTK_TYPE_MOVEMENT_STEP,
849 * GtkTextView::move-viewport:
850 * @text_view: the object which received the signal
851 * @step: the granularity of the move, as a #GtkMovementStep
852 * @count: the number of @step units to move
854 * The ::move-viewport signal is a
855 * <link linkend="keybinding-signals">keybinding signal</link>
856 * which can be bound to key combinations to allow the user
857 * to move the viewport, i.e. change what part of the text view
858 * is visible in a containing scrolled window.
860 * There are no default bindings for this signal.
862 signals[MOVE_VIEWPORT] =
863 g_signal_new_class_handler (I_("move-viewport"),
864 G_OBJECT_CLASS_TYPE (gobject_class),
865 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
866 G_CALLBACK (gtk_text_view_move_viewport),
868 _gtk_marshal_VOID__ENUM_INT,
870 GTK_TYPE_SCROLL_STEP,
874 * GtkTextView::set-anchor:
875 * @text_view: the object which received the signal
877 * The ::set-anchor signal is a
878 * <link linkend="keybinding-signals">keybinding signal</link>
879 * which gets emitted when the user initiates setting the "anchor"
880 * mark. The "anchor" mark gets placed at the same position as the
883 * This signal has no default bindings.
885 signals[SET_ANCHOR] =
886 g_signal_new (I_("set-anchor"),
887 G_OBJECT_CLASS_TYPE (gobject_class),
888 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
889 G_STRUCT_OFFSET (GtkTextViewClass, set_anchor),
891 _gtk_marshal_VOID__VOID,
895 * GtkTextView::insert-at-cursor:
896 * @text_view: the object which received the signal
897 * @string: the string to insert
899 * The ::insert-at-cursor signal is a
900 * <link linkend="keybinding-signals">keybinding signal</link>
901 * which gets emitted when the user initiates the insertion of a
902 * fixed string at the cursor.
904 * This signal has no default bindings.
906 signals[INSERT_AT_CURSOR] =
907 g_signal_new (I_("insert-at-cursor"),
908 G_OBJECT_CLASS_TYPE (gobject_class),
909 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
910 G_STRUCT_OFFSET (GtkTextViewClass, insert_at_cursor),
912 _gtk_marshal_VOID__STRING,
917 * GtkTextView::delete-from-cursor:
918 * @text_view: the object which received the signal
919 * @type: the granularity of the deletion, as a #GtkDeleteType
920 * @count: the number of @type units to delete
922 * The ::delete-from-cursor signal is a
923 * <link linkend="keybinding-signals">keybinding signal</link>
924 * which gets emitted when the user initiates a text deletion.
926 * If the @type is %GTK_DELETE_CHARS, GTK+ deletes the selection
927 * if there is one, otherwise it deletes the requested number
930 * The default bindings for this signal are
931 * Delete for deleting a character, Ctrl-Delete for
932 * deleting a word and Ctrl-Backspace for deleting a word
935 signals[DELETE_FROM_CURSOR] =
936 g_signal_new (I_("delete-from-cursor"),
937 G_OBJECT_CLASS_TYPE (gobject_class),
938 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
939 G_STRUCT_OFFSET (GtkTextViewClass, delete_from_cursor),
941 _gtk_marshal_VOID__ENUM_INT,
943 GTK_TYPE_DELETE_TYPE,
947 * GtkTextView::backspace:
948 * @text_view: the object which received the signal
950 * The ::backspace signal is a
951 * <link linkend="keybinding-signals">keybinding signal</link>
952 * which gets emitted when the user asks for it.
954 * The default bindings for this signal are
955 * Backspace and Shift-Backspace.
958 g_signal_new (I_("backspace"),
959 G_OBJECT_CLASS_TYPE (gobject_class),
960 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
961 G_STRUCT_OFFSET (GtkTextViewClass, backspace),
963 _gtk_marshal_VOID__VOID,
967 * GtkTextView::cut-clipboard:
968 * @text_view: the object which received the signal
970 * The ::cut-clipboard signal is a
971 * <link linkend="keybinding-signals">keybinding signal</link>
972 * which gets emitted to cut the selection to the clipboard.
974 * The default bindings for this signal are
975 * Ctrl-x and Shift-Delete.
977 signals[CUT_CLIPBOARD] =
978 g_signal_new (I_("cut-clipboard"),
979 G_OBJECT_CLASS_TYPE (gobject_class),
980 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
981 G_STRUCT_OFFSET (GtkTextViewClass, cut_clipboard),
983 _gtk_marshal_VOID__VOID,
987 * GtkTextView::copy-clipboard:
988 * @text_view: the object which received the signal
990 * The ::copy-clipboard signal is a
991 * <link linkend="keybinding-signals">keybinding signal</link>
992 * which gets emitted to copy the selection to the clipboard.
994 * The default bindings for this signal are
995 * Ctrl-c and Ctrl-Insert.
997 signals[COPY_CLIPBOARD] =
998 g_signal_new (I_("copy-clipboard"),
999 G_OBJECT_CLASS_TYPE (gobject_class),
1000 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1001 G_STRUCT_OFFSET (GtkTextViewClass, copy_clipboard),
1003 _gtk_marshal_VOID__VOID,
1007 * GtkTextView::paste-clipboard:
1008 * @text_view: the object which received the signal
1010 * The ::paste-clipboard signal is a
1011 * <link linkend="keybinding-signals">keybinding signal</link>
1012 * which gets emitted to paste the contents of the clipboard
1013 * into the text view.
1015 * The default bindings for this signal are
1016 * Ctrl-v and Shift-Insert.
1018 signals[PASTE_CLIPBOARD] =
1019 g_signal_new (I_("paste-clipboard"),
1020 G_OBJECT_CLASS_TYPE (gobject_class),
1021 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1022 G_STRUCT_OFFSET (GtkTextViewClass, paste_clipboard),
1024 _gtk_marshal_VOID__VOID,
1028 * GtkTextView::toggle-overwrite:
1029 * @text_view: the object which received the signal
1031 * The ::toggle-overwrite signal is a
1032 * <link linkend="keybinding-signals">keybinding signal</link>
1033 * which gets emitted to toggle the overwrite mode of the text view.
1035 * The default bindings for this signal is Insert.
1037 signals[TOGGLE_OVERWRITE] =
1038 g_signal_new (I_("toggle-overwrite"),
1039 G_OBJECT_CLASS_TYPE (gobject_class),
1040 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1041 G_STRUCT_OFFSET (GtkTextViewClass, toggle_overwrite),
1043 _gtk_marshal_VOID__VOID,
1047 * GtkTextView::populate-popup:
1048 * @entry: The text view on which the signal is emitted
1049 * @menu: the menu that is being populated
1051 * The ::populate-popup signal gets emitted before showing the
1052 * context menu of the text view.
1054 * If you need to add items to the context menu, connect
1055 * to this signal and append your menuitems to the @menu.
1057 signals[POPULATE_POPUP] =
1058 g_signal_new (I_("populate-popup"),
1059 G_OBJECT_CLASS_TYPE (gobject_class),
1061 G_STRUCT_OFFSET (GtkTextViewClass, populate_popup),
1063 _gtk_marshal_VOID__OBJECT,
1068 * GtkTextView::select-all:
1069 * @text_view: the object which received the signal
1070 * @select: %TRUE to select, %FALSE to unselect
1072 * The ::select-all signal is a
1073 * <link linkend="keybinding-signals">keybinding signal</link>
1074 * which gets emitted to select or unselect the complete
1075 * contents of the text view.
1077 * The default bindings for this signal are Ctrl-a and Ctrl-/
1078 * for selecting and Shift-Ctrl-a and Ctrl-\ for unselecting.
1080 signals[SELECT_ALL] =
1081 g_signal_new_class_handler (I_("select-all"),
1082 G_OBJECT_CLASS_TYPE (gobject_class),
1083 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1084 G_CALLBACK (gtk_text_view_select_all),
1086 _gtk_marshal_VOID__BOOLEAN,
1087 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
1090 * GtkTextView::toggle-cursor-visible:
1091 * @text_view: the object which received the signal
1093 * The ::toggle-cursor-visible signal is a
1094 * <link linkend="keybinding-signals">keybinding signal</link>
1095 * which gets emitted to toggle the visibility of the cursor.
1097 * The default binding for this signal is F7.
1099 signals[TOGGLE_CURSOR_VISIBLE] =
1100 g_signal_new_class_handler (I_("toggle-cursor-visible"),
1101 G_OBJECT_CLASS_TYPE (gobject_class),
1102 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1103 G_CALLBACK (gtk_text_view_toggle_cursor_visible),
1105 _gtk_marshal_VOID__VOID,
1109 * GtkTextView::preedit-changed:
1110 * @text_view: the object which received the signal
1111 * @preedit: the current preedit string
1113 * If an input method is used, the typed text will not immediately
1114 * be committed to the buffer. So if you are interested in the text,
1115 * connect to this signal.
1117 * This signal is only emitted if the text at the given position
1118 * is actually editable.
1122 signals[PREEDIT_CHANGED] =
1123 g_signal_new_class_handler (I_("preedit-changed"),
1124 G_OBJECT_CLASS_TYPE (gobject_class),
1125 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1128 _gtk_marshal_VOID__STRING,
1136 binding_set = gtk_binding_set_by_class (klass);
1138 /* Moving the insertion point */
1139 add_move_binding (binding_set, GDK_KEY_Right, 0,
1140 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1142 add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
1143 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1145 add_move_binding (binding_set, GDK_KEY_Left, 0,
1146 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1148 add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
1149 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1151 add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1152 GTK_MOVEMENT_WORDS, 1);
1154 add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1155 GTK_MOVEMENT_WORDS, 1);
1157 add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1158 GTK_MOVEMENT_WORDS, -1);
1160 add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1161 GTK_MOVEMENT_WORDS, -1);
1163 add_move_binding (binding_set, GDK_KEY_Up, 0,
1164 GTK_MOVEMENT_DISPLAY_LINES, -1);
1166 add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
1167 GTK_MOVEMENT_DISPLAY_LINES, -1);
1169 add_move_binding (binding_set, GDK_KEY_Down, 0,
1170 GTK_MOVEMENT_DISPLAY_LINES, 1);
1172 add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
1173 GTK_MOVEMENT_DISPLAY_LINES, 1);
1175 add_move_binding (binding_set, GDK_KEY_Up, GDK_CONTROL_MASK,
1176 GTK_MOVEMENT_PARAGRAPHS, -1);
1178 add_move_binding (binding_set, GDK_KEY_KP_Up, GDK_CONTROL_MASK,
1179 GTK_MOVEMENT_PARAGRAPHS, -1);
1181 add_move_binding (binding_set, GDK_KEY_Down, GDK_CONTROL_MASK,
1182 GTK_MOVEMENT_PARAGRAPHS, 1);
1184 add_move_binding (binding_set, GDK_KEY_KP_Down, GDK_CONTROL_MASK,
1185 GTK_MOVEMENT_PARAGRAPHS, 1);
1187 add_move_binding (binding_set, GDK_KEY_Home, 0,
1188 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1190 add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1191 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1193 add_move_binding (binding_set, GDK_KEY_End, 0,
1194 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1196 add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1197 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1199 add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK,
1200 GTK_MOVEMENT_BUFFER_ENDS, -1);
1202 add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK,
1203 GTK_MOVEMENT_BUFFER_ENDS, -1);
1205 add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK,
1206 GTK_MOVEMENT_BUFFER_ENDS, 1);
1208 add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK,
1209 GTK_MOVEMENT_BUFFER_ENDS, 1);
1211 add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
1212 GTK_MOVEMENT_PAGES, -1);
1214 add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
1215 GTK_MOVEMENT_PAGES, -1);
1217 add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
1218 GTK_MOVEMENT_PAGES, 1);
1220 add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
1221 GTK_MOVEMENT_PAGES, 1);
1223 add_move_binding (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1224 GTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1226 add_move_binding (binding_set, GDK_KEY_KP_Page_Up, GDK_CONTROL_MASK,
1227 GTK_MOVEMENT_HORIZONTAL_PAGES, -1);
1229 add_move_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1230 GTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1232 add_move_binding (binding_set, GDK_KEY_KP_Page_Down, GDK_CONTROL_MASK,
1233 GTK_MOVEMENT_HORIZONTAL_PAGES, 1);
1236 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
1238 G_TYPE_BOOLEAN, TRUE);
1240 gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK,
1242 G_TYPE_BOOLEAN, TRUE);
1245 gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK,
1247 G_TYPE_BOOLEAN, FALSE);
1249 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1251 G_TYPE_BOOLEAN, FALSE);
1254 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
1255 "delete-from-cursor", 2,
1256 G_TYPE_ENUM, GTK_DELETE_CHARS,
1259 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
1260 "delete-from-cursor", 2,
1261 G_TYPE_ENUM, GTK_DELETE_CHARS,
1264 gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
1267 /* Make this do the same as Backspace, to help with mis-typing */
1268 gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK,
1271 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK,
1272 "delete-from-cursor", 2,
1273 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1276 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK,
1277 "delete-from-cursor", 2,
1278 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1281 gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK,
1282 "delete-from-cursor", 2,
1283 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1286 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1287 "delete-from-cursor", 2,
1288 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1291 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1292 "delete-from-cursor", 2,
1293 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1296 gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1297 "delete-from-cursor", 2,
1298 G_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
1301 /* Cut/copy/paste */
1303 gtk_binding_entry_add_signal (binding_set, GDK_KEY_x, GDK_CONTROL_MASK,
1304 "cut-clipboard", 0);
1305 gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK,
1306 "copy-clipboard", 0);
1307 gtk_binding_entry_add_signal (binding_set, GDK_KEY_v, GDK_CONTROL_MASK,
1308 "paste-clipboard", 0);
1310 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
1311 "cut-clipboard", 0);
1312 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_CONTROL_MASK,
1313 "copy-clipboard", 0);
1314 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_SHIFT_MASK,
1315 "paste-clipboard", 0);
1318 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, 0,
1319 "toggle-overwrite", 0);
1320 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0,
1321 "toggle-overwrite", 0);
1324 gtk_binding_entry_add_signal (binding_set, GDK_KEY_F7, 0,
1325 "toggle-cursor-visible", 0);
1327 /* Control-tab focus motion */
1328 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, GDK_CONTROL_MASK,
1330 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
1331 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, GDK_CONTROL_MASK,
1333 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
1335 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1337 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
1338 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1340 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
1342 g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
1346 gtk_text_view_init (GtkTextView *text_view)
1348 GtkWidget *widget = GTK_WIDGET (text_view);
1349 GtkTargetList *target_list;
1350 GtkTextViewPrivate *priv;
1352 text_view->priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
1353 priv = text_view->priv;
1355 gtk_widget_set_can_focus (widget, TRUE);
1357 /* Set up default style */
1358 priv->wrap_mode = GTK_WRAP_NONE;
1359 priv->pixels_above_lines = 0;
1360 priv->pixels_below_lines = 0;
1361 priv->pixels_inside_wrap = 0;
1362 priv->justify = GTK_JUSTIFY_LEFT;
1363 priv->left_margin = 0;
1364 priv->right_margin = 0;
1367 priv->editable = TRUE;
1369 priv->scroll_after_paste = TRUE;
1371 gtk_drag_dest_set (widget, 0, NULL, 0,
1372 GDK_ACTION_COPY | GDK_ACTION_MOVE);
1374 target_list = gtk_target_list_new (NULL, 0);
1375 gtk_drag_dest_set_target_list (widget, target_list);
1376 gtk_target_list_unref (target_list);
1378 priv->virtual_cursor_x = -1;
1379 priv->virtual_cursor_y = -1;
1381 /* This object is completely private. No external entity can gain a reference
1382 * to it; so we create it here and destroy it in finalize ().
1384 priv->im_context = gtk_im_multicontext_new ();
1386 g_signal_connect (priv->im_context, "commit",
1387 G_CALLBACK (gtk_text_view_commit_handler), text_view);
1388 g_signal_connect (priv->im_context, "preedit-changed",
1389 G_CALLBACK (gtk_text_view_preedit_changed_handler), text_view);
1390 g_signal_connect (priv->im_context, "retrieve-surrounding",
1391 G_CALLBACK (gtk_text_view_retrieve_surrounding_handler), text_view);
1392 g_signal_connect (priv->im_context, "delete-surrounding",
1393 G_CALLBACK (gtk_text_view_delete_surrounding_handler), text_view);
1395 priv->cursor_visible = TRUE;
1397 priv->accepts_tab = TRUE;
1399 priv->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
1402 priv->drag_start_x = -1;
1403 priv->drag_start_y = -1;
1405 priv->pending_place_cursor_button = 0;
1407 /* We handle all our own redrawing */
1408 gtk_widget_set_redraw_on_allocate (widget, FALSE);
1412 * gtk_text_view_new:
1414 * Creates a new #GtkTextView. If you don't call gtk_text_view_set_buffer()
1415 * before using the text view, an empty default buffer will be created
1416 * for you. Get the buffer with gtk_text_view_get_buffer(). If you want
1417 * to specify your own buffer, consider gtk_text_view_new_with_buffer().
1419 * Return value: a new #GtkTextView
1422 gtk_text_view_new (void)
1424 return g_object_new (GTK_TYPE_TEXT_VIEW, NULL);
1428 * gtk_text_view_new_with_buffer:
1429 * @buffer: a #GtkTextBuffer
1431 * Creates a new #GtkTextView widget displaying the buffer
1432 * @buffer. One buffer can be shared among many widgets.
1433 * @buffer may be %NULL to create a default buffer, in which case
1434 * this function is equivalent to gtk_text_view_new(). The
1435 * text view adds its own reference count to the buffer; it does not
1436 * take over an existing reference.
1438 * Return value: a new #GtkTextView.
1441 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
1443 GtkTextView *text_view;
1445 text_view = (GtkTextView*)gtk_text_view_new ();
1447 gtk_text_view_set_buffer (text_view, buffer);
1449 return GTK_WIDGET (text_view);
1453 * gtk_text_view_set_buffer:
1454 * @text_view: a #GtkTextView
1455 * @buffer: (allow-none): a #GtkTextBuffer
1457 * Sets @buffer as the buffer being displayed by @text_view. The previous
1458 * buffer displayed by the text view is unreferenced, and a reference is
1459 * added to @buffer. If you owned a reference to @buffer before passing it
1460 * to this function, you must remove that reference yourself; #GtkTextView
1461 * will not "adopt" it.
1464 gtk_text_view_set_buffer (GtkTextView *text_view,
1465 GtkTextBuffer *buffer)
1467 GtkTextViewPrivate *priv;
1469 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1470 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
1472 priv = text_view->priv;
1474 if (priv->buffer == buffer)
1477 if (priv->buffer != NULL)
1479 /* Destroy all anchored children */
1483 copy = g_slist_copy (priv->children);
1485 while (tmp_list != NULL)
1487 GtkTextViewChild *vc = tmp_list->data;
1491 gtk_widget_destroy (vc->widget);
1492 /* vc may now be invalid! */
1495 tmp_list = g_slist_next (tmp_list);
1498 g_slist_free (copy);
1500 g_signal_handlers_disconnect_by_func (priv->buffer,
1501 gtk_text_view_mark_set_handler,
1503 g_signal_handlers_disconnect_by_func (priv->buffer,
1504 gtk_text_view_target_list_notify,
1506 g_signal_handlers_disconnect_by_func (priv->buffer,
1507 gtk_text_view_paste_done_handler,
1510 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
1512 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
1513 GDK_SELECTION_PRIMARY);
1514 gtk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
1518 gtk_text_layout_set_buffer (priv->layout, NULL);
1520 g_object_unref (priv->buffer);
1521 priv->dnd_mark = NULL;
1522 priv->first_para_mark = NULL;
1523 cancel_pending_scroll (text_view);
1526 priv->buffer = buffer;
1529 gtk_text_layout_set_buffer (priv->layout, buffer);
1535 g_object_ref (buffer);
1537 gtk_text_buffer_get_iter_at_offset (priv->buffer, &start, 0);
1539 priv->dnd_mark = gtk_text_buffer_create_mark (priv->buffer,
1543 priv->first_para_mark = gtk_text_buffer_create_mark (priv->buffer,
1547 priv->first_para_pixels = 0;
1550 g_signal_connect (priv->buffer, "mark-set",
1551 G_CALLBACK (gtk_text_view_mark_set_handler),
1553 g_signal_connect (priv->buffer, "notify::paste-target-list",
1554 G_CALLBACK (gtk_text_view_target_list_notify),
1556 g_signal_connect (priv->buffer, "paste-done",
1557 G_CALLBACK (gtk_text_view_paste_done_handler),
1560 gtk_text_view_target_list_notify (priv->buffer, NULL, text_view);
1562 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
1564 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
1565 GDK_SELECTION_PRIMARY);
1566 gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
1570 g_object_notify (G_OBJECT (text_view), "buffer");
1572 if (gtk_widget_get_visible (GTK_WIDGET (text_view)))
1573 gtk_widget_queue_draw (GTK_WIDGET (text_view));
1575 DV(g_print ("Invalidating due to set_buffer\n"));
1576 gtk_text_view_invalidate (text_view);
1579 static GtkTextBuffer*
1580 get_buffer (GtkTextView *text_view)
1582 if (text_view->priv->buffer == NULL)
1585 b = gtk_text_buffer_new (NULL);
1586 gtk_text_view_set_buffer (text_view, b);
1590 return text_view->priv->buffer;
1594 * gtk_text_view_get_buffer:
1595 * @text_view: a #GtkTextView
1597 * Returns the #GtkTextBuffer being displayed by this text view.
1598 * The reference count on the buffer is not incremented; the caller
1599 * of this function won't own a new reference.
1601 * Return value: (transfer none): a #GtkTextBuffer
1604 gtk_text_view_get_buffer (GtkTextView *text_view)
1606 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
1608 return get_buffer (text_view);
1612 * gtk_text_view_get_iter_at_location:
1613 * @text_view: a #GtkTextView
1614 * @iter: (out): a #GtkTextIter
1615 * @x: x position, in buffer coordinates
1616 * @y: y position, in buffer coordinates
1618 * Retrieves the iterator at buffer coordinates @x and @y. Buffer
1619 * coordinates are coordinates for the entire buffer, not just the
1620 * currently-displayed portion. If you have coordinates from an
1621 * event, you have to convert those to buffer coordinates with
1622 * gtk_text_view_window_to_buffer_coords().
1625 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
1630 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1631 g_return_if_fail (iter != NULL);
1633 gtk_text_view_ensure_layout (text_view);
1635 gtk_text_layout_get_iter_at_pixel (text_view->priv->layout,
1640 * gtk_text_view_get_iter_at_position:
1641 * @text_view: a #GtkTextView
1642 * @iter: (out): a #GtkTextIter
1643 * @trailing: (out) (allow-none): if non-%NULL, location to store an integer indicating where
1644 * in the grapheme the user clicked. It will either be
1645 * zero, or the number of characters in the grapheme.
1646 * 0 represents the trailing edge of the grapheme.
1647 * @x: x position, in buffer coordinates
1648 * @y: y position, in buffer coordinates
1650 * Retrieves the iterator pointing to the character at buffer
1651 * coordinates @x and @y. Buffer coordinates are coordinates for
1652 * the entire buffer, not just the currently-displayed portion.
1653 * If you have coordinates from an event, you have to convert
1654 * those to buffer coordinates with
1655 * gtk_text_view_window_to_buffer_coords().
1657 * Note that this is different from gtk_text_view_get_iter_at_location(),
1658 * which returns cursor locations, i.e. positions <emphasis>between</emphasis>
1664 gtk_text_view_get_iter_at_position (GtkTextView *text_view,
1670 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1671 g_return_if_fail (iter != NULL);
1673 gtk_text_view_ensure_layout (text_view);
1675 gtk_text_layout_get_iter_at_position (text_view->priv->layout,
1676 iter, trailing, x, y);
1680 * gtk_text_view_get_iter_location:
1681 * @text_view: a #GtkTextView
1682 * @iter: a #GtkTextIter
1683 * @location: (out): bounds of the character at @iter
1685 * Gets a rectangle which roughly contains the character at @iter.
1686 * The rectangle position is in buffer coordinates; use
1687 * gtk_text_view_buffer_to_window_coords() to convert these
1688 * coordinates to coordinates for one of the windows in the text view.
1691 gtk_text_view_get_iter_location (GtkTextView *text_view,
1692 const GtkTextIter *iter,
1693 GdkRectangle *location)
1695 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1696 g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1698 gtk_text_view_ensure_layout (text_view);
1700 gtk_text_layout_get_iter_location (text_view->priv->layout, iter, location);
1704 * gtk_text_view_get_line_yrange:
1705 * @text_view: a #GtkTextView
1706 * @iter: a #GtkTextIter
1707 * @y: (out): return location for a y coordinate
1708 * @height: (out): return location for a height
1710 * Gets the y coordinate of the top of the line containing @iter,
1711 * and the height of the line. The coordinate is a buffer coordinate;
1712 * convert to window coordinates with gtk_text_view_buffer_to_window_coords().
1715 gtk_text_view_get_line_yrange (GtkTextView *text_view,
1716 const GtkTextIter *iter,
1720 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1721 g_return_if_fail (gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
1723 gtk_text_view_ensure_layout (text_view);
1725 gtk_text_layout_get_line_yrange (text_view->priv->layout,
1732 * gtk_text_view_get_line_at_y:
1733 * @text_view: a #GtkTextView
1734 * @target_iter: (out): a #GtkTextIter
1735 * @y: a y coordinate
1736 * @line_top: (out): return location for top coordinate of the line
1738 * Gets the #GtkTextIter at the start of the line containing
1739 * the coordinate @y. @y is in buffer coordinates, convert from
1740 * window coordinates with gtk_text_view_window_to_buffer_coords().
1741 * If non-%NULL, @line_top will be filled with the coordinate of the top
1745 gtk_text_view_get_line_at_y (GtkTextView *text_view,
1746 GtkTextIter *target_iter,
1750 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1752 gtk_text_view_ensure_layout (text_view);
1754 gtk_text_layout_get_line_at_y (text_view->priv->layout,
1761 set_adjustment_clamped (GtkAdjustment *adj, gdouble val)
1763 DV (g_print (" Setting adj to raw value %g\n", val));
1765 /* We don't really want to clamp to upper; we want to clamp to
1766 upper - page_size which is the highest value the scrollbar
1767 will let us reach. */
1768 if (val > (adj->upper - adj->page_size))
1769 val = adj->upper - adj->page_size;
1771 if (val < adj->lower)
1774 if (val != adj->value)
1776 DV (g_print (" Setting adj to clamped value %g\n", val));
1777 gtk_adjustment_set_value (adj, val);
1785 * gtk_text_view_scroll_to_iter:
1786 * @text_view: a #GtkTextView
1787 * @iter: a #GtkTextIter
1788 * @within_margin: margin as a [0.0,0.5) fraction of screen size
1789 * @use_align: whether to use alignment arguments (if %FALSE,
1790 * just get the mark onscreen)
1791 * @xalign: horizontal alignment of mark within visible area
1792 * @yalign: vertical alignment of mark within visible area
1794 * Scrolls @text_view so that @iter is on the screen in the position
1795 * indicated by @xalign and @yalign. An alignment of 0.0 indicates
1796 * left or top, 1.0 indicates right or bottom, 0.5 means center.
1797 * If @use_align is %FALSE, the text scrolls the minimal distance to
1798 * get the mark onscreen, possibly not scrolling at all. The effective
1799 * screen for purposes of this function is reduced by a margin of size
1802 * Note that this function uses the currently-computed height of the
1803 * lines in the text buffer. Line heights are computed in an idle
1804 * handler; so this function may not have the desired effect if it's
1805 * called before the height computations. To avoid oddness, consider
1806 * using gtk_text_view_scroll_to_mark() which saves a point to be
1807 * scrolled to after line validation.
1809 * Return value: %TRUE if scrolling occurred
1812 gtk_text_view_scroll_to_iter (GtkTextView *text_view,
1814 gdouble within_margin,
1820 GdkRectangle screen;
1825 gboolean retval = FALSE;
1827 gint screen_xoffset, screen_yoffset;
1828 gint current_x_scroll, current_y_scroll;
1830 /* FIXME why don't we do the validate-at-scroll-destination thing
1831 * from flush_scroll in this function? I think it wasn't done before
1832 * because changed_handler was screwed up, but I could be wrong.
1835 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1836 g_return_val_if_fail (iter != NULL, FALSE);
1837 g_return_val_if_fail (within_margin >= 0.0 && within_margin < 0.5, FALSE);
1838 g_return_val_if_fail (xalign >= 0.0 && xalign <= 1.0, FALSE);
1839 g_return_val_if_fail (yalign >= 0.0 && yalign <= 1.0, FALSE);
1841 widget = GTK_WIDGET (text_view);
1843 DV(g_print(G_STRLOC"\n"));
1845 gtk_text_layout_get_iter_location (text_view->priv->layout,
1849 DV (g_print (" target rect %d,%d %d x %d\n", rect.x, rect.y, rect.width, rect.height));
1851 current_x_scroll = text_view->priv->xoffset;
1852 current_y_scroll = text_view->priv->yoffset;
1854 screen.x = current_x_scroll;
1855 screen.y = current_y_scroll;
1856 screen.width = SCREEN_WIDTH (widget);
1857 screen.height = SCREEN_HEIGHT (widget);
1859 screen_xoffset = screen.width * within_margin;
1860 screen_yoffset = screen.height * within_margin;
1862 screen.x += screen_xoffset;
1863 screen.y += screen_yoffset;
1864 screen.width -= screen_xoffset * 2;
1865 screen.height -= screen_yoffset * 2;
1867 /* paranoia check */
1868 if (screen.width < 1)
1870 if (screen.height < 1)
1873 /* The -1 here ensures that we leave enough space to draw the cursor
1874 * when this function is used for horizontal scrolling.
1876 screen_right = screen.x + screen.width - 1;
1877 screen_bottom = screen.y + screen.height;
1879 /* The alignment affects the point in the target character that we
1880 * choose to align. If we're doing right/bottom alignment, we align
1881 * the right/bottom edge of the character the mark is at; if we're
1882 * doing left/top we align the left/top edge of the character; if
1883 * we're doing center alignment we align the center of the
1887 /* Vertical scroll */
1890 scroll_dest = current_y_scroll;
1894 scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
1896 /* if scroll_dest < screen.y, we move a negative increment (up),
1897 * else a positive increment (down)
1899 scroll_inc = scroll_dest - screen.y + screen_yoffset;
1903 /* move minimum to get onscreen */
1904 if (rect.y < screen.y)
1906 scroll_dest = rect.y;
1907 scroll_inc = scroll_dest - screen.y - screen_yoffset;
1909 else if ((rect.y + rect.height) > screen_bottom)
1911 scroll_dest = rect.y + rect.height;
1912 scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
1916 if (scroll_inc != 0)
1918 retval = set_adjustment_clamped (text_view->priv->vadjustment,
1919 current_y_scroll + scroll_inc);
1921 DV (g_print (" vert increment %d\n", scroll_inc));
1924 /* Horizontal scroll */
1927 scroll_dest = current_x_scroll;
1931 scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
1933 /* if scroll_dest < screen.y, we move a negative increment (left),
1934 * else a positive increment (right)
1936 scroll_inc = scroll_dest - screen.x + screen_xoffset;
1940 /* move minimum to get onscreen */
1941 if (rect.x < screen.x)
1943 scroll_dest = rect.x;
1944 scroll_inc = scroll_dest - screen.x - screen_xoffset;
1946 else if ((rect.x + rect.width) > screen_right)
1948 scroll_dest = rect.x + rect.width;
1949 scroll_inc = scroll_dest - screen_right + screen_xoffset;
1953 if (scroll_inc != 0)
1955 retval = set_adjustment_clamped (text_view->priv->hadjustment,
1956 current_x_scroll + scroll_inc);
1958 DV (g_print (" horiz increment %d\n", scroll_inc));
1963 DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
1967 DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
1974 free_pending_scroll (GtkTextPendingScroll *scroll)
1976 if (!gtk_text_mark_get_deleted (scroll->mark))
1977 gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (scroll->mark),
1979 g_object_unref (scroll->mark);
1984 cancel_pending_scroll (GtkTextView *text_view)
1986 if (text_view->priv->pending_scroll)
1988 free_pending_scroll (text_view->priv->pending_scroll);
1989 text_view->priv->pending_scroll = NULL;
1994 gtk_text_view_queue_scroll (GtkTextView *text_view,
1996 gdouble within_margin,
2002 GtkTextPendingScroll *scroll;
2004 DV(g_print(G_STRLOC"\n"));
2006 scroll = g_new (GtkTextPendingScroll, 1);
2008 scroll->within_margin = within_margin;
2009 scroll->use_align = use_align;
2010 scroll->xalign = xalign;
2011 scroll->yalign = yalign;
2013 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2015 scroll->mark = gtk_text_buffer_create_mark (get_buffer (text_view),
2018 gtk_text_mark_get_left_gravity (mark));
2020 g_object_ref (scroll->mark);
2022 cancel_pending_scroll (text_view);
2024 text_view->priv->pending_scroll = scroll;
2028 gtk_text_view_flush_scroll (GtkTextView *text_view)
2030 GtkAllocation allocation;
2032 GtkTextPendingScroll *scroll;
2036 widget = GTK_WIDGET (text_view);
2038 DV(g_print(G_STRLOC"\n"));
2040 if (text_view->priv->pending_scroll == NULL)
2042 DV (g_print ("in flush scroll, no pending scroll\n"));
2046 scroll = text_view->priv->pending_scroll;
2048 /* avoid recursion */
2049 text_view->priv->pending_scroll = NULL;
2051 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, scroll->mark);
2053 /* Validate area around the scroll destination, so the adjustment
2054 * can meaningfully point into that area. We must validate
2055 * enough area to be sure that after we scroll, everything onscreen
2056 * is valid; otherwise, validation will maintain the first para
2057 * in one place, but may push the target iter off the bottom of
2060 DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
2061 gtk_widget_get_allocation (widget, &allocation);
2062 gtk_text_layout_validate_yrange (text_view->priv->layout, &iter,
2063 -(allocation.height * 2),
2064 allocation.height * 2);
2066 DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
2068 /* Ensure we have updated width/height */
2069 gtk_text_view_update_adjustments (text_view);
2071 retval = gtk_text_view_scroll_to_iter (text_view,
2073 scroll->within_margin,
2078 free_pending_scroll (scroll);
2084 gtk_text_view_update_adjustments (GtkTextView *text_view)
2086 GtkTextViewPrivate *priv;
2087 gint width = 0, height = 0;
2089 DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
2091 priv = text_view->priv;
2094 gtk_text_layout_get_size (priv->layout, &width, &height);
2096 /* Make room for the cursor after the last character in the widest line */
2097 width += SPACE_FOR_CURSOR;
2099 if (priv->width != width || priv->height != height)
2101 if (priv->width != width)
2102 priv->width_changed = TRUE;
2104 priv->width = width;
2105 priv->height = height;
2107 gtk_text_view_set_hadjustment_values (text_view);
2108 gtk_text_view_set_vadjustment_values (text_view);
2113 gtk_text_view_update_layout_width (GtkTextView *text_view)
2115 DV(g_print(">Updating layout width ("G_STRLOC")\n"));
2117 gtk_text_view_ensure_layout (text_view);
2119 gtk_text_layout_set_screen_width (text_view->priv->layout,
2120 MAX (1, SCREEN_WIDTH (text_view) - SPACE_FOR_CURSOR));
2124 gtk_text_view_update_im_spot_location (GtkTextView *text_view)
2128 if (text_view->priv->layout == NULL)
2131 gtk_text_view_get_cursor_location (text_view, &area);
2133 area.x -= text_view->priv->xoffset;
2134 area.y -= text_view->priv->yoffset;
2136 /* Width returned by Pango indicates direction of cursor,
2137 * by it's sign more than the size of cursor.
2141 gtk_im_context_set_cursor_location (text_view->priv->im_context, &area);
2145 do_update_im_spot_location (gpointer text_view)
2147 GtkTextViewPrivate *priv;
2149 priv = GTK_TEXT_VIEW (text_view)->priv;
2150 priv->im_spot_idle = 0;
2152 gtk_text_view_update_im_spot_location (text_view);
2157 queue_update_im_spot_location (GtkTextView *text_view)
2159 GtkTextViewPrivate *priv;
2161 priv = text_view->priv;
2163 /* Use priority a little higher than GTK_TEXT_VIEW_PRIORITY_VALIDATE,
2164 * so we don't wait until the entire buffer has been validated. */
2165 if (!priv->im_spot_idle)
2166 priv->im_spot_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE - 1,
2167 do_update_im_spot_location,
2173 flush_update_im_spot_location (GtkTextView *text_view)
2175 GtkTextViewPrivate *priv;
2177 priv = text_view->priv;
2179 if (priv->im_spot_idle)
2181 g_source_remove (priv->im_spot_idle);
2182 priv->im_spot_idle = 0;
2183 gtk_text_view_update_im_spot_location (text_view);
2188 * gtk_text_view_scroll_to_mark:
2189 * @text_view: a #GtkTextView
2190 * @mark: a #GtkTextMark
2191 * @within_margin: margin as a [0.0,0.5) fraction of screen size
2192 * @use_align: whether to use alignment arguments (if %FALSE, just
2193 * get the mark onscreen)
2194 * @xalign: horizontal alignment of mark within visible area
2195 * @yalign: vertical alignment of mark within visible area
2197 * Scrolls @text_view so that @mark is on the screen in the position
2198 * indicated by @xalign and @yalign. An alignment of 0.0 indicates
2199 * left or top, 1.0 indicates right or bottom, 0.5 means center.
2200 * If @use_align is %FALSE, the text scrolls the minimal distance to
2201 * get the mark onscreen, possibly not scrolling at all. The effective
2202 * screen for purposes of this function is reduced by a margin of size
2206 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
2208 gdouble within_margin,
2213 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2214 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2215 g_return_if_fail (within_margin >= 0.0 && within_margin < 0.5);
2216 g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
2217 g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
2219 /* We need to verify that the buffer contains the mark, otherwise this
2220 * can lead to data structure corruption later on.
2222 g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
2224 gtk_text_view_queue_scroll (text_view, mark,
2230 /* If no validation is pending, we need to go ahead and force an
2233 if (text_view->priv->layout &&
2234 gtk_text_layout_is_valid (text_view->priv->layout))
2235 gtk_text_view_flush_scroll (text_view);
2239 * gtk_text_view_scroll_mark_onscreen:
2240 * @text_view: a #GtkTextView
2241 * @mark: a mark in the buffer for @text_view
2243 * Scrolls @text_view the minimum distance such that @mark is contained
2244 * within the visible area of the widget.
2247 gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
2250 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2251 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
2253 /* We need to verify that the buffer contains the mark, otherwise this
2254 * can lead to data structure corruption later on.
2256 g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
2258 gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
2262 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
2264 GdkRectangle visible_rect;
2265 gtk_text_view_get_visible_rect (text_view, &visible_rect);
2267 return gtk_text_layout_clamp_iter_to_vrange (text_view->priv->layout, iter,
2269 visible_rect.y + visible_rect.height);
2273 * gtk_text_view_move_mark_onscreen:
2274 * @text_view: a #GtkTextView
2275 * @mark: a #GtkTextMark
2277 * Moves a mark within the buffer so that it's
2278 * located within the currently-visible text area.
2280 * Return value: %TRUE if the mark moved (wasn't already onscreen)
2283 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
2288 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2289 g_return_val_if_fail (mark != NULL, FALSE);
2291 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, mark);
2293 if (clamp_iter_onscreen (text_view, &iter))
2295 gtk_text_buffer_move_mark (get_buffer (text_view), mark, &iter);
2303 * gtk_text_view_get_visible_rect:
2304 * @text_view: a #GtkTextView
2305 * @visible_rect: rectangle to fill
2307 * Fills @visible_rect with the currently-visible
2308 * region of the buffer, in buffer coordinates. Convert to window coordinates
2309 * with gtk_text_view_buffer_to_window_coords().
2312 gtk_text_view_get_visible_rect (GtkTextView *text_view,
2313 GdkRectangle *visible_rect)
2317 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2319 widget = GTK_WIDGET (text_view);
2323 visible_rect->x = text_view->priv->xoffset;
2324 visible_rect->y = text_view->priv->yoffset;
2325 visible_rect->width = SCREEN_WIDTH (widget);
2326 visible_rect->height = SCREEN_HEIGHT (widget);
2328 DV(g_print(" visible rect: %d,%d %d x %d\n",
2331 visible_rect->width,
2332 visible_rect->height));
2337 * gtk_text_view_set_wrap_mode:
2338 * @text_view: a #GtkTextView
2339 * @wrap_mode: a #GtkWrapMode
2341 * Sets the line wrapping for the view.
2344 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
2345 GtkWrapMode wrap_mode)
2347 GtkTextViewPrivate *priv;
2349 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2351 priv = text_view->priv;
2353 if (priv->wrap_mode != wrap_mode)
2355 priv->wrap_mode = wrap_mode;
2359 priv->layout->default_style->wrap_mode = wrap_mode;
2360 gtk_text_layout_default_style_changed (priv->layout);
2364 g_object_notify (G_OBJECT (text_view), "wrap-mode");
2368 * gtk_text_view_get_wrap_mode:
2369 * @text_view: a #GtkTextView
2371 * Gets the line wrapping for the view.
2373 * Return value: the line wrap setting
2376 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
2378 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAP_NONE);
2380 return text_view->priv->wrap_mode;
2384 * gtk_text_view_set_editable:
2385 * @text_view: a #GtkTextView
2386 * @setting: whether it's editable
2388 * Sets the default editability of the #GtkTextView. You can override
2389 * this default setting with tags in the buffer, using the "editable"
2390 * attribute of tags.
2393 gtk_text_view_set_editable (GtkTextView *text_view,
2396 GtkTextViewPrivate *priv;
2398 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2400 priv = text_view->priv;
2401 setting = setting != FALSE;
2403 if (priv->editable != setting)
2407 gtk_text_view_reset_im_context(text_view);
2408 if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
2409 gtk_im_context_focus_out (priv->im_context);
2412 priv->editable = setting;
2414 if (setting && gtk_widget_has_focus (GTK_WIDGET (text_view)))
2415 gtk_im_context_focus_in (priv->im_context);
2419 gtk_text_layout_set_overwrite_mode (priv->layout,
2420 priv->overwrite_mode && priv->editable);
2421 priv->layout->default_style->editable = priv->editable;
2422 gtk_text_layout_default_style_changed (priv->layout);
2425 g_object_notify (G_OBJECT (text_view), "editable");
2430 * gtk_text_view_get_editable:
2431 * @text_view: a #GtkTextView
2433 * Returns the default editability of the #GtkTextView. Tags in the
2434 * buffer may override this setting for some ranges of text.
2436 * Return value: whether text is editable by default
2439 gtk_text_view_get_editable (GtkTextView *text_view)
2441 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2443 return text_view->priv->editable;
2447 * gtk_text_view_set_pixels_above_lines:
2448 * @text_view: a #GtkTextView
2449 * @pixels_above_lines: pixels above paragraphs
2451 * Sets the default number of blank pixels above paragraphs in @text_view.
2452 * Tags in the buffer for @text_view may override the defaults.
2455 gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
2456 gint pixels_above_lines)
2458 GtkTextViewPrivate *priv;
2460 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2462 priv = text_view->priv;
2464 if (priv->pixels_above_lines != pixels_above_lines)
2466 priv->pixels_above_lines = pixels_above_lines;
2470 priv->layout->default_style->pixels_above_lines = pixels_above_lines;
2471 gtk_text_layout_default_style_changed (priv->layout);
2474 g_object_notify (G_OBJECT (text_view), "pixels-above-lines");
2479 * gtk_text_view_get_pixels_above_lines:
2480 * @text_view: a #GtkTextView
2482 * Gets the default number of pixels to put above paragraphs.
2484 * Return value: default number of pixels above paragraphs
2487 gtk_text_view_get_pixels_above_lines (GtkTextView *text_view)
2489 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2491 return text_view->priv->pixels_above_lines;
2495 * gtk_text_view_set_pixels_below_lines:
2496 * @text_view: a #GtkTextView
2497 * @pixels_below_lines: pixels below paragraphs
2499 * Sets the default number of pixels of blank space
2500 * to put below paragraphs in @text_view. May be overridden
2501 * by tags applied to @text_view's buffer.
2504 gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
2505 gint pixels_below_lines)
2507 GtkTextViewPrivate *priv;
2509 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2511 priv = text_view->priv;
2513 if (priv->pixels_below_lines != pixels_below_lines)
2515 priv->pixels_below_lines = pixels_below_lines;
2519 priv->layout->default_style->pixels_below_lines = pixels_below_lines;
2520 gtk_text_layout_default_style_changed (priv->layout);
2523 g_object_notify (G_OBJECT (text_view), "pixels-below-lines");
2528 * gtk_text_view_get_pixels_below_lines:
2529 * @text_view: a #GtkTextView
2531 * Gets the value set by gtk_text_view_set_pixels_below_lines().
2533 * Return value: default number of blank pixels below paragraphs
2536 gtk_text_view_get_pixels_below_lines (GtkTextView *text_view)
2538 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2540 return text_view->priv->pixels_below_lines;
2544 * gtk_text_view_set_pixels_inside_wrap:
2545 * @text_view: a #GtkTextView
2546 * @pixels_inside_wrap: default number of pixels between wrapped lines
2548 * Sets the default number of pixels of blank space to leave between
2549 * display/wrapped lines within a paragraph. May be overridden by
2550 * tags in @text_view's buffer.
2553 gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
2554 gint pixels_inside_wrap)
2556 GtkTextViewPrivate *priv;
2558 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2560 priv = text_view->priv;
2562 if (priv->pixels_inside_wrap != pixels_inside_wrap)
2564 priv->pixels_inside_wrap = pixels_inside_wrap;
2568 priv->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
2569 gtk_text_layout_default_style_changed (priv->layout);
2572 g_object_notify (G_OBJECT (text_view), "pixels-inside-wrap");
2577 * gtk_text_view_get_pixels_inside_wrap:
2578 * @text_view: a #GtkTextView
2580 * Gets the value set by gtk_text_view_set_pixels_inside_wrap().
2582 * Return value: default number of pixels of blank space between wrapped lines
2585 gtk_text_view_get_pixels_inside_wrap (GtkTextView *text_view)
2587 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2589 return text_view->priv->pixels_inside_wrap;
2593 * gtk_text_view_set_justification:
2594 * @text_view: a #GtkTextView
2595 * @justification: justification
2597 * Sets the default justification of text in @text_view.
2598 * Tags in the view's buffer may override the default.
2602 gtk_text_view_set_justification (GtkTextView *text_view,
2603 GtkJustification justification)
2605 GtkTextViewPrivate *priv;
2607 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2609 priv = text_view->priv;
2611 if (priv->justify != justification)
2613 priv->justify = justification;
2617 priv->layout->default_style->justification = justification;
2618 gtk_text_layout_default_style_changed (priv->layout);
2621 g_object_notify (G_OBJECT (text_view), "justification");
2626 * gtk_text_view_get_justification:
2627 * @text_view: a #GtkTextView
2629 * Gets the default justification of paragraphs in @text_view.
2630 * Tags in the buffer may override the default.
2632 * Return value: default justification
2635 gtk_text_view_get_justification (GtkTextView *text_view)
2637 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_JUSTIFY_LEFT);
2639 return text_view->priv->justify;
2643 * gtk_text_view_set_left_margin:
2644 * @text_view: a #GtkTextView
2645 * @left_margin: left margin in pixels
2647 * Sets the default left margin for text in @text_view.
2648 * Tags in the buffer may override the default.
2651 gtk_text_view_set_left_margin (GtkTextView *text_view,
2654 GtkTextViewPrivate *priv;
2656 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2658 priv = text_view->priv;
2660 if (priv->left_margin != left_margin)
2662 priv->left_margin = left_margin;
2666 priv->layout->default_style->left_margin = left_margin;
2667 gtk_text_layout_default_style_changed (priv->layout);
2670 g_object_notify (G_OBJECT (text_view), "left-margin");
2675 * gtk_text_view_get_left_margin:
2676 * @text_view: a #GtkTextView
2678 * Gets the default left margin size of paragraphs in the @text_view.
2679 * Tags in the buffer may override the default.
2681 * Return value: left margin in pixels
2684 gtk_text_view_get_left_margin (GtkTextView *text_view)
2686 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2688 return text_view->priv->left_margin;
2692 * gtk_text_view_set_right_margin:
2693 * @text_view: a #GtkTextView
2694 * @right_margin: right margin in pixels
2696 * Sets the default right margin for text in the text view.
2697 * Tags in the buffer may override the default.
2700 gtk_text_view_set_right_margin (GtkTextView *text_view,
2703 GtkTextViewPrivate *priv = text_view->priv;
2705 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2707 if (priv->right_margin != right_margin)
2709 priv->right_margin = right_margin;
2713 priv->layout->default_style->right_margin = right_margin;
2714 gtk_text_layout_default_style_changed (priv->layout);
2717 g_object_notify (G_OBJECT (text_view), "right-margin");
2722 * gtk_text_view_get_right_margin:
2723 * @text_view: a #GtkTextView
2725 * Gets the default right margin for text in @text_view. Tags
2726 * in the buffer may override the default.
2728 * Return value: right margin in pixels
2731 gtk_text_view_get_right_margin (GtkTextView *text_view)
2733 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2735 return text_view->priv->right_margin;
2739 * gtk_text_view_set_indent:
2740 * @text_view: a #GtkTextView
2741 * @indent: indentation in pixels
2743 * Sets the default indentation for paragraphs in @text_view.
2744 * Tags in the buffer may override the default.
2747 gtk_text_view_set_indent (GtkTextView *text_view,
2750 GtkTextViewPrivate *priv;
2752 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2754 priv = text_view->priv;
2756 if (priv->indent != indent)
2758 priv->indent = indent;
2762 priv->layout->default_style->indent = indent;
2763 gtk_text_layout_default_style_changed (priv->layout);
2766 g_object_notify (G_OBJECT (text_view), "indent");
2771 * gtk_text_view_get_indent:
2772 * @text_view: a #GtkTextView
2774 * Gets the default indentation of paragraphs in @text_view.
2775 * Tags in the view's buffer may override the default.
2776 * The indentation may be negative.
2778 * Return value: number of pixels of indentation
2781 gtk_text_view_get_indent (GtkTextView *text_view)
2783 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
2785 return text_view->priv->indent;
2789 * gtk_text_view_set_tabs:
2790 * @text_view: a #GtkTextView
2791 * @tabs: tabs as a #PangoTabArray
2793 * Sets the default tab stops for paragraphs in @text_view.
2794 * Tags in the buffer may override the default.
2797 gtk_text_view_set_tabs (GtkTextView *text_view,
2798 PangoTabArray *tabs)
2800 GtkTextViewPrivate *priv;
2802 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2804 priv = text_view->priv;
2807 pango_tab_array_free (priv->tabs);
2809 priv->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
2813 /* some unkosher futzing in internal struct details... */
2814 if (priv->layout->default_style->tabs)
2815 pango_tab_array_free (priv->layout->default_style->tabs);
2817 priv->layout->default_style->tabs =
2818 priv->tabs ? pango_tab_array_copy (priv->tabs) : NULL;
2820 gtk_text_layout_default_style_changed (priv->layout);
2823 g_object_notify (G_OBJECT (text_view), "tabs");
2827 * gtk_text_view_get_tabs:
2828 * @text_view: a #GtkTextView
2830 * Gets the default tabs for @text_view. Tags in the buffer may
2831 * override the defaults. The returned array will be %NULL if
2832 * "standard" (8-space) tabs are used. Free the return value
2833 * with pango_tab_array_free().
2835 * Return value: copy of default tab array, or %NULL if "standard"
2836 * tabs are used; must be freed with pango_tab_array_free().
2839 gtk_text_view_get_tabs (GtkTextView *text_view)
2841 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
2843 return text_view->priv->tabs ? pango_tab_array_copy (text_view->priv->tabs) : NULL;
2847 gtk_text_view_toggle_cursor_visible (GtkTextView *text_view)
2849 gtk_text_view_set_cursor_visible (text_view, !text_view->priv->cursor_visible);
2853 * gtk_text_view_set_cursor_visible:
2854 * @text_view: a #GtkTextView
2855 * @setting: whether to show the insertion cursor
2857 * Toggles whether the insertion point is displayed. A buffer with no editable
2858 * text probably shouldn't have a visible cursor, so you may want to turn
2862 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
2865 GtkTextViewPrivate *priv;
2867 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2869 priv = text_view->priv;
2870 setting = (setting != FALSE);
2872 if (priv->cursor_visible != setting)
2874 priv->cursor_visible = setting;
2876 if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
2880 gtk_text_layout_set_cursor_visible (priv->layout, setting);
2881 gtk_text_view_check_cursor_blink (text_view);
2885 g_object_notify (G_OBJECT (text_view), "cursor-visible");
2890 * gtk_text_view_get_cursor_visible:
2891 * @text_view: a #GtkTextView
2893 * Find out whether the cursor is being displayed.
2895 * Return value: whether the insertion mark is visible
2898 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
2900 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2902 return text_view->priv->cursor_visible;
2907 * gtk_text_view_place_cursor_onscreen:
2908 * @text_view: a #GtkTextView
2910 * Moves the cursor to the currently visible region of the
2911 * buffer, it it isn't there already.
2913 * Return value: %TRUE if the cursor had to be moved.
2916 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
2920 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
2922 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
2923 gtk_text_buffer_get_insert (get_buffer (text_view)));
2925 if (clamp_iter_onscreen (text_view, &insert))
2927 gtk_text_buffer_place_cursor (get_buffer (text_view), &insert);
2935 gtk_text_view_remove_validate_idles (GtkTextView *text_view)
2937 GtkTextViewPrivate *priv = text_view->priv;
2939 if (priv->first_validate_idle != 0)
2941 DV (g_print ("Removing first validate idle: %s\n", G_STRLOC));
2942 g_source_remove (priv->first_validate_idle);
2943 priv->first_validate_idle = 0;
2946 if (priv->incremental_validate_idle != 0)
2948 g_source_remove (priv->incremental_validate_idle);
2949 priv->incremental_validate_idle = 0;
2954 gtk_text_view_destroy (GtkWidget *widget)
2956 GtkTextView *text_view;
2957 GtkTextViewPrivate *priv;
2959 text_view = GTK_TEXT_VIEW (widget);
2960 priv = text_view->priv;
2962 gtk_text_view_remove_validate_idles (text_view);
2963 gtk_text_view_set_buffer (text_view, NULL);
2964 gtk_text_view_destroy_layout (text_view);
2966 if (text_view->priv->scroll_timeout)
2968 g_source_remove (text_view->priv->scroll_timeout);
2969 text_view->priv->scroll_timeout = 0;
2972 if (priv->im_spot_idle)
2974 g_source_remove (priv->im_spot_idle);
2975 priv->im_spot_idle = 0;
2978 GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget);
2982 gtk_text_view_finalize (GObject *object)
2984 GtkTextView *text_view;
2985 GtkTextViewPrivate *priv;
2987 text_view = GTK_TEXT_VIEW (object);
2988 priv = text_view->priv;
2990 g_assert (priv->buffer == NULL);
2992 gtk_text_view_destroy_layout (text_view);
2993 gtk_text_view_set_buffer (text_view, NULL);
2995 cancel_pending_scroll (text_view);
2998 pango_tab_array_free (priv->tabs);
3000 if (priv->hadjustment)
3001 g_object_unref (priv->hadjustment);
3002 if (priv->vadjustment)
3003 g_object_unref (priv->vadjustment);
3005 text_window_free (priv->text_window);
3007 if (priv->left_window)
3008 text_window_free (priv->left_window);
3010 if (priv->top_window)
3011 text_window_free (priv->top_window);
3013 if (priv->right_window)
3014 text_window_free (priv->right_window);
3016 if (priv->bottom_window)
3017 text_window_free (priv->bottom_window);
3019 g_object_unref (priv->im_context);
3021 g_free (priv->im_module);
3023 G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize (object);
3027 gtk_text_view_set_property (GObject *object,
3029 const GValue *value,
3032 GtkTextView *text_view;
3033 GtkTextViewPrivate *priv;
3035 text_view = GTK_TEXT_VIEW (object);
3036 priv = text_view->priv;
3040 case PROP_PIXELS_ABOVE_LINES:
3041 gtk_text_view_set_pixels_above_lines (text_view, g_value_get_int (value));
3044 case PROP_PIXELS_BELOW_LINES:
3045 gtk_text_view_set_pixels_below_lines (text_view, g_value_get_int (value));
3048 case PROP_PIXELS_INSIDE_WRAP:
3049 gtk_text_view_set_pixels_inside_wrap (text_view, g_value_get_int (value));
3053 gtk_text_view_set_editable (text_view, g_value_get_boolean (value));
3056 case PROP_WRAP_MODE:
3057 gtk_text_view_set_wrap_mode (text_view, g_value_get_enum (value));
3060 case PROP_JUSTIFICATION:
3061 gtk_text_view_set_justification (text_view, g_value_get_enum (value));
3064 case PROP_LEFT_MARGIN:
3065 gtk_text_view_set_left_margin (text_view, g_value_get_int (value));
3068 case PROP_RIGHT_MARGIN:
3069 gtk_text_view_set_right_margin (text_view, g_value_get_int (value));
3073 gtk_text_view_set_indent (text_view, g_value_get_int (value));
3077 gtk_text_view_set_tabs (text_view, g_value_get_boxed (value));
3080 case PROP_CURSOR_VISIBLE:
3081 gtk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
3084 case PROP_OVERWRITE:
3085 gtk_text_view_set_overwrite (text_view, g_value_get_boolean (value));
3089 gtk_text_view_set_buffer (text_view, GTK_TEXT_BUFFER (g_value_get_object (value)));
3092 case PROP_ACCEPTS_TAB:
3093 gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
3096 case PROP_IM_MODULE:
3097 g_free (priv->im_module);
3098 priv->im_module = g_value_dup_string (value);
3099 if (GTK_IS_IM_MULTICONTEXT (priv->im_context))
3100 gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (priv->im_context), priv->im_module);
3103 case PROP_HADJUSTMENT:
3104 gtk_text_view_set_hadjustment (text_view, g_value_get_object (value));
3107 case PROP_VADJUSTMENT:
3108 gtk_text_view_set_vadjustment (text_view, g_value_get_object (value));
3111 case PROP_HSCROLL_POLICY:
3112 priv->hscroll_policy = g_value_get_enum (value);
3113 gtk_widget_queue_resize (GTK_WIDGET (text_view));
3116 case PROP_VSCROLL_POLICY:
3117 priv->vscroll_policy = g_value_get_enum (value);
3118 gtk_widget_queue_resize (GTK_WIDGET (text_view));
3122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3128 gtk_text_view_get_property (GObject *object,
3133 GtkTextView *text_view;
3134 GtkTextViewPrivate *priv;
3136 text_view = GTK_TEXT_VIEW (object);
3137 priv = text_view->priv;
3141 case PROP_PIXELS_ABOVE_LINES:
3142 g_value_set_int (value, priv->pixels_above_lines);
3145 case PROP_PIXELS_BELOW_LINES:
3146 g_value_set_int (value, priv->pixels_below_lines);
3149 case PROP_PIXELS_INSIDE_WRAP:
3150 g_value_set_int (value, priv->pixels_inside_wrap);
3154 g_value_set_boolean (value, priv->editable);
3157 case PROP_WRAP_MODE:
3158 g_value_set_enum (value, priv->wrap_mode);
3161 case PROP_JUSTIFICATION:
3162 g_value_set_enum (value, priv->justify);
3165 case PROP_LEFT_MARGIN:
3166 g_value_set_int (value, priv->left_margin);
3169 case PROP_RIGHT_MARGIN:
3170 g_value_set_int (value, priv->right_margin);
3174 g_value_set_int (value, priv->indent);
3178 g_value_set_boxed (value, priv->tabs);
3181 case PROP_CURSOR_VISIBLE:
3182 g_value_set_boolean (value, priv->cursor_visible);
3186 g_value_set_object (value, get_buffer (text_view));
3189 case PROP_OVERWRITE:
3190 g_value_set_boolean (value, priv->overwrite_mode);
3193 case PROP_ACCEPTS_TAB:
3194 g_value_set_boolean (value, priv->accepts_tab);
3197 case PROP_IM_MODULE:
3198 g_value_set_string (value, priv->im_module);
3201 case PROP_HADJUSTMENT:
3202 g_value_set_object (value, priv->hadjustment);
3205 case PROP_VADJUSTMENT:
3206 g_value_set_object (value, priv->vadjustment);
3209 case PROP_HSCROLL_POLICY:
3210 g_value_set_enum (value, priv->hscroll_policy);
3213 case PROP_VSCROLL_POLICY:
3214 g_value_set_enum (value, priv->vscroll_policy);
3218 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3224 gtk_text_view_size_request (GtkWidget *widget,
3225 GtkRequisition *requisition)
3227 GtkTextView *text_view;
3228 GtkTextViewPrivate *priv;
3230 gint focus_edge_width;
3233 gboolean interior_focus;
3235 text_view = GTK_TEXT_VIEW (widget);
3236 priv = text_view->priv;
3238 gtk_widget_style_get (widget,
3239 "interior-focus", &interior_focus,
3240 "focus-line-width", &focus_width,
3244 focus_edge_width = 0;
3246 focus_edge_width = focus_width;
3250 priv->text_window->requisition.width = priv->layout->width;
3251 priv->text_window->requisition.height = priv->layout->height;
3255 priv->text_window->requisition.width = 0;
3256 priv->text_window->requisition.height = 0;
3259 requisition->width = priv->text_window->requisition.width + focus_edge_width * 2;
3260 requisition->height = priv->text_window->requisition.height + focus_edge_width * 2;
3262 if (priv->left_window)
3263 requisition->width += priv->left_window->requisition.width;
3265 if (priv->right_window)
3266 requisition->width += priv->right_window->requisition.width;
3268 if (priv->top_window)
3269 requisition->height += priv->top_window->requisition.height;
3271 if (priv->bottom_window)
3272 requisition->height += priv->bottom_window->requisition.height;
3274 border_width = gtk_container_get_border_width (GTK_CONTAINER (text_view));
3275 requisition->width += border_width * 2;
3276 requisition->height += border_width * 2;
3278 tmp_list = priv->children;
3279 while (tmp_list != NULL)
3281 GtkTextViewChild *child = tmp_list->data;
3285 GtkRequisition child_req;
3286 GtkRequisition old_req;
3288 gtk_widget_get_preferred_size (child->widget, &old_req, NULL);
3290 gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
3292 /* Invalidate layout lines if required */
3294 (old_req.width != child_req.width ||
3295 old_req.height != child_req.height))
3296 gtk_text_child_anchor_queue_resize (child->anchor,
3301 GtkRequisition child_req;
3303 gtk_widget_get_preferred_size (child->widget,
3307 tmp_list = g_slist_next (tmp_list);
3310 /* Cache the requested size of the text view so we can
3311 * compare it in the changed_handler() */
3312 priv->cached_size_request = *requisition;
3316 gtk_text_view_get_preferred_width (GtkWidget *widget,
3320 GtkRequisition requisition;
3322 gtk_text_view_size_request (widget, &requisition);
3324 *minimum = *natural = requisition.width;
3328 gtk_text_view_get_preferred_height (GtkWidget *widget,
3332 GtkRequisition requisition;
3334 gtk_text_view_size_request (widget, &requisition);
3336 *minimum = *natural = requisition.height;
3341 gtk_text_view_compute_child_allocation (GtkTextView *text_view,
3342 GtkTextViewChild *vc,
3343 GtkAllocation *allocation)
3349 gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3353 gtk_text_layout_get_line_yrange (text_view->priv->layout, &iter,
3356 buffer_y += vc->from_top_of_line;
3358 allocation->x = vc->from_left_of_buffer - text_view->priv->xoffset;
3359 allocation->y = buffer_y - text_view->priv->yoffset;
3361 gtk_widget_get_preferred_size (vc->widget, &req, NULL);
3362 allocation->width = req.width;
3363 allocation->height = req.height;
3367 gtk_text_view_update_child_allocation (GtkTextView *text_view,
3368 GtkTextViewChild *vc)
3370 GtkAllocation allocation;
3372 gtk_text_view_compute_child_allocation (text_view, vc, &allocation);
3374 gtk_widget_size_allocate (vc->widget, &allocation);
3377 g_print ("allocation for %p allocated to %d,%d yoffset = %d\n",
3379 vc->widget->allocation.x,
3380 vc->widget->allocation.y,
3381 text_view->priv->yoffset);
3386 gtk_text_view_child_allocated (GtkTextLayout *layout,
3392 GtkTextViewChild *vc = NULL;
3393 GtkTextView *text_view = data;
3395 /* x,y is the position of the child from the top of the line, and
3396 * from the left of the buffer. We have to translate that into text
3397 * window coordinates, then size_allocate the child.
3400 vc = g_object_get_data (G_OBJECT (child),
3401 "gtk-text-view-child");
3403 g_assert (vc != NULL);
3405 DV (g_print ("child allocated at %d,%d\n", x, y));
3407 vc->from_left_of_buffer = x;
3408 vc->from_top_of_line = y;
3410 gtk_text_view_update_child_allocation (text_view, vc);
3414 gtk_text_view_allocate_children (GtkTextView *text_view)
3418 DV(g_print(G_STRLOC"\n"));
3420 tmp_list = text_view->priv->children;
3421 while (tmp_list != NULL)
3423 GtkTextViewChild *child = tmp_list->data;
3425 g_assert (child != NULL);
3429 /* We need to force-validate the regions containing
3432 GtkTextIter child_loc;
3433 gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
3437 /* Since anchored children are only ever allocated from
3438 * gtk_text_layout_get_line_display() we have to make sure
3439 * that the display line caching in the layout doesn't
3440 * get in the way. Invalidating the layout around the anchor
3443 if (_gtk_widget_get_alloc_needed (child->widget))
3445 GtkTextIter end = child_loc;
3446 gtk_text_iter_forward_char (&end);
3447 gtk_text_layout_invalidate (text_view->priv->layout, &child_loc, &end);
3450 gtk_text_layout_validate_yrange (text_view->priv->layout,
3456 GtkAllocation allocation;
3457 GtkRequisition child_req;
3459 allocation.x = child->x;
3460 allocation.y = child->y;
3462 gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
3464 allocation.width = child_req.width;
3465 allocation.height = child_req.height;
3467 gtk_widget_size_allocate (child->widget, &allocation);
3470 tmp_list = g_slist_next (tmp_list);
3475 gtk_text_view_size_allocate (GtkWidget *widget,
3476 GtkAllocation *allocation)
3478 GtkAllocation widget_allocation;
3479 GtkTextView *text_view;
3480 GtkTextViewPrivate *priv;
3482 GdkRectangle text_rect;
3483 GdkRectangle left_rect;
3484 GdkRectangle right_rect;
3485 GdkRectangle top_rect;
3486 GdkRectangle bottom_rect;
3487 gint focus_edge_width;
3490 gboolean interior_focus;
3491 gboolean size_changed;
3493 text_view = GTK_TEXT_VIEW (widget);
3494 priv = text_view->priv;
3496 DV(g_print(G_STRLOC"\n"));
3498 gtk_widget_get_allocation (widget, &widget_allocation);
3500 widget_allocation.width != allocation->width ||
3501 widget_allocation.height != allocation->height;
3503 border_width = gtk_container_get_border_width (GTK_CONTAINER (text_view));
3505 gtk_widget_set_allocation (widget, allocation);
3507 if (gtk_widget_get_realized (widget))
3509 gdk_window_move_resize (gtk_widget_get_window (widget),
3510 allocation->x, allocation->y,
3511 allocation->width, allocation->height);
3514 /* distribute width/height among child windows. Ensure all
3515 * windows get at least a 1x1 allocation.
3518 gtk_widget_style_get (widget,
3519 "interior-focus", &interior_focus,
3520 "focus-line-width", &focus_width,
3524 focus_edge_width = 0;
3526 focus_edge_width = focus_width;
3528 width = allocation->width - focus_edge_width * 2 - border_width * 2;
3530 if (priv->left_window)
3531 left_rect.width = priv->left_window->requisition.width;
3533 left_rect.width = 0;
3535 width -= left_rect.width;
3537 if (priv->right_window)
3538 right_rect.width = priv->right_window->requisition.width;
3540 right_rect.width = 0;
3542 width -= right_rect.width;
3544 text_rect.width = MAX (1, width);
3546 top_rect.width = text_rect.width;
3547 bottom_rect.width = text_rect.width;
3550 height = allocation->height - focus_edge_width * 2 - border_width * 2;
3552 if (priv->top_window)
3553 top_rect.height = priv->top_window->requisition.height;
3555 top_rect.height = 0;
3557 height -= top_rect.height;
3559 if (priv->bottom_window)
3560 bottom_rect.height = priv->bottom_window->requisition.height;
3562 bottom_rect.height = 0;
3564 height -= bottom_rect.height;
3566 text_rect.height = MAX (1, height);
3568 left_rect.height = text_rect.height;
3569 right_rect.height = text_rect.height;
3572 left_rect.x = focus_edge_width + border_width;
3573 top_rect.y = focus_edge_width + border_width;
3575 text_rect.x = left_rect.x + left_rect.width;
3576 text_rect.y = top_rect.y + top_rect.height;
3578 left_rect.y = text_rect.y;
3579 right_rect.y = text_rect.y;
3581 top_rect.x = text_rect.x;
3582 bottom_rect.x = text_rect.x;
3584 right_rect.x = text_rect.x + text_rect.width;
3585 bottom_rect.y = text_rect.y + text_rect.height;
3587 text_window_size_allocate (priv->text_window,
3590 if (priv->left_window)
3591 text_window_size_allocate (priv->left_window,
3594 if (priv->right_window)
3595 text_window_size_allocate (priv->right_window,
3598 if (priv->top_window)
3599 text_window_size_allocate (priv->top_window,
3602 if (priv->bottom_window)
3603 text_window_size_allocate (priv->bottom_window,
3606 gtk_text_view_update_layout_width (text_view);
3608 /* Note that this will do some layout validation */
3609 gtk_text_view_allocate_children (text_view);
3611 /* Update adjustments */
3612 gtk_text_view_set_hadjustment_values (text_view);
3613 gtk_text_view_set_vadjustment_values (text_view);
3615 /* The GTK resize loop processes all the pending exposes right
3616 * after doing the resize stuff, so the idle sizer won't have a
3617 * chance to run. So we do the work here.
3619 gtk_text_view_flush_first_validate (text_view);
3621 /* widget->window doesn't get auto-redrawn as the layout is computed, so has to
3624 if (size_changed && gtk_widget_get_realized (widget))
3625 gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);
3629 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
3632 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), iter,
3633 text_view->priv->first_para_mark);
3637 gtk_text_view_validate_onscreen (GtkTextView *text_view)
3640 GtkTextViewPrivate *priv;
3642 widget = GTK_WIDGET (text_view);
3643 priv = text_view->priv;
3645 DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
3647 if (SCREEN_HEIGHT (widget) > 0)
3649 GtkTextIter first_para;
3651 /* Be sure we've validated the stuff onscreen; if we
3652 * scrolled, these calls won't have any effect, because
3653 * they were called in the recursive validate_onscreen
3655 gtk_text_view_get_first_para_iter (text_view, &first_para);
3657 gtk_text_layout_validate_yrange (priv->layout,
3660 priv->first_para_pixels +
3661 SCREEN_HEIGHT (widget));
3664 priv->onscreen_validated = TRUE;
3666 DV(g_print(">Done validating onscreen, onscreen_validated = TRUE ("G_STRLOC")\n"));
3668 /* This can have the odd side effect of triggering a scroll, which should
3669 * flip "onscreen_validated" back to FALSE, but should also get us
3670 * back into this function to turn it on again.
3672 gtk_text_view_update_adjustments (text_view);
3674 g_assert (priv->onscreen_validated);
3678 gtk_text_view_flush_first_validate (GtkTextView *text_view)
3680 GtkTextViewPrivate *priv = text_view->priv;
3682 if (priv->first_validate_idle == 0)
3685 /* Do this first, which means that if an "invalidate"
3686 * occurs during any of this process, a new first_validate_callback
3687 * will be installed, and we'll start again.
3689 DV (g_print ("removing first validate in %s\n", G_STRLOC));
3690 g_source_remove (priv->first_validate_idle);
3691 priv->first_validate_idle = 0;
3693 /* be sure we have up-to-date screen size set on the
3696 gtk_text_view_update_layout_width (text_view);
3698 /* Bail out if we invalidated stuff; scrolling right away will just
3699 * confuse the issue.
3701 if (priv->first_validate_idle != 0)
3703 DV(g_print(">Width change forced requeue ("G_STRLOC")\n"));
3707 /* scroll to any marks, if that's pending. This can jump us to
3708 * the validation codepath used for scrolling onscreen, if so we
3709 * bail out. It won't jump if already in that codepath since
3710 * value_changed is not recursive, so also validate if
3713 if (!gtk_text_view_flush_scroll (text_view) ||
3714 !priv->onscreen_validated)
3715 gtk_text_view_validate_onscreen (text_view);
3717 DV(g_print(">Leaving first validate idle ("G_STRLOC")\n"));
3719 g_assert (priv->onscreen_validated);
3724 first_validate_callback (gpointer data)
3726 GtkTextView *text_view = data;
3728 /* Note that some of this code is duplicated at the end of size_allocate,
3729 * keep in sync with that.
3732 DV(g_print(G_STRLOC"\n"));
3734 gtk_text_view_flush_first_validate (text_view);
3740 incremental_validate_callback (gpointer data)
3742 GtkTextView *text_view = data;
3743 gboolean result = TRUE;
3745 DV(g_print(G_STRLOC"\n"));
3747 gtk_text_layout_validate (text_view->priv->layout, 2000);
3749 gtk_text_view_update_adjustments (text_view);
3751 if (gtk_text_layout_is_valid (text_view->priv->layout))
3753 text_view->priv->incremental_validate_idle = 0;
3761 gtk_text_view_invalidate (GtkTextView *text_view)
3763 GtkTextViewPrivate *priv = text_view->priv;
3765 DV (g_print (">Invalidate, onscreen_validated = %d now FALSE ("G_STRLOC")\n",
3766 priv->onscreen_validated));
3768 priv->onscreen_validated = FALSE;
3770 /* We'll invalidate when the layout is created */
3771 if (priv->layout == NULL)
3774 if (!priv->first_validate_idle)
3776 priv->first_validate_idle = gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
3777 DV (g_print (G_STRLOC": adding first validate idle %d\n",
3778 priv->first_validate_idle));
3781 if (!priv->incremental_validate_idle)
3783 priv->incremental_validate_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
3784 DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
3785 priv->incremental_validate_idle));
3790 invalidated_handler (GtkTextLayout *layout,
3793 GtkTextView *text_view;
3795 text_view = GTK_TEXT_VIEW (data);
3797 DV (g_print ("Invalidating due to layout invalidate signal\n"));
3798 gtk_text_view_invalidate (text_view);
3802 changed_handler (GtkTextLayout *layout,
3808 GtkTextView *text_view;
3809 GtkTextViewPrivate *priv;
3811 GdkRectangle visible_rect;
3812 GdkRectangle redraw_rect;
3814 text_view = GTK_TEXT_VIEW (data);
3815 priv = text_view->priv;
3816 widget = GTK_WIDGET (data);
3818 DV(g_print(">Lines Validated ("G_STRLOC")\n"));
3820 if (gtk_widget_get_realized (widget))
3822 gtk_text_view_get_visible_rect (text_view, &visible_rect);
3824 redraw_rect.x = visible_rect.x;
3825 redraw_rect.width = visible_rect.width;
3826 redraw_rect.y = start_y;
3828 if (old_height == new_height)
3829 redraw_rect.height = old_height;
3830 else if (start_y + old_height > visible_rect.y)
3831 redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
3833 redraw_rect.height = 0;
3835 if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
3837 /* text_window_invalidate_rect() takes buffer coordinates */
3838 text_window_invalidate_rect (priv->text_window,
3841 DV(g_print(" invalidated rect: %d,%d %d x %d\n",
3845 redraw_rect.height));
3847 if (priv->left_window)
3848 text_window_invalidate_rect (priv->left_window,
3850 if (priv->right_window)
3851 text_window_invalidate_rect (priv->right_window,
3853 if (priv->top_window)
3854 text_window_invalidate_rect (priv->top_window,
3856 if (priv->bottom_window)
3857 text_window_invalidate_rect (priv->bottom_window,
3860 queue_update_im_spot_location (text_view);
3864 if (old_height != new_height)
3866 gboolean yoffset_changed = FALSE;
3868 int new_first_para_top;
3869 int old_first_para_top;
3872 /* If the bottom of the old area was above the top of the
3873 * screen, we need to scroll to keep the current top of the
3874 * screen in place. Remember that first_para_pixels is the
3875 * position of the top of the screen in coordinates relative to
3876 * the first paragraph onscreen.
3878 * In short we are adding the height delta of the portion of the
3879 * changed region above first_para_mark to priv->yoffset.
3881 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &first,
3882 priv->first_para_mark);
3884 gtk_text_layout_get_line_yrange (layout, &first, &new_first_para_top, NULL);
3886 old_first_para_top = priv->yoffset - priv->first_para_pixels;
3888 if (new_first_para_top != old_first_para_top)
3890 priv->yoffset += new_first_para_top - old_first_para_top;
3892 text_view->priv->vadjustment->value = priv->yoffset;
3893 yoffset_changed = TRUE;
3896 if (yoffset_changed)
3898 DV(g_print ("Changing scroll position (%s)\n", G_STRLOC));
3899 gtk_adjustment_value_changed (text_view->priv->vadjustment);
3902 /* FIXME be smarter about which anchored widgets we update */
3904 tmp_list = priv->children;
3905 while (tmp_list != NULL)
3907 GtkTextViewChild *child = tmp_list->data;
3910 gtk_text_view_update_child_allocation (text_view, child);
3912 tmp_list = g_slist_next (tmp_list);
3917 GtkRequisition old_req = priv->cached_size_request;
3918 GtkRequisition new_req;
3920 /* Use this instead of gtk_widget_size_request wrapper
3921 * to avoid the optimization which just returns widget->requisition
3922 * if a resize hasn't been queued.
3924 gtk_text_view_size_request (widget, &new_req);
3926 if (old_req.width != new_req.width ||
3927 old_req.height != new_req.height)
3929 gtk_widget_queue_resize_no_redraw (widget);
3935 gtk_text_view_realize (GtkWidget *widget)
3937 GtkAllocation allocation;
3938 GtkTextView *text_view;
3939 GtkTextViewPrivate *priv;
3941 GdkWindowAttr attributes;
3942 gint attributes_mask;
3945 text_view = GTK_TEXT_VIEW (widget);
3946 priv = text_view->priv;
3948 gtk_widget_set_realized (widget, TRUE);
3950 gtk_widget_get_allocation (widget, &allocation);
3952 attributes.window_type = GDK_WINDOW_CHILD;
3953 attributes.x = allocation.x;
3954 attributes.y = allocation.y;
3955 attributes.width = allocation.width;
3956 attributes.height = allocation.height;
3957 attributes.wclass = GDK_INPUT_OUTPUT;
3958 attributes.visual = gtk_widget_get_visual (widget);
3959 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
3961 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3963 window = gdk_window_new (gtk_widget_get_parent_window (widget),
3964 &attributes, attributes_mask);
3965 gtk_widget_set_window (widget, window);
3966 gdk_window_set_user_data (window, widget);
3968 /* must come before text_window_realize calls */
3969 gtk_widget_style_attach (widget);
3971 gdk_window_set_background (window,
3972 >k_widget_get_style (widget)->bg[gtk_widget_get_state (widget)]);
3974 text_window_realize (priv->text_window, widget);
3976 if (priv->left_window)
3977 text_window_realize (priv->left_window, widget);
3979 if (priv->top_window)
3980 text_window_realize (priv->top_window, widget);
3982 if (priv->right_window)
3983 text_window_realize (priv->right_window, widget);
3985 if (priv->bottom_window)
3986 text_window_realize (priv->bottom_window, widget);
3988 gtk_text_view_ensure_layout (text_view);
3992 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
3993 GDK_SELECTION_PRIMARY);
3994 gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
3997 tmp_list = priv->children;
3998 while (tmp_list != NULL)
4000 GtkTextViewChild *vc = tmp_list->data;
4002 text_view_child_set_parent_window (text_view, vc);
4004 tmp_list = tmp_list->next;
4007 /* Ensure updating the spot location. */
4008 gtk_text_view_update_im_spot_location (text_view);
4012 gtk_text_view_unrealize (GtkWidget *widget)
4014 GtkTextView *text_view;
4015 GtkTextViewPrivate *priv;
4017 text_view = GTK_TEXT_VIEW (widget);
4018 priv = text_view->priv;
4022 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
4023 GDK_SELECTION_PRIMARY);
4024 gtk_text_buffer_remove_selection_clipboard (priv->buffer, clipboard);
4027 gtk_text_view_remove_validate_idles (text_view);
4029 if (priv->popup_menu)
4031 gtk_widget_destroy (priv->popup_menu);
4032 priv->popup_menu = NULL;
4035 text_window_unrealize (priv->text_window);
4037 if (priv->left_window)
4038 text_window_unrealize (priv->left_window);
4040 if (priv->top_window)
4041 text_window_unrealize (priv->top_window);
4043 if (priv->right_window)
4044 text_window_unrealize (priv->right_window);
4046 if (priv->bottom_window)
4047 text_window_unrealize (priv->bottom_window);
4049 gtk_text_view_destroy_layout (text_view);
4051 GTK_WIDGET_CLASS (gtk_text_view_parent_class)->unrealize (widget);
4055 gtk_text_view_set_background (GtkTextView *text_view)
4060 GtkTextViewPrivate *priv;
4062 widget = GTK_WIDGET (text_view);
4063 priv = text_view->priv;
4065 style = gtk_widget_get_style (widget);
4066 state = gtk_widget_get_state (widget);
4068 gdk_window_set_background (gtk_widget_get_window (widget),
4071 gdk_window_set_background (priv->text_window->bin_window,
4072 &style->base[state]);
4074 if (priv->left_window)
4075 gdk_window_set_background (priv->left_window->bin_window,
4077 if (priv->right_window)
4078 gdk_window_set_background (priv->right_window->bin_window,
4081 if (priv->top_window)
4082 gdk_window_set_background (priv->top_window->bin_window,
4085 if (priv->bottom_window)
4086 gdk_window_set_background (priv->bottom_window->bin_window,
4091 gtk_text_view_style_set (GtkWidget *widget,
4092 GtkStyle *previous_style)
4094 GtkTextView *text_view;
4095 GtkTextViewPrivate *priv;
4096 PangoContext *ltr_context, *rtl_context;
4098 text_view = GTK_TEXT_VIEW (widget);
4099 priv = text_view->priv;
4101 if (gtk_widget_get_realized (widget))
4103 gtk_text_view_set_background (text_view);
4106 if (priv->layout && previous_style)
4108 gtk_text_view_set_attributes_from_style (text_view,
4109 priv->layout->default_style,
4110 gtk_widget_get_style (widget));
4112 ltr_context = gtk_widget_create_pango_context (widget);
4113 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
4114 rtl_context = gtk_widget_create_pango_context (widget);
4115 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
4117 gtk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
4119 g_object_unref (ltr_context);
4120 g_object_unref (rtl_context);
4125 gtk_text_view_direction_changed (GtkWidget *widget,
4126 GtkTextDirection previous_direction)
4128 GtkTextViewPrivate *priv = GTK_TEXT_VIEW (widget)->priv;
4132 priv->layout->default_style->direction = gtk_widget_get_direction (widget);
4134 gtk_text_layout_default_style_changed (priv->layout);
4139 gtk_text_view_state_changed (GtkWidget *widget,
4140 GtkStateType previous_state)
4142 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
4145 if (gtk_widget_get_realized (widget))
4147 gtk_text_view_set_background (text_view);
4149 if (gtk_widget_is_sensitive (widget))
4150 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
4154 gdk_window_set_cursor (text_view->priv->text_window->bin_window, cursor);
4157 gdk_cursor_unref (cursor);
4159 text_view->priv->mouse_cursor_obscured = FALSE;
4162 if (!gtk_widget_is_sensitive (widget))
4164 /* Clear any selection */
4165 gtk_text_view_unselect (text_view);
4168 gtk_widget_queue_draw (widget);
4172 set_invisible_cursor (GdkWindow *window)
4174 GdkDisplay *display;
4177 display = gdk_window_get_display (window);
4178 cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
4180 gdk_window_set_cursor (window, cursor);
4182 gdk_cursor_unref (cursor);
4186 gtk_text_view_obscure_mouse_cursor (GtkTextView *text_view)
4188 if (text_view->priv->mouse_cursor_obscured)
4191 set_invisible_cursor (text_view->priv->text_window->bin_window);
4193 text_view->priv->mouse_cursor_obscured = TRUE;
4197 gtk_text_view_unobscure_mouse_cursor (GtkTextView *text_view)
4199 if (text_view->priv->mouse_cursor_obscured)
4203 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)),
4205 gdk_window_set_cursor (text_view->priv->text_window->bin_window, cursor);
4206 gdk_cursor_unref (cursor);
4207 text_view->priv->mouse_cursor_obscured = FALSE;
4212 gtk_text_view_grab_notify (GtkWidget *widget,
4213 gboolean was_grabbed)
4215 GtkTextViewPrivate *priv;
4217 priv = GTK_TEXT_VIEW (widget)->priv;
4219 if (priv->grab_device &&
4220 gtk_widget_device_is_shadowed (widget, priv->grab_device))
4222 gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
4223 gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
4233 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
4236 switch (event->type)
4238 case GDK_MOTION_NOTIFY:
4239 *x = event->motion.x;
4240 *y = event->motion.y;
4244 case GDK_BUTTON_PRESS:
4245 case GDK_2BUTTON_PRESS:
4246 case GDK_3BUTTON_PRESS:
4247 case GDK_BUTTON_RELEASE:
4248 *x = event->button.x;
4249 *y = event->button.y;
4254 case GDK_KEY_RELEASE:
4255 case GDK_ENTER_NOTIFY:
4256 case GDK_LEAVE_NOTIFY:
4257 case GDK_PROPERTY_NOTIFY:
4258 case GDK_SELECTION_CLEAR:
4259 case GDK_SELECTION_REQUEST:
4260 case GDK_SELECTION_NOTIFY:
4261 case GDK_PROXIMITY_IN:
4262 case GDK_PROXIMITY_OUT:
4263 case GDK_DRAG_ENTER:
4264 case GDK_DRAG_LEAVE:
4265 case GDK_DRAG_MOTION:
4266 case GDK_DRAG_STATUS:
4267 case GDK_DROP_START:
4268 case GDK_DROP_FINISHED:
4278 emit_event_on_tags (GtkWidget *widget,
4284 gboolean retval = FALSE;
4286 tags = gtk_text_iter_get_tags (iter);
4291 GtkTextTag *tag = tmp->data;
4293 if (gtk_text_tag_event (tag, G_OBJECT (widget), event, iter))
4299 tmp = g_slist_next (tmp);
4302 g_slist_free (tags);
4308 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
4310 GtkTextView *text_view;
4311 GtkTextViewPrivate *priv;
4314 text_view = GTK_TEXT_VIEW (widget);
4315 priv = text_view->priv;
4317 if (priv->layout == NULL ||
4318 get_buffer (text_view) == NULL)
4321 if (event->any.window != priv->text_window->bin_window)
4324 if (get_event_coordinates (event, &x, &y))
4331 /* FIXME this is slow and we do it twice per event.
4332 * My favorite solution is to have GtkTextLayout cache
4333 * the last couple lookups.
4335 gtk_text_layout_get_iter_at_pixel (priv->layout,
4339 return emit_event_on_tags (widget, event, &iter);
4341 else if (event->type == GDK_KEY_PRESS ||
4342 event->type == GDK_KEY_RELEASE)
4346 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
4347 gtk_text_buffer_get_insert (get_buffer (text_view)));
4349 return emit_event_on_tags (widget, event, &iter);
4356 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
4358 GtkTextView *text_view;
4359 GtkTextViewPrivate *priv;
4360 GtkTextMark *insert;
4362 gboolean can_insert;
4363 gboolean retval = FALSE;
4364 gboolean obscure = FALSE;
4366 text_view = GTK_TEXT_VIEW (widget);
4367 priv = text_view->priv;
4369 if (priv->layout == NULL ||
4370 get_buffer (text_view) == NULL)
4373 /* Make sure input method knows where it is */
4374 flush_update_im_spot_location (text_view);
4376 insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4377 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4378 can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
4379 if (gtk_im_context_filter_keypress (priv->im_context, event))
4381 priv->need_im_reset = TRUE;
4383 gtk_text_view_reset_im_context (text_view);
4384 obscure = can_insert;
4388 else if (GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event (widget, event))
4392 /* use overall editability not can_insert, more predictable for users */
4393 else if (priv->editable &&
4394 (event->keyval == GDK_KEY_Return ||
4395 event->keyval == GDK_KEY_ISO_Enter ||
4396 event->keyval == GDK_KEY_KP_Enter))
4398 /* this won't actually insert the newline if the cursor isn't
4401 gtk_text_view_reset_im_context (text_view);
4402 gtk_text_view_commit_text (text_view, "\n");
4407 /* Pass through Tab as literal tab, unless Control is held down */
4408 else if ((event->keyval == GDK_KEY_Tab ||
4409 event->keyval == GDK_KEY_KP_Tab ||
4410 event->keyval == GDK_KEY_ISO_Left_Tab) &&
4411 !(event->state & GDK_CONTROL_MASK))
4413 /* If the text widget isn't editable overall, or if the application
4414 * has turned off "accepts_tab", move the focus instead
4416 if (priv->accepts_tab && priv->editable)
4418 gtk_text_view_reset_im_context (text_view);
4419 gtk_text_view_commit_text (text_view, "\t");
4423 g_signal_emit_by_name (text_view, "move-focus",
4424 (event->state & GDK_SHIFT_MASK) ?
4425 GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
4433 gtk_text_view_obscure_mouse_cursor (text_view);
4435 gtk_text_view_reset_blink_time (text_view);
4436 gtk_text_view_pend_cursor_blink (text_view);
4442 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
4444 GtkTextView *text_view;
4445 GtkTextViewPrivate *priv;
4446 GtkTextMark *insert;
4449 text_view = GTK_TEXT_VIEW (widget);
4450 priv = text_view->priv;
4452 if (priv->layout == NULL || get_buffer (text_view) == NULL)
4455 insert = gtk_text_buffer_get_insert (get_buffer (text_view));
4456 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
4457 if (gtk_text_iter_can_insert (&iter, priv->editable) &&
4458 gtk_im_context_filter_keypress (priv->im_context, event))
4460 priv->need_im_reset = TRUE;
4464 return GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_release_event (widget, event);
4468 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
4470 GtkTextView *text_view;
4471 GtkTextViewPrivate *priv;
4473 text_view = GTK_TEXT_VIEW (widget);
4474 priv = text_view->priv;
4476 gtk_widget_grab_focus (widget);
4478 if (event->window != priv->text_window->bin_window)
4480 /* Remove selection if any. */
4481 gtk_text_view_unselect (text_view);
4485 gtk_text_view_reset_blink_time (text_view);
4489 if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
4490 _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
4491 else if (event->button == 3)
4492 gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
4495 if (event->type == GDK_BUTTON_PRESS)
4497 gtk_text_view_reset_im_context (text_view);
4499 if (event->button == 1)
4501 /* If we're in the selection, start a drag copy/move of the
4502 * selection; otherwise, start creating a new selection.
4505 GtkTextIter start, end;
4507 gtk_text_layout_get_iter_at_pixel (priv->layout,
4509 event->x + priv->xoffset,
4510 event->y + priv->yoffset);
4512 if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
4514 gtk_text_iter_in_range (&iter, &start, &end) &&
4515 !(event->state & GDK_SHIFT_MASK))
4517 priv->drag_start_x = event->x;
4518 priv->drag_start_y = event->y;
4519 priv->pending_place_cursor_button = event->button;
4523 gtk_text_view_start_selection_drag (text_view, &iter, event);
4528 else if (event->button == 2)
4532 /* We do not want to scroll back to the insert iter when we paste
4533 with the middle button */
4534 priv->scroll_after_paste = FALSE;
4536 gtk_text_layout_get_iter_at_pixel (priv->layout,
4538 event->x + priv->xoffset,
4539 event->y + priv->yoffset);
4541 gtk_text_buffer_paste_clipboard (get_buffer (text_view),
4542 gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY),
4547 else if (event->button == 3)
4549 gtk_text_view_do_popup (text_view, event);
4553 else if ((event->type == GDK_2BUTTON_PRESS ||
4554 event->type == GDK_3BUTTON_PRESS) &&
4559 gtk_text_view_end_selection_drag (text_view);
4561 gtk_text_layout_get_iter_at_pixel (priv->layout,
4563 event->x + priv->xoffset,
4564 event->y + priv->yoffset);
4566 gtk_text_view_start_selection_drag (text_view, &iter, event);
4574 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
4576 GtkTextView *text_view;
4577 GtkTextViewPrivate *priv;
4579 text_view = GTK_TEXT_VIEW (widget);
4580 priv = text_view->priv;
4582 if (event->window != priv->text_window->bin_window)
4585 if (event->button == 1)
4587 if (priv->drag_start_x >= 0)
4589 priv->drag_start_x = -1;
4590 priv->drag_start_y = -1;
4593 if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget)))
4595 else if (priv->pending_place_cursor_button == event->button)
4599 /* Unselect everything; we clicked inside selection, but
4600 * didn't move by the drag threshold, so just clear selection
4603 gtk_text_layout_get_iter_at_pixel (priv->layout,
4605 event->x + priv->xoffset,
4606 event->y + priv->yoffset);
4608 gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
4609 gtk_text_view_check_cursor_blink (text_view);
4611 priv->pending_place_cursor_button = 0;
4621 keymap_direction_changed (GdkKeymap *keymap,
4622 GtkTextView *text_view)
4624 gtk_text_view_check_keymap_direction (text_view);
4628 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
4630 GtkTextView *text_view;
4631 GtkTextViewPrivate *priv;
4633 text_view = GTK_TEXT_VIEW (widget);
4634 priv = text_view->priv;
4636 gtk_widget_queue_draw (widget);
4638 DV(g_print (G_STRLOC": focus_in_event\n"));
4640 gtk_text_view_reset_blink_time (text_view);
4642 if (priv->cursor_visible && priv->layout)
4644 gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
4645 gtk_text_view_check_cursor_blink (text_view);
4648 g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4649 "direction-changed",
4650 G_CALLBACK (keymap_direction_changed), text_view);
4651 gtk_text_view_check_keymap_direction (text_view);
4655 priv->need_im_reset = TRUE;
4656 gtk_im_context_focus_in (priv->im_context);
4663 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
4665 GtkTextView *text_view;
4666 GtkTextViewPrivate *priv;
4668 text_view = GTK_TEXT_VIEW (widget);
4669 priv = text_view->priv;
4671 gtk_text_view_end_selection_drag (text_view);
4673 gtk_widget_queue_draw (widget);
4675 DV(g_print (G_STRLOC": focus_out_event\n"));
4677 if (priv->cursor_visible && priv->layout)
4679 gtk_text_view_check_cursor_blink (text_view);
4680 gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
4683 g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
4684 keymap_direction_changed,
4689 priv->need_im_reset = TRUE;
4690 gtk_im_context_focus_out (priv->im_context);
4697 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
4699 GtkTextView *text_view;
4700 GtkTextViewPrivate *priv;
4702 text_view = GTK_TEXT_VIEW (widget);
4703 priv = text_view->priv;
4705 gtk_text_view_unobscure_mouse_cursor (text_view);
4707 if (event->window == priv->text_window->bin_window &&
4708 priv->drag_start_x >= 0)
4713 gdk_event_request_motions (event);
4715 if (gtk_drag_check_threshold (widget,
4721 gint buffer_x, buffer_y;
4723 gtk_text_view_window_to_buffer_coords (text_view,
4724 GTK_TEXT_WINDOW_TEXT,
4730 gtk_text_layout_get_iter_at_pixel (priv->layout,
4732 buffer_x, buffer_y);
4734 gtk_text_view_start_selection_dnd (text_view, &iter, event);
4743 gtk_text_view_paint (GtkWidget *widget,
4746 GtkTextView *text_view;
4747 GtkTextViewPrivate *priv;
4748 GList *child_exposes;
4751 text_view = GTK_TEXT_VIEW (widget);
4752 priv = text_view->priv;
4754 g_return_if_fail (priv->layout != NULL);
4755 g_return_if_fail (priv->xoffset >= 0);
4756 g_return_if_fail (priv->yoffset >= 0);
4758 while (priv->first_validate_idle != 0)
4760 DV (g_print (G_STRLOC": first_validate_idle: %d\n",
4761 priv->first_validate_idle));
4762 gtk_text_view_flush_first_validate (text_view);
4765 if (!priv->onscreen_validated)
4767 g_warning (G_STRLOC ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen - may be a text widget bug.");
4768 g_assert_not_reached ();
4772 printf ("painting %d,%d %d x %d\n",
4774 area->width, area->height);
4777 child_exposes = NULL;
4780 cairo_translate (cr, -priv->xoffset, -priv->yoffset);
4782 gtk_text_layout_draw (priv->layout,
4789 tmp_list = child_exposes;
4790 while (tmp_list != NULL)
4792 GtkWidget *child = tmp_list->data;
4794 gtk_container_propagate_draw (GTK_CONTAINER (text_view),
4798 g_object_unref (child);
4800 tmp_list = tmp_list->next;
4803 g_list_free (child_exposes);
4807 gtk_text_view_draw (GtkWidget *widget,
4813 if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
4814 gtk_text_view_draw_focus (widget, cr);
4816 window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
4817 GTK_TEXT_WINDOW_TEXT);
4818 if (gtk_cairo_should_draw_window (cr, window))
4820 DV(g_print (">Exposed ("G_STRLOC")\n"));
4822 gtk_cairo_transform_to_window (cr, widget, window);
4823 gtk_text_view_paint (widget, cr);
4827 /* Propagate exposes to all unanchored children.
4828 * Anchored children are handled in gtk_text_view_paint().
4830 tmp_list = GTK_TEXT_VIEW (widget)->priv->children;
4831 while (tmp_list != NULL)
4833 GtkTextViewChild *vc = tmp_list->data;
4835 /* propagate_draw checks that event->window matches
4839 gtk_container_propagate_draw (GTK_CONTAINER (widget),
4843 tmp_list = tmp_list->next;
4850 gtk_text_view_draw_focus (GtkWidget *widget,
4853 gboolean interior_focus;
4855 /* We clear the focus if we are in interior focus mode. */
4856 gtk_widget_style_get (widget,
4857 "interior-focus", &interior_focus,
4860 if (gtk_widget_has_focus (widget) && !interior_focus)
4862 gtk_paint_focus (gtk_widget_get_style (widget), cr,
4863 gtk_widget_get_state (widget),
4866 gtk_widget_get_allocated_width (widget),
4867 gtk_widget_get_allocated_height (widget));
4872 gtk_text_view_focus (GtkWidget *widget,
4873 GtkDirectionType direction)
4875 GtkContainer *container;
4878 container = GTK_CONTAINER (widget);
4880 if (!gtk_widget_is_focus (widget) &&
4881 gtk_container_get_focus_child (container) == NULL)
4883 gtk_widget_grab_focus (widget);
4889 * Unset CAN_FOCUS flag so that gtk_container_focus() allows
4890 * children to get the focus
4892 gtk_widget_set_can_focus (widget, FALSE);
4893 result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
4894 gtk_widget_set_can_focus (widget, TRUE);
4905 gtk_text_view_add (GtkContainer *container,
4908 /* This is pretty random. */
4909 gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
4911 GTK_TEXT_WINDOW_WIDGET,
4916 gtk_text_view_remove (GtkContainer *container,
4919 GtkTextView *text_view;
4920 GtkTextViewPrivate *priv;
4921 GtkTextViewChild *vc;
4924 text_view = GTK_TEXT_VIEW (container);
4925 priv = text_view->priv;
4928 iter = priv->children;
4930 while (iter != NULL)
4934 if (vc->widget == child)
4937 iter = g_slist_next (iter);
4940 g_assert (iter != NULL); /* be sure we had the child in the list */
4942 priv->children = g_slist_remove (priv->children, vc);
4944 gtk_widget_unparent (vc->widget);
4946 text_view_child_free (vc);
4950 gtk_text_view_forall (GtkContainer *container,
4951 gboolean include_internals,
4952 GtkCallback callback,
4953 gpointer callback_data)
4956 GtkTextView *text_view;
4959 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
4960 g_return_if_fail (callback != NULL);
4962 text_view = GTK_TEXT_VIEW (container);
4964 copy = g_slist_copy (text_view->priv->children);
4967 while (iter != NULL)
4969 GtkTextViewChild *vc = iter->data;
4971 (* callback) (vc->widget, callback_data);
4973 iter = g_slist_next (iter);
4976 g_slist_free (copy);
4979 #define CURSOR_ON_MULTIPLIER 2
4980 #define CURSOR_OFF_MULTIPLIER 1
4981 #define CURSOR_PEND_MULTIPLIER 3
4982 #define CURSOR_DIVIDER 3
4985 cursor_blinks (GtkTextView *text_view)
4987 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
4990 #ifdef DEBUG_VALIDATION_AND_SCROLLING
4993 if (gtk_get_debug_flags () & GTK_DEBUG_UPDATES)
4996 g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
5001 if (text_view->priv->editable)
5003 GtkTextMark *insert;
5006 insert = gtk_text_buffer_get_insert (get_buffer (text_view));
5007 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
5009 if (gtk_text_iter_editable (&iter, text_view->priv->editable))
5017 get_cursor_time (GtkTextView *text_view)
5019 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
5022 g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
5028 get_cursor_blink_timeout (GtkTextView *text_view)
5030 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
5033 g_object_get (settings, "gtk-cursor-blink-timeout", &time, NULL);
5044 blink_cb (gpointer data)
5046 GtkTextView *text_view;
5047 GtkTextViewPrivate *priv;
5051 text_view = GTK_TEXT_VIEW (data);
5052 priv = text_view->priv;
5054 if (!gtk_widget_has_focus (GTK_WIDGET (text_view)))
5056 g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
5057 "connect a handler to this signal, it must return\n"
5058 "FALSE so the text view gets the event as well");
5060 gtk_text_view_check_cursor_blink (text_view);
5065 g_assert (priv->layout);
5066 g_assert (priv->cursor_visible);
5068 visible = gtk_text_layout_get_cursor_visible (priv->layout);
5070 blink_timeout = get_cursor_blink_timeout (text_view);
5071 if (priv->blink_time > 1000 * blink_timeout &&
5072 blink_timeout < G_MAXINT/1000)
5074 /* we've blinked enough without the user doing anything, stop blinking */
5076 priv->blink_timeout = 0;
5079 priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
5084 priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
5087 priv->blink_time += get_cursor_time (text_view);
5090 /* Block changed_handler while changing the layout's cursor visibility
5091 * because it would expose the whole paragraph. Instead, we expose
5092 * the cursor's area(s) manually below.
5094 g_signal_handlers_block_by_func (priv->layout,
5097 gtk_text_layout_set_cursor_visible (priv->layout, !visible);
5098 g_signal_handlers_unblock_by_func (priv->layout,
5102 text_window_invalidate_cursors (priv->text_window);
5104 /* Remove ourselves */
5110 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
5112 if (text_view->priv->blink_timeout)
5114 g_source_remove (text_view->priv->blink_timeout);
5115 text_view->priv->blink_timeout = 0;
5120 gtk_text_view_check_cursor_blink (GtkTextView *text_view)
5122 GtkTextViewPrivate *priv = text_view->priv;
5124 if (priv->layout != NULL &&
5125 priv->cursor_visible &&
5126 gtk_widget_has_focus (GTK_WIDGET (text_view)))
5128 if (cursor_blinks (text_view))
5130 if (priv->blink_timeout == 0)
5132 gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
5134 priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
5141 gtk_text_view_stop_cursor_blink (text_view);
5142 gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
5147 gtk_text_view_stop_cursor_blink (text_view);
5148 gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
5153 gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
5155 GtkTextViewPrivate *priv = text_view->priv;
5157 if (priv->layout != NULL &&
5158 priv->cursor_visible &&
5159 gtk_widget_has_focus (GTK_WIDGET (text_view)) &&
5160 cursor_blinks (text_view))
5162 gtk_text_view_stop_cursor_blink (text_view);
5163 gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
5165 priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
5172 gtk_text_view_reset_blink_time (GtkTextView *text_view)
5174 GtkTextViewPrivate *priv = text_view->priv;
5176 priv->blink_time = 0;
5181 * Key binding handlers
5185 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
5186 GtkTextIter *newplace,
5189 gboolean ret = TRUE;
5193 ret = gtk_text_layout_move_iter_to_previous_line (text_view->priv->layout, newplace);
5199 ret = gtk_text_layout_move_iter_to_next_line (text_view->priv->layout, newplace);
5207 move_cursor (GtkTextView *text_view,
5208 const GtkTextIter *new_location,
5209 gboolean extend_selection)
5211 if (extend_selection)
5212 gtk_text_buffer_move_mark_by_name (get_buffer (text_view),
5216 gtk_text_buffer_place_cursor (get_buffer (text_view),
5218 gtk_text_view_check_cursor_blink (text_view);
5222 gtk_text_view_move_cursor_internal (GtkTextView *text_view,
5223 GtkMovementStep step,
5225 gboolean extend_selection)
5227 GtkTextViewPrivate *priv;
5229 GtkTextIter newplace;
5230 gboolean cancel_selection = FALSE;
5231 gint cursor_x_pos = 0;
5232 GtkDirectionType leave_direction = -1;
5234 priv = text_view->priv;
5236 if (!priv->cursor_visible)
5238 GtkScrollStep scroll_step;
5242 case GTK_MOVEMENT_VISUAL_POSITIONS:
5243 leave_direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
5245 case GTK_MOVEMENT_LOGICAL_POSITIONS:
5246 case GTK_MOVEMENT_WORDS:
5247 scroll_step = GTK_SCROLL_HORIZONTAL_STEPS;
5249 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5250 scroll_step = GTK_SCROLL_HORIZONTAL_ENDS;
5252 case GTK_MOVEMENT_DISPLAY_LINES:
5253 leave_direction = count > 0 ? GTK_DIR_DOWN : GTK_DIR_UP;
5255 case GTK_MOVEMENT_PARAGRAPHS:
5256 case GTK_MOVEMENT_PARAGRAPH_ENDS:
5257 scroll_step = GTK_SCROLL_STEPS;
5259 case GTK_MOVEMENT_PAGES:
5260 scroll_step = GTK_SCROLL_PAGES;
5262 case GTK_MOVEMENT_HORIZONTAL_PAGES:
5263 scroll_step = GTK_SCROLL_HORIZONTAL_PAGES;
5265 case GTK_MOVEMENT_BUFFER_ENDS:
5266 scroll_step = GTK_SCROLL_ENDS;
5269 scroll_step = GTK_SCROLL_PAGES;
5273 if (!gtk_text_view_move_viewport (text_view, scroll_step, count))
5275 if (leave_direction != -1 &&
5276 !gtk_widget_keynav_failed (GTK_WIDGET (text_view),
5279 g_signal_emit_by_name (text_view, "move-focus", leave_direction);
5286 gtk_text_view_reset_im_context (text_view);
5288 if (step == GTK_MOVEMENT_PAGES)
5290 if (!gtk_text_view_scroll_pages (text_view, count, extend_selection))
5291 gtk_widget_error_bell (GTK_WIDGET (text_view));
5293 gtk_text_view_check_cursor_blink (text_view);
5294 gtk_text_view_pend_cursor_blink (text_view);
5297 else if (step == GTK_MOVEMENT_HORIZONTAL_PAGES)
5299 if (!gtk_text_view_scroll_hpages (text_view, count, extend_selection))
5300 gtk_widget_error_bell (GTK_WIDGET (text_view));
5302 gtk_text_view_check_cursor_blink (text_view);
5303 gtk_text_view_pend_cursor_blink (text_view);
5307 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5308 gtk_text_buffer_get_insert (get_buffer (text_view)));
5310 if (! extend_selection)
5312 GtkTextIter sel_bound;
5314 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &sel_bound,
5315 gtk_text_buffer_get_selection_bound (get_buffer (text_view)));
5317 /* if we move forward, assume the cursor is at the end of the selection;
5318 * if we move backward, assume the cursor is at the start
5321 gtk_text_iter_order (&sel_bound, &insert);
5323 gtk_text_iter_order (&insert, &sel_bound);
5325 /* if we actually have a selection, just move *to* the beginning/end
5326 * of the selection and not *from* there on LOGICAL_POSITIONS
5327 * and VISUAL_POSITIONS movement
5329 if (! gtk_text_iter_equal (&sel_bound, &insert))
5330 cancel_selection = TRUE;
5335 if (step == GTK_MOVEMENT_DISPLAY_LINES)
5336 gtk_text_view_get_virtual_cursor_pos (text_view, &insert, &cursor_x_pos, NULL);
5340 case GTK_MOVEMENT_LOGICAL_POSITIONS:
5341 if (! cancel_selection)
5342 gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
5345 case GTK_MOVEMENT_VISUAL_POSITIONS:
5346 if (! cancel_selection)
5347 gtk_text_layout_move_iter_visually (priv->layout,
5351 case GTK_MOVEMENT_WORDS:
5353 gtk_text_iter_backward_visible_word_starts (&newplace, -count);
5356 if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
5357 gtk_text_iter_forward_to_line_end (&newplace);
5361 case GTK_MOVEMENT_DISPLAY_LINES:
5364 leave_direction = GTK_DIR_UP;
5366 if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
5367 gtk_text_layout_move_iter_to_x (priv->layout, &newplace, cursor_x_pos);
5369 gtk_text_iter_set_line_offset (&newplace, 0);
5373 leave_direction = GTK_DIR_DOWN;
5375 if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
5376 gtk_text_layout_move_iter_to_x (priv->layout, &newplace, cursor_x_pos);
5378 gtk_text_iter_forward_to_line_end (&newplace);
5382 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
5384 gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
5385 else if (count < -1)
5386 gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
5389 gtk_text_layout_move_iter_to_line_end (priv->layout, &newplace, count);
5392 case GTK_MOVEMENT_PARAGRAPHS:
5395 if (!gtk_text_iter_ends_line (&newplace))
5397 gtk_text_iter_forward_to_line_end (&newplace);
5400 gtk_text_iter_forward_visible_lines (&newplace, count);
5401 gtk_text_iter_forward_to_line_end (&newplace);
5405 if (gtk_text_iter_get_line_offset (&newplace) > 0)
5406 gtk_text_iter_set_line_offset (&newplace, 0);
5407 gtk_text_iter_forward_visible_lines (&newplace, count);
5408 gtk_text_iter_set_line_offset (&newplace, 0);
5412 case GTK_MOVEMENT_PARAGRAPH_ENDS:
5415 if (!gtk_text_iter_ends_line (&newplace))
5416 gtk_text_iter_forward_to_line_end (&newplace);
5420 gtk_text_iter_set_line_offset (&newplace, 0);
5424 case GTK_MOVEMENT_BUFFER_ENDS:
5426 gtk_text_buffer_get_end_iter (get_buffer (text_view), &newplace);
5428 gtk_text_buffer_get_iter_at_offset (get_buffer (text_view), &newplace, 0);
5435 /* call move_cursor() even if the cursor hasn't moved, since it
5436 cancels the selection
5438 move_cursor (text_view, &newplace, extend_selection);
5440 if (!gtk_text_iter_equal (&insert, &newplace))
5442 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5443 gtk_text_view_scroll_mark_onscreen (text_view,
5444 gtk_text_buffer_get_insert (get_buffer (text_view)));
5446 if (step == GTK_MOVEMENT_DISPLAY_LINES)
5447 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
5449 else if (leave_direction != -1)
5451 if (!gtk_widget_keynav_failed (GTK_WIDGET (text_view),
5454 g_signal_emit_by_name (text_view, "move-focus", leave_direction);
5457 else if (! cancel_selection)
5459 gtk_widget_error_bell (GTK_WIDGET (text_view));
5462 gtk_text_view_check_cursor_blink (text_view);
5463 gtk_text_view_pend_cursor_blink (text_view);
5467 gtk_text_view_move_cursor (GtkTextView *text_view,
5468 GtkMovementStep step,
5470 gboolean extend_selection)
5472 gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
5476 gtk_text_view_move_viewport (GtkTextView *text_view,
5480 GtkAdjustment *adjustment;
5485 case GTK_SCROLL_STEPS:
5486 case GTK_SCROLL_PAGES:
5487 case GTK_SCROLL_ENDS:
5488 adjustment = text_view->priv->vadjustment;
5490 case GTK_SCROLL_HORIZONTAL_STEPS:
5491 case GTK_SCROLL_HORIZONTAL_PAGES:
5492 case GTK_SCROLL_HORIZONTAL_ENDS:
5493 adjustment = text_view->priv->hadjustment;
5496 adjustment = text_view->priv->vadjustment;
5502 case GTK_SCROLL_STEPS:
5503 case GTK_SCROLL_HORIZONTAL_STEPS:
5504 increment = adjustment->step_increment;
5506 case GTK_SCROLL_PAGES:
5507 case GTK_SCROLL_HORIZONTAL_PAGES:
5508 increment = adjustment->page_increment;
5510 case GTK_SCROLL_ENDS:
5511 case GTK_SCROLL_HORIZONTAL_ENDS:
5512 increment = adjustment->upper - adjustment->lower;
5519 return set_adjustment_clamped (adjustment, adjustment->value + count * increment);
5523 gtk_text_view_set_anchor (GtkTextView *text_view)
5527 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5528 gtk_text_buffer_get_insert (get_buffer (text_view)));
5530 gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
5534 gtk_text_view_scroll_pages (GtkTextView *text_view,
5536 gboolean extend_selection)
5538 GtkTextViewPrivate *priv;
5540 gint cursor_x_pos, cursor_y_pos;
5541 GtkTextMark *insert_mark;
5542 GtkTextIter old_insert;
5543 GtkTextIter new_insert;
5549 priv = text_view->priv;
5551 g_return_val_if_fail (priv->vadjustment != NULL, FALSE);
5553 adj = priv->vadjustment;
5555 insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
5557 /* Make sure we start from the current cursor position, even
5558 * if it was offscreen, but don't queue more scrolls if we're
5561 if (priv->pending_scroll)
5562 cancel_pending_scroll (text_view);
5564 gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5566 /* Validate the region that will be brought into view by the cursor motion
5568 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5569 &old_insert, insert_mark);
5573 gtk_text_view_get_first_para_iter (text_view, &anchor);
5574 y0 = adj->page_size;
5575 y1 = adj->page_size + count * adj->page_increment;
5579 gtk_text_view_get_first_para_iter (text_view, &anchor);
5580 y0 = count * adj->page_increment + adj->page_size;
5584 gtk_text_layout_validate_yrange (priv->layout, &anchor, y0, y1);
5585 /* FIXME do we need to update the adjustment ranges here? */
5587 new_insert = old_insert;
5589 if (count < 0 && adj->value <= (adj->lower + 1e-12))
5591 /* already at top, just be sure we are at offset 0 */
5592 gtk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
5593 move_cursor (text_view, &new_insert, extend_selection);
5595 else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5597 /* already at bottom, just be sure we are at the end */
5598 gtk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
5599 move_cursor (text_view, &new_insert, extend_selection);
5603 gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
5605 oldval = adj->value;
5606 newval = adj->value;
5608 newval += count * adj->page_increment;
5610 set_adjustment_clamped (adj, newval);
5611 cursor_y_pos += adj->value - oldval;
5613 gtk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5614 clamp_iter_onscreen (text_view, &new_insert);
5615 move_cursor (text_view, &new_insert, extend_selection);
5617 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5620 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5621 * only guarantees 1 pixel onscreen.
5623 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5624 gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5626 return !gtk_text_iter_equal (&old_insert, &new_insert);
5630 gtk_text_view_scroll_hpages (GtkTextView *text_view,
5632 gboolean extend_selection)
5634 GtkTextViewPrivate *priv;
5636 gint cursor_x_pos, cursor_y_pos;
5637 GtkTextMark *insert_mark;
5638 GtkTextIter old_insert;
5639 GtkTextIter new_insert;
5644 priv = text_view->priv;
5646 g_return_val_if_fail (priv->hadjustment != NULL, FALSE);
5648 adj = priv->hadjustment;
5650 insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
5652 /* Make sure we start from the current cursor position, even
5653 * if it was offscreen, but don't queue more scrolls if we're
5656 if (priv->pending_scroll)
5657 cancel_pending_scroll (text_view);
5659 gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5661 /* Validate the line that we're moving within.
5663 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5664 &old_insert, insert_mark);
5666 gtk_text_layout_get_line_yrange (priv->layout, &old_insert, &y, &height);
5667 gtk_text_layout_validate_yrange (priv->layout, &old_insert, y, y + height);
5668 /* FIXME do we need to update the adjustment ranges here? */
5670 new_insert = old_insert;
5672 if (count < 0 && adj->value <= (adj->lower + 1e-12))
5674 /* already at far left, just be sure we are at offset 0 */
5675 gtk_text_iter_set_line_offset (&new_insert, 0);
5676 move_cursor (text_view, &new_insert, extend_selection);
5678 else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
5680 /* already at far right, just be sure we are at the end */
5681 if (!gtk_text_iter_ends_line (&new_insert))
5682 gtk_text_iter_forward_to_line_end (&new_insert);
5683 move_cursor (text_view, &new_insert, extend_selection);
5687 gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
5689 oldval = adj->value;
5690 newval = adj->value;
5692 newval += count * adj->page_increment;
5694 set_adjustment_clamped (adj, newval);
5695 cursor_x_pos += adj->value - oldval;
5697 gtk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
5698 clamp_iter_onscreen (text_view, &new_insert);
5699 move_cursor (text_view, &new_insert, extend_selection);
5701 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
5704 /* FIXME for lines shorter than the overall widget width, this results in a
5705 * "bounce" effect as we scroll to the right of the widget, then scroll
5706 * back to get the end of the line onscreen.
5707 * http://bugzilla.gnome.org/show_bug.cgi?id=68963
5710 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
5711 * only guarantees 1 pixel onscreen.
5713 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5714 gtk_text_view_scroll_mark_onscreen (text_view, insert_mark);
5716 return !gtk_text_iter_equal (&old_insert, &new_insert);
5720 whitespace (gunichar ch, gpointer user_data)
5722 return (ch == ' ' || ch == '\t');
5726 not_whitespace (gunichar ch, gpointer user_data)
5728 return !whitespace (ch, user_data);
5732 find_whitepace_region (const GtkTextIter *center,
5733 GtkTextIter *start, GtkTextIter *end)
5738 if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL, NULL))
5739 gtk_text_iter_forward_char (start); /* we want the first whitespace... */
5740 if (whitespace (gtk_text_iter_get_char (end), NULL))
5741 gtk_text_iter_forward_find_char (end, not_whitespace, NULL, NULL);
5743 return !gtk_text_iter_equal (start, end);
5747 gtk_text_view_insert_at_cursor (GtkTextView *text_view,
5750 if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
5751 text_view->priv->editable))
5753 gtk_widget_error_bell (GTK_WIDGET (text_view));
5758 gtk_text_view_delete_from_cursor (GtkTextView *text_view,
5762 GtkTextViewPrivate *priv;
5766 gboolean leave_one = FALSE;
5768 priv = text_view->priv;
5770 gtk_text_view_reset_im_context (text_view);
5772 if (type == GTK_DELETE_CHARS)
5774 /* Char delete deletes the selection, if one exists */
5775 if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5780 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
5781 gtk_text_buffer_get_insert (get_buffer (text_view)));
5788 case GTK_DELETE_CHARS:
5789 gtk_text_iter_forward_cursor_positions (&end, count);
5792 case GTK_DELETE_WORD_ENDS:
5794 gtk_text_iter_forward_word_ends (&end, count);
5796 gtk_text_iter_backward_word_starts (&start, 0 - count);
5799 case GTK_DELETE_WORDS:
5802 case GTK_DELETE_DISPLAY_LINE_ENDS:
5805 case GTK_DELETE_DISPLAY_LINES:
5808 case GTK_DELETE_PARAGRAPH_ENDS:
5811 /* If we're already at a newline, we need to
5812 * simply delete that newline, instead of
5813 * moving to the next one.
5815 if (gtk_text_iter_ends_line (&end))
5817 gtk_text_iter_forward_line (&end);
5823 if (!gtk_text_iter_forward_to_line_end (&end))
5831 if (gtk_text_iter_starts_line (&start))
5833 gtk_text_iter_backward_line (&start);
5834 if (!gtk_text_iter_ends_line (&end))
5835 gtk_text_iter_forward_to_line_end (&start);
5839 gtk_text_iter_set_line_offset (&start, 0);
5843 gtk_text_iter_backward_lines (&start, -count);
5847 case GTK_DELETE_PARAGRAPHS:
5850 gtk_text_iter_set_line_offset (&start, 0);
5851 gtk_text_iter_forward_to_line_end (&end);
5853 /* Do the lines beyond the first. */
5856 gtk_text_iter_forward_to_line_end (&end);
5862 /* FIXME negative count? */
5866 case GTK_DELETE_WHITESPACE:
5868 find_whitepace_region (&insert, &start, &end);
5876 if (!gtk_text_iter_equal (&start, &end))
5878 gtk_text_buffer_begin_user_action (get_buffer (text_view));
5880 if (gtk_text_buffer_delete_interactive (get_buffer (text_view), &start, &end,
5884 gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view),
5890 gtk_widget_error_bell (GTK_WIDGET (text_view));
5893 gtk_text_buffer_end_user_action (get_buffer (text_view));
5894 gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5896 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5897 gtk_text_view_scroll_mark_onscreen (text_view,
5898 gtk_text_buffer_get_insert (get_buffer (text_view)));
5902 gtk_widget_error_bell (GTK_WIDGET (text_view));
5907 gtk_text_view_backspace (GtkTextView *text_view)
5909 GtkTextViewPrivate *priv;
5912 priv = text_view->priv;
5914 gtk_text_view_reset_im_context (text_view);
5916 /* Backspace deletes the selection, if one exists */
5917 if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
5921 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
5923 gtk_text_buffer_get_insert (get_buffer (text_view)));
5925 if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
5926 TRUE, priv->editable))
5928 gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
5929 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5930 gtk_text_view_scroll_mark_onscreen (text_view,
5931 gtk_text_buffer_get_insert (get_buffer (text_view)));
5935 gtk_widget_error_bell (GTK_WIDGET (text_view));
5940 gtk_text_view_cut_clipboard (GtkTextView *text_view)
5942 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5943 GDK_SELECTION_CLIPBOARD);
5945 gtk_text_buffer_cut_clipboard (get_buffer (text_view),
5947 text_view->priv->editable);
5948 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5949 gtk_text_view_scroll_mark_onscreen (text_view,
5950 gtk_text_buffer_get_insert (get_buffer (text_view)));
5954 gtk_text_view_copy_clipboard (GtkTextView *text_view)
5956 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5957 GDK_SELECTION_CLIPBOARD);
5959 gtk_text_buffer_copy_clipboard (get_buffer (text_view),
5962 /* on copy do not scroll, we are already onscreen */
5966 gtk_text_view_paste_clipboard (GtkTextView *text_view)
5968 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
5969 GDK_SELECTION_CLIPBOARD);
5971 gtk_text_buffer_paste_clipboard (get_buffer (text_view),
5974 text_view->priv->editable);
5978 gtk_text_view_paste_done_handler (GtkTextBuffer *buffer,
5979 GtkClipboard *clipboard,
5982 GtkTextView *text_view = data;
5983 GtkTextViewPrivate *priv;
5985 priv = text_view->priv;
5987 if (priv->scroll_after_paste)
5989 DV(g_print (G_STRLOC": scrolling onscreen\n"));
5990 gtk_text_view_scroll_mark_onscreen (text_view, gtk_text_buffer_get_insert (buffer));
5993 priv->scroll_after_paste = TRUE;
5997 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
5999 GtkTextViewPrivate *priv = text_view->priv;
6001 if (priv->text_window)
6002 text_window_invalidate_cursors (priv->text_window);
6004 priv->overwrite_mode = !priv->overwrite_mode;
6007 gtk_text_layout_set_overwrite_mode (priv->layout,
6008 priv->overwrite_mode && priv->editable);
6010 if (priv->text_window)
6011 text_window_invalidate_cursors (priv->text_window);
6013 gtk_text_view_pend_cursor_blink (text_view);
6015 g_object_notify (G_OBJECT (text_view), "overwrite");
6019 * gtk_text_view_get_overwrite:
6020 * @text_view: a #GtkTextView
6022 * Returns whether the #GtkTextView is in overwrite mode or not.
6024 * Return value: whether @text_view is in overwrite mode or not.
6029 gtk_text_view_get_overwrite (GtkTextView *text_view)
6031 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
6033 return text_view->priv->overwrite_mode;
6037 * gtk_text_view_set_overwrite:
6038 * @text_view: a #GtkTextView
6039 * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
6041 * Changes the #GtkTextView overwrite mode.
6046 gtk_text_view_set_overwrite (GtkTextView *text_view,
6049 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6050 overwrite = overwrite != FALSE;
6052 if (text_view->priv->overwrite_mode != overwrite)
6053 gtk_text_view_toggle_overwrite (text_view);
6057 * gtk_text_view_set_accepts_tab:
6058 * @text_view: A #GtkTextView
6059 * @accepts_tab: %TRUE if pressing the Tab key should insert a tab
6060 * character, %FALSE, if pressing the Tab key should move the
6063 * Sets the behavior of the text widget when the Tab key is pressed.
6064 * If @accepts_tab is %TRUE, a tab character is inserted. If @accepts_tab
6065 * is %FALSE the keyboard focus is moved to the next widget in the focus
6071 gtk_text_view_set_accepts_tab (GtkTextView *text_view,
6072 gboolean accepts_tab)
6074 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6076 accepts_tab = accepts_tab != FALSE;
6078 if (text_view->priv->accepts_tab != accepts_tab)
6080 text_view->priv->accepts_tab = accepts_tab;
6082 g_object_notify (G_OBJECT (text_view), "accepts-tab");
6087 * gtk_text_view_get_accepts_tab:
6088 * @text_view: A #GtkTextView
6090 * Returns whether pressing the Tab key inserts a tab characters.
6091 * gtk_text_view_set_accepts_tab().
6093 * Return value: %TRUE if pressing the Tab key inserts a tab character,
6094 * %FALSE if pressing the Tab key moves the keyboard focus.
6099 gtk_text_view_get_accepts_tab (GtkTextView *text_view)
6101 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
6103 return text_view->priv->accepts_tab;
6111 gtk_text_view_unselect (GtkTextView *text_view)
6115 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
6116 gtk_text_buffer_get_insert (get_buffer (text_view)));
6118 gtk_text_buffer_move_mark (get_buffer (text_view),
6119 gtk_text_buffer_get_selection_bound (get_buffer (text_view)),
6124 get_iter_at_pointer (GtkTextView *text_view,
6130 GtkTextViewPrivate *priv;
6131 gint xcoord, ycoord;
6132 GdkModifierType state;
6134 priv = text_view->priv;
6136 gdk_window_get_device_position (priv->text_window->bin_window,
6137 device, &xcoord, &ycoord, &state);
6139 gtk_text_layout_get_iter_at_pixel (priv->layout,
6141 xcoord + priv->xoffset,
6142 ycoord + priv->yoffset);
6151 move_mark_to_pointer_and_scroll (GtkTextView *text_view,
6152 const gchar *mark_name,
6155 GtkTextIter newplace;
6158 get_iter_at_pointer (text_view, device, &newplace, NULL, NULL);
6160 mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
6162 /* This may invalidate the layout */
6163 DV(g_print (G_STRLOC": move mark\n"));
6165 gtk_text_buffer_move_mark (get_buffer (text_view),
6169 DV(g_print (G_STRLOC": scrolling onscreen\n"));
6170 gtk_text_view_scroll_mark_onscreen (text_view, mark);
6172 DV (g_print ("first validate idle leaving %s is %d\n",
6173 G_STRLOC, text_view->priv->first_validate_idle));
6177 selection_scan_timeout (gpointer data)
6179 GtkTextView *text_view;
6181 text_view = GTK_TEXT_VIEW (data);
6183 gtk_text_view_scroll_mark_onscreen (text_view,
6184 gtk_text_buffer_get_insert (get_buffer (text_view)));
6186 return TRUE; /* remain installed. */
6189 #define UPPER_OFFSET_ANCHOR 0.8
6190 #define LOWER_OFFSET_ANCHOR 0.2
6193 check_scroll (gdouble offset, GtkAdjustment *adj)
6195 if ((offset > UPPER_OFFSET_ANCHOR &&
6196 adj->value + adj->page_size < adj->upper) ||
6197 (offset < LOWER_OFFSET_ANCHOR &&
6198 adj->value > adj->lower))
6205 drag_scan_timeout (gpointer data)
6207 GtkTextView *text_view;
6208 GtkTextViewPrivate *priv;
6209 GtkTextIter newplace;
6211 gdouble pointer_xoffset, pointer_yoffset;
6213 text_view = GTK_TEXT_VIEW (data);
6214 priv = text_view->priv;
6216 get_iter_at_pointer (text_view, priv->dnd_device, &newplace, &x, &y);
6218 gtk_text_buffer_move_mark (get_buffer (text_view),
6222 pointer_xoffset = (gdouble) x / gdk_window_get_width (priv->text_window->bin_window);
6223 pointer_yoffset = (gdouble) y / gdk_window_get_height (priv->text_window->bin_window);
6225 if (check_scroll (pointer_xoffset, priv->hadjustment) ||
6226 check_scroll (pointer_yoffset, priv->vadjustment))
6228 /* do not make offsets surpass lower nor upper anchors, this makes
6229 * scrolling speed relative to the distance of the pointer to the
6230 * anchors when it moves beyond them.
6232 pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
6233 pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR);
6235 gtk_text_view_scroll_to_mark (text_view,
6237 0., TRUE, pointer_xoffset, pointer_yoffset);
6248 } SelectionGranularity;
6251 * Move @start and @end to the boundaries of the selection unit (indicated by
6252 * @granularity) which contained @start initially.
6253 * If the selction unit is SELECT_WORDS and @start is not contained in a word
6254 * the selection is extended to all the white spaces between the end of the
6255 * word preceding @start and the start of the one following.
6258 extend_selection (GtkTextView *text_view,
6259 SelectionGranularity granularity,
6265 if (granularity == SELECT_WORDS)
6267 if (gtk_text_iter_inside_word (start))
6269 if (!gtk_text_iter_starts_word (start))
6270 gtk_text_iter_backward_visible_word_start (start);
6272 if (!gtk_text_iter_ends_word (end))
6274 if (!gtk_text_iter_forward_visible_word_end (end))
6275 gtk_text_iter_forward_to_end (end);
6283 if (gtk_text_iter_backward_visible_word_start (&tmp))
6284 gtk_text_iter_forward_visible_word_end (&tmp);
6286 if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
6289 gtk_text_iter_set_line_offset (start, 0);
6292 if (!gtk_text_iter_forward_visible_word_end (&tmp))
6293 gtk_text_iter_forward_to_end (&tmp);
6295 if (gtk_text_iter_ends_word (&tmp))
6296 gtk_text_iter_backward_visible_word_start (&tmp);
6298 if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
6301 gtk_text_iter_forward_to_line_end (end);
6304 else if (granularity == SELECT_LINES)
6306 if (gtk_text_view_starts_display_line (text_view, start))
6308 /* If on a display line boundary, we assume the user
6309 * clicked off the end of a line and we therefore select
6310 * the line before the boundary.
6312 gtk_text_view_backward_display_line_start (text_view, start);
6316 /* start isn't on the start of a line, so we move it to the
6317 * start, and move end to the end unless it's already there.
6319 gtk_text_view_backward_display_line_start (text_view, start);
6321 if (!gtk_text_view_starts_display_line (text_view, end))
6322 gtk_text_view_forward_display_line_end (text_view, end);
6330 SelectionGranularity granularity;
6331 GtkTextMark *orig_start;
6332 GtkTextMark *orig_end;
6336 selection_data_free (SelectionData *data)
6338 if (data->orig_start != NULL)
6339 gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_start),
6341 if (data->orig_end != NULL)
6342 gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (data->orig_end),
6348 selection_motion_event_handler (GtkTextView *text_view,
6349 GdkEventMotion *event,
6350 SelectionData *data)
6352 GtkTextViewPrivate *priv;
6354 priv = text_view->priv;
6355 gdk_event_request_motions (event);
6357 if (priv->grab_device != event->device)
6360 if (data->granularity == SELECT_CHARACTERS)
6362 move_mark_to_pointer_and_scroll (text_view, "insert", event->device);
6366 GtkTextIter cursor, start, end;
6367 GtkTextIter orig_start, orig_end;
6368 GtkTextBuffer *buffer;
6370 buffer = get_buffer (text_view);
6372 gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
6373 gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
6375 get_iter_at_pointer (text_view, event->device, &cursor, NULL, NULL);
6378 extend_selection (text_view, data->granularity, &start, &end);
6380 /* either the selection extends to the front, or end (or not) */
6381 if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
6382 gtk_text_buffer_select_range (buffer, &start, &orig_end);
6384 gtk_text_buffer_select_range (buffer, &end, &orig_start);
6386 gtk_text_view_scroll_mark_onscreen (text_view,
6387 gtk_text_buffer_get_insert (buffer));
6390 /* If we had to scroll offscreen, insert a timeout to do so
6391 * again. Note that in the timeout, even if the mouse doesn't
6392 * move, due to this scroll xoffset/yoffset will have changed
6393 * and we'll need to scroll again.
6395 if (text_view->priv->scroll_timeout != 0) /* reset on every motion event */
6396 g_source_remove (text_view->priv->scroll_timeout);
6398 text_view->priv->scroll_timeout =
6399 gdk_threads_add_timeout (50, selection_scan_timeout, text_view);
6405 gtk_text_view_start_selection_drag (GtkTextView *text_view,
6406 const GtkTextIter *iter,
6407 GdkEventButton *button)
6409 GtkTextViewPrivate *priv;
6410 GtkTextIter cursor, ins, bound;
6411 GtkTextIter orig_start, orig_end;
6412 GtkTextBuffer *buffer;
6413 SelectionData *data;
6415 if (text_view->priv->selection_drag_handler != 0)
6418 priv = text_view->priv;
6419 data = g_new0 (SelectionData, 1);
6421 if (button->type == GDK_2BUTTON_PRESS)
6422 data->granularity = SELECT_WORDS;
6423 else if (button->type == GDK_3BUTTON_PRESS)
6424 data->granularity = SELECT_LINES;
6426 data->granularity = SELECT_CHARACTERS;
6428 priv->grab_device = button->device;
6429 gtk_device_grab_add (GTK_WIDGET (text_view),
6433 buffer = get_buffer (text_view);
6438 extend_selection (text_view, data->granularity, &ins, &bound);
6442 if (button->state & GDK_SHIFT_MASK)
6444 /* Extend selection */
6445 GtkTextIter old_ins, old_bound;
6446 GtkTextIter old_start, old_end;
6448 gtk_text_buffer_get_iter_at_mark (buffer, &old_ins, gtk_text_buffer_get_insert (buffer));
6449 gtk_text_buffer_get_iter_at_mark (buffer, &old_bound, gtk_text_buffer_get_selection_bound (buffer));
6450 old_start = old_ins;
6451 old_end = old_bound;
6452 gtk_text_iter_order (&old_start, &old_end);
6454 /* move the front cursor, if the mouse is in front of the selection. Should the
6455 * cursor however be inside the selection (this happens on tripple click) then we
6456 * move the side which was last moved (current insert mark) */
6457 if (gtk_text_iter_compare (&cursor, &old_start) <= 0 ||
6458 (gtk_text_iter_compare (&cursor, &old_end) < 0 &&
6459 gtk_text_iter_compare (&old_ins, &old_bound) <= 0))
6462 orig_start = old_end;
6474 gtk_text_buffer_select_range (buffer, &ins, &bound);
6476 gtk_text_iter_order (&orig_start, &orig_end);
6477 data->orig_start = gtk_text_buffer_create_mark (buffer, NULL,
6479 data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
6481 gtk_text_view_check_cursor_blink (text_view);
6483 text_view->priv->selection_drag_handler = g_signal_connect_data (text_view,
6484 "motion-notify-event",
6485 G_CALLBACK (selection_motion_event_handler),
6487 (GClosureNotify) selection_data_free, 0);
6490 /* returns whether we were really dragging */
6492 gtk_text_view_end_selection_drag (GtkTextView *text_view)
6494 GtkTextViewPrivate *priv;
6496 priv = text_view->priv;
6498 if (!priv->grab_device)
6501 if (priv->selection_drag_handler == 0)
6504 g_signal_handler_disconnect (text_view, priv->selection_drag_handler);
6505 priv->selection_drag_handler = 0;
6507 if (priv->scroll_timeout != 0)
6509 g_source_remove (priv->scroll_timeout);
6510 priv->scroll_timeout = 0;
6513 gtk_device_grab_remove (GTK_WIDGET (text_view),
6515 priv->grab_device = NULL;
6525 gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
6526 GtkTextAttributes *values,
6529 values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
6530 values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
6533 pango_font_description_free (values->font);
6535 values->font = pango_font_description_copy (style->font_desc);
6539 gtk_text_view_check_keymap_direction (GtkTextView *text_view)
6541 GtkTextViewPrivate *priv = text_view->priv;
6545 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
6546 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
6547 GtkTextDirection new_cursor_dir;
6548 GtkTextDirection new_keyboard_dir;
6549 gboolean split_cursor;
6551 g_object_get (settings,
6552 "gtk-split-cursor", &split_cursor,
6555 if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
6556 new_keyboard_dir = GTK_TEXT_DIR_RTL;
6558 new_keyboard_dir = GTK_TEXT_DIR_LTR;
6561 new_cursor_dir = GTK_TEXT_DIR_NONE;
6563 new_cursor_dir = new_keyboard_dir;
6565 gtk_text_layout_set_cursor_direction (priv->layout, new_cursor_dir);
6566 gtk_text_layout_set_keyboard_direction (priv->layout, new_keyboard_dir);
6571 gtk_text_view_ensure_layout (GtkTextView *text_view)
6574 GtkTextViewPrivate *priv;
6576 widget = GTK_WIDGET (text_view);
6577 priv = text_view->priv;
6579 if (priv->layout == NULL)
6581 GtkTextAttributes *style;
6582 PangoContext *ltr_context, *rtl_context;
6585 DV(g_print(G_STRLOC"\n"));
6587 priv->layout = gtk_text_layout_new ();
6589 g_signal_connect (priv->layout,
6591 G_CALLBACK (invalidated_handler),
6594 g_signal_connect (priv->layout,
6596 G_CALLBACK (changed_handler),
6599 g_signal_connect (priv->layout,
6601 G_CALLBACK (gtk_text_view_child_allocated),
6604 if (get_buffer (text_view))
6605 gtk_text_layout_set_buffer (priv->layout, get_buffer (text_view));
6607 if ((gtk_widget_has_focus (widget) && priv->cursor_visible))
6608 gtk_text_view_pend_cursor_blink (text_view);
6610 gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
6612 gtk_text_layout_set_overwrite_mode (priv->layout,
6613 priv->overwrite_mode && priv->editable);
6615 ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6616 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
6617 rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
6618 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
6620 gtk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
6622 g_object_unref (ltr_context);
6623 g_object_unref (rtl_context);
6625 gtk_text_view_check_keymap_direction (text_view);
6627 style = gtk_text_attributes_new ();
6629 gtk_widget_ensure_style (widget);
6630 gtk_text_view_set_attributes_from_style (text_view,
6632 gtk_widget_get_style (widget));
6634 style->pixels_above_lines = priv->pixels_above_lines;
6635 style->pixels_below_lines = priv->pixels_below_lines;
6636 style->pixels_inside_wrap = priv->pixels_inside_wrap;
6637 style->left_margin = priv->left_margin;
6638 style->right_margin = priv->right_margin;
6639 style->indent = priv->indent;
6640 style->tabs = priv->tabs ? pango_tab_array_copy (priv->tabs) : NULL;
6642 style->wrap_mode = priv->wrap_mode;
6643 style->justification = priv->justify;
6644 style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
6646 gtk_text_layout_set_default_style (priv->layout, style);
6648 gtk_text_attributes_unref (style);
6650 /* Set layout for all anchored children */
6652 tmp_list = priv->children;
6653 while (tmp_list != NULL)
6655 GtkTextViewChild *vc = tmp_list->data;
6659 gtk_text_anchored_child_set_layout (vc->widget,
6661 /* vc may now be invalid! */
6664 tmp_list = g_slist_next (tmp_list);
6667 gtk_text_view_invalidate (text_view);
6672 * gtk_text_view_get_default_attributes:
6673 * @text_view: a #GtkTextView
6675 * Obtains a copy of the default text attributes. These are the
6676 * attributes used for text unless a tag overrides them.
6677 * You'd typically pass the default attributes in to
6678 * gtk_text_iter_get_attributes() in order to get the
6679 * attributes in effect at a given text position.
6681 * The return value is a copy owned by the caller of this function,
6682 * and should be freed.
6684 * Return value: a new #GtkTextAttributes
6687 gtk_text_view_get_default_attributes (GtkTextView *text_view)
6689 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
6691 gtk_text_view_ensure_layout (text_view);
6693 return gtk_text_attributes_copy (text_view->priv->layout->default_style);
6697 gtk_text_view_destroy_layout (GtkTextView *text_view)
6699 GtkTextViewPrivate *priv = text_view->priv;
6705 gtk_text_view_remove_validate_idles (text_view);
6707 g_signal_handlers_disconnect_by_func (priv->layout,
6708 invalidated_handler,
6710 g_signal_handlers_disconnect_by_func (priv->layout,
6714 /* Remove layout from all anchored children */
6715 tmp_list = priv->children;
6716 while (tmp_list != NULL)
6718 GtkTextViewChild *vc = tmp_list->data;
6722 gtk_text_anchored_child_set_layout (vc->widget, NULL);
6723 /* vc may now be invalid! */
6726 tmp_list = g_slist_next (tmp_list);
6729 gtk_text_view_stop_cursor_blink (text_view);
6730 gtk_text_view_end_selection_drag (text_view);
6732 g_object_unref (priv->layout);
6733 priv->layout = NULL;
6738 * gtk_text_view_reset_im_context:
6739 * @text_view: a #GtkTextView
6741 * Reset the input method context of the text view if needed.
6743 * This can be necessary in the case where modifying the buffer
6744 * would confuse on-going input method behavior.
6749 gtk_text_view_reset_im_context (GtkTextView *text_view)
6751 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
6753 if (text_view->priv->need_im_reset)
6755 text_view->priv->need_im_reset = FALSE;
6756 gtk_im_context_reset (text_view->priv->im_context);
6761 * gtk_text_view_im_context_filter_keypress:
6762 * @text_view: a #GtkTextView
6763 * @event: the key event
6765 * Allow the #GtkTextView input method to internally handle key press
6766 * and release events. If this function returns %TRUE, then no further
6767 * processing should be done for this key event. See
6768 * gtk_im_context_filter_keypress().
6770 * Note that you are expected to call this function from your handler
6771 * when overriding key event handling. This is needed in the case when
6772 * you need to insert your own key handling between the input method
6773 * and the default key event handling of the #GtkTextView.
6777 * gtk_foo_bar_key_press_event (GtkWidget *widget,
6778 * GdkEventKey *event)
6780 * if ((key->keyval == GDK_Return || key->keyval == GDK_KP_Enter))
6782 * if (gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
6786 * /* Do some stuff */
6788 * return GTK_WIDGET_CLASS (gtk_foo_bar_parent_class)->key_press_event (widget, event);
6792 * Return value: %TRUE if the input method handled the key event.
6797 gtk_text_view_im_context_filter_keypress (GtkTextView *text_view,
6800 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
6802 return gtk_im_context_filter_keypress (text_view->priv->im_context, event);
6810 drag_begin_cb (GtkWidget *widget,
6811 GdkDragContext *context,
6814 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6815 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6818 cairo_surface_t *surface = NULL;
6820 g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
6822 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6823 surface = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
6827 gtk_drag_set_icon_surface (context, surface);
6828 cairo_surface_destroy (surface);
6832 gtk_drag_set_icon_default (context);
6837 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
6838 const GtkTextIter *iter,
6839 GdkEventMotion *event)
6841 GtkTargetList *target_list;
6843 text_view->priv->drag_start_x = -1;
6844 text_view->priv->drag_start_y = -1;
6845 text_view->priv->pending_place_cursor_button = 0;
6847 target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
6849 g_signal_connect (text_view, "drag-begin",
6850 G_CALLBACK (drag_begin_cb), NULL);
6851 gtk_drag_begin (GTK_WIDGET (text_view), target_list,
6852 GDK_ACTION_COPY | GDK_ACTION_MOVE,
6853 1, (GdkEvent*)event);
6857 gtk_text_view_drag_begin (GtkWidget *widget,
6858 GdkDragContext *context)
6864 gtk_text_view_drag_end (GtkWidget *widget,
6865 GdkDragContext *context)
6870 gtk_text_view_drag_data_get (GtkWidget *widget,
6871 GdkDragContext *context,
6872 GtkSelectionData *selection_data,
6876 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
6877 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
6879 if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
6881 gtk_selection_data_set (selection_data,
6882 gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
6887 else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
6894 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6896 /* Extract the selected text */
6897 str = gtk_text_buffer_serialize (buffer, buffer,
6898 selection_data->target,
6905 gtk_selection_data_set (selection_data,
6906 selection_data->target,
6908 (guchar *) str, len);
6918 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
6920 /* Extract the selected text */
6921 str = gtk_text_iter_get_visible_text (&start, &end);
6926 gtk_selection_data_set_text (selection_data, str, -1);
6933 gtk_text_view_drag_data_delete (GtkWidget *widget,
6934 GdkDragContext *context)
6936 gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->priv->buffer,
6937 TRUE, GTK_TEXT_VIEW (widget)->priv->editable);
6941 gtk_text_view_drag_leave (GtkWidget *widget,
6942 GdkDragContext *context,
6945 GtkTextView *text_view;
6946 GtkTextViewPrivate *priv;
6948 text_view = GTK_TEXT_VIEW (widget);
6949 priv = text_view->priv;
6951 gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
6953 if (priv->dnd_device)
6954 priv->dnd_device = NULL;
6956 if (priv->scroll_timeout != 0)
6957 g_source_remove (priv->scroll_timeout);
6959 priv->scroll_timeout = 0;
6963 gtk_text_view_drag_motion (GtkWidget *widget,
6964 GdkDragContext *context,
6969 GtkTextIter newplace;
6970 GtkTextView *text_view;
6971 GtkTextViewPrivate *priv;
6974 GdkRectangle target_rect;
6977 GdkDragAction suggested_action = 0;
6979 text_view = GTK_TEXT_VIEW (widget);
6980 priv = text_view->priv;
6982 target_rect = priv->text_window->allocation;
6984 if (x < target_rect.x ||
6985 y < target_rect.y ||
6986 x > (target_rect.x + target_rect.width) ||
6987 y > (target_rect.y + target_rect.height))
6988 return FALSE; /* outside the text window, allow parent widgets to handle event */
6990 gtk_text_view_window_to_buffer_coords (text_view,
6991 GTK_TEXT_WINDOW_WIDGET,
6995 gtk_text_layout_get_iter_at_pixel (priv->layout,
6999 target = gtk_drag_dest_find_target (widget, context,
7000 gtk_drag_dest_get_target_list (widget));
7002 if (target == GDK_NONE)
7004 /* can't accept any of the offered targets */
7006 else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7008 gtk_text_iter_compare (&newplace, &start) >= 0 &&
7009 gtk_text_iter_compare (&newplace, &end) <= 0)
7011 /* We're inside the selection. */
7015 if (gtk_text_iter_can_insert (&newplace, priv->editable))
7017 GtkWidget *source_widget;
7019 suggested_action = context->suggested_action;
7021 source_widget = gtk_drag_get_source_widget (context);
7023 if (source_widget == widget)
7025 /* Default to MOVE, unless the user has
7026 * pressed ctrl or alt to affect available actions
7028 if ((context->actions & GDK_ACTION_MOVE) != 0)
7029 suggested_action = GDK_ACTION_MOVE;
7034 /* Can't drop here. */
7038 if (suggested_action != 0)
7040 gtk_text_mark_set_visible (priv->dnd_mark,
7041 priv->cursor_visible);
7043 gdk_drag_status (context, suggested_action, time);
7047 gdk_drag_status (context, 0, time);
7048 gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
7051 priv->dnd_device = gdk_drag_context_get_device (context);
7053 if (!priv->scroll_timeout)
7054 priv->scroll_timeout =
7055 gdk_threads_add_timeout (100, drag_scan_timeout, text_view);
7057 /* TRUE return means don't propagate the drag motion to parent
7058 * widgets that may also be drop sites.
7064 gtk_text_view_drag_drop (GtkWidget *widget,
7065 GdkDragContext *context,
7070 GtkTextView *text_view;
7071 GtkTextViewPrivate *priv;
7072 GtkTextIter drop_point;
7073 GdkAtom target = GDK_NONE;
7075 text_view = GTK_TEXT_VIEW (widget);
7076 priv = text_view->priv;
7078 if (priv->scroll_timeout != 0)
7079 g_source_remove (priv->scroll_timeout);
7081 priv->scroll_timeout = 0;
7083 gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
7085 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7089 if (gtk_text_iter_can_insert (&drop_point, priv->editable))
7090 target = gtk_drag_dest_find_target (widget, context, NULL);
7092 if (target != GDK_NONE)
7093 gtk_drag_get_data (widget, context, target, time);
7095 gtk_drag_finish (context, FALSE, FALSE, time);
7101 insert_text_data (GtkTextView *text_view,
7102 GtkTextIter *drop_point,
7103 GtkSelectionData *selection_data)
7107 str = gtk_selection_data_get_text (selection_data);
7111 if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
7112 drop_point, (gchar *) str, -1,
7113 text_view->priv->editable))
7115 gtk_widget_error_bell (GTK_WIDGET (text_view));
7123 gtk_text_view_drag_data_received (GtkWidget *widget,
7124 GdkDragContext *context,
7127 GtkSelectionData *selection_data,
7131 GtkTextIter drop_point;
7132 GtkTextView *text_view;
7133 GtkTextViewPrivate *priv;
7134 gboolean success = FALSE;
7135 GtkTextBuffer *buffer = NULL;
7137 text_view = GTK_TEXT_VIEW (widget);
7138 priv = text_view->priv;
7140 if (!priv->dnd_mark)
7143 buffer = get_buffer (text_view);
7145 gtk_text_buffer_get_iter_at_mark (buffer,
7149 if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
7154 gtk_text_buffer_begin_user_action (buffer);
7156 if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
7158 GtkTextBuffer *src_buffer = NULL;
7159 GtkTextIter start, end;
7160 gboolean copy_tags = TRUE;
7162 if (selection_data->length != sizeof (src_buffer))
7165 memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
7167 if (src_buffer == NULL)
7170 g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
7172 if (gtk_text_buffer_get_tag_table (src_buffer) !=
7173 gtk_text_buffer_get_tag_table (buffer))
7175 /* try to find a suitable rich text target instead */
7179 GdkAtom target = GDK_NONE;
7183 atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
7185 for (list = context->targets; list; list = g_list_next (list))
7189 for (i = 0; i < n_atoms; i++)
7190 if (GUINT_TO_POINTER (atoms[i]) == list->data)
7199 if (target != GDK_NONE)
7201 gtk_drag_get_data (widget, context, target, time);
7202 gtk_text_buffer_end_user_action (buffer);
7207 if (gtk_text_buffer_get_selection_bounds (src_buffer,
7212 gtk_text_buffer_insert_range_interactive (buffer,
7221 str = gtk_text_iter_get_visible_text (&start, &end);
7222 gtk_text_buffer_insert_interactive (buffer,
7223 &drop_point, str, -1,
7229 else if (selection_data->length > 0 &&
7230 info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
7233 GError *error = NULL;
7235 retval = gtk_text_buffer_deserialize (buffer, buffer,
7236 selection_data->target,
7238 (guint8 *) selection_data->data,
7239 selection_data->length,
7244 g_warning ("error pasting: %s\n", error->message);
7245 g_clear_error (&error);
7249 insert_text_data (text_view, &drop_point, selection_data);
7252 gtk_drag_finish (context, success,
7253 success && context->action == GDK_ACTION_MOVE,
7258 gtk_text_buffer_get_iter_at_mark (buffer,
7261 gtk_text_buffer_place_cursor (buffer, &drop_point);
7263 gtk_text_buffer_end_user_action (buffer);
7268 * gtk_text_view_get_hadjustment:
7269 * @text_view: a #GtkTextView
7271 * Gets the horizontal-scrolling #GtkAdjustment.
7273 * Returns: (transfer none): pointer to the horizontal #GtkAdjustment
7277 * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
7280 gtk_text_view_get_hadjustment (GtkTextView *text_view)
7282 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7284 return text_view->priv->hadjustment;
7288 gtk_text_view_set_hadjustment (GtkTextView *text_view,
7289 GtkAdjustment *adjustment)
7291 GtkTextViewPrivate *priv = text_view->priv;
7293 if (adjustment && priv->hadjustment == adjustment)
7296 if (priv->hadjustment != NULL)
7298 g_signal_handlers_disconnect_by_func (priv->hadjustment,
7299 gtk_text_view_value_changed,
7301 g_object_unref (priv->hadjustment);
7304 if (adjustment == NULL)
7305 adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
7307 g_signal_connect (adjustment, "value-changed",
7308 G_CALLBACK (gtk_text_view_value_changed), text_view);
7309 priv->hadjustment = g_object_ref_sink (adjustment);
7310 gtk_text_view_set_hadjustment_values (text_view);
7312 g_object_notify (G_OBJECT (text_view), "hadjustment");
7316 * gtk_text_view_get_vadjustment:
7317 * @text_view: a #GtkTextView
7319 * Gets the vertical-scrolling #GtkAdjustment.
7321 * Returns: (transfer none): pointer to the vertical #GtkAdjustment
7326 gtk_text_view_get_vadjustment (GtkTextView *text_view)
7328 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
7330 return text_view->priv->vadjustment;
7334 gtk_text_view_set_vadjustment (GtkTextView *text_view,
7335 GtkAdjustment *adjustment)
7337 GtkTextViewPrivate *priv = text_view->priv;
7339 if (adjustment && priv->vadjustment == adjustment)
7342 if (priv->vadjustment != NULL)
7344 g_signal_handlers_disconnect_by_func (priv->vadjustment,
7345 gtk_text_view_value_changed,
7347 g_object_unref (priv->vadjustment);
7350 if (adjustment == NULL)
7351 adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
7353 g_signal_connect (adjustment, "value-changed",
7354 G_CALLBACK (gtk_text_view_value_changed), text_view);
7355 priv->vadjustment = g_object_ref_sink (adjustment);
7356 gtk_text_view_set_vadjustment_values (text_view);
7358 g_object_notify (G_OBJECT (text_view), "vadjustment");
7362 gtk_text_view_set_hadjustment_values (GtkTextView *text_view)
7364 GtkTextViewPrivate *priv;
7370 priv = text_view->priv;
7372 screen_width = SCREEN_WIDTH (text_view);
7373 old_value = gtk_adjustment_get_value (priv->hadjustment);
7374 new_upper = MAX (screen_width, priv->width);
7376 g_object_set (priv->hadjustment,
7379 "page-size", (gdouble)screen_width,
7380 "step-increment", screen_width * 0.1,
7381 "page-increment", screen_width * 0.9,
7384 new_value = CLAMP (old_value, 0, new_upper - screen_width);
7385 if (new_value != old_value)
7386 gtk_adjustment_set_value (priv->hadjustment, new_value);
7390 gtk_text_view_set_vadjustment_values (GtkTextView *text_view)
7392 GtkTextViewPrivate *priv;
7393 GtkTextIter first_para;
7400 priv = text_view->priv;
7402 screen_height = SCREEN_HEIGHT (text_view);
7403 old_value = gtk_adjustment_get_value (priv->vadjustment);
7404 new_upper = MAX (screen_height, priv->height);
7406 g_object_set (priv->vadjustment,
7409 "page-size", (gdouble)screen_height,
7410 "step-increment", screen_height * 0.1,
7411 "page-increment", screen_height * 0.9,
7414 /* Now adjust the value of the adjustment to keep the cursor at the
7415 * same place in the buffer */
7416 gtk_text_view_ensure_layout (text_view);
7417 gtk_text_view_get_first_para_iter (text_view, &first_para);
7418 gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
7420 y += priv->first_para_pixels;
7422 new_value = CLAMP (y, 0, new_upper - screen_height);
7423 if (new_value != old_value)
7424 gtk_adjustment_set_value (priv->vadjustment, new_value);
7428 /* FIXME this adjust_allocation is a big cut-and-paste from
7429 * GtkCList, needs to be some "official" way to do this
7439 /* The window to which widget->window is relative */
7440 #define ALLOCATION_WINDOW(widget) \
7441 (!gtk_widget_get_has_window (widget) ? \
7442 gtk_widget_get_window (widget) : \
7443 gdk_window_get_parent (gtk_widget_get_window (widget)))
7446 adjust_allocation_recurse (GtkWidget *widget,
7449 GtkAllocation allocation;
7450 ScrollData *scroll_data = data;
7452 /* Need to really size allocate instead of just poking
7453 * into widget->allocation if the widget is not realized.
7454 * FIXME someone figure out why this was.
7456 if (!gtk_widget_get_realized (widget))
7458 if (gtk_widget_get_visible (widget))
7460 GdkRectangle tmp_rectangle;
7462 tmp_rectangle = allocation;
7463 tmp_rectangle.x += scroll_data->dx;
7464 tmp_rectangle.y += scroll_data->dy;
7466 gtk_widget_size_allocate (widget, &tmp_rectangle);
7471 if (ALLOCATION_WINDOW (widget) == scroll_data->window)
7473 allocation.x += scroll_data->dx;
7474 allocation.y += scroll_data->dy;
7475 gtk_widget_set_allocation (widget, &allocation);
7477 if (GTK_IS_CONTAINER (widget))
7478 gtk_container_forall (GTK_CONTAINER (widget),
7479 adjust_allocation_recurse,
7486 adjust_allocation (GtkWidget *widget,
7490 ScrollData scroll_data;
7492 if (gtk_widget_get_realized (widget))
7493 scroll_data.window = ALLOCATION_WINDOW (widget);
7495 scroll_data.window = NULL;
7497 scroll_data.dx = dx;
7498 scroll_data.dy = dy;
7500 adjust_allocation_recurse (widget, &scroll_data);
7504 gtk_text_view_value_changed (GtkAdjustment *adj,
7505 GtkTextView *text_view)
7507 GtkTextViewPrivate *priv;
7513 priv = text_view->priv;
7515 /* Note that we oddly call this function with adj == NULL
7519 priv->onscreen_validated = FALSE;
7521 DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
7522 adj == priv->hadjustment ? "hadj" : adj == priv->vadjustment ? "vadj" : "none",
7523 adj ? adj->value : 0.0));
7525 if (adj == priv->hadjustment)
7527 dx = priv->xoffset - (gint)adj->value;
7528 priv->xoffset = adj->value;
7530 /* If the change is due to a size change we need
7531 * to invalidate the entire text window because there might be
7532 * right-aligned or centered text
7534 if (priv->width_changed)
7536 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7537 gdk_window_invalidate_rect (priv->text_window->bin_window, NULL, FALSE);
7539 priv->width_changed = FALSE;
7542 else if (adj == priv->vadjustment)
7544 dy = priv->yoffset - (gint)adj->value;
7545 priv->yoffset = adj->value;
7549 gtk_text_layout_get_line_at_y (priv->layout, &iter, adj->value, &line_top);
7551 gtk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
7553 priv->first_para_pixels = adj->value - line_top;
7557 if (dx != 0 || dy != 0)
7561 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7565 if (priv->left_window)
7566 text_window_scroll (priv->left_window, 0, dy);
7567 if (priv->right_window)
7568 text_window_scroll (priv->right_window, 0, dy);
7573 if (priv->top_window)
7574 text_window_scroll (priv->top_window, dx, 0);
7575 if (priv->bottom_window)
7576 text_window_scroll (priv->bottom_window, dx, 0);
7579 /* It looks nicer to scroll the main area last, because
7580 * it takes a while, and making the side areas update
7581 * afterward emphasizes the slowness of scrolling the
7584 text_window_scroll (priv->text_window, dx, dy);
7587 /* Children are now "moved" in the text window, poke
7588 * into widget->allocation for each child
7590 tmp_list = priv->children;
7591 while (tmp_list != NULL)
7593 GtkTextViewChild *child = tmp_list->data;
7596 adjust_allocation (child->widget, dx, dy);
7598 tmp_list = g_slist_next (tmp_list);
7602 /* This could result in invalidation, which would install the
7603 * first_validate_idle, which would validate onscreen;
7604 * but we're going to go ahead and validate here, so
7605 * first_validate_idle shouldn't have anything to do.
7607 gtk_text_view_update_layout_width (text_view);
7609 /* We also update the IM spot location here, since the IM context
7610 * might do something that leads to validation.
7612 gtk_text_view_update_im_spot_location (text_view);
7614 /* note that validation of onscreen could invoke this function
7615 * recursively, by scrolling to maintain first_para, or in response
7616 * to updating the layout width, however there is no problem with
7617 * that, or shouldn't be.
7619 gtk_text_view_validate_onscreen (text_view);
7621 /* process exposes */
7622 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
7624 DV (g_print ("Processing updates (%s)\n", G_STRLOC));
7626 if (priv->left_window)
7627 gdk_window_process_updates (priv->left_window->bin_window, TRUE);
7629 if (priv->right_window)
7630 gdk_window_process_updates (priv->right_window->bin_window, TRUE);
7632 if (priv->top_window)
7633 gdk_window_process_updates (priv->top_window->bin_window, TRUE);
7635 if (priv->bottom_window)
7636 gdk_window_process_updates (priv->bottom_window->bin_window, TRUE);
7638 gdk_window_process_updates (priv->text_window->bin_window, TRUE);
7641 /* If this got installed, get rid of it, it's just a waste of time. */
7642 if (priv->first_validate_idle != 0)
7644 g_source_remove (priv->first_validate_idle);
7645 priv->first_validate_idle = 0;
7648 /* Finally we update the IM cursor location again, to ensure any
7649 * changes made by the validation are pushed through.
7651 gtk_text_view_update_im_spot_location (text_view);
7653 DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
7657 gtk_text_view_commit_handler (GtkIMContext *context,
7659 GtkTextView *text_view)
7661 gtk_text_view_commit_text (text_view, str);
7665 gtk_text_view_commit_text (GtkTextView *text_view,
7668 GtkTextViewPrivate *priv;
7669 gboolean had_selection;
7671 priv = text_view->priv;
7673 gtk_text_buffer_begin_user_action (get_buffer (text_view));
7675 had_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
7678 gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
7681 if (!strcmp (str, "\n"))
7683 if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
7686 gtk_widget_error_bell (GTK_WIDGET (text_view));
7691 if (!had_selection && priv->overwrite_mode)
7695 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
7697 gtk_text_buffer_get_insert (get_buffer (text_view)));
7698 if (!gtk_text_iter_ends_line (&insert))
7699 gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
7702 if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
7705 gtk_widget_error_bell (GTK_WIDGET (text_view));
7709 gtk_text_buffer_end_user_action (get_buffer (text_view));
7711 gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
7712 DV(g_print (G_STRLOC": scrolling onscreen\n"));
7713 gtk_text_view_scroll_mark_onscreen (text_view,
7714 gtk_text_buffer_get_insert (get_buffer (text_view)));
7718 gtk_text_view_preedit_changed_handler (GtkIMContext *context,
7719 GtkTextView *text_view)
7721 GtkTextViewPrivate *priv;
7723 PangoAttrList *attrs;
7727 priv = text_view->priv;
7729 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
7730 gtk_text_buffer_get_insert (priv->buffer));
7732 /* Keypress events are passed to input method even if cursor position is
7733 * not editable; so beep here if it's multi-key input sequence, input
7734 * method will be reset in key-press-event handler.
7736 gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
7738 if (str && str[0] && !gtk_text_iter_can_insert (&iter, priv->editable))
7740 gtk_widget_error_bell (GTK_WIDGET (text_view));
7744 g_signal_emit (text_view, signals[PREEDIT_CHANGED], 0, str);
7747 gtk_text_layout_set_preedit_string (priv->layout, str, attrs, cursor_pos);
7748 if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
7749 gtk_text_view_scroll_mark_onscreen (text_view,
7750 gtk_text_buffer_get_insert (get_buffer (text_view)));
7753 pango_attr_list_unref (attrs);
7758 gtk_text_view_retrieve_surrounding_handler (GtkIMContext *context,
7759 GtkTextView *text_view)
7766 gtk_text_buffer_get_iter_at_mark (text_view->priv->buffer, &start,
7767 gtk_text_buffer_get_insert (text_view->priv->buffer));
7770 pos = gtk_text_iter_get_line_index (&start);
7771 gtk_text_iter_set_line_offset (&start, 0);
7772 gtk_text_iter_forward_to_line_end (&end);
7774 text = gtk_text_iter_get_slice (&start, &end);
7775 gtk_im_context_set_surrounding (context, text, -1, pos);
7782 gtk_text_view_delete_surrounding_handler (GtkIMContext *context,
7785 GtkTextView *text_view)
7787 GtkTextViewPrivate *priv;
7791 priv = text_view->priv;
7793 gtk_text_buffer_get_iter_at_mark (priv->buffer, &start,
7794 gtk_text_buffer_get_insert (priv->buffer));
7797 gtk_text_iter_forward_chars (&start, offset);
7798 gtk_text_iter_forward_chars (&end, offset + n_chars);
7800 gtk_text_buffer_delete_interactive (priv->buffer, &start, &end,
7807 gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
7808 const GtkTextIter *location,
7812 GtkTextView *text_view = GTK_TEXT_VIEW (data);
7813 gboolean need_reset = FALSE;
7815 if (mark == gtk_text_buffer_get_insert (buffer))
7817 text_view->priv->virtual_cursor_x = -1;
7818 text_view->priv->virtual_cursor_y = -1;
7819 gtk_text_view_update_im_spot_location (text_view);
7822 else if (mark == gtk_text_buffer_get_selection_bound (buffer))
7828 gtk_text_view_reset_im_context (text_view);
7832 gtk_text_view_target_list_notify (GtkTextBuffer *buffer,
7833 const GParamSpec *pspec,
7836 GtkWidget *widget = GTK_WIDGET (data);
7837 GtkTargetList *view_list;
7838 GtkTargetList *buffer_list;
7841 view_list = gtk_drag_dest_get_target_list (widget);
7842 buffer_list = gtk_text_buffer_get_paste_target_list (buffer);
7845 gtk_target_list_ref (view_list);
7847 view_list = gtk_target_list_new (NULL, 0);
7849 list = view_list->list;
7852 GtkTargetPair *pair = list->data;
7854 list = g_list_next (list); /* get next element before removing */
7856 if (pair->info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
7857 pair->info <= GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
7859 gtk_target_list_remove (view_list, pair->target);
7863 for (list = buffer_list->list; list; list = g_list_next (list))
7865 GtkTargetPair *pair = list->data;
7867 gtk_target_list_add (view_list, pair->target, pair->flags, pair->info);
7870 gtk_drag_dest_set_target_list (widget, view_list);
7871 gtk_target_list_unref (view_list);
7875 gtk_text_view_get_cursor_location (GtkTextView *text_view,
7880 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7881 gtk_text_buffer_get_insert (get_buffer (text_view)));
7883 gtk_text_layout_get_cursor_locations (text_view->priv->layout, &insert, pos, NULL);
7887 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
7888 GtkTextIter *cursor,
7892 GtkTextViewPrivate *priv;
7896 priv = text_view->priv;
7901 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
7902 gtk_text_buffer_get_insert (get_buffer (text_view)));
7904 if ((x && priv->virtual_cursor_x == -1) ||
7905 (y && priv->virtual_cursor_y == -1))
7906 gtk_text_layout_get_cursor_locations (priv->layout, &insert, &pos, NULL);
7910 if (priv->virtual_cursor_x != -1)
7911 *x = priv->virtual_cursor_x;
7918 if (priv->virtual_cursor_x != -1)
7919 *y = priv->virtual_cursor_y;
7921 *y = pos.y + pos.height / 2;
7926 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
7932 if (!text_view->priv->layout)
7935 if (x == -1 || y == -1)
7936 gtk_text_view_get_cursor_location (text_view, &pos);
7938 text_view->priv->virtual_cursor_x = (x == -1) ? pos.x : x;
7939 text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
7942 /* Quick hack of a popup menu
7945 activate_cb (GtkWidget *menuitem,
7946 GtkTextView *text_view)
7948 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
7949 g_signal_emit_by_name (text_view, signal);
7953 append_action_signal (GtkTextView *text_view,
7955 const gchar *stock_id,
7956 const gchar *signal,
7959 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
7961 g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
7962 g_signal_connect (menuitem, "activate",
7963 G_CALLBACK (activate_cb), text_view);
7965 gtk_widget_set_sensitive (menuitem, sensitive);
7967 gtk_widget_show (menuitem);
7968 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
7972 gtk_text_view_select_all (GtkWidget *widget,
7975 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
7976 GtkTextBuffer *buffer;
7977 GtkTextIter start_iter, end_iter, insert;
7979 buffer = text_view->priv->buffer;
7982 gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
7983 gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
7987 gtk_text_buffer_get_iter_at_mark (buffer, &insert,
7988 gtk_text_buffer_get_insert (buffer));
7989 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
7994 select_all_cb (GtkWidget *menuitem,
7995 GtkTextView *text_view)
7997 gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
8001 delete_cb (GtkTextView *text_view)
8003 gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
8004 text_view->priv->editable);
8008 popup_menu_detach (GtkWidget *attach_widget,
8011 GTK_TEXT_VIEW (attach_widget)->priv->popup_menu = NULL;
8015 popup_position_func (GtkMenu *menu,
8021 GtkAllocation allocation;
8022 GtkTextView *text_view;
8024 GdkRectangle cursor_rect;
8025 GdkRectangle onscreen_rect;
8026 gint root_x, root_y;
8031 GdkRectangle monitor;
8033 text_view = GTK_TEXT_VIEW (user_data);
8034 widget = GTK_WIDGET (text_view);
8036 g_return_if_fail (gtk_widget_get_realized (widget));
8038 screen = gtk_widget_get_screen (widget);
8040 gdk_window_get_origin (gtk_widget_get_window (widget),
8043 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
8045 gtk_text_buffer_get_insert (get_buffer (text_view)));
8047 gtk_text_view_get_iter_location (text_view,
8051 gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
8053 gtk_widget_get_preferred_size (text_view->priv->popup_menu,
8056 gtk_widget_get_allocation (widget, &allocation);
8058 /* can't use rectangle_intersect since cursor rect can have 0 width */
8059 if (cursor_rect.x >= onscreen_rect.x &&
8060 cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
8061 cursor_rect.y >= onscreen_rect.y &&
8062 cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
8064 gtk_text_view_buffer_to_window_coords (text_view,
8065 GTK_TEXT_WINDOW_WIDGET,
8066 cursor_rect.x, cursor_rect.y,
8067 &cursor_rect.x, &cursor_rect.y);
8069 *x = root_x + cursor_rect.x + cursor_rect.width;
8070 *y = root_y + cursor_rect.y + cursor_rect.height;
8074 /* Just center the menu, since cursor is offscreen. */
8075 *x = root_x + (allocation.width / 2 - req.width / 2);
8076 *y = root_y + (allocation.height / 2 - req.height / 2);
8080 *x = CLAMP (*x, root_x, (root_x + allocation.width));
8081 *y = CLAMP (*y, root_y, (root_y + allocation.height));
8083 monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
8084 gtk_menu_set_monitor (menu, monitor_num);
8085 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
8087 *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
8088 *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
8095 GtkTextView *text_view;
8101 range_contains_editable_text (const GtkTextIter *start,
8102 const GtkTextIter *end,
8103 gboolean default_editability)
8105 GtkTextIter iter = *start;
8107 while (gtk_text_iter_compare (&iter, end) < 0)
8109 if (gtk_text_iter_editable (&iter, default_editability))
8112 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
8119 unichar_chosen_func (const char *text,
8122 GtkTextView *text_view = GTK_TEXT_VIEW (data);
8124 gtk_text_view_commit_text (text_view, text);
8128 popup_targets_received (GtkClipboard *clipboard,
8129 GtkSelectionData *data,
8132 PopupInfo *info = user_data;
8133 GtkTextView *text_view;
8134 GtkTextViewPrivate *priv;
8136 text_view = info->text_view;
8137 priv = text_view->priv;
8139 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
8141 /* We implicitely rely here on the fact that if we are pasting ourself, we'll
8142 * have text targets as well as the private GTK_TEXT_BUFFER_CONTENTS target.
8144 gboolean clipboard_contains_text;
8145 GtkWidget *menuitem;
8147 gboolean have_selection;
8148 gboolean can_insert;
8150 GtkTextIter sel_start, sel_end;
8151 gboolean show_input_method_menu;
8152 gboolean show_unicode_menu;
8154 clipboard_contains_text = gtk_selection_data_targets_include_text (data);
8156 if (priv->popup_menu)
8157 gtk_widget_destroy (priv->popup_menu);
8159 priv->popup_menu = gtk_menu_new ();
8161 gtk_menu_attach_to_widget (GTK_MENU (priv->popup_menu),
8162 GTK_WIDGET (text_view),
8165 have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
8166 &sel_start, &sel_end);
8168 gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
8170 gtk_text_buffer_get_insert (get_buffer (text_view)));
8172 can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
8174 append_action_signal (text_view, priv->popup_menu, GTK_STOCK_CUT, "cut-clipboard",
8176 range_contains_editable_text (&sel_start, &sel_end,
8178 append_action_signal (text_view, priv->popup_menu, GTK_STOCK_COPY, "copy-clipboard",
8180 append_action_signal (text_view, priv->popup_menu, GTK_STOCK_PASTE, "paste-clipboard",
8181 can_insert && clipboard_contains_text);
8183 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
8184 gtk_widget_set_sensitive (menuitem,
8186 range_contains_editable_text (&sel_start, &sel_end,
8188 g_signal_connect_swapped (menuitem, "activate",
8189 G_CALLBACK (delete_cb), text_view);
8190 gtk_widget_show (menuitem);
8191 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8193 menuitem = gtk_separator_menu_item_new ();
8194 gtk_widget_show (menuitem);
8195 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8197 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
8198 g_signal_connect (menuitem, "activate",
8199 G_CALLBACK (select_all_cb), text_view);
8200 gtk_widget_show (menuitem);
8201 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8203 g_object_get (gtk_widget_get_settings (GTK_WIDGET (text_view)),
8204 "gtk-show-input-method-menu", &show_input_method_menu,
8205 "gtk-show-unicode-menu", &show_unicode_menu,
8208 if (show_input_method_menu || show_unicode_menu)
8210 menuitem = gtk_separator_menu_item_new ();
8211 gtk_widget_show (menuitem);
8212 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8215 if (show_input_method_menu)
8217 menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
8218 gtk_widget_show (menuitem);
8219 gtk_widget_set_sensitive (menuitem, can_insert);
8221 submenu = gtk_menu_new ();
8222 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8223 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8225 gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (priv->im_context),
8226 GTK_MENU_SHELL (submenu));
8229 if (show_unicode_menu)
8231 menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
8232 gtk_widget_show (menuitem);
8233 gtk_widget_set_sensitive (menuitem, can_insert);
8235 submenu = gtk_menu_new ();
8236 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8237 gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
8239 _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
8240 unichar_chosen_func,
8244 g_signal_emit (text_view,
8245 signals[POPULATE_POPUP],
8250 gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
8252 info->button, info->time);
8255 gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
8256 popup_position_func, text_view,
8257 0, gtk_get_current_event_time ());
8258 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
8262 g_object_unref (text_view);
8267 gtk_text_view_do_popup (GtkTextView *text_view,
8268 GdkEventButton *event)
8270 PopupInfo *info = g_new (PopupInfo, 1);
8272 /* In order to know what entries we should make sensitive, we
8273 * ask for the current targets of the clipboard, and when
8274 * we get them, then we actually pop up the menu.
8276 info->text_view = g_object_ref (text_view);
8280 info->button = event->button;
8281 info->time = event->time;
8286 info->time = gtk_get_current_event_time ();
8289 gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
8290 GDK_SELECTION_CLIPBOARD),
8291 gdk_atom_intern_static_string ("TARGETS"),
8292 popup_targets_received,
8297 gtk_text_view_popup_menu (GtkWidget *widget)
8299 gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);
8303 /* Child GdkWindows */
8306 static GtkTextWindow*
8307 text_window_new (GtkTextWindowType type,
8310 gint height_request)
8314 win = g_new (GtkTextWindow, 1);
8317 win->widget = widget;
8319 win->bin_window = NULL;
8320 win->requisition.width = width_request;
8321 win->requisition.height = height_request;
8322 win->allocation.width = width_request;
8323 win->allocation.height = height_request;
8324 win->allocation.x = 0;
8325 win->allocation.y = 0;
8331 text_window_free (GtkTextWindow *win)
8334 text_window_unrealize (win);
8340 text_window_realize (GtkTextWindow *win,
8344 GdkWindowAttr attributes;
8345 gint attributes_mask;
8348 attributes.window_type = GDK_WINDOW_CHILD;
8349 attributes.x = win->allocation.x;
8350 attributes.y = win->allocation.y;
8351 attributes.width = win->allocation.width;
8352 attributes.height = win->allocation.height;
8353 attributes.wclass = GDK_INPUT_OUTPUT;
8354 attributes.visual = gtk_widget_get_visual (win->widget);
8355 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
8357 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
8359 window = gtk_widget_get_window (widget);
8361 win->window = gdk_window_new (window,
8362 &attributes, attributes_mask);
8364 gdk_window_show (win->window);
8365 gdk_window_set_user_data (win->window, win->widget);
8366 gdk_window_lower (win->window);
8370 attributes.width = win->allocation.width;
8371 attributes.height = win->allocation.height;
8372 attributes.event_mask = (GDK_EXPOSURE_MASK |
8374 GDK_KEY_PRESS_MASK |
8375 GDK_BUTTON_PRESS_MASK |
8376 GDK_BUTTON_RELEASE_MASK |
8377 GDK_POINTER_MOTION_MASK |
8378 GDK_POINTER_MOTION_HINT_MASK |
8379 gtk_widget_get_events (win->widget));
8381 win->bin_window = gdk_window_new (win->window,
8385 gdk_window_show (win->bin_window);
8386 gdk_window_set_user_data (win->bin_window, win->widget);
8388 if (win->type == GTK_TEXT_WINDOW_TEXT)
8390 if (gtk_widget_is_sensitive (widget))
8393 cursor = gdk_cursor_new_for_display (gdk_window_get_display (window),
8395 gdk_window_set_cursor (win->bin_window, cursor);
8396 gdk_cursor_unref (cursor);
8399 gtk_im_context_set_client_window (GTK_TEXT_VIEW (widget)->priv->im_context,
8403 gdk_window_set_background (win->bin_window,
8404 >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
8408 gdk_window_set_background (win->bin_window,
8409 >k_widget_get_style (widget)->bg[gtk_widget_get_state (widget)]);
8412 g_object_set_qdata (G_OBJECT (win->window),
8413 g_quark_from_static_string ("gtk-text-view-text-window"),
8416 g_object_set_qdata (G_OBJECT (win->bin_window),
8417 g_quark_from_static_string ("gtk-text-view-text-window"),
8422 text_window_unrealize (GtkTextWindow *win)
8424 if (win->type == GTK_TEXT_WINDOW_TEXT)
8426 gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->priv->im_context,
8430 gdk_window_set_user_data (win->window, NULL);
8431 gdk_window_set_user_data (win->bin_window, NULL);
8432 gdk_window_destroy (win->bin_window);
8433 gdk_window_destroy (win->window);
8435 win->bin_window = NULL;
8439 text_window_size_allocate (GtkTextWindow *win,
8442 win->allocation = *rect;
8446 gdk_window_move_resize (win->window,
8448 rect->width, rect->height);
8450 gdk_window_resize (win->bin_window,
8451 rect->width, rect->height);
8456 text_window_scroll (GtkTextWindow *win,
8460 if (dx != 0 || dy != 0)
8462 gdk_window_scroll (win->bin_window, dx, dy);
8467 text_window_invalidate_rect (GtkTextWindow *win,
8470 GdkRectangle window_rect;
8472 gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (win->widget),
8479 window_rect.width = rect->width;
8480 window_rect.height = rect->height;
8482 /* Adjust the rect as appropriate */
8486 case GTK_TEXT_WINDOW_TEXT:
8489 case GTK_TEXT_WINDOW_LEFT:
8490 case GTK_TEXT_WINDOW_RIGHT:
8492 window_rect.width = win->allocation.width;
8495 case GTK_TEXT_WINDOW_TOP:
8496 case GTK_TEXT_WINDOW_BOTTOM:
8498 window_rect.height = win->allocation.height;
8502 g_warning ("%s: bug!", G_STRFUNC);
8507 gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
8511 cairo_t *cr = gdk_cairo_create (win->bin_window);
8512 gdk_cairo_rectangle (cr, &window_rect);
8513 cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */
8521 text_window_invalidate_cursors (GtkTextWindow *win)
8523 GtkTextView *text_view;
8524 GtkTextViewPrivate *priv;
8526 GdkRectangle strong;
8528 gboolean draw_arrow;
8529 gfloat cursor_aspect_ratio;
8533 text_view = GTK_TEXT_VIEW (win->widget);
8534 priv = text_view->priv;
8536 gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
8537 gtk_text_buffer_get_insert (priv->buffer));
8539 if (_gtk_text_layout_get_block_cursor (priv->layout, &strong))
8541 text_window_invalidate_rect (win, &strong);
8545 gtk_text_layout_get_cursor_locations (priv->layout, &iter,
8548 /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
8549 * ignoring the text direction be exposing both sides of the cursor
8552 draw_arrow = (strong.x != weak.x || strong.y != weak.y);
8554 gtk_widget_style_get (win->widget,
8555 "cursor-aspect-ratio", &cursor_aspect_ratio,
8558 stem_width = strong.height * cursor_aspect_ratio + 1;
8559 arrow_width = stem_width + 1;
8561 strong.width = stem_width;
8563 /* round up to the next even number */
8567 strong.x -= stem_width / 2;
8568 strong.width += stem_width;
8572 strong.x -= arrow_width;
8573 strong.width += arrow_width * 2;
8576 text_window_invalidate_rect (win, &strong);
8578 if (draw_arrow) /* == have weak */
8580 stem_width = weak.height * cursor_aspect_ratio + 1;
8581 arrow_width = stem_width + 1;
8583 weak.width = stem_width;
8585 /* round up to the next even number */
8589 weak.x -= stem_width / 2;
8590 weak.width += stem_width;
8592 weak.x -= arrow_width;
8593 weak.width += arrow_width * 2;
8595 text_window_invalidate_rect (win, &weak);
8600 text_window_get_width (GtkTextWindow *win)
8602 return win->allocation.width;
8606 text_window_get_height (GtkTextWindow *win)
8608 return win->allocation.height;
8615 * gtk_text_view_get_window:
8616 * @text_view: a #GtkTextView
8617 * @win: window to get
8619 * Retrieves the #GdkWindow corresponding to an area of the text view;
8620 * possible windows include the overall widget window, child windows
8621 * on the left, right, top, bottom, and the window that displays the
8622 * text buffer. Windows are %NULL and nonexistent if their width or
8623 * height is 0, and are nonexistent before the widget has been
8626 * Return value: (transfer none): a #GdkWindow, or %NULL
8629 gtk_text_view_get_window (GtkTextView *text_view,
8630 GtkTextWindowType win)
8632 GtkTextViewPrivate *priv = text_view->priv;
8634 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
8638 case GTK_TEXT_WINDOW_WIDGET:
8639 return gtk_widget_get_window (GTK_WIDGET (text_view));
8642 case GTK_TEXT_WINDOW_TEXT:
8643 return priv->text_window->bin_window;
8646 case GTK_TEXT_WINDOW_LEFT:
8647 if (priv->left_window)
8648 return priv->left_window->bin_window;
8653 case GTK_TEXT_WINDOW_RIGHT:
8654 if (priv->right_window)
8655 return priv->right_window->bin_window;
8660 case GTK_TEXT_WINDOW_TOP:
8661 if (priv->top_window)
8662 return priv->top_window->bin_window;
8667 case GTK_TEXT_WINDOW_BOTTOM:
8668 if (priv->bottom_window)
8669 return priv->bottom_window->bin_window;
8674 case GTK_TEXT_WINDOW_PRIVATE:
8675 g_warning ("%s: You can't get GTK_TEXT_WINDOW_PRIVATE, it has \"PRIVATE\" in the name because it is private.", G_STRFUNC);
8680 g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8685 * gtk_text_view_get_window_type:
8686 * @text_view: a #GtkTextView
8687 * @window: a window type
8689 * Usually used to find out which window an event corresponds to.
8690 * If you connect to an event signal on @text_view, this function
8691 * should be called on <literal>event->window</literal> to
8692 * see which window it was.
8694 * Return value: the window type.
8697 gtk_text_view_get_window_type (GtkTextView *text_view,
8702 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
8703 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
8705 if (window == gtk_widget_get_window (GTK_WIDGET (text_view)))
8706 return GTK_TEXT_WINDOW_WIDGET;
8708 win = g_object_get_qdata (G_OBJECT (window),
8709 g_quark_try_string ("gtk-text-view-text-window"));
8715 return GTK_TEXT_WINDOW_PRIVATE;
8720 buffer_to_widget (GtkTextView *text_view,
8726 GtkTextViewPrivate *priv = text_view->priv;
8730 *window_x = buffer_x - priv->xoffset;
8731 *window_x += priv->text_window->allocation.x;
8736 *window_y = buffer_y - priv->yoffset;
8737 *window_y += priv->text_window->allocation.y;
8742 widget_to_text_window (GtkTextWindow *win,
8749 *window_x = widget_x - win->allocation.x;
8752 *window_y = widget_y - win->allocation.y;
8756 buffer_to_text_window (GtkTextView *text_view,
8765 g_warning ("Attempt to convert text buffer coordinates to coordinates "
8766 "for a nonexistent or private child window of GtkTextView");
8770 buffer_to_widget (text_view,
8772 window_x, window_y);
8774 widget_to_text_window (win,
8775 window_x ? *window_x : 0,
8776 window_y ? *window_y : 0,
8782 * gtk_text_view_buffer_to_window_coords:
8783 * @text_view: a #GtkTextView
8784 * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8785 * @buffer_x: buffer x coordinate
8786 * @buffer_y: buffer y coordinate
8787 * @window_x: (out) (allow-none): window x coordinate return location or %NULL
8788 * @window_y: (out) (allow-none): window y coordinate return location or %NULL
8790 * Converts coordinate (@buffer_x, @buffer_y) to coordinates for the window
8791 * @win, and stores the result in (@window_x, @window_y).
8793 * Note that you can't convert coordinates for a nonexisting window (see
8794 * gtk_text_view_set_border_window_size()).
8797 gtk_text_view_buffer_to_window_coords (GtkTextView *text_view,
8798 GtkTextWindowType win,
8804 GtkTextViewPrivate *priv = text_view->priv;
8806 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8810 case GTK_TEXT_WINDOW_WIDGET:
8811 buffer_to_widget (text_view,
8813 window_x, window_y);
8816 case GTK_TEXT_WINDOW_TEXT:
8818 *window_x = buffer_x - priv->xoffset;
8820 *window_y = buffer_y - priv->yoffset;
8823 case GTK_TEXT_WINDOW_LEFT:
8824 buffer_to_text_window (text_view,
8827 window_x, window_y);
8830 case GTK_TEXT_WINDOW_RIGHT:
8831 buffer_to_text_window (text_view,
8834 window_x, window_y);
8837 case GTK_TEXT_WINDOW_TOP:
8838 buffer_to_text_window (text_view,
8841 window_x, window_y);
8844 case GTK_TEXT_WINDOW_BOTTOM:
8845 buffer_to_text_window (text_view,
8846 priv->bottom_window,
8848 window_x, window_y);
8851 case GTK_TEXT_WINDOW_PRIVATE:
8852 g_warning ("%s: can't get coords for private windows", G_STRFUNC);
8856 g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
8862 widget_to_buffer (GtkTextView *text_view,
8868 GtkTextViewPrivate *priv = text_view->priv;
8872 *buffer_x = widget_x + priv->xoffset;
8873 *buffer_x -= priv->text_window->allocation.x;
8878 *buffer_y = widget_y + priv->yoffset;
8879 *buffer_y -= priv->text_window->allocation.y;
8884 text_window_to_widget (GtkTextWindow *win,
8891 *widget_x = window_x + win->allocation.x;
8894 *widget_y = window_y + win->allocation.y;
8898 text_window_to_buffer (GtkTextView *text_view,
8907 g_warning ("Attempt to convert GtkTextView buffer coordinates into "
8908 "coordinates for a nonexistent child window.");
8912 text_window_to_widget (win,
8918 widget_to_buffer (text_view,
8919 buffer_x ? *buffer_x : 0,
8920 buffer_y ? *buffer_y : 0,
8926 * gtk_text_view_window_to_buffer_coords:
8927 * @text_view: a #GtkTextView
8928 * @win: a #GtkTextWindowType except #GTK_TEXT_WINDOW_PRIVATE
8929 * @window_x: window x coordinate
8930 * @window_y: window y coordinate
8931 * @buffer_x: (out) (allow-none): buffer x coordinate return location or %NULL
8932 * @buffer_y: (out) (allow-none): buffer y coordinate return location or %NULL
8934 * Converts coordinates on the window identified by @win to buffer
8935 * coordinates, storing the result in (@buffer_x,@buffer_y).
8937 * Note that you can't convert coordinates for a nonexisting window (see
8938 * gtk_text_view_set_border_window_size()).
8941 gtk_text_view_window_to_buffer_coords (GtkTextView *text_view,
8942 GtkTextWindowType win,
8948 GtkTextViewPrivate *priv = text_view->priv;
8950 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
8954 case GTK_TEXT_WINDOW_WIDGET:
8955 widget_to_buffer (text_view,
8957 buffer_x, buffer_y);
8960 case GTK_TEXT_WINDOW_TEXT:
8962 *buffer_x = window_x + priv->xoffset;
8964 *buffer_y = window_y + priv->yoffset;
8967 case GTK_TEXT_WINDOW_LEFT:
8968 text_window_to_buffer (text_view,
8971 buffer_x, buffer_y);
8974 case GTK_TEXT_WINDOW_RIGHT:
8975 text_window_to_buffer (text_view,
8978 buffer_x, buffer_y);
8981 case GTK_TEXT_WINDOW_TOP:
8982 text_window_to_buffer (text_view,
8985 buffer_x, buffer_y);
8988 case GTK_TEXT_WINDOW_BOTTOM:
8989 text_window_to_buffer (text_view,
8990 priv->bottom_window,
8992 buffer_x, buffer_y);
8995 case GTK_TEXT_WINDOW_PRIVATE:
8996 g_warning ("%s: can't get coords for private windows", G_STRFUNC);
9000 g_warning ("%s: Unknown GtkTextWindowType", G_STRFUNC);
9006 set_window_width (GtkTextView *text_view,
9008 GtkTextWindowType type,
9009 GtkTextWindow **winp)
9015 text_window_free (*winp);
9017 gtk_widget_queue_resize (GTK_WIDGET (text_view));
9024 *winp = text_window_new (type,
9025 GTK_WIDGET (text_view),
9027 /* if the widget is already realized we need to realize the child manually */
9028 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9029 text_window_realize (*winp, GTK_WIDGET (text_view));
9033 if ((*winp)->requisition.width == width)
9036 (*winp)->requisition.width = width;
9039 gtk_widget_queue_resize (GTK_WIDGET (text_view));
9045 set_window_height (GtkTextView *text_view,
9047 GtkTextWindowType type,
9048 GtkTextWindow **winp)
9054 text_window_free (*winp);
9056 gtk_widget_queue_resize (GTK_WIDGET (text_view));
9063 *winp = text_window_new (type,
9064 GTK_WIDGET (text_view),
9067 /* if the widget is already realized we need to realize the child manually */
9068 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9069 text_window_realize (*winp, GTK_WIDGET (text_view));
9073 if ((*winp)->requisition.height == height)
9076 (*winp)->requisition.height = height;
9079 gtk_widget_queue_resize (GTK_WIDGET (text_view));
9084 * gtk_text_view_set_border_window_size:
9085 * @text_view: a #GtkTextView
9086 * @type: window to affect
9087 * @size: width or height of the window
9089 * Sets the width of %GTK_TEXT_WINDOW_LEFT or %GTK_TEXT_WINDOW_RIGHT,
9090 * or the height of %GTK_TEXT_WINDOW_TOP or %GTK_TEXT_WINDOW_BOTTOM.
9091 * Automatically destroys the corresponding window if the size is set
9092 * to 0, and creates the window if the size is set to non-zero. This
9093 * function can only be used for the "border windows," it doesn't work
9094 * with #GTK_TEXT_WINDOW_WIDGET, #GTK_TEXT_WINDOW_TEXT, or
9095 * #GTK_TEXT_WINDOW_PRIVATE.
9098 gtk_text_view_set_border_window_size (GtkTextView *text_view,
9099 GtkTextWindowType type,
9102 GtkTextViewPrivate *priv = text_view->priv;
9104 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9105 g_return_if_fail (size >= 0);
9109 case GTK_TEXT_WINDOW_LEFT:
9110 set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
9111 &priv->left_window);
9114 case GTK_TEXT_WINDOW_RIGHT:
9115 set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
9116 &priv->right_window);
9119 case GTK_TEXT_WINDOW_TOP:
9120 set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
9124 case GTK_TEXT_WINDOW_BOTTOM:
9125 set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
9126 &priv->bottom_window);
9130 g_warning ("Can only set size of left/right/top/bottom border windows with gtk_text_view_set_border_window_size()");
9136 * gtk_text_view_get_border_window_size:
9137 * @text_view: a #GtkTextView
9138 * @type: window to return size from
9140 * Gets the width of the specified border window. See
9141 * gtk_text_view_set_border_window_size().
9143 * Return value: width of window
9146 gtk_text_view_get_border_window_size (GtkTextView *text_view,
9147 GtkTextWindowType type)
9149 GtkTextViewPrivate *priv = text_view->priv;
9151 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
9155 case GTK_TEXT_WINDOW_LEFT:
9156 if (priv->left_window)
9157 return priv->left_window->requisition.width;
9160 case GTK_TEXT_WINDOW_RIGHT:
9161 if (priv->right_window)
9162 return priv->right_window->requisition.width;
9165 case GTK_TEXT_WINDOW_TOP:
9166 if (priv->top_window)
9167 return priv->top_window->requisition.height;
9170 case GTK_TEXT_WINDOW_BOTTOM:
9171 if (priv->bottom_window)
9172 return priv->bottom_window->requisition.height;
9176 g_warning ("Can only get size of left/right/top/bottom border windows with gtk_text_view_get_border_window_size()");
9187 static GtkTextViewChild*
9188 text_view_child_new_anchored (GtkWidget *child,
9189 GtkTextChildAnchor *anchor,
9190 GtkTextLayout *layout)
9192 GtkTextViewChild *vc;
9194 vc = g_new (GtkTextViewChild, 1);
9196 vc->type = GTK_TEXT_WINDOW_PRIVATE;
9198 vc->anchor = anchor;
9200 vc->from_top_of_line = 0;
9201 vc->from_left_of_buffer = 0;
9203 g_object_ref (vc->widget);
9204 g_object_ref (vc->anchor);
9206 g_object_set_data (G_OBJECT (child),
9207 I_("gtk-text-view-child"),
9210 gtk_text_child_anchor_register_child (anchor, child, layout);
9215 static GtkTextViewChild*
9216 text_view_child_new_window (GtkWidget *child,
9217 GtkTextWindowType type,
9221 GtkTextViewChild *vc;
9223 vc = g_new (GtkTextViewChild, 1);
9228 vc->from_top_of_line = 0;
9229 vc->from_left_of_buffer = 0;
9231 g_object_ref (vc->widget);
9237 g_object_set_data (G_OBJECT (child),
9238 I_("gtk-text-view-child"),
9245 text_view_child_free (GtkTextViewChild *child)
9247 g_object_set_data (G_OBJECT (child->widget),
9248 I_("gtk-text-view-child"), NULL);
9252 gtk_text_child_anchor_unregister_child (child->anchor,
9254 g_object_unref (child->anchor);
9257 g_object_unref (child->widget);
9263 text_view_child_set_parent_window (GtkTextView *text_view,
9264 GtkTextViewChild *vc)
9267 gtk_widget_set_parent_window (vc->widget,
9268 text_view->priv->text_window->bin_window);
9272 window = gtk_text_view_get_window (text_view,
9274 gtk_widget_set_parent_window (vc->widget, window);
9279 add_child (GtkTextView *text_view,
9280 GtkTextViewChild *vc)
9282 text_view->priv->children = g_slist_prepend (text_view->priv->children,
9285 if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
9286 text_view_child_set_parent_window (text_view, vc);
9288 gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
9292 * gtk_text_view_add_child_at_anchor:
9293 * @text_view: a #GtkTextView
9294 * @child: a #GtkWidget
9295 * @anchor: a #GtkTextChildAnchor in the #GtkTextBuffer for @text_view
9297 * Adds a child widget in the text buffer, at the given @anchor.
9300 gtk_text_view_add_child_at_anchor (GtkTextView *text_view,
9302 GtkTextChildAnchor *anchor)
9304 GtkTextViewChild *vc;
9306 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9307 g_return_if_fail (GTK_IS_WIDGET (child));
9308 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
9309 g_return_if_fail (gtk_widget_get_parent (child) == NULL);
9311 gtk_text_view_ensure_layout (text_view);
9313 vc = text_view_child_new_anchored (child, anchor,
9314 text_view->priv->layout);
9316 add_child (text_view, vc);
9318 g_assert (vc->widget == child);
9319 g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9323 * gtk_text_view_add_child_in_window:
9324 * @text_view: a #GtkTextView
9325 * @child: a #GtkWidget
9326 * @which_window: which window the child should appear in
9327 * @xpos: X position of child in window coordinates
9328 * @ypos: Y position of child in window coordinates
9330 * Adds a child at fixed coordinates in one of the text widget's
9331 * windows. The window must have nonzero size (see
9332 * gtk_text_view_set_border_window_size()). Note that the child
9333 * coordinates are given relative to the #GdkWindow in question, and
9334 * that these coordinates have no sane relationship to scrolling. When
9335 * placing a child in #GTK_TEXT_WINDOW_WIDGET, scrolling is
9336 * irrelevant, the child floats above all scrollable areas. But when
9337 * placing a child in one of the scrollable windows (border windows or
9338 * text window), you'll need to compute the child's correct position
9339 * in buffer coordinates any time scrolling occurs or buffer changes
9340 * occur, and then call gtk_text_view_move_child() to update the
9341 * child's position. Unfortunately there's no good way to detect that
9342 * scrolling has occurred, using the current API; a possible hack
9343 * would be to update all child positions when the scroll adjustments
9344 * change or the text buffer changes. See bug 64518 on
9345 * bugzilla.gnome.org for status of fixing this issue.
9348 gtk_text_view_add_child_in_window (GtkTextView *text_view,
9350 GtkTextWindowType which_window,
9354 GtkTextViewChild *vc;
9356 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9357 g_return_if_fail (GTK_IS_WIDGET (child));
9358 g_return_if_fail (gtk_widget_get_parent (child) == NULL);
9360 vc = text_view_child_new_window (child, which_window,
9363 add_child (text_view, vc);
9365 g_assert (vc->widget == child);
9366 g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9370 * gtk_text_view_move_child:
9371 * @text_view: a #GtkTextView
9372 * @child: child widget already added to the text view
9373 * @xpos: new X position in window coordinates
9374 * @ypos: new Y position in window coordinates
9376 * Updates the position of a child, as for gtk_text_view_add_child_in_window().
9379 gtk_text_view_move_child (GtkTextView *text_view,
9384 GtkTextViewChild *vc;
9386 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
9387 g_return_if_fail (GTK_IS_WIDGET (child));
9388 g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view));
9390 vc = g_object_get_data (G_OBJECT (child),
9391 "gtk-text-view-child");
9393 g_assert (vc != NULL);
9395 if (vc->x == xpos &&
9402 if (gtk_widget_get_visible (child) &&
9403 gtk_widget_get_visible (GTK_WIDGET (text_view)))
9404 gtk_widget_queue_resize (child);
9408 /* Iterator operations */
9411 * gtk_text_view_forward_display_line:
9412 * @text_view: a #GtkTextView
9413 * @iter: a #GtkTextIter
9415 * Moves the given @iter forward by one display (wrapped) line.
9416 * A display line is different from a paragraph. Paragraphs are
9417 * separated by newlines or other paragraph separator characters.
9418 * Display lines are created by line-wrapping a paragraph. If
9419 * wrapping is turned off, display lines and paragraphs will be the
9420 * same. Display lines are divided differently for each view, since
9421 * they depend on the view's width; paragraphs are the same in all
9422 * views, since they depend on the contents of the #GtkTextBuffer.
9424 * Return value: %TRUE if @iter was moved and is not on the end iterator
9427 gtk_text_view_forward_display_line (GtkTextView *text_view,
9430 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9431 g_return_val_if_fail (iter != NULL, FALSE);
9433 gtk_text_view_ensure_layout (text_view);
9435 return gtk_text_layout_move_iter_to_next_line (text_view->priv->layout, iter);
9439 * gtk_text_view_backward_display_line:
9440 * @text_view: a #GtkTextView
9441 * @iter: a #GtkTextIter
9443 * Moves the given @iter backward by one display (wrapped) line.
9444 * A display line is different from a paragraph. Paragraphs are
9445 * separated by newlines or other paragraph separator characters.
9446 * Display lines are created by line-wrapping a paragraph. If
9447 * wrapping is turned off, display lines and paragraphs will be the
9448 * same. Display lines are divided differently for each view, since
9449 * they depend on the view's width; paragraphs are the same in all
9450 * views, since they depend on the contents of the #GtkTextBuffer.
9452 * Return value: %TRUE if @iter was moved and is not on the end iterator
9455 gtk_text_view_backward_display_line (GtkTextView *text_view,
9458 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9459 g_return_val_if_fail (iter != NULL, FALSE);
9461 gtk_text_view_ensure_layout (text_view);
9463 return gtk_text_layout_move_iter_to_previous_line (text_view->priv->layout, iter);
9467 * gtk_text_view_forward_display_line_end:
9468 * @text_view: a #GtkTextView
9469 * @iter: a #GtkTextIter
9471 * Moves the given @iter forward to the next display line end.
9472 * A display line is different from a paragraph. Paragraphs are
9473 * separated by newlines or other paragraph separator characters.
9474 * Display lines are created by line-wrapping a paragraph. If
9475 * wrapping is turned off, display lines and paragraphs will be the
9476 * same. Display lines are divided differently for each view, since
9477 * they depend on the view's width; paragraphs are the same in all
9478 * views, since they depend on the contents of the #GtkTextBuffer.
9480 * Return value: %TRUE if @iter was moved and is not on the end iterator
9483 gtk_text_view_forward_display_line_end (GtkTextView *text_view,
9486 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9487 g_return_val_if_fail (iter != NULL, FALSE);
9489 gtk_text_view_ensure_layout (text_view);
9491 return gtk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, 1);
9495 * gtk_text_view_backward_display_line_start:
9496 * @text_view: a #GtkTextView
9497 * @iter: a #GtkTextIter
9499 * Moves the given @iter backward to the next display line start.
9500 * A display line is different from a paragraph. Paragraphs are
9501 * separated by newlines or other paragraph separator characters.
9502 * Display lines are created by line-wrapping a paragraph. If
9503 * wrapping is turned off, display lines and paragraphs will be the
9504 * same. Display lines are divided differently for each view, since
9505 * they depend on the view's width; paragraphs are the same in all
9506 * views, since they depend on the contents of the #GtkTextBuffer.
9508 * Return value: %TRUE if @iter was moved and is not on the end iterator
9511 gtk_text_view_backward_display_line_start (GtkTextView *text_view,
9514 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9515 g_return_val_if_fail (iter != NULL, FALSE);
9517 gtk_text_view_ensure_layout (text_view);
9519 return gtk_text_layout_move_iter_to_line_end (text_view->priv->layout, iter, -1);
9523 * gtk_text_view_starts_display_line:
9524 * @text_view: a #GtkTextView
9525 * @iter: a #GtkTextIter
9527 * Determines whether @iter is at the start of a display line.
9528 * See gtk_text_view_forward_display_line() for an explanation of
9529 * display lines vs. paragraphs.
9531 * Return value: %TRUE if @iter begins a wrapped line
9534 gtk_text_view_starts_display_line (GtkTextView *text_view,
9535 const GtkTextIter *iter)
9537 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9538 g_return_val_if_fail (iter != NULL, FALSE);
9540 gtk_text_view_ensure_layout (text_view);
9542 return gtk_text_layout_iter_starts_line (text_view->priv->layout, iter);
9546 * gtk_text_view_move_visually:
9547 * @text_view: a #GtkTextView
9548 * @iter: a #GtkTextIter
9549 * @count: number of characters to move (negative moves left,
9550 * positive moves right)
9552 * Move the iterator a given number of characters visually, treating
9553 * it as the strong cursor position. If @count is positive, then the
9554 * new strong cursor position will be @count positions to the right of
9555 * the old cursor position. If @count is negative then the new strong
9556 * cursor position will be @count positions to the left of the old
9559 * In the presence of bi-directional text, the correspondence
9560 * between logical and visual order will depend on the direction
9561 * of the current run, and there may be jumps when the cursor
9562 * is moved off of the end of a run.
9564 * Return value: %TRUE if @iter moved and is not on the end iterator
9567 gtk_text_view_move_visually (GtkTextView *text_view,
9571 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
9572 g_return_val_if_fail (iter != NULL, FALSE);
9574 gtk_text_view_ensure_layout (text_view);
9576 return gtk_text_layout_move_iter_visually (text_view->priv->layout, iter, count);