1 /* GTK - The GIMP Toolkit
2 * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtkbindings.h"
32 #include "gtksignal.h"
34 #include "gtktextdisplay.h"
35 #include "gtktextview.h"
36 #include "gtkimmulticontext.h"
37 #include "gdk/gdkkeysyms.h"
38 #include "gtktexttypes.h"
41 #define FOCUS_EDGE_WIDTH 1
42 #define DRAG_THRESHOLD 8
44 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
45 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
56 SET_SCROLL_ADJUSTMENTS,
64 ARG_PIXELS_ABOVE_LINES,
65 ARG_PIXELS_BELOW_LINES,
66 ARG_PIXELS_INSIDE_WRAP,
72 static void gtk_text_view_init (GtkTextView *text_view);
73 static void gtk_text_view_class_init (GtkTextViewClass *klass);
74 static void gtk_text_view_destroy (GtkObject *object);
75 static void gtk_text_view_finalize (GObject *object);
76 static void gtk_text_view_set_arg (GtkObject *object,
79 static void gtk_text_view_get_arg (GtkObject *object,
82 static void gtk_text_view_size_request (GtkWidget *widget,
83 GtkRequisition *requisition);
84 static void gtk_text_view_size_allocate (GtkWidget *widget,
85 GtkAllocation *allocation);
86 static void gtk_text_view_realize (GtkWidget *widget);
87 static void gtk_text_view_unrealize (GtkWidget *widget);
88 static void gtk_text_view_style_set (GtkWidget *widget,
89 GtkStyle *previous_style);
90 static void gtk_text_view_direction_changed (GtkWidget *widget,
91 GtkTextDirection previous_direction);
92 static gint gtk_text_view_event (GtkWidget *widget,
94 static gint gtk_text_view_key_press_event (GtkWidget *widget,
96 static gint gtk_text_view_key_release_event (GtkWidget *widget,
98 static gint gtk_text_view_button_press_event (GtkWidget *widget,
99 GdkEventButton *event);
100 static gint gtk_text_view_button_release_event (GtkWidget *widget,
101 GdkEventButton *event);
102 static gint gtk_text_view_focus_in_event (GtkWidget *widget,
103 GdkEventFocus *event);
104 static gint gtk_text_view_focus_out_event (GtkWidget *widget,
105 GdkEventFocus *event);
106 static gint gtk_text_view_motion_event (GtkWidget *widget,
107 GdkEventMotion *event);
108 static void gtk_text_view_draw (GtkWidget *widget,
110 static gint gtk_text_view_expose_event (GtkWidget *widget,
111 GdkEventExpose *expose);
112 static void gtk_text_view_draw_focus (GtkWidget *widget);
114 /* Source side drag signals */
115 static void gtk_text_view_drag_begin (GtkWidget *widget,
116 GdkDragContext *context);
117 static void gtk_text_view_drag_end (GtkWidget *widget,
118 GdkDragContext *context);
119 static void gtk_text_view_drag_data_get (GtkWidget *widget,
120 GdkDragContext *context,
121 GtkSelectionData *selection_data,
124 static void gtk_text_view_drag_data_delete (GtkWidget *widget,
125 GdkDragContext *context);
127 /* Target side drag signals */
128 static void gtk_text_view_drag_leave (GtkWidget *widget,
129 GdkDragContext *context,
131 static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
132 GdkDragContext *context,
136 static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
137 GdkDragContext *context,
141 static void gtk_text_view_drag_data_received (GtkWidget *widget,
142 GdkDragContext *context,
145 GtkSelectionData *selection_data,
149 static void gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
151 GtkAdjustment *vadj);
153 static void gtk_text_view_move (GtkTextView *text_view,
154 GtkMovementStep step,
156 gboolean extend_selection);
157 static void gtk_text_view_set_anchor (GtkTextView *text_view);
158 static void gtk_text_view_scroll_pages (GtkTextView *text_view,
160 static void gtk_text_view_insert (GtkTextView *text_view,
162 static void gtk_text_view_delete (GtkTextView *text_view,
165 static void gtk_text_view_cut_clipboard (GtkTextView *text_view);
166 static void gtk_text_view_copy_clipboard (GtkTextView *text_view);
167 static void gtk_text_view_paste_clipboard (GtkTextView *text_view);
168 static void gtk_text_view_toggle_overwrite (GtkTextView *text_view);
169 static void gtk_text_view_unselect (GtkTextView *text_view);
171 static void gtk_text_view_validate_onscreen (GtkTextView *text_view);
172 static void gtk_text_view_get_first_para_iter (GtkTextView *text_view,
174 static void gtk_text_view_scroll_calc_now (GtkTextView *text_view);
175 static void gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
176 GtkTextAttributes *values,
178 static void gtk_text_view_ensure_layout (GtkTextView *text_view);
179 static void gtk_text_view_destroy_layout (GtkTextView *text_view);
180 static void gtk_text_view_start_selection_drag (GtkTextView *text_view,
181 const GtkTextIter *iter,
182 GdkEventButton *event);
183 static gboolean gtk_text_view_end_selection_drag (GtkTextView *text_view,
184 GdkEventButton *event);
185 static void gtk_text_view_start_selection_dnd (GtkTextView *text_view,
186 const GtkTextIter *iter,
187 GdkEventMotion *event);
188 static void gtk_text_view_start_cursor_blink (GtkTextView *text_view);
189 static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view);
191 static void gtk_text_view_value_changed (GtkAdjustment *adj,
193 static void gtk_text_view_commit_handler (GtkIMContext *context,
195 GtkTextView *text_view);
197 static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
198 const GtkTextIter *location,
201 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
204 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
208 static GtkAdjustment* get_hadjustment (GtkTextView *text_view);
209 static GtkAdjustment* get_vadjustment (GtkTextView *text_view);
211 /* Container methods */
212 static void gtk_text_view_add (GtkContainer *container,
214 static void gtk_text_view_remove (GtkContainer *container,
216 static void gtk_text_view_forall (GtkContainer *container,
217 gboolean include_internals,
218 GtkCallback callback,
219 gpointer callback_data);
221 /* FIXME probably need the focus methods. */
223 typedef struct _GtkTextViewChild GtkTextViewChild;
225 struct _GtkTextViewChild
229 GtkTextChildAnchor *anchor;
231 /* These are ignored if anchor != NULL */
232 GtkTextWindowType type;
237 static GtkTextViewChild* text_view_child_new_anchored (GtkWidget *child,
238 GtkTextChildAnchor *anchor);
239 static GtkTextViewChild* text_view_child_new_window (GtkWidget *child,
240 GtkTextWindowType type,
243 static void text_view_child_free (GtkTextViewChild *child);
245 static void text_view_child_realize (GtkTextView *text_view,
246 GtkTextViewChild *child);
247 static void text_view_child_unrealize (GtkTextViewChild *child);
249 struct _GtkTextWindow
251 GtkTextWindowType type;
254 GdkWindow *bin_window;
255 GtkRequisition requisition;
256 GdkRectangle allocation;
259 static GtkTextWindow *text_window_new (GtkTextWindowType type,
262 gint height_request);
263 static void text_window_free (GtkTextWindow *win);
264 static void text_window_realize (GtkTextWindow *win,
266 static void text_window_unrealize (GtkTextWindow *win);
267 static void text_window_size_allocate (GtkTextWindow *win,
269 static void text_window_scroll (GtkTextWindow *win,
272 static void text_window_invalidate_rect (GtkTextWindow *win,
275 static gint text_window_get_width (GtkTextWindow *win);
276 static gint text_window_get_height (GtkTextWindow *win);
277 static void text_window_get_allocation (GtkTextWindow *win,
284 TARGET_COMPOUND_TEXT,
288 static GtkTargetEntry target_table[] = {
289 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
290 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
291 { "TEXT", 0, TARGET_TEXT },
292 { "text/plain", 0, TARGET_STRING },
293 { "STRING", 0, TARGET_STRING }
296 static GtkContainerClass *parent_class = NULL;
297 static guint signals[LAST_SIGNAL] = { 0 };
300 gtk_text_view_get_type (void)
302 static GtkType our_type = 0;
306 static const GtkTypeInfo our_info =
309 sizeof (GtkTextView),
310 sizeof (GtkTextViewClass),
311 (GtkClassInitFunc) gtk_text_view_class_init,
312 (GtkObjectInitFunc) gtk_text_view_init,
313 /* reserved_1 */ NULL,
314 /* reserved_2 */ NULL,
315 (GtkClassInitFunc) NULL
318 our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
325 add_move_binding (GtkBindingSet *binding_set,
328 GtkMovementStep step,
331 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
333 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
337 GTK_TYPE_BOOL, FALSE);
339 /* Selection-extending version */
340 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
344 GTK_TYPE_BOOL, TRUE);
348 gtk_text_view_class_init (GtkTextViewClass *klass)
350 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
351 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
352 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
353 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
354 GtkBindingSet *binding_set;
356 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
361 gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
362 GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
363 gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
364 GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
365 gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
366 GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
367 gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
368 GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
369 gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
370 GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
371 gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
372 GTK_ARG_READWRITE, ARG_EDITABLE);
373 gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
374 GTK_ARG_READWRITE, ARG_WRAP_MODE);
382 gtk_signal_new ("move",
383 GTK_RUN_LAST | GTK_RUN_ACTION,
384 GTK_CLASS_TYPE (object_class),
385 GTK_SIGNAL_OFFSET (GtkTextViewClass, move),
386 gtk_marshal_VOID__ENUM_INT_BOOLEAN,
387 GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
389 signals[SET_ANCHOR] =
390 gtk_signal_new ("set_anchor",
391 GTK_RUN_LAST | GTK_RUN_ACTION,
392 GTK_CLASS_TYPE (object_class),
393 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
394 gtk_marshal_VOID__VOID,
398 gtk_signal_new ("insert",
399 GTK_RUN_LAST | GTK_RUN_ACTION,
400 GTK_CLASS_TYPE (object_class),
401 GTK_SIGNAL_OFFSET (GtkTextViewClass, insert),
402 gtk_marshal_VOID__POINTER,
403 GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
406 gtk_signal_new ("delete",
407 GTK_RUN_LAST | GTK_RUN_ACTION,
408 GTK_CLASS_TYPE (object_class),
409 GTK_SIGNAL_OFFSET (GtkTextViewClass, delete),
410 gtk_marshal_VOID__ENUM_INT,
411 GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
413 signals[CUT_CLIPBOARD] =
414 gtk_signal_new ("cut_clipboard",
415 GTK_RUN_LAST | GTK_RUN_ACTION,
416 GTK_CLASS_TYPE (object_class),
417 GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_clipboard),
418 gtk_marshal_VOID__VOID,
421 signals[COPY_CLIPBOARD] =
422 gtk_signal_new ("copy_clipboard",
423 GTK_RUN_LAST | GTK_RUN_ACTION,
424 GTK_CLASS_TYPE (object_class),
425 GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_clipboard),
426 gtk_marshal_VOID__VOID,
429 signals[PASTE_CLIPBOARD] =
430 gtk_signal_new ("paste_clipboard",
431 GTK_RUN_LAST | GTK_RUN_ACTION,
432 GTK_CLASS_TYPE (object_class),
433 GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_clipboard),
434 gtk_marshal_VOID__VOID,
437 signals[TOGGLE_OVERWRITE] =
438 gtk_signal_new ("toggle_overwrite",
439 GTK_RUN_LAST | GTK_RUN_ACTION,
440 GTK_CLASS_TYPE (object_class),
441 GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
442 gtk_marshal_VOID__VOID,
445 signals[SET_SCROLL_ADJUSTMENTS] = widget_class->set_scroll_adjustments_signal =
446 gtk_signal_new ("set_scroll_adjustments",
448 GTK_CLASS_TYPE (object_class),
449 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
450 gtk_marshal_VOID__POINTER_POINTER,
451 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
453 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
459 binding_set = gtk_binding_set_by_class (klass);
461 /* Moving the insertion point */
462 add_move_binding (binding_set, GDK_Right, 0,
463 GTK_MOVEMENT_POSITIONS, 1);
465 add_move_binding (binding_set, GDK_Left, 0,
466 GTK_MOVEMENT_POSITIONS, -1);
468 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
469 GTK_MOVEMENT_CHARS, 1);
471 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
472 GTK_MOVEMENT_CHARS, -1);
474 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
475 GTK_MOVEMENT_WORDS, 1);
477 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
478 GTK_MOVEMENT_WORDS, -1);
480 /* Eventually we want to move by display lines, not paragraphs */
481 add_move_binding (binding_set, GDK_Up, 0,
482 GTK_MOVEMENT_DISPLAY_LINES, -1);
484 add_move_binding (binding_set, GDK_Down, 0,
485 GTK_MOVEMENT_DISPLAY_LINES, 1);
487 add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
488 GTK_MOVEMENT_DISPLAY_LINES, -1);
490 add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
491 GTK_MOVEMENT_DISPLAY_LINES, 1);
493 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
494 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
496 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
497 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
499 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
500 GTK_MOVEMENT_WORDS, 1);
502 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
503 GTK_MOVEMENT_WORDS, -1);
505 add_move_binding (binding_set, GDK_Home, 0,
506 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
508 add_move_binding (binding_set, GDK_End, 0,
509 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
511 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
512 GTK_MOVEMENT_BUFFER_ENDS, -1);
514 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
515 GTK_MOVEMENT_BUFFER_ENDS, 1);
517 add_move_binding (binding_set, GDK_Page_Up, 0,
518 GTK_MOVEMENT_PAGES, -1);
520 add_move_binding (binding_set, GDK_Page_Down, 0,
521 GTK_MOVEMENT_PAGES, 1);
524 /* Setting the cut/paste/copy anchor */
525 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
529 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
531 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
534 gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
536 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
539 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
541 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
544 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
546 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
549 gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
551 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
554 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
556 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
559 gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
561 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
564 gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
566 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
569 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
571 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
573 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
575 GTK_TYPE_STRING, " ");
577 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
579 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
584 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
587 gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
590 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
591 "copy_clipboard", 0);
593 gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
594 "paste_clipboard", 0);
596 gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
597 "paste_clipboard", 0);
600 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
601 "toggle_overwrite", 0);
604 * Default handlers and virtual methods
606 object_class->set_arg = gtk_text_view_set_arg;
607 object_class->get_arg = gtk_text_view_get_arg;
609 object_class->destroy = gtk_text_view_destroy;
610 gobject_class->finalize = gtk_text_view_finalize;
612 widget_class->realize = gtk_text_view_realize;
613 widget_class->unrealize = gtk_text_view_unrealize;
614 widget_class->style_set = gtk_text_view_style_set;
615 widget_class->direction_changed = gtk_text_view_direction_changed;
616 widget_class->size_request = gtk_text_view_size_request;
617 widget_class->size_allocate = gtk_text_view_size_allocate;
618 widget_class->event = gtk_text_view_event;
619 widget_class->key_press_event = gtk_text_view_key_press_event;
620 widget_class->key_release_event = gtk_text_view_key_release_event;
621 widget_class->button_press_event = gtk_text_view_button_press_event;
622 widget_class->button_release_event = gtk_text_view_button_release_event;
623 widget_class->focus_in_event = gtk_text_view_focus_in_event;
624 widget_class->focus_out_event = gtk_text_view_focus_out_event;
625 widget_class->motion_notify_event = gtk_text_view_motion_event;
626 widget_class->expose_event = gtk_text_view_expose_event;
627 widget_class->draw = gtk_text_view_draw;
628 widget_class->draw_focus = gtk_text_view_draw_focus;
630 widget_class->drag_begin = gtk_text_view_drag_begin;
631 widget_class->drag_end = gtk_text_view_drag_end;
632 widget_class->drag_data_get = gtk_text_view_drag_data_get;
633 widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
635 widget_class->drag_leave = gtk_text_view_drag_leave;
636 widget_class->drag_motion = gtk_text_view_drag_motion;
637 widget_class->drag_drop = gtk_text_view_drag_drop;
638 widget_class->drag_data_received = gtk_text_view_drag_data_received;
640 container_class->add = gtk_text_view_add;
641 container_class->remove = gtk_text_view_remove;
642 container_class->forall = gtk_text_view_forall;
644 klass->move = gtk_text_view_move;
645 klass->set_anchor = gtk_text_view_set_anchor;
646 klass->insert = gtk_text_view_insert;
647 klass->delete = gtk_text_view_delete;
648 klass->cut_clipboard = gtk_text_view_cut_clipboard;
649 klass->copy_clipboard = gtk_text_view_copy_clipboard;
650 klass->paste_clipboard = gtk_text_view_paste_clipboard;
651 klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
652 klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
656 gtk_text_view_init (GtkTextView *text_view)
660 widget = GTK_WIDGET (text_view);
662 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
664 text_view->wrap_mode = GTK_WRAPMODE_NONE;
666 gtk_drag_dest_set (widget,
667 GTK_DEST_DEFAULT_DROP,
668 target_table, G_N_ELEMENTS (target_table),
669 GDK_ACTION_COPY | GDK_ACTION_MOVE);
671 text_view->virtual_cursor_x = -1;
672 text_view->virtual_cursor_y = -1;
674 /* This object is completely private. No external entity can gain a reference
675 * to it; so we create it here and destroy it in finalize().
677 text_view->im_context = gtk_im_multicontext_new ();
679 gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
680 GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
682 text_view->editable = TRUE;
683 text_view->cursor_visible = TRUE;
685 text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
688 text_view->drag_start_x = -1;
689 text_view->drag_start_y = -1;
693 gtk_text_view_new (void)
695 return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
699 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
701 GtkTextView *text_view;
703 text_view = (GtkTextView*)gtk_text_view_new ();
705 gtk_text_view_set_buffer (text_view, buffer);
707 return GTK_WIDGET (text_view);
711 gtk_text_view_set_buffer (GtkTextView *text_view,
712 GtkTextBuffer *buffer)
714 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
715 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
717 if (text_view->buffer == buffer)
720 if (text_view->buffer != NULL)
722 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer),
723 gtk_text_view_mark_set_handler, text_view);
724 gtk_object_unref (GTK_OBJECT (text_view->buffer));
725 text_view->dnd_mark = NULL;
728 text_view->buffer = buffer;
734 gtk_object_ref (GTK_OBJECT (buffer));
735 gtk_object_sink (GTK_OBJECT (buffer));
737 if (text_view->layout)
738 gtk_text_layout_set_buffer (text_view->layout, buffer);
740 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
742 text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
746 text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
750 text_view->first_para_pixels = 0;
752 gtk_signal_connect (GTK_OBJECT (text_view->buffer), "mark_set",
753 gtk_text_view_mark_set_handler, text_view);
756 if (GTK_WIDGET_VISIBLE (text_view))
757 gtk_widget_queue_draw (GTK_WIDGET (text_view));
761 gtk_text_view_get_buffer (GtkTextView *text_view)
763 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
765 return text_view->buffer;
769 gtk_text_view_get_iter_at_location (GtkTextView *text_view,
773 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
774 g_return_if_fail (iter != NULL);
775 g_return_if_fail (text_view->layout != NULL);
777 gtk_text_layout_get_iter_at_pixel (text_view->layout,
784 gtk_text_view_get_iter_location (GtkTextView *text_view,
785 const GtkTextIter *iter,
786 GdkRectangle *location)
788 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
789 g_return_if_fail (gtk_text_iter_get_buffer (iter) == text_view->buffer);
791 gtk_text_layout_get_iter_location (text_view->layout, iter, location);
795 gtk_text_view_get_line_yrange (GtkTextView *text_view,
796 const GtkTextIter *iter,
800 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
801 g_return_if_fail (gtk_text_iter_get_buffer (iter) == text_view->buffer);
803 gtk_text_layout_get_line_yrange (text_view->layout,
810 gtk_text_view_get_line_at_y (GtkTextView *text_view,
811 GtkTextIter *target_iter,
815 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
817 gtk_text_layout_get_line_at_y (text_view->layout,
824 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
826 /* We don't really want to clamp to upper; we want to clamp to
827 upper - page_size which is the highest value the scrollbar
828 will let us reach. */
829 if (val > (adj->upper - adj->page_size))
830 val = adj->upper - adj->page_size;
832 if (val < adj->lower)
835 gtk_adjustment_set_value (adj, val);
839 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
850 gboolean retval = FALSE;
853 gint current_x_scroll, current_y_scroll;
855 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
856 g_return_val_if_fail (mark != NULL, FALSE);
858 widget = GTK_WIDGET (text_view);
860 if (!GTK_WIDGET_MAPPED (widget))
862 g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
866 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
868 gtk_text_layout_get_iter_location (text_view->layout,
872 /* Be sure the scroll region is up-to-date */
873 gtk_text_view_scroll_calc_now (text_view);
875 current_x_scroll = text_view->xoffset;
876 current_y_scroll = text_view->yoffset;
878 screen.x = current_x_scroll;
879 screen.y = current_y_scroll;
880 screen.width = SCREEN_WIDTH (widget);
881 screen.height = SCREEN_HEIGHT (widget);
884 /* Clamp margin so it's not too large. */
885 gint small_dimension = MIN (screen.width, screen.height);
888 if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
889 margin = (small_dimension/2 - 5);
894 /* make sure rectangle fits in the leftover space */
896 max_rect_dim = MAX (rect.width, rect.height);
898 if (max_rect_dim > (small_dimension - margin*2))
899 margin -= max_rect_dim - (small_dimension - margin*2);
905 g_assert (margin >= 0);
910 screen.width -= margin*2;
911 screen.height -= margin*2;
913 screen_bottom = screen.y + screen.height;
914 screen_right = screen.x + screen.width;
916 /* Vertical scroll (only vertical gets adjusted) */
919 if (rect.y < screen.y)
921 gint scroll_dest = rect.y;
922 scroll_inc = (scroll_dest - screen.y) * percentage;
924 else if ((rect.y + rect.height) > screen_bottom)
926 gint scroll_dest = rect.y + rect.height;
927 scroll_inc = (scroll_dest - screen_bottom) * percentage;
932 set_adjustment_clamped (get_vadjustment (text_view),
933 current_y_scroll + scroll_inc);
937 /* Horizontal scroll */
940 if (rect.x < screen.x)
942 gint scroll_dest = rect.x;
943 scroll_inc = scroll_dest - screen.x;
945 else if ((rect.x + rect.width) > screen_right)
947 gint scroll_dest = rect.x + rect.width;
948 scroll_inc = scroll_dest - screen_right;
953 set_adjustment_clamped (get_hadjustment (text_view),
954 current_x_scroll + scroll_inc);
962 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
964 gint mark_within_margin)
966 g_return_val_if_fail (mark_within_margin >= 0, FALSE);
968 return gtk_text_view_scroll_to_mark_adjusted (text_view, mark,
969 mark_within_margin, 1.0);
973 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
975 GdkRectangle visible_rect;
976 gtk_text_view_get_visible_rect (text_view, &visible_rect);
978 return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
980 visible_rect.y + visible_rect.height);
984 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
989 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
990 g_return_val_if_fail (mark != NULL, FALSE);
992 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
994 if (clamp_iter_onscreen (text_view, &iter))
996 gtk_text_buffer_move_mark (text_view->buffer, mark, &iter);
1004 gtk_text_view_get_visible_rect (GtkTextView *text_view,
1005 GdkRectangle *visible_rect)
1009 g_return_if_fail (text_view != NULL);
1010 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1012 widget = GTK_WIDGET (text_view);
1016 visible_rect->x = text_view->xoffset;
1017 visible_rect->y = text_view->yoffset;
1018 visible_rect->width = SCREEN_WIDTH (widget);
1019 visible_rect->height = SCREEN_HEIGHT (widget);
1024 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
1025 GtkWrapMode wrap_mode)
1027 g_return_if_fail (text_view != NULL);
1028 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1030 if (text_view->wrap_mode != wrap_mode)
1032 text_view->wrap_mode = wrap_mode;
1034 if (text_view->layout)
1036 text_view->layout->default_style->wrap_mode = wrap_mode;
1037 gtk_text_layout_default_style_changed (text_view->layout);
1043 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
1045 g_return_val_if_fail (text_view != NULL, GTK_WRAPMODE_NONE);
1046 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAPMODE_NONE);
1048 return text_view->wrap_mode;
1052 gtk_text_view_set_editable (GtkTextView *text_view,
1055 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1057 if (text_view->editable != setting)
1059 text_view->editable = setting;
1061 if (text_view->layout)
1063 text_view->layout->default_style->editable = text_view->editable;
1064 gtk_text_layout_default_style_changed (text_view->layout);
1070 gtk_text_view_get_editable (GtkTextView *text_view)
1072 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1074 return text_view->editable;
1078 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
1081 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
1083 setting = (setting != FALSE);
1085 if (text_view->cursor_visible != setting)
1087 text_view->cursor_visible = setting;
1089 if (GTK_WIDGET_HAS_FOCUS (text_view))
1091 if (text_view->layout)
1093 gtk_text_layout_set_cursor_visible (text_view->layout, setting);
1096 gtk_text_view_start_cursor_blink (text_view);
1098 gtk_text_view_stop_cursor_blink (text_view);
1105 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
1107 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1109 return text_view->cursor_visible;
1114 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
1118 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1120 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1121 gtk_text_buffer_get_mark (text_view->buffer,
1124 if (clamp_iter_onscreen (text_view, &insert))
1126 gtk_text_buffer_place_cursor (text_view->buffer, &insert);
1134 gtk_text_view_destroy (GtkObject *object)
1136 GtkTextView *text_view;
1138 text_view = GTK_TEXT_VIEW (object);
1140 gtk_text_view_destroy_layout (text_view);
1141 gtk_text_view_set_buffer (text_view, NULL);
1143 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1147 gtk_text_view_finalize (GObject *object)
1149 GtkTextView *text_view;
1151 text_view = GTK_TEXT_VIEW (object);
1153 if (text_view->hadjustment)
1154 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
1155 if (text_view->vadjustment)
1156 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
1158 text_window_free (text_view->text_window);
1160 if (text_view->left_window)
1161 text_window_free (text_view->left_window);
1163 if (text_view->top_window)
1164 text_window_free (text_view->top_window);
1166 if (text_view->right_window)
1167 text_window_free (text_view->right_window);
1169 if (text_view->bottom_window)
1170 text_window_free (text_view->bottom_window);
1172 gtk_object_unref (GTK_OBJECT (text_view->im_context));
1174 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1178 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1180 GtkTextView *text_view;
1182 text_view = GTK_TEXT_VIEW (object);
1186 case ARG_HEIGHT_LINES:
1189 case ARG_WIDTH_COLUMNS:
1192 case ARG_PIXELS_ABOVE_LINES:
1195 case ARG_PIXELS_BELOW_LINES:
1198 case ARG_PIXELS_INSIDE_WRAP:
1208 g_assert_not_reached ();
1214 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1216 GtkTextView *text_view;
1218 text_view = GTK_TEXT_VIEW (object);
1222 case ARG_HEIGHT_LINES:
1225 case ARG_WIDTH_COLUMNS:
1228 case ARG_PIXELS_ABOVE_LINES:
1231 case ARG_PIXELS_BELOW_LINES:
1234 case ARG_PIXELS_INSIDE_WRAP:
1244 arg->type = GTK_TYPE_INVALID;
1250 gtk_text_view_size_request (GtkWidget *widget,
1251 GtkRequisition *requisition)
1253 GtkTextView *text_view;
1255 text_view = GTK_TEXT_VIEW (widget);
1257 requisition->width = text_view->text_window->requisition.width + FOCUS_EDGE_WIDTH * 2;
1258 requisition->height = text_view->text_window->requisition.height + FOCUS_EDGE_WIDTH * 2;
1260 if (text_view->left_window)
1261 requisition->width += text_view->left_window->requisition.width;
1263 if (text_view->right_window)
1264 requisition->width += text_view->right_window->requisition.width;
1266 if (text_view->top_window)
1267 requisition->height += text_view->top_window->requisition.height;
1269 if (text_view->bottom_window)
1270 requisition->height += text_view->bottom_window->requisition.height;
1274 gtk_text_view_size_allocate (GtkWidget *widget,
1275 GtkAllocation *allocation)
1277 GtkTextView *text_view;
1278 GtkTextIter first_para;
1280 GtkAdjustment *vadj;
1281 gboolean yoffset_changed = FALSE;
1283 GdkRectangle text_rect;
1284 GdkRectangle left_rect;
1285 GdkRectangle right_rect;
1286 GdkRectangle top_rect;
1287 GdkRectangle bottom_rect;
1289 text_view = GTK_TEXT_VIEW (widget);
1291 widget->allocation = *allocation;
1293 if (GTK_WIDGET_REALIZED (widget))
1295 gdk_window_move_resize (widget->window,
1296 allocation->x, allocation->y,
1297 allocation->width, allocation->height);
1300 /* distribute width/height among child windows. Ensure all
1301 * windows get at least a 1x1 allocation.
1304 width = allocation->width - FOCUS_EDGE_WIDTH * 2;
1306 if (text_view->left_window)
1307 left_rect.width = text_view->left_window->requisition.width;
1309 left_rect.width = 1;
1311 width -= left_rect.width;
1313 if (text_view->right_window)
1314 right_rect.width = text_view->right_window->requisition.width;
1316 right_rect.width = 1;
1318 width -= right_rect.width;
1320 text_rect.width = MAX (1, width);
1322 top_rect.width = text_rect.width;
1323 bottom_rect.width = text_rect.width;
1326 height = allocation->height - FOCUS_EDGE_WIDTH * 2;
1328 if (text_view->top_window)
1329 top_rect.height = text_view->top_window->requisition.height;
1331 top_rect.height = 1;
1333 height -= top_rect.height;
1335 if (text_view->bottom_window)
1336 bottom_rect.height = text_view->bottom_window->requisition.height;
1338 bottom_rect.height = 1;
1340 height -= bottom_rect.height;
1342 text_rect.height = MAX (1, height);
1344 left_rect.height = text_rect.height;
1345 right_rect.height = text_rect.height;
1348 left_rect.x = FOCUS_EDGE_WIDTH;
1349 top_rect.y = FOCUS_EDGE_WIDTH;
1351 text_rect.x = left_rect.x + left_rect.width;
1352 text_rect.y = top_rect.y + top_rect.height;
1354 left_rect.y = text_rect.y;
1355 right_rect.y = text_rect.y;
1357 top_rect.x = text_rect.x;
1358 bottom_rect.x = text_rect.x;
1360 right_rect.x = text_rect.x + text_rect.width;
1361 bottom_rect.y = text_rect.y + text_rect.height;
1363 text_window_size_allocate (text_view->text_window,
1366 if (text_view->left_window)
1367 text_window_size_allocate (text_view->left_window,
1370 if (text_view->right_window)
1371 text_window_size_allocate (text_view->right_window,
1374 if (text_view->top_window)
1375 text_window_size_allocate (text_view->top_window,
1378 if (text_view->bottom_window)
1379 text_window_size_allocate (text_view->bottom_window,
1382 gtk_text_view_ensure_layout (text_view);
1383 gtk_text_layout_set_screen_width (text_view->layout,
1384 SCREEN_WIDTH (text_view));
1386 gtk_text_view_validate_onscreen (text_view);
1387 gtk_text_view_scroll_calc_now (text_view);
1389 /* Now adjust the value of the adjustment to keep the cursor at the
1390 * same place in the buffer
1392 gtk_text_view_get_first_para_iter (text_view, &first_para);
1393 gtk_text_layout_get_line_yrange (text_view->layout, &first_para, &y, NULL);
1395 y += text_view->first_para_pixels;
1397 /* Ensure h/v adj exist */
1398 get_hadjustment (text_view);
1399 get_vadjustment (text_view);
1401 vadj = text_view->vadjustment;
1402 if (y > vadj->upper - vadj->page_size)
1403 y = MAX (0, vadj->upper - vadj->page_size);
1405 if (y != text_view->yoffset)
1407 vadj->value = text_view->yoffset = y;
1408 yoffset_changed = TRUE;
1411 text_view->hadjustment->page_size = SCREEN_WIDTH (text_view);
1412 text_view->hadjustment->page_increment = SCREEN_WIDTH (text_view) / 2;
1413 text_view->hadjustment->lower = 0;
1414 text_view->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
1416 gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
1418 text_view->vadjustment->page_size = SCREEN_HEIGHT (text_view);
1419 text_view->vadjustment->page_increment = SCREEN_HEIGHT (text_view) / 2;
1420 text_view->vadjustment->lower = 0;
1421 text_view->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
1423 gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
1425 if (yoffset_changed)
1426 gtk_adjustment_value_changed (vadj);
1430 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
1433 gtk_text_buffer_get_iter_at_mark (text_view->buffer, iter,
1434 text_view->first_para_mark);
1438 gtk_text_view_validate_onscreen (GtkTextView *text_view)
1440 GtkWidget *widget = GTK_WIDGET (text_view);
1442 if (SCREEN_HEIGHT (widget) > 0)
1444 GtkTextIter first_para;
1445 gtk_text_view_get_first_para_iter (text_view, &first_para);
1446 gtk_text_layout_validate_yrange (text_view->layout,
1449 text_view->first_para_pixels +
1450 SCREEN_HEIGHT (widget));
1455 first_validate_callback (gpointer data)
1457 GtkTextView *text_view = data;
1459 gtk_text_view_validate_onscreen (text_view);
1461 text_view->first_validate_idle = 0;
1466 incremental_validate_callback (gpointer data)
1468 GtkTextView *text_view = data;
1470 gtk_text_layout_validate (text_view->layout, 2000);
1471 if (gtk_text_layout_is_valid (text_view->layout))
1473 text_view->incremental_validate_idle = 0;
1481 invalidated_handler (GtkTextLayout *layout,
1484 GtkTextView *text_view;
1486 text_view = GTK_TEXT_VIEW (data);
1488 if (!text_view->first_validate_idle)
1489 text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
1491 if (!text_view->incremental_validate_idle)
1492 text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
1496 changed_handler (GtkTextLayout *layout,
1502 GtkTextView *text_view;
1504 GdkRectangle visible_rect;
1505 GdkRectangle redraw_rect;
1507 text_view = GTK_TEXT_VIEW (data);
1508 widget = GTK_WIDGET (data);
1510 if (GTK_WIDGET_REALIZED (text_view))
1512 gtk_text_view_get_visible_rect (text_view, &visible_rect);
1514 redraw_rect.x = visible_rect.x;
1515 redraw_rect.width = visible_rect.width;
1516 redraw_rect.y = start_y;
1518 if (old_height == new_height)
1519 redraw_rect.height = old_height;
1521 redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
1523 if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
1525 redraw_rect.y -= text_view->yoffset;
1526 text_window_invalidate_rect (text_view->text_window,
1531 if (old_height != new_height)
1533 gboolean yoffset_changed = FALSE;
1535 if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
1537 text_view->yoffset += new_height - old_height;
1538 get_vadjustment (text_view)->value = text_view->yoffset;
1539 yoffset_changed = TRUE;
1542 gtk_text_view_scroll_calc_now (text_view);
1544 if (yoffset_changed)
1545 gtk_adjustment_value_changed (get_vadjustment (text_view));
1550 gtk_text_view_realize (GtkWidget *widget)
1552 GtkTextView *text_view;
1553 GdkWindowAttr attributes;
1554 gint attributes_mask;
1556 text_view = GTK_TEXT_VIEW (widget);
1557 GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
1559 attributes.window_type = GDK_WINDOW_CHILD;
1560 attributes.x = widget->allocation.x;
1561 attributes.y = widget->allocation.y;
1562 attributes.width = widget->allocation.width;
1563 attributes.height = widget->allocation.height;
1564 attributes.wclass = GDK_INPUT_OUTPUT;
1565 attributes.visual = gtk_widget_get_visual (widget);
1566 attributes.colormap = gtk_widget_get_colormap (widget);
1567 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
1569 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1571 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1572 &attributes, attributes_mask);
1573 gdk_window_set_user_data (widget->window, widget);
1575 /* must come before text_window_realize calls */
1576 widget->style = gtk_style_attach (widget->style, widget->window);
1578 gdk_window_set_background (widget->window,
1579 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1581 text_window_realize (text_view->text_window, widget->window);
1583 if (text_view->left_window)
1584 text_window_realize (text_view->left_window,
1587 if (text_view->top_window)
1588 text_window_realize (text_view->top_window,
1591 if (text_view->right_window)
1592 text_window_realize (text_view->right_window,
1595 if (text_view->bottom_window)
1596 text_window_realize (text_view->bottom_window,
1599 gtk_text_view_ensure_layout (text_view);
1603 gtk_text_view_unrealize (GtkWidget *widget)
1605 GtkTextView *text_view;
1607 text_view = GTK_TEXT_VIEW (widget);
1609 if (text_view->first_validate_idle)
1611 g_source_remove (text_view->first_validate_idle);
1612 text_view->first_validate_idle = 0;
1615 if (text_view->incremental_validate_idle)
1617 g_source_remove (text_view->incremental_validate_idle);
1618 text_view->incremental_validate_idle = 0;
1621 text_window_unrealize (text_view->text_window);
1623 if (text_view->left_window)
1624 text_window_unrealize (text_view->left_window);
1626 if (text_view->top_window)
1627 text_window_unrealize (text_view->top_window);
1629 if (text_view->right_window)
1630 text_window_unrealize (text_view->right_window);
1632 if (text_view->bottom_window)
1633 text_window_unrealize (text_view->bottom_window);
1635 gtk_text_view_destroy_layout (text_view);
1637 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1641 gtk_text_view_style_set (GtkWidget *widget,
1642 GtkStyle *previous_style)
1644 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1646 if (GTK_WIDGET_REALIZED (widget))
1648 gdk_window_set_background (widget->window,
1649 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1651 gdk_window_set_background (text_view->text_window->bin_window,
1652 &widget->style->base[GTK_WIDGET_STATE (widget)]);
1654 if (text_view->left_window)
1655 gdk_window_set_background (text_view->left_window->bin_window,
1656 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1657 if (text_view->right_window)
1658 gdk_window_set_background (text_view->right_window->bin_window,
1659 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1661 if (text_view->top_window)
1662 gdk_window_set_background (text_view->top_window->bin_window,
1663 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1665 if (text_view->bottom_window)
1666 gdk_window_set_background (text_view->bottom_window->bin_window,
1667 &widget->style->bg[GTK_WIDGET_STATE (widget)]);
1669 gtk_text_view_set_attributes_from_style (text_view,
1670 text_view->layout->default_style,
1672 gtk_text_layout_default_style_changed (text_view->layout);
1677 gtk_text_view_direction_changed (GtkWidget *widget,
1678 GtkTextDirection previous_direction)
1680 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1682 if (text_view->layout)
1684 text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
1685 gtk_text_layout_default_style_changed (text_view->layout);
1694 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
1697 switch (event->type)
1699 case GDK_MOTION_NOTIFY:
1700 *x = event->motion.x;
1701 *y = event->motion.y;
1705 case GDK_BUTTON_PRESS:
1706 case GDK_2BUTTON_PRESS:
1707 case GDK_3BUTTON_PRESS:
1708 case GDK_BUTTON_RELEASE:
1709 *x = event->button.x;
1710 *y = event->button.y;
1715 case GDK_KEY_RELEASE:
1716 case GDK_ENTER_NOTIFY:
1717 case GDK_LEAVE_NOTIFY:
1718 case GDK_PROPERTY_NOTIFY:
1719 case GDK_SELECTION_CLEAR:
1720 case GDK_SELECTION_REQUEST:
1721 case GDK_SELECTION_NOTIFY:
1722 case GDK_PROXIMITY_IN:
1723 case GDK_PROXIMITY_OUT:
1724 case GDK_DRAG_ENTER:
1725 case GDK_DRAG_LEAVE:
1726 case GDK_DRAG_MOTION:
1727 case GDK_DRAG_STATUS:
1728 case GDK_DROP_START:
1729 case GDK_DROP_FINISHED:
1739 emit_event_on_tags (GtkWidget *widget,
1745 gint retval = FALSE;
1746 GtkTextView *text_view;
1748 text_view = GTK_TEXT_VIEW (widget);
1750 tags = gtk_text_buffer_get_tags (text_view->buffer, iter);
1755 GtkTextTag *tag = tmp->data;
1757 if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, iter))
1763 tmp = g_slist_next (tmp);
1766 g_slist_free (tags);
1772 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
1774 GtkTextView *text_view;
1777 text_view = GTK_TEXT_VIEW (widget);
1779 if (text_view->layout == NULL ||
1780 text_view->buffer == NULL)
1783 if (event->any.window != text_view->text_window->bin_window)
1786 if (get_event_coordinates (event, &x, &y))
1790 x += text_view->xoffset;
1791 y += text_view->yoffset;
1793 /* FIXME this is slow and we do it twice per event.
1794 My favorite solution is to have GtkTextLayout cache
1795 the last couple lookups. */
1796 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1800 return emit_event_on_tags (widget, event, &iter);
1802 else if (event->type == GDK_KEY_PRESS ||
1803 event->type == GDK_KEY_RELEASE)
1805 GtkTextMark *insert;
1808 insert = gtk_text_buffer_get_mark (text_view->buffer,
1811 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, insert);
1813 return emit_event_on_tags (widget, event, &iter);
1820 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
1822 GtkTextView *text_view;
1824 text_view = GTK_TEXT_VIEW (widget);
1826 if (text_view->layout == NULL ||
1827 text_view->buffer == NULL)
1830 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
1831 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
1834 if (event->window != text_view->text_window->bin_window)
1837 if (gtk_im_context_filter_keypress (text_view->im_context, event))
1839 else if (event->keyval == GDK_Return)
1841 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1,
1842 text_view->editable);
1843 gtk_text_view_scroll_to_mark (text_view,
1844 gtk_text_buffer_get_mark (text_view->buffer,
1849 /* Pass through Tab as literal tab, unless Control is held down */
1850 else if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK))
1852 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\t", 1,
1853 text_view->editable);
1854 gtk_text_view_scroll_to_mark (text_view,
1855 gtk_text_buffer_get_mark (text_view->buffer,
1865 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
1871 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
1873 GtkTextView *text_view;
1875 text_view = GTK_TEXT_VIEW (widget);
1877 gtk_widget_grab_focus (widget);
1879 if (event->window != text_view->text_window->bin_window)
1881 /* Remove selection if any. */
1882 gtk_text_view_unselect (text_view);
1887 if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
1888 _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
1889 else if (event->button == 3)
1890 gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
1892 if (event->type == GDK_BUTTON_PRESS)
1894 if (event->button == 1)
1896 /* If we're in the selection, start a drag copy/move of the
1897 * selection; otherwise, start creating a new selection.
1900 GtkTextIter start, end;
1902 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1904 event->x + text_view->xoffset,
1905 event->y + text_view->yoffset);
1907 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
1909 gtk_text_iter_in_range (&iter, &start, &end))
1911 text_view->drag_start_x = event->x;
1912 text_view->drag_start_y = event->y;
1916 gtk_text_view_start_selection_drag (text_view, &iter, event);
1921 else if (event->button == 2)
1925 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1927 event->x + text_view->xoffset,
1928 event->y + text_view->yoffset);
1930 gtk_text_buffer_paste_primary (text_view->buffer,
1932 text_view->editable);
1935 else if (event->button == 3)
1937 if (gtk_text_view_end_selection_drag (text_view, event))
1948 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
1950 GtkTextView *text_view;
1952 text_view = GTK_TEXT_VIEW (widget);
1954 if (event->window != text_view->text_window->bin_window)
1957 if (event->button == 1)
1959 if (text_view->drag_start_x >= 0)
1961 text_view->drag_start_x = -1;
1962 text_view->drag_start_y = -1;
1965 if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
1969 /* Unselect everything; probably we were dragging, or clicked
1972 gtk_text_view_unselect (text_view);
1981 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1983 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1985 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1986 gtk_widget_draw_focus (widget);
1988 if (text_view->cursor_visible && text_view->layout)
1990 gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
1991 gtk_text_view_start_cursor_blink (text_view);
1994 gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
2000 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
2002 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2004 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2005 gtk_widget_draw_focus (widget);
2007 if (text_view->cursor_visible && text_view->layout)
2009 gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
2010 gtk_text_view_stop_cursor_blink (text_view);
2013 gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
2019 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
2021 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
2023 if (event->window == text_view->text_window->bin_window &&
2024 text_view->drag_start_x >= 0)
2029 gdk_window_get_pointer (text_view->text_window->bin_window,
2032 dx = text_view->drag_start_x - x;
2033 dy = text_view->drag_start_y - y;
2035 if (ABS (dx) > DRAG_THRESHOLD ||
2036 ABS (dy) > DRAG_THRESHOLD)
2039 gint buffer_x, buffer_y;
2041 gtk_text_view_window_to_buffer_coords (text_view,
2042 GTK_TEXT_WINDOW_TEXT,
2043 text_view->drag_start_x,
2044 text_view->drag_start_y,
2048 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2050 buffer_x, buffer_y);
2052 gtk_text_view_start_selection_dnd (text_view, &iter, event);
2061 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
2063 GtkTextView *text_view;
2065 text_view = GTK_TEXT_VIEW (widget);
2067 g_return_if_fail (text_view->layout != NULL);
2068 g_return_if_fail (text_view->xoffset >= 0);
2069 g_return_if_fail (text_view->yoffset >= 0);
2071 gtk_text_view_validate_onscreen (text_view);
2074 printf ("painting %d,%d %d x %d\n",
2076 area->width, area->height);
2079 gtk_text_layout_draw (text_view->layout,
2081 text_view->text_window->bin_window,
2085 area->width, area->height);
2089 send_expose (GtkTextView *text_view,
2093 GdkEventExpose event;
2095 event.type = GDK_EXPOSE;
2096 event.send_event = TRUE;
2097 event.window = win->bin_window;
2101 /* Fix coordinates (convert widget coords to window coords) */
2102 gtk_text_view_window_to_buffer_coords (text_view,
2103 GTK_TEXT_WINDOW_WIDGET,
2109 gtk_text_view_buffer_to_window_coords (text_view,
2117 gdk_window_ref (event.window);
2118 gtk_widget_event (GTK_WIDGET (text_view), (GdkEvent*) &event);
2119 gdk_window_unref (event.window);
2123 gtk_text_view_draw (GtkWidget *widget, GdkRectangle *area)
2125 GdkRectangle intersection;
2126 GtkTextView *text_view;
2128 text_view = GTK_TEXT_VIEW (widget);
2130 gtk_text_view_paint (widget, area);
2132 /* If the area overlaps the "edge" of the widget, draw the focus
2135 if (area->x < FOCUS_EDGE_WIDTH ||
2136 area->y < FOCUS_EDGE_WIDTH ||
2137 (area->x + area->width) > (widget->allocation.width - FOCUS_EDGE_WIDTH) ||
2138 (area->y + area->height) > (widget->allocation.height - FOCUS_EDGE_WIDTH))
2139 gtk_widget_draw_focus (widget);
2141 /* Synthesize expose events for the user-drawn border windows,
2142 * just as we would for a drawing area.
2145 if (text_view->left_window &&
2146 gdk_rectangle_intersect (area, &text_view->left_window->allocation,
2148 send_expose (text_view, text_view->left_window, &intersection);
2150 if (text_view->right_window &&
2151 gdk_rectangle_intersect (area, &text_view->right_window->allocation,
2153 send_expose (text_view, text_view->right_window, &intersection);
2155 if (text_view->top_window &&
2156 gdk_rectangle_intersect (area, &text_view->top_window->allocation,
2158 send_expose (text_view, text_view->top_window, &intersection);
2160 if (text_view->bottom_window &&
2161 gdk_rectangle_intersect (area, &text_view->bottom_window->allocation,
2163 send_expose (text_view, text_view->bottom_window, &intersection);
2167 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
2169 if (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
2170 GTK_TEXT_WINDOW_TEXT))
2171 gtk_text_view_paint (widget, &event->area);
2173 if (event->window == widget->window)
2174 gtk_widget_draw_focus (widget);
2180 gtk_text_view_draw_focus (GtkWidget *widget)
2182 if (GTK_WIDGET_DRAWABLE (widget))
2184 if (GTK_WIDGET_HAS_FOCUS (widget))
2186 gtk_paint_focus (widget->style, widget->window,
2187 NULL, widget, "textview",
2189 widget->allocation.width - 1,
2190 widget->allocation.height - 1);
2194 gdk_window_clear (widget->window);
2204 gtk_text_view_add (GtkContainer *container,
2207 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
2208 g_return_if_fail (GTK_IS_WIDGET (child));
2210 /* This is pretty random. */
2211 gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (container),
2213 GTK_TEXT_WINDOW_WIDGET,
2218 gtk_text_view_remove (GtkContainer *container,
2222 GtkTextView *text_view;
2223 GtkTextViewChild *vc;
2225 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
2226 g_return_if_fail (GTK_IS_WIDGET (child));
2227 g_return_if_fail (child->parent == (GtkWidget*) container);
2229 text_view = GTK_TEXT_VIEW (container);
2232 iter = text_view->children;
2234 while (iter != NULL)
2238 if (vc->widget == child)
2241 iter = g_slist_next (iter);
2244 g_assert (iter != NULL); /* be sure we had the child in the list */
2246 text_view->children = g_slist_remove (text_view->children, vc);
2248 gtk_widget_unparent (vc->widget);
2250 text_view_child_free (vc);
2254 gtk_text_view_forall (GtkContainer *container,
2255 gboolean include_internals,
2256 GtkCallback callback,
2257 gpointer callback_data)
2260 GtkTextView *text_view;
2262 g_return_if_fail (GTK_IS_TEXT_VIEW (container));
2263 g_return_if_fail (callback != NULL);
2265 text_view = GTK_TEXT_VIEW (container);
2267 iter = text_view->children;
2269 while (iter != NULL)
2271 GtkTextViewChild *vc = iter->data;
2273 (* callback) (vc->widget, callback_data);
2275 iter = g_slist_next (iter);
2284 blink_cb (gpointer data)
2286 GtkTextView *text_view;
2288 text_view = GTK_TEXT_VIEW (data);
2290 g_assert (text_view->layout && GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible);
2292 gtk_text_layout_set_cursor_visible (text_view->layout,
2293 !gtk_text_layout_get_cursor_visible (text_view->layout));
2298 gtk_text_view_start_cursor_blink (GtkTextView *text_view)
2300 if (text_view->blink_timeout != 0)
2303 text_view->blink_timeout = gtk_timeout_add (500, blink_cb, text_view);
2307 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
2309 if (text_view->blink_timeout == 0)
2312 gtk_timeout_remove (text_view->blink_timeout);
2313 text_view->blink_timeout = 0;
2317 * Key binding handlers
2321 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
2322 GtkTextIter *newplace,
2327 gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
2333 gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
2339 gtk_text_view_move (GtkTextView *text_view,
2340 GtkMovementStep step,
2342 gboolean extend_selection)
2345 GtkTextIter newplace;
2347 gint cursor_x_pos = 0;
2349 if (step == GTK_MOVEMENT_PAGES)
2351 gtk_text_view_scroll_pages (text_view, count);
2355 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
2356 gtk_text_buffer_get_mark (text_view->buffer,
2360 if (step == GTK_MOVEMENT_DISPLAY_LINES)
2361 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
2365 case GTK_MOVEMENT_CHARS:
2366 gtk_text_iter_forward_chars (&newplace, count);
2369 case GTK_MOVEMENT_POSITIONS:
2370 gtk_text_layout_move_iter_visually (text_view->layout,
2374 case GTK_MOVEMENT_WORDS:
2376 gtk_text_iter_backward_word_starts (&newplace, -count);
2378 gtk_text_iter_forward_word_ends (&newplace, count);
2381 case GTK_MOVEMENT_DISPLAY_LINES:
2382 gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
2383 gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
2386 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2388 gtk_text_view_move_iter_by_lines (text_view, &newplace, --count);
2389 else if (count < -1)
2390 gtk_text_view_move_iter_by_lines (text_view, &newplace, ++count);
2393 gtk_text_layout_move_iter_to_line_end (text_view->layout, &newplace, count);
2396 case GTK_MOVEMENT_PARAGRAPHS:
2397 /* This should almost certainly instead be doing the parallel thing to WORD */
2398 /* gtk_text_iter_down_lines (&newplace, count); */
2402 case GTK_MOVEMENT_PARAGRAPH_ENDS:
2404 gtk_text_iter_forward_to_newline (&newplace);
2406 gtk_text_iter_set_line_offset (&newplace, 0);
2409 case GTK_MOVEMENT_BUFFER_ENDS:
2411 gtk_text_buffer_get_last_iter (text_view->buffer, &newplace);
2413 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &newplace, 0);
2420 if (!gtk_text_iter_equal (&insert, &newplace))
2422 if (extend_selection)
2423 gtk_text_buffer_move_mark (text_view->buffer,
2424 gtk_text_buffer_get_mark (text_view->buffer,
2428 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
2430 gtk_text_view_scroll_to_mark (text_view,
2431 gtk_text_buffer_get_mark (text_view->buffer,
2434 if (step == GTK_MOVEMENT_DISPLAY_LINES)
2436 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
2442 gtk_text_view_set_anchor (GtkTextView *text_view)
2446 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
2447 gtk_text_buffer_get_mark (text_view->buffer,
2450 gtk_text_buffer_create_mark (text_view->buffer, "anchor", &insert, TRUE);
2454 gtk_text_view_scroll_pages (GtkTextView *text_view,
2459 gint cursor_x_pos, cursor_y_pos;
2460 GtkTextIter new_insert;
2464 g_return_if_fail (text_view->vadjustment != NULL);
2466 adj = text_view->vadjustment;
2468 /* Validate the region that will be brought into view by the cursor motion
2472 gtk_text_view_get_first_para_iter (text_view, &anchor);
2473 y0 = adj->page_size;
2474 y1 = adj->page_size + count * adj->page_increment;
2478 gtk_text_view_get_first_para_iter (text_view, &anchor);
2479 y0 = count * adj->page_increment + adj->page_size;
2483 gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
2485 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
2487 newval = adj->value;
2489 newval += count * adj->page_increment;
2491 cursor_y_pos += newval - adj->value;
2492 set_adjustment_clamped (adj, newval);
2494 gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
2495 clamp_iter_onscreen (text_view, &new_insert);
2496 gtk_text_buffer_place_cursor (text_view->buffer, &new_insert);
2498 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
2500 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
2501 * only guarantees 1 pixel onscreen.
2503 gtk_text_view_scroll_to_mark (text_view,
2504 gtk_text_buffer_get_mark (text_view->buffer,
2510 whitespace (gunichar ch, gpointer user_data)
2512 return (ch == ' ' || ch == '\t');
2516 not_whitespace (gunichar ch, gpointer user_data)
2518 return !whitespace (ch, user_data);
2522 find_whitepace_region (const GtkTextIter *center,
2523 GtkTextIter *start, GtkTextIter *end)
2528 if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL))
2529 gtk_text_iter_next_char (start); /* we want the first whitespace... */
2530 if (whitespace (gtk_text_iter_get_char (end), NULL))
2531 gtk_text_iter_forward_find_char (end, not_whitespace, NULL);
2533 return !gtk_text_iter_equal (start, end);
2537 gtk_text_view_insert (GtkTextView *text_view,
2540 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, str, -1,
2541 text_view->editable);
2545 gtk_text_view_delete (GtkTextView *text_view,
2552 gboolean leave_one = FALSE;
2554 if (type == GTK_DELETE_CHARS)
2556 /* Char delete deletes the selection, if one exists */
2557 if (gtk_text_buffer_delete_selection (text_view->buffer, TRUE,
2558 text_view->editable))
2562 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
2564 gtk_text_buffer_get_mark (text_view->buffer,
2572 case GTK_DELETE_CHARS:
2573 gtk_text_iter_forward_chars (&end, count);
2576 case GTK_DELETE_WORD_ENDS:
2578 gtk_text_iter_forward_word_ends (&end, count);
2580 gtk_text_iter_backward_word_starts (&start, 0 - count);
2583 case GTK_DELETE_WORDS:
2586 case GTK_DELETE_DISPLAY_LINE_ENDS:
2589 case GTK_DELETE_DISPLAY_LINES:
2592 case GTK_DELETE_PARAGRAPH_ENDS:
2593 /* If we're already at a newline, we need to
2594 * simply delete that newline, instead of
2595 * moving to the next one.
2597 if (gtk_text_iter_get_char (&end) == '\n')
2599 gtk_text_iter_next_char (&end);
2605 if (!gtk_text_iter_forward_to_newline (&end))
2611 /* FIXME figure out what a negative count means
2615 case GTK_DELETE_PARAGRAPHS:
2618 gtk_text_iter_set_line_offset (&start, 0);
2619 gtk_text_iter_forward_to_newline (&end);
2621 /* Do the lines beyond the first. */
2624 gtk_text_iter_forward_to_newline (&end);
2630 /* FIXME negative count? */
2634 case GTK_DELETE_WHITESPACE:
2636 find_whitepace_region (&insert, &start, &end);
2644 if (!gtk_text_iter_equal (&start, &end))
2646 if (gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
2647 text_view->editable))
2650 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer,
2652 text_view->editable);
2655 gtk_text_view_scroll_to_mark (text_view,
2656 gtk_text_buffer_get_mark (text_view->buffer, "insert"),
2662 gtk_text_view_cut_clipboard (GtkTextView *text_view)
2664 gtk_text_buffer_cut_clipboard (text_view->buffer, text_view->editable);
2665 gtk_text_view_scroll_to_mark (text_view,
2666 gtk_text_buffer_get_mark (text_view->buffer,
2672 gtk_text_view_copy_clipboard (GtkTextView *text_view)
2674 gtk_text_buffer_copy_clipboard (text_view->buffer);
2675 gtk_text_view_scroll_to_mark (text_view,
2676 gtk_text_buffer_get_mark (text_view->buffer,
2682 gtk_text_view_paste_clipboard (GtkTextView *text_view)
2684 gtk_text_buffer_paste_clipboard (text_view->buffer, text_view->editable);
2685 gtk_text_view_scroll_to_mark (text_view,
2686 gtk_text_buffer_get_mark (text_view->buffer,
2692 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
2694 text_view->overwrite_mode = !text_view->overwrite_mode;
2702 gtk_text_view_unselect (GtkTextView *text_view)
2706 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
2708 gtk_text_buffer_get_mark (text_view->buffer,
2711 gtk_text_buffer_move_mark (text_view->buffer,
2712 gtk_text_buffer_get_mark (text_view->buffer,
2718 move_insert_to_pointer_and_scroll (GtkTextView *text_view, gboolean partial_scroll)
2721 GdkModifierType state;
2722 GtkTextIter newplace;
2724 gboolean in_threshold = FALSE;
2726 gdk_window_get_pointer (text_view->text_window->bin_window,
2729 /* Adjust movement by how long we've been selecting, to
2730 get an acceleration effect. The exact numbers are
2731 pretty arbitrary. We have a threshold before we
2732 start to accelerate. */
2733 /* uncommenting this printf helps visualize how it works. */
2734 /* printf ("%d\n", text_view->scrolling_accel_factor); */
2736 if (text_view->scrolling_accel_factor > 10)
2737 adjust = (text_view->scrolling_accel_factor - 10) * 75;
2739 if (y < 0) /* scrolling upward */
2742 /* No adjust if the pointer has moved back inside the window for sure.
2743 Also I'm adding a small threshold where no adjust is added,
2744 in case you want to do a continuous slow scroll. */
2745 #define SLOW_SCROLL_TH 7
2746 if (x >= (0 - SLOW_SCROLL_TH) &&
2747 x < (SCREEN_WIDTH (text_view) + SLOW_SCROLL_TH) &&
2748 y >= (0 - SLOW_SCROLL_TH) &&
2749 y < (SCREEN_HEIGHT (text_view) + SLOW_SCROLL_TH))
2752 in_threshold = TRUE;
2755 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2757 x + text_view->xoffset,
2758 y + text_view->yoffset + adjust);
2761 gboolean scrolled = FALSE;
2762 GtkTextMark *insert_mark =
2763 gtk_text_buffer_get_mark (text_view->buffer, "insert");
2765 gtk_text_buffer_move_mark (text_view->buffer,
2770 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 0.7);
2772 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 1.0);
2776 /* We want to avoid rapid jump to super-accelerated when you
2777 leave the slow scroll threshold after scrolling for a
2778 while. So we slowly decrease accel when scrolling inside
2783 if (text_view->scrolling_accel_factor > 1)
2784 text_view->scrolling_accel_factor -= 2;
2787 text_view->scrolling_accel_factor += 1;
2791 /* If we don't scroll we're probably inside the window, but
2792 potentially just a bit outside. We decrease acceleration
2793 while the user is fooling around inside the window.
2794 Acceleration decreases faster than it increases. */
2795 if (text_view->scrolling_accel_factor > 4)
2796 text_view->scrolling_accel_factor -= 5;
2804 selection_scan_timeout (gpointer data)
2806 GtkTextView *text_view;
2808 text_view = GTK_TEXT_VIEW (data);
2810 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2812 return TRUE; /* remain installed. */
2816 text_view->selection_drag_scan_timeout = 0;
2817 return FALSE; /* remove ourselves */
2822 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
2824 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2826 /* If we had to scroll offscreen, insert a timeout to do so
2827 again. Note that in the timeout, even if the mouse doesn't
2828 move, due to this scroll xoffset/yoffset will have changed
2829 and we'll need to scroll again. */
2830 if (text_view->selection_drag_scan_timeout != 0) /* reset on every motion event */
2831 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2833 text_view->selection_drag_scan_timeout =
2834 gtk_timeout_add (50, selection_scan_timeout, text_view);
2841 gtk_text_view_start_selection_drag (GtkTextView *text_view,
2842 const GtkTextIter *iter,
2843 GdkEventButton *button)
2845 GtkTextIter newplace;
2847 g_return_if_fail (text_view->selection_drag_handler == 0);
2849 gtk_grab_add (GTK_WIDGET (text_view));
2851 text_view->scrolling_accel_factor = 0;
2855 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
2857 text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
2858 "motion_notify_event",
2859 GTK_SIGNAL_FUNC (selection_motion_event_handler),
2863 /* returns whether we were really dragging */
2865 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
2867 if (text_view->selection_drag_handler == 0)
2870 gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
2871 text_view->selection_drag_handler = 0;
2873 text_view->scrolling_accel_factor = 0;
2875 if (text_view->selection_drag_scan_timeout != 0)
2877 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2878 text_view->selection_drag_scan_timeout = 0;
2881 /* one last update to current position */
2882 move_insert_to_pointer_and_scroll (text_view, FALSE);
2884 gtk_grab_remove (GTK_WIDGET (text_view));
2894 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
2896 if (upper != adj->upper)
2898 gfloat min = MAX (0., upper - adj->page_size);
2899 gboolean value_changed = FALSE;
2903 if (adj->value > min)
2906 value_changed = TRUE;
2909 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
2911 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2916 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
2918 gint width = 0, height = 0;
2920 gtk_text_view_ensure_layout (text_view);
2923 gtk_text_layout_set_screen_width (text_view->layout,
2924 SCREEN_WIDTH (text_view));
2926 gtk_text_layout_get_size (text_view->layout, &width, &height);
2929 /* If the width is less than the screen width (likely
2930 if we have wrapping turned on for the whole widget),
2931 then we want to set the scroll region to the screen
2932 width. If the width is greater (wrapping off) then we
2933 probably want to set the scroll region to the width
2934 of the layout. I guess.
2937 width = MAX (text_view->layout->screen_width, width);
2941 if (text_view->width != width || text_view->height != height)
2944 printf ("layout size set, widget width is %d\n",
2945 GTK_WIDGET (text_view)->allocation.width);
2947 text_view->width = width;
2948 text_view->height = height;
2950 gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
2951 MAX (SCREEN_WIDTH (text_view), width));
2952 gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
2953 MAX (SCREEN_HEIGHT (text_view), height));
2955 /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
2957 /* Set up the step sizes; we'll say that a page is
2958 our allocation minus one step, and a step is
2959 1/10 of our allocation. */
2960 text_view->hadjustment->step_increment =
2961 SCREEN_WIDTH (text_view) / 10.0;
2962 text_view->hadjustment->page_increment =
2963 SCREEN_WIDTH (text_view) * 0.9;
2965 text_view->vadjustment->step_increment =
2966 SCREEN_HEIGHT (text_view) / 10.0;
2967 text_view->vadjustment->page_increment =
2968 SCREEN_HEIGHT (text_view) * 0.9;
2973 gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
2974 GtkTextAttributes *values,
2977 values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
2978 values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
2980 if (values->font_desc)
2981 pango_font_description_free (values->font_desc);
2983 values->font_desc = pango_font_description_copy (style->font_desc);
2987 gtk_text_view_ensure_layout (GtkTextView *text_view)
2991 widget = GTK_WIDGET (text_view);
2993 if (text_view->layout == NULL)
2995 GtkTextAttributes *style;
2996 PangoContext *ltr_context, *rtl_context;
2998 text_view->layout = gtk_text_layout_new ();
3000 gtk_signal_connect (GTK_OBJECT (text_view->layout),
3002 GTK_SIGNAL_FUNC (invalidated_handler),
3005 gtk_signal_connect (GTK_OBJECT (text_view->layout),
3007 GTK_SIGNAL_FUNC (changed_handler),
3010 if (text_view->buffer)
3011 gtk_text_layout_set_buffer (text_view->layout, text_view->buffer);
3013 if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
3014 gtk_text_view_start_cursor_blink (text_view);
3016 gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
3018 ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
3019 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
3020 rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
3021 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
3023 gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
3025 g_object_unref (G_OBJECT (ltr_context));
3026 g_object_unref (G_OBJECT (rtl_context));
3028 style = gtk_text_attributes_new ();
3030 gtk_widget_ensure_style (widget);
3031 gtk_text_view_set_attributes_from_style (text_view,
3032 style, widget->style);
3034 style->pixels_above_lines = 2;
3035 style->pixels_below_lines = 2;
3036 style->pixels_inside_wrap = 1;
3038 style->wrap_mode = text_view->wrap_mode;
3039 style->justify = GTK_JUSTIFY_LEFT;
3040 style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
3042 gtk_text_layout_set_default_style (text_view->layout, style);
3044 gtk_text_attributes_unref (style);
3049 gtk_text_view_destroy_layout (GtkTextView *text_view)
3051 if (text_view->layout)
3053 gtk_text_view_stop_cursor_blink (text_view);
3054 gtk_text_view_end_selection_drag (text_view, NULL);
3056 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
3057 invalidated_handler, text_view);
3058 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
3059 changed_handler, text_view);
3060 gtk_object_unref (GTK_OBJECT (text_view->layout));
3061 text_view->layout = NULL;
3071 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
3072 const GtkTextIter *iter,
3073 GdkEventMotion *event)
3075 GdkDragContext *context;
3076 GtkTargetList *target_list;
3078 text_view->drag_start_x = -1;
3079 text_view->drag_start_y = -1;
3081 target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
3083 context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
3084 GDK_ACTION_COPY | GDK_ACTION_MOVE,
3085 1, (GdkEvent*)event);
3087 gtk_target_list_unref (target_list);
3089 gtk_drag_set_icon_default (context);
3091 /* We're inside the selection, so start without being able
3092 * to accept the drag.
3094 gdk_drag_status (context, 0, event->time);
3095 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3099 gtk_text_view_drag_begin (GtkWidget *widget,
3100 GdkDragContext *context)
3106 gtk_text_view_drag_end (GtkWidget *widget,
3107 GdkDragContext *context)
3109 GtkTextView *text_view;
3111 text_view = GTK_TEXT_VIEW (widget);
3113 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3117 gtk_text_view_drag_data_get (GtkWidget *widget,
3118 GdkDragContext *context,
3119 GtkSelectionData *selection_data,
3127 GtkTextView *text_view;
3129 text_view = GTK_TEXT_VIEW (widget);
3134 if (gtk_text_buffer_get_selection_bounds (text_view->buffer, &start, &end))
3136 /* Extract the selected text */
3137 str = gtk_text_iter_get_visible_text (&start, &end);
3139 length = strlen (str);
3144 gtk_selection_data_set_text (selection_data, str);
3150 gtk_text_view_drag_data_delete (GtkWidget *widget,
3151 GdkDragContext *context)
3153 GtkTextView *text_view;
3155 text_view = GTK_TEXT_VIEW (widget);
3157 gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
3158 TRUE, GTK_TEXT_VIEW (widget)->editable);
3162 gtk_text_view_drag_leave (GtkWidget *widget,
3163 GdkDragContext *context,
3171 gtk_text_view_drag_motion (GtkWidget *widget,
3172 GdkDragContext *context,
3177 GtkTextIter newplace;
3178 GtkTextView *text_view;
3181 GdkRectangle target_rect;
3184 text_view = GTK_TEXT_VIEW (widget);
3186 target_rect = text_view->text_window->allocation;
3188 if (x < target_rect.x ||
3189 y < target_rect.y ||
3190 x > (target_rect.x + target_rect.width) ||
3191 y > (target_rect.y + target_rect.height))
3192 return FALSE; /* outside the text window */
3194 gtk_text_view_window_to_buffer_coords (text_view,
3195 GTK_TEXT_WINDOW_WIDGET,
3199 gtk_text_layout_get_iter_at_pixel (text_view->layout,
3203 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
3205 gtk_text_iter_in_range (&newplace, &start, &end))
3207 /* We're inside the selection. */
3208 gdk_drag_status (context, 0, time);
3209 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3213 if (gtk_text_iter_editable (&newplace, text_view->editable))
3215 gtk_text_mark_set_visible (text_view->dnd_mark,
3216 text_view->cursor_visible);
3218 gdk_drag_status (context, context->suggested_action, time);
3222 /* Can't drop here. */
3223 gdk_drag_status (context, 0, time);
3224 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
3228 gtk_text_buffer_move_mark (text_view->buffer,
3229 gtk_text_buffer_get_mark (text_view->buffer,
3234 /* The effect of this is that the text scrolls if you're near
3235 the edge. We have to scroll whether or not we're inside
3239 margin = MIN (SCREEN_WIDTH (widget), SCREEN_HEIGHT (widget));
3242 gtk_text_view_scroll_to_mark_adjusted (text_view,
3243 gtk_text_buffer_get_mark (text_view->buffer,
3252 gtk_text_view_drag_drop (GtkWidget *widget,
3253 GdkDragContext *context,
3259 /* called automatically. */
3260 if (context->targets)
3262 gtk_drag_get_data (widget, context,
3263 GPOINTER_TO_INT (context->targets->data),
3274 gtk_text_view_drag_data_received (GtkWidget *widget,
3275 GdkDragContext *context,
3278 GtkSelectionData *selection_data,
3282 GtkTextIter drop_point;
3283 GtkTextView *text_view;
3284 GtkTextMark *drag_target_mark;
3287 text_view = GTK_TEXT_VIEW (widget);
3289 drag_target_mark = gtk_text_buffer_get_mark (text_view->buffer,
3292 if (drag_target_mark == NULL)
3295 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
3299 str = gtk_selection_data_get_text (selection_data);
3303 gtk_text_buffer_insert_interactive (text_view->buffer,
3304 &drop_point, str, -1,
3305 text_view->editable);
3310 static GtkAdjustment*
3311 get_hadjustment (GtkTextView *text_view)
3313 if (text_view->hadjustment == NULL)
3314 gtk_text_view_set_scroll_adjustments (text_view,
3316 gtk_adjustment_new (0.0, 0.0, 0.0,
3318 text_view->vadjustment);
3320 return text_view->hadjustment;
3323 static GtkAdjustment*
3324 get_vadjustment (GtkTextView *text_view)
3326 if (text_view->vadjustment == NULL)
3327 gtk_text_view_set_scroll_adjustments (text_view,
3328 text_view->hadjustment,
3330 gtk_adjustment_new (0.0, 0.0, 0.0,
3333 return text_view->vadjustment;
3338 gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
3339 GtkAdjustment *hadj,
3340 GtkAdjustment *vadj)
3342 gboolean need_adjust = FALSE;
3344 g_return_if_fail (text_view != NULL);
3345 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
3348 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
3350 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3352 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
3354 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3356 if (text_view->hadjustment && (text_view->hadjustment != hadj))
3358 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
3359 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
3362 if (text_view->vadjustment && (text_view->vadjustment != vadj))
3364 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
3365 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
3368 if (text_view->hadjustment != hadj)
3370 text_view->hadjustment = hadj;
3371 gtk_object_ref (GTK_OBJECT (text_view->hadjustment));
3372 gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
3374 gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
3375 (GtkSignalFunc) gtk_text_view_value_changed,
3380 if (text_view->vadjustment != vadj)
3382 text_view->vadjustment = vadj;
3383 gtk_object_ref (GTK_OBJECT (text_view->vadjustment));
3384 gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
3386 gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
3387 (GtkSignalFunc) gtk_text_view_value_changed,
3393 gtk_text_view_value_changed (NULL, text_view);
3397 gtk_text_view_value_changed (GtkAdjustment *adj,
3398 GtkTextView *text_view)
3405 if (adj == text_view->hadjustment)
3407 dx = text_view->xoffset - (gint)adj->value;
3408 text_view->xoffset = adj->value;
3410 else if (adj == text_view->vadjustment)
3412 dy = text_view->yoffset - (gint)adj->value;
3413 text_view->yoffset = adj->value;
3415 if (text_view->layout)
3417 gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
3419 gtk_text_buffer_move_mark (text_view->buffer, text_view->first_para_mark, &iter);
3421 text_view->first_para_pixels = adj->value - line_top;
3425 if (dx != 0 || dy != 0)
3429 if (text_view->left_window)
3430 text_window_scroll (text_view->left_window, 0, dy);
3431 if (text_view->right_window)
3432 text_window_scroll (text_view->right_window, 0, dy);
3437 if (text_view->top_window)
3438 text_window_scroll (text_view->top_window, dx, 0);
3439 if (text_view->bottom_window)
3440 text_window_scroll (text_view->bottom_window, dx, 0);
3443 /* It looks nicer to scroll the main area last, because
3444 * it takes a while, and making the side areas update
3445 * afterward emphasizes the slowness of scrolling the
3448 text_window_scroll (text_view->text_window, dx, dy);
3453 gtk_text_view_commit_handler (GtkIMContext *context,
3455 GtkTextView *text_view)
3457 gtk_text_buffer_delete_selection (text_view->buffer, TRUE,
3458 text_view->editable);
3460 if (!strcmp (str, "\n"))
3462 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1,
3463 text_view->editable);
3467 if (text_view->overwrite_mode)
3468 gtk_text_view_delete (text_view, GTK_DELETE_CHARS, 1);
3469 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, str, -1,
3470 text_view->editable);
3473 gtk_text_view_scroll_to_mark (text_view,
3474 gtk_text_buffer_get_mark (text_view->buffer,
3480 gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
3481 const GtkTextIter *location,
3485 GtkTextView *text_view = GTK_TEXT_VIEW (data);
3487 if (mark == gtk_text_buffer_get_insert (buffer))
3489 text_view->virtual_cursor_x = -1;
3490 text_view->virtual_cursor_y = -1;
3495 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
3499 GdkRectangle strong_pos;
3502 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
3503 gtk_text_buffer_get_mark (text_view->buffer,
3506 if ((x && text_view->virtual_cursor_x == -1) ||
3507 (y && text_view->virtual_cursor_y == -1))
3508 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
3512 if (text_view->virtual_cursor_x != -1)
3513 *x = text_view->virtual_cursor_x;
3520 if (text_view->virtual_cursor_x != -1)
3521 *y = text_view->virtual_cursor_y;
3523 *y = strong_pos.y + strong_pos.height / 2;
3528 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
3532 GdkRectangle strong_pos;
3535 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
3536 gtk_text_buffer_get_mark (text_view->buffer,
3539 if (x == -1 || y == -1)
3540 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
3542 text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
3543 text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
3548 /* Child GdkWindows */
3551 static GtkTextWindow*
3552 text_window_new (GtkTextWindowType type,
3555 gint height_request)
3559 win = g_new (GtkTextWindow, 1);
3562 win->widget = widget;
3564 win->bin_window = NULL;
3565 win->requisition.width = width_request;
3566 win->requisition.height = height_request;
3567 win->allocation.width = width_request;
3568 win->allocation.height = height_request;
3569 win->allocation.x = 0;
3570 win->allocation.y = 0;
3576 text_window_free (GtkTextWindow *win)
3579 text_window_unrealize (win);
3585 text_window_realize (GtkTextWindow *win,
3588 GdkWindowAttr attributes;
3589 gint attributes_mask;
3592 attributes.window_type = GDK_WINDOW_CHILD;
3593 attributes.x = win->allocation.x;
3594 attributes.y = win->allocation.y;
3595 attributes.width = win->allocation.width;
3596 attributes.height = win->allocation.height;
3597 attributes.wclass = GDK_INPUT_OUTPUT;
3598 attributes.visual = gtk_widget_get_visual (win->widget);
3599 attributes.colormap = gtk_widget_get_colormap (win->widget);
3600 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
3602 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3604 win->window = gdk_window_new (parent,
3608 gdk_window_show (win->window);
3609 gdk_window_set_user_data (win->window, win->widget);
3613 attributes.width = win->allocation.width;
3614 attributes.height = win->allocation.height;
3615 attributes.event_mask = (GDK_EXPOSURE_MASK |
3617 GDK_KEY_PRESS_MASK |
3618 GDK_BUTTON_PRESS_MASK |
3619 GDK_BUTTON_RELEASE_MASK |
3620 GDK_POINTER_MOTION_MASK |
3621 GDK_POINTER_MOTION_HINT_MASK |
3622 gtk_widget_get_events (win->widget));
3624 win->bin_window = gdk_window_new (win->window,
3628 gdk_window_show (win->bin_window);
3629 gdk_window_set_user_data (win->bin_window, win->widget);
3631 if (win->type == GTK_TEXT_WINDOW_TEXT)
3634 cursor = gdk_cursor_new (GDK_XTERM);
3635 gdk_window_set_cursor (win->bin_window, cursor);
3636 gdk_cursor_destroy (cursor);
3638 gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
3642 gdk_window_set_background (win->bin_window,
3643 &win->widget->style->base[GTK_WIDGET_STATE (win->widget)]);
3647 gdk_window_set_background (win->bin_window,
3648 &win->widget->style->bg[GTK_WIDGET_STATE (win->widget)]);
3651 g_object_set_qdata (G_OBJECT (win->window),
3652 g_quark_from_static_string ("gtk-text-view-text-window"),
3655 g_object_set_qdata (G_OBJECT (win->bin_window),
3656 g_quark_from_static_string ("gtk-text-view-text-window"),
3661 text_window_unrealize (GtkTextWindow *win)
3663 if (win->type == GTK_TEXT_WINDOW_TEXT)
3665 gtk_im_context_set_client_window (GTK_TEXT_VIEW (win->widget)->im_context,
3669 gdk_window_set_user_data (win->window, NULL);
3670 gdk_window_set_user_data (win->bin_window, NULL);
3671 gdk_window_destroy (win->bin_window);
3672 gdk_window_destroy (win->window);
3674 win->bin_window = NULL;
3678 text_window_size_allocate (GtkTextWindow *win,
3681 win->allocation = *rect;
3685 gdk_window_move_resize (win->window,
3687 rect->width, rect->height);
3689 gdk_window_resize (win->bin_window,
3690 rect->width, rect->height);
3695 text_window_scroll (GtkTextWindow *win,
3699 if (dx != 0 || dy != 0)
3701 gdk_window_scroll (win->bin_window, dx, dy);
3702 gdk_window_process_updates (win->bin_window, TRUE);
3707 text_window_invalidate_rect (GtkTextWindow *win,
3710 gdk_window_invalidate_rect (win->bin_window, rect, FALSE);
3714 text_window_get_width (GtkTextWindow *win)
3716 return win->allocation.width;
3720 text_window_get_height (GtkTextWindow *win)
3722 return win->allocation.height;
3726 text_window_get_allocation (GtkTextWindow *win,
3729 *rect = win->allocation;
3736 gtk_text_view_get_window (GtkTextView *text_view,
3737 GtkTextWindowType win)
3739 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
3743 case GTK_TEXT_WINDOW_WIDGET:
3744 return GTK_WIDGET (text_view)->window;
3747 case GTK_TEXT_WINDOW_TEXT:
3748 return text_view->text_window->bin_window;
3751 case GTK_TEXT_WINDOW_LEFT:
3752 if (text_view->left_window)
3753 return text_view->left_window->bin_window;
3758 case GTK_TEXT_WINDOW_RIGHT:
3759 if (text_view->right_window)
3760 return text_view->right_window->bin_window;
3765 case GTK_TEXT_WINDOW_TOP:
3766 if (text_view->top_window)
3767 return text_view->top_window->bin_window;
3772 case GTK_TEXT_WINDOW_BOTTOM:
3773 if (text_view->bottom_window)
3774 return text_view->bottom_window->bin_window;
3780 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
3787 gtk_text_view_get_window_type (GtkTextView *text_view,
3792 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), 0);
3793 g_return_val_if_fail (GDK_IS_WINDOW (text_view), 0);
3795 if (window == GTK_WIDGET (text_view)->window)
3796 return GTK_TEXT_WINDOW_WIDGET;
3798 win = g_object_get_qdata (G_OBJECT (window),
3799 g_quark_try_string ("gtk-text-view-text-window"));
3805 g_warning ("%s: Window is not a text view window",
3812 buffer_to_widget (GtkTextView *text_view,
3820 *window_x = buffer_x - text_view->xoffset + FOCUS_EDGE_WIDTH;
3821 if (text_view->left_window)
3822 *window_x += text_view->left_window->allocation.width;
3827 *window_y = buffer_y - text_view->yoffset + FOCUS_EDGE_WIDTH;
3828 if (text_view->top_window)
3829 *window_y += text_view->top_window->allocation.height;
3834 widget_to_text_window (GtkTextWindow *win,
3841 *window_x = widget_x - win->allocation.x;
3844 *window_y = widget_y - win->allocation.y;
3848 buffer_to_text_window (GtkTextView *text_view,
3857 g_warning ("Attempt to convert text buffer coordinates to coordinates "
3858 "for a nonexistent child window of GtkTextView");
3862 buffer_to_widget (text_view,
3864 window_x, window_y);
3866 widget_to_text_window (win,
3867 window_x ? *window_x : 0,
3868 window_y ? *window_y : 0,
3874 gtk_text_view_buffer_to_window_coords (GtkTextView *text_view,
3875 GtkTextWindowType win,
3881 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
3885 case GTK_TEXT_WINDOW_WIDGET:
3886 buffer_to_widget (text_view,
3888 window_x, window_y);
3891 case GTK_TEXT_WINDOW_TEXT:
3893 *window_x = buffer_x - text_view->xoffset;
3895 *window_y = buffer_y - text_view->yoffset;
3898 case GTK_TEXT_WINDOW_LEFT:
3899 buffer_to_text_window (text_view,
3900 text_view->left_window,
3902 window_x, window_y);
3905 case GTK_TEXT_WINDOW_RIGHT:
3906 buffer_to_text_window (text_view,
3907 text_view->right_window,
3909 window_x, window_y);
3912 case GTK_TEXT_WINDOW_TOP:
3913 buffer_to_text_window (text_view,
3914 text_view->top_window,
3916 window_x, window_y);
3919 case GTK_TEXT_WINDOW_BOTTOM:
3920 buffer_to_text_window (text_view,
3921 text_view->bottom_window,
3923 window_x, window_y);
3927 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
3933 widget_to_buffer (GtkTextView *text_view,
3941 *buffer_x = widget_x - FOCUS_EDGE_WIDTH + text_view->xoffset;
3942 if (text_view->left_window)
3943 *buffer_x -= text_view->left_window->allocation.width;
3948 *buffer_y = widget_y - FOCUS_EDGE_WIDTH + text_view->yoffset;
3949 if (text_view->top_window)
3950 *buffer_y -= text_view->top_window->allocation.height;
3955 text_window_to_widget (GtkTextWindow *win,
3962 *widget_x = window_x + win->allocation.x;
3965 *widget_y = window_y + win->allocation.y;
3969 text_window_to_buffer (GtkTextView *text_view,
3978 g_warning ("Attempt to convert GtkTextView buffer coordinates into "
3979 "coordinates for a nonexistent child window.");
3983 text_window_to_widget (win,
3989 widget_to_buffer (text_view,
3990 buffer_x ? *buffer_x : 0,
3991 buffer_y ? *buffer_y : 0,
3997 gtk_text_view_window_to_buffer_coords (GtkTextView *text_view,
3998 GtkTextWindowType win,
4004 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4008 case GTK_TEXT_WINDOW_WIDGET:
4009 widget_to_buffer (text_view,
4011 buffer_x, buffer_y);
4014 case GTK_TEXT_WINDOW_TEXT:
4016 *buffer_x = window_x + text_view->xoffset;
4018 *buffer_y = window_y + text_view->yoffset;
4021 case GTK_TEXT_WINDOW_LEFT:
4022 text_window_to_buffer (text_view,
4023 text_view->left_window,
4025 buffer_x, buffer_y);
4028 case GTK_TEXT_WINDOW_RIGHT:
4029 text_window_to_buffer (text_view,
4030 text_view->right_window,
4032 buffer_x, buffer_y);
4035 case GTK_TEXT_WINDOW_TOP:
4036 text_window_to_buffer (text_view,
4037 text_view->top_window,
4039 buffer_x, buffer_y);
4042 case GTK_TEXT_WINDOW_BOTTOM:
4043 text_window_to_buffer (text_view,
4044 text_view->bottom_window,
4046 buffer_x, buffer_y);
4050 g_warning ("%s: Unknown GtkTextWindowType", G_STRLOC);
4056 set_window_width (GtkTextView *text_view,
4058 GtkTextWindowType type,
4059 GtkTextWindow **winp)
4065 text_window_free (*winp);
4067 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4074 *winp = text_window_new (type,
4075 GTK_WIDGET (text_view),
4080 if ((*winp)->requisition.width == width)
4084 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4090 set_window_height (GtkTextView *text_view,
4092 GtkTextWindowType type,
4093 GtkTextWindow **winp)
4099 text_window_free (*winp);
4101 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4108 *winp = text_window_new (type,
4109 GTK_WIDGET (text_view),
4114 if ((*winp)->requisition.height == height)
4118 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4123 gtk_text_view_set_border_window_size (GtkTextView *text_view,
4124 GtkTextWindowType type,
4128 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4129 g_return_if_fail (size >= 0);
4130 g_return_if_fail (type != GTK_TEXT_WINDOW_WIDGET);
4131 g_return_if_fail (type != GTK_TEXT_WINDOW_TEXT);
4135 case GTK_TEXT_WINDOW_LEFT:
4136 set_window_width (text_view, size, GTK_TEXT_WINDOW_LEFT,
4137 &text_view->left_window);
4140 case GTK_TEXT_WINDOW_RIGHT:
4141 set_window_width (text_view, size, GTK_TEXT_WINDOW_RIGHT,
4142 &text_view->right_window);
4145 case GTK_TEXT_WINDOW_TOP:
4146 set_window_height (text_view, size, GTK_TEXT_WINDOW_TOP,
4147 &text_view->top_window);
4150 case GTK_TEXT_WINDOW_BOTTOM:
4151 set_window_height (text_view, size, GTK_TEXT_WINDOW_BOTTOM,
4152 &text_view->bottom_window);
4156 g_warning ("Unknown GtkTextWindowType in %s", G_STRLOC);
4162 gtk_text_view_set_text_window_size (GtkTextView *text_view,
4168 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4169 g_return_if_fail (width > 0);
4170 g_return_if_fail (height > 0);
4172 win = text_view->text_window;
4174 if (win->requisition.width == width &&
4175 win->requisition.height == height)
4178 win->requisition.width = width;
4179 win->requisition.height = height;
4181 gtk_widget_queue_resize (GTK_WIDGET (text_view));
4188 static GtkTextViewChild*
4189 text_view_child_new_anchored (GtkWidget *child,
4190 GtkTextChildAnchor *anchor)
4192 GtkTextViewChild *vc;
4194 vc = g_new (GtkTextViewChild, 1);
4197 vc->anchor = anchor;
4199 g_object_ref (G_OBJECT (vc->widget));
4200 gtk_text_child_anchor_ref (vc->anchor);
4202 gtk_object_set_data (GTK_OBJECT (child),
4203 "gtk-text-view-child",
4209 static GtkTextViewChild*
4210 text_view_child_new_window (GtkWidget *child,
4211 GtkTextWindowType type,
4215 GtkTextViewChild *vc;
4217 vc = g_new (GtkTextViewChild, 1);
4222 g_object_ref (G_OBJECT (vc->widget));
4232 text_view_child_free (GtkTextViewChild *child)
4235 gtk_object_remove_data (GTK_OBJECT (child->widget),
4236 "gtk-text-view-child");
4238 g_object_unref (G_OBJECT (child->widget));
4239 gtk_text_child_anchor_unref (child->anchor);
4245 text_view_child_realize (GtkTextView *text_view,
4246 GtkTextViewChild *vc)
4249 gtk_widget_set_parent_window (vc->widget,
4250 text_view->text_window->bin_window);
4254 window = gtk_text_view_get_window (text_view,
4256 gtk_widget_set_parent_window (vc->widget, window);
4259 gtk_widget_realize (vc->widget);
4263 text_view_child_unrealize (GtkTextViewChild *vc)
4265 gtk_widget_unrealize (vc->widget);
4269 add_child (GtkTextView *text_view,
4270 GtkTextViewChild *vc)
4272 text_view->children = g_slist_prepend (text_view->children,
4275 gtk_widget_set_parent (vc->widget, GTK_WIDGET (text_view));
4277 if (GTK_WIDGET_REALIZED (text_view))
4278 text_view_child_realize (text_view, vc);
4280 if (GTK_WIDGET_VISIBLE (text_view) && GTK_WIDGET_VISIBLE (vc->widget))
4282 if (GTK_WIDGET_MAPPED (text_view))
4283 gtk_widget_map (vc->widget);
4285 gtk_widget_queue_resize (vc->widget);
4290 gtk_text_view_add_child_at_anchor (GtkTextView *text_view,
4292 GtkTextChildAnchor *anchor)
4294 GtkTextViewChild *vc;
4296 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4297 g_return_if_fail (GTK_IS_WIDGET (child));
4298 g_return_if_fail (anchor != NULL);
4299 g_return_if_fail (child->parent == NULL);
4301 vc = text_view_child_new_anchored (child, anchor);
4303 add_child (text_view, vc);
4307 gtk_text_view_add_child_in_window (GtkTextView *text_view,
4309 GtkTextWindowType which_window,
4313 GtkTextViewChild *vc;
4315 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4316 g_return_if_fail (GTK_IS_WIDGET (child));
4317 g_return_if_fail (xpos >= 0);
4318 g_return_if_fail (ypos >= 0);
4319 g_return_if_fail (child->parent == NULL);
4321 vc = text_view_child_new_window (child, which_window,
4324 add_child (text_view, vc);
4328 gtk_text_view_move_child (GtkTextView *text_view,
4333 GtkTextViewChild *vc;
4335 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
4336 g_return_if_fail (GTK_IS_WIDGET (child));
4337 g_return_if_fail (xpos >= 0);
4338 g_return_if_fail (ypos >= 0);
4339 g_return_if_fail (child->parent == (GtkWidget*) text_view);
4341 vc = gtk_object_get_data (GTK_OBJECT (child),
4342 "gtk-text-view-child");
4344 g_assert (vc != NULL);
4349 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
4350 gtk_widget_queue_resize (child);