1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Copyright (C) 2004-2006 Christian Hammond
5 * Copyright (C) 2008 Cody Russell
6 * Copyright (C) 2008 Red Hat, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
36 #include "gdk/gdkkeysyms.h"
37 #include "gtkalignment.h"
38 #include "gtkbindings.h"
39 #include "gtkcelleditable.h"
40 #include "gtkclipboard.h"
43 #include "gtkimagemenuitem.h"
44 #include "gtkimcontextsimple.h"
45 #include "gtkimmulticontext.h"
49 #include "gtkmarshalers.h"
51 #include "gtkmenuitem.h"
52 #include "gtkseparatormenuitem.h"
53 #include "gtkselection.h"
54 #include "gtksettings.h"
55 #include "gtkspinbutton.h"
57 #include "gtktextutil.h"
58 #include "gtkwindow.h"
59 #include "gtktreeview.h"
60 #include "gtktreeselection.h"
61 #include "gtkprivate.h"
62 #include "gtkentryprivate.h"
63 #include "gtkcelllayout.h"
64 #include "gtktooltip.h"
65 #include "gtkiconfactory.h"
66 #include "gtkicontheme.h"
69 #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
71 #define MIN_ENTRY_WIDTH 150
72 #define DRAW_TIMEOUT 20
73 #define COMPLETION_TIMEOUT 300
74 #define PASSWORD_HINT_MAX 8
76 /* Initial size of buffer, in bytes */
79 /* Maximum size of text buffer, in bytes */
80 #define MAX_SIZE G_MAXUSHORT
84 #define IS_VALID_ICON_POSITION(pos) \
85 ((pos) == GTK_ENTRY_ICON_PRIMARY || \
86 (pos) == GTK_ENTRY_ICON_SECONDARY)
88 static const GtkBorder default_inner_border = { 2, 2, 2, 2 };
89 static GQuark quark_inner_border = 0;
90 static GQuark quark_password_hint = 0;
91 static GQuark quark_cursor_hadjustment = 0;
92 static GQuark quark_capslock_feedback = 0;
94 typedef struct _GtkEntryPrivate GtkEntryPrivate;
96 #define GTK_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY, GtkEntryPrivate))
102 guint insensitive : 1;
103 guint nonactivatable : 1;
108 GtkImageType storage_type;
114 GtkTargetList *target_list;
115 GdkDragAction actions;
118 struct _GtkEntryPrivate
122 guint blink_time; /* time in msec the cursor has blinked since last user event */
123 guint interior_focus : 1;
124 guint real_changed : 1;
125 guint invisible_char_set : 1;
126 guint caps_lock_warning : 1;
127 guint caps_lock_warning_shown : 1;
128 guint change_count : 8;
129 guint progress_pulse_mode : 1;
130 guint progress_pulse_way_back : 1;
133 GtkShadowType shadow_type;
135 gdouble progress_fraction;
136 gdouble progress_pulse_fraction;
137 gdouble progress_pulse_current;
139 EntryIconInfo *icons[MAX_ICONS];
145 typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
147 struct _GtkEntryPasswordHint
149 gchar password_hint[PASSWORD_HINT_MAX];
150 guint password_hint_timeout_id;
151 gint password_hint_length;
152 gint password_hint_position;
155 typedef struct _GtkEntryCapslockFeedback GtkEntryCapslockFeedback;
157 struct _GtkEntryCapslockFeedback
182 PROP_CURSOR_POSITION,
183 PROP_SELECTION_BOUND,
190 PROP_ACTIVATES_DEFAULT,
195 PROP_TRUNCATE_MULTILINE,
199 PROP_INVISIBLE_CHAR_SET,
200 PROP_CAPS_LOCK_WARNING,
201 PROP_PROGRESS_FRACTION,
202 PROP_PROGRESS_PULSE_STEP,
204 PROP_PIXBUF_SECONDARY,
206 PROP_STOCK_SECONDARY,
207 PROP_ICON_NAME_PRIMARY,
208 PROP_ICON_NAME_SECONDARY,
210 PROP_GICON_SECONDARY,
211 PROP_STORAGE_TYPE_PRIMARY,
212 PROP_STORAGE_TYPE_SECONDARY,
213 PROP_ACTIVATABLE_PRIMARY,
214 PROP_ACTIVATABLE_SECONDARY,
215 PROP_SENSITIVE_PRIMARY,
216 PROP_SENSITIVE_SECONDARY
219 static guint signals[LAST_SIGNAL] = { 0 };
226 /* GObject, GtkObject methods
228 static void gtk_entry_editable_init (GtkEditableClass *iface);
229 static void gtk_entry_cell_editable_init (GtkCellEditableIface *iface);
230 static void gtk_entry_set_property (GObject *object,
234 static void gtk_entry_get_property (GObject *object,
238 static void gtk_entry_finalize (GObject *object);
239 static void gtk_entry_destroy (GtkObject *object);
240 static void gtk_entry_dispose (GObject *object);
244 static void gtk_entry_realize (GtkWidget *widget);
245 static void gtk_entry_unrealize (GtkWidget *widget);
246 static void gtk_entry_map (GtkWidget *widget);
247 static void gtk_entry_unmap (GtkWidget *widget);
248 static void gtk_entry_size_request (GtkWidget *widget,
249 GtkRequisition *requisition);
250 static void gtk_entry_size_allocate (GtkWidget *widget,
251 GtkAllocation *allocation);
252 static void gtk_entry_draw_frame (GtkWidget *widget,
254 static void gtk_entry_draw_progress (GtkWidget *widget,
255 GdkEventExpose *event);
256 static gint gtk_entry_expose (GtkWidget *widget,
257 GdkEventExpose *event);
258 static gint gtk_entry_button_press (GtkWidget *widget,
259 GdkEventButton *event);
260 static gint gtk_entry_button_release (GtkWidget *widget,
261 GdkEventButton *event);
262 static gint gtk_entry_enter_notify (GtkWidget *widget,
263 GdkEventCrossing *event);
264 static gint gtk_entry_leave_notify (GtkWidget *widget,
265 GdkEventCrossing *event);
266 static gint gtk_entry_motion_notify (GtkWidget *widget,
267 GdkEventMotion *event);
268 static gint gtk_entry_key_press (GtkWidget *widget,
270 static gint gtk_entry_key_release (GtkWidget *widget,
272 static gint gtk_entry_focus_in (GtkWidget *widget,
273 GdkEventFocus *event);
274 static gint gtk_entry_focus_out (GtkWidget *widget,
275 GdkEventFocus *event);
276 static void gtk_entry_grab_focus (GtkWidget *widget);
277 static void gtk_entry_style_set (GtkWidget *widget,
278 GtkStyle *previous_style);
279 static gboolean gtk_entry_query_tooltip (GtkWidget *widget,
282 gboolean keyboard_tip,
283 GtkTooltip *tooltip);
284 static void gtk_entry_direction_changed (GtkWidget *widget,
285 GtkTextDirection previous_dir);
286 static void gtk_entry_state_changed (GtkWidget *widget,
287 GtkStateType previous_state);
288 static void gtk_entry_screen_changed (GtkWidget *widget,
289 GdkScreen *old_screen);
291 static gboolean gtk_entry_drag_drop (GtkWidget *widget,
292 GdkDragContext *context,
296 static gboolean gtk_entry_drag_motion (GtkWidget *widget,
297 GdkDragContext *context,
301 static void gtk_entry_drag_leave (GtkWidget *widget,
302 GdkDragContext *context,
304 static void gtk_entry_drag_data_received (GtkWidget *widget,
305 GdkDragContext *context,
308 GtkSelectionData *selection_data,
311 static void gtk_entry_drag_data_get (GtkWidget *widget,
312 GdkDragContext *context,
313 GtkSelectionData *selection_data,
316 static void gtk_entry_drag_data_delete (GtkWidget *widget,
317 GdkDragContext *context);
318 static void gtk_entry_drag_begin (GtkWidget *widget,
319 GdkDragContext *context);
320 static void gtk_entry_drag_end (GtkWidget *widget,
321 GdkDragContext *context);
324 /* GtkEditable method implementations
326 static void gtk_entry_insert_text (GtkEditable *editable,
327 const gchar *new_text,
328 gint new_text_length,
330 static void gtk_entry_delete_text (GtkEditable *editable,
333 static gchar * gtk_entry_get_chars (GtkEditable *editable,
336 static void gtk_entry_real_set_position (GtkEditable *editable,
338 static gint gtk_entry_get_position (GtkEditable *editable);
339 static void gtk_entry_set_selection_bounds (GtkEditable *editable,
342 static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
346 /* GtkCellEditable method implementations
348 static void gtk_entry_start_editing (GtkCellEditable *cell_editable,
351 /* Default signal handlers
353 static void gtk_entry_real_insert_text (GtkEditable *editable,
354 const gchar *new_text,
355 gint new_text_length,
357 static void gtk_entry_real_delete_text (GtkEditable *editable,
360 static void gtk_entry_move_cursor (GtkEntry *entry,
361 GtkMovementStep step,
363 gboolean extend_selection);
364 static void gtk_entry_insert_at_cursor (GtkEntry *entry,
366 static void gtk_entry_delete_from_cursor (GtkEntry *entry,
369 static void gtk_entry_backspace (GtkEntry *entry);
370 static void gtk_entry_cut_clipboard (GtkEntry *entry);
371 static void gtk_entry_copy_clipboard (GtkEntry *entry);
372 static void gtk_entry_paste_clipboard (GtkEntry *entry);
373 static void gtk_entry_toggle_overwrite (GtkEntry *entry);
374 static void gtk_entry_select_all (GtkEntry *entry);
375 static void gtk_entry_real_activate (GtkEntry *entry);
376 static gboolean gtk_entry_popup_menu (GtkWidget *widget);
378 static void keymap_direction_changed (GdkKeymap *keymap,
380 static void keymap_state_changed (GdkKeymap *keymap,
382 static void remove_capslock_feedback (GtkEntry *entry);
384 /* IM Context Callbacks
386 static void gtk_entry_commit_cb (GtkIMContext *context,
389 static void gtk_entry_preedit_changed_cb (GtkIMContext *context,
391 static gboolean gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
393 static gboolean gtk_entry_delete_surrounding_cb (GtkIMContext *context,
400 static void gtk_entry_enter_text (GtkEntry *entry,
402 static void gtk_entry_set_positions (GtkEntry *entry,
404 gint selection_bound);
405 static void gtk_entry_draw_text (GtkEntry *entry);
406 static void gtk_entry_draw_cursor (GtkEntry *entry,
408 static PangoLayout *gtk_entry_ensure_layout (GtkEntry *entry,
409 gboolean include_preedit);
410 static void gtk_entry_reset_layout (GtkEntry *entry);
411 static void gtk_entry_queue_draw (GtkEntry *entry);
412 static void gtk_entry_recompute (GtkEntry *entry);
413 static gint gtk_entry_find_position (GtkEntry *entry,
415 static void gtk_entry_get_cursor_locations (GtkEntry *entry,
419 static void gtk_entry_adjust_scroll (GtkEntry *entry);
420 static gint gtk_entry_move_visually (GtkEntry *editable,
423 static gint gtk_entry_move_logically (GtkEntry *entry,
426 static gint gtk_entry_move_forward_word (GtkEntry *entry,
428 gboolean allow_whitespace);
429 static gint gtk_entry_move_backward_word (GtkEntry *entry,
431 gboolean allow_whitespace);
432 static void gtk_entry_delete_whitespace (GtkEntry *entry);
433 static void gtk_entry_select_word (GtkEntry *entry);
434 static void gtk_entry_select_line (GtkEntry *entry);
435 static char * gtk_entry_get_public_chars (GtkEntry *entry,
438 static void gtk_entry_paste (GtkEntry *entry,
440 static void gtk_entry_update_primary_selection (GtkEntry *entry);
441 static void gtk_entry_do_popup (GtkEntry *entry,
442 GdkEventButton *event);
443 static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget,
444 gboolean group_cycling);
445 static void gtk_entry_state_changed (GtkWidget *widget,
446 GtkStateType previous_state);
447 static void gtk_entry_check_cursor_blink (GtkEntry *entry);
448 static void gtk_entry_pend_cursor_blink (GtkEntry *entry);
449 static void gtk_entry_reset_blink_time (GtkEntry *entry);
450 static void gtk_entry_get_text_area_size (GtkEntry *entry,
455 static void get_widget_window_size (GtkEntry *entry,
460 static void gtk_entry_move_adjustments (GtkEntry *entry);
461 static void gtk_entry_ensure_pixbuf (GtkEntry *entry,
462 GtkEntryIconPosition icon_pos);
466 static gint gtk_entry_completion_timeout (gpointer data);
467 static gboolean gtk_entry_completion_key_press (GtkWidget *widget,
470 static void gtk_entry_completion_changed (GtkWidget *entry,
472 static gboolean check_completion_callback (GtkEntryCompletion *completion);
473 static void clear_completion_callback (GtkEntry *entry,
475 static gboolean accept_completion_callback (GtkEntry *entry);
476 static void completion_insert_text_callback (GtkEntry *entry,
480 GtkEntryCompletion *completion);
481 static void completion_changed (GtkEntryCompletion *completion,
484 static void disconnect_completion_signals (GtkEntry *entry,
485 GtkEntryCompletion *completion);
486 static void connect_completion_signals (GtkEntry *entry,
487 GtkEntryCompletion *completion);
489 static void begin_change (GtkEntry *entry);
490 static void end_change (GtkEntry *entry);
491 static void emit_changed (GtkEntry *entry);
494 G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
495 G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
496 gtk_entry_editable_init)
497 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
498 gtk_entry_cell_editable_init))
501 add_move_binding (GtkBindingSet *binding_set,
504 GtkMovementStep step,
507 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
509 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
513 G_TYPE_BOOLEAN, FALSE);
515 /* Selection-extending version */
516 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
520 G_TYPE_BOOLEAN, TRUE);
524 gtk_entry_class_init (GtkEntryClass *class)
526 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
527 GtkWidgetClass *widget_class;
528 GtkObjectClass *gtk_object_class;
529 GtkBindingSet *binding_set;
531 widget_class = (GtkWidgetClass*) class;
532 gtk_object_class = (GtkObjectClass *)class;
534 gobject_class->dispose = gtk_entry_dispose;
535 gobject_class->finalize = gtk_entry_finalize;
536 gobject_class->set_property = gtk_entry_set_property;
537 gobject_class->get_property = gtk_entry_get_property;
539 widget_class->map = gtk_entry_map;
540 widget_class->unmap = gtk_entry_unmap;
541 widget_class->realize = gtk_entry_realize;
542 widget_class->unrealize = gtk_entry_unrealize;
543 widget_class->size_request = gtk_entry_size_request;
544 widget_class->size_allocate = gtk_entry_size_allocate;
545 widget_class->expose_event = gtk_entry_expose;
546 widget_class->enter_notify_event = gtk_entry_enter_notify;
547 widget_class->leave_notify_event = gtk_entry_leave_notify;
548 widget_class->button_press_event = gtk_entry_button_press;
549 widget_class->button_release_event = gtk_entry_button_release;
550 widget_class->motion_notify_event = gtk_entry_motion_notify;
551 widget_class->key_press_event = gtk_entry_key_press;
552 widget_class->key_release_event = gtk_entry_key_release;
553 widget_class->focus_in_event = gtk_entry_focus_in;
554 widget_class->focus_out_event = gtk_entry_focus_out;
555 widget_class->grab_focus = gtk_entry_grab_focus;
556 widget_class->style_set = gtk_entry_style_set;
557 widget_class->query_tooltip = gtk_entry_query_tooltip;
558 widget_class->drag_begin = gtk_entry_drag_begin;
559 widget_class->drag_end = gtk_entry_drag_end;
560 widget_class->direction_changed = gtk_entry_direction_changed;
561 widget_class->state_changed = gtk_entry_state_changed;
562 widget_class->screen_changed = gtk_entry_screen_changed;
563 widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
565 widget_class->drag_drop = gtk_entry_drag_drop;
566 widget_class->drag_motion = gtk_entry_drag_motion;
567 widget_class->drag_leave = gtk_entry_drag_leave;
568 widget_class->drag_data_received = gtk_entry_drag_data_received;
569 widget_class->drag_data_get = gtk_entry_drag_data_get;
570 widget_class->drag_data_delete = gtk_entry_drag_data_delete;
572 widget_class->popup_menu = gtk_entry_popup_menu;
574 gtk_object_class->destroy = gtk_entry_destroy;
576 class->move_cursor = gtk_entry_move_cursor;
577 class->insert_at_cursor = gtk_entry_insert_at_cursor;
578 class->delete_from_cursor = gtk_entry_delete_from_cursor;
579 class->backspace = gtk_entry_backspace;
580 class->cut_clipboard = gtk_entry_cut_clipboard;
581 class->copy_clipboard = gtk_entry_copy_clipboard;
582 class->paste_clipboard = gtk_entry_paste_clipboard;
583 class->toggle_overwrite = gtk_entry_toggle_overwrite;
584 class->activate = gtk_entry_real_activate;
585 class->get_text_area_size = gtk_entry_get_text_area_size;
587 quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border");
588 quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint");
589 quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment");
590 quark_capslock_feedback = g_quark_from_static_string ("gtk-entry-capslock-feedback");
592 g_object_class_install_property (gobject_class,
593 PROP_CURSOR_POSITION,
594 g_param_spec_int ("cursor-position",
595 P_("Cursor Position"),
596 P_("The current position of the insertion cursor in chars"),
600 GTK_PARAM_READABLE));
602 g_object_class_install_property (gobject_class,
603 PROP_SELECTION_BOUND,
604 g_param_spec_int ("selection-bound",
605 P_("Selection Bound"),
606 P_("The position of the opposite end of the selection from the cursor in chars"),
610 GTK_PARAM_READABLE));
612 g_object_class_install_property (gobject_class,
614 g_param_spec_boolean ("editable",
616 P_("Whether the entry contents can be edited"),
618 GTK_PARAM_READWRITE));
620 g_object_class_install_property (gobject_class,
622 g_param_spec_int ("max-length",
623 P_("Maximum length"),
624 P_("Maximum number of characters for this entry. Zero if no maximum"),
628 GTK_PARAM_READWRITE));
629 g_object_class_install_property (gobject_class,
631 g_param_spec_boolean ("visibility",
633 P_("FALSE displays the \"invisible char\" instead of the actual text (password mode)"),
635 GTK_PARAM_READWRITE));
637 g_object_class_install_property (gobject_class,
639 g_param_spec_boolean ("has-frame",
641 P_("FALSE removes outside bevel from entry"),
643 GTK_PARAM_READWRITE));
645 g_object_class_install_property (gobject_class,
647 g_param_spec_boxed ("inner-border",
649 P_("Border between text and frame. Overrides the inner-border style property"),
651 GTK_PARAM_READWRITE));
653 g_object_class_install_property (gobject_class,
655 g_param_spec_unichar ("invisible-char",
656 P_("Invisible character"),
657 P_("The character to use when masking entry contents (in \"password mode\")"),
659 GTK_PARAM_READWRITE));
661 g_object_class_install_property (gobject_class,
662 PROP_ACTIVATES_DEFAULT,
663 g_param_spec_boolean ("activates-default",
664 P_("Activates default"),
665 P_("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed"),
667 GTK_PARAM_READWRITE));
668 g_object_class_install_property (gobject_class,
670 g_param_spec_int ("width-chars",
671 P_("Width in chars"),
672 P_("Number of characters to leave space for in the entry"),
676 GTK_PARAM_READWRITE));
678 g_object_class_install_property (gobject_class,
680 g_param_spec_int ("scroll-offset",
682 P_("Number of pixels of the entry scrolled off the screen to the left"),
686 GTK_PARAM_READABLE));
688 g_object_class_install_property (gobject_class,
690 g_param_spec_string ("text",
692 P_("The contents of the entry"),
694 GTK_PARAM_READWRITE));
699 * The horizontal alignment, from 0 (left) to 1 (right).
700 * Reversed for RTL layouts.
704 g_object_class_install_property (gobject_class,
706 g_param_spec_float ("xalign",
708 P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
712 GTK_PARAM_READWRITE));
715 * GtkEntry:truncate-multiline:
717 * When %TRUE, pasted multi-line text is truncated to the first line.
721 g_object_class_install_property (gobject_class,
722 PROP_TRUNCATE_MULTILINE,
723 g_param_spec_boolean ("truncate-multiline",
724 P_("Truncate multiline"),
725 P_("Whether to truncate multiline pastes to one line."),
727 GTK_PARAM_READWRITE));
730 * GtkEntry:shadow-type:
732 * Which kind of shadow to draw around the entry when
733 * #GtkEntry:has-frame is set to %TRUE.
737 g_object_class_install_property (gobject_class,
739 g_param_spec_enum ("shadow-type",
741 P_("Which kind of shadow to draw around the entry when has-frame is set"),
742 GTK_TYPE_SHADOW_TYPE,
744 GTK_PARAM_READWRITE));
747 * GtkEntry:overwrite-mode:
749 * If text is overwritten when typing in the #GtkEntry.
753 g_object_class_install_property (gobject_class,
755 g_param_spec_boolean ("overwrite-mode",
756 P_("Overwrite mode"),
757 P_("Whether new text overwrites existing text"),
759 GTK_PARAM_READWRITE));
762 * GtkEntry:text-length:
764 * The length of the text in the #GtkEntry.
768 g_object_class_install_property (gobject_class,
770 g_param_spec_uint ("text-length",
772 P_("Length of the text currently in the entry"),
776 GTK_PARAM_READABLE));
778 * GtkEntry:invisible-char-set:
780 * Whether the invisible char has been set for the #GtkEntry.
784 g_object_class_install_property (gobject_class,
785 PROP_INVISIBLE_CHAR_SET,
786 g_param_spec_boolean ("invisible-char-set",
787 P_("Invisible char set"),
788 P_("Whether the invisible char has been set"),
790 GTK_PARAM_READWRITE));
793 * GtkEntry:caps-lock-warning
795 * Whether password entries will show a warning when Caps Lock is on
796 * or an input method is active.
798 * Note that the warning is shown using a secondary icon, and thus
799 * does not work if you are using the secondary icon position for some
804 g_object_class_install_property (gobject_class,
805 PROP_CAPS_LOCK_WARNING,
806 g_param_spec_boolean ("caps-lock-warning",
807 P_("Caps Lock warning"),
808 P_("Whether password entries will show a warning when Caps Lock is on or an input method is active"),
810 GTK_PARAM_READWRITE));
813 * GtkEntry:progress-fraction:
815 * The current fraction of the task that's been completed.
819 g_object_class_install_property (gobject_class,
820 PROP_PROGRESS_FRACTION,
821 g_param_spec_double ("progress-fraction",
822 P_("Progress Fraction"),
823 P_("The current fraction of the task that's been completed"),
827 GTK_PARAM_READWRITE));
830 * GtkEntry:progress-pulse-step:
832 * The fraction of total entry width to move the progress
833 * bouncing block for each call to gtk_entry_progress_pulse().
837 g_object_class_install_property (gobject_class,
838 PROP_PROGRESS_PULSE_STEP,
839 g_param_spec_double ("progress-pulse-step",
840 P_("Progress Pulse Step"),
841 P_("The fraction of total entry width to move the progress bouncing block for each call to gtk_entry_progress_pulse()"),
845 GTK_PARAM_READWRITE));
848 * GtkEntry:pixbuf-primary:
850 * A pixbuf to use as the primary icon for the entry.
854 g_object_class_install_property (gobject_class,
856 g_param_spec_object ("pixbuf-primary",
857 P_("Primary pixbuf"),
858 P_("Primary pixbuf for the entry"),
860 GTK_PARAM_READWRITE));
863 * GtkEntry:pixbuf-secondary:
865 * An pixbuf to use as the secondary icon for the entry.
869 g_object_class_install_property (gobject_class,
870 PROP_PIXBUF_SECONDARY,
871 g_param_spec_object ("pixbuf-secondary",
872 P_("Secondary pixbuf"),
873 P_("Secondary pixbuf for the entry"),
875 GTK_PARAM_READWRITE));
878 * GtkEntry:stock-primary:
880 * The stock id to use for the primary icon for the entry.
884 g_object_class_install_property (gobject_class,
886 g_param_spec_string ("stock-primary",
887 P_("Primary stock ID"),
888 P_("Stock ID for primary icon"),
890 GTK_PARAM_READWRITE));
893 * GtkEntry:stock-secondary:
895 * The stock id to use for the secondary icon for the entry.
899 g_object_class_install_property (gobject_class,
900 PROP_STOCK_SECONDARY,
901 g_param_spec_string ("stock-secondary",
902 P_("Secondary stock ID"),
903 P_("Stock ID for secondary icon"),
905 GTK_PARAM_READWRITE));
908 * GtkEntry:icon-name-primary:
910 * The icon name to use for the primary icon for the entry.
914 g_object_class_install_property (gobject_class,
915 PROP_ICON_NAME_PRIMARY,
916 g_param_spec_string ("icon-name-primary",
917 P_("Primary icon name"),
918 P_("Icon name for primary icon"),
920 GTK_PARAM_READWRITE));
923 * GtkEntry:icon-name-secondary:
925 * The icon name to use for the secondary icon for the entry.
929 g_object_class_install_property (gobject_class,
930 PROP_ICON_NAME_SECONDARY,
931 g_param_spec_string ("icon-name-secondary",
932 P_("Secondary icon name"),
933 P_("Icon name for secondary icon"),
935 GTK_PARAM_READWRITE));
938 * GtkEntry:gicon-primary:
940 * The #GIcon to use for the primary icon for the entry.
944 g_object_class_install_property (gobject_class,
946 g_param_spec_object ("gicon-primary",
948 P_("GIcon for primary icon"),
950 GTK_PARAM_READWRITE));
953 * GtkEntry:gicon-secondary:
955 * The #GIcon to use for the secondary icon for the entry.
959 g_object_class_install_property (gobject_class,
960 PROP_GICON_SECONDARY,
961 g_param_spec_object ("gicon-secondary",
962 P_("Secondary GIcon"),
963 P_("GIcon for secondary icon"),
965 GTK_PARAM_READWRITE));
968 * GtkEntry:storage-type-primary:
970 * The representation which is used for the primary icon of the entry.
974 g_object_class_install_property (gobject_class,
975 PROP_STORAGE_TYPE_PRIMARY,
976 g_param_spec_enum ("storage-type-primary",
977 P_("Primary storage type"),
978 P_("The representation being used for primary icon"),
981 GTK_PARAM_READABLE));
984 * GtkEntry:storage-type-secondary:
986 * The representation which is used for the secondary icon of the entry.
990 g_object_class_install_property (gobject_class,
991 PROP_STORAGE_TYPE_SECONDARY,
992 g_param_spec_enum ("storage-type-secondary",
993 P_("Secondary storage type"),
994 P_("The representation being used for secondary icon"),
997 GTK_PARAM_READABLE));
1000 * GtkEntry:activatable-primary:
1002 * Whether the primary icon is activatable.
1004 * GTK+ emits the #GtkEntry::icon-press and #GtkEntry::icon-release
1005 * signals only on sensitive, activatable icons.
1007 * Sensitive, but non-activatable icons can be used for purely
1008 * informational purposes.
1012 g_object_class_install_property (gobject_class,
1013 PROP_ACTIVATABLE_PRIMARY,
1014 g_param_spec_boolean ("activatable-primary",
1015 P_("Primary icon activatable"),
1016 P_("Whether the primary icon is activatable"),
1018 GTK_PARAM_READWRITE));
1021 * GtkEntry:activatable-secondary:
1023 * Whether the secondary icon is activatable.
1025 * GTK+ emits the #GtkEntry::icon-press and #GtkEntry::icon-release
1026 * signals only on sensitive, activatable icons.
1028 * Sensitive, but non-activatable icons can be used for purely
1029 * informational purposes.
1033 g_object_class_install_property (gobject_class,
1034 PROP_ACTIVATABLE_SECONDARY,
1035 g_param_spec_boolean ("activatable-secondary",
1036 P_("Secondary icon activatable"),
1037 P_("Whether the secondary icon is activatable"),
1039 GTK_PARAM_READWRITE));
1043 * GtkEntry:sensitive-primary:
1045 * Whether the primary icon is sensitive.
1047 * An insensitive icon appears grayed out. GTK+ does not emit the
1048 * #GtkEntry::icon-press and #GtkEntry::icon-release signals and
1049 * does not allow DND from insensitive icons.
1051 * An icon should be set insensitive if the action that would trigger
1052 * when clicked is currently not available.
1056 g_object_class_install_property (gobject_class,
1057 PROP_SENSITIVE_PRIMARY,
1058 g_param_spec_boolean ("sensitive-primary",
1059 P_("Primary icon sensitive"),
1060 P_("Whether the primary icon is sensitive"),
1062 GTK_PARAM_READWRITE));
1065 * GtkEntry:sensitive-secondary:
1067 * Whether the secondary icon is sensitive.
1069 * An insensitive icon appears grayed out. GTK+ does not emit the
1070 * #GtkEntry::icon-press and #GtkEntry::icon-release signals and
1071 * does not allow DND from insensitive icons.
1073 * An icon should be set insensitive if the action that would trigger
1074 * when clicked is currently not available.
1078 g_object_class_install_property (gobject_class,
1079 PROP_SENSITIVE_SECONDARY,
1080 g_param_spec_boolean ("sensitive-secondary",
1081 P_("Secondary icon sensitive"),
1082 P_("Whether the secondary icon is sensitive"),
1084 GTK_PARAM_READWRITE));
1087 * GtkEntry:prelight:
1089 * The prelight style property determines whether activatable
1090 * icons prelight on mouseover.
1094 gtk_widget_class_install_style_property (widget_class,
1095 g_param_spec_boolean ("prelight",
1097 P_("Whether activatable icons should prelight when hovered"),
1099 GTK_PARAM_READABLE));
1102 * GtkEntry::populate-popup:
1103 * @entry: The entry on which the signal is emitted
1104 * @menu: the menu that is being populated
1106 * The ::populate-popup signal gets emitted before showing the
1107 * context menu of the entry.
1109 * If you need to add items to the context menu, connect
1110 * to this signal and append your menuitems to the @menu.
1112 signals[POPULATE_POPUP] =
1113 g_signal_new (I_("populate-popup"),
1114 G_OBJECT_CLASS_TYPE (gobject_class),
1116 G_STRUCT_OFFSET (GtkEntryClass, populate_popup),
1118 _gtk_marshal_VOID__OBJECT,
1122 /* Action signals */
1125 * GtkEntry::activate:
1126 * @entry: The entry on which the signal is emitted
1128 * A <link linkend="keybinding-signals">keybinding signal</link>
1129 * which gets emitted when the user activates the entry.
1131 * Applications should not connect to it, but may emit it with
1132 * g_signal_emit_by_name() if they need to control scrolling
1135 * The default bindings for this signal are all forms of the Enter key.
1138 g_signal_new (I_("activate"),
1139 G_OBJECT_CLASS_TYPE (gobject_class),
1140 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1141 G_STRUCT_OFFSET (GtkEntryClass, activate),
1143 _gtk_marshal_VOID__VOID,
1145 widget_class->activate_signal = signals[ACTIVATE];
1148 * GtkEntry::move-cursor:
1149 * @entry: the object which received the signal
1150 * @step: the granularity of the move, as a #GtkMovementStep
1151 * @count: the number of @step units to move
1152 * @extend_selection: %TRUE if the move should extend the selection
1154 * The ::move-cursor signal is a
1155 * <link linkend="keybinding-signals">keybinding signal</link>
1156 * which gets emitted when the user initiates a cursor movement.
1157 * If the cursor is not visible in @entry, this signal causes
1158 * the viewport to be moved instead.
1160 * Applications should not connect to it, but may emit it with
1161 * g_signal_emit_by_name() if they need to control scrolling
1164 * The default bindings for this signal come in two variants,
1165 * the variant with the Shift modifier extends the selection,
1166 * the variant without the Shift modifer does not.
1167 * There are too many key combinations to list them all here.
1169 * <listitem>Arrow keys move by individual characters/lines</listitem>
1170 * <listitem>Ctrl-arrow key combinations move by words/paragraphs</listitem>
1171 * <listitem>Home/End keys move to the ends of the buffer</listitem>
1174 signals[MOVE_CURSOR] =
1175 g_signal_new (I_("move-cursor"),
1176 G_OBJECT_CLASS_TYPE (gobject_class),
1177 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1178 G_STRUCT_OFFSET (GtkEntryClass, move_cursor),
1180 _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
1182 GTK_TYPE_MOVEMENT_STEP,
1187 * GtkEntry::insert-at-cursor:
1188 * @entry: the object which received the signal
1189 * @string: the string to insert
1191 * The ::insert-at-cursor signal is a
1192 * <link linkend="keybinding-signals">keybinding signal</link>
1193 * which gets emitted when the user initiates the insertion of a
1194 * fixed string at the cursor.
1196 * This signal has no default bindings.
1198 signals[INSERT_AT_CURSOR] =
1199 g_signal_new (I_("insert-at-cursor"),
1200 G_OBJECT_CLASS_TYPE (gobject_class),
1201 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1202 G_STRUCT_OFFSET (GtkEntryClass, insert_at_cursor),
1204 _gtk_marshal_VOID__STRING,
1209 * GtkEntry::delete-from-cursor:
1210 * @entry: the object which received the signal
1211 * @type: the granularity of the deletion, as a #GtkDeleteType
1212 * @count: the number of @type units to delete
1214 * The ::delete-from-cursor signal is a
1215 * <link linkend="keybinding-signals">keybinding signal</link>
1216 * which gets emitted when the user initiates a text deletion.
1218 * If the @type is %GTK_DELETE_CHARS, GTK+ deletes the selection
1219 * if there is one, otherwise it deletes the requested number
1222 * The default bindings for this signal are
1223 * Delete for deleting a character and Ctrl-Delete for
1226 signals[DELETE_FROM_CURSOR] =
1227 g_signal_new (I_("delete-from-cursor"),
1228 G_OBJECT_CLASS_TYPE (gobject_class),
1229 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1230 G_STRUCT_OFFSET (GtkEntryClass, delete_from_cursor),
1232 _gtk_marshal_VOID__ENUM_INT,
1234 GTK_TYPE_DELETE_TYPE,
1238 * GtkEntry::backspace:
1239 * @entry: the object which received the signal
1241 * The ::backspace signal is a
1242 * <link linkend="keybinding-signals">keybinding signal</link>
1243 * which gets emitted when the user asks for it.
1245 * The default bindings for this signal are
1246 * Backspace and Shift-Backspace.
1248 signals[BACKSPACE] =
1249 g_signal_new (I_("backspace"),
1250 G_OBJECT_CLASS_TYPE (gobject_class),
1251 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1252 G_STRUCT_OFFSET (GtkEntryClass, backspace),
1254 _gtk_marshal_VOID__VOID,
1258 * GtkEntry::cut-clipboard:
1259 * @entry: the object which received the signal
1261 * The ::cut-clipboard signal is a
1262 * <link linkend="keybinding-signals">keybinding signal</link>
1263 * which gets emitted to cut the selection to the clipboard.
1265 * The default bindings for this signal are
1266 * Ctrl-x and Shift-Delete.
1268 signals[CUT_CLIPBOARD] =
1269 g_signal_new (I_("cut-clipboard"),
1270 G_OBJECT_CLASS_TYPE (gobject_class),
1271 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1272 G_STRUCT_OFFSET (GtkEntryClass, cut_clipboard),
1274 _gtk_marshal_VOID__VOID,
1278 * GtkEntry::copy-clipboard:
1279 * @entry: the object which received the signal
1281 * The ::copy-clipboard signal is a
1282 * <link linkend="keybinding-signals">keybinding signal</link>
1283 * which gets emitted to copy the selection to the clipboard.
1285 * The default bindings for this signal are
1286 * Ctrl-c and Ctrl-Insert.
1288 signals[COPY_CLIPBOARD] =
1289 g_signal_new (I_("copy-clipboard"),
1290 G_OBJECT_CLASS_TYPE (gobject_class),
1291 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1292 G_STRUCT_OFFSET (GtkEntryClass, copy_clipboard),
1294 _gtk_marshal_VOID__VOID,
1298 * GtkEntry::paste-clipboard:
1299 * @entry: the object which received the signal
1301 * The ::paste-clipboard signal is a
1302 * <link linkend="keybinding-signals">keybinding signal</link>
1303 * which gets emitted to paste the contents of the clipboard
1304 * into the text view.
1306 * The default bindings for this signal are
1307 * Ctrl-v and Shift-Insert.
1309 signals[PASTE_CLIPBOARD] =
1310 g_signal_new (I_("paste-clipboard"),
1311 G_OBJECT_CLASS_TYPE (gobject_class),
1312 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1313 G_STRUCT_OFFSET (GtkEntryClass, paste_clipboard),
1315 _gtk_marshal_VOID__VOID,
1319 * GtkEntry::toggle-overwrite:
1320 * @entry: the object which received the signal
1322 * The ::toggle-overwrite signal is a
1323 * <link linkend="keybinding-signals">keybinding signal</link>
1324 * which gets emitted to toggle the overwrite mode of the entry.
1326 * The default bindings for this signal is Insert.
1328 signals[TOGGLE_OVERWRITE] =
1329 g_signal_new (I_("toggle-overwrite"),
1330 G_OBJECT_CLASS_TYPE (gobject_class),
1331 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1332 G_STRUCT_OFFSET (GtkEntryClass, toggle_overwrite),
1334 _gtk_marshal_VOID__VOID,
1338 * GtkEntry::icon-press:
1339 * @entry: The entry on which the signal is emitted
1340 * @icon_pos: The position of the clicked icon
1341 * @event: the button press event
1343 * The ::icon-press signal is emitted when an activatable icon
1348 signals[ICON_PRESS] =
1349 g_signal_new (I_("icon-press"),
1350 G_TYPE_FROM_CLASS (gobject_class),
1351 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1354 _gtk_marshal_VOID__ENUM_BOXED,
1356 GTK_TYPE_ENTRY_ICON_POSITION,
1357 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1360 * GtkEntry::icon-release:
1361 * @entry: The entry on which the signal is emitted
1362 * @icon_pos: The position of the clicked icon
1363 * @event: the button release event
1365 * The ::icon-release signal is emitted on the button release from a
1366 * mouse click over an activatable icon.
1370 signals[ICON_RELEASE] =
1371 g_signal_new (I_("icon-release"),
1372 G_TYPE_FROM_CLASS (gobject_class),
1373 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1376 _gtk_marshal_VOID__ENUM_BOXED,
1378 GTK_TYPE_ENTRY_ICON_POSITION,
1379 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1386 binding_set = gtk_binding_set_by_class (class);
1388 /* Moving the insertion point */
1389 add_move_binding (binding_set, GDK_Right, 0,
1390 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1392 add_move_binding (binding_set, GDK_Left, 0,
1393 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1395 add_move_binding (binding_set, GDK_KP_Right, 0,
1396 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1398 add_move_binding (binding_set, GDK_KP_Left, 0,
1399 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1401 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
1402 GTK_MOVEMENT_WORDS, 1);
1404 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
1405 GTK_MOVEMENT_WORDS, -1);
1407 add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1408 GTK_MOVEMENT_WORDS, 1);
1410 add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1411 GTK_MOVEMENT_WORDS, -1);
1413 add_move_binding (binding_set, GDK_Home, 0,
1414 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1416 add_move_binding (binding_set, GDK_End, 0,
1417 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1419 add_move_binding (binding_set, GDK_KP_Home, 0,
1420 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1422 add_move_binding (binding_set, GDK_KP_End, 0,
1423 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1425 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
1426 GTK_MOVEMENT_BUFFER_ENDS, -1);
1428 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
1429 GTK_MOVEMENT_BUFFER_ENDS, 1);
1431 add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
1432 GTK_MOVEMENT_BUFFER_ENDS, -1);
1434 add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
1435 GTK_MOVEMENT_BUFFER_ENDS, 1);
1439 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
1441 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1443 G_TYPE_BOOLEAN, FALSE);
1444 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
1446 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1448 G_TYPE_BOOLEAN, TRUE);
1450 gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
1452 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1454 G_TYPE_BOOLEAN, FALSE);
1455 gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
1457 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1459 G_TYPE_BOOLEAN, TRUE);
1462 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
1464 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
1466 G_TYPE_BOOLEAN, FALSE);
1467 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1469 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
1471 G_TYPE_BOOLEAN, FALSE);
1475 gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
1477 gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0,
1479 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
1483 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
1484 "delete-from-cursor", 2,
1485 G_TYPE_ENUM, GTK_DELETE_CHARS,
1488 gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
1489 "delete-from-cursor", 2,
1490 G_TYPE_ENUM, GTK_DELETE_CHARS,
1493 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
1496 /* Make this do the same as Backspace, to help with mis-typing */
1497 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK,
1500 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
1501 "delete-from-cursor", 2,
1502 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1505 gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
1506 "delete-from-cursor", 2,
1507 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1510 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
1511 "delete-from-cursor", 2,
1512 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1515 /* Cut/copy/paste */
1517 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
1518 "cut-clipboard", 0);
1519 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
1520 "copy-clipboard", 0);
1521 gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
1522 "paste-clipboard", 0);
1524 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK,
1525 "cut-clipboard", 0);
1526 gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK,
1527 "copy-clipboard", 0);
1528 gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK,
1529 "paste-clipboard", 0);
1532 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
1533 "toggle-overwrite", 0);
1534 gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
1535 "toggle-overwrite", 0);
1538 * GtkEntry:inner-border:
1540 * Sets the text area's border between the text and the frame.
1544 gtk_widget_class_install_style_property (widget_class,
1545 g_param_spec_boxed ("inner-border",
1547 P_("Border between text and frame."),
1549 GTK_PARAM_READABLE));
1552 * GtkEntry:state-hint:
1554 * Indicates whether to pass a proper widget state when
1555 * drawing the shadow and the widget background.
1559 gtk_widget_class_install_style_property (widget_class,
1560 g_param_spec_boolean ("state-hint",
1562 P_("Whether to pass a proper state when drawing shadow or background"),
1564 GTK_PARAM_READABLE));
1566 gtk_settings_install_property (g_param_spec_boolean ("gtk-entry-select-on-focus",
1567 P_("Select on focus"),
1568 P_("Whether to select the contents of an entry when it is focused"),
1570 GTK_PARAM_READWRITE));
1573 * GtkSettings:gtk-entry-password-hint-timeout:
1575 * How long to show the last input character in hidden
1576 * entries. This value is in milliseconds. 0 disables showing the
1577 * last char. 600 is a good value for enabling it.
1581 gtk_settings_install_property (g_param_spec_uint ("gtk-entry-password-hint-timeout",
1582 P_("Password Hint Timeout"),
1583 P_("How long to show the last input character in hidden entries"),
1585 GTK_PARAM_READWRITE));
1587 g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate));
1591 gtk_entry_editable_init (GtkEditableClass *iface)
1593 iface->do_insert_text = gtk_entry_insert_text;
1594 iface->do_delete_text = gtk_entry_delete_text;
1595 iface->insert_text = gtk_entry_real_insert_text;
1596 iface->delete_text = gtk_entry_real_delete_text;
1597 iface->get_chars = gtk_entry_get_chars;
1598 iface->set_selection_bounds = gtk_entry_set_selection_bounds;
1599 iface->get_selection_bounds = gtk_entry_get_selection_bounds;
1600 iface->set_position = gtk_entry_real_set_position;
1601 iface->get_position = gtk_entry_get_position;
1605 gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
1607 iface->start_editing = gtk_entry_start_editing;
1611 gtk_entry_set_property (GObject *object,
1613 const GValue *value,
1616 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
1617 GtkEntry *entry = GTK_ENTRY (object);
1623 gboolean new_value = g_value_get_boolean (value);
1625 if (new_value != entry->editable)
1629 _gtk_entry_reset_im_context (entry);
1630 if (GTK_WIDGET_HAS_FOCUS (entry))
1631 gtk_im_context_focus_out (entry->im_context);
1633 entry->preedit_length = 0;
1634 entry->preedit_cursor = 0;
1637 entry->editable = new_value;
1639 if (new_value && GTK_WIDGET_HAS_FOCUS (entry))
1640 gtk_im_context_focus_in (entry->im_context);
1642 gtk_entry_queue_draw (entry);
1647 case PROP_MAX_LENGTH:
1648 gtk_entry_set_max_length (entry, g_value_get_int (value));
1651 case PROP_VISIBILITY:
1652 gtk_entry_set_visibility (entry, g_value_get_boolean (value));
1655 case PROP_HAS_FRAME:
1656 gtk_entry_set_has_frame (entry, g_value_get_boolean (value));
1659 case PROP_INNER_BORDER:
1660 gtk_entry_set_inner_border (entry, g_value_get_boxed (value));
1663 case PROP_INVISIBLE_CHAR:
1664 gtk_entry_set_invisible_char (entry, g_value_get_uint (value));
1667 case PROP_ACTIVATES_DEFAULT:
1668 gtk_entry_set_activates_default (entry, g_value_get_boolean (value));
1671 case PROP_WIDTH_CHARS:
1672 gtk_entry_set_width_chars (entry, g_value_get_int (value));
1676 gtk_entry_set_text (entry, g_value_get_string (value));
1680 gtk_entry_set_alignment (entry, g_value_get_float (value));
1683 case PROP_TRUNCATE_MULTILINE:
1684 entry->truncate_multiline = g_value_get_boolean (value);
1687 case PROP_SHADOW_TYPE:
1688 priv->shadow_type = g_value_get_enum (value);
1691 case PROP_OVERWRITE_MODE:
1692 gtk_entry_set_overwrite_mode (entry, g_value_get_boolean (value));
1695 case PROP_INVISIBLE_CHAR_SET:
1696 if (g_value_get_boolean (value))
1697 priv->invisible_char_set = TRUE;
1699 gtk_entry_unset_invisible_char (entry);
1702 case PROP_CAPS_LOCK_WARNING:
1703 priv->caps_lock_warning = g_value_get_boolean (value);
1706 case PROP_PROGRESS_FRACTION:
1707 gtk_entry_set_progress_fraction (entry, g_value_get_double (value));
1710 case PROP_PROGRESS_PULSE_STEP:
1711 gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value));
1714 case PROP_PIXBUF_PRIMARY:
1715 gtk_entry_set_icon_from_pixbuf (entry,
1716 GTK_ENTRY_ICON_PRIMARY,
1717 g_value_get_object (value));
1720 case PROP_PIXBUF_SECONDARY:
1721 gtk_entry_set_icon_from_pixbuf (entry,
1722 GTK_ENTRY_ICON_SECONDARY,
1723 g_value_get_object (value));
1726 case PROP_STOCK_PRIMARY:
1727 gtk_entry_set_icon_from_stock (entry,
1728 GTK_ENTRY_ICON_PRIMARY,
1729 g_value_get_string (value));
1732 case PROP_STOCK_SECONDARY:
1733 gtk_entry_set_icon_from_stock (entry,
1734 GTK_ENTRY_ICON_SECONDARY,
1735 g_value_get_string (value));
1738 case PROP_ICON_NAME_PRIMARY:
1739 gtk_entry_set_icon_from_icon_name (entry,
1740 GTK_ENTRY_ICON_PRIMARY,
1741 g_value_get_string (value));
1744 case PROP_ICON_NAME_SECONDARY:
1745 gtk_entry_set_icon_from_icon_name (entry,
1746 GTK_ENTRY_ICON_SECONDARY,
1747 g_value_get_string (value));
1750 case PROP_GICON_PRIMARY:
1751 gtk_entry_set_icon_from_gicon (entry,
1752 GTK_ENTRY_ICON_PRIMARY,
1753 g_value_get_object (value));
1756 case PROP_GICON_SECONDARY:
1757 gtk_entry_set_icon_from_gicon (entry,
1758 GTK_ENTRY_ICON_SECONDARY,
1759 g_value_get_object (value));
1762 case PROP_ACTIVATABLE_PRIMARY:
1763 gtk_entry_set_icon_activatable (entry,
1764 GTK_ENTRY_ICON_PRIMARY,
1765 g_value_get_boolean (value));
1768 case PROP_ACTIVATABLE_SECONDARY:
1769 gtk_entry_set_icon_activatable (entry,
1770 GTK_ENTRY_ICON_SECONDARY,
1771 g_value_get_boolean (value));
1774 case PROP_SENSITIVE_PRIMARY:
1775 gtk_entry_set_icon_sensitive (entry,
1776 GTK_ENTRY_ICON_PRIMARY,
1777 g_value_get_boolean (value));
1780 case PROP_SENSITIVE_SECONDARY:
1781 gtk_entry_set_icon_sensitive (entry,
1782 GTK_ENTRY_ICON_SECONDARY,
1783 g_value_get_boolean (value));
1786 case PROP_SCROLL_OFFSET:
1787 case PROP_CURSOR_POSITION:
1789 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1795 gtk_entry_get_property (GObject *object,
1800 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
1801 GtkEntry *entry = GTK_ENTRY (object);
1805 case PROP_CURSOR_POSITION:
1806 g_value_set_int (value, entry->current_pos);
1809 case PROP_SELECTION_BOUND:
1810 g_value_set_int (value, entry->selection_bound);
1814 g_value_set_boolean (value, entry->editable);
1817 case PROP_MAX_LENGTH:
1818 g_value_set_int (value, entry->text_max_length);
1821 case PROP_VISIBILITY:
1822 g_value_set_boolean (value, entry->visible);
1825 case PROP_HAS_FRAME:
1826 g_value_set_boolean (value, entry->has_frame);
1829 case PROP_INNER_BORDER:
1830 g_value_set_boxed (value, gtk_entry_get_inner_border (entry));
1833 case PROP_INVISIBLE_CHAR:
1834 g_value_set_uint (value, entry->invisible_char);
1837 case PROP_ACTIVATES_DEFAULT:
1838 g_value_set_boolean (value, entry->activates_default);
1841 case PROP_WIDTH_CHARS:
1842 g_value_set_int (value, entry->width_chars);
1845 case PROP_SCROLL_OFFSET:
1846 g_value_set_int (value, entry->scroll_offset);
1850 g_value_set_string (value, gtk_entry_get_text (entry));
1854 g_value_set_float (value, gtk_entry_get_alignment (entry));
1857 case PROP_TRUNCATE_MULTILINE:
1858 g_value_set_boolean (value, entry->truncate_multiline);
1861 case PROP_SHADOW_TYPE:
1862 g_value_set_enum (value, priv->shadow_type);
1865 case PROP_OVERWRITE_MODE:
1866 g_value_set_boolean (value, entry->overwrite_mode);
1869 case PROP_TEXT_LENGTH:
1870 g_value_set_uint (value, entry->text_length);
1873 case PROP_INVISIBLE_CHAR_SET:
1874 g_value_set_boolean (value, priv->invisible_char_set);
1877 case PROP_CAPS_LOCK_WARNING:
1878 g_value_set_boolean (value, priv->caps_lock_warning);
1881 case PROP_PROGRESS_FRACTION:
1882 g_value_set_double (value, priv->progress_fraction);
1885 case PROP_PROGRESS_PULSE_STEP:
1886 g_value_set_double (value, priv->progress_pulse_fraction);
1889 case PROP_PIXBUF_PRIMARY:
1890 g_value_set_object (value,
1891 gtk_entry_get_pixbuf (entry,
1892 GTK_ENTRY_ICON_PRIMARY));
1895 case PROP_PIXBUF_SECONDARY:
1896 g_value_set_object (value,
1897 gtk_entry_get_pixbuf (entry,
1898 GTK_ENTRY_ICON_SECONDARY));
1901 case PROP_STOCK_PRIMARY:
1902 g_value_set_string (value,
1903 gtk_entry_get_stock (entry,
1904 GTK_ENTRY_ICON_PRIMARY));
1907 case PROP_STOCK_SECONDARY:
1908 g_value_set_string (value,
1909 gtk_entry_get_stock (entry,
1910 GTK_ENTRY_ICON_SECONDARY));
1913 case PROP_ICON_NAME_PRIMARY:
1914 g_value_set_string (value,
1915 gtk_entry_get_icon_name (entry,
1916 GTK_ENTRY_ICON_PRIMARY));
1919 case PROP_ICON_NAME_SECONDARY:
1920 g_value_set_string (value,
1921 gtk_entry_get_icon_name (entry,
1922 GTK_ENTRY_ICON_SECONDARY));
1925 case PROP_GICON_PRIMARY:
1926 g_value_set_object (value,
1927 gtk_entry_get_gicon (entry,
1928 GTK_ENTRY_ICON_PRIMARY));
1931 case PROP_GICON_SECONDARY:
1932 g_value_set_object (value,
1933 gtk_entry_get_gicon (entry,
1934 GTK_ENTRY_ICON_SECONDARY));
1937 case PROP_STORAGE_TYPE_PRIMARY:
1938 g_value_set_enum (value,
1939 gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_PRIMARY));
1942 case PROP_STORAGE_TYPE_SECONDARY:
1943 g_value_set_enum (value,
1944 gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_SECONDARY));
1947 case PROP_ACTIVATABLE_PRIMARY:
1948 g_value_set_boolean (value,
1949 gtk_entry_get_icon_activatable (entry, GTK_ENTRY_ICON_PRIMARY));
1952 case PROP_ACTIVATABLE_SECONDARY:
1953 g_value_set_boolean (value,
1954 gtk_entry_get_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY));
1957 case PROP_SENSITIVE_PRIMARY:
1958 g_value_set_boolean (value,
1959 gtk_entry_get_icon_sensitive (entry, GTK_ENTRY_ICON_PRIMARY));
1962 case PROP_SENSITIVE_SECONDARY:
1963 g_value_set_boolean (value,
1964 gtk_entry_get_icon_sensitive (entry, GTK_ENTRY_ICON_SECONDARY));
1968 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1974 find_invisible_char (GtkWidget *widget)
1976 PangoLayout *layout;
1977 PangoAttrList *attr_list;
1979 gunichar invisible_chars [] = {
1980 0x25cf, /* BLACK CIRCLE */
1981 0x2022, /* BULLET */
1982 0x2731, /* HEAVY ASTERISK */
1983 0x273a /* SIXTEEN POINTED ASTERISK */
1986 layout = gtk_widget_create_pango_layout (widget, NULL);
1988 attr_list = pango_attr_list_new ();
1989 pango_attr_list_insert (attr_list, pango_attr_fallback_new (FALSE));
1991 pango_layout_set_attributes (layout, attr_list);
1992 pango_attr_list_unref (attr_list);
1994 for (i = 0; i < G_N_ELEMENTS (invisible_chars); i++)
1996 gchar text[7] = { 0, };
1999 len = g_unichar_to_utf8 (invisible_chars[i], text);
2000 pango_layout_set_text (layout, text, len);
2002 count = pango_layout_get_unknown_glyphs_count (layout);
2006 g_object_unref (layout);
2007 return invisible_chars[i];
2011 g_object_unref (layout);
2016 gtk_entry_init (GtkEntry *entry)
2018 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2020 GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
2022 entry->text_size = MIN_SIZE;
2023 entry->text = g_malloc (entry->text_size);
2024 entry->text[0] = '\0';
2026 entry->editable = TRUE;
2027 entry->visible = TRUE;
2028 entry->invisible_char = find_invisible_char (GTK_WIDGET (entry));
2029 entry->dnd_position = -1;
2030 entry->width_chars = -1;
2031 entry->is_cell_renderer = FALSE;
2032 entry->editing_canceled = FALSE;
2033 entry->has_frame = TRUE;
2034 entry->truncate_multiline = FALSE;
2035 priv->shadow_type = GTK_SHADOW_IN;
2037 priv->caps_lock_warning = TRUE;
2038 priv->caps_lock_warning_shown = FALSE;
2039 priv->progress_fraction = 0.0;
2040 priv->progress_pulse_fraction = 0.1;
2042 gtk_drag_dest_set (GTK_WIDGET (entry),
2043 GTK_DEST_DEFAULT_HIGHLIGHT,
2045 GDK_ACTION_COPY | GDK_ACTION_MOVE);
2046 gtk_drag_dest_add_text_targets (GTK_WIDGET (entry));
2048 /* This object is completely private. No external entity can gain a reference
2049 * to it; so we create it here and destroy it in finalize().
2051 entry->im_context = gtk_im_multicontext_new ();
2053 g_signal_connect (entry->im_context, "commit",
2054 G_CALLBACK (gtk_entry_commit_cb), entry);
2055 g_signal_connect (entry->im_context, "preedit-changed",
2056 G_CALLBACK (gtk_entry_preedit_changed_cb), entry);
2057 g_signal_connect (entry->im_context, "retrieve-surrounding",
2058 G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry);
2059 g_signal_connect (entry->im_context, "delete-surrounding",
2060 G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
2064 get_icon_width (GtkEntry *entry,
2065 GtkEntryIconPosition icon_pos)
2067 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2068 EntryIconInfo *icon_info = priv->icons[icon_pos];
2070 GtkSettings *settings;
2071 gint menu_icon_width;
2073 if (!icon_info || icon_info->pixbuf == NULL)
2076 screen = gtk_widget_get_screen (GTK_WIDGET (entry));
2077 settings = gtk_settings_get_for_screen (screen);
2079 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
2080 &menu_icon_width, NULL);
2082 return MAX (gdk_pixbuf_get_width (icon_info->pixbuf), menu_icon_width);
2086 get_icon_allocations (GtkEntry *entry,
2087 GtkAllocation *primary,
2088 GtkAllocation *secondary)
2091 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2092 gint x, y, width, height;
2094 gtk_entry_get_text_area_size (entry, &x, &y, &width, &height);
2097 primary->height = height;
2098 primary->width = get_icon_width (entry, GTK_ENTRY_ICON_PRIMARY);
2099 if (primary->width > 0)
2100 primary->width += 2 * priv->icon_margin;
2103 secondary->height = height;
2104 secondary->width = get_icon_width (entry, GTK_ENTRY_ICON_SECONDARY);
2105 if (secondary->width > 0)
2106 secondary->width += 2 * priv->icon_margin;
2108 if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
2110 primary->x = x + width - primary->width;
2116 secondary->x = x + width - secondary->width;
2122 begin_change (GtkEntry *entry)
2124 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2126 priv->change_count++;
2130 end_change (GtkEntry *entry)
2132 GtkEditable *editable = GTK_EDITABLE (entry);
2133 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2135 g_return_if_fail (priv->change_count > 0);
2137 priv->change_count--;
2139 if (priv->change_count == 0)
2141 if (priv->real_changed)
2143 g_signal_emit_by_name (editable, "changed");
2144 priv->real_changed = FALSE;
2150 emit_changed (GtkEntry *entry)
2152 GtkEditable *editable = GTK_EDITABLE (entry);
2153 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2155 if (priv->change_count == 0)
2156 g_signal_emit_by_name (editable, "changed");
2158 priv->real_changed = TRUE;
2162 * Overwrite a memory that might contain sensitive information.
2165 trash_area (gchar *area, gsize len)
2167 volatile gchar *varea = (volatile gchar *)area;
2173 gtk_entry_destroy (GtkObject *object)
2175 GtkEntry *entry = GTK_ENTRY (object);
2178 entry->current_pos = entry->selection_bound = entry->text_length = 0;
2179 _gtk_entry_reset_im_context (entry);
2180 gtk_entry_reset_layout (entry);
2182 if (entry->blink_timeout)
2184 g_source_remove (entry->blink_timeout);
2185 entry->blink_timeout = 0;
2188 if (entry->recompute_idle)
2190 g_source_remove (entry->recompute_idle);
2191 entry->recompute_idle = 0;
2194 if (!entry->visible)
2196 /* We want to trash the text here because the entry might be leaked. */
2197 trash_area (entry->text, strlen (entry->text));
2200 GTK_OBJECT_CLASS (gtk_entry_parent_class)->destroy (object);
2204 gtk_entry_dispose (GObject *object)
2206 GtkEntry *entry = GTK_ENTRY (object);
2208 gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
2209 gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
2210 gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
2211 gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
2213 G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object);
2217 gtk_entry_finalize (GObject *object)
2219 GtkEntry *entry = GTK_ENTRY (object);
2220 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2221 EntryIconInfo *icon_info = NULL;
2224 for (i = 0; i < MAX_ICONS; i++)
2226 if ((icon_info = priv->icons[i]) != NULL)
2228 if (icon_info->target_list != NULL)
2230 gtk_target_list_unref (icon_info->target_list);
2231 icon_info->target_list = NULL;
2234 g_slice_free (EntryIconInfo, icon_info);
2235 priv->icons[i] = NULL;
2239 gtk_entry_set_completion (entry, NULL);
2241 if (entry->cached_layout)
2242 g_object_unref (entry->cached_layout);
2244 g_object_unref (entry->im_context);
2246 if (entry->blink_timeout)
2247 g_source_remove (entry->blink_timeout);
2249 if (entry->recompute_idle)
2250 g_source_remove (entry->recompute_idle);
2252 entry->text_size = 0;
2256 if (!entry->visible)
2257 trash_area (entry->text, strlen (entry->text));
2258 g_free (entry->text);
2262 G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
2266 update_cursors (GtkWidget *widget)
2268 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2269 EntryIconInfo *icon_info = NULL;
2270 GdkDisplay *display;
2274 for (i = 0; i < MAX_ICONS; i++)
2276 if ((icon_info = priv->icons[i]) != NULL)
2278 if (icon_info->pixbuf != NULL)
2279 gdk_window_show (icon_info->window);
2281 /* The icon windows are not children of the visible entry window,
2282 * thus we can't just inherit the xterm cursor. Slight complication
2283 * here is that for the entry, insensitive => arrow cursor, but for
2284 * an icon in a sensitive entry, insensitive => xterm cursor.
2286 if (GTK_WIDGET_IS_SENSITIVE (widget) &&
2287 (icon_info->insensitive ||
2288 (icon_info->nonactivatable && icon_info->target_list == NULL)))
2290 display = gtk_widget_get_display (widget);
2291 cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
2292 gdk_window_set_cursor (icon_info->window, cursor);
2293 gdk_cursor_unref (cursor);
2297 gdk_window_set_cursor (icon_info->window, NULL);
2304 realize_icon_info (GtkWidget *widget,
2305 GtkEntryIconPosition icon_pos)
2307 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2308 EntryIconInfo *icon_info = priv->icons[icon_pos];
2309 GdkWindowAttr attributes;
2310 gint attributes_mask;
2312 g_return_if_fail (icon_info != NULL);
2316 attributes.width = 1;
2317 attributes.height = 1;
2318 attributes.window_type = GDK_WINDOW_CHILD;
2319 attributes.wclass = GDK_INPUT_OUTPUT;
2320 attributes.visual = gtk_widget_get_visual (widget);
2321 attributes.colormap = gtk_widget_get_colormap (widget);
2322 attributes.event_mask = gtk_widget_get_events (widget);
2323 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2324 GDK_BUTTON_PRESS_MASK |
2325 GDK_BUTTON_RELEASE_MASK |
2326 GDK_BUTTON1_MOTION_MASK |
2327 GDK_BUTTON3_MOTION_MASK |
2328 GDK_POINTER_MOTION_HINT_MASK |
2329 GDK_POINTER_MOTION_MASK |
2330 GDK_ENTER_NOTIFY_MASK |
2331 GDK_LEAVE_NOTIFY_MASK);
2332 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2334 icon_info->window = gdk_window_new (widget->window,
2337 gdk_window_set_user_data (icon_info->window, widget);
2338 gdk_window_set_background (icon_info->window,
2339 &widget->style->base[GTK_WIDGET_STATE (widget)]);
2341 gtk_widget_queue_resize (widget);
2344 static EntryIconInfo*
2345 construct_icon_info (GtkWidget *widget,
2346 GtkEntryIconPosition icon_pos)
2348 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2349 EntryIconInfo *icon_info;
2351 g_return_val_if_fail (priv->icons[icon_pos] == NULL, NULL);
2353 icon_info = g_slice_new0 (EntryIconInfo);
2354 priv->icons[icon_pos] = icon_info;
2356 if (GTK_WIDGET_REALIZED (widget))
2357 realize_icon_info (widget, icon_pos);
2359 if (GTK_WIDGET_MAPPED (widget))
2360 gdk_window_show (icon_info->window);
2366 gtk_entry_map (GtkWidget *widget)
2368 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2369 EntryIconInfo *icon_info = NULL;
2372 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
2374 GTK_WIDGET_CLASS (gtk_entry_parent_class)->map (widget);
2376 for (i = 0; i < MAX_ICONS; i++)
2378 if ((icon_info = priv->icons[i]) != NULL)
2380 if (icon_info->pixbuf != NULL && icon_info->window != NULL)
2381 gdk_window_show (icon_info->window);
2385 update_cursors (widget);
2390 gtk_entry_unmap (GtkWidget *widget)
2392 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2393 EntryIconInfo *icon_info = NULL;
2396 if (GTK_WIDGET_MAPPED (widget))
2398 for (i = 0; i < MAX_ICONS; i++)
2400 if ((icon_info = priv->icons[i]) != NULL)
2402 if (icon_info->pixbuf != NULL && icon_info->window != NULL)
2403 gdk_window_hide (icon_info->window);
2407 GTK_WIDGET_CLASS (gtk_entry_parent_class)->unmap (widget);
2412 gtk_entry_realize (GtkWidget *widget)
2415 GtkEntryPrivate *priv;
2416 EntryIconInfo *icon_info;
2417 GdkWindowAttr attributes;
2418 gint attributes_mask;
2421 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2422 entry = GTK_ENTRY (widget);
2423 priv = GTK_ENTRY_GET_PRIVATE (entry);
2425 attributes.window_type = GDK_WINDOW_CHILD;
2427 get_widget_window_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
2429 attributes.wclass = GDK_INPUT_OUTPUT;
2430 attributes.visual = gtk_widget_get_visual (widget);
2431 attributes.colormap = gtk_widget_get_colormap (widget);
2432 attributes.event_mask = gtk_widget_get_events (widget);
2433 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2434 GDK_BUTTON_PRESS_MASK |
2435 GDK_BUTTON_RELEASE_MASK |
2436 GDK_BUTTON1_MOTION_MASK |
2437 GDK_BUTTON3_MOTION_MASK |
2438 GDK_POINTER_MOTION_HINT_MASK |
2439 GDK_POINTER_MOTION_MASK |
2440 GDK_ENTER_NOTIFY_MASK |
2441 GDK_LEAVE_NOTIFY_MASK);
2442 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2444 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2445 gdk_window_set_user_data (widget->window, entry);
2447 gtk_entry_get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
2449 if (GTK_WIDGET_IS_SENSITIVE (widget))
2451 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
2452 attributes_mask |= GDK_WA_CURSOR;
2455 entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
2457 gdk_window_set_user_data (entry->text_area, entry);
2459 if (attributes_mask & GDK_WA_CURSOR)
2460 gdk_cursor_unref (attributes.cursor);
2462 widget->style = gtk_style_attach (widget->style, widget->window);
2464 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2465 gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2467 gdk_window_show (entry->text_area);
2469 gtk_im_context_set_client_window (entry->im_context, entry->text_area);
2471 gtk_entry_adjust_scroll (entry);
2472 gtk_entry_update_primary_selection (entry);
2475 /* If the icon positions are already setup, create their windows.
2476 * Otherwise if they don't exist yet, then construct_icon_info()
2477 * will create the windows once the widget is already realized.
2479 for (i = 0; i < MAX_ICONS; i++)
2481 if ((icon_info = priv->icons[i]) != NULL)
2483 if (icon_info->window == NULL)
2484 realize_icon_info (widget, i);
2490 gtk_entry_unrealize (GtkWidget *widget)
2492 GtkEntry *entry = GTK_ENTRY (widget);
2493 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2494 GtkClipboard *clipboard;
2495 EntryIconInfo *icon_info;
2498 gtk_entry_reset_layout (entry);
2500 gtk_im_context_set_client_window (entry->im_context, NULL);
2502 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY);
2503 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
2504 gtk_clipboard_clear (clipboard);
2506 if (entry->text_area)
2508 gdk_window_set_user_data (entry->text_area, NULL);
2509 gdk_window_destroy (entry->text_area);
2510 entry->text_area = NULL;
2513 if (entry->popup_menu)
2515 gtk_widget_destroy (entry->popup_menu);
2516 entry->popup_menu = NULL;
2519 GTK_WIDGET_CLASS (gtk_entry_parent_class)->unrealize (widget);
2521 for (i = 0; i < MAX_ICONS; i++)
2523 if ((icon_info = priv->icons[i]) != NULL)
2525 if (icon_info->window != NULL)
2527 gdk_window_destroy (icon_info->window);
2528 icon_info->window = NULL;
2535 _gtk_entry_get_borders (GtkEntry *entry,
2539 GtkWidget *widget = GTK_WIDGET (entry);
2540 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2542 if (entry->has_frame)
2544 *xborder = widget->style->xthickness;
2545 *yborder = widget->style->ythickness;
2553 if (!priv->interior_focus)
2555 *xborder += priv->focus_width;
2556 *yborder += priv->focus_width;
2561 gtk_entry_size_request (GtkWidget *widget,
2562 GtkRequisition *requisition)
2564 GtkEntry *entry = GTK_ENTRY (widget);
2565 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2566 PangoFontMetrics *metrics;
2567 gint xborder, yborder;
2568 GtkBorder inner_border;
2569 PangoContext *context;
2570 int icon_widths = 0;
2573 gtk_widget_ensure_style (widget);
2574 context = gtk_widget_get_pango_context (widget);
2575 metrics = pango_context_get_metrics (context,
2576 widget->style->font_desc,
2577 pango_context_get_language (context));
2579 entry->ascent = pango_font_metrics_get_ascent (metrics);
2580 entry->descent = pango_font_metrics_get_descent (metrics);
2582 _gtk_entry_get_borders (entry, &xborder, &yborder);
2583 _gtk_entry_effective_inner_border (entry, &inner_border);
2585 if (entry->width_chars < 0)
2586 requisition->width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right;
2589 gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
2590 gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2591 gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
2593 requisition->width = char_pixels * entry->width_chars + xborder * 2 + inner_border.left + inner_border.right;
2596 requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2 + inner_border.top + inner_border.bottom;
2598 for (i = 0; i < MAX_ICONS; i++)
2600 icon_width = get_icon_width (entry, i);
2602 icon_widths += icon_width + 2 * priv->icon_margin;
2605 if (icon_widths > requisition->width)
2606 requisition->width += icon_widths;
2608 pango_font_metrics_unref (metrics);
2612 place_windows (GtkEntry *entry)
2615 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2616 gint x, y, width, height;
2617 GtkAllocation primary;
2618 GtkAllocation secondary;
2619 EntryIconInfo *icon_info = NULL;
2621 gtk_entry_get_text_area_size (entry, &x, &y, &width, &height);
2623 get_icon_allocations (entry, &primary, &secondary);
2625 if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
2626 x += secondary.width;
2629 width -= primary.width + secondary.width;
2631 if ((icon_info = priv->icons[GTK_ENTRY_ICON_PRIMARY]) != NULL)
2632 gdk_window_move_resize (icon_info->window,
2633 primary.x, primary.y,
2634 primary.width, primary.height);
2636 if ((icon_info = priv->icons[GTK_ENTRY_ICON_SECONDARY]) != NULL)
2637 gdk_window_move_resize (icon_info->window,
2638 secondary.x, secondary.y,
2639 secondary.width, secondary.height);
2641 gdk_window_move_resize (GTK_ENTRY (entry)->text_area, x, y, width, height);
2645 gtk_entry_get_text_area_size (GtkEntry *entry,
2651 GtkWidget *widget = GTK_WIDGET (entry);
2652 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2654 gint xborder, yborder;
2655 GtkRequisition requisition;
2657 gtk_widget_get_child_requisition (widget, &requisition);
2658 _gtk_entry_get_borders (entry, &xborder, &yborder);
2660 if (GTK_WIDGET_REALIZED (widget))
2661 gdk_drawable_get_size (widget->window, NULL, &frame_height);
2663 frame_height = requisition.height;
2665 if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2666 frame_height -= 2 * priv->focus_width;
2672 *y = frame_height / 2 - (requisition.height - yborder * 2) / 2;
2675 *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
2678 *height = requisition.height - yborder * 2;
2682 get_widget_window_size (GtkEntry *entry,
2688 GtkRequisition requisition;
2689 GtkWidget *widget = GTK_WIDGET (entry);
2691 gtk_widget_get_child_requisition (widget, &requisition);
2694 *x = widget->allocation.x;
2698 if (entry->is_cell_renderer)
2699 *y = widget->allocation.y;
2701 *y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2;
2705 *width = widget->allocation.width;
2709 if (entry->is_cell_renderer)
2710 *height = widget->allocation.height;
2712 *height = requisition.height;
2717 _gtk_entry_effective_inner_border (GtkEntry *entry,
2720 GtkBorder *tmp_border;
2722 tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
2726 *border = *tmp_border;
2730 gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
2734 *border = *tmp_border;
2735 gtk_border_free (tmp_border);
2739 *border = default_inner_border;
2743 gtk_entry_size_allocate (GtkWidget *widget,
2744 GtkAllocation *allocation)
2746 GtkEntry *entry = GTK_ENTRY (widget);
2748 widget->allocation = *allocation;
2750 if (GTK_WIDGET_REALIZED (widget))
2752 /* We call gtk_widget_get_child_requisition, since we want (for
2753 * backwards compatibility reasons) the realization here to
2754 * be affected by the usize of the entry, if set
2756 gint x, y, width, height;
2757 GtkEntryCompletion* completion;
2759 get_widget_window_size (entry, &x, &y, &width, &height);
2760 gdk_window_move_resize (widget->window, x, y, width, height);
2762 place_windows (entry);
2763 gtk_entry_recompute (entry);
2765 completion = gtk_entry_get_completion (entry);
2766 if (completion && GTK_WIDGET_MAPPED (completion->priv->popup_window))
2767 _gtk_entry_completion_resize_popup (completion);
2771 /* Kudos to the gnome-panel guys. */
2773 colorshift_pixbuf (GdkPixbuf *dest,
2778 gint width, height, has_alpha, src_rowstride, dest_rowstride;
2779 guchar *target_pixels;
2780 guchar *original_pixels;
2786 has_alpha = gdk_pixbuf_get_has_alpha (src);
2787 width = gdk_pixbuf_get_width (src);
2788 height = gdk_pixbuf_get_height (src);
2789 src_rowstride = gdk_pixbuf_get_rowstride (src);
2790 dest_rowstride = gdk_pixbuf_get_rowstride (dest);
2791 original_pixels = gdk_pixbuf_get_pixels (src);
2792 target_pixels = gdk_pixbuf_get_pixels (dest);
2794 for (i = 0; i < height; i++)
2796 pix_dest = target_pixels + i * dest_rowstride;
2797 pix_src = original_pixels + i * src_rowstride;
2799 for (j = 0; j < width; j++)
2806 *(pix_dest++) = CLAMP (val, 0, 255);
2809 *(pix_dest++) = CLAMP (val, 0, 255);
2812 *(pix_dest++) = CLAMP (val, 0, 255);
2815 *(pix_dest++) = *(pix_src++);
2821 should_prelight (GtkEntry *entry,
2822 GtkEntryIconPosition icon_pos)
2824 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2825 EntryIconInfo *icon_info = priv->icons[icon_pos];
2831 if (icon_info->nonactivatable && icon_info->target_list == NULL)
2834 if (icon_info->pressed)
2837 gtk_widget_style_get (GTK_WIDGET (entry),
2838 "prelight", &prelight,
2845 draw_icon (GtkWidget *widget,
2846 GtkEntryIconPosition icon_pos)
2848 GtkEntry *entry = GTK_ENTRY (widget);
2849 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2850 EntryIconInfo *icon_info = priv->icons[icon_pos];
2852 gint x, y, width, height;
2857 gtk_entry_ensure_pixbuf (entry, icon_pos);
2859 if (icon_info->pixbuf == NULL)
2862 gdk_drawable_get_size (icon_info->window, &width, &height);
2864 /* size_allocate hasn't been called yet. These are the default values.
2866 if (width == 1 || height == 1)
2869 pixbuf = icon_info->pixbuf;
2870 g_object_ref (pixbuf);
2872 if (gdk_pixbuf_get_height (pixbuf) > height)
2874 GdkPixbuf *temp_pixbuf;
2877 scale = height - 2 * priv->icon_margin;
2878 temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf, scale, scale,
2879 GDK_INTERP_BILINEAR);
2880 g_object_unref (pixbuf);
2881 pixbuf = temp_pixbuf;
2884 x = (width - gdk_pixbuf_get_width (pixbuf)) / 2;
2885 y = (height - gdk_pixbuf_get_height (pixbuf)) / 2;
2887 if (!GTK_WIDGET_IS_SENSITIVE (widget) ||
2888 icon_info->insensitive)
2890 GdkPixbuf *temp_pixbuf;
2892 temp_pixbuf = gdk_pixbuf_copy (pixbuf);
2893 gdk_pixbuf_saturate_and_pixelate (pixbuf,
2897 g_object_unref (pixbuf);
2898 pixbuf = temp_pixbuf;
2900 else if (icon_info->prelight)
2902 GdkPixbuf *temp_pixbuf;
2904 temp_pixbuf = gdk_pixbuf_copy (pixbuf);
2905 colorshift_pixbuf (temp_pixbuf, pixbuf, 30);
2906 g_object_unref (pixbuf);
2907 pixbuf = temp_pixbuf;
2910 gdk_draw_pixbuf (icon_info->window, widget->style->black_gc, pixbuf,
2912 GDK_RGB_DITHER_NORMAL, 0, 0);
2914 g_object_unref (pixbuf);
2919 gtk_entry_draw_frame (GtkWidget *widget,
2922 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2923 gint x = 0, y = 0, width, height;
2924 gboolean state_hint;
2927 gdk_drawable_get_size (widget->window, &width, &height);
2929 /* Fix a problem with some themes which assume that entry->text_area's
2930 * width equals widget->window's width */
2931 if (GTK_IS_SPIN_BUTTON (widget))
2933 gint xborder, yborder;
2935 gtk_entry_get_text_area_size (GTK_ENTRY (widget), &x, NULL, &width, NULL);
2936 _gtk_entry_get_borders (GTK_ENTRY (widget), &xborder, &yborder);
2939 width += xborder * 2;
2942 if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2944 x += priv->focus_width;
2945 y += priv->focus_width;
2946 width -= 2 * priv->focus_width;
2947 height -= 2 * priv->focus_width;
2950 gtk_widget_style_get (widget, "state-hint", &state_hint, NULL);
2952 state = GTK_WIDGET_HAS_FOCUS (widget) ?
2953 GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget);
2955 state = GTK_STATE_NORMAL;
2957 gtk_paint_shadow (widget->style, widget->window,
2958 state, priv->shadow_type,
2959 area, widget, "entry", x, y, width, height);
2961 if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2963 x -= priv->focus_width;
2964 y -= priv->focus_width;
2965 width += 2 * priv->focus_width;
2966 height += 2 * priv->focus_width;
2968 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
2969 area, widget, "entry",
2970 0, 0, width, height);
2975 gtk_entry_draw_progress (GtkWidget *widget,
2976 GdkEventExpose *event)
2978 GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget);
2979 GtkEntry *entry = GTK_ENTRY (widget);
2981 if (private->progress_pulse_mode)
2983 gdouble value = private->progress_pulse_current;
2984 gint area_width, area_height;
2986 gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
2988 gtk_paint_box (widget->style, entry->text_area,
2989 GTK_STATE_SELECTED, GTK_SHADOW_OUT,
2990 &event->area, widget, "entry-progress",
2991 value * area_width, 0,
2992 private->progress_pulse_fraction * area_width, area_height);
2994 else if (private->progress_fraction > 0)
2996 gdouble value = private->progress_fraction;
2997 gint area_width, area_height;
2999 gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
3001 if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
3003 gtk_paint_box (widget->style, entry->text_area,
3004 GTK_STATE_SELECTED, GTK_SHADOW_OUT,
3005 &event->area, widget, "entry-progress",
3006 area_width - value * area_width, 0,
3007 value * area_width, area_height);
3011 gtk_paint_box (widget->style, entry->text_area,
3012 GTK_STATE_SELECTED, GTK_SHADOW_OUT,
3013 &event->area, widget, "entry-progress",
3015 value * area_width, area_height);
3021 gtk_entry_expose (GtkWidget *widget,
3022 GdkEventExpose *event)
3024 GtkEntry *entry = GTK_ENTRY (widget);
3025 gboolean state_hint;
3027 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3029 gtk_widget_style_get (widget, "state-hint", &state_hint, NULL);
3031 state = GTK_WIDGET_HAS_FOCUS (widget) ?
3032 GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget);
3034 state = GTK_WIDGET_STATE(widget);
3036 if (widget->window == event->window)
3038 gtk_entry_draw_frame (widget, &event->area);
3040 else if (entry->text_area == event->window)
3044 gdk_drawable_get_size (entry->text_area, &width, &height);
3046 gtk_paint_flat_box (widget->style, entry->text_area,
3047 state, GTK_SHADOW_NONE,
3048 &event->area, widget, "entry_bg",
3049 0, 0, width, height);
3051 gtk_entry_draw_progress (widget, event);
3053 if (entry->dnd_position != -1)
3054 gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
3056 gtk_entry_draw_text (GTK_ENTRY (widget));
3058 if ((entry->visible || entry->invisible_char != 0) &&
3059 GTK_WIDGET_HAS_FOCUS (widget) &&
3060 entry->selection_bound == entry->current_pos && entry->cursor_visible)
3061 gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
3067 for (i = 0; i < MAX_ICONS; i++)
3069 EntryIconInfo *icon_info = priv->icons[i];
3071 if (icon_info != NULL && event->window == icon_info->window)
3075 gdk_drawable_get_size (icon_info->window, &width, &height);
3077 gtk_paint_flat_box (widget->style, icon_info->window,
3078 GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
3079 NULL, widget, "entry_bg",
3080 0, 0, width, height);
3082 draw_icon (widget, i);
3093 gtk_entry_enter_notify (GtkWidget *widget,
3094 GdkEventCrossing *event)
3096 GtkEntry *entry = GTK_ENTRY (widget);
3097 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3100 for (i = 0; i < MAX_ICONS; i++)
3102 EntryIconInfo *icon_info = priv->icons[i];
3104 if (icon_info != NULL && event->window == icon_info->window)
3106 if (should_prelight (entry, i))
3108 icon_info->prelight = TRUE;
3109 gtk_widget_queue_draw (widget);
3120 gtk_entry_leave_notify (GtkWidget *widget,
3121 GdkEventCrossing *event)
3123 GtkEntry *entry = GTK_ENTRY (widget);
3124 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3127 for (i = 0; i < MAX_ICONS; i++)
3129 EntryIconInfo *icon_info = priv->icons[i];
3131 if (icon_info != NULL && event->window == icon_info->window)
3133 if (should_prelight (entry, i))
3135 icon_info->prelight = FALSE;
3136 gtk_widget_queue_draw (widget);
3147 gtk_entry_get_pixel_ranges (GtkEntry *entry,
3151 gint start_char, end_char;
3153 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char))
3155 PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
3156 PangoLayoutLine *line = pango_layout_get_lines_readonly (layout)->data;
3157 const char *text = pango_layout_get_text (layout);
3158 gint start_index = g_utf8_offset_to_pointer (text, start_char) - text;
3159 gint end_index = g_utf8_offset_to_pointer (text, end_char) - text;
3160 gint real_n_ranges, i;
3162 pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges);
3168 for (i = 0; i < real_n_ranges; ++i)
3170 r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
3171 r[2 * i] = r[2 * i] / PANGO_SCALE;
3176 *n_ranges = real_n_ranges;
3188 in_selection (GtkEntry *entry,
3193 gint retval = FALSE;
3195 gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
3197 for (i = 0; i < n_ranges; ++i)
3199 if (x >= ranges[2 * i] && x < ranges[2 * i] + ranges[2 * i + 1])
3211 gtk_entry_button_press (GtkWidget *widget,
3212 GdkEventButton *event)
3214 GtkEntry *entry = GTK_ENTRY (widget);
3215 GtkEditable *editable = GTK_EDITABLE (widget);
3216 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3217 EntryIconInfo *icon_info = NULL;
3219 gint sel_start, sel_end;
3222 for (i = 0; i < MAX_ICONS; i++)
3224 icon_info = priv->icons[i];
3226 if (!icon_info || icon_info->insensitive)
3229 if (event->window == icon_info->window)
3231 if (should_prelight (entry, i))
3233 icon_info->prelight = FALSE;
3234 gtk_widget_queue_draw (widget);
3237 priv->start_x = event->x;
3238 priv->start_y = event->y;
3239 icon_info->pressed = TRUE;
3241 if (!icon_info->nonactivatable)
3242 g_signal_emit (entry, signals[ICON_PRESS], 0, i, event);
3248 if (event->window != entry->text_area ||
3249 (entry->button && event->button != entry->button))
3252 gtk_entry_reset_blink_time (entry);
3254 entry->button = event->button;
3256 if (!GTK_WIDGET_HAS_FOCUS (widget))
3258 entry->in_click = TRUE;
3259 gtk_widget_grab_focus (widget);
3260 entry->in_click = FALSE;
3263 tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
3265 if (event->button == 1)
3267 gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
3269 entry->select_words = FALSE;
3270 entry->select_lines = FALSE;
3272 if (event->state & GDK_SHIFT_MASK)
3274 _gtk_entry_reset_im_context (entry);
3276 if (!have_selection) /* select from the current position to the clicked position */
3277 sel_start = sel_end = entry->current_pos;
3279 if (tmp_pos > sel_start && tmp_pos < sel_end)
3281 /* Truncate current selection, but keep it as big as possible */
3282 if (tmp_pos - sel_start > sel_end - tmp_pos)
3283 gtk_entry_set_positions (entry, sel_start, tmp_pos);
3285 gtk_entry_set_positions (entry, tmp_pos, sel_end);
3289 gboolean extend_to_left;
3292 /* Figure out what click selects and extend current selection */
3293 switch (event->type)
3295 case GDK_BUTTON_PRESS:
3296 gtk_entry_set_positions (entry, tmp_pos, tmp_pos);
3299 case GDK_2BUTTON_PRESS:
3300 entry->select_words = TRUE;
3301 gtk_entry_select_word (entry);
3304 case GDK_3BUTTON_PRESS:
3305 entry->select_lines = TRUE;
3306 gtk_entry_select_line (entry);
3313 start = MIN (entry->current_pos, entry->selection_bound);
3314 start = MIN (sel_start, start);
3316 end = MAX (entry->current_pos, entry->selection_bound);
3317 end = MAX (sel_end, end);
3319 if (tmp_pos == sel_start || tmp_pos == sel_end)
3320 extend_to_left = (tmp_pos == start);
3322 extend_to_left = (end == sel_end);
3325 gtk_entry_set_positions (entry, start, end);
3327 gtk_entry_set_positions (entry, end, start);
3330 else /* no shift key */
3331 switch (event->type)
3333 case GDK_BUTTON_PRESS:
3334 if (in_selection (entry, event->x + entry->scroll_offset))
3336 /* Click inside the selection - we'll either start a drag, or
3337 * clear the selection
3339 entry->in_drag = TRUE;
3340 entry->drag_start_x = event->x + entry->scroll_offset;
3341 entry->drag_start_y = event->y;
3344 gtk_editable_set_position (editable, tmp_pos);
3347 case GDK_2BUTTON_PRESS:
3348 /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
3349 * receiving a GDK_2BUTTON_PRESS so we need to reset
3350 * entry->in_drag which may have been set above
3352 entry->in_drag = FALSE;
3353 entry->select_words = TRUE;
3354 gtk_entry_select_word (entry);
3357 case GDK_3BUTTON_PRESS:
3358 /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
3359 * receiving a GDK_3BUTTON_PRESS so we need to reset
3360 * entry->in_drag which may have been set above
3362 entry->in_drag = FALSE;
3363 entry->select_lines = TRUE;
3364 gtk_entry_select_line (entry);
3373 else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
3375 if (entry->editable)
3377 priv->insert_pos = tmp_pos;
3378 gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
3383 gtk_widget_error_bell (widget);
3386 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
3388 gtk_entry_do_popup (entry, event);
3389 entry->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
3398 gtk_entry_button_release (GtkWidget *widget,
3399 GdkEventButton *event)
3401 GtkEntry *entry = GTK_ENTRY (widget);
3402 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
3403 EntryIconInfo *icon_info = NULL;
3406 for (i = 0; i < MAX_ICONS; i++)
3408 icon_info = priv->icons[i];
3410 if (!icon_info || icon_info->insensitive)
3413 if (event->window == icon_info->window)
3417 gdk_drawable_get_size (icon_info->window, &width, &height);
3419 icon_info->pressed = FALSE;
3421 if (should_prelight (entry, i) &&
3422 event->x >= 0 && event->y >= 0 &&
3423 event->x < width && event->y < height)
3425 icon_info->prelight = TRUE;
3426 gtk_widget_queue_draw (widget);
3429 if (!icon_info->nonactivatable)
3430 g_signal_emit (entry, signals[ICON_RELEASE], 0, i, event);
3436 if (event->window != entry->text_area || entry->button != event->button)
3441 gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
3443 gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
3450 gtk_entry_update_primary_selection (entry);
3456 _gtk_entry_get_selected_text (GtkEntry *entry)
3458 GtkEditable *editable = GTK_EDITABLE (entry);
3459 gint start_text, end_text;
3462 if (gtk_editable_get_selection_bounds (editable, &start_text, &end_text))
3463 text = gtk_editable_get_chars (editable, start_text, end_text);
3469 gtk_entry_motion_notify (GtkWidget *widget,
3470 GdkEventMotion *event)
3472 GtkEntry *entry = GTK_ENTRY (widget);
3473 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3474 EntryIconInfo *icon_info = NULL;
3475 GdkDragContext *context;
3479 for (i = 0; i < MAX_ICONS; i++)
3481 icon_info = priv->icons[i];
3483 if (!icon_info || icon_info->insensitive)
3486 if (event->window == icon_info->window)
3488 if (icon_info->pressed &&
3489 icon_info->target_list != NULL &&
3490 gtk_drag_check_threshold (widget,
3496 icon_info->in_drag = TRUE;
3497 icon_info->pressed = FALSE;
3498 context = gtk_drag_begin (widget,
3499 icon_info->target_list,
3509 if (entry->mouse_cursor_obscured)
3513 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
3514 gdk_window_set_cursor (entry->text_area, cursor);
3515 gdk_cursor_unref (cursor);
3516 entry->mouse_cursor_obscured = FALSE;
3519 if (event->window != entry->text_area || entry->button != 1)
3522 if (entry->select_lines)
3525 gdk_event_request_motions (event);
3529 if (entry->visible &&
3530 gtk_drag_check_threshold (widget,
3531 entry->drag_start_x, entry->drag_start_y,
3532 event->x + entry->scroll_offset, event->y))
3534 GdkDragContext *context;
3535 GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
3536 guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
3538 GdkPixmap *pixmap = NULL;
3540 gtk_target_list_add_text_targets (target_list, 0);
3542 text = _gtk_entry_get_selected_text (entry);
3543 pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
3545 context = gtk_drag_begin (widget, target_list, actions,
3546 entry->button, (GdkEvent *)event);
3549 gtk_drag_set_icon_pixmap (context,
3550 gdk_drawable_get_colormap (pixmap),
3555 gtk_drag_set_icon_default (context);
3558 g_object_unref (pixmap);
3561 entry->in_drag = FALSE;
3564 gtk_target_list_unref (target_list);
3570 gdk_drawable_get_size (entry->text_area, NULL, &height);
3574 else if (event->y >= height)
3575 tmp_pos = entry->text_length;
3577 tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
3579 if (entry->select_words)
3582 gint old_min, old_max;
3585 min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE);
3586 max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE);
3588 pos = entry->current_pos;
3589 bound = entry->selection_bound;
3591 old_min = MIN(entry->current_pos, entry->selection_bound);
3592 old_max = MAX(entry->current_pos, entry->selection_bound);
3599 else if (old_max < max)
3604 else if (pos == old_min)
3606 if (entry->current_pos != min)
3611 if (entry->current_pos != max)
3615 gtk_entry_set_positions (entry, pos, bound);
3618 gtk_entry_set_positions (entry, tmp_pos, -1);
3625 set_invisible_cursor (GdkWindow *window)
3627 GdkBitmap *empty_bitmap;
3630 char invisible_cursor_bits[] = { 0x0 };
3632 useless.red = useless.green = useless.blue = 0;
3635 empty_bitmap = gdk_bitmap_create_from_data (window,
3636 invisible_cursor_bits,
3639 cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
3644 gdk_window_set_cursor (window, cursor);
3646 gdk_cursor_unref (cursor);
3648 g_object_unref (empty_bitmap);
3652 gtk_entry_obscure_mouse_cursor (GtkEntry *entry)
3654 if (entry->mouse_cursor_obscured)
3657 set_invisible_cursor (entry->text_area);
3659 entry->mouse_cursor_obscured = TRUE;
3663 gtk_entry_key_press (GtkWidget *widget,
3666 GtkEntry *entry = GTK_ENTRY (widget);
3668 gtk_entry_reset_blink_time (entry);
3669 gtk_entry_pend_cursor_blink (entry);
3671 if (entry->editable)
3673 if (gtk_im_context_filter_keypress (entry->im_context, event))
3675 gtk_entry_obscure_mouse_cursor (entry);
3676 entry->need_im_reset = TRUE;
3681 if (event->keyval == GDK_Return ||
3682 event->keyval == GDK_KP_Enter ||
3683 event->keyval == GDK_ISO_Enter ||
3684 event->keyval == GDK_Escape)
3686 GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
3688 if (completion && completion->priv->completion_timeout)
3690 g_source_remove (completion->priv->completion_timeout);
3691 completion->priv->completion_timeout = 0;
3694 _gtk_entry_reset_im_context (entry);
3697 if (GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_press_event (widget, event))
3698 /* Activate key bindings
3702 if (!entry->editable && event->length)
3703 gtk_widget_error_bell (widget);
3709 gtk_entry_key_release (GtkWidget *widget,
3712 GtkEntry *entry = GTK_ENTRY (widget);
3714 if (entry->editable)
3716 if (gtk_im_context_filter_keypress (entry->im_context, event))
3718 entry->need_im_reset = TRUE;
3723 return GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_release_event (widget, event);
3727 gtk_entry_focus_in (GtkWidget *widget,
3728 GdkEventFocus *event)
3730 GtkEntry *entry = GTK_ENTRY (widget);
3733 gtk_widget_queue_draw (widget);
3735 keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
3737 if (entry->editable)
3739 entry->need_im_reset = TRUE;
3740 gtk_im_context_focus_in (entry->im_context);
3741 keymap_state_changed (keymap, entry);
3742 g_signal_connect (keymap, "state-changed",
3743 G_CALLBACK (keymap_state_changed), entry);
3746 g_signal_connect (keymap, "direction-changed",
3747 G_CALLBACK (keymap_direction_changed), entry);
3749 gtk_entry_reset_blink_time (entry);
3750 gtk_entry_check_cursor_blink (entry);
3756 gtk_entry_focus_out (GtkWidget *widget,
3757 GdkEventFocus *event)
3759 GtkEntry *entry = GTK_ENTRY (widget);
3760 GtkEntryCompletion *completion;
3763 gtk_widget_queue_draw (widget);
3765 keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
3767 if (entry->editable)
3769 entry->need_im_reset = TRUE;
3770 gtk_im_context_focus_out (entry->im_context);
3771 remove_capslock_feedback (entry);
3774 gtk_entry_check_cursor_blink (entry);
3776 g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
3777 g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry);
3779 completion = gtk_entry_get_completion (entry);
3781 _gtk_entry_completion_popdown (completion);
3787 gtk_entry_grab_focus (GtkWidget *widget)
3789 GtkEntry *entry = GTK_ENTRY (widget);
3790 gboolean select_on_focus;
3792 GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_focus (widget);
3794 if (entry->editable && !entry->in_click)
3796 g_object_get (gtk_widget_get_settings (widget),
3797 "gtk-entry-select-on-focus",
3801 if (select_on_focus)
3802 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
3807 gtk_entry_direction_changed (GtkWidget *widget,
3808 GtkTextDirection previous_dir)
3810 GtkEntry *entry = GTK_ENTRY (widget);
3812 gtk_entry_recompute (entry);
3814 GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir);
3818 gtk_entry_state_changed (GtkWidget *widget,
3819 GtkStateType previous_state)
3821 GtkEntry *entry = GTK_ENTRY (widget);
3822 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
3826 if (GTK_WIDGET_REALIZED (widget))
3828 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3829 gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3830 for (i = 0; i < MAX_ICONS; i++)
3832 EntryIconInfo *icon_info = priv->icons[i];
3833 if (icon_info && icon_info->window)
3834 gdk_window_set_background (icon_info->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3837 if (GTK_WIDGET_IS_SENSITIVE (widget))
3838 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
3842 gdk_window_set_cursor (entry->text_area, cursor);
3845 gdk_cursor_unref (cursor);
3847 entry->mouse_cursor_obscured = FALSE;
3849 update_cursors (widget);
3852 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3854 /* Clear any selection */
3855 gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
3858 gtk_widget_queue_draw (widget);
3862 gtk_entry_screen_changed (GtkWidget *widget,
3863 GdkScreen *old_screen)
3865 gtk_entry_recompute (GTK_ENTRY (widget));
3868 /* GtkEditable method implementations
3871 gtk_entry_insert_text (GtkEditable *editable,
3872 const gchar *new_text,
3873 gint new_text_length,
3876 GtkEntry *entry = GTK_ENTRY (editable);
3880 if (*position < 0 || *position > entry->text_length)
3881 *position = entry->text_length;
3883 g_object_ref (editable);
3885 if (new_text_length <= 63)
3888 text = g_new (gchar, new_text_length + 1);
3890 text[new_text_length] = '\0';
3891 strncpy (text, new_text, new_text_length);
3893 g_signal_emit_by_name (editable, "insert-text", text, new_text_length, position);
3895 if (!entry->visible)
3896 trash_area (text, new_text_length);
3898 if (new_text_length > 63)
3901 g_object_unref (editable);
3905 gtk_entry_delete_text (GtkEditable *editable,
3909 GtkEntry *entry = GTK_ENTRY (editable);
3911 if (end_pos < 0 || end_pos > entry->text_length)
3912 end_pos = entry->text_length;
3915 if (start_pos > end_pos)
3916 start_pos = end_pos;
3918 g_object_ref (editable);
3920 g_signal_emit_by_name (editable, "delete-text", start_pos, end_pos);
3922 g_object_unref (editable);
3926 gtk_entry_get_chars (GtkEditable *editable,
3930 GtkEntry *entry = GTK_ENTRY (editable);
3931 gint start_index, end_index;
3934 end_pos = entry->text_length;
3936 start_pos = MIN (entry->text_length, start_pos);
3937 end_pos = MIN (entry->text_length, end_pos);
3939 start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
3940 end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
3942 return g_strndup (entry->text + start_index, end_index - start_index);
3946 gtk_entry_real_set_position (GtkEditable *editable,
3949 GtkEntry *entry = GTK_ENTRY (editable);
3951 if (position < 0 || position > entry->text_length)
3952 position = entry->text_length;
3954 if (position != entry->current_pos ||
3955 position != entry->selection_bound)
3957 _gtk_entry_reset_im_context (entry);
3958 gtk_entry_set_positions (entry, position, position);
3963 gtk_entry_get_position (GtkEditable *editable)
3965 return GTK_ENTRY (editable)->current_pos;
3969 gtk_entry_set_selection_bounds (GtkEditable *editable,
3973 GtkEntry *entry = GTK_ENTRY (editable);
3976 start = entry->text_length;
3978 end = entry->text_length;
3980 _gtk_entry_reset_im_context (entry);
3982 gtk_entry_set_positions (entry,
3983 MIN (end, entry->text_length),
3984 MIN (start, entry->text_length));
3986 gtk_entry_update_primary_selection (entry);
3990 gtk_entry_get_selection_bounds (GtkEditable *editable,
3994 GtkEntry *entry = GTK_ENTRY (editable);
3996 *start = entry->selection_bound;
3997 *end = entry->current_pos;
3999 return (entry->selection_bound != entry->current_pos);
4003 icon_theme_changed (GtkEntry *entry)
4005 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
4008 for (i = 0; i < MAX_ICONS; i++)
4010 EntryIconInfo *icon_info = priv->icons[i];
4011 if (icon_info != NULL)
4013 if (icon_info->storage_type == GTK_IMAGE_ICON_NAME)
4014 gtk_entry_set_icon_from_icon_name (entry, i, icon_info->icon_name);
4015 else if (icon_info->storage_type == GTK_IMAGE_STOCK)
4016 gtk_entry_set_icon_from_stock (entry, i, icon_info->stock_id);
4017 else if (icon_info->storage_type == GTK_IMAGE_GICON)
4018 gtk_entry_set_icon_from_gicon (entry, i, icon_info->gicon);
4022 gtk_widget_queue_draw (GTK_WIDGET (entry));
4026 icon_margin_changed (GtkEntry *entry)
4028 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
4031 _gtk_entry_effective_inner_border (GTK_ENTRY (entry), &border);
4033 priv->icon_margin = border.left;
4037 gtk_entry_style_set (GtkWidget *widget,
4038 GtkStyle *previous_style)
4040 GtkEntry *entry = GTK_ENTRY (widget);
4041 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
4043 gboolean interior_focus;
4046 gtk_widget_style_get (widget,
4047 "focus-line-width", &focus_width,
4048 "interior-focus", &interior_focus,
4051 priv->focus_width = focus_width;
4052 priv->interior_focus = interior_focus;
4054 if (!priv->invisible_char_set)
4055 entry->invisible_char = find_invisible_char (GTK_WIDGET (entry));
4057 gtk_entry_recompute (entry);
4059 if (previous_style && GTK_WIDGET_REALIZED (widget))
4061 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
4062 gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
4063 for (i = 0; i < MAX_ICONS; i++)
4065 EntryIconInfo *icon_info = priv->icons[i];
4066 if (icon_info && icon_info->window)
4067 gdk_window_set_background (icon_info->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
4071 icon_theme_changed (entry);
4072 icon_margin_changed (entry);
4075 /* GtkCellEditable method implementations
4078 gtk_cell_editable_entry_activated (GtkEntry *entry, gpointer data)
4080 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
4081 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
4085 gtk_cell_editable_key_press_event (GtkEntry *entry,
4086 GdkEventKey *key_event,
4089 if (key_event->keyval == GDK_Escape)
4091 entry->editing_canceled = TRUE;
4092 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
4093 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
4098 /* override focus */
4099 if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down)
4101 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
4102 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
4111 gtk_entry_start_editing (GtkCellEditable *cell_editable,
4114 GTK_ENTRY (cell_editable)->is_cell_renderer = TRUE;
4116 g_signal_connect (cell_editable, "activate",
4117 G_CALLBACK (gtk_cell_editable_entry_activated), NULL);
4118 g_signal_connect (cell_editable, "key-press-event",
4119 G_CALLBACK (gtk_cell_editable_key_press_event), NULL);
4123 gtk_entry_password_hint_free (GtkEntryPasswordHint *password_hint)
4125 if (password_hint->password_hint_timeout_id)
4126 g_source_remove (password_hint->password_hint_timeout_id);
4128 g_slice_free (GtkEntryPasswordHint, password_hint);
4131 /* Default signal handlers
4134 gtk_entry_real_insert_text (GtkEditable *editable,
4135 const gchar *new_text,
4136 gint new_text_length,
4139 GtkEntry *entry = GTK_ENTRY (editable);
4143 if (new_text_length < 0)
4144 new_text_length = strlen (new_text);
4146 n_chars = g_utf8_strlen (new_text, new_text_length);
4147 if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
4149 gtk_widget_error_bell (GTK_WIDGET (entry));
4150 n_chars = entry->text_max_length - entry->text_length;
4151 new_text_length = g_utf8_offset_to_pointer (new_text, n_chars) - new_text;
4154 if (new_text_length + entry->n_bytes + 1 > entry->text_size)
4156 gsize prev_size = entry->text_size;
4158 while (new_text_length + entry->n_bytes + 1 > entry->text_size)
4160 if (entry->text_size == 0)
4161 entry->text_size = MIN_SIZE;
4164 if (2 * (guint)entry->text_size < MAX_SIZE &&
4165 2 * (guint)entry->text_size > entry->text_size)
4166 entry->text_size *= 2;
4169 entry->text_size = MAX_SIZE;
4170 if (new_text_length > (gint)entry->text_size - (gint)entry->n_bytes - 1)
4172 new_text_length = (gint)entry->text_size - (gint)entry->n_bytes - 1;
4173 new_text_length = g_utf8_find_prev_char (new_text, new_text + new_text_length + 1) - new_text;
4174 n_chars = g_utf8_strlen (new_text, new_text_length);
4182 entry->text = g_realloc (entry->text, entry->text_size);
4185 /* Same thing, just slower and without leaving stuff in memory. */
4186 gchar *et_new = g_malloc (entry->text_size);
4187 memcpy (et_new, entry->text, MIN (prev_size, entry->text_size));
4188 trash_area (entry->text, prev_size);
4189 g_free (entry->text);
4190 entry->text = et_new;
4194 index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
4196 g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
4197 memcpy (entry->text + index, new_text, new_text_length);
4199 entry->n_bytes += new_text_length;
4200 entry->text_length += n_chars;
4202 /* NUL terminate for safety and convenience */
4203 entry->text[entry->n_bytes] = '\0';
4205 if (entry->current_pos > *position)
4206 entry->current_pos += n_chars;
4208 if (entry->selection_bound > *position)
4209 entry->selection_bound += n_chars;
4211 if (n_chars == 1 && !entry->visible && (new_text_length < PASSWORD_HINT_MAX))
4213 guint password_hint_timeout;
4215 g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
4216 "gtk-entry-password-hint-timeout", &password_hint_timeout,
4219 if (password_hint_timeout > 0)
4221 GtkEntryPasswordHint *password_hint = g_object_get_qdata (G_OBJECT (entry),
4222 quark_password_hint);
4226 password_hint = g_slice_new0 (GtkEntryPasswordHint);
4227 g_object_set_qdata_full (G_OBJECT (entry), quark_password_hint,
4229 (GDestroyNotify) gtk_entry_password_hint_free);
4232 memset (&password_hint->password_hint, 0x0, PASSWORD_HINT_MAX);
4233 password_hint->password_hint_length = new_text_length;
4234 memcpy (&password_hint->password_hint, new_text, new_text_length);
4235 password_hint->password_hint_position = *position + n_chars;
4240 g_object_set_qdata (G_OBJECT (entry), quark_password_hint, NULL);
4243 *position += n_chars;
4245 gtk_entry_recompute (entry);
4247 emit_changed (entry);
4248 g_object_notify (G_OBJECT (editable), "text");
4249 g_object_notify (G_OBJECT (editable), "text-length");
4253 gtk_entry_real_delete_text (GtkEditable *editable,
4257 GtkEntry *entry = GTK_ENTRY (editable);
4261 if (end_pos < 0 || end_pos > entry->text_length)
4262 end_pos = entry->text_length;
4264 if (start_pos < end_pos)
4266 gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
4267 gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
4269 gint selection_bound;
4271 g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes + 1 - end_index);
4272 entry->text_length -= (end_pos - start_pos);
4273 entry->n_bytes -= (end_index - start_index);
4275 /* In password-mode, make sure we don't leave anything sensitive after
4276 * the terminating zero. Note, that the terminating zero already trashed
4279 if (!entry->visible)
4280 trash_area (entry->text + entry->n_bytes + 1, end_index - start_index - 1);
4282 current_pos = entry->current_pos;
4283 if (current_pos > start_pos)
4284 current_pos -= MIN (current_pos, end_pos) - start_pos;
4286 selection_bound = entry->selection_bound;
4287 if (selection_bound > start_pos)
4288 selection_bound -= MIN (selection_bound, end_pos) - start_pos;
4290 gtk_entry_set_positions (entry, current_pos, selection_bound);
4292 /* We might have deleted the selection
4294 gtk_entry_update_primary_selection (entry);
4296 gtk_entry_recompute (entry);
4298 emit_changed (entry);
4299 g_object_notify (G_OBJECT (editable), "text");
4300 g_object_notify (G_OBJECT (editable), "text-length");
4304 /* Compute the X position for an offset that corresponds to the "more important
4305 * cursor position for that offset. We use this when trying to guess to which
4306 * end of the selection we should go to when the user hits the left or
4310 get_better_cursor_x (GtkEntry *entry,
4313 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
4314 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
4315 gboolean split_cursor;
4317 PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
4318 const gchar *text = pango_layout_get_text (layout);
4319 gint index = g_utf8_offset_to_pointer (text, offset) - text;
4321 PangoRectangle strong_pos, weak_pos;
4323 g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
4324 "gtk-split-cursor", &split_cursor,
4327 pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
4330 return strong_pos.x / PANGO_SCALE;
4332 return (keymap_direction == entry->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE;
4336 gtk_entry_move_cursor (GtkEntry *entry,
4337 GtkMovementStep step,
4339 gboolean extend_selection)
4341 gint new_pos = entry->current_pos;
4343 _gtk_entry_reset_im_context (entry);
4345 if (entry->current_pos != entry->selection_bound && !extend_selection)
4347 /* If we have a current selection and aren't extending it, move to the
4348 * start/or end of the selection as appropriate
4352 case GTK_MOVEMENT_VISUAL_POSITIONS:
4354 gint current_x = get_better_cursor_x (entry, entry->current_pos);
4355 gint bound_x = get_better_cursor_x (entry, entry->selection_bound);
4358 new_pos = current_x < bound_x ? entry->current_pos : entry->selection_bound;
4360 new_pos = current_x > bound_x ? entry->current_pos : entry->selection_bound;
4363 case GTK_MOVEMENT_LOGICAL_POSITIONS:
4364 case GTK_MOVEMENT_WORDS:
4366 new_pos = MIN (entry->current_pos, entry->selection_bound);
4368 new_pos = MAX (entry->current_pos, entry->selection_bound);
4370 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4371 case GTK_MOVEMENT_PARAGRAPH_ENDS:
4372 case GTK_MOVEMENT_BUFFER_ENDS:
4373 new_pos = count < 0 ? 0 : entry->text_length;
4375 case GTK_MOVEMENT_DISPLAY_LINES:
4376 case GTK_MOVEMENT_PARAGRAPHS:
4377 case GTK_MOVEMENT_PAGES:
4378 case GTK_MOVEMENT_HORIZONTAL_PAGES:
4386 case GTK_MOVEMENT_LOGICAL_POSITIONS:
4387 new_pos = gtk_entry_move_logically (entry, new_pos, count);
4389 case GTK_MOVEMENT_VISUAL_POSITIONS:
4390 new_pos = gtk_entry_move_visually (entry, new_pos, count);
4391 if (entry->current_pos == new_pos)
4393 if (!extend_selection)
4395 if (!gtk_widget_keynav_failed (GTK_WIDGET (entry),
4397 GTK_DIR_RIGHT : GTK_DIR_LEFT))
4399 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
4402 gtk_widget_child_focus (toplevel,
4404 GTK_DIR_RIGHT : GTK_DIR_LEFT);
4409 gtk_widget_error_bell (GTK_WIDGET (entry));
4413 case GTK_MOVEMENT_WORDS:
4416 new_pos = gtk_entry_move_forward_word (entry, new_pos, FALSE);
4421 new_pos = gtk_entry_move_backward_word (entry, new_pos, FALSE);
4424 if (entry->current_pos == new_pos)
4425 gtk_widget_error_bell (GTK_WIDGET (entry));
4427 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4428 case GTK_MOVEMENT_PARAGRAPH_ENDS:
4429 case GTK_MOVEMENT_BUFFER_ENDS:
4430 new_pos = count < 0 ? 0 : entry->text_length;
4431 if (entry->current_pos == new_pos)
4432 gtk_widget_error_bell (GTK_WIDGET (entry));
4434 case GTK_MOVEMENT_DISPLAY_LINES:
4435 case GTK_MOVEMENT_PARAGRAPHS:
4436 case GTK_MOVEMENT_PAGES:
4437 case GTK_MOVEMENT_HORIZONTAL_PAGES:
4442 if (extend_selection)
4443 gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos);
4445 gtk_editable_set_position (GTK_EDITABLE (entry), new_pos);
4447 gtk_entry_pend_cursor_blink (entry);
4451 gtk_entry_insert_at_cursor (GtkEntry *entry,
4454 GtkEditable *editable = GTK_EDITABLE (entry);
4455 gint pos = entry->current_pos;
4457 if (entry->editable)
4459 _gtk_entry_reset_im_context (entry);
4461 gtk_editable_insert_text (editable, str, -1, &pos);
4462 gtk_editable_set_position (editable, pos);
4467 gtk_entry_delete_from_cursor (GtkEntry *entry,
4471 GtkEditable *editable = GTK_EDITABLE (entry);
4472 gint start_pos = entry->current_pos;
4473 gint end_pos = entry->current_pos;
4474 gint old_n_bytes = entry->n_bytes;
4476 _gtk_entry_reset_im_context (entry);
4478 if (!entry->editable)
4480 gtk_widget_error_bell (GTK_WIDGET (entry));
4484 if (entry->selection_bound != entry->current_pos)
4486 gtk_editable_delete_selection (editable);
4492 case GTK_DELETE_CHARS:
4493 end_pos = gtk_entry_move_logically (entry, entry->current_pos, count);
4494 gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos));
4496 case GTK_DELETE_WORDS:
4499 /* Move to end of current word, or if not on a word, end of previous word */
4500 end_pos = gtk_entry_move_backward_word (entry, end_pos, FALSE);
4501 end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
4505 /* Move to beginning of current word, or if not on a word, begining of next word */
4506 start_pos = gtk_entry_move_forward_word (entry, start_pos, FALSE);
4507 start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
4511 case GTK_DELETE_WORD_ENDS:
4514 start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
4519 end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
4522 gtk_editable_delete_text (editable, start_pos, end_pos);
4524 case GTK_DELETE_DISPLAY_LINE_ENDS:
4525 case GTK_DELETE_PARAGRAPH_ENDS:
4527 gtk_editable_delete_text (editable, 0, entry->current_pos);
4529 gtk_editable_delete_text (editable, entry->current_pos, -1);
4531 case GTK_DELETE_DISPLAY_LINES:
4532 case GTK_DELETE_PARAGRAPHS:
4533 gtk_editable_delete_text (editable, 0, -1);
4535 case GTK_DELETE_WHITESPACE:
4536 gtk_entry_delete_whitespace (entry);
4540 if (entry->n_bytes == old_n_bytes)
4541 gtk_widget_error_bell (GTK_WIDGET (entry));
4543 gtk_entry_pend_cursor_blink (entry);
4547 gtk_entry_backspace (GtkEntry *entry)
4549 GtkEditable *editable = GTK_EDITABLE (entry);
4552 _gtk_entry_reset_im_context (entry);
4554 if (!entry->editable || !entry->text)
4556 gtk_widget_error_bell (GTK_WIDGET (entry));
4560 if (entry->selection_bound != entry->current_pos)
4562 gtk_editable_delete_selection (editable);
4566 prev_pos = gtk_entry_move_logically (entry, entry->current_pos, -1);
4568 if (prev_pos < entry->current_pos)
4570 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4571 PangoLogAttr *log_attrs;
4574 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4576 if (entry->visible &&
4577 log_attrs[entry->current_pos].backspace_deletes_character)
4579 gchar *cluster_text;
4580 gchar *normalized_text;
4583 cluster_text = gtk_editable_get_chars (editable,
4585 entry->current_pos);
4586 normalized_text = g_utf8_normalize (cluster_text,
4587 strlen (cluster_text),
4589 len = g_utf8_strlen (normalized_text, -1);
4591 gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
4594 gint pos = entry->current_pos;
4596 gtk_editable_insert_text (editable, normalized_text,
4597 g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
4599 gtk_editable_set_position (editable, pos);
4602 g_free (normalized_text);
4603 g_free (cluster_text);
4607 gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
4614 gtk_widget_error_bell (GTK_WIDGET (entry));
4617 gtk_entry_pend_cursor_blink (entry);
4621 gtk_entry_copy_clipboard (GtkEntry *entry)
4623 GtkEditable *editable = GTK_EDITABLE (entry);
4627 if (gtk_editable_get_selection_bounds (editable, &start, &end))
4629 if (!entry->visible)
4631 gtk_widget_error_bell (GTK_WIDGET (entry));
4635 str = gtk_entry_get_public_chars (entry, start, end);
4636 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (entry),
4637 GDK_SELECTION_CLIPBOARD),
4644 gtk_entry_cut_clipboard (GtkEntry *entry)
4646 GtkEditable *editable = GTK_EDITABLE (entry);
4649 if (!entry->visible)
4651 gtk_widget_error_bell (GTK_WIDGET (entry));
4655 gtk_entry_copy_clipboard (entry);
4657 if (entry->editable)
4659 if (gtk_editable_get_selection_bounds (editable, &start, &end))
4660 gtk_editable_delete_text (editable, start, end);
4664 gtk_widget_error_bell (GTK_WIDGET (entry));
4669 gtk_entry_paste_clipboard (GtkEntry *entry)
4671 if (entry->editable)
4672 gtk_entry_paste (entry, GDK_NONE);
4674 gtk_widget_error_bell (GTK_WIDGET (entry));
4678 gtk_entry_delete_cb (GtkEntry *entry)
4680 GtkEditable *editable = GTK_EDITABLE (entry);
4683 if (entry->editable)
4685 if (gtk_editable_get_selection_bounds (editable, &start, &end))
4686 gtk_editable_delete_text (editable, start, end);
4691 gtk_entry_toggle_overwrite (GtkEntry *entry)
4693 entry->overwrite_mode = !entry->overwrite_mode;
4694 gtk_entry_pend_cursor_blink (entry);
4695 gtk_widget_queue_draw (GTK_WIDGET (entry));
4699 gtk_entry_select_all (GtkEntry *entry)
4701 gtk_entry_select_line (entry);
4705 gtk_entry_real_activate (GtkEntry *entry)
4708 GtkWidget *toplevel;
4711 widget = GTK_WIDGET (entry);
4713 if (entry->activates_default)
4715 toplevel = gtk_widget_get_toplevel (widget);
4716 if (GTK_IS_WINDOW (toplevel))
4718 window = GTK_WINDOW (toplevel);
4721 widget != window->default_widget &&
4722 !(widget == window->focus_widget &&
4723 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
4724 gtk_window_activate_default (window);
4730 keymap_direction_changed (GdkKeymap *keymap,
4733 gtk_entry_recompute (entry);
4736 /* IM Context Callbacks
4740 gtk_entry_commit_cb (GtkIMContext *context,
4744 if (entry->editable)
4745 gtk_entry_enter_text (entry, str);
4749 gtk_entry_preedit_changed_cb (GtkIMContext *context,
4752 if (entry->editable)
4754 gchar *preedit_string;
4757 gtk_im_context_get_preedit_string (entry->im_context,
4758 &preedit_string, NULL,
4760 entry->preedit_length = strlen (preedit_string);
4761 cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
4762 entry->preedit_cursor = cursor_pos;
4763 g_free (preedit_string);
4765 gtk_entry_recompute (entry);
4770 gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
4773 gtk_im_context_set_surrounding (context,
4776 g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text);
4782 gtk_entry_delete_surrounding_cb (GtkIMContext *slave,
4787 if (entry->editable)
4788 gtk_editable_delete_text (GTK_EDITABLE (entry),
4789 entry->current_pos + offset,
4790 entry->current_pos + offset + n_chars);
4795 /* Internal functions
4798 /* Used for im_commit_cb and inserting Unicode chars */
4800 gtk_entry_enter_text (GtkEntry *entry,
4803 GtkEditable *editable = GTK_EDITABLE (entry);
4805 gboolean old_need_im_reset;
4807 old_need_im_reset = entry->need_im_reset;
4808 entry->need_im_reset = FALSE;
4810 if (gtk_editable_get_selection_bounds (editable, NULL, NULL))
4811 gtk_editable_delete_selection (editable);
4814 if (entry->overwrite_mode)
4815 gtk_entry_delete_from_cursor (entry, GTK_DELETE_CHARS, 1);
4818 tmp_pos = entry->current_pos;
4819 gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
4820 gtk_editable_set_position (editable, tmp_pos);
4822 entry->need_im_reset = old_need_im_reset;
4825 /* All changes to entry->current_pos and entry->selection_bound
4826 * should go through this function.
4829 gtk_entry_set_positions (GtkEntry *entry,
4831 gint selection_bound)
4833 gboolean changed = FALSE;
4835 g_object_freeze_notify (G_OBJECT (entry));
4837 if (current_pos != -1 &&
4838 entry->current_pos != current_pos)
4840 entry->current_pos = current_pos;
4843 g_object_notify (G_OBJECT (entry), "cursor-position");
4846 if (selection_bound != -1 &&
4847 entry->selection_bound != selection_bound)
4849 entry->selection_bound = selection_bound;
4852 g_object_notify (G_OBJECT (entry), "selection-bound");
4855 g_object_thaw_notify (G_OBJECT (entry));
4859 gtk_entry_move_adjustments (entry);
4860 gtk_entry_recompute (entry);
4865 gtk_entry_reset_layout (GtkEntry *entry)
4867 if (entry->cached_layout)
4869 g_object_unref (entry->cached_layout);
4870 entry->cached_layout = NULL;
4875 update_im_cursor_location (GtkEntry *entry)
4879 gint strong_xoffset;
4880 gint area_width, area_height;
4882 gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
4883 gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
4885 strong_xoffset = strong_x - entry->scroll_offset;
4886 if (strong_xoffset < 0)
4890 else if (strong_xoffset > area_width)
4892 strong_xoffset = area_width;
4894 area.x = strong_xoffset;
4897 area.height = area_height;
4899 gtk_im_context_set_cursor_location (entry->im_context, &area);
4903 recompute_idle_func (gpointer data)
4907 entry = GTK_ENTRY (data);
4909 entry->recompute_idle = 0;
4911 if (gtk_widget_has_screen (GTK_WIDGET (entry)))
4913 gtk_entry_adjust_scroll (entry);
4914 gtk_entry_queue_draw (entry);
4916 update_im_cursor_location (entry);
4923 gtk_entry_recompute (GtkEntry *entry)
4925 gtk_entry_reset_layout (entry);
4926 gtk_entry_check_cursor_blink (entry);
4928 if (!entry->recompute_idle)
4930 entry->recompute_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
4931 recompute_idle_func, entry, NULL);
4936 append_char (GString *str,
4944 char_len = g_unichar_to_utf8 (ch, buf);
4949 g_string_append_len (str, buf, char_len);
4955 gtk_entry_remove_password_hint (gpointer data)
4957 /* Force the string to be redrawn, but now without a visible character */
4958 gtk_entry_recompute (GTK_ENTRY (data));
4963 static PangoLayout *
4964 gtk_entry_create_layout (GtkEntry *entry,
4965 gboolean include_preedit)
4967 GtkWidget *widget = GTK_WIDGET (entry);
4968 PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
4969 PangoAttrList *tmp_attrs = pango_attr_list_new ();
4971 gchar *preedit_string = NULL;
4972 gint preedit_length = 0;
4973 PangoAttrList *preedit_attrs = NULL;
4975 pango_layout_set_single_paragraph_mode (layout, TRUE);
4977 if (include_preedit)
4979 gtk_im_context_get_preedit_string (entry->im_context,
4980 &preedit_string, &preedit_attrs, NULL);
4981 preedit_length = entry->preedit_length;
4986 GString *tmp_string = g_string_new (NULL);
4988 gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
4992 g_string_prepend_len (tmp_string, entry->text, entry->n_bytes);
4993 g_string_insert (tmp_string, cursor_index, preedit_string);
4998 gunichar invisible_char;
5000 if (entry->invisible_char != 0)
5001 invisible_char = entry->invisible_char;
5003 invisible_char = ' '; /* just pick a char */
5005 ch_len = g_utf8_strlen (entry->text, entry->n_bytes);
5006 append_char (tmp_string, invisible_char, ch_len);
5008 g_utf8_offset_to_pointer (tmp_string->str, entry->current_pos) -
5010 g_string_insert (tmp_string, cursor_index, preedit_string);
5013 pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
5015 pango_attr_list_splice (tmp_attrs, preedit_attrs,
5016 cursor_index, preedit_length);
5018 g_string_free (tmp_string, TRUE);
5022 PangoDirection pango_dir;
5025 pango_dir = pango_find_base_dir (entry->text, entry->n_bytes);
5028 pango_dir = PANGO_DIRECTION_NEUTRAL;
5030 if (pango_dir == PANGO_DIRECTION_NEUTRAL)
5032 if (GTK_WIDGET_HAS_FOCUS (widget))
5034 GdkDisplay *display = gtk_widget_get_display (widget);
5035 GdkKeymap *keymap = gdk_keymap_get_for_display (display);
5036 if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
5037 pango_dir = PANGO_DIRECTION_RTL;
5039 pango_dir = PANGO_DIRECTION_LTR;
5043 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
5044 pango_dir = PANGO_DIRECTION_RTL;
5046 pango_dir = PANGO_DIRECTION_LTR;
5050 pango_context_set_base_dir (gtk_widget_get_pango_context (widget),
5053 entry->resolved_dir = pango_dir;
5057 pango_layout_set_text (layout, entry->text, entry->n_bytes);
5061 GString *str = g_string_new (NULL);
5062 gunichar invisible_char;
5063 guint password_hint_timeout;
5064 GtkEntryPasswordHint *password_hint;
5066 g_object_get (gtk_widget_get_settings (widget),
5067 "gtk-entry-password-hint-timeout", &password_hint_timeout,
5070 if (entry->invisible_char != 0)
5071 invisible_char = entry->invisible_char;
5073 invisible_char = ' '; /* just pick a char */
5075 password_hint = g_object_get_qdata (G_OBJECT (entry),
5076 quark_password_hint);
5078 if (password_hint && password_hint->password_hint_timeout_id)
5080 g_source_remove (password_hint->password_hint_timeout_id);
5081 password_hint->password_hint_timeout_id = 0;
5084 if (password_hint_timeout == 0 || password_hint == NULL ||
5085 (password_hint && password_hint->password_hint_length == 0))
5087 append_char (str, invisible_char, entry->text_length);
5089 else if (password_hint)
5091 /* Draw hidden characters upto the inserted position,
5092 * then the real thing, pad up to full length
5094 if (password_hint->password_hint_position > 1)
5095 append_char (str, invisible_char,
5096 password_hint->password_hint_position - 1);
5098 g_string_append_len (str, password_hint->password_hint,
5099 password_hint->password_hint_length);
5101 if (password_hint->password_hint_position < entry->text_length)
5102 append_char (str, invisible_char,
5103 entry->text_length -
5104 password_hint->password_hint_position);
5106 /* Now remove this last input character, don't need
5109 memset (password_hint->password_hint, 0, PASSWORD_HINT_MAX);
5110 password_hint->password_hint_length = 0;
5112 password_hint->password_hint_timeout_id =
5113 gdk_threads_add_timeout (password_hint_timeout,
5114 (GSourceFunc) gtk_entry_remove_password_hint,
5118 pango_layout_set_text (layout, str->str, str->len);
5119 g_string_free (str, TRUE);
5123 pango_layout_set_attributes (layout, tmp_attrs);
5125 g_free (preedit_string);
5127 pango_attr_list_unref (preedit_attrs);
5129 pango_attr_list_unref (tmp_attrs);
5134 static PangoLayout *
5135 gtk_entry_ensure_layout (GtkEntry *entry,
5136 gboolean include_preedit)
5138 if (entry->preedit_length > 0 &&
5139 !include_preedit != !entry->cache_includes_preedit)
5140 gtk_entry_reset_layout (entry);
5142 if (!entry->cached_layout)
5144 entry->cached_layout = gtk_entry_create_layout (entry, include_preedit);
5145 entry->cache_includes_preedit = include_preedit;
5148 return entry->cached_layout;
5152 get_layout_position (GtkEntry *entry,
5156 PangoLayout *layout;
5157 PangoRectangle logical_rect;
5158 gint area_width, area_height;
5159 GtkBorder inner_border;
5161 PangoLayoutLine *line;
5163 layout = gtk_entry_ensure_layout (entry, TRUE);
5165 gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
5166 _gtk_entry_effective_inner_border (entry, &inner_border);
5168 area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom);
5170 line = pango_layout_get_lines_readonly (layout)->data;
5171 pango_layout_line_get_extents (line, NULL, &logical_rect);
5173 /* Align primarily for locale's ascent/descent */
5174 y_pos = ((area_height - entry->ascent - entry->descent) / 2 +
5175 entry->ascent + logical_rect.y);
5177 /* Now see if we need to adjust to fit in actual drawn string */
5178 if (logical_rect.height > area_height)
5179 y_pos = (area_height - logical_rect.height) / 2;
5182 else if (y_pos + logical_rect.height > area_height)
5183 y_pos = area_height - logical_rect.height;
5185 y_pos = inner_border.top + y_pos / PANGO_SCALE;
5188 *x = inner_border.left - entry->scroll_offset;
5195 gtk_entry_draw_text (GtkEntry *entry)
5199 if (!entry->visible && entry->invisible_char == 0)
5202 if (GTK_WIDGET_DRAWABLE (entry))
5204 PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
5207 gint start_pos, end_pos;
5209 widget = GTK_WIDGET (entry);
5211 get_layout_position (entry, &x, &y);
5213 cr = gdk_cairo_create (entry->text_area);
5215 cairo_move_to (cr, x, y);
5216 gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
5217 pango_cairo_show_layout (cr, layout);
5219 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
5223 PangoRectangle logical_rect;
5224 GdkColor *selection_color, *text_color;
5225 GtkBorder inner_border;
5227 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
5228 gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
5230 if (GTK_WIDGET_HAS_FOCUS (entry))
5232 selection_color = &widget->style->base [GTK_STATE_SELECTED];
5233 text_color = &widget->style->text [GTK_STATE_SELECTED];
5237 selection_color = &widget->style->base [GTK_STATE_ACTIVE];
5238 text_color = &widget->style->text [GTK_STATE_ACTIVE];
5241 _gtk_entry_effective_inner_border (entry, &inner_border);
5243 for (i = 0; i < n_ranges; ++i)
5244 cairo_rectangle (cr,
5245 inner_border.left - entry->scroll_offset + ranges[2 * i],
5248 logical_rect.height);
5252 gdk_cairo_set_source_color (cr, selection_color);
5255 cairo_move_to (cr, x, y);
5256 gdk_cairo_set_source_color (cr, text_color);
5257 pango_cairo_show_layout (cr, layout);
5267 draw_insertion_cursor (GtkEntry *entry,
5268 GdkRectangle *cursor_location,
5269 gboolean is_primary,
5270 PangoDirection direction,
5271 gboolean draw_arrow)
5273 GtkWidget *widget = GTK_WIDGET (entry);
5274 GtkTextDirection text_dir;
5276 if (direction == PANGO_DIRECTION_LTR)
5277 text_dir = GTK_TEXT_DIR_LTR;
5279 text_dir = GTK_TEXT_DIR_RTL;
5281 gtk_draw_insertion_cursor (widget, entry->text_area, NULL,
5283 is_primary, text_dir, draw_arrow);
5287 gtk_entry_draw_cursor (GtkEntry *entry,
5290 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
5291 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5293 if (GTK_WIDGET_DRAWABLE (entry))
5295 GtkWidget *widget = GTK_WIDGET (entry);
5296 GdkRectangle cursor_location;
5297 gboolean split_cursor;
5298 PangoRectangle cursor_rect;
5299 GtkBorder inner_border;
5301 gint text_area_height;
5304 gboolean block_at_line_end;
5305 PangoLayout *layout;
5308 _gtk_entry_effective_inner_border (entry, &inner_border);
5310 xoffset = inner_border.left - entry->scroll_offset;
5312 gdk_drawable_get_size (entry->text_area, NULL, &text_area_height);
5314 layout = gtk_entry_ensure_layout (entry, TRUE);
5315 text = pango_layout_get_text (layout);
5316 cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
5317 if (!entry->overwrite_mode)
5320 block = _gtk_text_util_get_block_cursor_location (layout,
5321 cursor_index, &cursor_rect, &block_at_line_end);
5325 gint strong_x, weak_x;
5326 PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
5327 PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
5331 gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
5333 g_object_get (gtk_widget_get_settings (widget),
5334 "gtk-split-cursor", &split_cursor,
5337 dir1 = entry->resolved_dir;
5343 if (weak_x != strong_x)
5345 dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
5351 if (keymap_direction == entry->resolved_dir)
5357 cursor_location.x = xoffset + x1;
5358 cursor_location.y = inner_border.top;
5359 cursor_location.width = 0;
5360 cursor_location.height = text_area_height - inner_border.top - inner_border.bottom;
5362 draw_insertion_cursor (entry,
5363 &cursor_location, TRUE, dir1,
5364 dir2 != PANGO_DIRECTION_NEUTRAL);
5366 if (dir2 != PANGO_DIRECTION_NEUTRAL)
5368 cursor_location.x = xoffset + x2;
5369 draw_insertion_cursor (entry,
5370 &cursor_location, FALSE, dir2,
5374 else /* overwrite_mode */
5376 GdkColor cursor_color;
5381 get_layout_position (entry, &x, &y);
5383 rect.x = PANGO_PIXELS (cursor_rect.x) + x;
5384 rect.y = PANGO_PIXELS (cursor_rect.y) + y;
5385 rect.width = PANGO_PIXELS (cursor_rect.width);
5386 rect.height = PANGO_PIXELS (cursor_rect.height);
5388 cr = gdk_cairo_create (entry->text_area);
5390 _gtk_widget_get_cursor_color (widget, &cursor_color);
5391 gdk_cairo_set_source_color (cr, &cursor_color);
5392 gdk_cairo_rectangle (cr, &rect);
5395 if (!block_at_line_end)
5397 gdk_cairo_rectangle (cr, &rect);
5399 cairo_move_to (cr, x, y);
5400 gdk_cairo_set_source_color (cr, &widget->style->base[widget->state]);
5401 pango_cairo_show_layout (cr, layout);
5410 gtk_entry_queue_draw (GtkEntry *entry)
5412 if (GTK_WIDGET_DRAWABLE (entry))
5413 gdk_window_invalidate_rect (entry->text_area, NULL, FALSE);
5417 _gtk_entry_reset_im_context (GtkEntry *entry)
5419 if (entry->need_im_reset)
5421 entry->need_im_reset = FALSE;
5422 gtk_im_context_reset (entry->im_context);
5427 gtk_entry_find_position (GtkEntry *entry,
5430 PangoLayout *layout;
5431 PangoLayoutLine *line;
5438 layout = gtk_entry_ensure_layout (entry, TRUE);
5439 text = pango_layout_get_text (layout);
5440 cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
5442 line = pango_layout_get_lines_readonly (layout)->data;
5443 pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
5445 if (index >= cursor_index && entry->preedit_length)
5447 if (index >= cursor_index + entry->preedit_length)
5448 index -= entry->preedit_length;
5451 index = cursor_index;
5456 pos = g_utf8_pointer_to_offset (text, text + index);
5463 gtk_entry_get_cursor_locations (GtkEntry *entry,
5468 if (!entry->visible && !entry->invisible_char)
5478 PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
5479 const gchar *text = pango_layout_get_text (layout);
5480 PangoRectangle strong_pos, weak_pos;
5483 if (type == CURSOR_STANDARD)
5485 index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
5487 else /* type == CURSOR_DND */
5489 index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text;
5491 if (entry->dnd_position > entry->current_pos)
5494 index += entry->preedit_length;
5497 gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length;
5498 index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL);
5503 pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
5506 *strong_x = strong_pos.x / PANGO_SCALE;
5509 *weak_x = weak_pos.x / PANGO_SCALE;
5514 gtk_entry_adjust_scroll (GtkEntry *entry)
5516 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5517 gint min_offset, max_offset;
5518 gint text_area_width, text_width;
5519 GtkBorder inner_border;
5520 gint strong_x, weak_x;
5521 gint strong_xoffset, weak_xoffset;
5523 PangoLayout *layout;
5524 PangoLayoutLine *line;
5525 PangoRectangle logical_rect;
5527 if (!GTK_WIDGET_REALIZED (entry))
5530 _gtk_entry_effective_inner_border (entry, &inner_border);
5532 gdk_drawable_get_size (entry->text_area, &text_area_width, NULL);
5533 text_area_width -= inner_border.left + inner_border.right;
5534 if (text_area_width < 0)
5535 text_area_width = 0;
5537 layout = gtk_entry_ensure_layout (entry, TRUE);
5538 line = pango_layout_get_lines_readonly (layout)->data;
5540 pango_layout_line_get_extents (line, NULL, &logical_rect);
5542 /* Display as much text as we can */
5544 if (entry->resolved_dir == PANGO_DIRECTION_LTR)
5545 xalign = priv->xalign;
5547 xalign = 1.0 - priv->xalign;
5549 text_width = PANGO_PIXELS(logical_rect.width);
5551 if (text_width > text_area_width)
5554 max_offset = text_width - text_area_width;
5558 min_offset = (text_width - text_area_width) * xalign;
5559 max_offset = min_offset;
5562 entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
5564 /* And make sure cursors are on screen. Note that the cursor is
5565 * actually drawn one pixel into the INNER_BORDER space on
5566 * the right, when the scroll is at the utmost right. This
5567 * looks better to to me than confining the cursor inside the
5568 * border entirely, though it means that the cursor gets one
5569 * pixel closer to the edge of the widget on the right than
5570 * on the left. This might need changing if one changed
5571 * INNER_BORDER from 2 to 1, as one would do on a
5572 * small-screen-real-estate display.
5574 * We always make sure that the strong cursor is on screen, and
5575 * put the weak cursor on screen if possible.
5578 gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
5580 strong_xoffset = strong_x - entry->scroll_offset;
5582 if (strong_xoffset < 0)
5584 entry->scroll_offset += strong_xoffset;
5587 else if (strong_xoffset > text_area_width)
5589 entry->scroll_offset += strong_xoffset - text_area_width;
5590 strong_xoffset = text_area_width;
5593 weak_xoffset = weak_x - entry->scroll_offset;
5595 if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
5597 entry->scroll_offset += weak_xoffset;
5599 else if (weak_xoffset > text_area_width &&
5600 strong_xoffset - (weak_xoffset - text_area_width) >= 0)
5602 entry->scroll_offset += weak_xoffset - text_area_width;
5605 g_object_notify (G_OBJECT (entry), "scroll-offset");
5609 gtk_entry_move_adjustments (GtkEntry *entry)
5611 PangoContext *context;
5612 PangoFontMetrics *metrics;
5613 gint x, layout_x, border_x, border_y;
5615 GtkAdjustment *adjustment;
5617 adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
5621 /* Cursor position, layout offset, border width, and widget allocation */
5622 gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL);
5623 get_layout_position (entry, &layout_x, NULL);
5624 _gtk_entry_get_borders (entry, &border_x, &border_y);
5625 x += entry->widget.allocation.x + layout_x + border_x;
5627 /* Approximate width of a char, so user can see what is ahead/behind */
5628 context = gtk_widget_get_pango_context (GTK_WIDGET (entry));
5629 metrics = pango_context_get_metrics (context,
5630 entry->widget.style->font_desc,
5631 pango_context_get_language (context));
5632 char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE;
5635 gtk_adjustment_clamp_page (adjustment,
5636 x - (char_width + 1), /* one char + one pixel before */
5637 x + (char_width + 2)); /* one char + cursor + one pixel after */
5641 gtk_entry_move_visually (GtkEntry *entry,
5646 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5649 text = pango_layout_get_text (layout);
5651 index = g_utf8_offset_to_pointer (text, start) - text;
5655 int new_index, new_trailing;
5656 gboolean split_cursor;
5659 g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
5660 "gtk-split-cursor", &split_cursor,
5667 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
5668 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5670 strong = keymap_direction == entry->resolved_dir;
5675 pango_layout_move_cursor_visually (layout, strong, index, 0, 1, &new_index, &new_trailing);
5680 pango_layout_move_cursor_visually (layout, strong, index, 0, -1, &new_index, &new_trailing);
5686 else if (new_index != G_MAXINT)
5689 while (new_trailing--)
5690 index = g_utf8_next_char (text + index) - text;
5693 return g_utf8_pointer_to_offset (text, text + index);
5697 gtk_entry_move_logically (GtkEntry *entry,
5701 gint new_pos = start;
5703 /* Prevent any leak of information */
5704 if (!entry->visible)
5706 new_pos = CLAMP (start + count, 0, entry->text_length);
5708 else if (entry->text)
5710 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5711 PangoLogAttr *log_attrs;
5714 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5716 while (count > 0 && new_pos < entry->text_length)
5720 while (new_pos < entry->text_length && !log_attrs[new_pos].is_cursor_position);
5724 while (count < 0 && new_pos > 0)
5728 while (new_pos > 0 && !log_attrs[new_pos].is_cursor_position);
5740 gtk_entry_move_forward_word (GtkEntry *entry,
5742 gboolean allow_whitespace)
5744 gint new_pos = start;
5746 /* Prevent any leak of information */
5747 if (!entry->visible)
5749 new_pos = entry->text_length;
5751 else if (entry->text && (new_pos < entry->text_length))
5753 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5754 PangoLogAttr *log_attrs;
5757 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5759 /* Find the next word boundary */
5761 while (new_pos < n_attrs - 1 && !(log_attrs[new_pos].is_word_end ||
5762 (log_attrs[new_pos].is_word_start && allow_whitespace)))
5773 gtk_entry_move_backward_word (GtkEntry *entry,
5775 gboolean allow_whitespace)
5777 gint new_pos = start;
5779 /* Prevent any leak of information */
5780 if (!entry->visible)
5784 else if (entry->text && start > 0)
5786 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5787 PangoLogAttr *log_attrs;
5790 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5792 new_pos = start - 1;
5794 /* Find the previous word boundary */
5795 while (new_pos > 0 && !(log_attrs[new_pos].is_word_start ||
5796 (log_attrs[new_pos].is_word_end && allow_whitespace)))
5806 gtk_entry_delete_whitespace (GtkEntry *entry)
5808 PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5809 PangoLogAttr *log_attrs;
5813 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5815 start = end = entry->current_pos;
5817 while (start > 0 && log_attrs[start-1].is_white)
5820 while (end < n_attrs && log_attrs[end].is_white)
5826 gtk_editable_delete_text (GTK_EDITABLE (entry), start, end);
5831 gtk_entry_select_word (GtkEntry *entry)
5833 gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos, TRUE);
5834 gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos, TRUE);
5836 gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
5840 gtk_entry_select_line (GtkEntry *entry)
5842 gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
5846 * Like gtk_editable_get_chars, but handle not-visible entries
5850 gtk_entry_get_public_chars (GtkEntry *entry,
5855 end = entry->text_length;
5858 return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
5859 else if (!entry->invisible_char)
5860 return g_strdup ("");
5863 GString *str = g_string_new (NULL);
5864 append_char (str, entry->invisible_char, end - start);
5865 return g_string_free (str, FALSE);
5870 truncate_multiline (const gchar *text)
5875 text[length] && text[length] != '\n' && text[length] != '\r';
5882 paste_received (GtkClipboard *clipboard,
5886 GtkEntry *entry = GTK_ENTRY (data);
5887 GtkEditable *editable = GTK_EDITABLE (entry);
5888 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5890 if (entry->button == 2)
5892 gint pos, start, end;
5893 pos = priv->insert_pos;
5894 gtk_editable_get_selection_bounds (editable, &start, &end);
5895 if (!((start <= pos && pos <= end) || (end <= pos && pos <= start)))
5896 gtk_editable_select_region (editable, pos, pos);
5901 gint pos, start, end;
5903 gboolean popup_completion;
5904 GtkEntryCompletion *completion;
5906 completion = gtk_entry_get_completion (entry);
5908 if (entry->truncate_multiline)
5909 length = truncate_multiline (text);
5911 /* only complete if the selection is at the end */
5912 popup_completion = (entry->text_length == MAX (entry->current_pos, entry->selection_bound));
5916 if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
5917 _gtk_entry_completion_popdown (completion);
5919 if (!popup_completion && completion->priv->changed_id > 0)
5920 g_signal_handler_block (entry, completion->priv->changed_id);
5923 begin_change (entry);
5924 g_object_freeze_notify (G_OBJECT (entry));
5925 if (gtk_editable_get_selection_bounds (editable, &start, &end))
5926 gtk_editable_delete_text (editable, start, end);
5928 pos = entry->current_pos;
5929 gtk_editable_insert_text (editable, text, length, &pos);
5930 gtk_editable_set_position (editable, pos);
5931 g_object_thaw_notify (G_OBJECT (entry));
5935 !popup_completion && completion->priv->changed_id > 0)
5936 g_signal_handler_unblock (entry, completion->priv->changed_id);
5939 g_object_unref (entry);
5943 gtk_entry_paste (GtkEntry *entry,
5946 g_object_ref (entry);
5947 gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (entry), selection),
5948 paste_received, entry);
5952 primary_get_cb (GtkClipboard *clipboard,
5953 GtkSelectionData *selection_data,
5957 GtkEntry *entry = GTK_ENTRY (data);
5960 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
5962 gchar *str = gtk_entry_get_public_chars (entry, start, end);
5963 gtk_selection_data_set_text (selection_data, str, -1);
5969 primary_clear_cb (GtkClipboard *clipboard,
5972 GtkEntry *entry = GTK_ENTRY (data);
5974 gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
5978 gtk_entry_update_primary_selection (GtkEntry *entry)
5980 GtkTargetList *list;
5981 GtkTargetEntry *targets;
5982 GtkClipboard *clipboard;
5986 if (!GTK_WIDGET_REALIZED (entry))
5989 list = gtk_target_list_new (NULL, 0);
5990 gtk_target_list_add_text_targets (list, 0);
5992 targets = gtk_target_table_new_from_list (list, &n_targets);
5994 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_PRIMARY);
5996 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
5998 if (!gtk_clipboard_set_with_owner (clipboard, targets, n_targets,
5999 primary_get_cb, primary_clear_cb, G_OBJECT (entry)))
6000 primary_clear_cb (clipboard, entry);
6004 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
6005 gtk_clipboard_clear (clipboard);
6008 gtk_target_table_free (targets, n_targets);
6009 gtk_target_list_unref (list);
6013 gtk_entry_clear (GtkEntry *entry,
6014 GtkEntryIconPosition icon_pos)
6016 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
6017 EntryIconInfo *icon_info = priv->icons[icon_pos];
6019 if (!icon_info || icon_info->storage_type == GTK_IMAGE_EMPTY)
6022 g_object_freeze_notify (G_OBJECT (entry));
6024 /* Explicitly check, as the pointer may become invalidated
6025 * during destruction.
6027 if (GDK_IS_WINDOW (icon_info->window))
6028 gdk_window_hide (icon_info->window);
6030 if (icon_info->pixbuf)
6032 g_object_unref (icon_info->pixbuf);
6033 icon_info->pixbuf = NULL;
6036 switch (icon_info->storage_type)
6038 case GTK_IMAGE_PIXBUF:
6039 g_object_notify (G_OBJECT (entry),
6040 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "pixbuf-primary" : "pixbuf-secondary");
6043 case GTK_IMAGE_STOCK:
6044 g_free (icon_info->stock_id);
6045 icon_info->stock_id = NULL;
6046 g_object_notify (G_OBJECT (entry),
6047 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "stock-primary" : "stock-secondary");
6050 case GTK_IMAGE_ICON_NAME:
6051 g_free (icon_info->icon_name);
6052 icon_info->icon_name = NULL;
6053 g_object_notify (G_OBJECT (entry),
6054 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "icon-name-primary" : "icon-name-secondary");
6057 case GTK_IMAGE_GICON:
6058 if (icon_info->gicon)
6060 g_object_unref (icon_info->gicon);
6061 icon_info->gicon = NULL;
6063 g_object_notify (G_OBJECT (entry),
6064 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "gicon-primary" : "gicon-secondary");
6068 g_assert_not_reached ();
6072 icon_info->storage_type = GTK_IMAGE_EMPTY;
6073 g_object_notify (G_OBJECT (entry),
6074 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "storage-type-primary" : "storage-type-secondary");
6076 g_object_thaw_notify (G_OBJECT (entry));
6080 gtk_entry_ensure_pixbuf (GtkEntry *entry,
6081 GtkEntryIconPosition icon_pos)
6083 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
6084 EntryIconInfo *icon_info = priv->icons[icon_pos];
6086 GtkIconTheme *icon_theme;
6087 GtkSettings *settings;
6091 if (!icon_info || icon_info->pixbuf)
6094 switch (icon_info->storage_type)
6096 case GTK_IMAGE_EMPTY:
6097 case GTK_IMAGE_PIXBUF:
6099 case GTK_IMAGE_STOCK:
6100 icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
6101 icon_info->stock_id,
6106 case GTK_IMAGE_ICON_NAME:
6107 screen = gtk_widget_get_screen (GTK_WIDGET (entry));
6110 icon_theme = gtk_icon_theme_get_for_screen (screen);
6111 settings = gtk_settings_get_for_screen (screen);
6113 gtk_icon_size_lookup_for_settings (settings,
6117 icon_info->pixbuf = gtk_icon_theme_load_icon (icon_theme,
6118 icon_info->icon_name,
6119 MIN (width, height),
6122 if (icon_info->pixbuf == NULL)
6123 icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
6124 GTK_STOCK_MISSING_IMAGE,
6130 case GTK_IMAGE_GICON:
6131 screen = gtk_widget_get_screen (GTK_WIDGET (entry));
6134 icon_theme = gtk_icon_theme_get_for_screen (screen);
6135 settings = gtk_settings_get_for_screen (screen);
6137 gtk_icon_size_lookup_for_settings (settings,
6141 info = gtk_icon_theme_lookup_by_gicon (icon_theme,
6143 MIN (width, height),
6144 GTK_ICON_LOOKUP_USE_BUILTIN);
6147 icon_info->pixbuf = gtk_icon_info_load_icon (info, NULL);
6148 gtk_icon_info_free (info);
6151 if (icon_info->pixbuf == NULL)
6152 icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
6153 GTK_STOCK_MISSING_IMAGE,
6160 g_assert_not_reached ();
6164 if (GDK_IS_WINDOW (icon_info->window))
6165 gdk_window_show (icon_info->window);
6175 * Creates a new entry.
6177 * Return value: a new #GtkEntry.
6180 gtk_entry_new (void)
6182 return g_object_new (GTK_TYPE_ENTRY, NULL);
6186 * gtk_entry_new_with_max_length:
6187 * @max: the maximum length of the entry, or 0 for no maximum.
6188 * (other than the maximum length of entries.) The value passed in will
6189 * be clamped to the range 0-65536.
6191 * Creates a new #GtkEntry widget with the given maximum length.
6193 * Return value: a new #GtkEntry
6195 * Deprecated: Use gtk_entry_set_max_length() instead.
6198 gtk_entry_new_with_max_length (gint max)
6202 max = CLAMP (max, 0, MAX_SIZE);
6204 entry = g_object_new (GTK_TYPE_ENTRY, NULL);
6205 entry->text_max_length = max;
6207 return GTK_WIDGET (entry);
6211 * gtk_entry_set_text:
6212 * @entry: a #GtkEntry
6213 * @text: the new text
6215 * Sets the text in the widget to the given
6216 * value, replacing the current contents.
6219 gtk_entry_set_text (GtkEntry *entry,
6223 GtkEntryCompletion *completion;
6225 g_return_if_fail (GTK_IS_ENTRY (entry));
6226 g_return_if_fail (text != NULL);
6228 /* Actually setting the text will affect the cursor and selection;
6229 * if the contents don't actually change, this will look odd to the user.
6231 if (strcmp (entry->text, text) == 0)
6234 completion = gtk_entry_get_completion (entry);
6235 if (completion && completion->priv->changed_id > 0)
6236 g_signal_handler_block (entry, completion->priv->changed_id);
6238 begin_change (entry);
6239 g_object_freeze_notify (G_OBJECT (entry));
6240 gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
6243 gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos);
6244 g_object_thaw_notify (G_OBJECT (entry));
6247 if (completion && completion->priv->changed_id > 0)
6248 g_signal_handler_unblock (entry, completion->priv->changed_id);
6252 * gtk_entry_append_text:
6253 * @entry: a #GtkEntry
6254 * @text: the text to append
6256 * Appends the given text to the contents of the widget.
6258 * Deprecated: 2.0: Use gtk_editable_insert_text() instead.
6261 gtk_entry_append_text (GtkEntry *entry,
6266 g_return_if_fail (GTK_IS_ENTRY (entry));
6267 g_return_if_fail (text != NULL);
6269 tmp_pos = entry->text_length;
6270 gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
6274 * gtk_entry_prepend_text:
6275 * @entry: a #GtkEntry
6276 * @text: the text to prepend
6278 * Prepends the given text to the contents of the widget.
6280 * Deprecated: 2.0: Use gtk_editable_insert_text() instead.
6283 gtk_entry_prepend_text (GtkEntry *entry,
6288 g_return_if_fail (GTK_IS_ENTRY (entry));
6289 g_return_if_fail (text != NULL);
6292 gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
6296 * gtk_entry_set_position:
6297 * @entry: a #GtkEntry
6298 * @position: the position of the cursor. The cursor is displayed
6299 * before the character with the given (base 0) index in the widget.
6300 * The value must be less than or equal to the number of characters
6301 * in the widget. A value of -1 indicates that the position should
6302 * be set after the last character in the entry. Note that this
6303 * position is in characters, not in bytes.
6305 * Sets the cursor position in an entry to the given value.
6307 * Deprecated: 2.0: Use gtk_editable_set_position() instead.
6310 gtk_entry_set_position (GtkEntry *entry,
6313 g_return_if_fail (GTK_IS_ENTRY (entry));
6315 gtk_editable_set_position (GTK_EDITABLE (entry), position);
6319 * gtk_entry_set_visibility:
6320 * @entry: a #GtkEntry
6321 * @visible: %TRUE if the contents of the entry are displayed
6324 * Sets whether the contents of the entry are visible or not.
6325 * When visibility is set to %FALSE, characters are displayed
6326 * as the invisible char, and will also appear that way when
6327 * the text in the entry widget is copied elsewhere.
6329 * By default, GTK+ picks the best invisible character available
6330 * in the current font, but it can be changed with
6331 * gtk_entry_set_invisible_char().
6334 gtk_entry_set_visibility (GtkEntry *entry,
6337 g_return_if_fail (GTK_IS_ENTRY (entry));
6339 visible = visible != FALSE;
6341 if (entry->visible != visible)
6343 entry->visible = visible;
6345 g_object_notify (G_OBJECT (entry), "visibility");
6346 gtk_entry_recompute (entry);
6351 * gtk_entry_get_visibility:
6352 * @entry: a #GtkEntry
6354 * Retrieves whether the text in @entry is visible. See
6355 * gtk_entry_set_visibility().
6357 * Return value: %TRUE if the text is currently visible
6360 gtk_entry_get_visibility (GtkEntry *entry)
6362 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6364 return entry->visible;
6368 * gtk_entry_set_invisible_char:
6369 * @entry: a #GtkEntry
6370 * @ch: a Unicode character
6372 * Sets the character to use in place of the actual text when
6373 * gtk_entry_set_visibility() has been called to set text visibility
6374 * to %FALSE. i.e. this is the character used in "password mode" to
6375 * show the user how many characters have been typed. By default, GTK+
6376 * picks the best invisible char available in the current font. If you
6377 * set the invisible char to 0, then the user will get no feedback
6378 * at all; there will be no text on the screen as they type.
6381 gtk_entry_set_invisible_char (GtkEntry *entry,
6384 GtkEntryPrivate *priv;
6386 g_return_if_fail (GTK_IS_ENTRY (entry));
6388 priv = GTK_ENTRY_GET_PRIVATE (entry);
6390 if (!priv->invisible_char_set)
6392 priv->invisible_char_set = TRUE;
6393 g_object_notify (G_OBJECT (entry), "invisible-char-set");
6396 if (ch == entry->invisible_char)
6399 entry->invisible_char = ch;
6400 g_object_notify (G_OBJECT (entry), "invisible-char");
6401 gtk_entry_recompute (entry);
6405 * gtk_entry_get_invisible_char:
6406 * @entry: a #GtkEntry
6408 * Retrieves the character displayed in place of the real characters
6409 * for entries with visibility set to false. See gtk_entry_set_invisible_char().
6411 * Return value: the current invisible char, or 0, if the entry does not
6412 * show invisible text at all.
6415 gtk_entry_get_invisible_char (GtkEntry *entry)
6417 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6419 return entry->invisible_char;
6423 * gtk_entry_unset_invisible_char:
6424 * @entry: a #GtkEntry
6426 * Unsets the invisible char previously set with
6427 * gtk_entry_set_invisible_char(). So that the
6428 * default invisible char is used again.
6433 gtk_entry_unset_invisible_char (GtkEntry *entry)
6435 GtkEntryPrivate *priv;
6438 g_return_if_fail (GTK_IS_ENTRY (entry));
6440 priv = GTK_ENTRY_GET_PRIVATE (entry);
6442 if (!priv->invisible_char_set)
6445 priv->invisible_char_set = FALSE;
6446 ch = find_invisible_char (GTK_WIDGET (entry));
6448 if (entry->invisible_char != ch)
6450 entry->invisible_char = ch;
6451 g_object_notify (G_OBJECT (entry), "invisible-char");
6454 g_object_notify (G_OBJECT (entry), "invisible-char-set");
6455 gtk_entry_recompute (entry);
6459 * gtk_entry_set_editable:
6460 * @entry: a #GtkEntry
6461 * @editable: %TRUE if the user is allowed to edit the text
6464 * Determines if the user can edit the text in the editable
6467 * Deprecated: 2.0: Use gtk_editable_set_editable() instead.
6470 gtk_entry_set_editable (GtkEntry *entry,
6473 g_return_if_fail (GTK_IS_ENTRY (entry));
6475 gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
6479 * gtk_entry_set_overwrite_mode:
6480 * @entry: a #GtkEntry
6481 * @overwrite: new value
6483 * Sets whether the text is overwritten when typing in the #GtkEntry.
6488 gtk_entry_set_overwrite_mode (GtkEntry *entry,
6491 g_return_if_fail (GTK_IS_ENTRY (entry));
6493 if (entry->overwrite_mode == overwrite)
6496 gtk_entry_toggle_overwrite (entry);
6498 g_object_notify (G_OBJECT (entry), "overwrite-mode");
6502 * gtk_entry_get_overwrite_mode:
6503 * @entry: a #GtkEntry
6505 * Gets the value set by gtk_entry_set_overwrite_mode().
6507 * Return value: whether the text is overwritten when typing.
6512 gtk_entry_get_overwrite_mode (GtkEntry *entry)
6514 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6516 return entry->overwrite_mode;
6520 * gtk_entry_get_text:
6521 * @entry: a #GtkEntry
6523 * Retrieves the contents of the entry widget.
6524 * See also gtk_editable_get_chars().
6526 * Return value: a pointer to the contents of the widget as a
6527 * string. This string points to internally allocated
6528 * storage in the widget and must not be freed, modified or
6531 G_CONST_RETURN gchar*
6532 gtk_entry_get_text (GtkEntry *entry)
6534 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6540 * gtk_entry_select_region:
6541 * @entry: a #GtkEntry
6542 * @start: the starting position
6543 * @end: the end position
6545 * Selects a region of text. The characters that are selected are
6546 * those characters at positions from @start_pos up to, but not
6547 * including @end_pos. If @end_pos is negative, then the the characters
6548 * selected will be those characters from @start_pos to the end of
6551 * Deprecated: 2.0: Use gtk_editable_select_region() instead.
6554 gtk_entry_select_region (GtkEntry *entry,
6558 gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
6562 * gtk_entry_set_max_length:
6563 * @entry: a #GtkEntry
6564 * @max: the maximum length of the entry, or 0 for no maximum.
6565 * (other than the maximum length of entries.) The value passed in will
6566 * be clamped to the range 0-65536.
6568 * Sets the maximum allowed length of the contents of the widget. If
6569 * the current contents are longer than the given length, then they
6570 * will be truncated to fit.
6573 gtk_entry_set_max_length (GtkEntry *entry,
6576 g_return_if_fail (GTK_IS_ENTRY (entry));
6578 max = CLAMP (max, 0, MAX_SIZE);
6580 if (max > 0 && entry->text_length > max)
6581 gtk_editable_delete_text (GTK_EDITABLE (entry), max, -1);
6583 entry->text_max_length = max;
6584 g_object_notify (G_OBJECT (entry), "max-length");
6588 * gtk_entry_get_max_length:
6589 * @entry: a #GtkEntry
6591 * Retrieves the maximum allowed length of the text in
6592 * @entry. See gtk_entry_set_max_length().
6594 * Return value: the maximum allowed number of characters
6595 * in #GtkEntry, or 0 if there is no maximum.
6598 gtk_entry_get_max_length (GtkEntry *entry)
6600 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6602 return entry->text_max_length;
6606 * gtk_entry_get_text_length:
6607 * @entry: a #GtkEntry
6609 * Retrieves the current length of the text in
6612 * Return value: the current number of characters
6613 * in #GtkEntry, or 0 if there are none.
6618 gtk_entry_get_text_length (GtkEntry *entry)
6620 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6622 return entry->text_length;
6626 * gtk_entry_set_activates_default:
6627 * @entry: a #GtkEntry
6628 * @setting: %TRUE to activate window's default widget on Enter keypress
6630 * If @setting is %TRUE, pressing Enter in the @entry will activate the default
6631 * widget for the window containing the entry. This usually means that
6632 * the dialog box containing the entry will be closed, since the default
6633 * widget is usually one of the dialog buttons.
6635 * (For experts: if @setting is %TRUE, the entry calls
6636 * gtk_window_activate_default() on the window containing the entry, in
6637 * the default handler for the #GtkWidget::activate signal.)
6640 gtk_entry_set_activates_default (GtkEntry *entry,
6643 g_return_if_fail (GTK_IS_ENTRY (entry));
6644 setting = setting != FALSE;
6646 if (setting != entry->activates_default)
6648 entry->activates_default = setting;
6649 g_object_notify (G_OBJECT (entry), "activates-default");
6654 * gtk_entry_get_activates_default:
6655 * @entry: a #GtkEntry
6657 * Retrieves the value set by gtk_entry_set_activates_default().
6659 * Return value: %TRUE if the entry will activate the default widget
6662 gtk_entry_get_activates_default (GtkEntry *entry)
6664 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6666 return entry->activates_default;
6670 * gtk_entry_set_width_chars:
6671 * @entry: a #GtkEntry
6672 * @n_chars: width in chars
6674 * Changes the size request of the entry to be about the right size
6675 * for @n_chars characters. Note that it changes the size
6676 * <emphasis>request</emphasis>, the size can still be affected by
6677 * how you pack the widget into containers. If @n_chars is -1, the
6678 * size reverts to the default entry size.
6681 gtk_entry_set_width_chars (GtkEntry *entry,
6684 g_return_if_fail (GTK_IS_ENTRY (entry));
6686 if (entry->width_chars != n_chars)
6688 entry->width_chars = n_chars;
6689 g_object_notify (G_OBJECT (entry), "width-chars");
6690 gtk_widget_queue_resize (GTK_WIDGET (entry));
6695 * gtk_entry_get_width_chars:
6696 * @entry: a #GtkEntry
6698 * Gets the value set by gtk_entry_set_width_chars().
6700 * Return value: number of chars to request space for, or negative if unset
6703 gtk_entry_get_width_chars (GtkEntry *entry)
6705 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6707 return entry->width_chars;
6711 * gtk_entry_set_has_frame:
6712 * @entry: a #GtkEntry
6713 * @setting: new value
6715 * Sets whether the entry has a beveled frame around it.
6718 gtk_entry_set_has_frame (GtkEntry *entry,
6721 g_return_if_fail (GTK_IS_ENTRY (entry));
6723 setting = (setting != FALSE);
6725 if (entry->has_frame == setting)
6728 gtk_widget_queue_resize (GTK_WIDGET (entry));
6729 entry->has_frame = setting;
6730 g_object_notify (G_OBJECT (entry), "has-frame");
6734 * gtk_entry_get_has_frame:
6735 * @entry: a #GtkEntry
6737 * Gets the value set by gtk_entry_set_has_frame().
6739 * Return value: whether the entry has a beveled frame
6742 gtk_entry_get_has_frame (GtkEntry *entry)
6744 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6746 return entry->has_frame;
6750 * gtk_entry_set_inner_border:
6751 * @entry: a #GtkEntry
6752 * @border: a #GtkBorder, or %NULL
6754 * Sets %entry's inner-border property to %border, or clears it if %NULL
6755 * is passed. The inner-border is the area around the entry's text, but
6758 * If set, this property overrides the inner-border style property.
6759 * Overriding the style-provided border is useful when you want to do
6760 * in-place editing of some text in a canvas or list widget, where
6761 * pixel-exact positioning of the entry is important.
6766 gtk_entry_set_inner_border (GtkEntry *entry,
6767 const GtkBorder *border)
6769 g_return_if_fail (GTK_IS_ENTRY (entry));
6771 gtk_widget_queue_resize (GTK_WIDGET (entry));
6774 g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border,
6775 gtk_border_copy (border),
6776 (GDestroyNotify) gtk_border_free);
6778 g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL);
6780 g_object_notify (G_OBJECT (entry), "inner-border");
6784 * gtk_entry_get_inner_border:
6785 * @entry: a #GtkEntry
6787 * This function returns the entry's #GtkEntry:inner-border property. See
6788 * gtk_entry_set_inner_border() for more information.
6790 * Return value: the entry's #GtkBorder, or %NULL if none was set.
6794 G_CONST_RETURN GtkBorder *
6795 gtk_entry_get_inner_border (GtkEntry *entry)
6797 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6799 return g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
6803 * gtk_entry_get_layout:
6804 * @entry: a #GtkEntry
6806 * Gets the #PangoLayout used to display the entry.
6807 * The layout is useful to e.g. convert text positions to
6808 * pixel positions, in combination with gtk_entry_get_layout_offsets().
6809 * The returned layout is owned by the entry and must not be
6810 * modified or freed by the caller.
6812 * Keep in mind that the layout text may contain a preedit string, so
6813 * gtk_entry_layout_index_to_text_index() and
6814 * gtk_entry_text_index_to_layout_index() are needed to convert byte
6815 * indices in the layout to byte indices in the entry contents.
6817 * Return value: the #PangoLayout for this entry
6820 gtk_entry_get_layout (GtkEntry *entry)
6822 PangoLayout *layout;
6824 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6826 layout = gtk_entry_ensure_layout (entry, TRUE);
6833 * gtk_entry_layout_index_to_text_index:
6834 * @entry: a #GtkEntry
6835 * @layout_index: byte index into the entry layout text
6837 * Converts from a position in the entry contents (returned
6838 * by gtk_entry_get_text()) to a position in the
6839 * entry's #PangoLayout (returned by gtk_entry_get_layout(),
6840 * with text retrieved via pango_layout_get_text()).
6842 * Return value: byte index into the entry contents
6845 gtk_entry_layout_index_to_text_index (GtkEntry *entry,
6848 PangoLayout *layout;
6852 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6854 layout = gtk_entry_ensure_layout (entry, TRUE);
6855 text = pango_layout_get_text (layout);
6856 cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
6858 if (layout_index >= cursor_index && entry->preedit_length)
6860 if (layout_index >= cursor_index + entry->preedit_length)
6861 layout_index -= entry->preedit_length;
6863 layout_index = cursor_index;
6866 return layout_index;
6870 * gtk_entry_text_index_to_layout_index:
6871 * @entry: a #GtkEntry
6872 * @text_index: byte index into the entry contents
6874 * Converts from a position in the entry's #PangoLayout (returned by
6875 * gtk_entry_get_layout()) to a position in the entry contents
6876 * (returned by gtk_entry_get_text()).
6878 * Return value: byte index into the entry layout text
6881 gtk_entry_text_index_to_layout_index (GtkEntry *entry,
6884 PangoLayout *layout;
6887 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6889 layout = gtk_entry_ensure_layout (entry, TRUE);
6890 text = pango_layout_get_text (layout);
6891 cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
6893 if (text_index > cursor_index)
6894 text_index += entry->preedit_length;
6900 * gtk_entry_get_layout_offsets:
6901 * @entry: a #GtkEntry
6902 * @x: location to store X offset of layout, or %NULL
6903 * @y: location to store Y offset of layout, or %NULL
6906 * Obtains the position of the #PangoLayout used to render text
6907 * in the entry, in widget coordinates. Useful if you want to line
6908 * up the text in an entry with some other text, e.g. when using the
6909 * entry to implement editable cells in a sheet widget.
6911 * Also useful to convert mouse events into coordinates inside the
6912 * #PangoLayout, e.g. to take some action if some part of the entry text
6915 * Note that as the user scrolls around in the entry the offsets will
6916 * change; you'll need to connect to the "notify::scroll-offset"
6917 * signal to track this. Remember when using the #PangoLayout
6918 * functions you need to convert to and from pixels using
6919 * PANGO_PIXELS() or #PANGO_SCALE.
6921 * Keep in mind that the layout text may contain a preedit string, so
6922 * gtk_entry_layout_index_to_text_index() and
6923 * gtk_entry_text_index_to_layout_index() are needed to convert byte
6924 * indices in the layout to byte indices in the entry contents.
6927 gtk_entry_get_layout_offsets (GtkEntry *entry,
6931 gint text_area_x, text_area_y;
6933 g_return_if_fail (GTK_IS_ENTRY (entry));
6935 /* this gets coords relative to text area */
6936 get_layout_position (entry, x, y);
6938 /* convert to widget coords */
6939 gtk_entry_get_text_area_size (entry, &text_area_x, &text_area_y, NULL, NULL);
6950 * gtk_entry_set_alignment:
6951 * @entry: a #GtkEntry
6952 * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
6953 * Reversed for RTL layouts
6955 * Sets the alignment for the contents of the entry. This controls
6956 * the horizontal positioning of the contents when the displayed
6957 * text is shorter than the width of the entry.
6962 gtk_entry_set_alignment (GtkEntry *entry, gfloat xalign)
6964 GtkEntryPrivate *priv;
6966 g_return_if_fail (GTK_IS_ENTRY (entry));
6968 priv = GTK_ENTRY_GET_PRIVATE (entry);
6972 else if (xalign > 1.0)
6975 if (xalign != priv->xalign)
6977 priv->xalign = xalign;
6979 gtk_entry_recompute (entry);
6981 g_object_notify (G_OBJECT (entry), "xalign");
6986 * gtk_entry_get_alignment:
6987 * @entry: a #GtkEntry
6989 * Gets the value set by gtk_entry_set_alignment().
6991 * Return value: the alignment
6996 gtk_entry_get_alignment (GtkEntry *entry)
6998 GtkEntryPrivate *priv;
7000 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
7002 priv = GTK_ENTRY_GET_PRIVATE (entry);
7004 return priv->xalign;
7008 * gtk_entry_set_icon_from_pixbuf:
7009 * @entry: a #GtkEntry
7010 * @icon_pos: Icon position
7011 * @pixbuf: A #GdkPixbuf, or %NULL
7013 * Sets the icon shown in the specified position using a pixbuf.
7015 * If @pixbuf is %NULL, no icon will be shown in the specified position.
7020 gtk_entry_set_icon_from_pixbuf (GtkEntry *entry,
7021 GtkEntryIconPosition icon_pos,
7024 GtkEntryPrivate *priv;
7025 EntryIconInfo *icon_info;
7027 g_return_if_fail (GTK_IS_ENTRY (entry));
7028 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7030 priv = GTK_ENTRY_GET_PRIVATE (entry);
7032 if ((icon_info = priv->icons[icon_pos]) == NULL)
7033 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7035 g_object_freeze_notify (G_OBJECT (entry));
7038 g_object_ref (pixbuf);
7040 gtk_entry_clear (entry, icon_pos);
7044 icon_info->storage_type = GTK_IMAGE_PIXBUF;
7045 icon_info->pixbuf = pixbuf;
7047 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7049 g_object_notify (G_OBJECT (entry), "pixbuf-primary");
7050 g_object_notify (G_OBJECT (entry), "storage-type-primary");
7054 g_object_notify (G_OBJECT (entry), "pixbuf-secondary");
7055 g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7059 gtk_entry_ensure_pixbuf (entry, icon_pos);
7061 if (GTK_WIDGET_VISIBLE (entry))
7062 gtk_widget_queue_resize (GTK_WIDGET (entry));
7064 g_object_thaw_notify (G_OBJECT (entry));
7068 * gtk_entry_set_icon_from_stock:
7069 * @entry: A #GtkEntry
7070 * @icon_pos: Icon position
7071 * @stock_id: The name of the stock item, or %NULL
7073 * Sets the icon shown in the entry at the specified position from
7076 * If @stock_id is %NULL, no icon will be shown in the specified position.
7081 gtk_entry_set_icon_from_stock (GtkEntry *entry,
7082 GtkEntryIconPosition icon_pos,
7083 const gchar *stock_id)
7085 GtkEntryPrivate *priv;
7086 EntryIconInfo *icon_info;
7089 g_return_if_fail (GTK_IS_ENTRY (entry));
7090 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7092 priv = GTK_ENTRY_GET_PRIVATE (entry);
7094 if ((icon_info = priv->icons[icon_pos]) == NULL)
7095 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7097 g_object_freeze_notify (G_OBJECT (entry));
7099 gtk_widget_ensure_style (GTK_WIDGET (entry));
7101 /* need to dup before clearing */
7102 new_id = g_strdup (stock_id);
7104 gtk_entry_clear (entry, icon_pos);
7108 icon_info->storage_type = GTK_IMAGE_STOCK;
7109 icon_info->stock_id = new_id;
7111 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7113 g_object_notify (G_OBJECT (entry), "stock-primary");
7114 g_object_notify (G_OBJECT (entry), "storage-type-primary");
7118 g_object_notify (G_OBJECT (entry), "stock-secondary");
7119 g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7123 gtk_entry_ensure_pixbuf (entry, icon_pos);
7125 if (GTK_WIDGET_VISIBLE (entry))
7126 gtk_widget_queue_resize (GTK_WIDGET (entry));
7128 g_object_thaw_notify (G_OBJECT (entry));
7132 * gtk_entry_set_icon_from_icon_name:
7133 * @entry: A #GtkEntry
7134 * @icon_pos: The position at which to set the icon
7135 * @icon_name: An icon name, or %NULL
7137 * Sets the icon shown in the entry at the specified position
7138 * from the current icon theme.
7140 * If the icon name isn't known, a "broken image" icon will be displayed
7143 * If @icon_name is %NULL, no icon will be shown in the specified position.
7148 gtk_entry_set_icon_from_icon_name (GtkEntry *entry,
7149 GtkEntryIconPosition icon_pos,
7150 const gchar *icon_name)
7152 GtkEntryPrivate *priv;
7153 EntryIconInfo *icon_info;
7156 g_return_if_fail (GTK_IS_ENTRY (entry));
7157 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7159 priv = GTK_ENTRY_GET_PRIVATE (entry);
7161 if ((icon_info = priv->icons[icon_pos]) == NULL)
7162 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7164 g_object_freeze_notify (G_OBJECT (entry));
7166 gtk_widget_ensure_style (GTK_WIDGET (entry));
7168 /* need to dup before clearing */
7169 new_name = g_strdup (icon_name);
7171 gtk_entry_clear (entry, icon_pos);
7173 if (new_name != NULL)
7175 icon_info->storage_type = GTK_IMAGE_ICON_NAME;
7176 icon_info->icon_name = new_name;
7178 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7180 g_object_notify (G_OBJECT (entry), "icon-name-primary");
7181 g_object_notify (G_OBJECT (entry), "storage-type-primary");
7185 g_object_notify (G_OBJECT (entry), "icon-name-secondary");
7186 g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7190 gtk_entry_ensure_pixbuf (entry, icon_pos);
7192 if (GTK_WIDGET_VISIBLE (entry))
7193 gtk_widget_queue_resize (GTK_WIDGET (entry));
7195 g_object_thaw_notify (G_OBJECT (entry));
7199 * gtk_entry_set_icon_from_gicon:
7200 * @entry: A #GtkEntry
7201 * @icon_pos: The position at which to set the icon
7202 * @icon: The icon to set, or %NULL
7204 * Sets the icon shown in the entry at the specified position
7205 * from the current icon theme.
7206 * If the icon isn't known, a "broken image" icon will be displayed
7209 * If @icon is %NULL, no icon will be shown in the specified position.
7214 gtk_entry_set_icon_from_gicon (GtkEntry *entry,
7215 GtkEntryIconPosition icon_pos,
7218 GtkEntryPrivate *priv;
7219 EntryIconInfo *icon_info;
7221 g_return_if_fail (GTK_IS_ENTRY (entry));
7222 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7224 priv = GTK_ENTRY_GET_PRIVATE (entry);
7226 if ((icon_info = priv->icons[icon_pos]) == NULL)
7227 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7229 g_object_freeze_notify (G_OBJECT (entry));
7231 /* need to ref before clearing */
7233 g_object_ref (icon);
7235 gtk_entry_clear (entry, icon_pos);
7239 icon_info->storage_type = GTK_IMAGE_GICON;
7240 icon_info->gicon = icon;
7242 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7244 g_object_notify (G_OBJECT (entry), "gicon-primary");
7245 g_object_notify (G_OBJECT (entry), "storage-type-primary");
7249 g_object_notify (G_OBJECT (entry), "gicon-secondary");
7250 g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7254 gtk_entry_ensure_pixbuf (entry, icon_pos);
7256 if (GTK_WIDGET_VISIBLE (entry))
7257 gtk_widget_queue_resize (GTK_WIDGET (entry));
7259 g_object_thaw_notify (G_OBJECT (entry));
7263 * gtk_entry_set_icon_activatable:
7264 * @entry: A #GtkEntry
7265 * @icon_pos: Icon position
7266 * @activatable: %TRUE if the icon should be activatable
7268 * Sets whether the icon is activatable.
7273 gtk_entry_set_icon_activatable (GtkEntry *entry,
7274 GtkEntryIconPosition icon_pos,
7275 gboolean activatable)
7277 GtkEntryPrivate *priv;
7278 EntryIconInfo *icon_info;
7280 g_return_if_fail (GTK_IS_ENTRY (entry));
7281 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7283 priv = GTK_ENTRY_GET_PRIVATE (entry);
7285 if ((icon_info = priv->icons[icon_pos]) == NULL)
7286 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7288 activatable = activatable != FALSE;
7290 if (icon_info->nonactivatable != !activatable)
7292 icon_info->nonactivatable = !activatable;
7294 if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry)))
7295 update_cursors (GTK_WIDGET (entry));
7297 g_object_notify (G_OBJECT (entry),
7298 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "activatable-primary" : "activatable-secondary");
7303 * gtk_entry_get_icon_activatable:
7304 * @entry: a #GtkEntry
7305 * @icon_pos: Icon position
7307 * Returns whether the icon is activatable.
7309 * Returns: %TRUE if the icon is activatable.
7314 gtk_entry_get_icon_activatable (GtkEntry *entry,
7315 GtkEntryIconPosition icon_pos)
7317 GtkEntryPrivate *priv;
7318 EntryIconInfo *icon_info;
7320 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
7321 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), FALSE);
7323 priv = GTK_ENTRY_GET_PRIVATE (entry);
7324 icon_info = priv->icons[icon_pos];
7326 return (icon_info != NULL && !icon_info->nonactivatable);
7330 * gtk_entry_get_pixbuf:
7331 * @entry: A #GtkEntry
7332 * @icon_pos: Icon position
7334 * Retrieves the image used for the icon.
7336 * Unlike the other methods of setting and getting icon data, this
7337 * method will work regardless of whether the icon was set using a
7338 * #GdkPixbuf, a #GIcon, a stock item, or an icon name.
7340 * Returns: A #GdkPixbuf, or %NULL if no icon is set for this position.
7345 gtk_entry_get_pixbuf (GtkEntry *entry,
7346 GtkEntryIconPosition icon_pos)
7348 GtkEntryPrivate *priv;
7349 EntryIconInfo *icon_info;
7351 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7352 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7354 priv = GTK_ENTRY_GET_PRIVATE (entry);
7355 icon_info = priv->icons[icon_pos];
7360 gtk_entry_ensure_pixbuf (entry, icon_pos);
7362 return icon_info->pixbuf;
7366 * gtk_entry_get_gicon:
7367 * @entry: A #GtkEntry
7368 * @icon_pos: Icon position
7370 * Retrieves the #GIcon used for the icon, or %NULL if there is
7371 * no icon or if the icon was set by some other method (e.g., by
7372 * stock, pixbuf, or icon name).
7374 * Returns: A #GIcon, or %NULL if no icon is set or if the icon
7380 gtk_entry_get_gicon (GtkEntry *entry,
7381 GtkEntryIconPosition icon_pos)
7383 GtkEntryPrivate *priv;
7384 EntryIconInfo *icon_info;
7386 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7387 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7389 priv = GTK_ENTRY_GET_PRIVATE (entry);
7390 icon_info = priv->icons[icon_pos];
7395 return icon_info->storage_type == GTK_IMAGE_GICON ? icon_info->gicon : NULL;
7399 * gtk_entry_get_stock:
7400 * @entry: A #GtkEntry
7401 * @icon_pos: Icon position
7403 * Retrieves the stock id used for the icon, or %NULL if there is
7404 * no icon or if the icon was set by some other method (e.g., by
7405 * pixbuf, icon name or gicon).
7407 * Returns: A stock id, or %NULL if no icon is set or if the icon
7408 * wasn't set from a stock id
7413 gtk_entry_get_stock (GtkEntry *entry,
7414 GtkEntryIconPosition icon_pos)
7416 GtkEntryPrivate *priv;
7417 EntryIconInfo *icon_info;
7419 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7420 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7422 priv = GTK_ENTRY_GET_PRIVATE (entry);
7423 icon_info = priv->icons[icon_pos];
7428 return icon_info->storage_type == GTK_IMAGE_STOCK ? icon_info->stock_id : NULL;
7432 * gtk_entry_get_icon_name:
7433 * @entry: A #GtkEntry
7434 * @icon_pos: Icon position
7436 * Retrieves the icon name used for the icon, or %NULL if there is
7437 * no icon or if the icon was set by some other method (e.g., by
7438 * pixbuf, stock or gicon).
7440 * Returns: An icon name, or %NULL if no icon is set or if the icon
7441 * wasn't set from an icon name
7446 gtk_entry_get_icon_name (GtkEntry *entry,
7447 GtkEntryIconPosition icon_pos)
7449 GtkEntryPrivate *priv;
7450 EntryIconInfo *icon_info;
7452 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7453 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7455 priv = GTK_ENTRY_GET_PRIVATE (entry);
7456 icon_info = priv->icons[icon_pos];
7461 return icon_info->storage_type == GTK_IMAGE_ICON_NAME ? icon_info->icon_name : NULL;
7465 * gtk_entry_set_icon_sensitive:
7466 * @entry: A #GtkEntry
7467 * @icon_pos: Icon position
7468 * @sensitive: Specifies whether the icon should appear
7469 * sensitive or insensitive
7471 * Sets the sensitivity for the specified icon.
7476 gtk_entry_set_icon_sensitive (GtkEntry *entry,
7477 GtkEntryIconPosition icon_pos,
7480 GtkEntryPrivate *priv;
7481 EntryIconInfo *icon_info;
7483 g_return_if_fail (GTK_IS_ENTRY (entry));
7484 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7486 priv = GTK_ENTRY_GET_PRIVATE (entry);
7488 if ((icon_info = priv->icons[icon_pos]) == NULL)
7489 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7491 if (icon_info->insensitive != !sensitive)
7493 icon_info->insensitive = !sensitive;
7495 if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry)))
7496 update_cursors (GTK_WIDGET (entry));
7498 g_object_notify (G_OBJECT (entry),
7499 icon_pos == GTK_ENTRY_ICON_PRIMARY ? "sensitive-primary" : "sensitive-secondary");
7504 * gtk_entry_get_icon_sensitive:
7505 * @entry: a #GtkEntry
7506 * @icon_pos: Icon position
7508 * Returns whether the icon appears sensitive or insensitive.
7510 * Returns: %TRUE if the icon is sensitive.
7515 gtk_entry_get_icon_sensitive (GtkEntry *entry,
7516 GtkEntryIconPosition icon_pos)
7518 GtkEntryPrivate *priv;
7519 EntryIconInfo *icon_info;
7521 g_return_val_if_fail (GTK_IS_ENTRY (entry), TRUE);
7522 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), TRUE);
7524 priv = GTK_ENTRY_GET_PRIVATE (entry);
7525 icon_info = priv->icons[icon_pos];
7527 return (!icon_info || !icon_info->insensitive);
7532 * gtk_entry_get_storage_type:
7533 * @entry: a #GtkEntry
7534 * @icon_pos: Icon position
7536 * Gets the type of representation being used by the icon
7537 * to store image data. If the icon has no image data,
7538 * the return value will be %GTK_IMAGE_EMPTY.
7540 * Return value: image representation being used
7545 gtk_entry_get_storage_type (GtkEntry *entry,
7546 GtkEntryIconPosition icon_pos)
7548 GtkEntryPrivate *priv;
7549 EntryIconInfo *icon_info;
7551 g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_IMAGE_EMPTY);
7552 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), GTK_IMAGE_EMPTY);
7554 priv = GTK_ENTRY_GET_PRIVATE (entry);
7555 icon_info = priv->icons[icon_pos];
7558 return GTK_IMAGE_EMPTY;
7560 return icon_info->storage_type;
7564 * gtk_entry_get_icon_at_pos:
7565 * @entry: a #GtkEntry
7566 * @x: the x coordinate of the position to find
7567 * @y: the y coordinate of the position to find
7569 * Finds the icon at the given position and return its index.
7570 * If @x, @y doesn't lie inside an icon, -1 is returned.
7571 * This function is intended for use in a #GtkWidget::query-tooltip
7574 * Returns: the index of the icon at the given position, or -1
7579 gtk_entry_get_icon_at_pos (GtkEntry *entry,
7583 GtkAllocation primary;
7584 GtkAllocation secondary;
7586 g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
7588 get_icon_allocations (entry, &primary, &secondary);
7590 if (primary.x <= x && x < primary.x + primary.width &&
7591 primary.y <= y && y < primary.y + primary.height)
7592 return GTK_ENTRY_ICON_PRIMARY;
7594 if (secondary.x <= x && x < secondary.x + secondary.width &&
7595 secondary.y <= y && y < secondary.y + secondary.height)
7596 return GTK_ENTRY_ICON_SECONDARY;
7602 * gtk_entry_set_icon_drag_source:
7603 * @entry: a #GtkIconEntry
7604 * @icon_pos: icon position
7605 * @target_list: the targets (data formats) in which the data can be provided
7606 * @actions: a bitmask of the allowed drag actions
7608 * Sets up the icon at the given position so that GTK+ will start a drag
7609 * operation when the user clicks and drags the icon.
7611 * To handle the drag operation, you need to connect to the usual
7612 * #GtkWidget::drag-data-get (or possibly #GtkWidget::drag-data-delete)
7613 * signal, and use gtk_entry_get_current_icon_drag_source() in
7614 * your signal handler to find out if the drag was started from
7617 * By default, GTK+ uses the icon as the drag icon. You can use the
7618 * #GtkWidget::drag-begin signal to set a different icon. Note that you
7619 * have to use g_signal_connect_after() to ensure that your signal handler
7620 * gets executed after the default handler.
7623 gtk_entry_set_icon_drag_source (GtkEntry *entry,
7624 GtkEntryIconPosition icon_pos,
7625 GtkTargetList *target_list,
7626 GdkDragAction actions)
7628 GtkEntryPrivate *priv;
7629 EntryIconInfo *icon_info;
7631 g_return_if_fail (GTK_IS_ENTRY (entry));
7632 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7634 priv = GTK_ENTRY_GET_PRIVATE (entry);
7636 if ((icon_info = priv->icons[icon_pos]) == NULL)
7637 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7639 if (icon_info->target_list)
7640 gtk_target_list_unref (icon_info->target_list);
7641 icon_info->target_list = target_list;
7642 if (icon_info->target_list)
7643 gtk_target_list_ref (icon_info->target_list);
7645 icon_info->actions = actions;
7649 * gtk_entry_get_current_icon_drag_source:
7650 * @entry: a #GtkIconEntry
7652 * Returns the index of the icon which is the source of the current
7653 * DND operation, or -1.
7655 * This function is meant to be used in a #GtkWidget::drag-data-get
7658 * Returns: index of the icon which is the source of the current
7659 * DND operation, or -1.
7662 gtk_entry_get_current_icon_drag_source (GtkEntry *entry)
7664 GtkEntryPrivate *priv;
7665 EntryIconInfo *icon_info = NULL;
7668 g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
7670 priv = GTK_ENTRY_GET_PRIVATE (entry);
7672 for (i = 0; i < MAX_ICONS; i++)
7674 if ((icon_info = priv->icons[i]))
7676 if (icon_info->in_drag)
7685 ensure_has_tooltip (GtkEntry *entry)
7687 GtkEntryPrivate *priv;
7688 EntryIconInfo *icon_info;
7690 gboolean has_tooltip = FALSE;
7692 priv = GTK_ENTRY_GET_PRIVATE (entry);
7694 for (i = 0; i < MAX_ICONS; i++)
7696 if ((icon_info = priv->icons[i]) != NULL)
7698 if (icon_info->tooltip != NULL)
7706 gtk_widget_set_has_tooltip (GTK_WIDGET (entry), has_tooltip);
7710 * gtk_entry_set_icon_tooltip_text:
7711 * @entry: a #GtkEntry
7712 * @icon_pos: the icon position
7713 * @tooltip: the contents of the tooltip for the icon, or %NULL
7715 * Sets @tooltip as the contents of the tooltip for the icon
7716 * at the specified position.
7718 * Use %NULL for @tooltip to remove an existing tooltip.
7720 * See also gtk_widget_set_tooltip_text() and
7721 * gtk_entry_set_icon_tooltip_markup().
7726 gtk_entry_set_icon_tooltip_text (GtkEntry *entry,
7727 GtkEntryIconPosition icon_pos,
7728 const gchar *tooltip)
7730 GtkEntryPrivate *priv;
7731 EntryIconInfo *icon_info;
7733 g_return_if_fail (GTK_IS_ENTRY (entry));
7734 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7736 priv = GTK_ENTRY_GET_PRIVATE (entry);
7738 if (!(icon_info = priv->icons[icon_pos]))
7739 icon_info = priv->icons[icon_pos];
7741 if (icon_info->tooltip)
7742 g_free (icon_info->tooltip);
7744 icon_info->tooltip = tooltip ? g_markup_escape_text (tooltip, -1) : NULL;
7746 ensure_has_tooltip (entry);
7750 * gtk_entry_set_icon_tooltip_markup:
7751 * @entry: a #GtkEntry
7752 * @icon_pos: the icon position
7753 * @tooltip: the contents of the tooltip for the icon, or %NULL
7755 * Sets @tooltip as the contents of the tooltip for the icon at
7756 * the specified position. @tooltip is assumed to be marked up with
7757 * the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
7759 * Use %NULL for @tooltip to remove an existing tooltip.
7761 * See also gtk_widget_set_tooltip_markup() and
7762 * gtk_enty_set_icon_tooltip_text().
7767 gtk_entry_set_icon_tooltip_markup (GtkEntry *entry,
7768 GtkEntryIconPosition icon_pos,
7769 const gchar *tooltip)
7771 GtkEntryPrivate *priv;
7772 EntryIconInfo *icon_info;
7774 g_return_if_fail (GTK_IS_ENTRY (entry));
7775 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7777 priv = GTK_ENTRY_GET_PRIVATE (entry);
7779 if (!(icon_info = priv->icons[icon_pos]))
7780 icon_info = priv->icons[icon_pos];
7782 if (icon_info->tooltip)
7783 g_free (icon_info->tooltip);
7785 icon_info->tooltip = g_strdup (tooltip);
7787 ensure_has_tooltip (entry);
7791 gtk_entry_query_tooltip (GtkWidget *widget,
7794 gboolean keyboard_tip,
7795 GtkTooltip *tooltip)
7798 GtkEntryPrivate *priv;
7799 EntryIconInfo *icon_info;
7802 entry = GTK_ENTRY (widget);
7803 priv = GTK_ENTRY_GET_PRIVATE (entry);
7807 icon_pos = gtk_entry_get_icon_at_pos (entry, x, y);
7810 if ((icon_info = priv->icons[icon_pos]) != NULL)
7812 if (icon_info->tooltip)
7814 gtk_tooltip_set_markup (tooltip, icon_info->tooltip);
7823 return GTK_WIDGET_CLASS (gtk_entry_parent_class)->query_tooltip (widget,
7830 /* Quick hack of a popup menu
7833 activate_cb (GtkWidget *menuitem,
7836 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
7837 g_signal_emit_by_name (entry, signal);
7842 gtk_entry_mnemonic_activate (GtkWidget *widget,
7843 gboolean group_cycling)
7845 gtk_widget_grab_focus (widget);
7850 append_action_signal (GtkEntry *entry,
7852 const gchar *stock_id,
7853 const gchar *signal,
7856 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
7858 g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
7859 g_signal_connect (menuitem, "activate",
7860 G_CALLBACK (activate_cb), entry);
7862 gtk_widget_set_sensitive (menuitem, sensitive);
7864 gtk_widget_show (menuitem);
7865 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
7869 popup_menu_detach (GtkWidget *attach_widget,
7872 GTK_ENTRY (attach_widget)->popup_menu = NULL;
7876 popup_position_func (GtkMenu *menu,
7882 GtkEntry *entry = GTK_ENTRY (user_data);
7883 GtkWidget *widget = GTK_WIDGET (entry);
7885 GtkRequisition menu_req;
7886 GdkRectangle monitor;
7887 GtkBorder inner_border;
7888 gint monitor_num, strong_x, height;
7890 g_return_if_fail (GTK_WIDGET_REALIZED (entry));
7892 gdk_window_get_origin (entry->text_area, x, y);
7894 screen = gtk_widget_get_screen (widget);
7895 monitor_num = gdk_screen_get_monitor_at_window (screen, entry->text_area);
7896 if (monitor_num < 0)
7898 gtk_menu_set_monitor (menu, monitor_num);
7900 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
7901 gtk_widget_size_request (entry->popup_menu, &menu_req);
7902 gdk_drawable_get_size (entry->text_area, NULL, &height);
7903 gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
7904 _gtk_entry_effective_inner_border (entry, &inner_border);
7906 *x += inner_border.left + strong_x - entry->scroll_offset;
7907 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
7908 *x -= menu_req.width;
7910 if ((*y + height + menu_req.height) <= monitor.y + monitor.height)
7912 else if ((*y - menu_req.height) >= monitor.y)
7913 *y -= menu_req.height;
7914 else if (monitor.y + monitor.height - (*y + height) > *y)
7917 *y -= menu_req.height;
7923 unichar_chosen_func (const char *text,
7926 GtkEntry *entry = GTK_ENTRY (data);
7928 if (entry->editable)
7929 gtk_entry_enter_text (entry, text);
7940 popup_targets_received (GtkClipboard *clipboard,
7941 GtkSelectionData *data,
7944 PopupInfo *info = user_data;
7945 GtkEntry *entry = info->entry;
7947 if (GTK_WIDGET_REALIZED (entry))
7949 gboolean clipboard_contains_text;
7950 GtkWidget *menuitem;
7952 gboolean show_input_method_menu;
7953 gboolean show_unicode_menu;
7955 clipboard_contains_text = gtk_selection_data_targets_include_text (data);
7956 if (entry->popup_menu)
7957 gtk_widget_destroy (entry->popup_menu);
7959 entry->popup_menu = gtk_menu_new ();
7961 gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu),
7965 append_action_signal (entry, entry->popup_menu, GTK_STOCK_CUT, "cut-clipboard",
7966 entry->editable && entry->visible && entry->current_pos != entry->selection_bound);
7967 append_action_signal (entry, entry->popup_menu, GTK_STOCK_COPY, "copy-clipboard",
7968 entry->visible && entry->current_pos != entry->selection_bound);
7969 append_action_signal (entry, entry->popup_menu, GTK_STOCK_PASTE, "paste-clipboard",
7970 entry->editable && clipboard_contains_text);
7972 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7973 gtk_widget_set_sensitive (menuitem, entry->editable && entry->current_pos != entry->selection_bound);
7974 g_signal_connect_swapped (menuitem, "activate",
7975 G_CALLBACK (gtk_entry_delete_cb), entry);
7976 gtk_widget_show (menuitem);
7977 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7979 menuitem = gtk_separator_menu_item_new ();
7980 gtk_widget_show (menuitem);
7981 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7983 menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
7984 g_signal_connect_swapped (menuitem, "activate",
7985 G_CALLBACK (gtk_entry_select_all), entry);
7986 gtk_widget_show (menuitem);
7987 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7989 g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
7990 "gtk-show-input-method-menu", &show_input_method_menu,
7991 "gtk-show-unicode-menu", &show_unicode_menu,
7994 if (show_input_method_menu || show_unicode_menu)
7996 menuitem = gtk_separator_menu_item_new ();
7997 gtk_widget_show (menuitem);
7998 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
8001 if (show_input_method_menu)
8003 menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
8004 gtk_widget_set_sensitive (menuitem, entry->editable);
8005 gtk_widget_show (menuitem);
8006 submenu = gtk_menu_new ();
8007 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8009 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
8011 gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context),
8012 GTK_MENU_SHELL (submenu));
8015 if (show_unicode_menu)
8017 menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
8018 gtk_widget_set_sensitive (menuitem, entry->editable);
8019 gtk_widget_show (menuitem);
8021 submenu = gtk_menu_new ();
8022 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
8023 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
8025 _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
8026 unichar_chosen_func,
8030 g_signal_emit (entry,
8031 signals[POPULATE_POPUP],
8037 gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
8039 info->button, info->time);
8042 gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
8043 popup_position_func, entry,
8044 info->button, info->time);
8045 gtk_menu_shell_select_first (GTK_MENU_SHELL (entry->popup_menu), FALSE);
8049 g_object_unref (entry);
8050 g_slice_free (PopupInfo, info);
8054 gtk_entry_do_popup (GtkEntry *entry,
8055 GdkEventButton *event)
8057 PopupInfo *info = g_slice_new (PopupInfo);
8059 /* In order to know what entries we should make sensitive, we
8060 * ask for the current targets of the clipboard, and when
8061 * we get them, then we actually pop up the menu.
8063 info->entry = g_object_ref (entry);
8067 info->button = event->button;
8068 info->time = event->time;
8073 info->time = gtk_get_current_event_time ();
8076 gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
8077 gdk_atom_intern_static_string ("TARGETS"),
8078 popup_targets_received,
8083 gtk_entry_popup_menu (GtkWidget *widget)
8085 gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
8090 gtk_entry_drag_begin (GtkWidget *widget,
8091 GdkDragContext *context)
8093 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8096 for (i = 0; i < MAX_ICONS; i++)
8098 EntryIconInfo *icon_info = priv->icons[i];
8100 if (icon_info != NULL)
8102 if (icon_info->in_drag)
8104 switch (icon_info->storage_type)
8106 case GTK_IMAGE_STOCK:
8107 gtk_drag_set_icon_stock (context, icon_info->stock_id, -2, -2);
8110 case GTK_IMAGE_ICON_NAME:
8111 gtk_drag_set_icon_name (context, icon_info->icon_name, -2, -2);
8114 /* FIXME: No GIcon support for dnd icons */
8115 case GTK_IMAGE_GICON:
8116 case GTK_IMAGE_PIXBUF:
8117 gtk_drag_set_icon_pixbuf (context, icon_info->pixbuf, -2, -2);
8120 g_assert_not_reached ();
8128 gtk_entry_drag_end (GtkWidget *widget,
8129 GdkDragContext *context)
8131 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8134 for (i = 0; i < MAX_ICONS; i++)
8136 EntryIconInfo *icon_info = priv->icons[i];
8138 if (icon_info != NULL)
8139 icon_info->in_drag = 0;
8144 gtk_entry_drag_leave (GtkWidget *widget,
8145 GdkDragContext *context,
8148 GtkEntry *entry = GTK_ENTRY (widget);
8150 entry->dnd_position = -1;
8151 gtk_widget_queue_draw (widget);
8155 gtk_entry_drag_drop (GtkWidget *widget,
8156 GdkDragContext *context,
8161 GtkEntry *entry = GTK_ENTRY (widget);
8162 GdkAtom target = GDK_NONE;
8164 if (entry->editable)
8165 target = gtk_drag_dest_find_target (widget, context, NULL);
8167 if (target != GDK_NONE)
8168 gtk_drag_get_data (widget, context, target, time);
8170 gtk_drag_finish (context, FALSE, FALSE, time);
8176 gtk_entry_drag_motion (GtkWidget *widget,
8177 GdkDragContext *context,
8182 GtkEntry *entry = GTK_ENTRY (widget);
8183 GtkWidget *source_widget;
8184 GdkDragAction suggested_action;
8185 gint new_position, old_position;
8188 x -= widget->style->xthickness;
8189 y -= widget->style->ythickness;
8191 old_position = entry->dnd_position;
8192 new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
8194 if (entry->editable &&
8195 gtk_drag_dest_find_target (widget, context, NULL) != GDK_NONE)
8197 source_widget = gtk_drag_get_source_widget (context);
8198 suggested_action = context->suggested_action;
8200 if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
8201 new_position < sel1 || new_position > sel2)
8203 if (source_widget == widget)
8205 /* Default to MOVE, unless the user has
8206 * pressed ctrl or alt to affect available actions
8208 if ((context->actions & GDK_ACTION_MOVE) != 0)
8209 suggested_action = GDK_ACTION_MOVE;
8212 entry->dnd_position = new_position;
8216 if (source_widget == widget)
8217 suggested_action = 0; /* Can't drop in selection where drag started */
8219 entry->dnd_position = -1;
8224 /* Entry not editable, or no text */
8225 suggested_action = 0;
8226 entry->dnd_position = -1;
8229 gdk_drag_status (context, suggested_action, time);
8231 if (entry->dnd_position != old_position)
8232 gtk_widget_queue_draw (widget);
8238 gtk_entry_drag_data_received (GtkWidget *widget,
8239 GdkDragContext *context,
8242 GtkSelectionData *selection_data,
8246 GtkEntry *entry = GTK_ENTRY (widget);
8247 GtkEditable *editable = GTK_EDITABLE (widget);
8250 str = (gchar *) gtk_selection_data_get_text (selection_data);
8252 x -= widget->style->xthickness;
8253 y -= widget->style->ythickness;
8255 if (str && entry->editable)
8261 if (entry->truncate_multiline)
8262 length = truncate_multiline (str);
8264 new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
8266 if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
8267 new_position < sel1 || new_position > sel2)
8269 gtk_editable_insert_text (editable, str, length, &new_position);
8273 /* Replacing selection */
8274 begin_change (entry);
8275 g_object_freeze_notify (G_OBJECT (entry));
8276 gtk_editable_delete_text (editable, sel1, sel2);
8277 gtk_editable_insert_text (editable, str, length, &sel1);
8278 g_object_thaw_notify (G_OBJECT (entry));
8282 gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, time);
8286 /* Drag and drop didn't happen! */
8287 gtk_drag_finish (context, FALSE, FALSE, time);
8294 gtk_entry_drag_data_get (GtkWidget *widget,
8295 GdkDragContext *context,
8296 GtkSelectionData *selection_data,
8300 gint sel_start, sel_end;
8303 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8304 GtkEditable *editable = GTK_EDITABLE (widget);
8306 /* If there is an icon drag going on, exit early. */
8307 for (i = 0; i < MAX_ICONS; i++)
8309 EntryIconInfo *icon_info = priv->icons[i];
8311 if (icon_info != NULL)
8313 if (icon_info->in_drag)
8318 if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
8320 gchar *str = gtk_entry_get_public_chars (GTK_ENTRY (widget), sel_start, sel_end);
8322 gtk_selection_data_set_text (selection_data, str, -1);
8330 gtk_entry_drag_data_delete (GtkWidget *widget,
8331 GdkDragContext *context)
8333 gint sel_start, sel_end;
8336 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8337 GtkEditable *editable = GTK_EDITABLE (widget);
8339 /* If there is an icon drag going on, exit early. */
8340 for (i = 0; i < MAX_ICONS; i++)
8342 EntryIconInfo *icon_info = priv->icons[i];
8344 if (icon_info != NULL)
8346 if (icon_info->in_drag)
8351 if (GTK_ENTRY (widget)->editable &&
8352 gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
8353 gtk_editable_delete_text (editable, sel_start, sel_end);
8356 /* We display the cursor when
8358 * - the selection is empty, AND
8359 * - the widget has focus
8362 #define CURSOR_ON_MULTIPLIER 2
8363 #define CURSOR_OFF_MULTIPLIER 1
8364 #define CURSOR_PEND_MULTIPLIER 3
8365 #define CURSOR_DIVIDER 3
8368 cursor_blinks (GtkEntry *entry)
8370 if (GTK_WIDGET_HAS_FOCUS (entry) &&
8372 entry->selection_bound == entry->current_pos)
8374 GtkSettings *settings;
8377 settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8378 g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
8387 get_cursor_time (GtkEntry *entry)
8389 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8392 g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
8398 get_cursor_blink_timeout (GtkEntry *entry)
8400 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8403 g_object_get (settings, "gtk-cursor-blink-timeout", &timeout, NULL);
8409 show_cursor (GtkEntry *entry)
8411 if (!entry->cursor_visible)
8413 entry->cursor_visible = TRUE;
8415 if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
8416 gtk_widget_queue_draw (GTK_WIDGET (entry));
8421 hide_cursor (GtkEntry *entry)
8423 if (entry->cursor_visible)
8425 entry->cursor_visible = FALSE;
8427 if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
8428 gtk_widget_queue_draw (GTK_WIDGET (entry));
8436 blink_cb (gpointer data)
8439 GtkEntryPrivate *priv;
8442 entry = GTK_ENTRY (data);
8443 priv = GTK_ENTRY_GET_PRIVATE (entry);
8445 if (!GTK_WIDGET_HAS_FOCUS (entry))
8447 g_warning ("GtkEntry - did not receive focus-out-event. If you\n"
8448 "connect a handler to this signal, it must return\n"
8449 "FALSE so the entry gets the event as well");
8451 gtk_entry_check_cursor_blink (entry);
8456 g_assert (entry->selection_bound == entry->current_pos);
8458 blink_timeout = get_cursor_blink_timeout (entry);
8459 if (priv->blink_time > 1000 * blink_timeout &&
8460 blink_timeout < G_MAXINT/1000)
8462 /* we've blinked enough without the user doing anything, stop blinking */
8463 show_cursor (entry);
8464 entry->blink_timeout = 0;
8466 else if (entry->cursor_visible)
8468 hide_cursor (entry);
8469 entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
8475 show_cursor (entry);
8476 priv->blink_time += get_cursor_time (entry);
8477 entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
8482 /* Remove ourselves */
8487 gtk_entry_check_cursor_blink (GtkEntry *entry)
8489 GtkEntryPrivate *priv;
8491 priv = GTK_ENTRY_GET_PRIVATE (entry);
8493 if (cursor_blinks (entry))
8495 if (!entry->blink_timeout)
8497 show_cursor (entry);
8498 entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
8505 if (entry->blink_timeout)
8507 g_source_remove (entry->blink_timeout);
8508 entry->blink_timeout = 0;
8511 entry->cursor_visible = TRUE;
8517 gtk_entry_pend_cursor_blink (GtkEntry *entry)
8519 if (cursor_blinks (entry))
8521 if (entry->blink_timeout != 0)
8522 g_source_remove (entry->blink_timeout);
8524 entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
8527 show_cursor (entry);
8532 gtk_entry_reset_blink_time (GtkEntry *entry)
8534 GtkEntryPrivate *priv;
8536 priv = GTK_ENTRY_GET_PRIVATE (entry);
8538 priv->blink_time = 0;
8544 gtk_entry_completion_timeout (gpointer data)
8546 GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
8548 completion->priv->completion_timeout = 0;
8550 if (completion->priv->filter_model &&
8551 g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)), -1)
8552 >= completion->priv->minimum_key_length)
8556 GtkTreeSelection *s;
8557 gboolean popup_single;
8559 gtk_entry_completion_complete (completion);
8560 matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
8562 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8564 s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
8566 gtk_tree_selection_unselect_all (s);
8568 actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
8570 g_object_get (completion, "popup-single-match", &popup_single, NULL);
8571 if ((matches > (popup_single ? 0: 1)) || actions > 0)
8573 if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8574 _gtk_entry_completion_resize_popup (completion);
8576 _gtk_entry_completion_popup (completion);
8579 _gtk_entry_completion_popdown (completion);
8581 else if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8582 _gtk_entry_completion_popdown (completion);
8587 static inline gboolean
8588 keyval_is_cursor_move (guint keyval)
8590 if (keyval == GDK_Up || keyval == GDK_KP_Up)
8593 if (keyval == GDK_Down || keyval == GDK_KP_Down)
8596 if (keyval == GDK_Page_Up)
8599 if (keyval == GDK_Page_Down)
8606 gtk_entry_completion_key_press (GtkWidget *widget,
8610 gint matches, actions = 0;
8611 GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
8613 if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
8616 matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
8618 if (completion->priv->actions)
8619 actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
8621 if (keyval_is_cursor_move (event->keyval))
8623 GtkTreePath *path = NULL;
8625 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
8627 if (completion->priv->current_selected < 0)
8628 completion->priv->current_selected = matches + actions - 1;
8630 completion->priv->current_selected--;
8632 else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
8634 if (completion->priv->current_selected < matches + actions - 1)
8635 completion->priv->current_selected++;
8637 completion->priv->current_selected = -1;
8639 else if (event->keyval == GDK_Page_Up)
8641 if (completion->priv->current_selected < 0)
8642 completion->priv->current_selected = matches + actions - 1;
8643 else if (completion->priv->current_selected == 0)
8644 completion->priv->current_selected = -1;
8645 else if (completion->priv->current_selected < matches)
8647 completion->priv->current_selected -= 14;
8648 if (completion->priv->current_selected < 0)
8649 completion->priv->current_selected = 0;
8653 completion->priv->current_selected -= 14;
8654 if (completion->priv->current_selected < matches - 1)
8655 completion->priv->current_selected = matches - 1;
8658 else if (event->keyval == GDK_Page_Down)
8660 if (completion->priv->current_selected < 0)
8661 completion->priv->current_selected = 0;
8662 else if (completion->priv->current_selected < matches - 1)
8664 completion->priv->current_selected += 14;
8665 if (completion->priv->current_selected > matches - 1)
8666 completion->priv->current_selected = matches - 1;
8668 else if (completion->priv->current_selected == matches + actions - 1)
8670 completion->priv->current_selected = -1;
8674 completion->priv->current_selected += 14;
8675 if (completion->priv->current_selected > matches + actions - 1)
8676 completion->priv->current_selected = matches + actions - 1;
8680 if (completion->priv->current_selected < 0)
8682 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8683 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
8685 if (completion->priv->inline_selection &&
8686 completion->priv->completion_prefix)
8688 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
8689 completion->priv->completion_prefix);
8690 gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8693 else if (completion->priv->current_selected < matches)
8695 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
8697 path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
8698 gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
8701 if (completion->priv->inline_selection)
8705 GtkTreeModel *model = NULL;
8706 GtkTreeSelection *sel;
8709 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
8710 if (!gtk_tree_selection_get_selected (sel, &model, &iter))
8713 if (completion->priv->completion_prefix == NULL)
8714 completion->priv->completion_prefix = g_strdup (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)));
8716 g_signal_emit_by_name (completion, "cursor-on-match", model,
8720 else if (completion->priv->current_selected - matches >= 0)
8722 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8724 path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
8725 gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
8728 if (completion->priv->inline_selection &&
8729 completion->priv->completion_prefix)
8731 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
8732 completion->priv->completion_prefix);
8733 gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8737 gtk_tree_path_free (path);
8741 else if (event->keyval == GDK_Escape ||
8742 event->keyval == GDK_Left ||
8743 event->keyval == GDK_KP_Left ||
8744 event->keyval == GDK_Right ||
8745 event->keyval == GDK_KP_Right)
8747 gboolean retval = TRUE;
8749 _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8750 _gtk_entry_completion_popdown (completion);
8752 if (completion->priv->current_selected < 0)
8755 goto keypress_completion_out;
8757 else if (completion->priv->inline_selection)
8759 /* Escape rejects the tentative completion */
8760 if (event->keyval == GDK_Escape)
8762 if (completion->priv->completion_prefix)
8763 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
8764 completion->priv->completion_prefix);
8766 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), "");
8769 /* Move the cursor to the end for Right/Esc, to the
8770 beginning for Left */
8771 if (event->keyval == GDK_Right ||
8772 event->keyval == GDK_KP_Right ||
8773 event->keyval == GDK_Escape)
8774 gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8776 gtk_editable_set_position (GTK_EDITABLE (widget), 0);
8779 keypress_completion_out:
8780 if (completion->priv->inline_selection)
8782 g_free (completion->priv->completion_prefix);
8783 completion->priv->completion_prefix = NULL;
8788 else if (event->keyval == GDK_Tab ||
8789 event->keyval == GDK_KP_Tab ||
8790 event->keyval == GDK_ISO_Left_Tab)
8792 GtkDirectionType dir = event->keyval == GDK_ISO_Left_Tab ?
8793 GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
8795 _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8796 _gtk_entry_completion_popdown (completion);
8798 g_free (completion->priv->completion_prefix);
8799 completion->priv->completion_prefix = NULL;
8801 gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir);
8805 else if (event->keyval == GDK_ISO_Enter ||
8806 event->keyval == GDK_KP_Enter ||
8807 event->keyval == GDK_Return)
8809 gboolean retval = TRUE;
8811 _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8812 _gtk_entry_completion_popdown (completion);
8814 if (completion->priv->current_selected < matches)
8817 GtkTreeModel *model = NULL;
8818 GtkTreeSelection *sel;
8821 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
8822 if (gtk_tree_selection_get_selected (sel, &model, &iter))
8824 g_signal_handler_block (widget, completion->priv->changed_id);
8825 g_signal_emit_by_name (completion, "match-selected",
8826 model, &iter, &entry_set);
8827 g_signal_handler_unblock (widget, completion->priv->changed_id);
8833 gtk_tree_model_get (model, &iter,
8834 completion->priv->text_column, &str,
8837 gtk_entry_set_text (GTK_ENTRY (widget), str);
8839 /* move the cursor to the end */
8840 gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8848 else if (completion->priv->current_selected - matches >= 0)
8852 _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8854 path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
8856 g_signal_emit_by_name (completion, "action-activated",
8857 gtk_tree_path_get_indices (path)[0]);
8858 gtk_tree_path_free (path);
8861 g_free (completion->priv->completion_prefix);
8862 completion->priv->completion_prefix = NULL;
8871 gtk_entry_completion_changed (GtkWidget *entry,
8874 GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
8876 /* (re)install completion timeout */
8877 if (completion->priv->completion_timeout)
8878 g_source_remove (completion->priv->completion_timeout);
8880 if (!gtk_entry_get_text (GTK_ENTRY (entry)))
8883 /* no need to normalize for this test */
8884 if (completion->priv->minimum_key_length > 0 &&
8885 strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))) == 0)
8887 if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8888 _gtk_entry_completion_popdown (completion);
8892 completion->priv->completion_timeout =
8893 gdk_threads_add_timeout (COMPLETION_TIMEOUT,
8894 gtk_entry_completion_timeout,
8899 check_completion_callback (GtkEntryCompletion *completion)
8901 completion->priv->check_completion_idle = NULL;
8903 gtk_entry_completion_complete (completion);
8904 gtk_entry_completion_insert_prefix (completion);
8910 clear_completion_callback (GtkEntry *entry,
8913 if (pspec->name == I_("cursor-position") ||
8914 pspec->name == I_("selection-bound"))
8916 GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
8918 completion->priv->has_completion = FALSE;
8923 accept_completion_callback (GtkEntry *entry)
8925 GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
8927 if (completion->priv->has_completion)
8928 gtk_editable_set_position (GTK_EDITABLE (entry),
8929 entry->text_length);
8935 completion_insert_text_callback (GtkEntry *entry,
8939 GtkEntryCompletion *completion)
8941 /* idle to update the selection based on the file list */
8942 if (completion->priv->check_completion_idle == NULL)
8944 completion->priv->check_completion_idle = g_idle_source_new ();
8945 g_source_set_priority (completion->priv->check_completion_idle, G_PRIORITY_HIGH);
8946 g_source_set_closure (completion->priv->check_completion_idle,
8947 g_cclosure_new_object (G_CALLBACK (check_completion_callback),
8948 G_OBJECT (completion)));
8949 g_source_attach (completion->priv->check_completion_idle, NULL);
8954 completion_changed (GtkEntryCompletion *completion,
8958 GtkEntry *entry = GTK_ENTRY (data);
8960 if (pspec->name == I_("popup-completion") ||
8961 pspec->name == I_("inline-completion"))
8963 disconnect_completion_signals (entry, completion);
8964 connect_completion_signals (entry, completion);
8969 disconnect_completion_signals (GtkEntry *entry,
8970 GtkEntryCompletion *completion)
8972 g_signal_handlers_disconnect_by_func (completion,
8973 G_CALLBACK (completion_changed), entry);
8974 if (completion->priv->changed_id > 0 &&
8975 g_signal_handler_is_connected (entry, completion->priv->changed_id))
8977 g_signal_handler_disconnect (entry, completion->priv->changed_id);
8978 completion->priv->changed_id = 0;
8980 g_signal_handlers_disconnect_by_func (entry,
8981 G_CALLBACK (gtk_entry_completion_key_press), completion);
8982 if (completion->priv->insert_text_id > 0 &&
8983 g_signal_handler_is_connected (entry, completion->priv->insert_text_id))
8985 g_signal_handler_disconnect (entry, completion->priv->insert_text_id);
8986 completion->priv->insert_text_id = 0;
8988 g_signal_handlers_disconnect_by_func (entry,
8989 G_CALLBACK (completion_insert_text_callback), completion);
8990 g_signal_handlers_disconnect_by_func (entry,
8991 G_CALLBACK (clear_completion_callback), completion);
8992 g_signal_handlers_disconnect_by_func (entry,
8993 G_CALLBACK (accept_completion_callback), completion);
8997 connect_completion_signals (GtkEntry *entry,
8998 GtkEntryCompletion *completion)
9000 if (completion->priv->popup_completion)
9002 completion->priv->changed_id =
9003 g_signal_connect (entry, "changed",
9004 G_CALLBACK (gtk_entry_completion_changed), completion);
9005 g_signal_connect (entry, "key-press-event",
9006 G_CALLBACK (gtk_entry_completion_key_press), completion);
9009 if (completion->priv->inline_completion)
9011 completion->priv->insert_text_id =
9012 g_signal_connect (entry, "insert-text",
9013 G_CALLBACK (completion_insert_text_callback), completion);
9014 g_signal_connect (entry, "notify",
9015 G_CALLBACK (clear_completion_callback), completion);
9016 g_signal_connect (entry, "activate",
9017 G_CALLBACK (accept_completion_callback), completion);
9018 g_signal_connect (entry, "focus-out-event",
9019 G_CALLBACK (accept_completion_callback), completion);
9022 g_signal_connect (completion, "notify",
9023 G_CALLBACK (completion_changed), entry);
9027 * gtk_entry_set_completion:
9028 * @entry: A #GtkEntry
9029 * @completion: The #GtkEntryCompletion or %NULL
9031 * Sets @completion to be the auxiliary completion object to use with @entry.
9032 * All further configuration of the completion mechanism is done on
9033 * @completion using the #GtkEntryCompletion API. Completion is disabled if
9034 * @completion is set to %NULL.
9039 gtk_entry_set_completion (GtkEntry *entry,
9040 GtkEntryCompletion *completion)
9042 GtkEntryCompletion *old;
9044 g_return_if_fail (GTK_IS_ENTRY (entry));
9045 g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
9047 old = gtk_entry_get_completion (entry);
9049 if (old == completion)
9054 if (old->priv->completion_timeout)
9056 g_source_remove (old->priv->completion_timeout);
9057 old->priv->completion_timeout = 0;
9060 if (GTK_WIDGET_MAPPED (old->priv->popup_window))
9061 _gtk_entry_completion_popdown (old);
9063 disconnect_completion_signals (entry, old);
9064 old->priv->entry = NULL;
9066 g_object_unref (old);
9071 g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), NULL);
9075 /* hook into the entry */
9076 g_object_ref (completion);
9078 connect_completion_signals (entry, completion);
9079 completion->priv->entry = GTK_WIDGET (entry);
9080 g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), completion);
9084 * gtk_entry_get_completion:
9085 * @entry: A #GtkEntry
9087 * Returns the auxiliary completion object currently in use by @entry.
9089 * Return value: The auxiliary completion object currently in use by @entry.
9093 GtkEntryCompletion *
9094 gtk_entry_get_completion (GtkEntry *entry)
9096 GtkEntryCompletion *completion;
9098 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
9100 completion = GTK_ENTRY_COMPLETION (g_object_get_data (G_OBJECT (entry),
9101 GTK_ENTRY_COMPLETION_KEY));
9107 * gtk_entry_set_cursor_hadjustment:
9108 * @entry: a #GtkEntry
9109 * @adjustment: an adjustment which should be adjusted when the cursor
9110 * is moved, or %NULL
9112 * Hooks up an adjustment to the cursor position in an entry, so that when
9113 * the cursor is moved, the adjustment is scrolled to show that position.
9114 * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining
9117 * The adjustment has to be in pixel units and in the same coordinate system
9123 gtk_entry_set_cursor_hadjustment (GtkEntry *entry,
9124 GtkAdjustment *adjustment)
9126 g_return_if_fail (GTK_IS_ENTRY (entry));
9128 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
9131 g_object_ref (adjustment);
9133 g_object_set_qdata_full (G_OBJECT (entry),
9134 quark_cursor_hadjustment,
9140 * gtk_entry_get_cursor_hadjustment:
9141 * @entry: a #GtkEntry
9143 * Retrieves the horizontal cursor adjustment for the entry.
9144 * See gtk_entry_set_cursor_hadjustment().
9146 * Return value: the horizontal cursor adjustment, or %NULL
9147 * if none has been set.
9152 gtk_entry_get_cursor_hadjustment (GtkEntry *entry)
9154 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
9156 return g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
9160 * gtk_entry_set_progress_fraction:
9161 * @entry: a #GtkEntry
9162 * @fraction: fraction of the task that's been completed
9164 * Causes the entry's progress indicator to "fill in" the given
9165 * fraction of the bar. The fraction should be between 0.0 and 1.0,
9171 gtk_entry_set_progress_fraction (GtkEntry *entry,
9174 GtkEntryPrivate *private;
9175 gdouble old_fraction;
9177 g_return_if_fail (GTK_IS_ENTRY (entry));
9179 private = GTK_ENTRY_GET_PRIVATE (entry);
9181 if (private->progress_pulse_mode)
9184 old_fraction = private->progress_fraction;
9186 fraction = CLAMP (fraction, 0.0, 1.0);
9188 private->progress_fraction = fraction;
9189 private->progress_pulse_mode = FALSE;
9190 private->progress_pulse_current = 0.0;
9192 if (fabs (fraction - old_fraction) > 0.0001)
9193 gtk_entry_queue_draw (entry);
9195 if (fraction != old_fraction)
9196 g_object_notify (G_OBJECT (entry), "progress-fraction");
9200 * gtk_entry_get_progress_fraction:
9201 * @entry: a #GtkEntry
9203 * Returns the current fraction of the task that's been completed.
9204 * See gtk_entry_set_progress_fraction().
9206 * Return value: a fraction from 0.0 to 1.0
9211 gtk_entry_get_progress_fraction (GtkEntry *entry)
9213 GtkEntryPrivate *private;
9215 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
9217 private = GTK_ENTRY_GET_PRIVATE (entry);
9219 return private->progress_fraction;
9223 * gtk_entry_set_progress_pulse_step:
9224 * @entry: a #GtkEntry
9225 * @fraction: fraction between 0.0 and 1.0
9227 * Sets the fraction of total entry width to move the progress
9228 * bouncing block for each call to gtk_entry_progress_pulse().
9233 gtk_entry_set_progress_pulse_step (GtkEntry *entry,
9236 GtkEntryPrivate *private;
9238 g_return_if_fail (GTK_IS_ENTRY (entry));
9240 private = GTK_ENTRY_GET_PRIVATE (entry);
9242 fraction = CLAMP (fraction, 0.0, 1.0);
9244 if (fraction != private->progress_pulse_fraction)
9246 private->progress_pulse_fraction = fraction;
9248 gtk_entry_queue_draw (entry);
9250 g_object_notify (G_OBJECT (entry), "progress-pulse-step");
9255 * gtk_entry_get_progress_pulse_step:
9256 * @entry: a #GtkEntry
9258 * Retrieves the pulse step set with gtk_entry_set_progress_pulse_step().
9260 * Return value: a fraction from 0.0 to 1.0
9265 gtk_entry_get_progress_pulse_step (GtkEntry *entry)
9267 GtkEntryPrivate *private;
9269 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
9271 private = GTK_ENTRY_GET_PRIVATE (entry);
9273 return private->progress_pulse_fraction;
9277 * gtk_entry_progress_pulse:
9278 * @entry: a #GtkEntry
9280 * Indicates that some progress is made, but you don't know how much.
9281 * Causes the entry's progress indicator to enter "activity mode,"
9282 * where a block bounces back and forth. Each call to
9283 * gtk_entry_progress_pulse() causes the block to move by a little bit
9284 * (the amount of movement per pulse is determined by
9285 * gtk_entry_set_progress_pulse_step()).
9290 gtk_entry_progress_pulse (GtkEntry *entry)
9292 GtkEntryPrivate *private;
9294 g_return_if_fail (GTK_IS_ENTRY (entry));
9296 private = GTK_ENTRY_GET_PRIVATE (entry);
9298 if (private->progress_pulse_mode)
9300 if (private->progress_pulse_way_back)
9302 private->progress_pulse_current -= private->progress_pulse_fraction;
9304 if (private->progress_pulse_current < 0.0)
9306 private->progress_pulse_current = 0.0;
9307 private->progress_pulse_way_back = FALSE;
9312 private->progress_pulse_current += private->progress_pulse_fraction;
9314 if (private->progress_pulse_current > 1.0 - private->progress_pulse_fraction)
9316 private->progress_pulse_current = 1.0 - private->progress_pulse_fraction;
9317 private->progress_pulse_way_back = TRUE;
9323 private->progress_fraction = 0.0;
9324 private->progress_pulse_mode = TRUE;
9325 private->progress_pulse_way_back = FALSE;
9326 private->progress_pulse_current = 0.0;
9329 gtk_entry_queue_draw (entry);
9332 /* Caps Lock warning for password entries */
9335 show_capslock_feedback (GtkEntry *entry,
9338 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
9340 if (gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
9342 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CAPS_LOCK_WARNING);
9343 gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
9344 priv->caps_lock_warning_shown = TRUE;
9347 if (priv->caps_lock_warning_shown)
9348 gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, text);
9350 g_warning ("Can't show Caps Lock warning, since secondary icon is set");
9354 remove_capslock_feedback (GtkEntry *entry)
9356 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
9358 if (priv->caps_lock_warning_shown)
9360 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
9361 priv->caps_lock_warning_shown = FALSE;
9366 keymap_state_changed (GdkKeymap *keymap,
9369 GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
9372 if (!entry->visible && priv->caps_lock_warning)
9374 gboolean capslock_on;
9377 capslock_on = gdk_keymap_get_caps_lock_state (keymap);
9378 im_on = g_strcmp0 (gtk_im_multicontext_get_context_id (GTK_IM_MULTICONTEXT (entry->im_context)), "gtk-im-context-simple") != 0;
9379 if (capslock_on && im_on)
9380 text = _("You have the Caps Lock key on\nand an active input method");
9381 else if (capslock_on)
9382 text = _("You have the Caps Lock key on");
9384 text = _("You have an active input method");
9388 show_capslock_feedback (entry, text);
9390 remove_capslock_feedback (entry);
9393 #define __GTK_ENTRY_C__
9394 #include "gtkaliasdef.c"