1 /* gtktext.c - A "view" widget for the GtkTextBuffer object
3 * Copyright (c) 1992-1994 The Regents of the University of California.
4 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
5 * Copyright (c) 1999 by Scriptics Corporation.
6 * Copyright (c) 2000 Red Hat, Inc.
7 * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
9 * This software is copyrighted by the Regents of the University of
10 * California, Sun Microsystems, Inc., and other parties. The
11 * following terms apply to all files associated with the software
12 * unless explicitly disclaimed in individual files.
14 * The authors hereby grant permission to use, copy, modify,
15 * distribute, and license this software and its documentation for any
16 * purpose, provided that existing copyright notices are retained in
17 * all copies and that this notice is included verbatim in any
18 * distributions. No written agreement, license, or royalty fee is
19 * required for any of the authorized uses. Modifications to this
20 * software may be copyrighted by their authors and need not follow
21 * the licensing terms described here, provided that the new terms are
22 * clearly indicated on the first page of each file where they apply.
24 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
25 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
26 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
27 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
33 * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
34 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
35 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
37 * GOVERNMENT USE: If you are acquiring this software on behalf of the
38 * U.S. government, the Government shall have only "Restricted Rights"
39 * in the software and related documentation as defined in the Federal
40 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
41 * are acquiring the software on behalf of the Department of Defense,
42 * the software shall be classified as "Commercial Computer Software"
43 * and the Government shall have only "Restricted Rights" as defined
44 * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
45 * foregoing, the authors grant the U.S. Government and others acting
46 * in its behalf permission to use and distribute the software in
47 * accordance with the terms specified in this license.
53 #include "gtkbindings.h"
56 #include "gtksignal.h"
58 #include "gtktextdisplay.h"
59 #include "gtktextview.h"
60 #include "gtkimmulticontext.h"
61 #include "gdk/gdkkeysyms.h"
62 #include "gtktexttypes.h"
74 SET_SCROLL_ADJUSTMENTS,
82 ARG_PIXELS_ABOVE_LINES,
83 ARG_PIXELS_BELOW_LINES,
84 ARG_PIXELS_INSIDE_WRAP,
90 static void gtk_text_view_init (GtkTextView *text_view);
91 static void gtk_text_view_class_init (GtkTextViewClass *klass);
92 static void gtk_text_view_destroy (GtkObject *object);
93 static void gtk_text_view_finalize (GObject *object);
94 static void gtk_text_view_set_arg (GtkObject *object,
97 static void gtk_text_view_get_arg (GtkObject *object,
100 static void gtk_text_view_size_request (GtkWidget *widget,
101 GtkRequisition *requisition);
102 static void gtk_text_view_size_allocate (GtkWidget *widget,
103 GtkAllocation *allocation);
104 static void gtk_text_view_realize (GtkWidget *widget);
105 static void gtk_text_view_unrealize (GtkWidget *widget);
106 static void gtk_text_view_style_set (GtkWidget *widget,
107 GtkStyle *previous_style);
108 static void gtk_text_view_direction_changed (GtkWidget *widget,
109 GtkTextDirection previous_direction);
110 static gint gtk_text_view_event (GtkWidget *widget,
112 static gint gtk_text_view_key_press_event (GtkWidget *widget,
114 static gint gtk_text_view_key_release_event (GtkWidget *widget,
116 static gint gtk_text_view_button_press_event (GtkWidget *widget,
117 GdkEventButton *event);
118 static gint gtk_text_view_button_release_event (GtkWidget *widget,
119 GdkEventButton *event);
120 static gint gtk_text_view_focus_in_event (GtkWidget *widget,
121 GdkEventFocus *event);
122 static gint gtk_text_view_focus_out_event (GtkWidget *widget,
123 GdkEventFocus *event);
124 static gint gtk_text_view_motion_event (GtkWidget *widget,
125 GdkEventMotion *event);
126 static void gtk_text_view_draw (GtkWidget *widget,
128 static gint gtk_text_view_expose_event (GtkWidget *widget,
129 GdkEventExpose *expose);
132 /* Source side drag signals */
133 static void gtk_text_view_drag_begin (GtkWidget *widget,
134 GdkDragContext *context);
135 static void gtk_text_view_drag_end (GtkWidget *widget,
136 GdkDragContext *context);
137 static void gtk_text_view_drag_data_get (GtkWidget *widget,
138 GdkDragContext *context,
139 GtkSelectionData *selection_data,
142 static void gtk_text_view_drag_data_delete (GtkWidget *widget,
143 GdkDragContext *context);
145 /* Target side drag signals */
146 static void gtk_text_view_drag_leave (GtkWidget *widget,
147 GdkDragContext *context,
149 static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
150 GdkDragContext *context,
154 static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
155 GdkDragContext *context,
159 static void gtk_text_view_drag_data_received (GtkWidget *widget,
160 GdkDragContext *context,
163 GtkSelectionData *selection_data,
167 static void gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
169 GtkAdjustment *vadj);
171 static void gtk_text_view_move_insert (GtkTextView *text_view,
172 GtkTextViewMovementStep step,
174 gboolean extend_selection);
175 static void gtk_text_view_set_anchor (GtkTextView *text_view);
176 static void gtk_text_view_scroll_text (GtkTextView *text_view,
177 GtkTextViewScrollType type);
178 static void gtk_text_view_delete_text (GtkTextView *text_view,
179 GtkTextViewDeleteType type,
181 static void gtk_text_view_cut_text (GtkTextView *text_view);
182 static void gtk_text_view_copy_text (GtkTextView *text_view);
183 static void gtk_text_view_paste_text (GtkTextView *text_view);
184 static void gtk_text_view_toggle_overwrite (GtkTextView *text_view);
187 static void gtk_text_view_validate_onscreen (GtkTextView *text_view);
188 static void gtk_text_view_get_first_para_iter (GtkTextView *text_view,
190 static void gtk_text_view_scroll_calc_now (GtkTextView *text_view);
191 static void gtk_text_view_set_values_from_style (GtkTextView *text_view,
192 GtkTextStyleValues *values,
194 static void gtk_text_view_ensure_layout (GtkTextView *text_view);
195 static void gtk_text_view_destroy_layout (GtkTextView *text_view);
196 static void gtk_text_view_start_selection_drag (GtkTextView *text_view,
197 const GtkTextIter *iter,
198 GdkEventButton *event);
199 static gboolean gtk_text_view_end_selection_drag (GtkTextView *text_view,
200 GdkEventButton *event);
201 static void gtk_text_view_start_selection_dnd (GtkTextView *text_view,
202 const GtkTextIter *iter,
203 GdkEventButton *event);
204 static void gtk_text_view_start_cursor_blink (GtkTextView *text_view);
205 static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view);
207 static void gtk_text_view_value_changed (GtkAdjustment *adj,
209 static void gtk_text_view_commit_handler (GtkIMContext *context,
211 GtkTextView *text_view);
213 static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
214 const GtkTextIter *location,
215 const char *mark_name,
217 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
220 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
224 static GtkAdjustment* get_hadjustment (GtkTextView *text_view);
225 static GtkAdjustment* get_vadjustment (GtkTextView *text_view);
230 TARGET_COMPOUND_TEXT,
234 static GdkAtom clipboard_atom = GDK_NONE;
235 static GdkAtom text_atom = GDK_NONE;
236 static GdkAtom ctext_atom = GDK_NONE;
237 static GdkAtom utf8_atom = GDK_NONE;
240 static GtkTargetEntry target_table[] = {
241 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
242 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
243 { "TEXT", 0, TARGET_TEXT },
244 { "text/plain", 0, TARGET_STRING },
245 { "STRING", 0, TARGET_STRING }
248 static guint n_targets = sizeof (target_table) / sizeof (target_table[0]);
250 static GtkContainerClass *parent_class = NULL;
251 static guint signals[LAST_SIGNAL] = { 0 };
254 gtk_text_view_get_type (void)
256 static GtkType our_type = 0;
260 static const GtkTypeInfo our_info =
263 sizeof (GtkTextView),
264 sizeof (GtkTextViewClass),
265 (GtkClassInitFunc) gtk_text_view_class_init,
266 (GtkObjectInitFunc) gtk_text_view_init,
267 /* reserved_1 */ NULL,
268 /* reserved_2 */ NULL,
269 (GtkClassInitFunc) NULL
272 our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
279 add_move_insert_binding (GtkBindingSet *binding_set,
282 GtkTextViewMovementStep step,
285 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
287 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
291 GTK_TYPE_BOOL, FALSE);
293 /* Selection-extending version */
294 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
298 GTK_TYPE_BOOL, TRUE);
302 gtk_text_view_class_init (GtkTextViewClass *klass)
304 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
305 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
306 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
307 GtkBindingSet *binding_set;
309 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
314 gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
315 GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
316 gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
317 GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
318 gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
319 GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
320 gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
321 GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
322 gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
323 GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
324 gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
325 GTK_ARG_READWRITE, ARG_EDITABLE);
326 gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
327 GTK_ARG_READWRITE, ARG_WRAP_MODE);
334 signals[MOVE_INSERT] =
335 gtk_signal_new ("move_insert",
336 GTK_RUN_LAST | GTK_RUN_ACTION,
337 GTK_CLASS_TYPE (object_class),
338 GTK_SIGNAL_OFFSET (GtkTextViewClass, move_insert),
339 gtk_marshal_NONE__INT_INT_INT,
340 GTK_TYPE_NONE, 3, GTK_TYPE_ENUM, GTK_TYPE_INT, GTK_TYPE_BOOL);
342 signals[SET_ANCHOR] =
343 gtk_signal_new ("set_anchor",
344 GTK_RUN_LAST | GTK_RUN_ACTION,
345 GTK_CLASS_TYPE (object_class),
346 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
347 gtk_marshal_NONE__NONE,
350 signals[SCROLL_TEXT] =
351 gtk_signal_new ("scroll_text",
352 GTK_RUN_LAST | GTK_RUN_ACTION,
353 GTK_CLASS_TYPE (object_class),
354 GTK_SIGNAL_OFFSET (GtkTextViewClass, scroll_text),
355 gtk_marshal_NONE__INT,
356 GTK_TYPE_NONE, 1, GTK_TYPE_ENUM);
358 signals[DELETE_TEXT] =
359 gtk_signal_new ("delete_text",
360 GTK_RUN_LAST | GTK_RUN_ACTION,
361 GTK_CLASS_TYPE (object_class),
362 GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_text),
363 gtk_marshal_NONE__INT_INT,
364 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_INT);
367 gtk_signal_new ("cut_text",
368 GTK_RUN_LAST | GTK_RUN_ACTION,
369 GTK_CLASS_TYPE (object_class),
370 GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_text),
371 gtk_marshal_NONE__NONE,
375 gtk_signal_new ("copy_text",
376 GTK_RUN_LAST | GTK_RUN_ACTION,
377 GTK_CLASS_TYPE (object_class),
378 GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_text),
379 gtk_marshal_NONE__NONE,
382 signals[PASTE_TEXT] =
383 gtk_signal_new ("paste_text",
384 GTK_RUN_LAST | GTK_RUN_ACTION,
385 GTK_CLASS_TYPE (object_class),
386 GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_text),
387 gtk_marshal_NONE__NONE,
390 signals[TOGGLE_OVERWRITE] =
391 gtk_signal_new ("toggle_overwrite",
392 GTK_RUN_LAST | GTK_RUN_ACTION,
393 GTK_CLASS_TYPE (object_class),
394 GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
395 gtk_marshal_NONE__NONE,
398 signals[SET_SCROLL_ADJUSTMENTS] = widget_class->set_scroll_adjustments_signal =
399 gtk_signal_new ("set_scroll_adjustments",
401 GTK_CLASS_TYPE (object_class),
402 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
403 gtk_marshal_NONE__POINTER_POINTER,
404 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
406 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
412 binding_set = gtk_binding_set_by_class (klass);
414 /* Moving the insertion point */
415 add_move_insert_binding (binding_set, GDK_Right, 0,
416 GTK_TEXT_MOVEMENT_POSITIONS, 1);
418 add_move_insert_binding (binding_set, GDK_Left, 0,
419 GTK_TEXT_MOVEMENT_POSITIONS, -1);
421 add_move_insert_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
422 GTK_TEXT_MOVEMENT_CHAR, 1);
424 add_move_insert_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
425 GTK_TEXT_MOVEMENT_CHAR, -1);
427 add_move_insert_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
428 GTK_TEXT_MOVEMENT_WORD, 1);
430 add_move_insert_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
431 GTK_TEXT_MOVEMENT_WORD, -1);
433 /* Eventually we want to move by display lines, not paragraphs */
434 add_move_insert_binding (binding_set, GDK_Up, 0,
435 GTK_TEXT_MOVEMENT_WRAPPED_LINE, -1);
437 add_move_insert_binding (binding_set, GDK_Down, 0,
438 GTK_TEXT_MOVEMENT_WRAPPED_LINE, 1);
440 add_move_insert_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
441 GTK_TEXT_MOVEMENT_WRAPPED_LINE, -1);
443 add_move_insert_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
444 GTK_TEXT_MOVEMENT_WRAPPED_LINE, 1);
446 add_move_insert_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
447 GTK_TEXT_MOVEMENT_LINE_ENDS, -1);
449 add_move_insert_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
450 GTK_TEXT_MOVEMENT_LINE_ENDS, 1);
452 add_move_insert_binding (binding_set, GDK_f, GDK_MOD1_MASK,
453 GTK_TEXT_MOVEMENT_WORD, 1);
455 add_move_insert_binding (binding_set, GDK_b, GDK_MOD1_MASK,
456 GTK_TEXT_MOVEMENT_WORD, -1);
458 add_move_insert_binding (binding_set, GDK_Home, 0,
459 GTK_TEXT_MOVEMENT_BUFFER_ENDS, -1);
461 add_move_insert_binding (binding_set, GDK_End, 0,
462 GTK_TEXT_MOVEMENT_BUFFER_ENDS, 1);
464 /* Setting the cut/paste/copy anchor */
465 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
469 /* Scrolling around */
470 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
472 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_UP);
474 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
476 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_DOWN);
479 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
481 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
484 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
486 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
489 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
491 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
494 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
496 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
499 gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
501 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_LINE,
504 gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
506 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHOLE_LINE,
509 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
511 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE,
514 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
516 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE,
521 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
524 gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
527 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
530 gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
534 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
535 "toggle_overwrite", 0);
538 * Default handlers and virtual methods
540 object_class->set_arg = gtk_text_view_set_arg;
541 object_class->get_arg = gtk_text_view_get_arg;
543 object_class->destroy = gtk_text_view_destroy;
544 gobject_class->finalize = gtk_text_view_finalize;
546 widget_class->realize = gtk_text_view_realize;
547 widget_class->unrealize = gtk_text_view_unrealize;
548 widget_class->style_set = gtk_text_view_style_set;
549 widget_class->direction_changed = gtk_text_view_direction_changed;
550 widget_class->size_request = gtk_text_view_size_request;
551 widget_class->size_allocate = gtk_text_view_size_allocate;
552 widget_class->event = gtk_text_view_event;
553 widget_class->key_press_event = gtk_text_view_key_press_event;
554 widget_class->key_release_event = gtk_text_view_key_release_event;
555 widget_class->button_press_event = gtk_text_view_button_press_event;
556 widget_class->button_release_event = gtk_text_view_button_release_event;
557 widget_class->focus_in_event = gtk_text_view_focus_in_event;
558 widget_class->focus_out_event = gtk_text_view_focus_out_event;
559 widget_class->motion_notify_event = gtk_text_view_motion_event;
560 widget_class->expose_event = gtk_text_view_expose_event;
561 widget_class->draw = gtk_text_view_draw;
563 widget_class->drag_begin = gtk_text_view_drag_begin;
564 widget_class->drag_end = gtk_text_view_drag_end;
565 widget_class->drag_data_get = gtk_text_view_drag_data_get;
566 widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
568 widget_class->drag_leave = gtk_text_view_drag_leave;
569 widget_class->drag_motion = gtk_text_view_drag_motion;
570 widget_class->drag_drop = gtk_text_view_drag_drop;
571 widget_class->drag_data_received = gtk_text_view_drag_data_received;
573 klass->move_insert = gtk_text_view_move_insert;
574 klass->set_anchor = gtk_text_view_set_anchor;
575 klass->scroll_text = gtk_text_view_scroll_text;
576 klass->delete_text = gtk_text_view_delete_text;
577 klass->cut_text = gtk_text_view_cut_text;
578 klass->copy_text = gtk_text_view_copy_text;
579 klass->paste_text = gtk_text_view_paste_text;
580 klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
581 klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
585 gtk_text_view_init (GtkTextView *text_view)
589 widget = GTK_WIDGET (text_view);
591 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
593 text_view->wrap_mode = GTK_WRAPMODE_NONE;
596 clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
599 text_atom = gdk_atom_intern ("TEXT", FALSE);
602 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
605 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
607 gtk_drag_dest_set (widget,
608 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION,
609 target_table, n_targets,
610 GDK_ACTION_COPY | GDK_ACTION_MOVE);
612 text_view->virtual_cursor_x = -1;
613 text_view->virtual_cursor_y = -1;
615 /* This object is completely private. No external entity can gain a reference
616 * to it; so we create it here and destroy it in finalize().
618 text_view->im_context = gtk_im_multicontext_new ();
620 gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
621 GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
623 text_view->editable = TRUE;
624 text_view->cursor_visible = TRUE;
628 gtk_text_view_new (void)
630 return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
634 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
636 GtkTextView *text_view;
638 text_view = (GtkTextView*)gtk_text_view_new ();
640 gtk_text_view_set_buffer (text_view, buffer);
642 return GTK_WIDGET (text_view);
646 gtk_text_view_set_buffer (GtkTextView *text_view,
647 GtkTextBuffer *buffer)
649 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
650 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
652 if (text_view->buffer == buffer)
655 if (text_view->buffer != NULL)
657 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer),
658 gtk_text_view_mark_set_handler, text_view);
659 gtk_object_unref (GTK_OBJECT (text_view->buffer));
660 text_view->dnd_mark = NULL;
663 text_view->buffer = buffer;
669 gtk_object_ref (GTK_OBJECT (buffer));
670 gtk_object_sink (GTK_OBJECT (buffer));
672 if (text_view->layout)
673 gtk_text_layout_set_buffer (text_view->layout, buffer);
675 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
677 text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
681 text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
685 text_view->first_para_pixels = 0;
687 gtk_signal_connect (GTK_OBJECT (text_view->buffer), "mark_set",
688 gtk_text_view_mark_set_handler, text_view);
691 if (GTK_WIDGET_VISIBLE (text_view))
692 gtk_widget_queue_draw (GTK_WIDGET (text_view));
696 gtk_text_view_get_buffer (GtkTextView *text_view)
698 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
700 return text_view->buffer;
704 gtk_text_view_get_iter_at_pixel (GtkTextView *text_view,
708 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
709 g_return_if_fail (iter != NULL);
710 g_return_if_fail (text_view->layout != NULL);
712 gtk_text_layout_get_iter_at_pixel (text_view->layout,
714 x + text_view->xoffset,
715 y + text_view->yoffset);
719 gtk_text_view_get_iter_location (GtkTextView *text_view,
720 const GtkTextIter *iter,
721 GdkRectangle *location)
723 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
724 g_return_if_fail (gtk_text_iter_get_buffer (iter) == text_view->buffer);
726 gtk_text_layout_get_iter_location (text_view->layout, iter, location);
730 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
732 /* We don't really want to clamp to upper; we want to clamp to
733 upper - page_size which is the highest value the scrollbar
734 will let us reach. */
735 if (val > (adj->upper - adj->page_size))
736 val = adj->upper - adj->page_size;
738 if (val < adj->lower)
741 gtk_adjustment_set_value (adj, val);
745 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
756 gboolean retval = FALSE;
759 gint current_x_scroll, current_y_scroll;
761 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
762 g_return_val_if_fail (mark != NULL, FALSE);
764 widget = GTK_WIDGET (text_view);
766 if (!GTK_WIDGET_MAPPED (widget))
768 g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
772 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
774 gtk_text_layout_get_iter_location (text_view->layout,
778 /* Be sure the scroll region is up-to-date */
779 gtk_text_view_scroll_calc_now (text_view);
781 current_x_scroll = text_view->xoffset;
782 current_y_scroll = text_view->yoffset;
784 screen.x = current_x_scroll;
785 screen.y = current_y_scroll;
786 screen.width = widget->allocation.width;
787 screen.height = widget->allocation.height;
790 /* Clamp margin so it's not too large. */
791 gint small_dimension = MIN (screen.width, screen.height);
794 if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
795 margin = (small_dimension/2 - 5);
800 /* make sure rectangle fits in the leftover space */
802 max_rect_dim = MAX (rect.width, rect.height);
804 if (max_rect_dim > (small_dimension - margin*2))
805 margin -= max_rect_dim - (small_dimension - margin*2);
811 g_assert (margin >= 0);
816 screen.width -= margin*2;
817 screen.height -= margin*2;
819 screen_bottom = screen.y + screen.height;
820 screen_right = screen.x + screen.width;
822 /* Vertical scroll (only vertical gets adjusted) */
825 if (rect.y < screen.y)
827 gint scroll_dest = rect.y;
828 scroll_inc = (scroll_dest - screen.y) * percentage;
830 else if ((rect.y + rect.height) > screen_bottom)
832 gint scroll_dest = rect.y + rect.height;
833 scroll_inc = (scroll_dest - screen_bottom) * percentage;
838 set_adjustment_clamped (get_vadjustment (text_view),
839 current_y_scroll + scroll_inc);
843 /* Horizontal scroll */
846 if (rect.x < screen.x)
848 gint scroll_dest = rect.x;
849 scroll_inc = scroll_dest - screen.x;
851 else if ((rect.x + rect.width) > screen_right)
853 gint scroll_dest = rect.x + rect.width;
854 scroll_inc = scroll_dest - screen_right;
859 set_adjustment_clamped (get_hadjustment (text_view),
860 current_x_scroll + scroll_inc);
868 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
870 gint mark_within_margin)
872 g_return_val_if_fail (mark_within_margin >= 0, FALSE);
874 return gtk_text_view_scroll_to_mark_adjusted (text_view, mark,
875 mark_within_margin, 1.0);
879 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
881 GdkRectangle visible_rect;
882 gtk_text_view_get_visible_rect (text_view, &visible_rect);
884 return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
886 visible_rect.y + visible_rect.height);
890 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
895 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
896 g_return_val_if_fail (mark != NULL, FALSE);
898 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark);
900 if (clamp_iter_onscreen (text_view, &iter))
902 gtk_text_buffer_move_mark (text_view->buffer, mark, &iter);
910 gtk_text_view_get_visible_rect (GtkTextView *text_view,
911 GdkRectangle *visible_rect)
915 g_return_if_fail (text_view != NULL);
916 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
918 widget = GTK_WIDGET (text_view);
922 visible_rect->x = text_view->xoffset;
923 visible_rect->y = text_view->yoffset;
924 visible_rect->width = widget->allocation.width;
925 visible_rect->height = widget->allocation.height;
930 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
931 GtkWrapMode wrap_mode)
933 g_return_if_fail (text_view != NULL);
934 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
936 if (text_view->wrap_mode != wrap_mode)
938 text_view->wrap_mode = wrap_mode;
940 if (text_view->layout)
942 text_view->layout->default_style->wrap_mode = wrap_mode;
943 gtk_text_layout_default_style_changed (text_view->layout);
949 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
951 g_return_val_if_fail (text_view != NULL, GTK_WRAPMODE_NONE);
952 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAPMODE_NONE);
954 return text_view->wrap_mode;
958 gtk_text_view_set_editable (GtkTextView *text_view,
961 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
963 if (text_view->editable != setting)
965 text_view->editable = setting;
967 if (text_view->layout)
969 text_view->layout->default_style->editable = text_view->editable;
970 gtk_text_layout_default_style_changed (text_view->layout);
976 gtk_text_view_get_editable (GtkTextView *text_view)
978 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
980 return text_view->editable;
984 gtk_text_view_set_cursor_visible (GtkTextView *text_view,
987 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
989 if (text_view->cursor_visible != setting)
991 text_view->cursor_visible = setting;
993 if (GTK_WIDGET_HAS_FOCUS (text_view))
997 insert = gtk_text_buffer_get_mark (text_view->buffer,
999 gtk_text_mark_set_visible (insert, text_view->cursor_visible);
1005 gtk_text_view_get_cursor_visible (GtkTextView *text_view)
1007 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1009 return text_view->cursor_visible;
1014 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
1018 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
1020 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1021 gtk_text_buffer_get_mark (text_view->buffer,
1024 if (clamp_iter_onscreen (text_view, &insert))
1026 gtk_text_buffer_place_cursor (text_view->buffer, &insert);
1034 gtk_text_view_destroy (GtkObject *object)
1036 GtkTextView *text_view;
1038 text_view = GTK_TEXT_VIEW (object);
1040 gtk_text_view_destroy_layout (text_view);
1041 gtk_text_view_set_buffer (text_view, NULL);
1043 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1047 gtk_text_view_finalize (GObject *object)
1049 GtkTextView *text_view;
1051 text_view = GTK_TEXT_VIEW (object);
1053 if (text_view->hadjustment)
1054 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
1055 if (text_view->vadjustment)
1056 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
1058 gtk_object_unref (GTK_OBJECT (text_view->im_context));
1060 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1064 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1066 GtkTextView *text_view;
1068 text_view = GTK_TEXT_VIEW (object);
1072 case ARG_HEIGHT_LINES:
1075 case ARG_WIDTH_COLUMNS:
1078 case ARG_PIXELS_ABOVE_LINES:
1081 case ARG_PIXELS_BELOW_LINES:
1084 case ARG_PIXELS_INSIDE_WRAP:
1094 g_assert_not_reached ();
1100 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1102 GtkTextView *text_view;
1104 text_view = GTK_TEXT_VIEW (object);
1108 case ARG_HEIGHT_LINES:
1111 case ARG_WIDTH_COLUMNS:
1114 case ARG_PIXELS_ABOVE_LINES:
1117 case ARG_PIXELS_BELOW_LINES:
1120 case ARG_PIXELS_INSIDE_WRAP:
1130 arg->type = GTK_TYPE_INVALID;
1136 gtk_text_view_size_request (GtkWidget *widget,
1137 GtkRequisition *requisition)
1141 requisition->width = 200;
1142 requisition->height = 200;
1146 gtk_text_view_size_allocate (GtkWidget *widget,
1147 GtkAllocation *allocation)
1149 GtkTextView *text_view;
1150 GtkTextIter first_para;
1152 GtkAdjustment *vadj;
1153 gboolean yoffset_changed = FALSE;
1155 text_view = GTK_TEXT_VIEW (widget);
1157 widget->allocation = *allocation;
1159 if (GTK_WIDGET_REALIZED (widget))
1161 gdk_window_move_resize (widget->window,
1162 allocation->x, allocation->y,
1163 allocation->width, allocation->height);
1165 gdk_window_resize (text_view->bin_window,
1166 allocation->width, allocation->height);
1169 gtk_text_view_ensure_layout (text_view);
1170 gtk_text_layout_set_screen_width (text_view->layout,
1171 GTK_WIDGET (text_view)->allocation.width);
1173 gtk_text_view_validate_onscreen (text_view);
1174 gtk_text_view_scroll_calc_now (text_view);
1176 /* Now adjust the value of the adjustment to keep the cursor at the same place in
1179 gtk_text_view_get_first_para_iter (text_view, &first_para);
1180 y = gtk_text_layout_get_line_y (text_view->layout, &first_para) + text_view->first_para_pixels;
1182 /* Ensure h/v adj exist */
1183 get_hadjustment (text_view);
1184 get_vadjustment (text_view);
1186 vadj = text_view->vadjustment;
1187 if (y > vadj->upper - vadj->page_size)
1188 y = MAX (0, vadj->upper - vadj->page_size);
1190 if (y != text_view->yoffset)
1192 vadj->value = text_view->yoffset = y;
1193 yoffset_changed = TRUE;
1196 text_view->hadjustment->page_size = allocation->width;
1197 text_view->hadjustment->page_increment = allocation->width / 2;
1198 text_view->hadjustment->lower = 0;
1199 text_view->hadjustment->upper = MAX (allocation->width, text_view->width);
1200 gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
1202 text_view->vadjustment->page_size = allocation->height;
1203 text_view->vadjustment->page_increment = allocation->height / 2;
1204 text_view->vadjustment->lower = 0;
1205 text_view->vadjustment->upper = MAX (allocation->height, text_view->height);
1206 gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
1208 if (yoffset_changed)
1209 gtk_adjustment_value_changed (vadj);
1213 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
1216 gtk_text_buffer_get_iter_at_mark (text_view->buffer, iter,
1217 text_view->first_para_mark);
1221 gtk_text_view_validate_onscreen (GtkTextView *text_view)
1223 GtkWidget *widget = GTK_WIDGET (text_view);
1225 if (widget->allocation.height > 0)
1227 GtkTextIter first_para;
1228 gtk_text_view_get_first_para_iter (text_view, &first_para);
1229 gtk_text_layout_validate_yrange (text_view->layout,
1231 0, text_view->first_para_pixels + widget->allocation.height);
1236 first_validate_callback (gpointer data)
1238 GtkTextView *text_view = data;
1240 gtk_text_view_validate_onscreen (text_view);
1242 text_view->first_validate_idle = 0;
1247 incremental_validate_callback (gpointer data)
1249 GtkTextView *text_view = data;
1251 gtk_text_layout_validate (text_view->layout, 2000);
1252 if (gtk_text_layout_is_valid (text_view->layout))
1254 text_view->incremental_validate_idle = 0;
1262 invalidated_handler (GtkTextLayout *layout,
1265 GtkTextView *text_view;
1267 text_view = GTK_TEXT_VIEW (data);
1269 if (!text_view->first_validate_idle)
1270 text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
1272 if (!text_view->incremental_validate_idle)
1273 text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
1277 changed_handler (GtkTextLayout *layout,
1283 GtkTextView *text_view;
1285 GdkRectangle visible_rect;
1286 GdkRectangle redraw_rect;
1288 text_view = GTK_TEXT_VIEW (data);
1289 widget = GTK_WIDGET (data);
1291 if (GTK_WIDGET_REALIZED (text_view))
1293 gtk_text_view_get_visible_rect (text_view, &visible_rect);
1295 redraw_rect.x = visible_rect.x;
1296 redraw_rect.width = visible_rect.width;
1297 redraw_rect.y = start_y;
1299 if (old_height == new_height)
1300 redraw_rect.height = old_height;
1302 redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
1304 if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
1306 redraw_rect.y -= text_view->yoffset;
1307 gdk_window_invalidate_rect (text_view->bin_window, &redraw_rect, FALSE);
1311 if (old_height != new_height)
1313 gboolean yoffset_changed = FALSE;
1315 if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
1317 text_view->yoffset += new_height - old_height;
1318 get_vadjustment (text_view)->value = text_view->yoffset;
1319 yoffset_changed = TRUE;
1322 gtk_text_view_scroll_calc_now (text_view);
1324 if (yoffset_changed)
1325 gtk_adjustment_value_changed (get_vadjustment (text_view));
1330 gtk_text_view_realize (GtkWidget *widget)
1332 GtkTextView *text_view;
1334 GdkWindowAttr attributes;
1335 gint attributes_mask;
1337 text_view = GTK_TEXT_VIEW (widget);
1338 GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
1340 attributes.window_type = GDK_WINDOW_CHILD;
1341 attributes.x = widget->allocation.x;
1342 attributes.y = widget->allocation.y;
1343 attributes.width = widget->allocation.width;
1344 attributes.height = widget->allocation.height;
1345 attributes.wclass = GDK_INPUT_OUTPUT;
1346 attributes.visual = gtk_widget_get_visual (widget);
1347 attributes.colormap = gtk_widget_get_colormap (widget);
1348 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1350 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1352 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1353 &attributes, attributes_mask);
1354 gdk_window_set_user_data (widget->window, widget);
1358 attributes.width = widget->allocation.width;
1359 attributes.height = widget->allocation.height;
1360 attributes.event_mask = (GDK_EXPOSURE_MASK |
1362 GDK_KEY_PRESS_MASK |
1363 GDK_BUTTON_PRESS_MASK |
1364 GDK_BUTTON_RELEASE_MASK |
1365 GDK_POINTER_MOTION_MASK |
1366 GDK_POINTER_MOTION_HINT_MASK |
1367 gtk_widget_get_events (widget));
1369 text_view->bin_window = gdk_window_new (widget->window,
1370 &attributes, attributes_mask);
1371 gdk_window_show (text_view->bin_window);
1372 gdk_window_set_user_data (text_view->bin_window, widget);
1374 widget->style = gtk_style_attach (widget->style, widget->window);
1376 gdk_window_set_background (text_view->bin_window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1378 gtk_text_view_ensure_layout (text_view);
1381 cursor = gdk_cursor_new (GDK_XTERM);
1382 gdk_window_set_cursor (text_view->bin_window, cursor);
1383 gdk_cursor_destroy (cursor);
1385 gtk_im_context_set_client_window (text_view->im_context, widget->window);
1389 gtk_text_view_unrealize (GtkWidget *widget)
1391 GtkTextView *text_view;
1393 text_view = GTK_TEXT_VIEW (widget);
1395 if (text_view->first_validate_idle)
1397 g_source_remove (text_view->first_validate_idle);
1398 text_view->first_validate_idle = 0;
1401 if (text_view->incremental_validate_idle)
1403 g_source_remove (text_view->incremental_validate_idle);
1404 text_view->incremental_validate_idle = 0;
1407 gtk_text_view_destroy_layout (text_view);
1409 gtk_im_context_set_client_window (text_view->im_context, NULL);
1411 gdk_window_set_user_data (text_view->bin_window, NULL);
1412 gdk_window_destroy (text_view->bin_window);
1413 text_view->bin_window = NULL;
1415 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1419 gtk_text_view_style_set (GtkWidget *widget,
1420 GtkStyle *previous_style)
1422 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1424 if (GTK_WIDGET_REALIZED (widget))
1426 gdk_window_set_background (text_view->bin_window,
1427 &widget->style->base[GTK_WIDGET_STATE (widget)]);
1429 gtk_text_view_set_values_from_style (text_view, text_view->layout->default_style, widget->style);
1430 gtk_text_layout_default_style_changed (text_view->layout);
1435 gtk_text_view_direction_changed (GtkWidget *widget,
1436 GtkTextDirection previous_direction)
1438 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1440 if (text_view->layout)
1442 text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
1443 gtk_text_layout_default_style_changed (text_view->layout);
1452 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
1455 switch (event->type)
1457 case GDK_MOTION_NOTIFY:
1458 *x = event->motion.x;
1459 *y = event->motion.y;
1463 case GDK_BUTTON_PRESS:
1464 case GDK_2BUTTON_PRESS:
1465 case GDK_3BUTTON_PRESS:
1466 case GDK_BUTTON_RELEASE:
1467 *x = event->button.x;
1468 *y = event->button.y;
1473 case GDK_KEY_RELEASE:
1474 case GDK_ENTER_NOTIFY:
1475 case GDK_LEAVE_NOTIFY:
1476 case GDK_PROPERTY_NOTIFY:
1477 case GDK_SELECTION_CLEAR:
1478 case GDK_SELECTION_REQUEST:
1479 case GDK_SELECTION_NOTIFY:
1480 case GDK_PROXIMITY_IN:
1481 case GDK_PROXIMITY_OUT:
1482 case GDK_DRAG_ENTER:
1483 case GDK_DRAG_LEAVE:
1484 case GDK_DRAG_MOTION:
1485 case GDK_DRAG_STATUS:
1486 case GDK_DROP_START:
1487 case GDK_DROP_FINISHED:
1497 emit_event_on_tags (GtkWidget *widget,
1503 gint retval = FALSE;
1504 GtkTextView *text_view;
1506 text_view = GTK_TEXT_VIEW (widget);
1508 tags = gtk_text_buffer_get_tags (text_view->buffer, iter);
1513 GtkTextTag *tag = tmp->data;
1515 if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, iter))
1521 tmp = g_slist_next (tmp);
1524 g_slist_free (tags);
1530 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
1532 GtkTextView *text_view;
1535 text_view = GTK_TEXT_VIEW (widget);
1537 if (text_view->layout == NULL ||
1538 text_view->buffer == NULL)
1541 if (get_event_coordinates (event, &x, &y))
1545 x += text_view->xoffset;
1546 y += text_view->yoffset;
1548 /* FIXME this is slow and we do it twice per event.
1549 My favorite solution is to have GtkTextLayout cache
1550 the last couple lookups. */
1551 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1555 return emit_event_on_tags (widget, event, &iter);
1557 else if (event->type == GDK_KEY_PRESS ||
1558 event->type == GDK_KEY_RELEASE)
1560 GtkTextMark *insert;
1563 insert = gtk_text_buffer_get_mark (text_view->buffer,
1566 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, insert);
1568 return emit_event_on_tags (widget, event, &iter);
1575 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
1577 GtkTextView *text_view;
1579 text_view = GTK_TEXT_VIEW (widget);
1581 if (text_view->layout == NULL ||
1582 text_view->buffer == NULL)
1585 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
1586 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
1589 if (gtk_im_context_filter_keypress (text_view->im_context, event))
1591 else if (event->keyval == GDK_Return)
1593 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1,
1594 text_view->editable);
1595 gtk_text_view_scroll_to_mark (text_view,
1596 gtk_text_buffer_get_mark (text_view->buffer,
1606 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
1612 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
1614 GtkTextView *text_view;
1616 text_view = GTK_TEXT_VIEW (widget);
1618 gtk_widget_grab_focus (widget);
1621 if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
1622 gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
1623 else if (event->button == 3)
1624 gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
1626 if (event->type == GDK_BUTTON_PRESS)
1628 if (event->button == 1)
1630 /* If we're in the selection, start a drag copy/move of the
1631 selection; otherwise, start creating a new selection. */
1633 GtkTextIter start, end;
1635 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1637 event->x + text_view->xoffset,
1638 event->y + text_view->yoffset);
1640 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
1642 gtk_text_iter_in_region (&iter, &start, &end))
1644 gtk_text_view_start_selection_dnd (text_view, &iter, event);
1648 gtk_text_view_start_selection_drag (text_view, &iter, event);
1653 else if (event->button == 2)
1657 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1659 event->x + text_view->xoffset,
1660 event->y + text_view->yoffset);
1662 gtk_text_buffer_paste_primary_selection (text_view->buffer,
1666 text_view->editable);
1669 else if (event->button == 3)
1671 if (gtk_text_view_end_selection_drag (text_view, event))
1682 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
1684 if (event->button == 1)
1686 gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event);
1694 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1696 GtkTextMark *insert;
1698 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1700 insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1702 gtk_text_mark_set_visible (insert, GTK_TEXT_VIEW (widget)->cursor_visible);
1704 gtk_text_view_start_cursor_blink (GTK_TEXT_VIEW (widget));
1706 gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
1712 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1714 GtkTextMark *insert;
1716 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1718 insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1720 gtk_text_mark_set_visible (insert, FALSE);
1722 gtk_text_view_stop_cursor_blink (GTK_TEXT_VIEW (widget));
1724 gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
1730 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
1737 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
1739 GtkTextView *text_view;
1741 text_view = GTK_TEXT_VIEW (widget);
1743 g_return_if_fail (text_view->layout != NULL);
1744 g_return_if_fail (text_view->xoffset >= 0);
1745 g_return_if_fail (text_view->yoffset >= 0);
1747 gtk_text_view_validate_onscreen (text_view);
1750 printf ("painting %d,%d %d x %d\n",
1752 area->width, area->height);
1755 gtk_text_layout_draw (text_view->layout,
1757 text_view->bin_window,
1758 text_view->xoffset, text_view->yoffset,
1760 area->width, area->height);
1764 gtk_text_view_draw (GtkWidget *widget, GdkRectangle *area)
1766 gtk_text_view_paint (widget, area);
1770 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
1772 if (event->window == GTK_TEXT_VIEW (widget)->bin_window)
1773 gtk_text_view_paint (widget, &event->area);
1783 blink_cb (gpointer data)
1785 GtkTextView *text_view;
1786 GtkTextMark *insert;
1788 text_view = GTK_TEXT_VIEW (data);
1790 insert = gtk_text_buffer_get_mark (text_view->buffer,
1793 if (!GTK_WIDGET_HAS_FOCUS (text_view))
1795 /* paranoia, in case the user somehow mangles our
1796 focus_in/focus_out pairing. */
1797 gtk_text_mark_set_visible (insert, FALSE);
1798 text_view->blink_timeout = 0;
1803 gtk_text_mark_set_visible (insert,
1804 !gtk_text_mark_is_visible (insert));
1810 gtk_text_view_start_cursor_blink (GtkTextView *text_view)
1813 if (text_view->blink_timeout != 0)
1816 text_view->blink_timeout = gtk_timeout_add (500, blink_cb, text_view);
1820 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
1823 if (text_view->blink_timeout == 0)
1826 gtk_timeout_remove (text_view->blink_timeout);
1827 text_view->blink_timeout = 0;
1831 * Key binding handlers
1835 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
1836 GtkTextIter *newplace,
1841 gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
1847 gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
1853 gtk_text_view_move_insert (GtkTextView *text_view,
1854 GtkTextViewMovementStep step,
1856 gboolean extend_selection)
1859 GtkTextIter newplace;
1861 gint cursor_x_pos = 0;
1863 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1864 gtk_text_buffer_get_mark (text_view->buffer,
1868 if (step == GTK_TEXT_MOVEMENT_WRAPPED_LINE)
1869 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
1873 case GTK_TEXT_MOVEMENT_CHAR:
1874 gtk_text_iter_forward_chars (&newplace, count);
1877 case GTK_TEXT_MOVEMENT_POSITIONS:
1878 gtk_text_layout_move_iter_visually (text_view->layout,
1882 case GTK_TEXT_MOVEMENT_WORD:
1884 gtk_text_iter_backward_word_starts (&newplace, -count);
1886 gtk_text_iter_forward_word_ends (&newplace, count);
1889 case GTK_TEXT_MOVEMENT_WRAPPED_LINE:
1890 gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
1891 gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
1894 case GTK_TEXT_MOVEMENT_LINE:
1895 /* This should almost certainly instead be doing the parallel thing to WORD */
1896 /* gtk_text_iter_down_lines (&newplace, count); */
1900 case GTK_TEXT_MOVEMENT_LINE_ENDS:
1902 gtk_text_iter_forward_to_newline (&newplace);
1904 gtk_text_iter_set_line_offset (&newplace, 0);
1907 case GTK_TEXT_MOVEMENT_BUFFER_ENDS:
1909 gtk_text_buffer_get_last_iter (text_view->buffer, &newplace);
1911 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &newplace, 0);
1918 if (!gtk_text_iter_equal (&insert, &newplace))
1920 if (extend_selection)
1921 gtk_text_buffer_move_mark (text_view->buffer,
1922 gtk_text_buffer_get_mark (text_view->buffer,
1926 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
1928 gtk_text_view_scroll_to_mark (text_view,
1929 gtk_text_buffer_get_mark (text_view->buffer,
1932 if (step == GTK_TEXT_MOVEMENT_WRAPPED_LINE)
1934 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
1940 gtk_text_view_set_anchor (GtkTextView *text_view)
1944 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
1945 gtk_text_buffer_get_mark (text_view->buffer,
1948 gtk_text_buffer_create_mark (text_view->buffer, "anchor", &insert, TRUE);
1952 gtk_text_view_scroll_text (GtkTextView *text_view,
1953 GtkTextViewScrollType type)
1957 gint cursor_x_pos, cursor_y_pos;
1958 GtkTextIter new_insert;
1962 g_return_if_fail (text_view->vadjustment != NULL);
1964 adj = text_view->vadjustment;
1966 /* Validate the region that will be brought into view by the cursor motion
1971 case GTK_TEXT_SCROLL_TO_TOP:
1972 gtk_text_buffer_get_iter_at_offset (text_view->buffer, &anchor, 0);
1974 y1 = adj->page_size;
1977 case GTK_TEXT_SCROLL_TO_BOTTOM:
1978 gtk_text_buffer_get_last_iter (text_view->buffer, &anchor);
1979 y0 = -adj->page_size;
1980 y1 = adj->page_size;
1983 case GTK_TEXT_SCROLL_PAGE_DOWN:
1984 gtk_text_view_get_first_para_iter (text_view, &anchor);
1985 y0 = adj->page_size;
1986 y1 = adj->page_size + adj->page_increment;
1989 case GTK_TEXT_SCROLL_PAGE_UP:
1990 gtk_text_view_get_first_para_iter (text_view, &anchor);
1991 y0 = - adj->page_increment + adj->page_size;
1995 gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
1998 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
2000 newval = adj->value;
2003 case GTK_TEXT_SCROLL_TO_TOP:
2004 newval = adj->lower;
2007 case GTK_TEXT_SCROLL_TO_BOTTOM:
2008 newval = adj->upper;
2011 case GTK_TEXT_SCROLL_PAGE_DOWN:
2012 newval += adj->page_increment;
2015 case GTK_TEXT_SCROLL_PAGE_UP:
2016 newval -= adj->page_increment;
2023 cursor_y_pos += newval - adj->value;
2024 set_adjustment_clamped (adj, newval);
2026 gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
2027 clamp_iter_onscreen (text_view, &new_insert);
2028 gtk_text_buffer_place_cursor (text_view->buffer, &new_insert);
2030 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
2032 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
2033 * only guarantees 1 pixel onscreen.
2035 gtk_text_view_scroll_to_mark (text_view,
2036 gtk_text_buffer_get_mark (text_view->buffer,
2042 whitespace (gunichar ch, gpointer user_data)
2044 return (ch == ' ' || ch == '\t');
2048 not_whitespace (gunichar ch, gpointer user_data)
2050 return !whitespace (ch, user_data);
2054 find_whitepace_region (const GtkTextIter *center,
2055 GtkTextIter *start, GtkTextIter *end)
2060 if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL))
2061 gtk_text_iter_next_char (start); /* we want the first whitespace... */
2062 if (whitespace (gtk_text_iter_get_char (end), NULL))
2063 gtk_text_iter_forward_find_char (end, not_whitespace, NULL);
2065 return !gtk_text_iter_equal (start, end);
2069 gtk_text_view_delete_text (GtkTextView *text_view,
2070 GtkTextViewDeleteType type,
2076 gboolean leave_one = FALSE;
2078 if (type == GTK_TEXT_DELETE_CHAR)
2080 /* Char delete deletes the selection, if one exists */
2081 if (gtk_text_buffer_delete_selection (text_view->buffer, TRUE,
2082 text_view->editable))
2086 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
2088 gtk_text_buffer_get_mark (text_view->buffer,
2096 case GTK_TEXT_DELETE_CHAR:
2097 gtk_text_iter_forward_chars (&end, count);
2100 case GTK_TEXT_DELETE_HALF_WORD:
2102 gtk_text_iter_forward_word_ends (&end, count);
2104 gtk_text_iter_backward_word_starts (&start, 0 - count);
2107 case GTK_TEXT_DELETE_WHOLE_WORD:
2110 case GTK_TEXT_DELETE_HALF_WRAPPED_LINE:
2113 case GTK_TEXT_DELETE_WHOLE_WRAPPED_LINE:
2116 case GTK_TEXT_DELETE_HALF_LINE:
2119 if (!gtk_text_iter_forward_to_newline (&end))
2125 /* FIXME figure out what a negative count means
2129 case GTK_TEXT_DELETE_WHOLE_LINE:
2132 gtk_text_iter_set_line_offset (&start, 0);
2133 gtk_text_iter_forward_to_newline (&end);
2135 /* Do the lines beyond the first. */
2138 gtk_text_iter_forward_to_newline (&end);
2144 /* FIXME negative count? */
2148 case GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE:
2149 leave_one = TRUE; /* FALL THRU */
2150 case GTK_TEXT_DELETE_WHITESPACE:
2152 find_whitepace_region (&insert, &start, &end);
2160 if (!gtk_text_iter_equal (&start, &end))
2162 if (gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end,
2163 text_view->editable))
2166 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer,
2168 text_view->editable);
2171 gtk_text_view_scroll_to_mark (text_view,
2172 gtk_text_buffer_get_mark (text_view->buffer, "insert"),
2178 gtk_text_view_cut_text (GtkTextView *text_view)
2180 gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable);
2181 gtk_text_view_scroll_to_mark (text_view,
2182 gtk_text_buffer_get_mark (text_view->buffer,
2188 gtk_text_view_copy_text (GtkTextView *text_view)
2190 gtk_text_buffer_copy (text_view->buffer, GDK_CURRENT_TIME);
2191 gtk_text_view_scroll_to_mark (text_view,
2192 gtk_text_buffer_get_mark (text_view->buffer,
2198 gtk_text_view_paste_text (GtkTextView *text_view)
2200 gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable);
2201 gtk_text_view_scroll_to_mark (text_view,
2202 gtk_text_buffer_get_mark (text_view->buffer,
2208 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
2210 text_view->overwrite_mode = !text_view->overwrite_mode;
2218 move_insert_to_pointer_and_scroll (GtkTextView *text_view, gboolean partial_scroll)
2221 GdkModifierType state;
2222 GtkTextIter newplace;
2224 gboolean in_threshold = FALSE;
2226 gdk_window_get_pointer (text_view->bin_window, &x, &y, &state);
2228 /* Adjust movement by how long we've been selecting, to
2229 get an acceleration effect. The exact numbers are
2230 pretty arbitrary. We have a threshold before we
2231 start to accelerate. */
2232 /* uncommenting this printf helps visualize how it works. */
2233 /* printf ("%d\n", text_view->scrolling_accel_factor); */
2235 if (text_view->scrolling_accel_factor > 10)
2236 adjust = (text_view->scrolling_accel_factor - 10) * 75;
2238 if (y < 0) /* scrolling upward */
2241 /* No adjust if the pointer has moved back inside the window for sure.
2242 Also I'm adding a small threshold where no adjust is added,
2243 in case you want to do a continuous slow scroll. */
2244 #define SLOW_SCROLL_TH 7
2245 if (x >= (0 - SLOW_SCROLL_TH) &&
2246 x < (GTK_WIDGET (text_view)->allocation.width + SLOW_SCROLL_TH) &&
2247 y >= (0 - SLOW_SCROLL_TH) &&
2248 y < (GTK_WIDGET (text_view)->allocation.height + SLOW_SCROLL_TH))
2251 in_threshold = TRUE;
2254 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2256 x + text_view->xoffset,
2257 y + text_view->yoffset + adjust);
2260 gboolean scrolled = FALSE;
2261 GtkTextMark *insert_mark =
2262 gtk_text_buffer_get_mark (text_view->buffer, "insert");
2264 gtk_text_buffer_move_mark (text_view->buffer,
2269 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 0.7);
2271 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, insert_mark, 0, 1.0);
2275 /* We want to avoid rapid jump to super-accelerated when you
2276 leave the slow scroll threshold after scrolling for a
2277 while. So we slowly decrease accel when scrolling inside
2282 if (text_view->scrolling_accel_factor > 1)
2283 text_view->scrolling_accel_factor -= 2;
2286 text_view->scrolling_accel_factor += 1;
2290 /* If we don't scroll we're probably inside the window, but
2291 potentially just a bit outside. We decrease acceleration
2292 while the user is fooling around inside the window.
2293 Acceleration decreases faster than it increases. */
2294 if (text_view->scrolling_accel_factor > 4)
2295 text_view->scrolling_accel_factor -= 5;
2303 selection_scan_timeout (gpointer data)
2305 GtkTextView *text_view;
2307 text_view = GTK_TEXT_VIEW (data);
2309 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2311 return TRUE; /* remain installed. */
2315 text_view->selection_drag_scan_timeout = 0;
2316 return FALSE; /* remove ourselves */
2321 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
2323 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2325 /* If we had to scroll offscreen, insert a timeout to do so
2326 again. Note that in the timeout, even if the mouse doesn't
2327 move, due to this scroll xoffset/yoffset will have changed
2328 and we'll need to scroll again. */
2329 if (text_view->selection_drag_scan_timeout != 0) /* reset on every motion event */
2330 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2332 text_view->selection_drag_scan_timeout =
2333 gtk_timeout_add (50, selection_scan_timeout, text_view);
2340 gtk_text_view_start_selection_drag (GtkTextView *text_view,
2341 const GtkTextIter *iter,
2342 GdkEventButton *event)
2344 GtkTextIter newplace;
2346 g_return_if_fail (text_view->selection_drag_handler == 0);
2348 gtk_grab_add (GTK_WIDGET (text_view));
2350 text_view->scrolling_accel_factor = 0;
2354 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
2356 text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
2357 "motion_notify_event",
2358 GTK_SIGNAL_FUNC (selection_motion_event_handler),
2362 /* returns whether we were really dragging */
2364 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
2366 if (text_view->selection_drag_handler == 0)
2369 gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
2370 text_view->selection_drag_handler = 0;
2372 text_view->scrolling_accel_factor = 0;
2374 if (text_view->selection_drag_scan_timeout != 0)
2376 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2377 text_view->selection_drag_scan_timeout = 0;
2380 /* one last update to current position */
2381 move_insert_to_pointer_and_scroll (text_view, FALSE);
2383 gtk_grab_remove (GTK_WIDGET (text_view));
2393 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
2395 if (upper != adj->upper)
2397 gfloat min = MAX (0., upper - adj->page_size);
2398 gboolean value_changed = FALSE;
2402 if (adj->value > min)
2405 value_changed = TRUE;
2408 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
2410 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2415 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
2417 gint width = 0, height = 0;
2418 GtkWidget *widget = GTK_WIDGET (text_view);
2420 gtk_text_view_ensure_layout (text_view);
2423 gtk_text_layout_set_screen_width (text_view->layout,
2424 widget->allocation.width);
2426 gtk_text_layout_get_size (text_view->layout, &width, &height);
2429 /* If the width is less than the screen width (likely
2430 if we have wrapping turned on for the whole widget),
2431 then we want to set the scroll region to the screen
2432 width. If the width is greater (wrapping off) then we
2433 probably want to set the scroll region to the width
2434 of the layout. I guess.
2437 width = MAX (text_view->layout->screen_width, width);
2441 if (text_view->width != width || text_view->height != height)
2444 printf ("layout size set, widget width is %d\n",
2445 GTK_WIDGET (text_view)->allocation.width);
2447 text_view->width = width;
2448 text_view->height = height;
2450 gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
2451 MAX (widget->allocation.width, width));
2452 gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
2453 MAX (widget->allocation.height, height));
2455 /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
2457 /* Set up the step sizes; we'll say that a page is
2458 our allocation minus one step, and a step is
2459 1/10 of our allocation. */
2460 text_view->hadjustment->step_increment =
2461 GTK_WIDGET (text_view)->allocation.width/10.0;
2462 text_view->hadjustment->page_increment =
2463 GTK_WIDGET (text_view)->allocation.width *0.9;
2465 text_view->vadjustment->step_increment =
2466 GTK_WIDGET (text_view)->allocation.height/10.0;
2467 text_view->vadjustment->page_increment =
2468 GTK_WIDGET (text_view)->allocation.height *0.9;
2473 gtk_text_view_set_values_from_style (GtkTextView *text_view,
2474 GtkTextStyleValues *values,
2477 values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
2478 values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
2480 if (values->font_desc)
2481 pango_font_description_free (values->font_desc);
2483 values->font_desc = pango_font_description_copy (style->font_desc);
2487 gtk_text_view_ensure_layout (GtkTextView *text_view)
2491 widget = GTK_WIDGET (text_view);
2493 if (text_view->layout == NULL)
2495 GtkTextStyleValues *style;
2496 PangoContext *ltr_context, *rtl_context;
2498 text_view->layout = gtk_text_layout_new ();
2500 gtk_signal_connect (GTK_OBJECT (text_view->layout),
2502 GTK_SIGNAL_FUNC (invalidated_handler),
2505 gtk_signal_connect (GTK_OBJECT (text_view->layout),
2507 GTK_SIGNAL_FUNC (changed_handler),
2510 if (text_view->buffer)
2511 gtk_text_layout_set_buffer (text_view->layout, text_view->buffer);
2513 ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2514 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
2515 rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2516 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
2518 gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
2520 g_object_unref (G_OBJECT (ltr_context));
2521 g_object_unref (G_OBJECT (rtl_context));
2523 style = gtk_text_style_values_new ();
2525 gtk_widget_ensure_style (widget);
2526 gtk_text_view_set_values_from_style (text_view, style, widget->style);
2528 style->pixels_above_lines = 2;
2529 style->pixels_below_lines = 2;
2530 style->pixels_inside_wrap = 1;
2532 style->wrap_mode = text_view->wrap_mode;
2533 style->justify = GTK_JUSTIFY_LEFT;
2534 style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
2536 gtk_text_layout_set_default_style (text_view->layout, style);
2538 gtk_text_style_values_unref (style);
2543 gtk_text_view_destroy_layout (GtkTextView *text_view)
2545 if (text_view->layout)
2547 gtk_text_view_end_selection_drag (text_view, NULL);
2549 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2550 invalidated_handler, text_view);
2551 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2552 changed_handler, text_view);
2553 gtk_object_unref (GTK_OBJECT (text_view->layout));
2554 text_view->layout = NULL;
2564 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
2565 const GtkTextIter *iter,
2566 GdkEventButton *event)
2568 GdkDragContext *context;
2569 GtkTargetList *target_list;
2571 /* FIXME we have to handle more formats for the selection,
2572 and do the conversions to/from UTF8 */
2574 /* FIXME not sure how this is memory-managed. */
2575 target_list = gtk_target_list_new (target_table, n_targets);
2577 context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
2578 GDK_ACTION_COPY | GDK_ACTION_MOVE,
2579 1, (GdkEvent*)event);
2581 gtk_drag_set_icon_default (context);
2583 /* We're inside the selection, so start without being able
2584 to accept the drag. */
2585 gdk_drag_status (context, 0, event->time);
2586 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2590 gtk_text_view_drag_begin (GtkWidget *widget,
2591 GdkDragContext *context)
2597 gtk_text_view_drag_end (GtkWidget *widget,
2598 GdkDragContext *context)
2600 GtkTextView *text_view;
2602 text_view = GTK_TEXT_VIEW (widget);
2604 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2608 gtk_text_view_drag_data_get (GtkWidget *widget,
2609 GdkDragContext *context,
2610 GtkSelectionData *selection_data,
2618 GtkTextView *text_view;
2620 text_view = GTK_TEXT_VIEW (widget);
2625 if (gtk_text_buffer_get_selection_bounds (text_view->buffer, &start, &end))
2627 /* Extract the selected text */
2628 str = gtk_text_iter_get_visible_text (&start, &end);
2630 length = strlen (str);
2635 if (info == TARGET_UTF8_STRING)
2638 gtk_selection_data_set (selection_data,
2640 8*sizeof (gchar), (guchar *)str, length);
2643 else if (info == TARGET_STRING ||
2644 info == TARGET_TEXT)
2648 latin1 = gtk_text_utf_to_latin1(str, length);
2650 gtk_selection_data_set (selection_data,
2651 GDK_SELECTION_TYPE_STRING,
2652 8*sizeof (gchar), latin1, strlen (latin1));
2655 else if (info == TARGET_COMPOUND_TEXT)
2657 /* FIXME convert UTF8 directly to current locale, not via
2666 latin1 = gtk_text_utf_to_latin1(str, length);
2668 gdk_string_to_compound_text (latin1, &encoding, &format, &text, &new_length);
2669 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
2670 gdk_free_compound_text (text);
2680 gtk_text_view_drag_data_delete (GtkWidget *widget,
2681 GdkDragContext *context)
2683 gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer,
2684 TRUE, GTK_TEXT_VIEW (widget)->editable);
2688 gtk_text_view_drag_leave (GtkWidget *widget,
2689 GdkDragContext *context,
2697 gtk_text_view_drag_motion (GtkWidget *widget,
2698 GdkDragContext *context,
2703 GtkTextIter newplace;
2704 GtkTextView *text_view;
2708 text_view = GTK_TEXT_VIEW (widget);
2710 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2712 x + text_view->xoffset,
2713 y + text_view->yoffset);
2715 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
2717 gtk_text_iter_in_region (&newplace, &start, &end))
2719 /* We're inside the selection. */
2720 gdk_drag_status (context, 0, time);
2721 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2725 if (gtk_text_iter_editable (&newplace, text_view->editable))
2727 gtk_text_mark_set_visible (text_view->dnd_mark, text_view->cursor_visible);
2729 gdk_drag_status (context, context->suggested_action, time);
2733 /* Can't drop here. */
2734 gdk_drag_status (context, 0, time);
2735 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2739 gtk_text_buffer_move_mark (text_view->buffer,
2740 gtk_text_buffer_get_mark (text_view->buffer,
2745 /* The effect of this is that the text scrolls if you're near
2746 the edge. We have to scroll whether or not we're inside
2750 margin = MIN (widget->allocation.width, widget->allocation.height);
2753 gtk_text_view_scroll_to_mark_adjusted (text_view,
2754 gtk_text_buffer_get_mark (text_view->buffer,
2763 gtk_text_view_drag_drop (GtkWidget *widget,
2764 GdkDragContext *context,
2770 /* called automatically. */
2771 if (context->targets)
2773 gtk_drag_get_data (widget, context,
2774 GPOINTER_TO_INT (context->targets->data),
2785 gtk_text_view_drag_data_received (GtkWidget *widget,
2786 GdkDragContext *context,
2789 GtkSelectionData *selection_data,
2793 GtkTextIter drop_point;
2794 GtkTextView *text_view;
2795 GtkTextMark *drag_target_mark;
2797 enum {INVALID, STRING, CTEXT, UTF8} type;
2799 text_view = GTK_TEXT_VIEW (widget);
2801 if (selection_data->type == GDK_TARGET_STRING)
2803 else if (selection_data->type == ctext_atom)
2805 else if (selection_data->type == utf8_atom)
2810 if (type == INVALID || selection_data->length < 0)
2812 /* I think the DND code automatically tries asking
2813 for the various formats. */
2817 drag_target_mark = gtk_text_buffer_get_mark (text_view->buffer,
2820 if (drag_target_mark == NULL)
2823 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
2834 utf = gtk_text_latin1_to_utf ((const gchar*)selection_data->data,
2835 selection_data->length);
2836 gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point,
2838 text_view->editable);
2844 gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point,
2845 (const gchar *)selection_data->data,
2846 selection_data->length,
2847 text_view->editable);
2856 count = gdk_text_property_to_text_list (selection_data->type,
2857 selection_data->format,
2858 selection_data->data,
2859 selection_data->length,
2861 for (i=0; i<count; i++)
2863 /* list contains stuff in our default encoding */
2864 gboolean free_utf = FALSE;
2866 gchar *charset = NULL;
2868 if (g_get_charset (&charset))
2870 utf = g_convert (list[i], -1,
2871 "UTF8", charset, NULL);
2877 gtk_text_buffer_insert_interactive (text_view->buffer,
2878 &drop_point, utf, -1,
2879 text_view->editable);
2886 gdk_free_text_list (list);
2890 case INVALID: /* quiet compiler */
2895 static GtkAdjustment*
2896 get_hadjustment (GtkTextView *text_view)
2898 if (text_view->hadjustment == NULL)
2899 gtk_text_view_set_scroll_adjustments (text_view,
2901 gtk_adjustment_new (0.0, 0.0, 0.0,
2903 text_view->vadjustment);
2905 return text_view->hadjustment;
2908 static GtkAdjustment*
2909 get_vadjustment (GtkTextView *text_view)
2911 if (text_view->vadjustment == NULL)
2912 gtk_text_view_set_scroll_adjustments (text_view,
2913 text_view->hadjustment,
2915 gtk_adjustment_new (0.0, 0.0, 0.0,
2918 return text_view->vadjustment;
2923 gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
2924 GtkAdjustment *hadj,
2925 GtkAdjustment *vadj)
2927 gboolean need_adjust = FALSE;
2929 g_return_if_fail (text_view != NULL);
2930 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2933 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2935 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2937 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2939 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2941 if (text_view->hadjustment && (text_view->hadjustment != hadj))
2943 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
2944 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
2947 if (text_view->vadjustment && (text_view->vadjustment != vadj))
2949 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
2950 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
2953 if (text_view->hadjustment != hadj)
2955 text_view->hadjustment = hadj;
2956 gtk_object_ref (GTK_OBJECT (text_view->hadjustment));
2957 gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
2959 gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
2960 (GtkSignalFunc) gtk_text_view_value_changed,
2965 if (text_view->vadjustment != vadj)
2967 text_view->vadjustment = vadj;
2968 gtk_object_ref (GTK_OBJECT (text_view->vadjustment));
2969 gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
2971 gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
2972 (GtkSignalFunc) gtk_text_view_value_changed,
2978 gtk_text_view_value_changed (NULL, text_view);
2982 gtk_text_view_value_changed (GtkAdjustment *adj,
2983 GtkTextView *text_view)
2990 if (adj == text_view->hadjustment)
2992 dx = text_view->xoffset - (gint)adj->value;
2993 text_view->xoffset = adj->value;
2995 else if (adj == text_view->vadjustment)
2997 dy = text_view->yoffset - (gint)adj->value;
2998 text_view->yoffset = adj->value;
3000 if (text_view->layout)
3002 gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
3004 gtk_text_buffer_move_mark (text_view->buffer, text_view->first_para_mark, &iter);
3006 text_view->first_para_pixels = adj->value - line_top;
3010 if (dx != 0 || dy != 0)
3012 gdk_window_scroll (text_view->bin_window, dx, dy);
3013 gdk_window_process_updates (text_view->bin_window, TRUE);
3018 gtk_text_view_commit_handler (GtkIMContext *context,
3020 GtkTextView *text_view)
3022 gtk_text_buffer_delete_selection (text_view->buffer, TRUE,
3023 text_view->editable);
3025 if (!strcmp (str, "\n"))
3027 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1,
3028 text_view->editable);
3032 if (text_view->overwrite_mode)
3033 gtk_text_view_delete_text (text_view, GTK_TEXT_DELETE_CHAR, 1);
3034 gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, str, -1,
3035 text_view->editable);
3038 gtk_text_view_scroll_to_mark (text_view,
3039 gtk_text_buffer_get_mark (text_view->buffer,
3045 gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
3046 const GtkTextIter *location,
3047 const char *mark_name,
3050 GtkTextView *text_view = GTK_TEXT_VIEW (data);
3052 if (!strcmp (mark_name, "insert"))
3054 text_view->virtual_cursor_x = -1;
3055 text_view->virtual_cursor_y = -1;
3060 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
3064 GdkRectangle strong_pos;
3067 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
3068 gtk_text_buffer_get_mark (text_view->buffer,
3071 if ((x && text_view->virtual_cursor_x == -1) ||
3072 (y && text_view->virtual_cursor_y == -1))
3073 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
3077 if (text_view->virtual_cursor_x != -1)
3078 *x = text_view->virtual_cursor_x;
3085 if (text_view->virtual_cursor_x != -1)
3086 *y = text_view->virtual_cursor_y;
3088 *y = strong_pos.y + strong_pos.height / 2;
3093 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
3097 GdkRectangle strong_pos;
3100 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert,
3101 gtk_text_buffer_get_mark (text_view->buffer,
3104 if (x == -1 || y == -1)
3105 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
3107 text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
3108 text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;