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.
51 #include "gtkbindings.h"
54 #include "gtksignal.h"
56 #include "gtktextdisplay.h"
57 #include "gtktextview.h"
58 #include "gtkimmulticontext.h"
59 #include "gdk/gdkkeysyms.h"
70 SET_SCROLL_ADJUSTMENTS,
78 ARG_PIXELS_ABOVE_LINES,
79 ARG_PIXELS_BELOW_LINES,
80 ARG_PIXELS_INSIDE_WRAP,
86 static void gtk_text_view_init (GtkTextView *text_view);
87 static void gtk_text_view_class_init (GtkTextViewClass *klass);
88 static void gtk_text_view_destroy (GtkObject *object);
89 static void gtk_text_view_finalize (GObject *object);
90 static void gtk_text_view_set_arg (GtkObject *object,
93 static void gtk_text_view_get_arg (GtkObject *object,
96 static void gtk_text_view_size_request (GtkWidget *widget,
97 GtkRequisition *requisition);
98 static void gtk_text_view_size_allocate (GtkWidget *widget,
99 GtkAllocation *allocation);
100 static void gtk_text_view_realize (GtkWidget *widget);
101 static void gtk_text_view_unrealize (GtkWidget *widget);
102 static void gtk_text_view_style_set (GtkWidget *widget,
103 GtkStyle *previous_style);
104 static gint gtk_text_view_event (GtkWidget *widget,
106 static gint gtk_text_view_key_press_event (GtkWidget *widget,
108 static gint gtk_text_view_key_release_event (GtkWidget *widget,
110 static gint gtk_text_view_button_press_event (GtkWidget *widget,
111 GdkEventButton *event);
112 static gint gtk_text_view_button_release_event (GtkWidget *widget,
113 GdkEventButton *event);
114 static gint gtk_text_view_focus_in_event (GtkWidget *widget,
115 GdkEventFocus *event);
116 static gint gtk_text_view_focus_out_event (GtkWidget *widget,
117 GdkEventFocus *event);
118 static gint gtk_text_view_motion_event (GtkWidget *widget,
119 GdkEventMotion *event);
120 static void gtk_text_view_draw (GtkWidget *widget,
122 static gint gtk_text_view_expose_event (GtkWidget *widget,
123 GdkEventExpose *expose);
126 /* Source side drag signals */
127 static void gtk_text_view_drag_begin (GtkWidget *widget,
128 GdkDragContext *context);
129 static void gtk_text_view_drag_end (GtkWidget *widget,
130 GdkDragContext *context);
131 static void gtk_text_view_drag_data_get (GtkWidget *widget,
132 GdkDragContext *context,
133 GtkSelectionData *selection_data,
136 static void gtk_text_view_drag_data_delete (GtkWidget *widget,
137 GdkDragContext *context);
139 /* Target side drag signals */
140 static void gtk_text_view_drag_leave (GtkWidget *widget,
141 GdkDragContext *context,
143 static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
144 GdkDragContext *context,
148 static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
149 GdkDragContext *context,
153 static void gtk_text_view_drag_data_received (GtkWidget *widget,
154 GdkDragContext *context,
157 GtkSelectionData *selection_data,
161 static void gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
163 GtkAdjustment *vadj);
165 static void gtk_text_view_move_insert (GtkTextView *text_view,
166 GtkTextViewMovementStep step,
168 gboolean extend_selection);
169 static void gtk_text_view_set_anchor (GtkTextView *text_view);
170 static void gtk_text_view_scroll_text (GtkTextView *text_view,
171 GtkTextViewScrollType type);
172 static void gtk_text_view_delete_text (GtkTextView *text_view,
173 GtkTextViewDeleteType type,
175 static void gtk_text_view_cut_text (GtkTextView *text_view);
176 static void gtk_text_view_copy_text (GtkTextView *text_view);
177 static void gtk_text_view_paste_text (GtkTextView *text_view);
178 static void gtk_text_view_toggle_overwrite (GtkTextView *text_view);
181 static void gtk_text_view_validate_onscreen (GtkTextView *text_view);
182 static void gtk_text_view_get_first_para_iter (GtkTextView *text_view,
184 static void gtk_text_view_scroll_calc_now (GtkTextView *text_view);
185 static void gtk_text_view_set_values_from_style (GtkTextView *text_view,
186 GtkTextStyleValues *values,
188 static void gtk_text_view_ensure_layout (GtkTextView *text_view);
189 static void gtk_text_view_destroy_layout (GtkTextView *text_view);
190 static void gtk_text_view_start_selection_drag (GtkTextView *text_view,
191 const GtkTextIter *iter,
192 GdkEventButton *event);
193 static gboolean gtk_text_view_end_selection_drag (GtkTextView *text_view,
194 GdkEventButton *event);
195 static void gtk_text_view_start_selection_dnd (GtkTextView *text_view,
196 const GtkTextIter *iter,
197 GdkEventButton *event);
198 static void gtk_text_view_start_cursor_blink (GtkTextView *text_view);
199 static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view);
201 static void gtk_text_view_value_changed (GtkAdjustment *adj,
203 static void gtk_text_view_commit_handler (GtkIMContext *context,
205 GtkTextView *text_view);
207 static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
208 const GtkTextIter *location,
209 const char *mark_name,
211 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
214 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
221 TARGET_COMPOUND_TEXT,
225 static GdkAtom clipboard_atom = GDK_NONE;
226 static GdkAtom text_atom = GDK_NONE;
227 static GdkAtom ctext_atom = GDK_NONE;
228 static GdkAtom utf8_atom = GDK_NONE;
231 static GtkTargetEntry target_table[] = {
232 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
233 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
234 { "TEXT", 0, TARGET_TEXT },
235 { "text/plain", 0, TARGET_STRING },
236 { "STRING", 0, TARGET_STRING }
239 static guint n_targets = sizeof (target_table) / sizeof (target_table[0]);
241 static GtkContainerClass *parent_class = NULL;
242 static guint signals[LAST_SIGNAL] = { 0 };
245 gtk_text_view_get_type (void)
247 static GtkType our_type = 0;
251 static const GtkTypeInfo our_info =
254 sizeof (GtkTextView),
255 sizeof (GtkTextViewClass),
256 (GtkClassInitFunc) gtk_text_view_class_init,
257 (GtkObjectInitFunc) gtk_text_view_init,
258 /* reserved_1 */ NULL,
259 /* reserved_2 */ NULL,
260 (GtkClassInitFunc) NULL
263 our_type = gtk_type_unique (GTK_TYPE_CONTAINER, &our_info);
270 add_move_insert_binding (GtkBindingSet *binding_set,
273 GtkTextViewMovementStep step,
276 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
278 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
282 GTK_TYPE_BOOL, FALSE);
284 /* Selection-extending version */
285 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
289 GTK_TYPE_BOOL, TRUE);
293 gtk_text_view_class_init (GtkTextViewClass *klass)
295 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
296 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
297 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
298 GtkBindingSet *binding_set;
300 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
305 gtk_object_add_arg_type ("GtkTextView::height_lines", GTK_TYPE_INT,
306 GTK_ARG_READWRITE, ARG_HEIGHT_LINES);
307 gtk_object_add_arg_type ("GtkTextView::width_columns", GTK_TYPE_INT,
308 GTK_ARG_READWRITE, ARG_WIDTH_COLUMNS);
309 gtk_object_add_arg_type ("GtkTextView::pixels_above_lines", GTK_TYPE_INT,
310 GTK_ARG_READWRITE, ARG_PIXELS_ABOVE_LINES);
311 gtk_object_add_arg_type ("GtkTextView::pixels_below_lines", GTK_TYPE_INT,
312 GTK_ARG_READWRITE, ARG_PIXELS_BELOW_LINES);
313 gtk_object_add_arg_type ("GtkTextView::pixels_inside_wrap", GTK_TYPE_INT,
314 GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
315 gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
316 GTK_ARG_READWRITE, ARG_EDITABLE);
317 gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_ENUM,
318 GTK_ARG_READWRITE, ARG_WRAP_MODE);
325 signals[MOVE_INSERT] =
326 gtk_signal_new ("move_insert",
327 GTK_RUN_LAST | GTK_RUN_ACTION,
328 GTK_CLASS_TYPE (object_class),
329 GTK_SIGNAL_OFFSET (GtkTextViewClass, move_insert),
330 gtk_marshal_NONE__INT_INT_INT,
331 GTK_TYPE_NONE, 3, GTK_TYPE_ENUM, GTK_TYPE_INT, GTK_TYPE_BOOL);
333 signals[SET_ANCHOR] =
334 gtk_signal_new ("set_anchor",
335 GTK_RUN_LAST | GTK_RUN_ACTION,
336 GTK_CLASS_TYPE (object_class),
337 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_anchor),
338 gtk_marshal_NONE__NONE,
341 signals[SCROLL_TEXT] =
342 gtk_signal_new ("scroll_text",
343 GTK_RUN_LAST | GTK_RUN_ACTION,
344 GTK_CLASS_TYPE (object_class),
345 GTK_SIGNAL_OFFSET (GtkTextViewClass, scroll_text),
346 gtk_marshal_NONE__INT,
347 GTK_TYPE_NONE, 1, GTK_TYPE_ENUM);
349 signals[DELETE_TEXT] =
350 gtk_signal_new ("delete_text",
351 GTK_RUN_LAST | GTK_RUN_ACTION,
352 GTK_CLASS_TYPE (object_class),
353 GTK_SIGNAL_OFFSET (GtkTextViewClass, delete_text),
354 gtk_marshal_NONE__INT_INT,
355 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_INT);
358 gtk_signal_new ("cut_text",
359 GTK_RUN_LAST | GTK_RUN_ACTION,
360 GTK_CLASS_TYPE (object_class),
361 GTK_SIGNAL_OFFSET (GtkTextViewClass, cut_text),
362 gtk_marshal_NONE__NONE,
366 gtk_signal_new ("copy_text",
367 GTK_RUN_LAST | GTK_RUN_ACTION,
368 GTK_CLASS_TYPE (object_class),
369 GTK_SIGNAL_OFFSET (GtkTextViewClass, copy_text),
370 gtk_marshal_NONE__NONE,
373 signals[PASTE_TEXT] =
374 gtk_signal_new ("paste_text",
375 GTK_RUN_LAST | GTK_RUN_ACTION,
376 GTK_CLASS_TYPE (object_class),
377 GTK_SIGNAL_OFFSET (GtkTextViewClass, paste_text),
378 gtk_marshal_NONE__NONE,
381 signals[TOGGLE_OVERWRITE] =
382 gtk_signal_new ("toggle_overwrite",
383 GTK_RUN_LAST | GTK_RUN_ACTION,
384 GTK_CLASS_TYPE (object_class),
385 GTK_SIGNAL_OFFSET (GtkTextViewClass, toggle_overwrite),
386 gtk_marshal_NONE__NONE,
389 signals[SET_SCROLL_ADJUSTMENTS] = widget_class->set_scroll_adjustments_signal =
390 gtk_signal_new ("set_scroll_adjustments",
392 GTK_CLASS_TYPE (object_class),
393 GTK_SIGNAL_OFFSET (GtkTextViewClass, set_scroll_adjustments),
394 gtk_marshal_NONE__POINTER_POINTER,
395 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
397 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
403 binding_set = gtk_binding_set_by_class (klass);
405 /* Moving the insertion point */
406 add_move_insert_binding (binding_set, GDK_Right, 0,
407 GTK_TEXT_MOVEMENT_POSITIONS, 1);
409 add_move_insert_binding (binding_set, GDK_Left, 0,
410 GTK_TEXT_MOVEMENT_POSITIONS, -1);
412 add_move_insert_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
413 GTK_TEXT_MOVEMENT_CHAR, 1);
415 add_move_insert_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
416 GTK_TEXT_MOVEMENT_CHAR, -1);
418 add_move_insert_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
419 GTK_TEXT_MOVEMENT_WORD, 1);
421 add_move_insert_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
422 GTK_TEXT_MOVEMENT_WORD, -1);
424 /* Eventually we want to move by display lines, not paragraphs */
425 add_move_insert_binding (binding_set, GDK_Up, 0,
426 GTK_TEXT_MOVEMENT_LINE, -1);
428 add_move_insert_binding (binding_set, GDK_Down, 0,
429 GTK_TEXT_MOVEMENT_LINE, 1);
431 add_move_insert_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
432 GTK_TEXT_MOVEMENT_LINE, -1);
434 add_move_insert_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
435 GTK_TEXT_MOVEMENT_LINE, 1);
437 add_move_insert_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
438 GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, -1);
440 add_move_insert_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
441 GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, 1);
443 add_move_insert_binding (binding_set, GDK_f, GDK_MOD1_MASK,
444 GTK_TEXT_MOVEMENT_WORD, 1);
446 add_move_insert_binding (binding_set, GDK_b, GDK_MOD1_MASK,
447 GTK_TEXT_MOVEMENT_WORD, -1);
449 add_move_insert_binding (binding_set, GDK_Home, 0,
450 GTK_TEXT_MOVEMENT_BUFFER_ENDS, -1);
452 add_move_insert_binding (binding_set, GDK_End, 0,
453 GTK_TEXT_MOVEMENT_BUFFER_ENDS, 1);
455 /* Setting the cut/paste/copy anchor */
456 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
460 /* Scrolling around */
461 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
463 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_UP);
465 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
467 GTK_TYPE_ENUM, GTK_TEXT_SCROLL_PAGE_DOWN);
470 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
472 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
475 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
477 GTK_TYPE_ENUM, GTK_TEXT_DELETE_CHAR,
480 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
482 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
485 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
487 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_WORD,
490 gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
492 GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_PARAGRAPH,
495 gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
497 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHOLE_PARAGRAPH,
500 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
502 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE,
505 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
507 GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHITESPACE,
512 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
515 gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
518 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
521 gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
525 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
526 "toggle_overwrite", 0);
529 * Default handlers and virtual methods
531 object_class->set_arg = gtk_text_view_set_arg;
532 object_class->get_arg = gtk_text_view_get_arg;
534 object_class->destroy = gtk_text_view_destroy;
535 gobject_class->finalize = gtk_text_view_finalize;
537 widget_class->realize = gtk_text_view_realize;
538 widget_class->unrealize = gtk_text_view_unrealize;
539 widget_class->style_set = gtk_text_view_style_set;
540 widget_class->size_request = gtk_text_view_size_request;
541 widget_class->size_allocate = gtk_text_view_size_allocate;
542 widget_class->event = gtk_text_view_event;
543 widget_class->key_press_event = gtk_text_view_key_press_event;
544 widget_class->key_release_event = gtk_text_view_key_release_event;
545 widget_class->button_press_event = gtk_text_view_button_press_event;
546 widget_class->button_release_event = gtk_text_view_button_release_event;
547 widget_class->focus_in_event = gtk_text_view_focus_in_event;
548 widget_class->focus_out_event = gtk_text_view_focus_out_event;
549 widget_class->motion_notify_event = gtk_text_view_motion_event;
550 widget_class->expose_event = gtk_text_view_expose_event;
551 widget_class->draw = gtk_text_view_draw;
553 widget_class->drag_begin = gtk_text_view_drag_begin;
554 widget_class->drag_end = gtk_text_view_drag_end;
555 widget_class->drag_data_get = gtk_text_view_drag_data_get;
556 widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
558 widget_class->drag_leave = gtk_text_view_drag_leave;
559 widget_class->drag_motion = gtk_text_view_drag_motion;
560 widget_class->drag_drop = gtk_text_view_drag_drop;
561 widget_class->drag_data_received = gtk_text_view_drag_data_received;
563 klass->move_insert = gtk_text_view_move_insert;
564 klass->set_anchor = gtk_text_view_set_anchor;
565 klass->scroll_text = gtk_text_view_scroll_text;
566 klass->delete_text = gtk_text_view_delete_text;
567 klass->cut_text = gtk_text_view_cut_text;
568 klass->copy_text = gtk_text_view_copy_text;
569 klass->paste_text = gtk_text_view_paste_text;
570 klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
571 klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
575 gtk_text_view_init (GtkTextView *text_view)
579 widget = GTK_WIDGET (text_view);
581 GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
583 text_view->wrap_mode = GTK_WRAPMODE_NONE;
586 clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
589 text_atom = gdk_atom_intern ("TEXT", FALSE);
592 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
595 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
597 gtk_drag_dest_set (widget,
598 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION,
599 target_table, n_targets,
600 GDK_ACTION_COPY | GDK_ACTION_MOVE);
602 text_view->virtual_cursor_x = -1;
603 text_view->virtual_cursor_y = -1;
605 /* This object is completely private. No external entity can gain a reference
606 * to it; so we create it here and destroy it in finalize().
608 text_view->im_context = gtk_im_multicontext_new ();
610 gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
611 GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
615 gtk_text_view_new (void)
617 return GTK_WIDGET (gtk_type_new (gtk_text_view_get_type ()));
621 gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
623 GtkTextView *text_view;
625 text_view = (GtkTextView*)gtk_text_view_new ();
627 gtk_text_view_set_buffer (text_view, buffer);
629 return GTK_WIDGET (text_view);
633 gtk_text_view_set_buffer (GtkTextView *text_view,
634 GtkTextBuffer *buffer)
636 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
637 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
639 if (text_view->buffer == buffer)
642 if (text_view->buffer != NULL)
644 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->buffer),
645 gtk_text_view_mark_set_handler, text_view);
646 gtk_object_unref (GTK_OBJECT (text_view->buffer));
647 text_view->dnd_mark = NULL;
650 text_view->buffer = buffer;
658 gtk_object_ref (GTK_OBJECT (buffer));
659 gtk_object_sink (GTK_OBJECT (buffer));
661 if (text_view->layout)
662 gtk_text_layout_set_buffer (text_view->layout, buffer);
664 gtk_text_buffer_get_iter_at_char (text_view->buffer, &start, 0);
666 text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
670 /* Initialize. FIXME: Allow anonymous marks and use one here
672 mark_name = g_strdup_printf ("__first_para_%p", text_view);
673 text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer,
677 text_view->first_para_pixels = 0;
679 gtk_signal_connect (GTK_OBJECT (text_view->buffer), "mark_set",
680 gtk_text_view_mark_set_handler, text_view);
683 if (GTK_WIDGET_VISIBLE (text_view))
684 gtk_widget_queue_draw (GTK_WIDGET (text_view));
688 gtk_text_view_get_buffer (GtkTextView *text_view)
690 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
692 return text_view->buffer;
696 gtk_text_view_get_iter_at_pixel (GtkTextView *text_view,
700 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
701 g_return_if_fail (iter != NULL);
702 g_return_if_fail (text_view->layout != NULL);
704 gtk_text_layout_get_iter_at_pixel (text_view->layout,
706 x + text_view->xoffset,
707 y + text_view->yoffset);
712 set_adjustment_clamped (GtkAdjustment *adj, gfloat val)
714 /* We don't really want to clamp to upper; we want to clamp to
715 upper - page_size which is the highest value the scrollbar
716 will let us reach. */
717 if (val > (adj->upper - adj->page_size))
718 val = adj->upper - adj->page_size;
720 if (val < adj->lower)
723 gtk_adjustment_set_value (adj, val);
727 gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view,
728 const gchar *mark_name,
738 gboolean retval = FALSE;
741 gint current_x_scroll, current_y_scroll;
743 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
744 g_return_val_if_fail (mark_name != NULL, FALSE);
746 widget = GTK_WIDGET (text_view);
748 if (!GTK_WIDGET_MAPPED (widget))
750 g_warning ("FIXME need to implement scroll_to_mark for unmapped GtkTextView?");
754 if (!gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, mark_name))
756 g_warning ("Mark %s does not exist! can't scroll to it.", mark_name);
760 gtk_text_layout_get_iter_location (text_view->layout,
764 /* Be sure the scroll region is up-to-date */
765 gtk_text_view_scroll_calc_now (text_view);
767 current_x_scroll = text_view->xoffset;
768 current_y_scroll = text_view->yoffset;
770 screen.x = current_x_scroll;
771 screen.y = current_y_scroll;
772 screen.width = widget->allocation.width;
773 screen.height = widget->allocation.height;
776 /* Clamp margin so it's not too large. */
777 gint small_dimension = MIN (screen.width, screen.height);
780 if (margin > (small_dimension/2 - 5)) /* 5 is arbitrary */
781 margin = (small_dimension/2 - 5);
786 /* make sure rectangle fits in the leftover space */
788 max_rect_dim = MAX (rect.width, rect.height);
790 if (max_rect_dim > (small_dimension - margin*2))
791 margin -= max_rect_dim - (small_dimension - margin*2);
797 g_assert (margin >= 0);
802 screen.width -= margin*2;
803 screen.height -= margin*2;
805 screen_bottom = screen.y + screen.height;
806 screen_right = screen.x + screen.width;
808 /* Vertical scroll (only vertical gets adjusted) */
811 if (rect.y < screen.y)
813 gint scroll_dest = rect.y;
814 scroll_inc = (scroll_dest - screen.y) * percentage;
816 else if ((rect.y + rect.height) > screen_bottom)
818 gint scroll_dest = rect.y + rect.height;
819 scroll_inc = (scroll_dest - screen_bottom) * percentage;
824 set_adjustment_clamped (text_view->vadjustment,
825 current_y_scroll + scroll_inc);
829 /* Horizontal scroll */
832 if (rect.x < screen.x)
834 gint scroll_dest = rect.x;
835 scroll_inc = scroll_dest - screen.x;
837 else if ((rect.x + rect.width) > screen_right)
839 gint scroll_dest = rect.x + rect.width;
840 scroll_inc = scroll_dest - screen_right;
845 set_adjustment_clamped (text_view->hadjustment,
846 current_x_scroll + scroll_inc);
854 gtk_text_view_scroll_to_mark (GtkTextView *text_view,
855 const gchar *mark_name,
856 gint mark_within_margin)
858 g_return_val_if_fail (mark_within_margin >= 0, FALSE);
860 return gtk_text_view_scroll_to_mark_adjusted (text_view, mark_name,
861 mark_within_margin, 1.0);
865 clamp_iter_onscreen (GtkTextView *text_view, GtkTextIter *iter)
867 GdkRectangle visible_rect;
868 gtk_text_view_get_visible_rect (text_view, &visible_rect);
870 return gtk_text_layout_clamp_iter_to_vrange (text_view->layout, iter,
872 visible_rect.y + visible_rect.height);
876 gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
877 const gchar *mark_name)
881 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
882 g_return_val_if_fail (mark_name != NULL, FALSE);
884 if (!gtk_text_buffer_get_iter_at_mark (text_view->buffer, &mark, mark_name))
887 if (clamp_iter_onscreen (text_view, &mark))
889 gtk_text_buffer_move_mark (text_view->buffer, mark_name, &mark);
897 gtk_text_view_get_visible_rect (GtkTextView *text_view,
898 GdkRectangle *visible_rect)
902 g_return_if_fail (text_view != NULL);
903 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
905 widget = GTK_WIDGET (text_view);
909 visible_rect->x = text_view->xoffset;
910 visible_rect->y = text_view->yoffset;
911 visible_rect->width = widget->allocation.width;
912 visible_rect->height = widget->allocation.height;
917 gtk_text_view_set_wrap_mode (GtkTextView *text_view,
918 GtkWrapMode wrap_mode)
920 g_return_if_fail (text_view != NULL);
921 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
923 if (text_view->wrap_mode != wrap_mode)
925 text_view->wrap_mode = wrap_mode;
927 if (text_view->layout)
929 text_view->layout->default_style->wrap_mode = wrap_mode;
930 gtk_text_layout_default_style_changed (text_view->layout);
936 gtk_text_view_get_wrap_mode (GtkTextView *text_view)
938 g_return_val_if_fail (text_view != NULL, GTK_WRAPMODE_NONE);
939 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_WRAPMODE_NONE);
941 return text_view->wrap_mode;
945 gtk_text_view_place_cursor_onscreen (GtkTextView *text_view)
949 g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
951 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert, "insert");
953 if (clamp_iter_onscreen (text_view, &insert))
955 gtk_text_buffer_place_cursor (text_view->buffer, &insert);
963 gtk_text_view_destroy (GtkObject *object)
965 GtkTextView *text_view;
967 text_view = GTK_TEXT_VIEW (object);
969 gtk_text_view_destroy_layout (text_view);
970 gtk_text_view_set_buffer (text_view, NULL);
972 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
976 gtk_text_view_finalize (GObject *object)
978 GtkTextView *text_view;
980 text_view = GTK_TEXT_VIEW (object);
982 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
983 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
984 gtk_object_unref (GTK_OBJECT (text_view->im_context));
986 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
990 gtk_text_view_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
992 GtkTextView *text_view;
994 text_view = GTK_TEXT_VIEW (object);
998 case ARG_HEIGHT_LINES:
1001 case ARG_WIDTH_COLUMNS:
1004 case ARG_PIXELS_ABOVE_LINES:
1007 case ARG_PIXELS_BELOW_LINES:
1010 case ARG_PIXELS_INSIDE_WRAP:
1020 g_assert_not_reached ();
1026 gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
1028 GtkTextView *text_view;
1030 text_view = GTK_TEXT_VIEW (object);
1034 case ARG_HEIGHT_LINES:
1037 case ARG_WIDTH_COLUMNS:
1040 case ARG_PIXELS_ABOVE_LINES:
1043 case ARG_PIXELS_BELOW_LINES:
1046 case ARG_PIXELS_INSIDE_WRAP:
1056 arg->type = GTK_TYPE_INVALID;
1062 gtk_text_view_size_request (GtkWidget *widget,
1063 GtkRequisition *requisition)
1065 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1068 requisition->width = 1;
1069 requisition->height = 1;
1071 /* Check to see if the widget direction has changed */
1073 if (text_view->layout)
1075 GtkTextDirection direction = gtk_widget_get_direction (widget);
1076 if (direction != text_view->layout->default_style->direction)
1078 text_view->layout->default_style->direction = direction;
1079 gtk_text_layout_default_style_changed (text_view->layout);
1085 gtk_text_view_size_allocate (GtkWidget *widget,
1086 GtkAllocation *allocation)
1088 GtkTextView *text_view;
1089 GtkTextIter first_para;
1091 GtkAdjustment *vadj;
1092 gboolean yoffset_changed = FALSE;
1094 text_view = GTK_TEXT_VIEW (widget);
1096 widget->allocation = *allocation;
1098 if (GTK_WIDGET_REALIZED (widget))
1100 gdk_window_move_resize (widget->window,
1101 allocation->x, allocation->y,
1102 allocation->width, allocation->height);
1104 gdk_window_resize (text_view->bin_window,
1105 allocation->width, allocation->height);
1108 gtk_text_view_ensure_layout (text_view);
1109 gtk_text_layout_set_screen_width (text_view->layout,
1110 GTK_WIDGET (text_view)->allocation.width);
1112 gtk_text_view_validate_onscreen (text_view);
1113 gtk_text_view_scroll_calc_now (text_view);
1115 /* Now adjust the value of the adjustment to keep the cursor at the same place in
1118 gtk_text_view_get_first_para_iter (text_view, &first_para);
1119 y = gtk_text_layout_get_line_y (text_view->layout, &first_para) + text_view->first_para_pixels;
1121 vadj = text_view->vadjustment;
1122 if (y > vadj->upper - vadj->page_size)
1123 y = MAX (0, vadj->upper - vadj->page_size);
1125 if (y != text_view->yoffset)
1127 vadj->value = text_view->yoffset = y;
1128 yoffset_changed = TRUE;
1131 text_view->hadjustment->page_size = allocation->width;
1132 text_view->hadjustment->page_increment = allocation->width / 2;
1133 text_view->hadjustment->lower = 0;
1134 text_view->hadjustment->upper = MAX (allocation->width, text_view->width);
1135 gtk_signal_emit_by_name (GTK_OBJECT (text_view->hadjustment), "changed");
1137 text_view->vadjustment->page_size = allocation->height;
1138 text_view->vadjustment->page_increment = allocation->height / 2;
1139 text_view->vadjustment->lower = 0;
1140 text_view->vadjustment->upper = MAX (allocation->height, text_view->height);
1141 gtk_signal_emit_by_name (GTK_OBJECT (text_view->vadjustment), "changed");
1143 if (yoffset_changed)
1144 gtk_adjustment_value_changed (vadj);
1148 gtk_text_view_get_first_para_iter (GtkTextView *text_view,
1151 gchar *mark_name = gtk_text_mark_get_name (text_view->first_para_mark);
1152 gtk_text_buffer_get_iter_at_mark (text_view->buffer, iter, mark_name);
1157 gtk_text_view_validate_onscreen (GtkTextView *text_view)
1159 GtkWidget *widget = GTK_WIDGET (text_view);
1161 if (widget->allocation.height > 0)
1163 GtkTextIter first_para;
1164 gtk_text_view_get_first_para_iter (text_view, &first_para);
1165 gtk_text_layout_validate_yrange (text_view->layout,
1167 0, text_view->first_para_pixels + widget->allocation.height);
1172 first_validate_callback (gpointer data)
1174 GtkTextView *text_view = data;
1176 gtk_text_view_validate_onscreen (text_view);
1178 text_view->first_validate_idle = 0;
1183 incremental_validate_callback (gpointer data)
1185 GtkTextView *text_view = data;
1187 gtk_text_layout_validate (text_view->layout, 2000);
1188 if (gtk_text_layout_is_valid (text_view->layout))
1190 text_view->incremental_validate_idle = 0;
1198 invalidated_handler (GtkTextLayout *layout,
1201 GtkTextView *text_view;
1203 text_view = GTK_TEXT_VIEW (data);
1205 if (!text_view->first_validate_idle)
1206 text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 1, first_validate_callback, text_view, NULL);
1208 if (!text_view->incremental_validate_idle)
1209 text_view->incremental_validate_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 1, incremental_validate_callback, text_view, NULL);
1213 changed_handler (GtkTextLayout *layout,
1219 GtkTextView *text_view;
1221 GdkRectangle visible_rect;
1222 GdkRectangle redraw_rect;
1224 text_view = GTK_TEXT_VIEW (data);
1225 widget = GTK_WIDGET (data);
1227 if (GTK_WIDGET_REALIZED (text_view))
1229 gtk_text_view_get_visible_rect (text_view, &visible_rect);
1231 redraw_rect.x = visible_rect.x;
1232 redraw_rect.width = visible_rect.width;
1233 redraw_rect.y = start_y;
1234 redraw_rect.height = MAX (old_height, new_height);
1236 if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
1238 redraw_rect.y -= text_view->yoffset;
1239 gdk_window_invalidate_rect (text_view->bin_window, &redraw_rect, FALSE);
1243 if (old_height != new_height)
1245 gboolean yoffset_changed = FALSE;
1247 if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
1249 text_view->yoffset += new_height - old_height;
1250 text_view->vadjustment->value = text_view->yoffset;
1251 yoffset_changed = TRUE;
1254 gtk_text_view_scroll_calc_now (text_view);
1256 if (yoffset_changed)
1257 gtk_adjustment_value_changed (text_view->vadjustment);
1263 gtk_text_view_realize (GtkWidget *widget)
1265 GtkTextView *text_view;
1267 GdkWindowAttr attributes;
1268 gint attributes_mask;
1270 text_view = GTK_TEXT_VIEW (widget);
1271 GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
1273 attributes.window_type = GDK_WINDOW_CHILD;
1274 attributes.x = widget->allocation.x;
1275 attributes.y = widget->allocation.y;
1276 attributes.width = widget->allocation.width;
1277 attributes.height = widget->allocation.height;
1278 attributes.wclass = GDK_INPUT_OUTPUT;
1279 attributes.visual = gtk_widget_get_visual (widget);
1280 attributes.colormap = gtk_widget_get_colormap (widget);
1281 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1283 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1285 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1286 &attributes, attributes_mask);
1287 gdk_window_set_user_data (widget->window, widget);
1291 attributes.width = widget->allocation.width;
1292 attributes.height = widget->allocation.height;
1293 attributes.event_mask = (GDK_EXPOSURE_MASK |
1295 GDK_KEY_PRESS_MASK |
1296 GDK_BUTTON_PRESS_MASK |
1297 GDK_BUTTON_RELEASE_MASK |
1298 GDK_POINTER_MOTION_MASK |
1299 GDK_POINTER_MOTION_HINT_MASK |
1300 gtk_widget_get_events (widget));
1302 text_view->bin_window = gdk_window_new (widget->window,
1303 &attributes, attributes_mask);
1304 gdk_window_show (text_view->bin_window);
1305 gdk_window_set_user_data (text_view->bin_window, widget);
1307 widget->style = gtk_style_attach (widget->style, widget->window);
1309 gdk_window_set_background (text_view->bin_window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1311 gtk_text_view_ensure_layout (text_view);
1314 cursor = gdk_cursor_new (GDK_XTERM);
1315 gdk_window_set_cursor (text_view->bin_window, cursor);
1316 gdk_cursor_destroy (cursor);
1318 gtk_im_context_set_client_window (text_view->im_context, widget->window);
1322 gtk_text_view_unrealize (GtkWidget *widget)
1324 GtkTextView *text_view;
1326 text_view = GTK_TEXT_VIEW (widget);
1328 if (text_view->first_validate_idle)
1330 g_source_remove (text_view->first_validate_idle);
1331 text_view->first_validate_idle = 0;
1334 if (text_view->incremental_validate_idle)
1336 g_source_remove (text_view->incremental_validate_idle);
1337 text_view->incremental_validate_idle = 0;
1340 gtk_text_view_destroy_layout (text_view);
1342 gtk_im_context_set_client_window (text_view->im_context, NULL);
1344 gdk_window_set_user_data (text_view->bin_window, NULL);
1345 gdk_window_destroy (text_view->bin_window);
1346 text_view->bin_window = NULL;
1348 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1352 gtk_text_view_style_set (GtkWidget *widget,
1353 GtkStyle *previous_style)
1355 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
1357 if (GTK_WIDGET_REALIZED (widget))
1359 gdk_window_set_background (text_view->bin_window,
1360 &widget->style->base[GTK_WIDGET_STATE (widget)]);
1362 gtk_text_view_set_values_from_style (text_view, text_view->layout->default_style, widget->style);
1363 gtk_text_layout_default_style_changed (text_view->layout);
1372 get_event_coordinates (GdkEvent *event, gint *x, gint *y)
1375 switch (event->type)
1377 case GDK_MOTION_NOTIFY:
1378 *x = event->motion.x;
1379 *y = event->motion.y;
1383 case GDK_BUTTON_PRESS:
1384 case GDK_2BUTTON_PRESS:
1385 case GDK_3BUTTON_PRESS:
1386 case GDK_BUTTON_RELEASE:
1387 *x = event->button.x;
1388 *y = event->button.y;
1393 case GDK_KEY_RELEASE:
1394 case GDK_ENTER_NOTIFY:
1395 case GDK_LEAVE_NOTIFY:
1396 case GDK_PROPERTY_NOTIFY:
1397 case GDK_SELECTION_CLEAR:
1398 case GDK_SELECTION_REQUEST:
1399 case GDK_SELECTION_NOTIFY:
1400 case GDK_PROXIMITY_IN:
1401 case GDK_PROXIMITY_OUT:
1402 case GDK_DRAG_ENTER:
1403 case GDK_DRAG_LEAVE:
1404 case GDK_DRAG_MOTION:
1405 case GDK_DRAG_STATUS:
1406 case GDK_DROP_START:
1407 case GDK_DROP_FINISHED:
1417 gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
1419 GtkTextView *text_view;
1422 text_view = GTK_TEXT_VIEW (widget);
1424 if (text_view->layout == NULL ||
1425 text_view->buffer == NULL)
1428 /* FIXME eventually we really want to synthesize enter/leave
1429 events here as the canvas does for canvas items */
1431 if (get_event_coordinates (event, &x, &y))
1434 gint retval = FALSE;
1436 x += text_view->xoffset;
1437 y += text_view->yoffset;
1439 /* FIXME this is slow and we do it twice per event.
1440 My favorite solution is to have GtkTextLayout cache
1441 the last couple lookups. */
1442 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1450 tags = gtk_text_buffer_get_tags (text_view->buffer, &iter);
1455 GtkTextTag *tag = tmp->data;
1457 if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, &iter))
1463 tmp = g_slist_next (tmp);
1466 g_slist_free (tags);
1476 gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
1478 GtkTextView *text_view;
1480 text_view = GTK_TEXT_VIEW (widget);
1482 if (text_view->layout == NULL ||
1483 text_view->buffer == NULL)
1486 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
1487 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
1490 if (gtk_im_context_filter_keypress (text_view->im_context, event))
1492 else if (event->keyval == GDK_Return)
1494 gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1);
1495 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
1503 gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
1509 gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
1511 GtkTextView *text_view;
1513 text_view = GTK_TEXT_VIEW (widget);
1515 gtk_widget_grab_focus (widget);
1518 if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
1519 gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
1520 else if (event->button == 3)
1521 gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
1523 if (event->type == GDK_BUTTON_PRESS)
1525 if (event->button == 1)
1527 /* If we're in the selection, start a drag copy/move of the
1528 selection; otherwise, start creating a new selection. */
1530 GtkTextIter start, end;
1532 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1534 event->x + text_view->xoffset,
1535 event->y + text_view->yoffset);
1537 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
1539 gtk_text_iter_in_region (&iter, &start, &end))
1541 gtk_text_view_start_selection_dnd (text_view, &iter, event);
1545 gtk_text_view_start_selection_drag (text_view, &iter, event);
1550 else if (event->button == 2)
1554 gtk_text_layout_get_iter_at_pixel (text_view->layout,
1556 event->x + text_view->xoffset,
1557 event->y + text_view->yoffset);
1559 gtk_text_buffer_paste_primary_selection (text_view->buffer,
1564 else if (event->button == 3)
1566 if (gtk_text_view_end_selection_drag (text_view, event))
1577 gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
1579 if (event->button == 1)
1581 gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event);
1589 gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1591 GtkTextMark *insert;
1593 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1595 insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1597 gtk_text_mark_set_visible (insert, TRUE);
1599 gtk_text_view_start_cursor_blink (GTK_TEXT_VIEW (widget));
1601 gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
1607 gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1609 GtkTextMark *insert;
1611 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1613 insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer,
1615 gtk_text_mark_set_visible (insert, FALSE);
1617 gtk_text_view_stop_cursor_blink (GTK_TEXT_VIEW (widget));
1619 gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
1625 gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
1632 gtk_text_view_paint (GtkWidget *widget, GdkRectangle *area)
1634 GtkTextView *text_view;
1636 text_view = GTK_TEXT_VIEW (widget);
1638 g_return_if_fail (text_view->layout != NULL);
1639 g_return_if_fail (text_view->xoffset >= 0);
1640 g_return_if_fail (text_view->yoffset >= 0);
1642 gtk_text_view_validate_onscreen (text_view);
1645 printf ("painting %d,%d %d x %d\n",
1647 area->width, area->height);
1650 gtk_text_layout_draw (text_view->layout,
1652 text_view->bin_window,
1653 text_view->xoffset, text_view->yoffset,
1655 area->width, area->height);
1659 gtk_text_view_draw (GtkWidget *widget, GdkRectangle *area)
1661 gtk_text_view_paint (widget, area);
1665 gtk_text_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
1667 if (event->window == GTK_TEXT_VIEW (widget)->bin_window)
1668 gtk_text_view_paint (widget, &event->area);
1678 blink_cb (gpointer data)
1680 GtkTextView *text_view;
1681 GtkTextMark *insert;
1683 text_view = GTK_TEXT_VIEW (data);
1685 insert = gtk_text_buffer_get_mark (text_view->buffer,
1688 if (!GTK_WIDGET_HAS_FOCUS (text_view))
1690 /* paranoia, in case the user somehow mangles our
1691 focus_in/focus_out pairing. */
1692 gtk_text_mark_set_visible (insert, FALSE);
1693 text_view->blink_timeout = 0;
1698 gtk_text_mark_set_visible (insert,
1699 !gtk_text_mark_is_visible (insert));
1705 gtk_text_view_start_cursor_blink (GtkTextView *text_view)
1708 if (text_view->blink_timeout != 0)
1711 text_view->blink_timeout = gtk_timeout_add (500, blink_cb, text_view);
1715 gtk_text_view_stop_cursor_blink (GtkTextView *text_view)
1718 if (text_view->blink_timeout == 0)
1721 gtk_timeout_remove (text_view->blink_timeout);
1722 text_view->blink_timeout = 0;
1726 * Key binding handlers
1730 gtk_text_view_move_iter_by_lines (GtkTextView *text_view,
1731 GtkTextIter *newplace,
1736 gtk_text_layout_move_iter_to_previous_line (text_view->layout, newplace);
1742 gtk_text_layout_move_iter_to_next_line (text_view->layout, newplace);
1748 gtk_text_view_move_insert (GtkTextView *text_view,
1749 GtkTextViewMovementStep step,
1751 gboolean extend_selection)
1754 GtkTextIter newplace;
1756 gint cursor_x_pos = 0;
1758 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert, "insert");
1761 if (step == GTK_TEXT_MOVEMENT_LINE)
1762 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
1766 case GTK_TEXT_MOVEMENT_CHAR:
1767 gtk_text_iter_forward_chars (&newplace, count);
1770 case GTK_TEXT_MOVEMENT_POSITIONS:
1771 gtk_text_layout_move_iter_visually (text_view->layout,
1775 case GTK_TEXT_MOVEMENT_WORD:
1777 gtk_text_iter_backward_word_starts (&newplace, -count);
1779 gtk_text_iter_forward_word_ends (&newplace, count);
1782 case GTK_TEXT_MOVEMENT_LINE:
1783 gtk_text_view_move_iter_by_lines (text_view, &newplace, count);
1784 gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
1787 case GTK_TEXT_MOVEMENT_PARAGRAPH:
1788 /* This should almost certainly instead be doing the parallel thing to WORD */
1789 gtk_text_iter_down_lines (&newplace, count);
1792 case GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS:
1794 gtk_text_iter_forward_to_newline (&newplace);
1796 gtk_text_iter_set_line_char (&newplace, 0);
1799 case GTK_TEXT_MOVEMENT_BUFFER_ENDS:
1801 gtk_text_buffer_get_last_iter (text_view->buffer, &newplace);
1803 gtk_text_buffer_get_iter_at_char (text_view->buffer, &newplace, 0);
1810 if (!gtk_text_iter_equal (&insert, &newplace))
1812 if (extend_selection)
1813 gtk_text_buffer_move_mark (text_view->buffer, "insert", &newplace);
1815 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
1817 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
1819 if (step == GTK_TEXT_MOVEMENT_LINE)
1821 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
1827 gtk_text_view_set_anchor (GtkTextView *text_view)
1831 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert, "insert");
1833 gtk_text_buffer_create_mark (text_view->buffer, "anchor", &insert, TRUE);
1837 gtk_text_view_scroll_text (GtkTextView *text_view,
1838 GtkTextViewScrollType type)
1842 gint cursor_x_pos, cursor_y_pos;
1843 GtkTextIter new_insert;
1847 g_return_if_fail (text_view->vadjustment != NULL);
1849 adj = text_view->vadjustment;
1851 /* Validate the region that will be brought into view by the cursor motion
1856 case GTK_TEXT_SCROLL_TO_TOP:
1857 gtk_text_buffer_get_iter_at_char (text_view->buffer, &anchor, 0);
1859 y1 = adj->page_size;
1862 case GTK_TEXT_SCROLL_TO_BOTTOM:
1863 gtk_text_buffer_get_last_iter (text_view->buffer, &anchor);
1864 y0 = -adj->page_size;
1865 y1 = adj->page_size;
1868 case GTK_TEXT_SCROLL_PAGE_DOWN:
1869 gtk_text_view_get_first_para_iter (text_view, &anchor);
1870 y0 = adj->page_size;
1871 y1 = adj->page_size + adj->page_increment;
1874 case GTK_TEXT_SCROLL_PAGE_UP:
1875 gtk_text_view_get_first_para_iter (text_view, &anchor);
1876 y0 = - adj->page_increment + adj->page_size;
1880 gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
1883 gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
1885 newval = adj->value;
1888 case GTK_TEXT_SCROLL_TO_TOP:
1889 newval = adj->lower;
1892 case GTK_TEXT_SCROLL_TO_BOTTOM:
1893 newval = adj->upper;
1896 case GTK_TEXT_SCROLL_PAGE_DOWN:
1897 newval += adj->page_increment;
1900 case GTK_TEXT_SCROLL_PAGE_UP:
1901 newval -= adj->page_increment;
1908 cursor_y_pos += newval - adj->value;
1909 set_adjustment_clamped (adj, newval);
1911 gtk_text_layout_get_iter_at_pixel (text_view->layout, &new_insert, cursor_x_pos, cursor_y_pos);
1912 clamp_iter_onscreen (text_view, &new_insert);
1913 gtk_text_buffer_place_cursor (text_view->buffer, &new_insert);
1915 gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, cursor_y_pos);
1917 /* Adjust to have the cursor _entirely_ onscreen, move_mark_onscreen
1918 * only guarantees 1 pixel onscreen.
1920 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
1924 whitespace (GtkTextUniChar ch, gpointer user_data)
1926 return (ch == ' ' || ch == '\t');
1930 not_whitespace (GtkTextUniChar ch, gpointer user_data)
1932 return !whitespace (ch, user_data);
1936 find_whitepace_region (const GtkTextIter *center,
1937 GtkTextIter *start, GtkTextIter *end)
1942 if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL))
1943 gtk_text_iter_forward_char (start); /* we want the first whitespace... */
1944 if (whitespace (gtk_text_iter_get_char (end), NULL))
1945 gtk_text_iter_forward_find_char (end, not_whitespace, NULL);
1947 return !gtk_text_iter_equal (start, end);
1951 gtk_text_view_delete_text (GtkTextView *text_view,
1952 GtkTextViewDeleteType type,
1958 gboolean leave_one = FALSE;
1960 if (type == GTK_TEXT_DELETE_CHAR)
1962 /* Char delete deletes the selection, if one exists */
1963 if (gtk_text_buffer_delete_selection (text_view->buffer))
1967 gtk_text_buffer_get_iter_at_mark (text_view->buffer,
1976 case GTK_TEXT_DELETE_CHAR:
1977 gtk_text_iter_forward_chars (&end, count);
1980 case GTK_TEXT_DELETE_HALF_WORD:
1982 gtk_text_iter_forward_word_ends (&end, count);
1984 gtk_text_iter_backward_word_starts (&start, 0 - count);
1987 case GTK_TEXT_DELETE_WHOLE_WORD:
1990 case GTK_TEXT_DELETE_HALF_LINE:
1993 case GTK_TEXT_DELETE_WHOLE_LINE:
1996 case GTK_TEXT_DELETE_HALF_PARAGRAPH:
1999 if (!gtk_text_iter_forward_to_newline (&end))
2005 /* FIXME figure out what a negative count means
2009 case GTK_TEXT_DELETE_WHOLE_PARAGRAPH:
2012 gtk_text_iter_set_line_char (&start, 0);
2013 gtk_text_iter_forward_to_newline (&end);
2015 /* Do the lines beyond the first. */
2018 gtk_text_iter_forward_to_newline (&end);
2024 /* FIXME negative count? */
2028 case GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE:
2029 leave_one = TRUE; /* FALL THRU */
2030 case GTK_TEXT_DELETE_WHITESPACE:
2032 find_whitepace_region (&insert, &start, &end);
2040 if (!gtk_text_iter_equal (&start, &end))
2042 gtk_text_buffer_delete (text_view->buffer, &start, &end);
2045 gtk_text_buffer_insert_at_cursor (text_view->buffer, " ", 1);
2047 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
2052 gtk_text_view_cut_text (GtkTextView *text_view)
2054 gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME);
2055 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
2059 gtk_text_view_copy_text (GtkTextView *text_view)
2061 gtk_text_buffer_copy (text_view->buffer, GDK_CURRENT_TIME);
2062 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
2066 gtk_text_view_paste_text (GtkTextView *text_view)
2068 gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME);
2069 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
2073 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
2075 text_view->overwrite_mode = !text_view->overwrite_mode;
2083 move_insert_to_pointer_and_scroll (GtkTextView *text_view, gboolean partial_scroll)
2086 GdkModifierType state;
2087 GtkTextIter newplace;
2089 gboolean in_threshold = FALSE;
2091 gdk_window_get_pointer (text_view->bin_window, &x, &y, &state);
2093 /* Adjust movement by how long we've been selecting, to
2094 get an acceleration effect. The exact numbers are
2095 pretty arbitrary. We have a threshold before we
2096 start to accelerate. */
2097 /* uncommenting this printf helps visualize how it works. */
2098 /* printf ("%d\n", text_view->scrolling_accel_factor); */
2100 if (text_view->scrolling_accel_factor > 10)
2101 adjust = (text_view->scrolling_accel_factor - 10) * 75;
2103 if (y < 0) /* scrolling upward */
2106 /* No adjust if the pointer has moved back inside the window for sure.
2107 Also I'm adding a small threshold where no adjust is added,
2108 in case you want to do a continuous slow scroll. */
2109 #define SLOW_SCROLL_TH 7
2110 if (x >= (0 - SLOW_SCROLL_TH) &&
2111 x < (GTK_WIDGET (text_view)->allocation.width + SLOW_SCROLL_TH) &&
2112 y >= (0 - SLOW_SCROLL_TH) &&
2113 y < (GTK_WIDGET (text_view)->allocation.height + SLOW_SCROLL_TH))
2116 in_threshold = TRUE;
2119 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2121 x + text_view->xoffset,
2122 y + text_view->yoffset + adjust);
2125 gboolean scrolled = FALSE;
2127 gtk_text_buffer_move_mark (text_view->buffer,
2132 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, "insert", 0, 0.7);
2134 scrolled = gtk_text_view_scroll_to_mark_adjusted (text_view, "insert", 0, 1.0);
2138 /* We want to avoid rapid jump to super-accelerated when you
2139 leave the slow scroll threshold after scrolling for a
2140 while. So we slowly decrease accel when scrolling inside
2145 if (text_view->scrolling_accel_factor > 1)
2146 text_view->scrolling_accel_factor -= 2;
2149 text_view->scrolling_accel_factor += 1;
2153 /* If we don't scroll we're probably inside the window, but
2154 potentially just a bit outside. We decrease acceleration
2155 while the user is fooling around inside the window.
2156 Acceleration decreases faster than it increases. */
2157 if (text_view->scrolling_accel_factor > 4)
2158 text_view->scrolling_accel_factor -= 5;
2166 selection_scan_timeout (gpointer data)
2168 GtkTextView *text_view;
2170 text_view = GTK_TEXT_VIEW (data);
2172 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2174 return TRUE; /* remain installed. */
2178 text_view->selection_drag_scan_timeout = 0;
2179 return FALSE; /* remove ourselves */
2184 selection_motion_event_handler (GtkTextView *text_view, GdkEventMotion *event, gpointer data)
2186 if (move_insert_to_pointer_and_scroll (text_view, TRUE))
2188 /* If we had to scroll offscreen, insert a timeout to do so
2189 again. Note that in the timeout, even if the mouse doesn't
2190 move, due to this scroll xoffset/yoffset will have changed
2191 and we'll need to scroll again. */
2192 if (text_view->selection_drag_scan_timeout != 0) /* reset on every motion event */
2193 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2195 text_view->selection_drag_scan_timeout =
2196 gtk_timeout_add (50, selection_scan_timeout, text_view);
2203 gtk_text_view_start_selection_drag (GtkTextView *text_view,
2204 const GtkTextIter *iter,
2205 GdkEventButton *event)
2207 GtkTextIter newplace;
2209 g_return_if_fail (text_view->selection_drag_handler == 0);
2211 gtk_grab_add (GTK_WIDGET (text_view));
2213 text_view->scrolling_accel_factor = 0;
2217 gtk_text_buffer_place_cursor (text_view->buffer, &newplace);
2219 text_view->selection_drag_handler = gtk_signal_connect (GTK_OBJECT (text_view),
2220 "motion_notify_event",
2221 GTK_SIGNAL_FUNC (selection_motion_event_handler),
2225 /* returns whether we were really dragging */
2227 gtk_text_view_end_selection_drag (GtkTextView *text_view, GdkEventButton *event)
2229 if (text_view->selection_drag_handler == 0)
2232 gtk_signal_disconnect (GTK_OBJECT (text_view), text_view->selection_drag_handler);
2233 text_view->selection_drag_handler = 0;
2235 text_view->scrolling_accel_factor = 0;
2237 if (text_view->selection_drag_scan_timeout != 0)
2239 gtk_timeout_remove (text_view->selection_drag_scan_timeout);
2240 text_view->selection_drag_scan_timeout = 0;
2243 /* one last update to current position */
2244 move_insert_to_pointer_and_scroll (text_view, FALSE);
2246 gtk_grab_remove (GTK_WIDGET (text_view));
2256 gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gfloat upper)
2258 if (upper != adj->upper)
2260 gfloat min = MAX (0., upper - adj->page_size);
2261 gboolean value_changed = FALSE;
2265 if (adj->value > min)
2268 value_changed = TRUE;
2271 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
2273 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2278 gtk_text_view_scroll_calc_now (GtkTextView *text_view)
2280 gint width = 0, height = 0;
2281 GtkWidget *widget = GTK_WIDGET (text_view);
2283 gtk_text_view_ensure_layout (text_view);
2286 gtk_text_layout_set_screen_width (text_view->layout,
2287 widget->allocation.width);
2289 gtk_text_layout_get_size (text_view->layout, &width, &height);
2292 /* If the width is less than the screen width (likely
2293 if we have wrapping turned on for the whole widget),
2294 then we want to set the scroll region to the screen
2295 width. If the width is greater (wrapping off) then we
2296 probably want to set the scroll region to the width
2297 of the layout. I guess.
2300 width = MAX (text_view->layout->screen_width, width);
2304 if (text_view->width != width || text_view->height != height)
2307 printf ("layout size set, widget width is %d\n",
2308 GTK_WIDGET (text_view)->allocation.width);
2310 text_view->width = width;
2311 text_view->height = height;
2313 gtk_text_view_set_adjustment_upper (text_view->hadjustment,
2314 MAX (widget->allocation.width, width));
2315 gtk_text_view_set_adjustment_upper (text_view->vadjustment,
2316 MAX (widget->allocation.height, height));
2318 /* Set up the step sizes; we'll say that a page is
2319 our allocation minus one step, and a step is
2320 1/10 of our allocation. */
2321 text_view->hadjustment->step_increment =
2322 GTK_WIDGET (text_view)->allocation.width/10.0;
2323 text_view->hadjustment->page_increment =
2324 GTK_WIDGET (text_view)->allocation.width *0.9;
2326 text_view->vadjustment->step_increment =
2327 GTK_WIDGET (text_view)->allocation.height/10.0;
2328 text_view->vadjustment->page_increment =
2329 GTK_WIDGET (text_view)->allocation.height *0.9;
2334 gtk_text_view_set_values_from_style (GtkTextView *text_view,
2335 GtkTextStyleValues *values,
2338 values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
2339 values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
2341 if (values->font_desc)
2342 pango_font_description_free (values->font_desc);
2344 values->font_desc = pango_font_description_copy (style->font_desc);
2348 gtk_text_view_ensure_layout (GtkTextView *text_view)
2352 widget = GTK_WIDGET (text_view);
2354 if (text_view->layout == NULL)
2356 GtkTextStyleValues *style;
2357 PangoContext *ltr_context, *rtl_context;
2359 text_view->layout = gtk_text_layout_new ();
2361 gtk_signal_connect (GTK_OBJECT (text_view->layout),
2363 GTK_SIGNAL_FUNC (invalidated_handler),
2366 gtk_signal_connect (GTK_OBJECT (text_view->layout),
2368 GTK_SIGNAL_FUNC (changed_handler),
2371 if (text_view->buffer)
2372 gtk_text_layout_set_buffer (text_view->layout, text_view->buffer);
2374 ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2375 pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
2376 rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
2377 pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
2379 gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
2381 pango_context_unref (ltr_context);
2382 pango_context_unref (rtl_context);
2384 style = gtk_text_view_style_values_new ();
2386 gtk_widget_ensure_style (widget);
2387 gtk_text_view_set_values_from_style (text_view, style, widget->style);
2389 style->pixels_above_lines = 2;
2390 style->pixels_below_lines = 2;
2391 style->pixels_inside_wrap = 1;
2393 style->wrap_mode = text_view->wrap_mode;
2394 style->justify = GTK_JUSTIFY_LEFT;
2395 style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
2397 gtk_text_layout_set_default_style (text_view->layout, style);
2399 gtk_text_view_style_values_unref (style);
2404 gtk_text_view_destroy_layout (GtkTextView *text_view)
2406 if (text_view->layout)
2408 gtk_text_view_end_selection_drag (text_view, NULL);
2410 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2411 invalidated_handler, text_view);
2412 gtk_signal_disconnect_by_func (GTK_OBJECT (text_view->layout),
2413 changed_handler, text_view);
2414 gtk_object_unref (GTK_OBJECT (text_view->layout));
2415 text_view->layout = NULL;
2425 gtk_text_view_start_selection_dnd (GtkTextView *text_view,
2426 const GtkTextIter *iter,
2427 GdkEventButton *event)
2429 GdkDragContext *context;
2430 GtkTargetList *target_list;
2432 /* FIXME we have to handle more formats for the selection,
2433 and do the conversions to/from UTF8 */
2435 /* FIXME not sure how this is memory-managed. */
2436 target_list = gtk_target_list_new (target_table, n_targets);
2438 context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
2439 GDK_ACTION_COPY | GDK_ACTION_MOVE,
2440 1, (GdkEvent*)event);
2442 gtk_drag_set_icon_default (context);
2444 /* We're inside the selection, so start without being able
2445 to accept the drag. */
2446 gdk_drag_status (context, 0, event->time);
2447 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2451 gtk_text_view_drag_begin (GtkWidget *widget,
2452 GdkDragContext *context)
2458 gtk_text_view_drag_end (GtkWidget *widget,
2459 GdkDragContext *context)
2461 GtkTextView *text_view;
2463 text_view = GTK_TEXT_VIEW (widget);
2465 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2469 gtk_text_view_drag_data_get (GtkWidget *widget,
2470 GdkDragContext *context,
2471 GtkSelectionData *selection_data,
2479 GtkTextView *text_view;
2481 text_view = GTK_TEXT_VIEW (widget);
2486 if (gtk_text_buffer_get_selection_bounds (text_view->buffer, &start, &end))
2488 /* Extract the selected text */
2489 str = gtk_text_iter_get_visible_text (&start, &end);
2491 length = strlen (str);
2496 if (info == TARGET_UTF8_STRING)
2499 gtk_selection_data_set (selection_data,
2501 8*sizeof (gchar), (guchar *)str, length);
2504 else if (info == TARGET_STRING ||
2505 info == TARGET_TEXT)
2509 latin1 = gtk_text_utf_to_latin1(str, length);
2511 gtk_selection_data_set (selection_data,
2512 GDK_SELECTION_TYPE_STRING,
2513 8*sizeof (gchar), latin1, strlen (latin1));
2516 else if (info == TARGET_COMPOUND_TEXT)
2518 /* FIXME convert UTF8 directly to current locale, not via
2527 latin1 = gtk_text_utf_to_latin1(str, length);
2529 gdk_string_to_compound_text (latin1, &encoding, &format, &text, &new_length);
2530 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
2531 gdk_free_compound_text (text);
2541 gtk_text_view_drag_data_delete (GtkWidget *widget,
2542 GdkDragContext *context)
2544 gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer);
2548 gtk_text_view_drag_leave (GtkWidget *widget,
2549 GdkDragContext *context,
2557 gtk_text_view_drag_motion (GtkWidget *widget,
2558 GdkDragContext *context,
2563 GtkTextIter newplace;
2564 GtkTextView *text_view;
2568 text_view = GTK_TEXT_VIEW (widget);
2570 gtk_text_layout_get_iter_at_pixel (text_view->layout,
2572 x + text_view->xoffset,
2573 y + text_view->yoffset);
2575 if (gtk_text_buffer_get_selection_bounds (text_view->buffer,
2577 gtk_text_iter_in_region (&newplace, &start, &end))
2579 /* We're inside the selection. */
2580 gdk_drag_status (context, 0, time);
2581 gtk_text_mark_set_visible (text_view->dnd_mark, FALSE);
2585 gtk_text_mark_set_visible (text_view->dnd_mark, TRUE);
2587 gdk_drag_status (context, context->suggested_action, time);
2590 gtk_text_buffer_move_mark (text_view->buffer,
2595 /* The effect of this is that the text scrolls if you're near
2596 the edge. We have to scroll whether or not we're inside
2600 margin = MIN (widget->allocation.width, widget->allocation.height);
2603 gtk_text_view_scroll_to_mark_adjusted (text_view, "__drag_target", margin, 1.0);
2610 gtk_text_view_drag_drop (GtkWidget *widget,
2611 GdkDragContext *context,
2617 /* called automatically. */
2618 if (context->targets)
2620 gtk_drag_get_data (widget, context,
2621 GPOINTER_TO_INT (context->targets->data),
2632 gtk_text_view_drag_data_received (GtkWidget *widget,
2633 GdkDragContext *context,
2636 GtkSelectionData *selection_data,
2640 GtkTextIter drop_point;
2641 GtkTextView *text_view;
2642 enum {INVALID, STRING, CTEXT, UTF8} type;
2644 text_view = GTK_TEXT_VIEW (widget);
2646 if (selection_data->type == GDK_TARGET_STRING)
2648 else if (selection_data->type == ctext_atom)
2650 else if (selection_data->type == utf8_atom)
2655 if (type == INVALID || selection_data->length < 0)
2657 /* I think the DND code automatically tries asking
2658 for the various formats. */
2662 if (!gtk_text_buffer_get_iter_at_mark (text_view->buffer, &drop_point, "__drag_target"))
2671 utf = gtk_text_latin1_to_utf ((const gchar*)selection_data->data,
2672 selection_data->length);
2673 gtk_text_buffer_insert (text_view->buffer, &drop_point,
2680 gtk_text_buffer_insert (text_view->buffer, &drop_point,
2681 (const gchar *)selection_data->data,
2682 selection_data->length);
2691 count = gdk_text_property_to_text_list (selection_data->type,
2692 selection_data->format,
2693 selection_data->data,
2694 selection_data->length,
2696 for (i=0; i<count; i++)
2698 /* FIXME this is broken, it assumes the CTEXT is latin1
2699 when it probably isn't. */
2702 utf = gtk_text_latin1_to_utf (list[i], strlen (list[i]));
2704 gtk_text_buffer_insert (text_view->buffer, &drop_point, utf, -1);
2710 gdk_free_text_list (list);
2714 case INVALID: /* quiet compiler */
2720 gtk_text_view_set_scroll_adjustments (GtkTextView *text_view,
2721 GtkAdjustment *hadj,
2722 GtkAdjustment *vadj)
2724 gboolean need_adjust = FALSE;
2726 g_return_if_fail (text_view != NULL);
2727 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
2730 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2732 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2734 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2736 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2738 if (text_view->hadjustment && (text_view->hadjustment != hadj))
2740 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->hadjustment), text_view);
2741 gtk_object_unref (GTK_OBJECT (text_view->hadjustment));
2744 if (text_view->vadjustment && (text_view->vadjustment != vadj))
2746 gtk_signal_disconnect_by_data (GTK_OBJECT (text_view->vadjustment), text_view);
2747 gtk_object_unref (GTK_OBJECT (text_view->vadjustment));
2750 if (text_view->hadjustment != hadj)
2752 text_view->hadjustment = hadj;
2753 gtk_object_ref (GTK_OBJECT (text_view->hadjustment));
2754 gtk_object_sink (GTK_OBJECT (text_view->hadjustment));
2756 gtk_signal_connect (GTK_OBJECT (text_view->hadjustment), "value_changed",
2757 (GtkSignalFunc) gtk_text_view_value_changed,
2762 if (text_view->vadjustment != vadj)
2764 text_view->vadjustment = vadj;
2765 gtk_object_ref (GTK_OBJECT (text_view->vadjustment));
2766 gtk_object_sink (GTK_OBJECT (text_view->vadjustment));
2768 gtk_signal_connect (GTK_OBJECT (text_view->vadjustment), "value_changed",
2769 (GtkSignalFunc) gtk_text_view_value_changed,
2775 gtk_text_view_value_changed (NULL, text_view);
2779 gtk_text_view_value_changed (GtkAdjustment *adj,
2780 GtkTextView *text_view)
2788 if (adj == text_view->hadjustment)
2790 dx = text_view->xoffset - (gint)adj->value;
2791 text_view->xoffset = adj->value;
2793 else if (adj == text_view->vadjustment)
2795 dy = text_view->yoffset - (gint)adj->value;
2796 text_view->yoffset = adj->value;
2798 if (text_view->layout)
2800 gtk_text_layout_get_line_at_y (text_view->layout, &iter, adj->value, &line_top);
2802 mark_name = gtk_text_mark_get_name (text_view->first_para_mark);
2803 gtk_text_buffer_move_mark (text_view->buffer, mark_name, &iter);
2806 text_view->first_para_pixels = adj->value - line_top;
2810 if (dx != 0 || dy != 0)
2812 gdk_window_scroll (text_view->bin_window, dx, dy);
2813 gdk_window_process_updates (text_view->bin_window, TRUE);
2818 gtk_text_view_commit_handler (GtkIMContext *context,
2820 GtkTextView *text_view)
2822 gtk_text_buffer_delete_selection (text_view->buffer);
2824 if (!strcmp (str, "\n"))
2826 gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1);
2830 if (text_view->overwrite_mode)
2831 gtk_text_view_delete_text (text_view, GTK_TEXT_DELETE_CHAR, 1);
2832 gtk_text_buffer_insert_at_cursor (text_view->buffer, str, strlen (str));
2835 gtk_text_view_scroll_to_mark (text_view, "insert", 0);
2839 gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
2840 const GtkTextIter *location,
2841 const char *mark_name,
2844 GtkTextView *text_view = GTK_TEXT_VIEW (data);
2846 if (!strcmp (mark_name, "insert"))
2848 text_view->virtual_cursor_x = -1;
2849 text_view->virtual_cursor_y = -1;
2854 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
2858 GdkRectangle strong_pos;
2861 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert, "insert");
2863 if ((x && text_view->virtual_cursor_x == -1) ||
2864 (y && text_view->virtual_cursor_y == -1))
2865 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
2869 if (text_view->virtual_cursor_x != -1)
2870 *x = text_view->virtual_cursor_x;
2877 if (text_view->virtual_cursor_x != -1)
2878 *y = text_view->virtual_cursor_y;
2880 *y = strong_pos.y + strong_pos.height / 2;
2885 gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
2889 GdkRectangle strong_pos;
2892 gtk_text_buffer_get_iter_at_mark (text_view->buffer, &insert, "insert");
2894 if (x == -1 || y == -1)
2895 gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
2897 text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
2898 text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;