X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;ds=sidebyside;f=gtk%2Fgtkentry.c;h=040d35bb45387990cfef9084fa1002a57a743386;hb=85e47b5c4ef49b4a803932e8215c1a104884921b;hp=784667c128134667609f80981758042c89d06fc3;hpb=a0ab93ca1328deef09832d0e3bef00667d37fa32;p=~andy%2Fgtk diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 784667c12..040d35bb4 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -40,6 +40,7 @@ #include "gtkclipboard.h" #include "gtkdnd.h" #include "gtkentry.h" +#include "gtkentrybuffer.h" #include "gtkimagemenuitem.h" #include "gtkimcontextsimple.h" #include "gtkimmulticontext.h" @@ -64,7 +65,6 @@ #include "gtktooltip.h" #include "gtkiconfactory.h" #include "gtkicontheme.h" -#include "gtkalias.h" #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key" @@ -73,12 +73,6 @@ #define COMPLETION_TIMEOUT 300 #define PASSWORD_HINT_MAX 8 -/* Initial size of buffer, in bytes */ -#define MIN_SIZE 16 - -/* Maximum size of text buffer, in bytes */ -#define MAX_SIZE G_MAXUSHORT - #define MAX_ICONS 2 #define IS_VALID_ICON_POSITION(pos) \ @@ -117,6 +111,8 @@ typedef struct struct _GtkEntryPrivate { + GtkEntryBuffer* buffer; + gfloat xalign; gint insert_pos; guint blink_time; /* time in msec the cursor has blinked since last user event */ @@ -142,16 +138,16 @@ struct _GtkEntryPrivate gint start_y; gchar *im_module; + + GdkDevice *completion_device; }; typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint; struct _GtkEntryPasswordHint { - gchar password_hint[PASSWORD_HINT_MAX]; - guint password_hint_timeout_id; - gint password_hint_length; - gint password_hint_position; + gint position; /* Position (in text) of the last password hint */ + guint source_id; /* Timeout source id */ }; typedef struct _GtkEntryCapslockFeedback GtkEntryCapslockFeedback; @@ -176,11 +172,13 @@ enum { TOGGLE_OVERWRITE, ICON_PRESS, ICON_RELEASE, + PREEDIT_CHANGED, LAST_SIGNAL }; enum { PROP_0, + PROP_BUFFER, PROP_CURSOR_POSITION, PROP_SELECTION_BOUND, PROP_EDITABLE, @@ -220,7 +218,8 @@ enum { PROP_TOOLTIP_TEXT_SECONDARY, PROP_TOOLTIP_MARKUP_PRIMARY, PROP_TOOLTIP_MARKUP_SECONDARY, - PROP_IM_MODULE + PROP_IM_MODULE, + PROP_EDITING_CANCELED }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -230,9 +229,16 @@ typedef enum { CURSOR_DND } CursorType; -/* GObject, GtkObject methods +typedef enum +{ + DISPLAY_NORMAL, /* The entry text is being shown */ + DISPLAY_INVISIBLE, /* In invisible mode, text replaced by (eg) bullets */ + DISPLAY_BLANK /* In invisible mode, nothing shown at all */ +} DisplayMode; + +/* GObject methods */ -static void gtk_entry_editable_init (GtkEditableClass *iface); +static void gtk_entry_editable_init (GtkEditableInterface *iface); static void gtk_entry_cell_editable_init (GtkCellEditableIface *iface); static void gtk_entry_set_property (GObject *object, guint prop_id, @@ -243,11 +249,11 @@ static void gtk_entry_get_property (GObject *object, GValue *value, GParamSpec *pspec); static void gtk_entry_finalize (GObject *object); -static void gtk_entry_destroy (GtkObject *object); static void gtk_entry_dispose (GObject *object); /* GtkWidget methods */ +static void gtk_entry_destroy (GtkWidget *widget); static void gtk_entry_realize (GtkWidget *widget); static void gtk_entry_unrealize (GtkWidget *widget); static void gtk_entry_map (GtkWidget *widget); @@ -257,11 +263,12 @@ static void gtk_entry_size_request (GtkWidget *widget, static void gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_entry_draw_frame (GtkWidget *widget, - GdkEventExpose *event); + cairo_t *cr); static void gtk_entry_draw_progress (GtkWidget *widget, - GdkEventExpose *event); -static gint gtk_entry_expose (GtkWidget *widget, - GdkEventExpose *event); + cairo_t *cr, + GdkWindow *window); +static gint gtk_entry_draw (GtkWidget *widget, + cairo_t *cr); static gint gtk_entry_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_entry_button_release (GtkWidget *widget, @@ -409,8 +416,10 @@ static void gtk_entry_enter_text (GtkEntry *entry, static void gtk_entry_set_positions (GtkEntry *entry, gint current_pos, gint selection_bound); -static void gtk_entry_draw_text (GtkEntry *entry); +static void gtk_entry_draw_text (GtkEntry *entry, + cairo_t *cr); static void gtk_entry_draw_cursor (GtkEntry *entry, + cairo_t *cr, CursorType type); static PangoLayout *gtk_entry_ensure_layout (GtkEntry *entry, gboolean include_preedit); @@ -439,9 +448,6 @@ static gint gtk_entry_move_backward_word (GtkEntry *entry, static void gtk_entry_delete_whitespace (GtkEntry *entry); static void gtk_entry_select_word (GtkEntry *entry); static void gtk_entry_select_line (GtkEntry *entry); -static char * gtk_entry_get_public_chars (GtkEntry *entry, - gint start, - gint end); static void gtk_entry_paste (GtkEntry *entry, GdkAtom selection); static void gtk_entry_update_primary_selection (GtkEntry *entry); @@ -501,6 +507,29 @@ static void end_change (GtkEntry *entry); static void emit_changed (GtkEntry *entry); +static void buffer_inserted_text (GtkEntryBuffer *buffer, + guint position, + const gchar *chars, + guint n_chars, + GtkEntry *entry); +static void buffer_deleted_text (GtkEntryBuffer *buffer, + guint position, + guint n_chars, + GtkEntry *entry); +static void buffer_notify_text (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry); +static void buffer_notify_length (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry); +static void buffer_notify_max_length (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry); +static void buffer_connect_signals (GtkEntry *entry); +static void buffer_disconnect_signals (GtkEntry *entry); +static GtkEntryBuffer *get_buffer (GtkEntry *entry); + + G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_entry_editable_init) @@ -535,24 +564,23 @@ gtk_entry_class_init (GtkEntryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class; - GtkObjectClass *gtk_object_class; GtkBindingSet *binding_set; widget_class = (GtkWidgetClass*) class; - gtk_object_class = (GtkObjectClass *)class; gobject_class->dispose = gtk_entry_dispose; gobject_class->finalize = gtk_entry_finalize; gobject_class->set_property = gtk_entry_set_property; gobject_class->get_property = gtk_entry_get_property; + widget_class->destroy = gtk_entry_destroy; widget_class->map = gtk_entry_map; widget_class->unmap = gtk_entry_unmap; widget_class->realize = gtk_entry_realize; widget_class->unrealize = gtk_entry_unrealize; widget_class->size_request = gtk_entry_size_request; widget_class->size_allocate = gtk_entry_size_allocate; - widget_class->expose_event = gtk_entry_expose; + widget_class->draw = gtk_entry_draw; widget_class->enter_notify_event = gtk_entry_enter_notify; widget_class->leave_notify_event = gtk_entry_leave_notify; widget_class->button_press_event = gtk_entry_button_press; @@ -581,8 +609,6 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->popup_menu = gtk_entry_popup_menu; - gtk_object_class->destroy = gtk_entry_destroy; - class->move_cursor = gtk_entry_move_cursor; class->insert_at_cursor = gtk_entry_insert_at_cursor; class->delete_from_cursor = gtk_entry_delete_from_cursor; @@ -599,13 +625,25 @@ gtk_entry_class_init (GtkEntryClass *class) quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment"); quark_capslock_feedback = g_quark_from_static_string ("gtk-entry-capslock-feedback"); + g_object_class_override_property (gobject_class, + PROP_EDITING_CANCELED, + "editing-canceled"); + + g_object_class_install_property (gobject_class, + PROP_BUFFER, + g_param_spec_object ("buffer", + P_("Text Buffer"), + P_("Text buffer object which actually stores entry text"), + GTK_TYPE_ENTRY_BUFFER, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, PROP_CURSOR_POSITION, g_param_spec_int ("cursor-position", P_("Cursor Position"), P_("The current position of the insertion cursor in chars"), 0, - MAX_SIZE, + GTK_ENTRY_BUFFER_MAX_SIZE, 0, GTK_PARAM_READABLE)); @@ -615,7 +653,7 @@ gtk_entry_class_init (GtkEntryClass *class) P_("Selection Bound"), P_("The position of the opposite end of the selection from the cursor in chars"), 0, - MAX_SIZE, + GTK_ENTRY_BUFFER_MAX_SIZE, 0, GTK_PARAM_READABLE)); @@ -633,7 +671,7 @@ gtk_entry_class_init (GtkEntryClass *class) P_("Maximum length"), P_("Maximum number of characters for this entry. Zero if no maximum"), 0, - MAX_SIZE, + GTK_ENTRY_BUFFER_MAX_SIZE, 0, GTK_PARAM_READWRITE)); g_object_class_install_property (gobject_class, @@ -794,8 +832,8 @@ gtk_entry_class_init (GtkEntryClass *class) g_object_class_install_property (gobject_class, PROP_INVISIBLE_CHAR_SET, g_param_spec_boolean ("invisible-char-set", - P_("Invisible char set"), - P_("Whether the invisible char has been set"), + P_("Invisible character set"), + P_("Whether the invisible character has been set"), FALSE, GTK_PARAM_READWRITE)); @@ -1200,7 +1238,7 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READABLE)); /** - * GtkEntry::progress-border: + * GtkEntry:progress-border: * * The border around the progress bar in the entry. * @@ -1214,7 +1252,7 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READABLE)); /** - * GtkEntry::invisible-char: + * GtkEntry:invisible-char: * * The invisible character is used when masking entry contents (in * \"password mode\")"). When it is not explicitly set with the @@ -1225,7 +1263,7 @@ gtk_entry_class_init (GtkEntryClass *class) * This style property allows the theme to prepend a character * to the list of candidates. * - * Since: 2.22 + * Since: 2.18 */ gtk_widget_class_install_style_property (widget_class, g_param_spec_unichar ("invisible-char", @@ -1514,6 +1552,27 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_TYPE_ENTRY_ICON_POSITION, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); + /** + * GtkEntry::preedit-changed: + * @entry: the object which received the signal + * @preedit: the current preedit string + * + * If an input method is used, the typed text will not immediately + * be committed to the buffer. So if you are interested in the text, + * connect to this signal. + * + * Since: 2.20 + */ + signals[PREEDIT_CHANGED] = + g_signal_new_class_handler (I_("preedit-changed"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + NULL, + NULL, NULL, + _gtk_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + /* * Key bindings @@ -1522,85 +1581,85 @@ gtk_entry_class_init (GtkEntryClass *class) binding_set = gtk_binding_set_by_class (class); /* Moving the insertion point */ - add_move_binding (binding_set, GDK_Right, 0, + add_move_binding (binding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); - add_move_binding (binding_set, GDK_Left, 0, + add_move_binding (binding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); - add_move_binding (binding_set, GDK_KP_Right, 0, + add_move_binding (binding_set, GDK_KEY_KP_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); - add_move_binding (binding_set, GDK_KP_Left, 0, + add_move_binding (binding_set, GDK_KEY_KP_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); - add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); - add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); - add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); - add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); - add_move_binding (binding_set, GDK_Home, 0, + add_move_binding (binding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); - add_move_binding (binding_set, GDK_End, 0, + add_move_binding (binding_set, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - add_move_binding (binding_set, GDK_KP_Home, 0, + add_move_binding (binding_set, GDK_KEY_KP_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); - add_move_binding (binding_set, GDK_KP_End, 0, + add_move_binding (binding_set, GDK_KEY_KP_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); - add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); - add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); - add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK, + add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); /* Select all */ - gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, -1, G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, -1, G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, 1, G_TYPE_BOOLEAN, TRUE); /* Unselect all */ - gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS, G_TYPE_INT, 0, G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK, "move-cursor", 3, GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS, G_TYPE_INT, 0, @@ -1608,66 +1667,66 @@ gtk_entry_class_init (GtkEntryClass *class) /* Activate */ - gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "activate", 0); /* Deleting text */ - gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "delete-from-cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "delete-from-cursor", 2, G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "backspace", 0); /* Make this do the same as Backspace, to help with mis-typing */ - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK, "backspace", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK, "delete-from-cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK, "delete-from-cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "delete-from-cursor", 2, G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, G_TYPE_INT, -1); /* Cut/copy/paste */ - gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_x, GDK_CONTROL_MASK, "cut-clipboard", 0); - gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK, "copy-clipboard", 0); - gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_v, GDK_CONTROL_MASK, "paste-clipboard", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "cut-clipboard", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_CONTROL_MASK, "copy-clipboard", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_SHIFT_MASK, "paste-clipboard", 0); /* Overwrite */ - gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, 0, "toggle-overwrite", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0, "toggle-overwrite", 0); /** @@ -1684,21 +1743,6 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_TYPE_BORDER, GTK_PARAM_READABLE)); - /** - * GtkEntry:state-hint: - * - * Indicates whether to pass a proper widget state when - * drawing the shadow and the widget background. - * - * Since: 2.16 - */ - gtk_widget_class_install_style_property (widget_class, - g_param_spec_boolean ("state-hint", - P_("State Hint"), - P_("Whether to pass a proper state when drawing shadow or background"), - FALSE, - GTK_PARAM_READABLE)); - gtk_settings_install_property (g_param_spec_boolean ("gtk-entry-select-on-focus", P_("Select on focus"), P_("Whether to select the contents of an entry when it is focused"), @@ -1724,7 +1768,7 @@ gtk_entry_class_init (GtkEntryClass *class) } static void -gtk_entry_editable_init (GtkEditableClass *iface) +gtk_entry_editable_init (GtkEditableInterface *iface) { iface->do_insert_text = gtk_entry_insert_text; iface->do_delete_text = gtk_entry_delete_text; @@ -1751,19 +1795,25 @@ gtk_entry_set_property (GObject *object, { GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object); GtkEntry *entry = GTK_ENTRY (object); + GtkWidget *widget; switch (prop_id) { + case PROP_BUFFER: + gtk_entry_set_buffer (entry, g_value_get_object (value)); + break; + case PROP_EDITABLE: { gboolean new_value = g_value_get_boolean (value); if (new_value != entry->editable) { + widget = GTK_WIDGET (entry); if (!new_value) { _gtk_entry_reset_im_context (entry); - if (GTK_WIDGET_HAS_FOCUS (entry)) + if (gtk_widget_has_focus (widget)) gtk_im_context_focus_out (entry->im_context); entry->preedit_length = 0; @@ -1772,7 +1822,7 @@ gtk_entry_set_property (GObject *object, entry->editable = new_value; - if (new_value && GTK_WIDGET_HAS_FOCUS (entry)) + if (new_value && gtk_widget_has_focus (widget)) gtk_im_context_focus_in (entry->im_context); gtk_entry_queue_draw (entry); @@ -1945,11 +1995,15 @@ gtk_entry_set_property (GObject *object, case PROP_IM_MODULE: g_free (priv->im_module); - priv->im_module = g_strdup (g_value_get_string (value)); + priv->im_module = g_value_dup_string (value); if (GTK_IS_IM_MULTICONTEXT (entry->im_context)) gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (entry->im_context), priv->im_module); break; + case PROP_EDITING_CANCELED: + entry->editing_canceled = g_value_get_boolean (value); + break; + case PROP_SCROLL_OFFSET: case PROP_CURSOR_POSITION: default: @@ -1969,6 +2023,10 @@ gtk_entry_get_property (GObject *object, switch (prop_id) { + case PROP_BUFFER: + g_value_set_object (value, gtk_entry_get_buffer (entry)); + break; + case PROP_CURSOR_POSITION: g_value_set_int (value, entry->current_pos); break; @@ -1982,7 +2040,7 @@ gtk_entry_get_property (GObject *object, break; case PROP_MAX_LENGTH: - g_value_set_int (value, entry->text_max_length); + g_value_set_int (value, gtk_entry_buffer_get_max_length (get_buffer (entry))); break; case PROP_VISIBILITY: @@ -2034,7 +2092,7 @@ gtk_entry_get_property (GObject *object, break; case PROP_TEXT_LENGTH: - g_value_set_uint (value, entry->text_length); + g_value_set_uint (value, gtk_entry_buffer_get_length (get_buffer (entry))); break; case PROP_INVISIBLE_CHAR_SET: @@ -2157,6 +2215,11 @@ gtk_entry_get_property (GObject *object, gtk_entry_get_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY)); break; + case PROP_EDITING_CANCELED: + g_value_set_boolean (value, + entry->editing_canceled); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2177,7 +2240,7 @@ find_invisible_char (GtkWidget *widget) 0x273a /* SIXTEEN POINTED ASTERISK */ }; - if (widget->style) + if (gtk_widget_get_style (widget)) gtk_widget_style_get (widget, "invisible-char", &invisible_chars[0], NULL); @@ -2216,12 +2279,8 @@ static void gtk_entry_init (GtkEntry *entry) { GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); - - GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS); - entry->text_size = MIN_SIZE; - entry->text = g_malloc (entry->text_size); - entry->text[0] = '\0'; + gtk_widget_set_can_focus (GTK_WIDGET (entry), TRUE); entry->editable = TRUE; entry->visible = TRUE; @@ -2258,6 +2317,7 @@ gtk_entry_init (GtkEntry *entry) G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry); g_signal_connect (entry->im_context, "delete-surrounding", G_CALLBACK (gtk_entry_delete_surrounding_cb), entry); + } static gint @@ -2293,7 +2353,7 @@ get_icon_allocations (GtkEntry *entry, get_text_area_size (entry, &x, &y, &width, &height); - if (GTK_WIDGET_HAS_FOCUS (entry) && !priv->interior_focus) + if (gtk_widget_has_focus (GTK_WIDGET (entry)) && !priv->interior_focus) y += priv->focus_width; primary->y = y; @@ -2361,24 +2421,12 @@ emit_changed (GtkEntry *entry) priv->real_changed = TRUE; } -/* - * Overwrite a memory that might contain sensitive information. - */ -static void -trash_area (gchar *area, gsize len) -{ - volatile gchar *varea = (volatile gchar *)area; - while (len-- > 0) - *varea++ = 0; -} - static void -gtk_entry_destroy (GtkObject *object) +gtk_entry_destroy (GtkWidget *widget) { - GtkEntry *entry = GTK_ENTRY (object); + GtkEntry *entry = GTK_ENTRY (widget); - entry->n_bytes = 0; - entry->current_pos = entry->selection_bound = entry->text_length = 0; + entry->current_pos = entry->selection_bound = 0; _gtk_entry_reset_im_context (entry); gtk_entry_reset_layout (entry); @@ -2394,25 +2442,27 @@ gtk_entry_destroy (GtkObject *object) entry->recompute_idle = 0; } - if (!entry->visible) - { - /* We want to trash the text here because the entry might be leaked. */ - trash_area (entry->text, strlen (entry->text)); - } - - GTK_OBJECT_CLASS (gtk_entry_parent_class)->destroy (object); + GTK_WIDGET_CLASS (gtk_entry_parent_class)->destroy (widget); } static void gtk_entry_dispose (GObject *object) { GtkEntry *entry = GTK_ENTRY (object); + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, NULL); gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY, NULL); gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_SECONDARY, NULL); gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY, NULL); + if (priv->buffer) + { + buffer_disconnect_signals (entry); + g_object_unref (priv->buffer); + priv->buffer = NULL; + } + G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object); } @@ -2452,19 +2502,91 @@ gtk_entry_finalize (GObject *object) if (entry->recompute_idle) g_source_remove (entry->recompute_idle); - entry->text_size = 0; + g_free (priv->im_module); + + G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object); +} + +static DisplayMode +gtk_entry_get_display_mode (GtkEntry *entry) +{ + GtkEntryPrivate *priv; + if (entry->visible) + return DISPLAY_NORMAL; + priv = GTK_ENTRY_GET_PRIVATE (entry); + if (entry->invisible_char == 0 && priv->invisible_char_set) + return DISPLAY_BLANK; + return DISPLAY_INVISIBLE; +} + +static gchar* +gtk_entry_get_display_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + GtkEntryPasswordHint *password_hint; + GtkEntryPrivate *priv; + gunichar invisible_char; + const gchar *start; + const gchar *end; + const gchar *text; + gchar char_str[7]; + gint char_len; + GString *str; + guint length; + gint i; + + priv = GTK_ENTRY_GET_PRIVATE (entry); + text = gtk_entry_buffer_get_text (get_buffer (entry)); + length = gtk_entry_buffer_get_length (get_buffer (entry)); + + if (end_pos < 0) + end_pos = length; + if (start_pos > length) + start_pos = length; - if (entry->text) + if (end_pos <= start_pos) + return g_strdup (""); + else if (entry->visible) { - if (!entry->visible) - trash_area (entry->text, strlen (entry->text)); - g_free (entry->text); - entry->text = NULL; + start = g_utf8_offset_to_pointer (text, start_pos); + end = g_utf8_offset_to_pointer (start, end_pos - start_pos); + return g_strndup (start, end - start); } + else + { + str = g_string_sized_new (length * 2); - g_free (priv->im_module); + /* Figure out what our invisible char is and encode it */ + if (!entry->invisible_char) + invisible_char = priv->invisible_char_set ? ' ' : '*'; + else + invisible_char = entry->invisible_char; + char_len = g_unichar_to_utf8 (invisible_char, char_str); + + /* + * Add hidden characters for each character in the text + * buffer. If there is a password hint, then keep that + * character visible. + */ + + password_hint = g_object_get_qdata (G_OBJECT (entry), quark_password_hint); + for (i = start_pos; i < end_pos; ++i) + { + if (password_hint && i == password_hint->position) + { + start = g_utf8_offset_to_pointer (text, i); + g_string_append_len (str, start, g_utf8_next_char (start) - start); + } + else + { + g_string_append_len (str, char_str, char_len); + } + } + + return g_string_free (str, FALSE); + } - G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object); } static void @@ -2488,7 +2610,7 @@ update_cursors (GtkWidget *widget) * here is that for the entry, insensitive => arrow cursor, but for * an icon in a sensitive entry, insensitive => xterm cursor. */ - if (GTK_WIDGET_IS_SENSITIVE (widget) && + if (gtk_widget_is_sensitive (widget) && (icon_info->insensitive || (icon_info->nonactivatable && icon_info->target_list == NULL))) { @@ -2523,7 +2645,6 @@ realize_icon_info (GtkWidget *widget, attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | @@ -2534,14 +2655,14 @@ realize_icon_info (GtkWidget *widget, GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - icon_info->window = gdk_window_new (widget->window, + icon_info->window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (icon_info->window, widget); gdk_window_set_background (icon_info->window, - &widget->style->base[GTK_WIDGET_STATE (widget)]); + >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]); gtk_widget_queue_resize (widget); } @@ -2558,12 +2679,9 @@ construct_icon_info (GtkWidget *widget, icon_info = g_slice_new0 (EntryIconInfo); priv->icons[icon_pos] = icon_info; - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) realize_icon_info (widget, icon_pos); - if (GTK_WIDGET_MAPPED (widget)) - gdk_window_show_unraised (icon_info->window); - return icon_info; } @@ -2574,21 +2692,18 @@ gtk_entry_map (GtkWidget *widget) EntryIconInfo *icon_info = NULL; gint i; - if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget)) - { - GTK_WIDGET_CLASS (gtk_entry_parent_class)->map (widget); + GTK_WIDGET_CLASS (gtk_entry_parent_class)->map (widget); - for (i = 0; i < MAX_ICONS; i++) + for (i = 0; i < MAX_ICONS; i++) + { + if ((icon_info = priv->icons[i]) != NULL) { - if ((icon_info = priv->icons[i]) != NULL) - { - if (icon_info->pixbuf != NULL && icon_info->window != NULL) - gdk_window_show (icon_info->window); - } + if (icon_info->pixbuf != NULL && icon_info->window != NULL) + gdk_window_show (icon_info->window); } - - update_cursors (widget); } + + update_cursors (widget); } static void @@ -2598,19 +2713,16 @@ gtk_entry_unmap (GtkWidget *widget) EntryIconInfo *icon_info = NULL; gint i; - if (GTK_WIDGET_MAPPED (widget)) + for (i = 0; i < MAX_ICONS; i++) { - for (i = 0; i < MAX_ICONS; i++) + if ((icon_info = priv->icons[i]) != NULL) { - if ((icon_info = priv->icons[i]) != NULL) - { - if (icon_info->pixbuf != NULL && icon_info->window != NULL) - gdk_window_hide (icon_info->window); - } + if (icon_info->pixbuf != NULL && icon_info->window != NULL) + gdk_window_hide (icon_info->window); } - - GTK_WIDGET_CLASS (gtk_entry_parent_class)->unmap (widget); } + + GTK_WIDGET_CLASS (gtk_entry_parent_class)->unmap (widget); } static void @@ -2618,12 +2730,15 @@ gtk_entry_realize (GtkWidget *widget) { GtkEntry *entry; GtkEntryPrivate *priv; + GtkStateType state; + GtkStyle *style; EntryIconInfo *icon_info; + GdkWindow *window; GdkWindowAttr attributes; gint attributes_mask; int i; - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + gtk_widget_set_realized (widget, TRUE); entry = GTK_ENTRY (widget); priv = GTK_ENTRY_GET_PRIVATE (entry); @@ -2633,7 +2748,6 @@ gtk_entry_realize (GtkWidget *widget) attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | @@ -2644,30 +2758,33 @@ gtk_entry_realize (GtkWidget *widget) GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, entry); + window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gtk_widget_set_window (widget, window); + gdk_window_set_user_data (window, entry); get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height); - if (GTK_WIDGET_IS_SENSITIVE (widget)) + if (gtk_widget_is_sensitive (widget)) { attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM); attributes_mask |= GDK_WA_CURSOR; } - entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + entry->text_area = gdk_window_new (window, &attributes, attributes_mask); gdk_window_set_user_data (entry->text_area, entry); if (attributes_mask & GDK_WA_CURSOR) gdk_cursor_unref (attributes.cursor); - widget->style = gtk_style_attach (widget->style, widget->window); + gtk_widget_style_attach (widget); - gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); - gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + gdk_window_set_background (window, &style->base[state]); + gdk_window_set_background (entry->text_area, &style->base[state]); gdk_window_show (entry->text_area); @@ -2743,11 +2860,14 @@ _gtk_entry_get_borders (GtkEntry *entry, { GtkWidget *widget = GTK_WIDGET (entry); GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkStyle *style; if (entry->has_frame) { - *xborder = widget->style->xthickness; - *yborder = widget->style->ythickness; + style = gtk_widget_get_style (widget); + + *xborder = style->xthickness; + *yborder = style->ythickness; } else { @@ -2778,7 +2898,7 @@ gtk_entry_size_request (GtkWidget *widget, gtk_widget_ensure_style (widget); context = gtk_widget_get_pango_context (widget); metrics = pango_context_get_metrics (context, - widget->style->font_desc, + gtk_widget_get_style (widget)->font_desc, pango_context_get_language (context)); entry->ascent = pango_font_metrics_get_ascent (metrics); @@ -2816,6 +2936,7 @@ gtk_entry_size_request (GtkWidget *widget, static void place_windows (GtkEntry *entry) { + GtkWidget *widget = GTK_WIDGET (entry); GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); gint x, y, width, height; GtkAllocation primary; @@ -2825,10 +2946,10 @@ place_windows (GtkEntry *entry) get_text_area_size (entry, &x, &y, &width, &height); get_icon_allocations (entry, &primary, &secondary); - if (GTK_WIDGET_HAS_FOCUS (entry) && !priv->interior_focus) + if (gtk_widget_has_focus (widget) && !priv->interior_focus) y += priv->focus_width; - if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) x += secondary.width; else x += primary.width; @@ -2844,7 +2965,7 @@ place_windows (GtkEntry *entry) secondary.x, secondary.y, secondary.width, secondary.height); - gdk_window_move_resize (GTK_ENTRY (entry)->text_area, x, y, width, height); + gdk_window_move_resize (entry->text_area, x, y, width, height); } static void @@ -2856,19 +2977,21 @@ gtk_entry_get_text_area_size (GtkEntry *entry, { GtkWidget *widget = GTK_WIDGET (entry); GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkAllocation allocation; + GtkRequisition requisition; gint frame_height; gint xborder, yborder; - GtkRequisition requisition; - gtk_widget_get_child_requisition (widget, &requisition); + gtk_widget_get_preferred_size (widget, &requisition, NULL); + gtk_widget_get_allocation (widget, &allocation); _gtk_entry_get_borders (entry, &xborder, &yborder); - if (GTK_WIDGET_REALIZED (widget)) - gdk_drawable_get_size (widget->window, NULL, &frame_height); + if (gtk_widget_get_realized (widget)) + frame_height = gdk_window_get_height (gtk_widget_get_window (widget)); else frame_height = requisition.height; - if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus) + if (gtk_widget_has_focus (widget) && !priv->interior_focus) frame_height -= 2 * priv->focus_width; if (x) @@ -2878,7 +3001,7 @@ gtk_entry_get_text_area_size (GtkEntry *entry, *y = frame_height / 2 - (requisition.height - yborder * 2) / 2; if (width) - *width = GTK_WIDGET (entry)->allocation.width - xborder * 2; + *width = allocation.width - xborder * 2; if (height) *height = requisition.height - yborder * 2; @@ -2909,29 +3032,31 @@ get_widget_window_size (GtkEntry *entry, gint *width, gint *height) { + GtkAllocation allocation; GtkRequisition requisition; GtkWidget *widget = GTK_WIDGET (entry); - - gtk_widget_get_child_requisition (widget, &requisition); + + gtk_widget_get_preferred_size (widget, &requisition, NULL); + gtk_widget_get_allocation (widget, &allocation); if (x) - *x = widget->allocation.x; + *x = allocation.x; if (y) { if (entry->is_cell_renderer) - *y = widget->allocation.y; + *y = allocation.y; else - *y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2; + *y = allocation.y + (allocation.height - requisition.height) / 2; } if (width) - *width = widget->allocation.width; + *width = allocation.width; if (height) { if (entry->is_cell_renderer) - *height = widget->allocation.height; + *height = allocation.height; else *height = requisition.height; } @@ -2968,26 +3093,23 @@ gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkEntry *entry = GTK_ENTRY (widget); - - widget->allocation = *allocation; - - if (GTK_WIDGET_REALIZED (widget)) + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) { - /* We call gtk_widget_get_child_requisition, since we want (for - * backwards compatibility reasons) the realization here to - * be affected by the usize of the entry, if set - */ gint x, y, width, height; GtkEntryCompletion* completion; get_widget_window_size (entry, &x, &y, &width, &height); - gdk_window_move_resize (widget->window, x, y, width, height); + gdk_window_move_resize (gtk_widget_get_window (widget), + x, y, width, height); place_windows (entry); gtk_entry_recompute (entry); completion = gtk_entry_get_completion (entry); - if (completion && GTK_WIDGET_MAPPED (completion->priv->popup_window)) + if (completion && gtk_widget_get_mapped (completion->priv->popup_window)) _gtk_entry_completion_resize_popup (completion); } } @@ -3067,6 +3189,7 @@ should_prelight (GtkEntry *entry, static void draw_icon (GtkWidget *widget, + cairo_t *cr, GtkEntryIconPosition icon_pos) { GtkEntry *entry = GTK_ENTRY (widget); @@ -3083,7 +3206,8 @@ draw_icon (GtkWidget *widget, if (icon_info->pixbuf == NULL) return; - gdk_drawable_get_size (icon_info->window, &width, &height); + width = gdk_window_get_width (icon_info->window); + height = gdk_window_get_height (icon_info->window); /* size_allocate hasn't been called yet. These are the default values. */ @@ -3108,7 +3232,7 @@ draw_icon (GtkWidget *widget, x = (width - gdk_pixbuf_get_width (pixbuf)) / 2; y = (height - gdk_pixbuf_get_height (pixbuf)) / 2; - if (!GTK_WIDGET_IS_SENSITIVE (widget) || + if (!gtk_widget_is_sensitive (widget) || icon_info->insensitive) { GdkPixbuf *temp_pixbuf; @@ -3131,9 +3255,8 @@ draw_icon (GtkWidget *widget, pixbuf = temp_pixbuf; } - gdk_draw_pixbuf (icon_info->window, widget->style->black_gc, pixbuf, - 0, 0, x, y, -1, -1, - GDK_RGB_DITHER_NORMAL, 0, 0); + gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); + cairo_paint (cr); g_object_unref (pixbuf); } @@ -3141,17 +3264,22 @@ draw_icon (GtkWidget *widget, static void gtk_entry_draw_frame (GtkWidget *widget, - GdkEventExpose *event) + cairo_t *cr) { GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkStyle *style; + GdkWindow *window; gint x = 0, y = 0, width, height; - gboolean state_hint; GtkStateType state; - gdk_drawable_get_size (widget->window, &width, &height); + window = gtk_widget_get_window (widget); + + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); /* Fix a problem with some themes which assume that entry->text_area's - * width equals widget->window's width */ + * width equals widget->window's width + * http://bugzilla.gnome.org/show_bug.cgi?id=466000 */ if (GTK_IS_SPIN_BUTTON (widget)) { gint xborder, yborder; @@ -3163,7 +3291,7 @@ gtk_entry_draw_frame (GtkWidget *widget, width += xborder * 2; } - if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus) + if (gtk_widget_has_focus (widget) && !priv->interior_focus) { x += priv->focus_width; y += priv->focus_width; @@ -3171,29 +3299,27 @@ gtk_entry_draw_frame (GtkWidget *widget, height -= 2 * priv->focus_width; } - gtk_widget_style_get (widget, "state-hint", &state_hint, NULL); - if (state_hint) - state = GTK_WIDGET_HAS_FOCUS (widget) ? - GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget); - else - state = GTK_STATE_NORMAL; + style = gtk_widget_get_style (widget); + state = gtk_widget_has_focus (widget) ? + GTK_STATE_ACTIVE : gtk_widget_get_state (widget); - gtk_paint_shadow (widget->style, widget->window, + gtk_paint_shadow (style, cr, state, priv->shadow_type, - &event->area, widget, "entry", x, y, width, height); + widget, "entry", x, y, width, height); - gtk_entry_draw_progress (widget, event); + gtk_entry_draw_progress (widget, cr, window); - if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus) + if (gtk_widget_has_focus (widget) && !priv->interior_focus) { x -= priv->focus_width; y -= priv->focus_width; width += 2 * priv->focus_width; height += 2 * priv->focus_width; - - gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), - &event->area, widget, "entry", + + gtk_paint_focus (style, cr, + gtk_widget_get_state (widget), + widget, "entry", 0, 0, width, height); } } @@ -3203,6 +3329,7 @@ gtk_entry_get_progress_border (GtkWidget *widget, GtkBorder *progress_border) { GtkBorder *tmp_border; + GtkStyle *style; gtk_widget_style_get (widget, "progress-border", &tmp_border, NULL); if (tmp_border) @@ -3212,10 +3339,12 @@ gtk_entry_get_progress_border (GtkWidget *widget, } else { - progress_border->left = widget->style->xthickness; - progress_border->right = widget->style->xthickness; - progress_border->top = widget->style->ythickness; - progress_border->bottom = widget->style->ythickness; + style = gtk_widget_get_style (widget); + + progress_border->left = style->xthickness; + progress_border->right = style->xthickness; + progress_border->top = style->ythickness; + progress_border->bottom = style->ythickness; } } @@ -3235,12 +3364,12 @@ get_progress_area (GtkWidget *widget, *x = progress_border.left; *y = progress_border.top; - gdk_drawable_get_size (widget->window, width, height); - - *width -= progress_border.left + progress_border.right; - *height -= progress_border.top + progress_border.bottom; + *width = gdk_window_get_width (gtk_widget_get_window (widget)) + - progress_border.left - progress_border.right; + *height = gdk_window_get_height (gtk_widget_get_window (widget)) + - progress_border.top - progress_border.bottom; - if (GTK_WIDGET_HAS_FOCUS (widget) && !private->interior_focus) + if (gtk_widget_has_focus (widget) && !private->interior_focus) { *x += private->focus_width; *y += private->focus_width; @@ -3281,7 +3410,8 @@ get_progress_area (GtkWidget *widget, static void gtk_entry_draw_progress (GtkWidget *widget, - GdkEventExpose *event) + cairo_t *cr, + GdkWindow *window) { gint x, y, width, height; GtkStateType state; @@ -3291,94 +3421,97 @@ gtk_entry_draw_progress (GtkWidget *widget, if ((width <= 0) || (height <= 0)) return; - if (event->window != widget->window) + if (window != gtk_widget_get_window (widget)) { gint pos_x, pos_y; - gdk_window_get_position (event->window, &pos_x, &pos_y); + gdk_window_get_position (window, &pos_x, &pos_y); x -= pos_x; y -= pos_y; } state = GTK_STATE_SELECTED; - if (!GTK_WIDGET_SENSITIVE (widget)) + if (!gtk_widget_get_sensitive (widget)) state = GTK_STATE_INSENSITIVE; - gtk_paint_box (widget->style, event->window, + gtk_paint_box (gtk_widget_get_style (widget), cr, state, GTK_SHADOW_OUT, - &event->area, widget, "entry-progress", + widget, "entry-progress", x, y, width, height); } static gint -gtk_entry_expose (GtkWidget *widget, - GdkEventExpose *event) +gtk_entry_draw (GtkWidget *widget, + cairo_t *cr) { GtkEntry *entry = GTK_ENTRY (widget); - gboolean state_hint; + GtkStyle *style; GtkStateType state; GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + int i; - gtk_widget_style_get (widget, "state-hint", &state_hint, NULL); - if (state_hint) - state = GTK_WIDGET_HAS_FOCUS (widget) ? - GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget); - else - state = GTK_WIDGET_STATE(widget); + style = gtk_widget_get_style (widget); - if (widget->window == event->window) - { - gtk_entry_draw_frame (widget, event); - } - else if (entry->text_area == event->window) + state = gtk_widget_has_focus (widget) ? + GTK_STATE_ACTIVE : gtk_widget_get_state (widget); + + if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) + gtk_entry_draw_frame (widget, cr); + + if (gtk_cairo_should_draw_window (cr, entry->text_area)) { - gint width, height; + cairo_save (cr); - gdk_drawable_get_size (entry->text_area, &width, &height); + gtk_cairo_transform_to_window (cr, widget, entry->text_area); - gtk_paint_flat_box (widget->style, entry->text_area, + gtk_paint_flat_box (style, cr, state, GTK_SHADOW_NONE, - &event->area, widget, "entry_bg", - 0, 0, width, height); + widget, "entry_bg", + 0, 0, + gdk_window_get_width (entry->text_area), + gdk_window_get_height (entry->text_area)); - gtk_entry_draw_progress (widget, event); + gtk_entry_draw_progress (widget, cr, entry->text_area); if (entry->dnd_position != -1) - gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND); + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND); - gtk_entry_draw_text (GTK_ENTRY (widget)); + gtk_entry_draw_text (GTK_ENTRY (widget), cr); - if ((entry->visible || entry->invisible_char != 0) && - GTK_WIDGET_HAS_FOCUS (widget) && - entry->selection_bound == entry->current_pos && entry->cursor_visible) - gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD); + /* When no text is being displayed at all, don't show the cursor */ + if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK && + gtk_widget_has_focus (widget) && + entry->selection_bound == entry->current_pos && entry->cursor_visible) + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD); + + cairo_restore (cr); } - else + + for (i = 0; i < MAX_ICONS; i++) { - int i; + EntryIconInfo *icon_info = priv->icons[i]; - for (i = 0; i < MAX_ICONS; i++) + if (icon_info != NULL && gtk_cairo_should_draw_window (cr, icon_info->window)) { - EntryIconInfo *icon_info = priv->icons[i]; + cairo_save (cr); - if (icon_info != NULL && event->window == icon_info->window) - { - gint width, height; + gtk_cairo_transform_to_window (cr, widget, icon_info->window); - gdk_drawable_get_size (icon_info->window, &width, &height); + gtk_paint_flat_box (style, cr, + state, GTK_SHADOW_NONE, + widget, "entry_bg", + 0, 0, + gdk_window_get_width (icon_info->window), + gdk_window_get_height (icon_info->window)); - gtk_paint_flat_box (widget->style, icon_info->window, - GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE, - NULL, widget, "entry_bg", - 0, 0, width, height); + gtk_entry_draw_progress (widget, cr, icon_info->window); + draw_icon (widget, cr, i); - gtk_entry_draw_progress (widget, event); - draw_icon (widget, i); + cairo_restore (cr); - break; - } + break; } } @@ -3426,6 +3559,10 @@ gtk_entry_leave_notify (GtkWidget *widget, if (icon_info != NULL && event->window == icon_info->window) { + /* a grab means that we may never see the button release */ + if (event->mode == GDK_CROSSING_GRAB || event->mode == GDK_CROSSING_GTK_GRAB) + icon_info->pressed = FALSE; + if (should_prelight (entry, i)) { icon_info->prelight = FALSE; @@ -3549,7 +3686,7 @@ gtk_entry_button_press (GtkWidget *widget, entry->button = event->button; - if (!GTK_WIDGET_HAS_FOCUS (widget)) + if (!gtk_widget_has_focus (widget)) { entry->in_click = TRUE; gtk_widget_grab_focus (widget); @@ -3708,15 +3845,12 @@ gtk_entry_button_release (GtkWidget *widget, if (event->window == icon_info->window) { - gint width, height; - - gdk_drawable_get_size (icon_info->window, &width, &height); - icon_info->pressed = FALSE; if (should_prelight (entry, i) && event->x >= 0 && event->y >= 0 && - event->x < width && event->y < height) + event->x < gdk_window_get_width (icon_info->window) && + event->y < gdk_window_get_height (icon_info->window)) { icon_info->prelight = TRUE; gtk_widget_queue_draw (widget); @@ -3822,7 +3956,7 @@ gtk_entry_motion_notify (GtkWidget *widget, if (entry->in_drag) { - if (entry->visible && + if (gtk_entry_get_display_mode (entry) == DISPLAY_NORMAL && gtk_drag_check_threshold (widget, entry->drag_start_x, entry->drag_start_y, event->x + entry->scroll_offset, event->y)) @@ -3831,27 +3965,23 @@ gtk_entry_motion_notify (GtkWidget *widget, GtkTargetList *target_list = gtk_target_list_new (NULL, 0); guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY; gchar *text = NULL; - GdkPixmap *pixmap = NULL; + cairo_surface_t *surface; gtk_target_list_add_text_targets (target_list, 0); text = _gtk_entry_get_selected_text (entry); - pixmap = _gtk_text_util_create_drag_icon (widget, text, -1); + surface = _gtk_text_util_create_drag_icon (widget, text, -1); context = gtk_drag_begin (widget, target_list, actions, entry->button, (GdkEvent *)event); - if (pixmap) - gtk_drag_set_icon_pixmap (context, - gdk_drawable_get_colormap (pixmap), - pixmap, - NULL, - -2, -2); + if (surface) + gtk_drag_set_icon_surface (context, surface); else gtk_drag_set_icon_default (context); - if (pixmap) - g_object_unref (pixmap); + if (surface) + cairo_surface_destroy (surface); g_free (text); entry->in_drag = FALSE; @@ -3862,13 +3992,10 @@ gtk_entry_motion_notify (GtkWidget *widget, } else { - gint height; - gdk_drawable_get_size (entry->text_area, NULL, &height); - if (event->y < 0) tmp_pos = 0; - else if (event->y >= height) - tmp_pos = entry->text_length; + else if (event->y >= gdk_window_get_height (entry->text_area)) + tmp_pos = gtk_entry_buffer_get_length (get_buffer (entry)); else tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); @@ -3923,7 +4050,7 @@ set_invisible_cursor (GdkWindow *window) GdkDisplay *display; GdkCursor *cursor; - display = gdk_drawable_get_display (window); + display = gdk_window_get_display (window); cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR); gdk_window_set_cursor (window, cursor); @@ -3961,10 +4088,10 @@ gtk_entry_key_press (GtkWidget *widget, } } - if (event->keyval == GDK_Return || - event->keyval == GDK_KP_Enter || - event->keyval == GDK_ISO_Enter || - event->keyval == GDK_Escape) + if (event->keyval == GDK_KEY_Return || + event->keyval == GDK_KEY_KP_Enter || + event->keyval == GDK_KEY_ISO_Enter || + event->keyval == GDK_KEY_Escape) { GtkEntryCompletion *completion = gtk_entry_get_completion (entry); @@ -4106,18 +4233,27 @@ gtk_entry_state_changed (GtkWidget *widget, GdkCursor *cursor; gint i; - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) { - gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); - gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); + GtkStateType state; + GtkStyle *style; + + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + + gdk_window_set_background (gtk_widget_get_window (widget), + &style->base[state]); + gdk_window_set_background (entry->text_area, + &style->base[state]); for (i = 0; i < MAX_ICONS; i++) { EntryIconInfo *icon_info = priv->icons[i]; if (icon_info && icon_info->window) - gdk_window_set_background (icon_info->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); + gdk_window_set_background (icon_info->window, + &style->base[state]); } - if (GTK_WIDGET_IS_SENSITIVE (widget)) + if (gtk_widget_is_sensitive (widget)) cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM); else cursor = NULL; @@ -4132,7 +4268,7 @@ gtk_entry_state_changed (GtkWidget *widget, update_cursors (widget); } - if (!GTK_WIDGET_IS_SENSITIVE (widget)) + if (!gtk_widget_is_sensitive (widget)) { /* Clear any selection */ gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos); @@ -4156,30 +4292,14 @@ gtk_entry_insert_text (GtkEditable *editable, gint new_text_length, gint *position) { - GtkEntry *entry = GTK_ENTRY (editable); - gchar buf[64]; - gchar *text; - - if (*position < 0 || *position > entry->text_length) - *position = entry->text_length; - g_object_ref (editable); - - if (new_text_length <= 63) - text = buf; - else - text = g_new (gchar, new_text_length + 1); - - text[new_text_length] = '\0'; - strncpy (text, new_text, new_text_length); - g_signal_emit_by_name (editable, "insert-text", text, new_text_length, position); - - if (!entry->visible) - trash_area (text, new_text_length); + /* + * The incoming text may a password or other secret. We make sure + * not to copy it into temporary buffers. + */ - if (new_text_length > 63) - g_free (text); + g_signal_emit_by_name (editable, "insert-text", new_text, new_text_length, position); g_object_unref (editable); } @@ -4189,15 +4309,6 @@ gtk_entry_delete_text (GtkEditable *editable, gint start_pos, gint end_pos) { - GtkEntry *entry = GTK_ENTRY (editable); - - if (end_pos < 0 || end_pos > entry->text_length) - end_pos = entry->text_length; - if (start_pos < 0) - start_pos = 0; - if (start_pos > end_pos) - start_pos = end_pos; - g_object_ref (editable); g_signal_emit_by_name (editable, "delete-text", start_pos, end_pos); @@ -4211,18 +4322,23 @@ gtk_entry_get_chars (GtkEditable *editable, gint end_pos) { GtkEntry *entry = GTK_ENTRY (editable); + const gchar *text; + gint text_length; gint start_index, end_index; - + + text = gtk_entry_buffer_get_text (get_buffer (entry)); + text_length = gtk_entry_buffer_get_length (get_buffer (entry)); + if (end_pos < 0) - end_pos = entry->text_length; + end_pos = text_length; - start_pos = MIN (entry->text_length, start_pos); - end_pos = MIN (entry->text_length, end_pos); + start_pos = MIN (text_length, start_pos); + end_pos = MIN (text_length, end_pos); - start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; - end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; + start_index = g_utf8_offset_to_pointer (text, start_pos) - text; + end_index = g_utf8_offset_to_pointer (text, end_pos) - text; - return g_strndup (entry->text + start_index, end_index - start_index); + return g_strndup (text + start_index, end_index - start_index); } static void @@ -4231,8 +4347,11 @@ gtk_entry_real_set_position (GtkEditable *editable, { GtkEntry *entry = GTK_ENTRY (editable); - if (position < 0 || position > entry->text_length) - position = entry->text_length; + guint length; + + length = gtk_entry_buffer_get_length (get_buffer (entry)); + if (position < 0 || position > length) + position = length; if (position != entry->current_pos || position != entry->selection_bound) @@ -4254,17 +4373,19 @@ gtk_entry_set_selection_bounds (GtkEditable *editable, gint end) { GtkEntry *entry = GTK_ENTRY (editable); + guint length; + length = gtk_entry_buffer_get_length (get_buffer (entry)); if (start < 0) - start = entry->text_length; + start = length; if (end < 0) - end = entry->text_length; + end = length; _gtk_entry_reset_im_context (entry); gtk_entry_set_positions (entry, - MIN (end, entry->text_length), - MIN (start, entry->text_length)); + MIN (end, length), + MIN (start, length)); gtk_entry_update_primary_selection (entry); } @@ -4339,15 +4460,22 @@ gtk_entry_style_set (GtkWidget *widget, gtk_entry_recompute (entry); - if (previous_style && GTK_WIDGET_REALIZED (widget)) + if (previous_style && gtk_widget_get_realized (widget)) { - gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); - gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); + GtkStyle *style; + + style = gtk_widget_get_style (widget); + + gdk_window_set_background (gtk_widget_get_window (widget), + &style->base[gtk_widget_get_state (widget)]); + gdk_window_set_background (entry->text_area, + &style->base[gtk_widget_get_state (widget)]); for (i = 0; i < MAX_ICONS; i++) { EntryIconInfo *icon_info = priv->icons[i]; if (icon_info && icon_info->window) - gdk_window_set_background (icon_info->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); + gdk_window_set_background (icon_info->window, + &style->base[gtk_widget_get_state (widget)]); } } @@ -4369,7 +4497,7 @@ gtk_cell_editable_key_press_event (GtkEntry *entry, GdkEventKey *key_event, gpointer data) { - if (key_event->keyval == GDK_Escape) + if (key_event->keyval == GDK_KEY_Escape) { entry->editing_canceled = TRUE; gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); @@ -4379,7 +4507,7 @@ gtk_cell_editable_key_press_event (GtkEntry *entry, } /* override focus */ - if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down) + if (key_event->keyval == GDK_KEY_Up || key_event->keyval == GDK_KEY_Down) { gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); @@ -4405,12 +4533,24 @@ gtk_entry_start_editing (GtkCellEditable *cell_editable, static void gtk_entry_password_hint_free (GtkEntryPasswordHint *password_hint) { - if (password_hint->password_hint_timeout_id) - g_source_remove (password_hint->password_hint_timeout_id); + if (password_hint->source_id) + g_source_remove (password_hint->source_id); g_slice_free (GtkEntryPasswordHint, password_hint); } + +static gboolean +gtk_entry_remove_password_hint (gpointer data) +{ + GtkEntryPasswordHint *password_hint = g_object_get_qdata (data, quark_password_hint); + password_hint->position = -1; + + /* Force the string to be redrawn, but now without a visible character */ + gtk_entry_recompute (GTK_ENTRY (data)); + return FALSE; +} + /* Default signal handlers */ static void @@ -4419,82 +4559,58 @@ gtk_entry_real_insert_text (GtkEditable *editable, gint new_text_length, gint *position) { - GtkEntry *entry = GTK_ENTRY (editable); - gint index; + guint n_inserted; gint n_chars; - if (new_text_length < 0) - new_text_length = strlen (new_text); - n_chars = g_utf8_strlen (new_text, new_text_length); - if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length) - { - gtk_widget_error_bell (GTK_WIDGET (entry)); - n_chars = entry->text_max_length - entry->text_length; - new_text_length = g_utf8_offset_to_pointer (new_text, n_chars) - new_text; - } - if (new_text_length + entry->n_bytes + 1 > entry->text_size) - { - gsize prev_size = entry->text_size; + /* + * The actual insertion into the buffer. This will end up firing the + * following signal handlers: buffer_inserted_text(), buffer_notify_display_text(), + * buffer_notify_text(), buffer_notify_length() + */ + n_inserted = gtk_entry_buffer_insert_text (get_buffer (GTK_ENTRY (editable)), *position, new_text, n_chars); - while (new_text_length + entry->n_bytes + 1 > entry->text_size) - { - if (entry->text_size == 0) - entry->text_size = MIN_SIZE; - else - { - if (2 * (guint)entry->text_size < MAX_SIZE && - 2 * (guint)entry->text_size > entry->text_size) - entry->text_size *= 2; - else - { - entry->text_size = MAX_SIZE; - if (new_text_length > (gint)entry->text_size - (gint)entry->n_bytes - 1) - { - new_text_length = (gint)entry->text_size - (gint)entry->n_bytes - 1; - new_text_length = g_utf8_find_prev_char (new_text, new_text + new_text_length + 1) - new_text; - n_chars = g_utf8_strlen (new_text, new_text_length); - } - break; - } - } - } + if (n_inserted != n_chars) + gtk_widget_error_bell (GTK_WIDGET (editable)); - if (entry->visible) - entry->text = g_realloc (entry->text, entry->text_size); - else - { - /* Same thing, just slower and without leaving stuff in memory. */ - gchar *et_new = g_malloc (entry->text_size); - memcpy (et_new, entry->text, MIN (prev_size, entry->text_size)); - trash_area (entry->text, prev_size); - g_free (entry->text); - entry->text = et_new; - } - } + *position += n_inserted; +} - index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text; +static void +gtk_entry_real_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + /* + * The actual deletion from the buffer. This will end up firing the + * following signal handlers: buffer_deleted_text(), buffer_notify_display_text(), + * buffer_notify_text(), buffer_notify_length() + */ - g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index); - memcpy (entry->text + index, new_text, new_text_length); + gtk_entry_buffer_delete_text (get_buffer (GTK_ENTRY (editable)), start_pos, end_pos - start_pos); +} - entry->n_bytes += new_text_length; - entry->text_length += n_chars; +/* GtkEntryBuffer signal handlers + */ +static void +buffer_inserted_text (GtkEntryBuffer *buffer, + guint position, + const gchar *chars, + guint n_chars, + GtkEntry *entry) +{ + guint password_hint_timeout; - /* NUL terminate for safety and convenience */ - entry->text[entry->n_bytes] = '\0'; - - if (entry->current_pos > *position) + if (entry->current_pos > position) entry->current_pos += n_chars; - - if (entry->selection_bound > *position) + + if (entry->selection_bound > position) entry->selection_bound += n_chars; - if (n_chars == 1 && !entry->visible && (new_text_length < PASSWORD_HINT_MAX)) + /* Calculate the password hint if it needs to be displayed. */ + if (n_chars == 1 && !entry->visible) { - guint password_hint_timeout; - g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)), "gtk-entry-password-hint-timeout", &password_hint_timeout, NULL); @@ -4503,95 +4619,114 @@ gtk_entry_real_insert_text (GtkEditable *editable, { GtkEntryPasswordHint *password_hint = g_object_get_qdata (G_OBJECT (entry), quark_password_hint); - if (!password_hint) { password_hint = g_slice_new0 (GtkEntryPasswordHint); - g_object_set_qdata_full (G_OBJECT (entry), quark_password_hint, - password_hint, - (GDestroyNotify) gtk_entry_password_hint_free); + g_object_set_qdata_full (G_OBJECT (entry), quark_password_hint, password_hint, + (GDestroyNotify)gtk_entry_password_hint_free); } - memset (&password_hint->password_hint, 0x0, PASSWORD_HINT_MAX); - password_hint->password_hint_length = new_text_length; - memcpy (&password_hint->password_hint, new_text, new_text_length); - password_hint->password_hint_position = *position + n_chars; - } - } - else - { - g_object_set_qdata (G_OBJECT (entry), quark_password_hint, NULL); + password_hint->position = position; + if (password_hint->source_id) + g_source_remove (password_hint->source_id); + password_hint->source_id = gdk_threads_add_timeout (password_hint_timeout, + (GSourceFunc)gtk_entry_remove_password_hint, entry); + } } - - *position += n_chars; - - gtk_entry_recompute (entry); - - emit_changed (entry); - g_object_notify (G_OBJECT (editable), "text"); - g_object_notify (G_OBJECT (editable), "text-length"); } static void -gtk_entry_real_delete_text (GtkEditable *editable, - gint start_pos, - gint end_pos) +buffer_deleted_text (GtkEntryBuffer *buffer, + guint position, + guint n_chars, + GtkEntry *entry) { - GtkEntry *entry = GTK_ENTRY (editable); + guint end_pos = position + n_chars; + gint selection_bound; + guint current_pos; - if (start_pos < 0) - start_pos = 0; - if (end_pos < 0 || end_pos > entry->text_length) - end_pos = entry->text_length; - - if (start_pos < end_pos) - { - gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text; - gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text; - gint current_pos; - gint selection_bound; - - g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes + 1 - end_index); - entry->text_length -= (end_pos - start_pos); - entry->n_bytes -= (end_index - start_index); - - /* In password-mode, make sure we don't leave anything sensitive after - * the terminating zero. Note, that the terminating zero already trashed - * one byte. - */ - if (!entry->visible) - trash_area (entry->text + entry->n_bytes + 1, end_index - start_index - 1); - - current_pos = entry->current_pos; - if (current_pos > start_pos) - current_pos -= MIN (current_pos, end_pos) - start_pos; + current_pos = entry->current_pos; + if (current_pos > position) + current_pos -= MIN (current_pos, end_pos) - position; - selection_bound = entry->selection_bound; - if (selection_bound > start_pos) - selection_bound -= MIN (selection_bound, end_pos) - start_pos; + selection_bound = entry->selection_bound; + if (selection_bound > position) + selection_bound -= MIN (selection_bound, end_pos) - position; - gtk_entry_set_positions (entry, current_pos, selection_bound); + gtk_entry_set_positions (entry, current_pos, selection_bound); - /* We might have deleted the selection - */ - gtk_entry_update_primary_selection (entry); - - gtk_entry_recompute (entry); + /* We might have deleted the selection */ + gtk_entry_update_primary_selection (entry); - emit_changed (entry); - g_object_notify (G_OBJECT (editable), "text"); - g_object_notify (G_OBJECT (editable), "text-length"); + /* Disable the password hint if one exists. */ + if (!entry->visible) + { + GtkEntryPasswordHint *password_hint = g_object_get_qdata (G_OBJECT (entry), + quark_password_hint); + if (password_hint) + { + if (password_hint->source_id) + g_source_remove (password_hint->source_id); + password_hint->source_id = 0; + password_hint->position = -1; + } } } -/* Compute the X position for an offset that corresponds to the "more important - * cursor position for that offset. We use this when trying to guess to which - * end of the selection we should go to when the user hits the left or - * right arrow key. - */ -static gint -get_better_cursor_x (GtkEntry *entry, - gint offset) +static void +buffer_notify_text (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry) +{ + gtk_entry_recompute (entry); + emit_changed (entry); + g_object_notify (G_OBJECT (entry), "text"); +} + +static void +buffer_notify_length (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry) +{ + g_object_notify (G_OBJECT (entry), "text-length"); +} + +static void +buffer_notify_max_length (GtkEntryBuffer *buffer, + GParamSpec *spec, + GtkEntry *entry) +{ + g_object_notify (G_OBJECT (entry), "max-length"); +} + +static void +buffer_connect_signals (GtkEntry *entry) +{ + g_signal_connect (get_buffer (entry), "inserted-text", G_CALLBACK (buffer_inserted_text), entry); + g_signal_connect (get_buffer (entry), "deleted-text", G_CALLBACK (buffer_deleted_text), entry); + g_signal_connect (get_buffer (entry), "notify::text", G_CALLBACK (buffer_notify_text), entry); + g_signal_connect (get_buffer (entry), "notify::length", G_CALLBACK (buffer_notify_length), entry); + g_signal_connect (get_buffer (entry), "notify::max-length", G_CALLBACK (buffer_notify_max_length), entry); +} + +static void +buffer_disconnect_signals (GtkEntry *entry) +{ + g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_inserted_text, entry); + g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_deleted_text, entry); + g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_text, entry); + g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_length, entry); + g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_max_length, entry); +} + +/* Compute the X position for an offset that corresponds to the "more important + * cursor position for that offset. We use this when trying to guess to which + * end of the selection we should go to when the user hits the left or + * right arrow key. + */ +static gint +get_better_cursor_x (GtkEntry *entry, + gint offset) { GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry))); PangoDirection keymap_direction = gdk_keymap_get_direction (keymap); @@ -4622,6 +4757,7 @@ gtk_entry_move_cursor (GtkEntry *entry, gboolean extend_selection) { gint new_pos = entry->current_pos; + GtkEntryPrivate *priv; _gtk_entry_reset_im_context (entry); @@ -4653,7 +4789,8 @@ gtk_entry_move_cursor (GtkEntry *entry, case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; + priv = GTK_ENTRY_GET_PRIVATE (entry); + new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry)); break; case GTK_MOVEMENT_DISPLAY_LINES: case GTK_MOVEMENT_PARAGRAPHS: @@ -4710,7 +4847,8 @@ gtk_entry_move_cursor (GtkEntry *entry, case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; + priv = GTK_ENTRY_GET_PRIVATE (entry); + new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry)); if (entry->current_pos == new_pos) gtk_widget_error_bell (GTK_WIDGET (entry)); break; @@ -4754,7 +4892,7 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, GtkEditable *editable = GTK_EDITABLE (entry); gint start_pos = entry->current_pos; gint end_pos = entry->current_pos; - gint old_n_bytes = entry->n_bytes; + gint old_n_bytes = gtk_entry_buffer_get_bytes (get_buffer (entry)); _gtk_entry_reset_im_context (entry); @@ -4820,7 +4958,7 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, break; } - if (entry->n_bytes == old_n_bytes) + if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == old_n_bytes) gtk_widget_error_bell (GTK_WIDGET (entry)); gtk_entry_pend_cursor_blink (entry); @@ -4834,7 +4972,7 @@ gtk_entry_backspace (GtkEntry *entry) _gtk_entry_reset_im_context (entry); - if (!entry->editable || !entry->text) + if (!entry->editable) { gtk_widget_error_bell (GTK_WIDGET (entry)); return; @@ -4856,16 +4994,15 @@ gtk_entry_backspace (GtkEntry *entry) pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); - if (entry->visible && - log_attrs[entry->current_pos].backspace_deletes_character) + /* Deleting parts of characters */ + if (log_attrs[entry->current_pos].backspace_deletes_character) { gchar *cluster_text; gchar *normalized_text; glong len; - cluster_text = gtk_editable_get_chars (editable, - prev_pos, - entry->current_pos); + cluster_text = gtk_entry_get_display_text (entry, prev_pos, + entry->current_pos); normalized_text = g_utf8_normalize (cluster_text, strlen (cluster_text), G_NORMALIZE_NFD); @@ -4915,7 +5052,7 @@ gtk_entry_copy_clipboard (GtkEntry *entry) return; } - str = gtk_entry_get_public_chars (entry, start, end); + str = gtk_entry_get_display_text (entry, start, end); gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD), str, -1); @@ -4988,6 +5125,7 @@ static void gtk_entry_real_activate (GtkEntry *entry) { GtkWindow *window; + GtkWidget *default_widget, *focus_widget; GtkWidget *toplevel; GtkWidget *widget; @@ -4999,12 +5137,15 @@ gtk_entry_real_activate (GtkEntry *entry) if (GTK_IS_WINDOW (toplevel)) { window = GTK_WINDOW (toplevel); - - if (window && - widget != window->default_widget && - !(widget == window->focus_widget && - (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget)))) - gtk_window_activate_default (window); + + if (window) + { + default_widget = gtk_window_get_default_widget (window); + focus_widget = gtk_window_get_focus (window); + if (widget != default_widget && + !(widget == focus_widget && (!default_widget || !gtk_widget_get_sensitive (default_widget)))) + gtk_window_activate_default (window); + } } } } @@ -5040,6 +5181,7 @@ gtk_entry_preedit_changed_cb (GtkIMContext *context, gtk_im_context_get_preedit_string (entry->im_context, &preedit_string, NULL, &cursor_pos); + g_signal_emit (entry, signals[PREEDIT_CHANGED], 0, preedit_string); entry->preedit_length = strlen (preedit_string); cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); entry->preedit_cursor = cursor_pos; @@ -5053,10 +5195,13 @@ static gboolean gtk_entry_retrieve_surrounding_cb (GtkIMContext *context, GtkEntry *entry) { - gtk_im_context_set_surrounding (context, - entry->text, - entry->n_bytes, - g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text); + gchar *text; + + /* XXXX ??? does this even make sense when text is not visible? Should we return FALSE? */ + text = gtk_entry_get_display_text (entry, 0, -1); + gtk_im_context_set_surrounding (context, text, strlen (text), /* Length in bytes */ + g_utf8_offset_to_pointer (text, entry->current_pos) - text); + g_free (text); return TRUE; } @@ -5215,34 +5360,6 @@ gtk_entry_recompute (GtkEntry *entry) } } -static void -append_char (GString *str, - gunichar ch, - gint count) -{ - gint i; - gint char_len; - gchar buf[7]; - - char_len = g_unichar_to_utf8 (ch, buf); - - i = 0; - while (i < count) - { - g_string_append_len (str, buf, char_len); - ++i; - } -} - -static gboolean -gtk_entry_remove_password_hint (gpointer data) -{ - /* Force the string to be redrawn, but now without a visible character */ - gtk_entry_recompute (GTK_ENTRY (data)); - - return FALSE; -} - static PangoLayout * gtk_entry_create_layout (GtkEntry *entry, gboolean include_preedit) @@ -5250,13 +5367,19 @@ gtk_entry_create_layout (GtkEntry *entry, GtkWidget *widget = GTK_WIDGET (entry); PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL); PangoAttrList *tmp_attrs = pango_attr_list_new (); - + gchar *preedit_string = NULL; gint preedit_length = 0; PangoAttrList *preedit_attrs = NULL; + gchar *display; + guint n_bytes; + pango_layout_set_single_paragraph_mode (layout, TRUE); + display = gtk_entry_get_display_text (entry, 0, -1); + n_bytes = strlen (display); + if (include_preedit) { gtk_im_context_get_preedit_string (entry->im_context, @@ -5266,32 +5389,10 @@ gtk_entry_create_layout (GtkEntry *entry, if (preedit_length) { - GString *tmp_string = g_string_new (NULL); + GString *tmp_string = g_string_new (display); + gint cursor_index = g_utf8_offset_to_pointer (display, entry->current_pos) - display; - gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text; - - if (entry->visible) - { - g_string_prepend_len (tmp_string, entry->text, entry->n_bytes); - g_string_insert (tmp_string, cursor_index, preedit_string); - } - else - { - gint ch_len; - gunichar invisible_char; - - if (entry->invisible_char != 0) - invisible_char = entry->invisible_char; - else - invisible_char = ' '; /* just pick a char */ - - ch_len = g_utf8_strlen (entry->text, entry->n_bytes); - append_char (tmp_string, invisible_char, ch_len); - cursor_index = - g_utf8_offset_to_pointer (tmp_string->str, entry->current_pos) - - tmp_string->str; - g_string_insert (tmp_string, cursor_index, preedit_string); - } + g_string_insert (tmp_string, cursor_index, preedit_string); pango_layout_set_text (layout, tmp_string->str, tmp_string->len); @@ -5304,15 +5405,14 @@ gtk_entry_create_layout (GtkEntry *entry, { PangoDirection pango_dir; - if (entry->visible) - pango_dir = pango_find_base_dir (entry->text, entry->n_bytes); - + if (gtk_entry_get_display_mode (entry) == DISPLAY_NORMAL) + pango_dir = pango_find_base_dir (display, n_bytes); else pango_dir = PANGO_DIRECTION_NEUTRAL; if (pango_dir == PANGO_DIRECTION_NEUTRAL) { - if (GTK_WIDGET_HAS_FOCUS (widget)) + if (gtk_widget_has_focus (widget)) { GdkDisplay *display = gtk_widget_get_display (widget); GdkKeymap *keymap = gdk_keymap_get_for_display (display); @@ -5334,78 +5434,15 @@ gtk_entry_create_layout (GtkEntry *entry, pango_dir); entry->resolved_dir = pango_dir; - - if (entry->visible) - { - pango_layout_set_text (layout, entry->text, entry->n_bytes); - } - else - { - GString *str = g_string_new (NULL); - gunichar invisible_char; - guint password_hint_timeout; - GtkEntryPasswordHint *password_hint; - - g_object_get (gtk_widget_get_settings (widget), - "gtk-entry-password-hint-timeout", &password_hint_timeout, - NULL); - - if (entry->invisible_char != 0) - invisible_char = entry->invisible_char; - else - invisible_char = ' '; /* just pick a char */ - - password_hint = g_object_get_qdata (G_OBJECT (entry), - quark_password_hint); - - if (password_hint && password_hint->password_hint_timeout_id) - { - g_source_remove (password_hint->password_hint_timeout_id); - password_hint->password_hint_timeout_id = 0; - } - - if (password_hint_timeout == 0 || password_hint == NULL || - (password_hint && password_hint->password_hint_length == 0)) - { - append_char (str, invisible_char, entry->text_length); - } - else if (password_hint) - { - /* Draw hidden characters upto the inserted position, - * then the real thing, pad up to full length - */ - if (password_hint->password_hint_position > 1) - append_char (str, invisible_char, - password_hint->password_hint_position - 1); - - g_string_append_len (str, password_hint->password_hint, - password_hint->password_hint_length); - - if (password_hint->password_hint_position < entry->text_length) - append_char (str, invisible_char, - entry->text_length - - password_hint->password_hint_position); - - /* Now remove this last input character, don't need - * it anymore - */ - memset (password_hint->password_hint, 0, PASSWORD_HINT_MAX); - password_hint->password_hint_length = 0; - - password_hint->password_hint_timeout_id = - gdk_threads_add_timeout (password_hint_timeout, - (GSourceFunc) gtk_entry_remove_password_hint, - entry); - } - pango_layout_set_text (layout, str->str, str->len); - g_string_free (str, TRUE); - } + pango_layout_set_text (layout, display, n_bytes); } pango_layout_set_attributes (layout, tmp_attrs); g_free (preedit_string); + g_free (display); + if (preedit_attrs) pango_attr_list_unref (preedit_attrs); @@ -5499,19 +5536,22 @@ draw_text_with_color (GtkEntry *entry, cairo_t *cr, GdkColor *default_color) PangoRectangle logical_rect; GdkColor *selection_color, *text_color; GtkBorder inner_border; + GtkStyle *style; pango_layout_get_pixel_extents (layout, NULL, &logical_rect); gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); - if (GTK_WIDGET_HAS_FOCUS (entry)) + style = gtk_widget_get_style (widget); + + if (gtk_widget_has_focus (widget)) { - selection_color = &widget->style->base [GTK_STATE_SELECTED]; - text_color = &widget->style->text [GTK_STATE_SELECTED]; + selection_color = &style->base [GTK_STATE_SELECTED]; + text_color = &style->text [GTK_STATE_SELECTED]; } else { - selection_color = &widget->style->base [GTK_STATE_ACTIVE]; - text_color = &widget->style->text [GTK_STATE_ACTIVE]; + selection_color = &style->base [GTK_STATE_ACTIVE]; + text_color = &style->text [GTK_STATE_ACTIVE]; } _gtk_entry_effective_inner_border (entry, &inner_border); @@ -5538,77 +5578,79 @@ draw_text_with_color (GtkEntry *entry, cairo_t *cr, GdkColor *default_color) } static void -gtk_entry_draw_text (GtkEntry *entry) +gtk_entry_draw_text (GtkEntry *entry, + cairo_t *cr) { GtkWidget *widget = GTK_WIDGET (entry); - cairo_t *cr; + GtkStateType state; + GtkStyle *style; + GdkColor text_color, bar_text_color; + gint pos_x, pos_y; + gint width, height; + gint progress_x, progress_y, progress_width, progress_height; + - if (!entry->visible && entry->invisible_char == 0) + /* Nothing to display at all */ + if (gtk_entry_get_display_mode (entry) == DISPLAY_BLANK) return; - if (GTK_WIDGET_DRAWABLE (entry)) - { - GdkColor text_color, bar_text_color; - gint pos_x, pos_y; - gint width, height; - gint progress_x, progress_y, progress_width, progress_height; - GtkStateType state; - - state = GTK_STATE_SELECTED; - if (!GTK_WIDGET_SENSITIVE (widget)) - state = GTK_STATE_INSENSITIVE; - text_color = widget->style->text[widget->state]; - bar_text_color = widget->style->fg[state]; + state = GTK_STATE_SELECTED; + if (!gtk_widget_get_sensitive (widget)) + state = GTK_STATE_INSENSITIVE; + style = gtk_widget_get_style (widget); + text_color = style->text[gtk_widget_get_state (widget)]; + bar_text_color = style->fg[state]; - get_progress_area (widget, - &progress_x, &progress_y, - &progress_width, &progress_height); + get_progress_area (widget, + &progress_x, &progress_y, + &progress_width, &progress_height); - cr = gdk_cairo_create (entry->text_area); + /* If the color is the same, or the progress area has a zero + * size, then we only need to draw once. */ + if ((text_color.pixel == bar_text_color.pixel) || + ((progress_width == 0) || (progress_height == 0))) + { + draw_text_with_color (entry, cr, &text_color); + } + else + { + width = gdk_window_get_width (entry->text_area); + height = gdk_window_get_height (entry->text_area); - /* If the color is the same, or the progress area has a zero - * size, then we only need to draw once. */ - if ((text_color.pixel == bar_text_color.pixel) || - ((progress_width == 0) || (progress_height == 0))) - { - draw_text_with_color (entry, cr, &text_color); - } - else - { - gdk_drawable_get_size (entry->text_area, &width, &height); + cairo_save (cr); - cairo_rectangle (cr, 0, 0, width, height); - cairo_clip (cr); - cairo_save (cr); + cairo_rectangle (cr, 0, 0, width, height); + cairo_clip (cr); + cairo_save (cr); - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_rectangle (cr, 0, 0, width, height); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, width, height); - gdk_window_get_position (entry->text_area, &pos_x, &pos_y); - progress_x -= pos_x; - progress_y -= pos_y; + gdk_window_get_position (entry->text_area, &pos_x, &pos_y); + progress_x -= pos_x; + progress_y -= pos_y; - cairo_rectangle (cr, progress_x, progress_y, - progress_width, progress_height); - cairo_clip (cr); - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); - - draw_text_with_color (entry, cr, &text_color); - cairo_restore (cr); + cairo_rectangle (cr, progress_x, progress_y, + progress_width, progress_height); + cairo_clip (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + draw_text_with_color (entry, cr, &text_color); + cairo_restore (cr); - cairo_rectangle (cr, progress_x, progress_y, - progress_width, progress_height); - cairo_clip (cr); + cairo_rectangle (cr, progress_x, progress_y, + progress_width, progress_height); + cairo_clip (cr); - draw_text_with_color (entry, cr, &bar_text_color); - } + draw_text_with_color (entry, cr, &bar_text_color); - cairo_destroy (cr); + cairo_restore (cr); } } static void draw_insertion_cursor (GtkEntry *entry, + cairo_t *cr, GdkRectangle *cursor_location, gboolean is_primary, PangoDirection direction, @@ -5622,138 +5664,134 @@ draw_insertion_cursor (GtkEntry *entry, else text_dir = GTK_TEXT_DIR_RTL; - gtk_draw_insertion_cursor (widget, entry->text_area, NULL, + gtk_draw_insertion_cursor (widget, cr, cursor_location, is_primary, text_dir, draw_arrow); } static void gtk_entry_draw_cursor (GtkEntry *entry, + cairo_t *cr, CursorType type) { + GtkWidget *widget = GTK_WIDGET (entry); GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry))); PangoDirection keymap_direction = gdk_keymap_get_direction (keymap); - - if (GTK_WIDGET_DRAWABLE (entry)) - { - GtkWidget *widget = GTK_WIDGET (entry); - GdkRectangle cursor_location; - gboolean split_cursor; - PangoRectangle cursor_rect; - GtkBorder inner_border; - gint xoffset; - gint text_area_height; - gint cursor_index; - gboolean block; - gboolean block_at_line_end; - PangoLayout *layout; - const char *text; - - _gtk_entry_effective_inner_border (entry, &inner_border); - - xoffset = inner_border.left - entry->scroll_offset; + GdkRectangle cursor_location; + gboolean split_cursor; + PangoRectangle cursor_rect; + GtkBorder inner_border; + gint xoffset; + gint text_area_height; + gint cursor_index; + gboolean block; + gboolean block_at_line_end; + PangoLayout *layout; + const char *text; - gdk_drawable_get_size (entry->text_area, NULL, &text_area_height); + _gtk_entry_effective_inner_border (entry, &inner_border); - layout = gtk_entry_ensure_layout (entry, TRUE); - text = pango_layout_get_text (layout); - cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text; - if (!entry->overwrite_mode) - block = FALSE; - else - block = _gtk_text_util_get_block_cursor_location (layout, - cursor_index, &cursor_rect, &block_at_line_end); + xoffset = inner_border.left - entry->scroll_offset; - if (!block) - { - gint strong_x, weak_x; - PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; - PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; - gint x1 = 0; - gint x2 = 0; + text_area_height = gdk_window_get_height (entry->text_area); - gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); + layout = gtk_entry_ensure_layout (entry, TRUE); + text = pango_layout_get_text (layout); + cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text; + if (!entry->overwrite_mode) + block = FALSE; + else + block = _gtk_text_util_get_block_cursor_location (layout, + cursor_index, &cursor_rect, &block_at_line_end); - g_object_get (gtk_widget_get_settings (widget), - "gtk-split-cursor", &split_cursor, - NULL); + if (!block) + { + gint strong_x, weak_x; + PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; + PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; + gint x1 = 0; + gint x2 = 0; - dir1 = entry->resolved_dir; - - if (split_cursor) - { - x1 = strong_x; + gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); - if (weak_x != strong_x) - { - dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; - x2 = weak_x; - } - } - else - { - if (keymap_direction == entry->resolved_dir) - x1 = strong_x; - else - x1 = weak_x; - } + g_object_get (gtk_widget_get_settings (widget), + "gtk-split-cursor", &split_cursor, + NULL); - cursor_location.x = xoffset + x1; - cursor_location.y = inner_border.top; - cursor_location.width = 0; - cursor_location.height = text_area_height - inner_border.top - inner_border.bottom; + dir1 = entry->resolved_dir; + + if (split_cursor) + { + x1 = strong_x; - draw_insertion_cursor (entry, - &cursor_location, TRUE, dir1, - dir2 != PANGO_DIRECTION_NEUTRAL); - - if (dir2 != PANGO_DIRECTION_NEUTRAL) + if (weak_x != strong_x) { - cursor_location.x = xoffset + x2; - draw_insertion_cursor (entry, - &cursor_location, FALSE, dir2, - TRUE); + dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; + x2 = weak_x; } } - else /* overwrite_mode */ + else { - GdkColor cursor_color; - GdkRectangle rect; - cairo_t *cr; - gint x, y; + if (keymap_direction == entry->resolved_dir) + x1 = strong_x; + else + x1 = weak_x; + } - get_layout_position (entry, &x, &y); + cursor_location.x = xoffset + x1; + cursor_location.y = inner_border.top; + cursor_location.width = 0; + cursor_location.height = text_area_height - inner_border.top - inner_border.bottom; - rect.x = PANGO_PIXELS (cursor_rect.x) + x; - rect.y = PANGO_PIXELS (cursor_rect.y) + y; - rect.width = PANGO_PIXELS (cursor_rect.width); - rect.height = PANGO_PIXELS (cursor_rect.height); + draw_insertion_cursor (entry, cr, + &cursor_location, TRUE, dir1, + dir2 != PANGO_DIRECTION_NEUTRAL); + + if (dir2 != PANGO_DIRECTION_NEUTRAL) + { + cursor_location.x = xoffset + x2; + draw_insertion_cursor (entry, cr, + &cursor_location, FALSE, dir2, + TRUE); + } + } + else /* overwrite_mode */ + { + GdkColor cursor_color; + GdkRectangle rect; + gint x, y; - cr = gdk_cairo_create (entry->text_area); + cairo_save (cr); - _gtk_widget_get_cursor_color (widget, &cursor_color); - gdk_cairo_set_source_color (cr, &cursor_color); - gdk_cairo_rectangle (cr, &rect); - cairo_fill (cr); + get_layout_position (entry, &x, &y); - if (!block_at_line_end) - { - gdk_cairo_rectangle (cr, &rect); - cairo_clip (cr); - cairo_move_to (cr, x, y); - gdk_cairo_set_source_color (cr, &widget->style->base[widget->state]); - pango_cairo_show_layout (cr, layout); - } + rect.x = PANGO_PIXELS (cursor_rect.x) + x; + rect.y = PANGO_PIXELS (cursor_rect.y) + y; + rect.width = PANGO_PIXELS (cursor_rect.width); + rect.height = PANGO_PIXELS (cursor_rect.height); + + _gtk_widget_get_cursor_color (widget, &cursor_color); + gdk_cairo_set_source_color (cr, &cursor_color); + gdk_cairo_rectangle (cr, &rect); + cairo_fill (cr); - cairo_destroy (cr); + if (!block_at_line_end) + { + gdk_cairo_rectangle (cr, &rect); + cairo_clip (cr); + cairo_move_to (cr, x, y); + gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]); + pango_cairo_show_layout (cr, layout); } + + cairo_restore (cr); } } static void gtk_entry_queue_draw (GtkEntry *entry) { - if (GTK_WIDGET_DRAWABLE (entry)) + if (gtk_widget_is_drawable (GTK_WIDGET (entry))) gdk_window_invalidate_rect (entry->text_area, NULL, FALSE); } @@ -5767,6 +5805,55 @@ _gtk_entry_reset_im_context (GtkEntry *entry) } } +/** + * gtk_entry_reset_im_context: + * @entry: a #GtkEntry + * + * Reset the input method context of the entry if needed. + * + * This can be necessary in the case where modifying the buffer + * would confuse on-going input method behavior. + * + * Since: 2.22 + */ +void +gtk_entry_reset_im_context (GtkEntry *entry) +{ + g_return_if_fail (GTK_IS_ENTRY (entry)); + + _gtk_entry_reset_im_context (entry); +} + +/** + * gtk_entry_im_context_filter_keypress: + * @entry: a #GtkEntry + * @event: the key event + * + * Allow the #GtkEntry input method to internally handle key press + * and release events. If this function returns %TRUE, then no further + * processing should be done for this key event. See + * gtk_im_context_filter_keypress(). + * + * Note that you are expected to call this function from your handler + * when overriding key event handling. This is needed in the case when + * you need to insert your own key handling between the input method + * and the default key event handling of the #GtkEntry. + * See gtk_text_view_reset_im_context() for an example of use. + * + * Return value: %TRUE if the input method handled the key event. + * + * Since: 2.22 + */ +gboolean +gtk_entry_im_context_filter_keypress (GtkEntry *entry, + GdkEventKey *event) +{ + g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); + + return gtk_im_context_filter_keypress (entry->im_context, event); +} + + static gint gtk_entry_find_position (GtkEntry *entry, gint x) @@ -5809,7 +5896,10 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, gint *strong_x, gint *weak_x) { - if (!entry->visible && !entry->invisible_char) + DisplayMode mode = gtk_entry_get_display_mode (entry); + + /* Nothing to display at all, so no cursor is relevant */ + if (mode == DISPLAY_BLANK) { if (strong_x) *strong_x = 0; @@ -5834,11 +5924,11 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, if (entry->dnd_position > entry->current_pos) { - if (entry->visible) + if (mode == DISPLAY_NORMAL) index += entry->preedit_length; else { - gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length; + gint preedit_len_chars = g_utf8_strlen (text, -1) - gtk_entry_buffer_get_length (get_buffer (entry)); index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL); } } @@ -5868,12 +5958,12 @@ gtk_entry_adjust_scroll (GtkEntry *entry) PangoLayoutLine *line; PangoRectangle logical_rect; - if (!GTK_WIDGET_REALIZED (entry)) + if (!gtk_widget_get_realized (GTK_WIDGET (entry))) return; _gtk_entry_effective_inner_border (entry, &inner_border); - gdk_drawable_get_size (entry->text_area, &text_area_width, NULL); + text_area_width = gdk_window_get_width (entry->text_area); text_area_width -= inner_border.left + inner_border.right; if (text_area_width < 0) text_area_width = 0; @@ -5952,26 +6042,29 @@ gtk_entry_adjust_scroll (GtkEntry *entry) static void gtk_entry_move_adjustments (GtkEntry *entry) { + GtkAllocation allocation; + GtkAdjustment *adjustment; PangoContext *context; PangoFontMetrics *metrics; gint x, layout_x, border_x, border_y; gint char_width; - GtkAdjustment *adjustment; adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment); if (!adjustment) return; + gtk_widget_get_allocation (&(entry->widget), &allocation); + /* Cursor position, layout offset, border width, and widget allocation */ gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL); get_layout_position (entry, &layout_x, NULL); _gtk_entry_get_borders (entry, &border_x, &border_y); - x += entry->widget.allocation.x + layout_x + border_x; + x += allocation.x + layout_x + border_x; /* Approximate width of a char, so user can see what is ahead/behind */ context = gtk_widget_get_pango_context (GTK_WIDGET (entry)); metrics = pango_context_get_metrics (context, - entry->widget.style->font_desc, + gtk_widget_get_style (&(entry->widget))->font_desc, pango_context_get_language (context)); char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE; @@ -6043,13 +6136,16 @@ gtk_entry_move_logically (GtkEntry *entry, gint count) { gint new_pos = start; + guint length; + + length = gtk_entry_buffer_get_length (get_buffer (entry)); /* Prevent any leak of information */ - if (!entry->visible) + if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL) { - new_pos = CLAMP (start + count, 0, entry->text_length); + new_pos = CLAMP (start + count, 0, length); } - else if (entry->text) + else { PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); PangoLogAttr *log_attrs; @@ -6057,11 +6153,11 @@ gtk_entry_move_logically (GtkEntry *entry, pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); - while (count > 0 && new_pos < entry->text_length) + while (count > 0 && new_pos < length) { do new_pos++; - while (new_pos < entry->text_length && !log_attrs[new_pos].is_cursor_position); + while (new_pos < length && !log_attrs[new_pos].is_cursor_position); count--; } @@ -6086,13 +6182,16 @@ gtk_entry_move_forward_word (GtkEntry *entry, gboolean allow_whitespace) { gint new_pos = start; + guint length; + + length = gtk_entry_buffer_get_length (get_buffer (entry)); /* Prevent any leak of information */ - if (!entry->visible) + if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL) { - new_pos = entry->text_length; + new_pos = length; } - else if (entry->text && (new_pos < entry->text_length)) + else if (new_pos < length) { PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); PangoLogAttr *log_attrs; @@ -6121,11 +6220,11 @@ gtk_entry_move_backward_word (GtkEntry *entry, gint new_pos = start; /* Prevent any leak of information */ - if (!entry->visible) + if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL) { new_pos = 0; } - else if (entry->text && start > 0) + else if (start > 0) { PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); PangoLogAttr *log_attrs; @@ -6186,30 +6285,6 @@ gtk_entry_select_line (GtkEntry *entry) gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); } -/* - * Like gtk_editable_get_chars, but handle not-visible entries - * correctly. - */ -static char * -gtk_entry_get_public_chars (GtkEntry *entry, - gint start, - gint end) -{ - if (end < 0) - end = entry->text_length; - - if (entry->visible) - return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end); - else if (!entry->invisible_char) - return g_strdup (""); - else - { - GString *str = g_string_new (NULL); - append_char (str, entry->invisible_char, end - start); - return g_string_free (str, FALSE); - } -} - static gint truncate_multiline (const gchar *text) { @@ -6253,11 +6328,12 @@ paste_received (GtkClipboard *clipboard, length = truncate_multiline (text); /* only complete if the selection is at the end */ - popup_completion = (entry->text_length == MAX (entry->current_pos, entry->selection_bound)); + popup_completion = (gtk_entry_buffer_get_length (get_buffer (entry)) == + MAX (entry->current_pos, entry->selection_bound)); if (completion) { - if (GTK_WIDGET_MAPPED (completion->priv->popup_window)) + if (gtk_widget_get_mapped (completion->priv->popup_window)) _gtk_entry_completion_popdown (completion); if (!popup_completion && completion->priv->changed_id > 0) @@ -6303,7 +6379,7 @@ primary_get_cb (GtkClipboard *clipboard, if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end)) { - gchar *str = gtk_entry_get_public_chars (entry, start, end); + gchar *str = gtk_entry_get_display_text (entry, start, end); gtk_selection_data_set_text (selection_data, str, -1); g_free (str); } @@ -6327,7 +6403,7 @@ gtk_entry_update_primary_selection (GtkEntry *entry) gint start, end; gint n_targets; - if (!GTK_WIDGET_REALIZED (entry)) + if (!gtk_widget_get_realized (GTK_WIDGET (entry))) return; list = gtk_target_list_new (NULL, 0); @@ -6426,38 +6502,41 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, { GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); EntryIconInfo *icon_info = priv->icons[icon_pos]; - GdkScreen *screen; + GtkIconInfo *info; GtkIconTheme *icon_theme; GtkSettings *settings; + GtkStateType state; + GtkWidget *widget; + GdkScreen *screen; gint width, height; - GtkIconInfo *info; - gint state; if (!icon_info || icon_info->pixbuf) return; + widget = GTK_WIDGET (entry); + switch (icon_info->storage_type) { case GTK_IMAGE_EMPTY: case GTK_IMAGE_PIXBUF: break; case GTK_IMAGE_STOCK: - state = GTK_WIDGET_STATE (entry); - GTK_WIDGET_STATE (entry) = GTK_STATE_NORMAL; - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), + state = gtk_widget_get_state (widget); + gtk_widget_set_state (widget, GTK_STATE_NORMAL); + icon_info->pixbuf = gtk_widget_render_icon (widget, icon_info->stock_id, GTK_ICON_SIZE_MENU, NULL); if (!icon_info->pixbuf) - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), + icon_info->pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); - GTK_WIDGET_STATE (entry) = state; + gtk_widget_set_state (widget, state); break; case GTK_IMAGE_ICON_NAME: - screen = gtk_widget_get_screen (GTK_WIDGET (entry)); + screen = gtk_widget_get_screen (widget); if (screen) { icon_theme = gtk_icon_theme_get_for_screen (screen); @@ -6474,19 +6553,19 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, if (icon_info->pixbuf == NULL) { - state = GTK_WIDGET_STATE (entry); - GTK_WIDGET_STATE (entry) = GTK_STATE_NORMAL; - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), + state = gtk_widget_get_state (widget); + gtk_widget_set_state (widget, GTK_STATE_NORMAL); + icon_info->pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); - GTK_WIDGET_STATE (entry) = state; + gtk_widget_set_state (widget, state); } } break; case GTK_IMAGE_GICON: - screen = gtk_widget_get_screen (GTK_WIDGET (entry)); + screen = gtk_widget_get_screen (widget); if (screen) { icon_theme = gtk_icon_theme_get_for_screen (screen); @@ -6508,13 +6587,13 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, if (icon_info->pixbuf == NULL) { - state = GTK_WIDGET_STATE (entry); - GTK_WIDGET_STATE (entry) = GTK_STATE_NORMAL; - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), + state = gtk_widget_get_state (widget); + gtk_widget_set_state (widget, GTK_STATE_NORMAL); + icon_info->pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); - GTK_WIDGET_STATE (entry) = state; + gtk_widget_set_state (widget, state); } } break; @@ -6546,136 +6625,175 @@ gtk_entry_new (void) } /** - * gtk_entry_new_with_max_length: - * @max: the maximum length of the entry, or 0 for no maximum. - * (other than the maximum length of entries.) The value passed in will - * be clamped to the range 0-65536. + * gtk_entry_new_with_buffer: + * @buffer: The buffer to use for the new #GtkEntry. + * + * Creates a new entry with the specified text buffer. * - * Creates a new #GtkEntry widget with the given maximum length. - * * Return value: a new #GtkEntry * - * Deprecated: Use gtk_entry_set_max_length() instead. - **/ + * Since: 2.18 + */ GtkWidget* -gtk_entry_new_with_max_length (gint max) +gtk_entry_new_with_buffer (GtkEntryBuffer *buffer) { - GtkEntry *entry; + g_return_val_if_fail (GTK_IS_ENTRY_BUFFER (buffer), NULL); + return g_object_new (GTK_TYPE_ENTRY, "buffer", buffer, NULL); +} - max = CLAMP (max, 0, MAX_SIZE); +static GtkEntryBuffer* +get_buffer (GtkEntry *entry) +{ + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); - entry = g_object_new (GTK_TYPE_ENTRY, NULL); - entry->text_max_length = max; + if (priv->buffer == NULL) + { + GtkEntryBuffer *buffer; + buffer = gtk_entry_buffer_new (NULL, 0); + gtk_entry_set_buffer (entry, buffer); + g_object_unref (buffer); + } - return GTK_WIDGET (entry); + return priv->buffer; } /** - * gtk_entry_set_text: + * gtk_entry_get_buffer: * @entry: a #GtkEntry - * @text: the new text * - * Sets the text in the widget to the given - * value, replacing the current contents. + * Get the #GtkEntryBuffer object which holds the text for + * this widget. + * + * Since: 2.18 + * + * Returns: (transfer none): A #GtkEntryBuffer object. */ -void -gtk_entry_set_text (GtkEntry *entry, - const gchar *text) +GtkEntryBuffer* +gtk_entry_get_buffer (GtkEntry *entry) { - gint tmp_pos; - GtkEntryCompletion *completion; - - g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); - - /* Actually setting the text will affect the cursor and selection; - * if the contents don't actually change, this will look odd to the user. - */ - if (strcmp (entry->text, text) == 0) - return; - - completion = gtk_entry_get_completion (entry); - if (completion && completion->priv->changed_id > 0) - g_signal_handler_block (entry, completion->priv->changed_id); - - begin_change (entry); - g_object_freeze_notify (G_OBJECT (entry)); - gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); - - tmp_pos = 0; - gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos); - g_object_thaw_notify (G_OBJECT (entry)); - end_change (entry); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - if (completion && completion->priv->changed_id > 0) - g_signal_handler_unblock (entry, completion->priv->changed_id); + return get_buffer (entry); } /** - * gtk_entry_append_text: + * gtk_entry_set_buffer: * @entry: a #GtkEntry - * @text: the text to append + * @buffer: a #GtkEntryBuffer * - * Appends the given text to the contents of the widget. + * Set the #GtkEntryBuffer object which holds the text for + * this widget. * - * Deprecated: 2.0: Use gtk_editable_insert_text() instead. + * Since: 2.18 */ void -gtk_entry_append_text (GtkEntry *entry, - const gchar *text) +gtk_entry_set_buffer (GtkEntry *entry, + GtkEntryBuffer *buffer) { - gint tmp_pos; + GtkEntryPrivate *priv; + GObject *obj; g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); + priv = GTK_ENTRY_GET_PRIVATE (entry); - tmp_pos = entry->text_length; - gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos); + if (buffer) + { + g_return_if_fail (GTK_IS_ENTRY_BUFFER (buffer)); + g_object_ref (buffer); + } + + if (priv->buffer) + { + buffer_disconnect_signals (entry); + g_object_unref (priv->buffer); + } + + priv->buffer = buffer; + + if (priv->buffer) + buffer_connect_signals (entry); + + obj = G_OBJECT (entry); + g_object_freeze_notify (obj); + g_object_notify (obj, "buffer"); + g_object_notify (obj, "text"); + g_object_notify (obj, "text-length"); + g_object_notify (obj, "max-length"); + g_object_notify (obj, "visibility"); + g_object_notify (obj, "invisible-char"); + g_object_notify (obj, "invisible-char-set"); + g_object_thaw_notify (obj); + + gtk_editable_set_position (GTK_EDITABLE (entry), 0); + gtk_entry_recompute (entry); } /** - * gtk_entry_prepend_text: + * gtk_entry_get_text_window: * @entry: a #GtkEntry - * @text: the text to prepend * - * Prepends the given text to the contents of the widget. + * Returns the #GdkWindow which contains the text. This function is + * useful when drawing something to the entry in a draw + * callback because it enables the callback to distinguish between + * the text window and entry's icon windows. * - * Deprecated: 2.0: Use gtk_editable_insert_text() instead. - */ -void -gtk_entry_prepend_text (GtkEntry *entry, - const gchar *text) + * See also gtk_entry_get_icon_window(). + * + * Return value: (transfer none): the entry's text window. + * + * Since: 2.20 + **/ +GdkWindow * +gtk_entry_get_text_window (GtkEntry *entry) { - gint tmp_pos; - - g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - tmp_pos = 0; - gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos); + return entry->text_area; } + /** - * gtk_entry_set_position: + * gtk_entry_set_text: * @entry: a #GtkEntry - * @position: the position of the cursor. The cursor is displayed - * before the character with the given (base 0) index in the widget. - * The value must be less than or equal to the number of characters - * in the widget. A value of -1 indicates that the position should - * be set after the last character in the entry. Note that this - * position is in characters, not in bytes. + * @text: the new text * - * Sets the cursor position in an entry to the given value. + * Sets the text in the widget to the given + * value, replacing the current contents. * - * Deprecated: 2.0: Use gtk_editable_set_position() instead. + * See gtk_entry_buffer_set_text(). */ void -gtk_entry_set_position (GtkEntry *entry, - gint position) +gtk_entry_set_text (GtkEntry *entry, + const gchar *text) { + gint tmp_pos; + GtkEntryCompletion *completion; + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (text != NULL); + priv = GTK_ENTRY_GET_PRIVATE (entry); - gtk_editable_set_position (GTK_EDITABLE (entry), position); + /* Actually setting the text will affect the cursor and selection; + * if the contents don't actually change, this will look odd to the user. + */ + if (strcmp (gtk_entry_buffer_get_text (get_buffer (entry)), text) == 0) + return; + + completion = gtk_entry_get_completion (entry); + if (completion && completion->priv->changed_id > 0) + g_signal_handler_block (entry, completion->priv->changed_id); + + begin_change (entry); + g_object_freeze_notify (G_OBJECT (entry)); + gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); + tmp_pos = 0; + gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos); + g_object_thaw_notify (G_OBJECT (entry)); + end_change (entry); + + if (completion && completion->priv->changed_id > 0) + g_signal_handler_unblock (entry, completion->priv->changed_id); } /** @@ -6818,26 +6936,6 @@ gtk_entry_unset_invisible_char (GtkEntry *entry) gtk_entry_recompute (entry); } -/** - * gtk_entry_set_editable: - * @entry: a #GtkEntry - * @editable: %TRUE if the user is allowed to edit the text - * in the widget - * - * Determines if the user can edit the text in the editable - * widget or not. - * - * Deprecated: 2.0: Use gtk_editable_set_editable() instead. - */ -void -gtk_entry_set_editable (GtkEntry *entry, - gboolean editable) -{ - g_return_if_fail (GTK_IS_ENTRY (entry)); - - gtk_editable_set_editable (GTK_EDITABLE (entry), editable); -} - /** * gtk_entry_set_overwrite_mode: * @entry: a #GtkEntry @@ -6886,6 +6984,12 @@ gtk_entry_get_overwrite_mode (GtkEntry *entry) * Retrieves the contents of the entry widget. * See also gtk_editable_get_chars(). * + * This is equivalent to: + * + * + * gtk_entry_buffer_get_text (gtk_entry_get_buffer (entry)); + * + * * Return value: a pointer to the contents of the widget as a * string. This string points to internally allocated * storage in the widget and must not be freed, modified or @@ -6895,30 +6999,7 @@ G_CONST_RETURN gchar* gtk_entry_get_text (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - - return entry->text; -} - -/** - * gtk_entry_select_region: - * @entry: a #GtkEntry - * @start: the starting position - * @end: the end position - * - * Selects a region of text. The characters that are selected are - * those characters at positions from @start_pos up to, but not - * including @end_pos. If @end_pos is negative, then the the characters - * selected will be those characters from @start_pos to the end of - * the text. - * - * Deprecated: 2.0: Use gtk_editable_select_region() instead. - */ -void -gtk_entry_select_region (GtkEntry *entry, - gint start, - gint end) -{ - gtk_editable_select_region (GTK_EDITABLE (entry), start, end); + return gtk_entry_buffer_get_text (get_buffer (entry)); } /** @@ -6931,20 +7012,19 @@ gtk_entry_select_region (GtkEntry *entry, * Sets the maximum allowed length of the contents of the widget. If * the current contents are longer than the given length, then they * will be truncated to fit. + * + * This is equivalent to: + * + * + * gtk_entry_buffer_set_max_length (gtk_entry_get_buffer (entry), max); + * **/ void gtk_entry_set_max_length (GtkEntry *entry, gint max) { g_return_if_fail (GTK_IS_ENTRY (entry)); - - max = CLAMP (max, 0, MAX_SIZE); - - if (max > 0 && entry->text_length > max) - gtk_editable_delete_text (GTK_EDITABLE (entry), max, -1); - - entry->text_max_length = max; - g_object_notify (G_OBJECT (entry), "max-length"); + gtk_entry_buffer_set_max_length (get_buffer (entry), max); } /** @@ -6954,6 +7034,12 @@ gtk_entry_set_max_length (GtkEntry *entry, * Retrieves the maximum allowed length of the text in * @entry. See gtk_entry_set_max_length(). * + * This is equivalent to: + * + * + * gtk_entry_buffer_get_max_length (gtk_entry_get_buffer (entry)); + * + * * Return value: the maximum allowed number of characters * in #GtkEntry, or 0 if there is no maximum. **/ @@ -6961,8 +7047,7 @@ gint gtk_entry_get_max_length (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); - - return entry->text_max_length; + return gtk_entry_buffer_get_max_length (get_buffer (entry)); } /** @@ -6972,6 +7057,12 @@ gtk_entry_get_max_length (GtkEntry *entry) * Retrieves the current length of the text in * @entry. * + * This is equivalent to: + * + * + * gtk_entry_buffer_get_length (gtk_entry_get_buffer (entry)); + * + * * Return value: the current number of characters * in #GtkEntry, or 0 if there are none. * @@ -6981,8 +7072,7 @@ guint16 gtk_entry_get_text_length (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); - - return entry->text_length; + return gtk_entry_buffer_get_length (get_buffer (entry)); } /** @@ -7112,7 +7202,7 @@ gtk_entry_get_has_frame (GtkEntry *entry) /** * gtk_entry_set_inner_border: * @entry: a #GtkEntry - * @border: a #GtkBorder, or %NULL + * @border: (allow-none): a #GtkBorder, or %NULL * * Sets %entry's inner-border property to %border, or clears it if %NULL * is passed. The inner-border is the area around the entry's text, but @@ -7150,7 +7240,7 @@ gtk_entry_set_inner_border (GtkEntry *entry, * This function returns the entry's #GtkEntry:inner-border property. See * gtk_entry_set_inner_border() for more information. * - * Return value: the entry's #GtkBorder, or %NULL if none was set. + * Return value: (transfer none): the entry's #GtkBorder, or %NULL if none was set. * * Since: 2.10 **/ @@ -7176,8 +7266,8 @@ gtk_entry_get_inner_border (GtkEntry *entry) * gtk_entry_layout_index_to_text_index() and * gtk_entry_text_index_to_layout_index() are needed to convert byte * indices in the layout to byte indices in the entry contents. - * - * Return value: the #PangoLayout for this entry + * + * Return value: (transfer none): the #PangoLayout for this entry **/ PangoLayout* gtk_entry_get_layout (GtkEntry *entry) @@ -7262,8 +7352,8 @@ gtk_entry_text_index_to_layout_index (GtkEntry *entry, /** * gtk_entry_get_layout_offsets: * @entry: a #GtkEntry - * @x: location to store X offset of layout, or %NULL - * @y: location to store Y offset of layout, or %NULL + * @x: (allow-none): location to store X offset of layout, or %NULL + * @y: (allow-none): location to store Y offset of layout, or %NULL * * * Obtains the position of the #PangoLayout used to render text @@ -7371,7 +7461,7 @@ gtk_entry_get_alignment (GtkEntry *entry) * gtk_entry_set_icon_from_pixbuf: * @entry: a #GtkEntry * @icon_pos: Icon position - * @pixbuf: A #GdkPixbuf, or %NULL + * @pixbuf: (allow-none): A #GdkPixbuf, or %NULL * * Sets the icon shown in the specified position using a pixbuf. * @@ -7417,11 +7507,14 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, g_object_notify (G_OBJECT (entry), "secondary-icon-pixbuf"); g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type"); } + + if (gtk_widget_get_mapped (GTK_WIDGET (entry))) + gdk_window_show_unraised (icon_info->window); } gtk_entry_ensure_pixbuf (entry, icon_pos); - if (GTK_WIDGET_VISIBLE (entry)) + if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); g_object_thaw_notify (G_OBJECT (entry)); @@ -7431,7 +7524,7 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, * gtk_entry_set_icon_from_stock: * @entry: A #GtkEntry * @icon_pos: Icon position - * @stock_id: The name of the stock item, or %NULL + * @stock_id: (allow-none): The name of the stock item, or %NULL * * Sets the icon shown in the entry at the specified position from * a stock image. @@ -7481,11 +7574,14 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, g_object_notify (G_OBJECT (entry), "secondary-icon-stock"); g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type"); } + + if (gtk_widget_get_mapped (GTK_WIDGET (entry))) + gdk_window_show_unraised (icon_info->window); } gtk_entry_ensure_pixbuf (entry, icon_pos); - if (GTK_WIDGET_VISIBLE (entry)) + if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); g_object_thaw_notify (G_OBJECT (entry)); @@ -7495,7 +7591,7 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, * gtk_entry_set_icon_from_icon_name: * @entry: A #GtkEntry * @icon_pos: The position at which to set the icon - * @icon_name: An icon name, or %NULL + * @icon_name: (allow-none): An icon name, or %NULL * * Sets the icon shown in the entry at the specified position * from the current icon theme. @@ -7548,11 +7644,14 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, g_object_notify (G_OBJECT (entry), "secondary-icon-name"); g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type"); } + + if (gtk_widget_get_mapped (GTK_WIDGET (entry))) + gdk_window_show_unraised (icon_info->window); } gtk_entry_ensure_pixbuf (entry, icon_pos); - if (GTK_WIDGET_VISIBLE (entry)) + if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); g_object_thaw_notify (G_OBJECT (entry)); @@ -7562,7 +7661,7 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, * gtk_entry_set_icon_from_gicon: * @entry: A #GtkEntry * @icon_pos: The position at which to set the icon - * @icon: The icon to set, or %NULL + * @icon: (allow-none): The icon to set, or %NULL * * Sets the icon shown in the entry at the specified position * from the current icon theme. @@ -7612,11 +7711,14 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry, g_object_notify (G_OBJECT (entry), "secondary-icon-gicon"); g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type"); } + + if (gtk_widget_get_mapped (GTK_WIDGET (entry))) + gdk_window_show_unraised (icon_info->window); } gtk_entry_ensure_pixbuf (entry, icon_pos); - if (GTK_WIDGET_VISIBLE (entry)) + if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); g_object_thaw_notify (G_OBJECT (entry)); @@ -7654,7 +7756,7 @@ gtk_entry_set_icon_activatable (GtkEntry *entry, { icon_info->nonactivatable = !activatable; - if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry))) + if (gtk_widget_get_realized (GTK_WIDGET (entry))) update_cursors (GTK_WIDGET (entry)); g_object_notify (G_OBJECT (entry), @@ -7700,7 +7802,8 @@ gtk_entry_get_icon_activatable (GtkEntry *entry, * method will work regardless of whether the icon was set using a * #GdkPixbuf, a #GIcon, a stock item, or an icon name. * - * Returns: A #GdkPixbuf, or %NULL if no icon is set for this position. + * Returns: (transfer none): A #GdkPixbuf, or %NULL if no icon is + * set for this position. * * Since: 2.16 */ @@ -7734,8 +7837,8 @@ gtk_entry_get_icon_pixbuf (GtkEntry *entry, * no icon or if the icon was set by some other method (e.g., by * stock, pixbuf, or icon name). * - * Returns: A #GIcon, or %NULL if no icon is set or if the icon - * is not a #GIcon + * Returns: (transfer none): A #GIcon, or %NULL if no icon is set + * or if the icon is not a #GIcon * * Since: 2.16 */ @@ -7855,9 +7958,14 @@ gtk_entry_set_icon_sensitive (GtkEntry *entry, { icon_info->insensitive = !sensitive; - if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry))) + icon_info->pressed = FALSE; + icon_info->prelight = FALSE; + + if (gtk_widget_get_realized (GTK_WIDGET (entry))) update_cursors (GTK_WIDGET (entry)); + gtk_widget_queue_draw (GTK_WIDGET (entry)); + g_object_notify (G_OBJECT (entry), icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-sensitive" : "secondary-icon-sensitive"); } @@ -7981,6 +8089,8 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry, * #GtkWidget::drag-begin signal to set a different icon. Note that you * have to use g_signal_connect_after() to ensure that your signal handler * gets executed after the default handler. + * + * Since: 2.16 */ void gtk_entry_set_icon_drag_source (GtkEntry *entry, @@ -8020,6 +8130,8 @@ gtk_entry_set_icon_drag_source (GtkEntry *entry, * * Returns: index of the icon which is the source of the current * DND operation, or -1. + * + * Since: 2.16 */ gint gtk_entry_get_current_icon_drag_source (GtkEntry *entry) @@ -8044,6 +8156,41 @@ gtk_entry_get_current_icon_drag_source (GtkEntry *entry) return -1; } +/** + * gtk_entry_get_icon_window: + * @entry: A #GtkEntry + * @icon_pos: Icon position + * + * Returns the #GdkWindow which contains the entry's icon at + * @icon_pos. This function is useful when drawing something to the + * entry in a draw callback because it enables the callback + * to distinguish between the text window and entry's icon windows. + * + * See also gtk_entry_get_text_window(). + * + * Return value: (transfer none): the entry's icon window at @icon_pos. + * + * Since: 2.20 + */ +GdkWindow * +gtk_entry_get_icon_window (GtkEntry *entry, + GtkEntryIconPosition icon_pos) +{ + GtkEntryPrivate *priv; + EntryIconInfo *icon_info; + + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + priv = GTK_ENTRY_GET_PRIVATE (entry); + + icon_info = priv->icons[icon_pos]; + + if (icon_info) + return icon_info->window; + + return NULL; +} + static void ensure_has_tooltip (GtkEntry *entry) { @@ -8110,7 +8257,7 @@ gtk_entry_get_icon_tooltip_text (GtkEntry *entry, * gtk_entry_set_icon_tooltip_text: * @entry: a #GtkEntry * @icon_pos: the icon position - * @tooltip: the contents of the tooltip for the icon, or %NULL + * @tooltip: (allow-none): the contents of the tooltip for the icon, or %NULL * * Sets @tooltip as the contents of the tooltip for the icon * at the specified position. @@ -8188,7 +8335,7 @@ gtk_entry_get_icon_tooltip_markup (GtkEntry *entry, * gtk_entry_set_icon_tooltip_markup: * @entry: a #GtkEntry * @icon_pos: the icon position - * @tooltip: the contents of the tooltip for the icon, or %NULL + * @tooltip: (allow-none): the contents of the tooltip for the icon, or %NULL * * Sets @tooltip as the contents of the tooltip for the icon at * the specified position. @tooltip is assumed to be marked up with @@ -8331,7 +8478,7 @@ popup_position_func (GtkMenu *menu, GtkBorder inner_border; gint monitor_num, strong_x, height; - g_return_if_fail (GTK_WIDGET_REALIZED (entry)); + g_return_if_fail (gtk_widget_get_realized (widget)); gdk_window_get_origin (entry->text_area, x, y); @@ -8342,8 +8489,9 @@ popup_position_func (GtkMenu *menu, gtk_menu_set_monitor (menu, monitor_num); gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); - gtk_widget_size_request (entry->popup_menu, &menu_req); - gdk_drawable_get_size (entry->text_area, NULL, &height); + gtk_widget_get_preferred_size (entry->popup_menu, + &menu_req, NULL); + height = gdk_window_get_height (entry->text_area); gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL); _gtk_entry_effective_inner_border (entry, &inner_border); @@ -8388,8 +8536,9 @@ popup_targets_received (GtkClipboard *clipboard, PopupInfo *info = user_data; GtkEntry *entry = info->entry; - if (GTK_WIDGET_REALIZED (entry)) + if (gtk_widget_get_realized (GTK_WIDGET (entry))) { + DisplayMode mode; gboolean clipboard_contains_text; GtkWidget *menuitem; GtkWidget *submenu; @@ -8406,13 +8555,18 @@ popup_targets_received (GtkClipboard *clipboard, GTK_WIDGET (entry), popup_menu_detach); + mode = gtk_entry_get_display_mode (entry); append_action_signal (entry, entry->popup_menu, GTK_STOCK_CUT, "cut-clipboard", - entry->editable && entry->visible && entry->current_pos != entry->selection_bound); + entry->editable && mode == DISPLAY_NORMAL && + entry->current_pos != entry->selection_bound); + append_action_signal (entry, entry->popup_menu, GTK_STOCK_COPY, "copy-clipboard", - entry->visible && entry->current_pos != entry->selection_bound); + mode == DISPLAY_NORMAL && + entry->current_pos != entry->selection_bound); + append_action_signal (entry, entry->popup_menu, GTK_STOCK_PASTE, "paste-clipboard", entry->editable && clipboard_contains_text); - + menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL); gtk_widget_set_sensitive (menuitem, entry->editable && entry->current_pos != entry->selection_bound); g_signal_connect_swapped (menuitem, "activate", @@ -8624,14 +8778,16 @@ gtk_entry_drag_motion (GtkWidget *widget, guint time) { GtkEntry *entry = GTK_ENTRY (widget); + GtkStyle *style; GtkWidget *source_widget; GdkDragAction suggested_action; gint new_position, old_position; gint sel1, sel2; - - x -= widget->style->xthickness; - y -= widget->style->ythickness; - + + style = gtk_widget_get_style (widget); + x -= style->xthickness; + y -= style->ythickness; + old_position = entry->dnd_position; new_position = gtk_entry_find_position (entry, x + entry->scroll_offset); @@ -8689,12 +8845,14 @@ gtk_entry_drag_data_received (GtkWidget *widget, { GtkEntry *entry = GTK_ENTRY (widget); GtkEditable *editable = GTK_EDITABLE (widget); + GtkStyle *style; gchar *str; str = (gchar *) gtk_selection_data_get_text (selection_data); - x -= widget->style->xthickness; - y -= widget->style->ythickness; + style = gtk_widget_get_style (widget); + x -= style->xthickness; + y -= style->ythickness; if (str && entry->editable) { @@ -8761,7 +8919,7 @@ gtk_entry_drag_data_get (GtkWidget *widget, if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end)) { - gchar *str = gtk_entry_get_public_chars (GTK_ENTRY (widget), sel_start, sel_end); + gchar *str = gtk_entry_get_display_text (GTK_ENTRY (widget), sel_start, sel_end); gtk_selection_data_set_text (selection_data, str, -1); @@ -8811,7 +8969,7 @@ gtk_entry_drag_data_delete (GtkWidget *widget, static gboolean cursor_blinks (GtkEntry *entry) { - if (GTK_WIDGET_HAS_FOCUS (entry) && + if (gtk_widget_has_focus (GTK_WIDGET (entry)) && entry->editable && entry->selection_bound == entry->current_pos) { @@ -8852,24 +9010,30 @@ get_cursor_blink_timeout (GtkEntry *entry) static void show_cursor (GtkEntry *entry) { + GtkWidget *widget; + if (!entry->cursor_visible) { entry->cursor_visible = TRUE; - if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos) - gtk_widget_queue_draw (GTK_WIDGET (entry)); + widget = GTK_WIDGET (entry); + if (gtk_widget_has_focus (widget) && entry->selection_bound == entry->current_pos) + gtk_widget_queue_draw (widget); } } static void hide_cursor (GtkEntry *entry) { + GtkWidget *widget; + if (entry->cursor_visible) { entry->cursor_visible = FALSE; - if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos) - gtk_widget_queue_draw (GTK_WIDGET (entry)); + widget = GTK_WIDGET (entry); + if (gtk_widget_has_focus (widget) && entry->selection_bound == entry->current_pos) + gtk_widget_queue_draw (widget); } } @@ -8886,7 +9050,7 @@ blink_cb (gpointer data) entry = GTK_ENTRY (data); priv = GTK_ENTRY_GET_PRIVATE (entry); - if (!GTK_WIDGET_HAS_FOCUS (entry)) + if (!gtk_widget_has_focus (GTK_WIDGET (entry))) { g_warning ("GtkEntry - did not receive focus-out-event. If you\n" "connect a handler to this signal, it must return\n" @@ -8988,6 +9152,7 @@ static gint gtk_entry_completion_timeout (gpointer data) { GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data); + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (completion->priv->entry); completion->priv->completion_timeout = 0; @@ -9014,15 +9179,15 @@ gtk_entry_completion_timeout (gpointer data) g_object_get (completion, "popup-single-match", &popup_single, NULL); if ((matches > (popup_single ? 0: 1)) || actions > 0) { - if (GTK_WIDGET_VISIBLE (completion->priv->popup_window)) + if (gtk_widget_get_visible (completion->priv->popup_window)) _gtk_entry_completion_resize_popup (completion); else - _gtk_entry_completion_popup (completion); + _gtk_entry_completion_popup (completion, priv->completion_device); } else _gtk_entry_completion_popdown (completion); } - else if (GTK_WIDGET_VISIBLE (completion->priv->popup_window)) + else if (gtk_widget_get_visible (completion->priv->popup_window)) _gtk_entry_completion_popdown (completion); return FALSE; @@ -9031,16 +9196,16 @@ gtk_entry_completion_timeout (gpointer data) static inline gboolean keyval_is_cursor_move (guint keyval) { - if (keyval == GDK_Up || keyval == GDK_KP_Up) + if (keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) return TRUE; - if (keyval == GDK_Down || keyval == GDK_KP_Down) + if (keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) return TRUE; - if (keyval == GDK_Page_Up) + if (keyval == GDK_KEY_Page_Up) return TRUE; - if (keyval == GDK_Page_Down) + if (keyval == GDK_KEY_Page_Down) return TRUE; return FALSE; @@ -9054,7 +9219,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, gint matches, actions = 0; GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data); - if (!GTK_WIDGET_MAPPED (completion->priv->popup_window)) + if (!gtk_widget_get_mapped (completion->priv->popup_window)) return FALSE; matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL); @@ -9066,21 +9231,21 @@ gtk_entry_completion_key_press (GtkWidget *widget, { GtkTreePath *path = NULL; - if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) { if (completion->priv->current_selected < 0) completion->priv->current_selected = matches + actions - 1; else completion->priv->current_selected--; } - else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + else if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) { if (completion->priv->current_selected < matches + actions - 1) completion->priv->current_selected++; else completion->priv->current_selected = -1; } - else if (event->keyval == GDK_Page_Up) + else if (event->keyval == GDK_KEY_Page_Up) { if (completion->priv->current_selected < 0) completion->priv->current_selected = matches + actions - 1; @@ -9099,7 +9264,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, completion->priv->current_selected = matches - 1; } } - else if (event->keyval == GDK_Page_Down) + else if (event->keyval == GDK_KEY_Page_Down) { if (completion->priv->current_selected < 0) completion->priv->current_selected = 0; @@ -9146,6 +9311,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, { GtkTreeIter iter; + GtkTreeIter child_iter; GtkTreeModel *model = NULL; GtkTreeSelection *sel; gboolean entry_set; @@ -9153,12 +9319,15 @@ gtk_entry_completion_key_press (GtkWidget *widget, sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)); if (!gtk_tree_selection_get_selected (sel, &model, &iter)) return FALSE; + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, &iter); + model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); if (completion->priv->completion_prefix == NULL) completion->priv->completion_prefix = g_strdup (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry))); g_signal_emit_by_name (completion, "cursor-on-match", model, - &iter, &entry_set); + &child_iter, &entry_set); } } else if (completion->priv->current_selected - matches >= 0) @@ -9182,11 +9351,11 @@ gtk_entry_completion_key_press (GtkWidget *widget, return TRUE; } - else if (event->keyval == GDK_Escape || - event->keyval == GDK_Left || - event->keyval == GDK_KP_Left || - event->keyval == GDK_Right || - event->keyval == GDK_KP_Right) + else if (event->keyval == GDK_KEY_Escape || + event->keyval == GDK_KEY_Left || + event->keyval == GDK_KEY_KP_Left || + event->keyval == GDK_KEY_Right || + event->keyval == GDK_KEY_KP_Right) { gboolean retval = TRUE; @@ -9201,7 +9370,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, else if (completion->priv->inline_selection) { /* Escape rejects the tentative completion */ - if (event->keyval == GDK_Escape) + if (event->keyval == GDK_KEY_Escape) { if (completion->priv->completion_prefix) gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), @@ -9212,9 +9381,9 @@ gtk_entry_completion_key_press (GtkWidget *widget, /* Move the cursor to the end for Right/Esc, to the beginning for Left */ - if (event->keyval == GDK_Right || - event->keyval == GDK_KP_Right || - event->keyval == GDK_Escape) + if (event->keyval == GDK_KEY_Right || + event->keyval == GDK_KEY_KP_Right || + event->keyval == GDK_KEY_Escape) gtk_editable_set_position (GTK_EDITABLE (widget), -1); else gtk_editable_set_position (GTK_EDITABLE (widget), 0); @@ -9229,11 +9398,11 @@ keypress_completion_out: return retval; } - else if (event->keyval == GDK_Tab || - event->keyval == GDK_KP_Tab || - event->keyval == GDK_ISO_Left_Tab) + else if (event->keyval == GDK_KEY_Tab || + event->keyval == GDK_KEY_KP_Tab || + event->keyval == GDK_KEY_ISO_Left_Tab) { - GtkDirectionType dir = event->keyval == GDK_ISO_Left_Tab ? + GtkDirectionType dir = event->keyval == GDK_KEY_ISO_Left_Tab ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD; _gtk_entry_reset_im_context (GTK_ENTRY (widget)); @@ -9246,10 +9415,13 @@ keypress_completion_out: return TRUE; } - else if (event->keyval == GDK_ISO_Enter || - event->keyval == GDK_KP_Enter || - event->keyval == GDK_Return) + else if (event->keyval == GDK_KEY_ISO_Enter || + event->keyval == GDK_KEY_KP_Enter || + event->keyval == GDK_KEY_Return) { + GtkTreeIter iter; + GtkTreeModel *model = NULL; + GtkTreeSelection *sel; gboolean retval = TRUE; _gtk_entry_reset_im_context (GTK_ENTRY (widget)); @@ -9257,9 +9429,6 @@ keypress_completion_out: if (completion->priv->current_selected < matches) { - GtkTreeIter iter; - GtkTreeModel *model = NULL; - GtkTreeSelection *sel; gboolean entry_set; sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)); @@ -9291,15 +9460,18 @@ keypress_completion_out: } else if (completion->priv->current_selected - matches >= 0) { - GtkTreePath *path; - - _gtk_entry_reset_im_context (GTK_ENTRY (widget)); - - path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1); + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)); + if (gtk_tree_selection_get_selected (sel, &model, &iter)) + { + GtkTreePath *path; - g_signal_emit_by_name (completion, "action-activated", - gtk_tree_path_get_indices (path)[0]); - gtk_tree_path_free (path); + path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1); + g_signal_emit_by_name (completion, "action-activated", + gtk_tree_path_get_indices (path)[0]); + gtk_tree_path_free (path); + } + else + retval = FALSE; } g_free (completion->priv->completion_prefix); @@ -9315,7 +9487,9 @@ static void gtk_entry_completion_changed (GtkWidget *entry, gpointer user_data) { + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data); + GdkDevice *device; /* (re)install completion timeout */ if (completion->priv->completion_timeout) @@ -9328,11 +9502,19 @@ gtk_entry_completion_changed (GtkWidget *entry, if (completion->priv->minimum_key_length > 0 && strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))) == 0) { - if (GTK_WIDGET_VISIBLE (completion->priv->popup_window)) + if (gtk_widget_get_visible (completion->priv->popup_window)) _gtk_entry_completion_popdown (completion); return; } + device = gtk_get_current_event_device (); + + if (device && device->source == GDK_SOURCE_KEYBOARD) + device = gdk_device_get_associated_device (device); + + if (device) + priv->completion_device = device; + completion->priv->completion_timeout = gdk_threads_add_timeout (COMPLETION_TIMEOUT, gtk_entry_completion_timeout, @@ -9370,7 +9552,7 @@ accept_completion_callback (GtkEntry *entry) if (completion->priv->has_completion) gtk_editable_set_position (GTK_EDITABLE (entry), - entry->text_length); + gtk_entry_buffer_get_length (get_buffer (entry))); return FALSE; } @@ -9470,7 +9652,7 @@ connect_completion_signals (GtkEntry *entry, /** * gtk_entry_set_completion: * @entry: A #GtkEntry - * @completion: The #GtkEntryCompletion or %NULL + * @completion: (allow-none): The #GtkEntryCompletion or %NULL * * Sets @completion to be the auxiliary completion object to use with @entry. * All further configuration of the completion mechanism is done on @@ -9501,7 +9683,7 @@ gtk_entry_set_completion (GtkEntry *entry, old->priv->completion_timeout = 0; } - if (GTK_WIDGET_MAPPED (old->priv->popup_window)) + if (gtk_widget_get_mapped (old->priv->popup_window)) _gtk_entry_completion_popdown (old); disconnect_completion_signals (entry, old); @@ -9530,7 +9712,8 @@ gtk_entry_set_completion (GtkEntry *entry, * * Returns the auxiliary completion object currently in use by @entry. * - * Return value: The auxiliary completion object currently in use by @entry. + * Return value: (transfer none): The auxiliary completion object currently + * in use by @entry. * * Since: 2.4 */ @@ -9587,9 +9770,9 @@ gtk_entry_set_cursor_hadjustment (GtkEntry *entry, * Retrieves the horizontal cursor adjustment for the entry. * See gtk_entry_set_cursor_hadjustment(). * - * Return value: the horizontal cursor adjustment, or %NULL + * Return value: (transfer none): the horizontal cursor adjustment, or %NULL * if none has been set. - * + * * Since: 2.12 */ GtkAdjustment* @@ -9615,6 +9798,7 @@ void gtk_entry_set_progress_fraction (GtkEntry *entry, gdouble fraction) { + GtkWidget *widget; GtkEntryPrivate *private; gdouble old_fraction; gint x, y, width, height; @@ -9622,6 +9806,7 @@ gtk_entry_set_progress_fraction (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); + widget = GTK_WIDGET (entry); private = GTK_ENTRY_GET_PRIVATE (entry); if (private->progress_pulse_mode) @@ -9629,8 +9814,8 @@ gtk_entry_set_progress_fraction (GtkEntry *entry, else old_fraction = private->progress_fraction; - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (entry))) - get_progress_area (GTK_WIDGET(entry), &old_x, &old_y, &old_width, &old_height); + if (gtk_widget_is_drawable (widget)) + get_progress_area (widget, &old_x, &old_y, &old_width, &old_height); fraction = CLAMP (fraction, 0.0, 1.0); @@ -9638,12 +9823,12 @@ gtk_entry_set_progress_fraction (GtkEntry *entry, private->progress_pulse_mode = FALSE; private->progress_pulse_current = 0.0; - if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (entry))) + if (gtk_widget_is_drawable (widget)) { - get_progress_area (GTK_WIDGET(entry), &x, &y, &width, &height); + get_progress_area (widget, &x, &y, &width, &height); if ((x != old_x) || (y != old_y) || (width != old_width) || (height != old_height)) - gtk_widget_queue_draw (GTK_WIDGET (entry)); + gtk_widget_queue_draw (widget); } if (fraction != old_fraction) @@ -9823,9 +10008,14 @@ keymap_state_changed (GdkKeymap *keymap, GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); char *text = NULL; - if (!entry->visible && priv->caps_lock_warning) + if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL && priv->caps_lock_warning) { - if (gdk_keymap_get_caps_lock_state (keymap)) + if (gdk_keymap_get_num_lock_state (keymap) + && gdk_keymap_get_caps_lock_state (keymap)) + text = _("Caps Lock and Num Lock are on"); + else if (gdk_keymap_get_num_lock_state (keymap)) + text = _("Num Lock is on"); + else if (gdk_keymap_get_caps_lock_state (keymap)) text = _("Caps Lock is on"); } @@ -9834,6 +10024,3 @@ keymap_state_changed (GdkKeymap *keymap, else remove_capslock_feedback (entry); } - -#define __GTK_ENTRY_C__ -#include "gtkaliasdef.c"