X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkentry.c;h=880db8971662a7ffb9fab64c13c96256b93042d0;hb=5b7add024d7c390826661d3c76d3434af7022e0a;hp=a204943f46138cc32cfd1cc33704ea38e04904f3;hpb=fc60f7e93eb94de0c6feb762591161fd02783305;p=~andy%2Fgtk diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index a204943f4..880db8971 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -33,13 +33,13 @@ #include #include -#include "gdk/gdkkeysyms.h" #include "gtkalignment.h" #include "gtkbindings.h" #include "gtkcelleditable.h" #include "gtkclipboard.h" #include "gtkdnd.h" #include "gtkentry.h" +#include "gtkentrybuffer.h" #include "gtkimagemenuitem.h" #include "gtkimcontextsimple.h" #include "gtkimmulticontext.h" @@ -58,13 +58,58 @@ #include "gtkwindow.h" #include "gtktreeview.h" #include "gtktreeselection.h" +#include "gtktypebuiltins.h" #include "gtkprivate.h" #include "gtkentryprivate.h" #include "gtkcelllayout.h" #include "gtktooltip.h" #include "gtkiconfactory.h" #include "gtkicontheme.h" -#include "gtkalias.h" + + +/** + * SECTION:gtkentry + * @Short_description: A single line text entry field + * @Title: GtkEntry + * @See_also: #GtkTextView, #GtkEntryCompletion + * + * The #GtkEntry widget is a single line text entry + * widget. A fairly large set of key bindings are supported + * by default. If the entered text is longer than the allocation + * of the widget, the widget will scroll so that the cursor + * position is visible. + * + * When using an entry for passwords and other sensitive information, + * it can be put into "password mode" using gtk_entry_set_visibility(). + * In this mode, entered text is displayed using a 'invisible' character. + * By default, GTK+ picks the best invisible character that is available + * in the current font, but it can be changed with + * gtk_entry_set_invisible_char(). Since 2.16, GTK+ displays a warning + * when Caps Lock or input methods might interfere with entering text in + * a password entry. The warning can be turned off with the + * #GtkEntry:caps-lock-warning property. + * + * Since 2.16, GtkEntry has the ability to display progress or activity + * information behind the text. To make an entry display such information, + * use gtk_entry_set_progress_fraction() or gtk_entry_set_progress_pulse_step(). + * + * Additionally, GtkEntry can show icons at either side of the entry. These + * icons can be activatable by clicking, can be set up as drag source and + * can have tooltips. To add an icon, use gtk_entry_set_icon_from_gicon() or + * one of the various other functions that set an icon from a stock id, an + * icon name or a pixbuf. To trigger an action when the user clicks an icon, + * connect to the #GtkEntry::icon-press signal. To allow DND operations + * from an icon, use gtk_entry_set_icon_drag_source(). To set a tooltip on + * an icon, use gtk_entry_set_icon_tooltip_text() or the corresponding function + * for markup. + * + * Note that functionality or information that is only available by clicking + * on an icon in an entry may not be accessible at all to users which are not + * able to use a mouse or other pointing device. It is therefore recommended + * that any such functionality should also be available by other means, e.g. + * via the context menu of the entry. + */ + #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key" @@ -73,12 +118,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) \ @@ -91,11 +130,89 @@ static GQuark quark_password_hint = 0; static GQuark quark_cursor_hadjustment = 0; static GQuark quark_capslock_feedback = 0; -typedef struct _GtkEntryPrivate GtkEntryPrivate; +typedef struct _EntryIconInfo EntryIconInfo; +typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint; +typedef struct _GtkEntryCapslockFeedback GtkEntryCapslockFeedback; -#define GTK_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY, GtkEntryPrivate)) +struct _GtkEntryPrivate +{ + EntryIconInfo *icons[MAX_ICONS]; + + GtkEntryBuffer *buffer; + GtkIMContext *im_context; + GtkShadowType shadow_type; + GtkWidget *popup_menu; + + GdkDevice *completion_device; + GdkWindow *text_area; + + PangoLayout *cached_layout; + + gchar *im_module; + + gdouble progress_fraction; + gdouble progress_pulse_fraction; + gdouble progress_pulse_current; + + gfloat xalign; + + gint ascent; /* font ascent in pango units */ + gint current_pos; + gint descent; /* font descent in pango units */ + gint dnd_position; /* In chars, -1 == no DND cursor */ + gint drag_start_x; + gint drag_start_y; + gint focus_width; + gint icon_margin; + gint insert_pos; + gint selection_bound; + gint scroll_offset; + gint start_x; + gint start_y; + gint width_chars; + + gunichar invisible_char; + + guint button; + guint blink_time; /* time in msec the cursor has blinked since last user event */ + guint blink_timeout; + guint recompute_idle; + + guint16 x_text_size; /* allocated size, in bytes */ + guint16 x_n_bytes; /* length in use, in bytes */ + + guint16 preedit_length; /* length of preedit string, in bytes */ + guint16 preedit_cursor; /* offset of cursor within preedit string, in chars */ + + guint editable : 1; + guint in_drag : 1; + guint overwrite_mode : 1; + guint visible : 1; + + guint activates_default : 1; + guint cache_includes_preedit : 1; + guint caps_lock_warning : 1; + guint caps_lock_warning_shown : 1; + guint change_count : 8; + guint cursor_visible : 1; + guint editing_canceled : 1; /* Only used by GtkCellRendererText */ + guint has_frame : 1; + guint in_click : 1; /* Flag so we don't select all when clicking in entry to focus in */ + guint is_cell_renderer : 1; + guint invisible_char_set : 1; + guint interior_focus : 1; + guint mouse_cursor_obscured : 1; + guint need_im_reset : 1; + guint progress_pulse_mode : 1; + guint progress_pulse_way_back : 1; + guint real_changed : 1; + guint resolved_dir : 4; /* PangoDirection */ + guint select_words : 1; + guint select_lines : 1; + guint truncate_multiline : 1; +}; -typedef struct +struct _EntryIconInfo { GdkWindow *window; gchar *tooltip; @@ -113,47 +230,14 @@ typedef struct GtkTargetList *target_list; GdkDragAction actions; -} EntryIconInfo; - -struct _GtkEntryPrivate -{ - gfloat xalign; - gint insert_pos; - guint blink_time; /* time in msec the cursor has blinked since last user event */ - guint interior_focus : 1; - guint real_changed : 1; - guint invisible_char_set : 1; - guint caps_lock_warning : 1; - guint caps_lock_warning_shown : 1; - guint change_count : 8; - guint progress_pulse_mode : 1; - guint progress_pulse_way_back : 1; - - gint focus_width; - GtkShadowType shadow_type; - - gdouble progress_fraction; - gdouble progress_pulse_fraction; - gdouble progress_pulse_current; - - EntryIconInfo *icons[MAX_ICONS]; - gint icon_margin; - gint start_x; - gint start_y; }; -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; - struct _GtkEntryCapslockFeedback { GtkWidget *entry; @@ -172,13 +256,15 @@ enum { COPY_CLIPBOARD, PASTE_CLIPBOARD, TOGGLE_OVERWRITE, - ICON_PRESSED, - ICON_RELEASED, + ICON_PRESS, + ICON_RELEASE, + PREEDIT_CHANGED, LAST_SIGNAL }; enum { PROP_0, + PROP_BUFFER, PROP_CURSOR_POSITION, PROP_SELECTION_BOUND, PROP_EDITABLE, @@ -213,7 +299,13 @@ enum { PROP_ACTIVATABLE_PRIMARY, PROP_ACTIVATABLE_SECONDARY, PROP_SENSITIVE_PRIMARY, - PROP_SENSITIVE_SECONDARY + PROP_SENSITIVE_SECONDARY, + PROP_TOOLTIP_TEXT_PRIMARY, + PROP_TOOLTIP_TEXT_SECONDARY, + PROP_TOOLTIP_MARKUP_PRIMARY, + PROP_TOOLTIP_MARKUP_SECONDARY, + PROP_IM_MODULE, + PROP_EDITING_CANCELED }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -223,9 +315,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, @@ -236,25 +335,31 @@ 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); static void gtk_entry_unmap (GtkWidget *widget); -static void gtk_entry_size_request (GtkWidget *widget, - GtkRequisition *requisition); +static void gtk_entry_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_entry_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); static void gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_entry_draw_frame (GtkWidget *widget, - GdkRectangle *area); + GtkStyleContext *context, + cairo_t *cr); static void gtk_entry_draw_progress (GtkWidget *widget, - GdkEventExpose *event); -static gint gtk_entry_expose (GtkWidget *widget, - GdkEventExpose *event); + GtkStyleContext *context, + cairo_t *cr); +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, @@ -274,8 +379,7 @@ static gint gtk_entry_focus_in (GtkWidget *widget, static gint gtk_entry_focus_out (GtkWidget *widget, GdkEventFocus *event); static void gtk_entry_grab_focus (GtkWidget *widget); -static void gtk_entry_style_set (GtkWidget *widget, - GtkStyle *previous_style); +static void gtk_entry_style_updated (GtkWidget *widget); static gboolean gtk_entry_query_tooltip (GtkWidget *widget, gint x, gint y, @@ -283,8 +387,8 @@ static gboolean gtk_entry_query_tooltip (GtkWidget *widget, GtkTooltip *tooltip); static void gtk_entry_direction_changed (GtkWidget *widget, GtkTextDirection previous_dir); -static void gtk_entry_state_changed (GtkWidget *widget, - GtkStateType previous_state); +static void gtk_entry_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous_state); static void gtk_entry_screen_changed (GtkWidget *widget, GdkScreen *old_screen); @@ -402,8 +506,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); @@ -432,9 +538,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); @@ -442,8 +545,6 @@ static void gtk_entry_do_popup (GtkEntry *entry, GdkEventButton *event); static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget, gboolean group_cycling); -static void gtk_entry_state_changed (GtkWidget *widget, - GtkStateType previous_state); static void gtk_entry_check_cursor_blink (GtkEntry *entry); static void gtk_entry_pend_cursor_blink (GtkEntry *entry); static void gtk_entry_reset_blink_time (GtkEntry *entry); @@ -452,7 +553,12 @@ static void gtk_entry_get_text_area_size (GtkEntry *entry, gint *y, gint *width, gint *height); -static void get_widget_window_size (GtkEntry *entry, +static void get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height); +static void get_frame_size (GtkEntry *entry, gint *x, gint *y, gint *width, @@ -491,6 +597,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) @@ -525,24 +654,24 @@ 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->get_preferred_width = gtk_entry_get_preferred_width; + widget_class->get_preferred_height = gtk_entry_get_preferred_height; 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; @@ -553,12 +682,12 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->focus_in_event = gtk_entry_focus_in; widget_class->focus_out_event = gtk_entry_focus_out; widget_class->grab_focus = gtk_entry_grab_focus; - widget_class->style_set = gtk_entry_style_set; + widget_class->style_updated = gtk_entry_style_updated; widget_class->query_tooltip = gtk_entry_query_tooltip; widget_class->drag_begin = gtk_entry_drag_begin; widget_class->drag_end = gtk_entry_drag_end; widget_class->direction_changed = gtk_entry_direction_changed; - widget_class->state_changed = gtk_entry_state_changed; + widget_class->state_flags_changed = gtk_entry_state_flags_changed; widget_class->screen_changed = gtk_entry_screen_changed; widget_class->mnemonic_activate = gtk_entry_mnemonic_activate; @@ -571,8 +700,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; @@ -589,13 +716,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)); @@ -605,7 +744,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)); @@ -623,7 +762,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, @@ -784,16 +923,15 @@ 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)); /** * GtkEntry:caps-lock-warning * - * Whether password entries will show a warning when Caps Lock is on - * or an input method is active. + * Whether password entries will show a warning when Caps Lock is on. * * Note that the warning is shown using a secondary icon, and thus * does not work if you are using the secondary icon position for some @@ -805,7 +943,7 @@ gtk_entry_class_init (GtkEntryClass *class) PROP_CAPS_LOCK_WARNING, g_param_spec_boolean ("caps-lock-warning", P_("Caps Lock warning"), - P_("Whether password entries will show a warning when Caps Lock is on or an input method is active"), + P_("Whether password entries will show a warning when Caps Lock is on"), TRUE, GTK_PARAM_READWRITE)); @@ -845,7 +983,7 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READWRITE)); /** - * GtkEntry:pixbuf-primary: + * GtkEntry:primary-icon-pixbuf: * * A pixbuf to use as the primary icon for the entry. * @@ -853,14 +991,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_PIXBUF_PRIMARY, - g_param_spec_object ("pixbuf-primary", + g_param_spec_object ("primary-icon-pixbuf", P_("Primary pixbuf"), P_("Primary pixbuf for the entry"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); /** - * GtkEntry:pixbuf-secondary: + * GtkEntry:secondary-icon-pixbuf: * * An pixbuf to use as the secondary icon for the entry. * @@ -868,14 +1006,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_PIXBUF_SECONDARY, - g_param_spec_object ("pixbuf-secondary", + g_param_spec_object ("secondary-icon-pixbuf", P_("Secondary pixbuf"), P_("Secondary pixbuf for the entry"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); /** - * GtkEntry:stock-primary: + * GtkEntry:primary-icon-stock: * * The stock id to use for the primary icon for the entry. * @@ -883,14 +1021,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_STOCK_PRIMARY, - g_param_spec_string ("stock-primary", + g_param_spec_string ("primary-icon-stock", P_("Primary stock ID"), P_("Stock ID for primary icon"), NULL, GTK_PARAM_READWRITE)); /** - * GtkEntry:stock-secondary: + * GtkEntry:secondary-icon-stock: * * The stock id to use for the secondary icon for the entry. * @@ -898,14 +1036,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_STOCK_SECONDARY, - g_param_spec_string ("stock-secondary", + g_param_spec_string ("secondary-icon-stock", P_("Secondary stock ID"), P_("Stock ID for secondary icon"), NULL, GTK_PARAM_READWRITE)); /** - * GtkEntry:icon-name-primary: + * GtkEntry:primary-icon-name: * * The icon name to use for the primary icon for the entry. * @@ -913,14 +1051,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_ICON_NAME_PRIMARY, - g_param_spec_string ("icon-name-primary", + g_param_spec_string ("primary-icon-name", P_("Primary icon name"), P_("Icon name for primary icon"), NULL, GTK_PARAM_READWRITE)); /** - * GtkEntry:icon-name-secondary: + * GtkEntry:secondary-icon-name: * * The icon name to use for the secondary icon for the entry. * @@ -928,14 +1066,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_ICON_NAME_SECONDARY, - g_param_spec_string ("icon-name-secondary", + g_param_spec_string ("secondary-icon-name", P_("Secondary icon name"), P_("Icon name for secondary icon"), NULL, GTK_PARAM_READWRITE)); /** - * GtkEntry:gicon-primary: + * GtkEntry:primary-icon-gicon: * * The #GIcon to use for the primary icon for the entry. * @@ -943,14 +1081,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_GICON_PRIMARY, - g_param_spec_object ("gicon-primary", + g_param_spec_object ("primary-icon-gicon", P_("Primary GIcon"), P_("GIcon for primary icon"), G_TYPE_ICON, GTK_PARAM_READWRITE)); /** - * GtkEntry:gicon-secondary: + * GtkEntry:secondary-icon-gicon: * * The #GIcon to use for the secondary icon for the entry. * @@ -958,14 +1096,14 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_GICON_SECONDARY, - g_param_spec_object ("gicon-secondary", + g_param_spec_object ("secondary-icon-gicon", P_("Secondary GIcon"), P_("GIcon for secondary icon"), G_TYPE_ICON, GTK_PARAM_READWRITE)); /** - * GtkEntry:storage-type-primary: + * GtkEntry:primary-icon-storage-type: * * The representation which is used for the primary icon of the entry. * @@ -973,7 +1111,7 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_STORAGE_TYPE_PRIMARY, - g_param_spec_enum ("storage-type-primary", + g_param_spec_enum ("primary-icon-storage-type", P_("Primary storage type"), P_("The representation being used for primary icon"), GTK_TYPE_IMAGE_TYPE, @@ -981,7 +1119,7 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READABLE)); /** - * GtkEntry:storage-type-secondary: + * GtkEntry:secondary-icon-storage-type: * * The representation which is used for the secondary icon of the entry. * @@ -989,7 +1127,7 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_STORAGE_TYPE_SECONDARY, - g_param_spec_enum ("storage-type-secondary", + g_param_spec_enum ("secondary-icon-storage-type", P_("Secondary storage type"), P_("The representation being used for secondary icon"), GTK_TYPE_IMAGE_TYPE, @@ -997,11 +1135,11 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READABLE)); /** - * GtkEntry:activatable-primary: + * GtkEntry:primary-icon-activatable: * * Whether the primary icon is activatable. * - * GTK+ emits the #GtkEntry::icon-pressed and #GtkEntry::icon-released + * GTK+ emits the #GtkEntry::icon-press and #GtkEntry::icon-release * signals only on sensitive, activatable icons. * * Sensitive, but non-activatable icons can be used for purely @@ -1011,18 +1149,18 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_ACTIVATABLE_PRIMARY, - g_param_spec_boolean ("activatable-primary", + g_param_spec_boolean ("primary-icon-activatable", P_("Primary icon activatable"), P_("Whether the primary icon is activatable"), - FALSE, + TRUE, GTK_PARAM_READWRITE)); /** - * GtkEntry:activatable-secondary: + * GtkEntry:secondary-icon-activatable: * * Whether the secondary icon is activatable. * - * GTK+ emits the #GtkEntry::icon-pressed and #GtkEntry::icon-released + * GTK+ emits the #GtkEntry::icon-press and #GtkEntry::icon-release * signals only on sensitive, activatable icons. * * Sensitive, but non-activatable icons can be used for purely @@ -1032,20 +1170,20 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_ACTIVATABLE_SECONDARY, - g_param_spec_boolean ("activatable-secondary", + g_param_spec_boolean ("secondary-icon-activatable", P_("Secondary icon activatable"), P_("Whether the secondary icon is activatable"), - FALSE, + TRUE, GTK_PARAM_READWRITE)); /** - * GtkEntry:sensitive-primary: + * GtkEntry:primary-icon-sensitive: * * Whether the primary icon is sensitive. * * An insensitive icon appears grayed out. GTK+ does not emit the - * #GtkEntry::icon-pressed and #GtkEntry::icon-released signals and + * #GtkEntry::icon-press and #GtkEntry::icon-release signals and * does not allow DND from insensitive icons. * * An icon should be set insensitive if the action that would trigger @@ -1055,19 +1193,19 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_SENSITIVE_PRIMARY, - g_param_spec_boolean ("sensitive-primary", + g_param_spec_boolean ("primary-icon-sensitive", P_("Primary icon sensitive"), P_("Whether the primary icon is sensitive"), TRUE, GTK_PARAM_READWRITE)); /** - * GtkEntry:sensitive-secondary: + * GtkEntry:secondary-icon-sensitive: * * Whether the secondary icon is sensitive. * * An insensitive icon appears grayed out. GTK+ does not emit the - * #GtkEntry::icon-pressed and #GtkEntry::icon-released signals and + * #GtkEntry::icon-press and #GtkEntry::icon-release signals and * does not allow DND from insensitive icons. * * An icon should be set insensitive if the action that would trigger @@ -1077,14 +1215,106 @@ gtk_entry_class_init (GtkEntryClass *class) */ g_object_class_install_property (gobject_class, PROP_SENSITIVE_SECONDARY, - g_param_spec_boolean ("sensitive-secondary", + g_param_spec_boolean ("secondary-icon-sensitive", P_("Secondary icon sensitive"), P_("Whether the secondary icon is sensitive"), TRUE, GTK_PARAM_READWRITE)); /** - * GtkEntry:prelight: + * GtkEntry:primary-icon-tooltip-text: + * + * The contents of the tooltip on the primary icon. + * + * Also see gtk_entry_set_icon_tooltip_text(). + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_TOOLTIP_TEXT_PRIMARY, + g_param_spec_string ("primary-icon-tooltip-text", + P_("Primary icon tooltip text"), + P_("The contents of the tooltip on the primary icon"), + NULL, + GTK_PARAM_READWRITE)); + + /** + * GtkEntry:secondary-icon-tooltip-text: + * + * The contents of the tooltip on the secondary icon. + * + * Also see gtk_entry_set_icon_tooltip_text(). + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_TOOLTIP_TEXT_SECONDARY, + g_param_spec_string ("secondary-icon-tooltip-text", + P_("Secondary icon tooltip text"), + P_("The contents of the tooltip on the secondary icon"), + NULL, + GTK_PARAM_READWRITE)); + + /** + * GtkEntry:primary-icon-tooltip-markup: + * + * The contents of the tooltip on the primary icon, which is marked up + * with the Pango text markup + * language. + * + * Also see gtk_entry_set_icon_tooltip_markup(). + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_TOOLTIP_MARKUP_PRIMARY, + g_param_spec_string ("primary-icon-tooltip-markup", + P_("Primary icon tooltip markup"), + P_("The contents of the tooltip on the primary icon"), + NULL, + GTK_PARAM_READWRITE)); + + /** + * GtkEntry:secondary-icon-tooltip-markup: + * + * The contents of the tooltip on the secondary icon, which is marked up + * with the Pango text markup + * language. + * + * Also see gtk_entry_set_icon_tooltip_markup(). + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_TOOLTIP_MARKUP_SECONDARY, + g_param_spec_string ("secondary-icon-tooltip-markup", + P_("Secondary icon tooltip markup"), + P_("The contents of the tooltip on the secondary icon"), + NULL, + GTK_PARAM_READWRITE)); + + /** + * GtkEntry:im-module: + * + * Which IM (input method) module should be used for this entry. + * See #GtkIMContext. + * + * Setting this to a non-%NULL value overrides the + * system-wide IM module setting. See the GtkSettings + * #GtkSettings:gtk-im-module property. + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_IM_MODULE, + g_param_spec_string ("im-module", + P_("IM module"), + P_("Which IM module should be used"), + NULL, + GTK_PARAM_READWRITE)); + + /** + * GtkEntry:icon-prelight: * * The prelight style property determines whether activatable * icons prelight on mouseover. @@ -1092,11 +1322,46 @@ gtk_entry_class_init (GtkEntryClass *class) * Since: 2.16 */ gtk_widget_class_install_style_property (widget_class, - g_param_spec_boolean ("prelight", - P_("Prelight"), + g_param_spec_boolean ("icon-prelight", + P_("Icon Prelight"), P_("Whether activatable icons should prelight when hovered"), TRUE, GTK_PARAM_READABLE)); + + /** + * GtkEntry:progress-border: + * + * The border around the progress bar in the entry. + * + * Since: 2.16 + */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boxed ("progress-border", + P_("Progress Border"), + P_("Border around the progress bar"), + GTK_TYPE_BORDER, + GTK_PARAM_READABLE)); + + /** + * GtkEntry:invisible-char: + * + * The invisible character is used when masking entry contents (in + * \"password mode\")"). When it is not explicitly set with the + * #GtkEntry::invisible-char property, GTK+ determines the character + * to use from a list of possible candidates, depending on availability + * in the current font. + * + * This style property allows the theme to prepend a character + * to the list of candidates. + * + * Since: 2.18 + */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_unichar ("invisible-char", + P_("Invisible character"), + P_("The character to use when masking entry contents (in \"password mode\")"), + 0, + GTK_PARAM_READABLE)); /** * GtkEntry::populate-popup: @@ -1129,7 +1394,7 @@ gtk_entry_class_init (GtkEntryClass *class) * which gets emitted when the user activates the entry. * * Applications should not connect to it, but may emit it with - * g_signal_emit_by_name() if they need to control scrolling + * g_signal_emit_by_name() if they need to control activation * programmatically. * * The default bindings for this signal are all forms of the Enter key. @@ -1158,7 +1423,7 @@ gtk_entry_class_init (GtkEntryClass *class) * the viewport to be moved instead. * * Applications should not connect to it, but may emit it with - * g_signal_emit_by_name() if they need to control scrolling + * g_signal_emit_by_name() if they need to control the cursor * programmatically. * * The default bindings for this signal come in two variants, @@ -1335,48 +1600,69 @@ gtk_entry_class_init (GtkEntryClass *class) G_TYPE_NONE, 0); /** - * GtkEntry::icon-pressed: + * GtkEntry::icon-press: * @entry: The entry on which the signal is emitted * @icon_pos: The position of the clicked icon * @event: the button press event * - * The ::icon-pressed signal is emitted when an activatable icon + * The ::icon-press signal is emitted when an activatable icon * is clicked. * * Since: 2.16 */ - signals[ICON_PRESSED] = - g_signal_new (I_("icon-pressed"), + signals[ICON_PRESS] = + g_signal_new (I_("icon-press"), G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, _gtk_marshal_VOID__ENUM_BOXED, G_TYPE_NONE, 2, GTK_TYPE_ENTRY_ICON_POSITION, - GDK_TYPE_EVENT); + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** - * GtkEntry::icon-released: + * GtkEntry::icon-release: * @entry: The entry on which the signal is emitted * @icon_pos: The position of the clicked icon * @event: the button release event * - * The ::icon-released signal is emitted on the button release from a + * The ::icon-release signal is emitted on the button release from a * mouse click over an activatable icon. * * Since: 2.16 */ - signals[ICON_RELEASED] = - g_signal_new (I_("icon-released"), + signals[ICON_RELEASE] = + g_signal_new (I_("icon-release"), G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, _gtk_marshal_VOID__ENUM_BOXED, G_TYPE_NONE, 2, GTK_TYPE_ENTRY_ICON_POSITION, - GDK_TYPE_EVENT); + 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); /* @@ -1386,85 +1672,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, @@ -1472,66 +1758,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); /** @@ -1546,49 +1832,13 @@ gtk_entry_class_init (GtkEntryClass *class) P_("Inner Border"), P_("Border between text and frame."), 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"), - TRUE, - GTK_PARAM_READWRITE)); - - /** - * GtkSettings:gtk-entry-password-hint-timeout: - * - * How long to show the last input character in hidden - * entries. This value is in milliseconds. 0 disables showing the - * last char. 600 is a good value for enabling it. - * - * Since: 2.10 - */ - gtk_settings_install_property (g_param_spec_uint ("gtk-entry-password-hint-timeout", - P_("Password Hint Timeout"), - P_("How long to show the last input character in hidden entries"), - 0, G_MAXUINT, 0, - GTK_PARAM_READWRITE)); + GTK_PARAM_READABLE)); g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate)); } 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; @@ -1613,32 +1863,38 @@ gtk_entry_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object); GtkEntry *entry = GTK_ENTRY (object); + GtkEntryPrivate *priv = entry->priv; + 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) + if (new_value != priv->editable) { + widget = GTK_WIDGET (entry); if (!new_value) { _gtk_entry_reset_im_context (entry); - if (GTK_WIDGET_HAS_FOCUS (entry)) - gtk_im_context_focus_out (entry->im_context); + if (gtk_widget_has_focus (widget)) + gtk_im_context_focus_out (priv->im_context); - entry->preedit_length = 0; - entry->preedit_cursor = 0; + priv->preedit_length = 0; + priv->preedit_cursor = 0; } - entry->editable = new_value; + priv->editable = new_value; + + if (new_value && gtk_widget_has_focus (widget)) + gtk_im_context_focus_in (priv->im_context); - if (new_value && GTK_WIDGET_HAS_FOCUS (entry)) - gtk_im_context_focus_in (entry->im_context); - gtk_entry_queue_draw (entry); } } @@ -1681,7 +1937,7 @@ gtk_entry_set_property (GObject *object, break; case PROP_TRUNCATE_MULTILINE: - entry->truncate_multiline = g_value_get_boolean (value); + priv->truncate_multiline = g_value_get_boolean (value); break; case PROP_SHADOW_TYPE: @@ -1783,6 +2039,41 @@ gtk_entry_set_property (GObject *object, g_value_get_boolean (value)); break; + case PROP_TOOLTIP_TEXT_PRIMARY: + gtk_entry_set_icon_tooltip_text (entry, + GTK_ENTRY_ICON_PRIMARY, + g_value_get_string (value)); + break; + + case PROP_TOOLTIP_TEXT_SECONDARY: + gtk_entry_set_icon_tooltip_text (entry, + GTK_ENTRY_ICON_SECONDARY, + g_value_get_string (value)); + break; + + case PROP_TOOLTIP_MARKUP_PRIMARY: + gtk_entry_set_icon_tooltip_markup (entry, + GTK_ENTRY_ICON_PRIMARY, + g_value_get_string (value)); + break; + + case PROP_TOOLTIP_MARKUP_SECONDARY: + gtk_entry_set_icon_tooltip_markup (entry, + GTK_ENTRY_ICON_SECONDARY, + g_value_get_string (value)); + break; + + case PROP_IM_MODULE: + g_free (priv->im_module); + priv->im_module = g_value_dup_string (value); + if (GTK_IS_IM_MULTICONTEXT (priv->im_context)) + gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (priv->im_context), priv->im_module); + break; + + case PROP_EDITING_CANCELED: + priv->editing_canceled = g_value_get_boolean (value); + break; + case PROP_SCROLL_OFFSET: case PROP_CURSOR_POSITION: default: @@ -1797,33 +2088,37 @@ gtk_entry_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object); GtkEntry *entry = GTK_ENTRY (object); + GtkEntryPrivate *priv = entry->priv; 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); + g_value_set_int (value, priv->current_pos); break; case PROP_SELECTION_BOUND: - g_value_set_int (value, entry->selection_bound); + g_value_set_int (value, priv->selection_bound); break; case PROP_EDITABLE: - g_value_set_boolean (value, entry->editable); + g_value_set_boolean (value, priv->editable); 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: - g_value_set_boolean (value, entry->visible); + g_value_set_boolean (value, priv->visible); break; case PROP_HAS_FRAME: - g_value_set_boolean (value, entry->has_frame); + g_value_set_boolean (value, priv->has_frame); break; case PROP_INNER_BORDER: @@ -1831,19 +2126,19 @@ gtk_entry_get_property (GObject *object, break; case PROP_INVISIBLE_CHAR: - g_value_set_uint (value, entry->invisible_char); + g_value_set_uint (value, priv->invisible_char); break; case PROP_ACTIVATES_DEFAULT: - g_value_set_boolean (value, entry->activates_default); + g_value_set_boolean (value, priv->activates_default); break; case PROP_WIDTH_CHARS: - g_value_set_int (value, entry->width_chars); + g_value_set_int (value, priv->width_chars); break; case PROP_SCROLL_OFFSET: - g_value_set_int (value, entry->scroll_offset); + g_value_set_int (value, priv->scroll_offset); break; case PROP_TEXT: @@ -1855,7 +2150,7 @@ gtk_entry_get_property (GObject *object, break; case PROP_TRUNCATE_MULTILINE: - g_value_set_boolean (value, entry->truncate_multiline); + g_value_set_boolean (value, priv->truncate_multiline); break; case PROP_SHADOW_TYPE: @@ -1863,17 +2158,21 @@ gtk_entry_get_property (GObject *object, break; case PROP_OVERWRITE_MODE: - g_value_set_boolean (value, entry->overwrite_mode); + g_value_set_boolean (value, priv->overwrite_mode); 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: g_value_set_boolean (value, priv->invisible_char_set); break; + case PROP_IM_MODULE: + g_value_set_string (value, priv->im_module); + break; + case PROP_CAPS_LOCK_WARNING: g_value_set_boolean (value, priv->caps_lock_warning); break; @@ -1888,26 +2187,26 @@ gtk_entry_get_property (GObject *object, case PROP_PIXBUF_PRIMARY: g_value_set_object (value, - gtk_entry_get_pixbuf (entry, - GTK_ENTRY_ICON_PRIMARY)); + gtk_entry_get_icon_pixbuf (entry, + GTK_ENTRY_ICON_PRIMARY)); break; case PROP_PIXBUF_SECONDARY: g_value_set_object (value, - gtk_entry_get_pixbuf (entry, - GTK_ENTRY_ICON_SECONDARY)); + gtk_entry_get_icon_pixbuf (entry, + GTK_ENTRY_ICON_SECONDARY)); break; case PROP_STOCK_PRIMARY: g_value_set_string (value, - gtk_entry_get_stock (entry, - GTK_ENTRY_ICON_PRIMARY)); + gtk_entry_get_icon_stock (entry, + GTK_ENTRY_ICON_PRIMARY)); break; case PROP_STOCK_SECONDARY: g_value_set_string (value, - gtk_entry_get_stock (entry, - GTK_ENTRY_ICON_SECONDARY)); + gtk_entry_get_icon_stock (entry, + GTK_ENTRY_ICON_SECONDARY)); break; case PROP_ICON_NAME_PRIMARY: @@ -1924,24 +2223,26 @@ gtk_entry_get_property (GObject *object, case PROP_GICON_PRIMARY: g_value_set_object (value, - gtk_entry_get_gicon (entry, - GTK_ENTRY_ICON_PRIMARY)); + gtk_entry_get_icon_gicon (entry, + GTK_ENTRY_ICON_PRIMARY)); break; case PROP_GICON_SECONDARY: g_value_set_object (value, - gtk_entry_get_gicon (entry, - GTK_ENTRY_ICON_SECONDARY)); + gtk_entry_get_icon_gicon (entry, + GTK_ENTRY_ICON_SECONDARY)); break; case PROP_STORAGE_TYPE_PRIMARY: g_value_set_enum (value, - gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_PRIMARY)); + gtk_entry_get_icon_storage_type (entry, + GTK_ENTRY_ICON_PRIMARY)); break; case PROP_STORAGE_TYPE_SECONDARY: g_value_set_enum (value, - gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_SECONDARY)); + gtk_entry_get_icon_storage_type (entry, + GTK_ENTRY_ICON_SECONDARY)); break; case PROP_ACTIVATABLE_PRIMARY: @@ -1964,6 +2265,31 @@ gtk_entry_get_property (GObject *object, gtk_entry_get_icon_sensitive (entry, GTK_ENTRY_ICON_SECONDARY)); break; + case PROP_TOOLTIP_TEXT_PRIMARY: + g_value_take_string (value, + gtk_entry_get_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY)); + break; + + case PROP_TOOLTIP_TEXT_SECONDARY: + g_value_take_string (value, + gtk_entry_get_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY)); + break; + + case PROP_TOOLTIP_MARKUP_PRIMARY: + g_value_take_string (value, + gtk_entry_get_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY)); + break; + + case PROP_TOOLTIP_MARKUP_SECONDARY: + g_value_take_string (value, + gtk_entry_get_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY)); + break; + + case PROP_EDITING_CANCELED: + g_value_set_boolean (value, + priv->editing_canceled); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1977,12 +2303,17 @@ find_invisible_char (GtkWidget *widget) PangoAttrList *attr_list; gint i; gunichar invisible_chars [] = { + 0, 0x25cf, /* BLACK CIRCLE */ 0x2022, /* BULLET */ 0x2731, /* HEAVY ASTERISK */ 0x273a /* SIXTEEN POINTED ASTERISK */ }; + gtk_widget_style_get (widget, + "invisible-char", &invisible_chars[0], + NULL); + layout = gtk_widget_create_pango_layout (widget, NULL); attr_list = pango_attr_list_new (); @@ -1991,7 +2322,7 @@ find_invisible_char (GtkWidget *widget) pango_layout_set_attributes (layout, attr_list); pango_attr_list_unref (attr_list); - for (i = 0; i < G_N_ELEMENTS (invisible_chars); i++) + for (i = (invisible_chars[0] != 0 ? 0 : 1); i < G_N_ELEMENTS (invisible_chars); i++) { gchar text[7] = { 0, }; gint len, count; @@ -2009,29 +2340,33 @@ find_invisible_char (GtkWidget *widget) } g_object_unref (layout); + return '*'; } 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'; - - entry->editable = TRUE; - entry->visible = TRUE; - entry->invisible_char = find_invisible_char (GTK_WIDGET (entry)); - entry->dnd_position = -1; - entry->width_chars = -1; - entry->is_cell_renderer = FALSE; - entry->editing_canceled = FALSE; - entry->has_frame = TRUE; - entry->truncate_multiline = FALSE; + GtkStyleContext *context; + GtkEntryPrivate *priv; + + entry->priv = G_TYPE_INSTANCE_GET_PRIVATE (entry, + GTK_TYPE_ENTRY, + GtkEntryPrivate); + priv = entry->priv; + + gtk_widget_set_can_focus (GTK_WIDGET (entry), TRUE); + gtk_widget_set_has_window (GTK_WIDGET (entry), FALSE); + + priv->editable = TRUE; + priv->visible = TRUE; + priv->invisible_char = find_invisible_char (GTK_WIDGET (entry)); + priv->dnd_position = -1; + priv->width_chars = -1; + priv->is_cell_renderer = FALSE; + priv->editing_canceled = FALSE; + priv->has_frame = TRUE; + priv->truncate_multiline = FALSE; priv->shadow_type = GTK_SHADOW_IN; priv->xalign = 0.0; priv->caps_lock_warning = TRUE; @@ -2048,23 +2383,26 @@ gtk_entry_init (GtkEntry *entry) /* This object is completely private. No external entity can gain a reference * to it; so we create it here and destroy it in finalize(). */ - entry->im_context = gtk_im_multicontext_new (); - - g_signal_connect (entry->im_context, "commit", + priv->im_context = gtk_im_multicontext_new (); + + g_signal_connect (priv->im_context, "commit", G_CALLBACK (gtk_entry_commit_cb), entry); - g_signal_connect (entry->im_context, "preedit-changed", + g_signal_connect (priv->im_context, "preedit-changed", G_CALLBACK (gtk_entry_preedit_changed_cb), entry); - g_signal_connect (entry->im_context, "retrieve-surrounding", + g_signal_connect (priv->im_context, "retrieve-surrounding", G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry); - g_signal_connect (entry->im_context, "delete-surrounding", + g_signal_connect (priv->im_context, "delete-surrounding", G_CALLBACK (gtk_entry_delete_surrounding_cb), entry); + + context = gtk_widget_get_style_context (GTK_WIDGET (entry)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY); } static gint get_icon_width (GtkEntry *entry, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; GdkScreen *screen; GtkSettings *settings; @@ -2088,10 +2426,13 @@ get_icon_allocations (GtkEntry *entry, GtkAllocation *secondary) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint x, y, width, height; - gtk_entry_get_text_area_size (entry, &x, &y, &width, &height); + get_text_area_size (entry, &x, &y, &width, &height); + + if (gtk_widget_has_focus (GTK_WIDGET (entry)) && !priv->interior_focus) + y += priv->focus_width; primary->y = y; primary->height = height; @@ -2121,7 +2462,7 @@ get_icon_allocations (GtkEntry *entry, static void begin_change (GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; priv->change_count++; } @@ -2130,86 +2471,77 @@ static void end_change (GtkEntry *entry) { GtkEditable *editable = GTK_EDITABLE (entry); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); - + GtkEntryPrivate *priv = entry->priv; + g_return_if_fail (priv->change_count > 0); priv->change_count--; if (priv->change_count == 0) { - if (priv->real_changed) + if (priv->real_changed) { g_signal_emit_by_name (editable, "changed"); priv->real_changed = FALSE; } - } + } } static void emit_changed (GtkEntry *entry) { GtkEditable *editable = GTK_EDITABLE (entry); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; if (priv->change_count == 0) g_signal_emit_by_name (editable, "changed"); - else + else 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); + GtkEntryPrivate *priv = entry->priv; - entry->n_bytes = 0; - entry->current_pos = entry->selection_bound = entry->text_length = 0; + priv->current_pos = priv->selection_bound = 0; _gtk_entry_reset_im_context (entry); gtk_entry_reset_layout (entry); - if (entry->blink_timeout) - { - g_source_remove (entry->blink_timeout); - entry->blink_timeout = 0; - } - - if (entry->recompute_idle) + if (priv->blink_timeout) { - g_source_remove (entry->recompute_idle); - entry->recompute_idle = 0; + g_source_remove (priv->blink_timeout); + priv->blink_timeout = 0; } - if (!entry->visible) + if (priv->recompute_idle) { - /* We want to trash the text here because the entry might be leaked. */ - trash_area (entry->text, strlen (entry->text)); + g_source_remove (priv->recompute_idle); + priv->recompute_idle = 0; } - 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 = entry->priv; 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); } @@ -2217,7 +2549,7 @@ static void gtk_entry_finalize (GObject *object) { GtkEntry *entry = GTK_ENTRY (object); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = NULL; gint i; @@ -2238,34 +2570,111 @@ gtk_entry_finalize (GObject *object) gtk_entry_set_completion (entry, NULL); - if (entry->cached_layout) - g_object_unref (entry->cached_layout); + if (priv->cached_layout) + g_object_unref (priv->cached_layout); + + g_object_unref (priv->im_context); + + if (priv->blink_timeout) + g_source_remove (priv->blink_timeout); + + if (priv->recompute_idle) + g_source_remove (priv->recompute_idle); + + 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 = entry->priv; + + if (priv->visible) + return DISPLAY_NORMAL; + + if (priv->invisible_char == 0 && priv->invisible_char_set) + return DISPLAY_BLANK; - g_object_unref (entry->im_context); + return DISPLAY_INVISIBLE; +} - if (entry->blink_timeout) - g_source_remove (entry->blink_timeout); +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; - if (entry->recompute_idle) - g_source_remove (entry->recompute_idle); + priv = entry->priv; + text = gtk_entry_buffer_get_text (get_buffer (entry)); + length = gtk_entry_buffer_get_length (get_buffer (entry)); - entry->text_size = 0; + 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 (priv->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); + + /* Figure out what our invisible char is and encode it */ + if (!priv->invisible_char) + invisible_char = priv->invisible_char_set ? ' ' : '*'; + else + invisible_char = priv->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 update_cursors (GtkWidget *widget) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = NULL; GdkDisplay *display; GdkCursor *cursor; @@ -2275,22 +2684,22 @@ update_cursors (GtkWidget *widget) { if ((icon_info = priv->icons[i]) != NULL) { - if (icon_info->pixbuf != NULL) - gdk_window_show (icon_info->window); + if (icon_info->pixbuf != NULL && icon_info->window != NULL) + gdk_window_show_unraised (icon_info->window); /* The icon windows are not children of the visible entry window, * thus we can't just inherit the xterm cursor. Slight complication * 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))) { display = gtk_widget_get_display (widget); cursor = gdk_cursor_new_for_display (display, GDK_XTERM); gdk_window_set_cursor (icon_info->window, cursor); - gdk_cursor_unref (cursor); + g_object_unref (cursor); } else { @@ -2304,7 +2713,8 @@ static void realize_icon_info (GtkWidget *widget, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; GdkWindowAttr attributes; gint attributes_mask; @@ -2316,12 +2726,9 @@ realize_icon_info (GtkWidget *widget, attributes.width = 1; attributes.height = 1; 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.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | @@ -2329,14 +2736,12 @@ 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; - 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)]); gtk_widget_queue_resize (widget); } @@ -2345,7 +2750,8 @@ static EntryIconInfo* construct_icon_info (GtkWidget *widget, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info; g_return_val_if_fail (priv->icons[icon_pos] == NULL, NULL); @@ -2353,59 +2759,56 @@ 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 (icon_info->window); - return icon_info; } static void gtk_entry_map (GtkWidget *widget) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; 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++) + gdk_window_show (priv->text_area); + + 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 gtk_entry_unmap (GtkWidget *widget) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; 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); } + + gdk_window_hide (priv->text_area); + + GTK_WIDGET_CLASS (gtk_entry_parent_class)->unmap (widget); } static void @@ -2414,24 +2817,24 @@ gtk_entry_realize (GtkWidget *widget) GtkEntry *entry; GtkEntryPrivate *priv; EntryIconInfo *icon_info; + GdkWindow *window; GdkWindowAttr attributes; gint attributes_mask; + gint frame_x, frame_y; int i; - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + gtk_widget_set_realized (widget, TRUE); + window = gtk_widget_get_parent_window (widget); + gtk_widget_set_window (widget, window); + g_object_ref (window); + entry = GTK_ENTRY (widget); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; attributes.window_type = GDK_WINDOW_CHILD; - - get_widget_window_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height); - - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); + attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | @@ -2439,37 +2842,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; - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, entry); + get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height); - gtk_entry_get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height); - - if (GTK_WIDGET_IS_SENSITIVE (widget)) + get_frame_size (entry, &frame_x, &frame_y, NULL, NULL); + attributes.x += frame_x; + attributes.y += frame_y; + + 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); + priv->text_area = gdk_window_new (gtk_widget_get_window (widget), + &attributes, + attributes_mask); - gdk_window_set_user_data (entry->text_area, entry); + gdk_window_set_user_data (priv->text_area, entry); if (attributes_mask & GDK_WA_CURSOR) - gdk_cursor_unref (attributes.cursor); + g_object_unref (attributes.cursor); - widget->style = gtk_style_attach (widget->style, widget->window); + gtk_im_context_set_client_window (priv->im_context, priv->text_area); - 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)]); - - gdk_window_show (entry->text_area); - - gtk_im_context_set_client_window (entry->im_context, entry->text_area); - - gtk_entry_adjust_scroll (entry); - gtk_entry_update_primary_selection (entry); + gtk_entry_adjust_scroll (entry); + gtk_entry_update_primary_selection (entry); /* If the icon positions are already setup, create their windows. @@ -2490,30 +2889,30 @@ static void gtk_entry_unrealize (GtkWidget *widget) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; GtkClipboard *clipboard; EntryIconInfo *icon_info; gint i; gtk_entry_reset_layout (entry); - gtk_im_context_set_client_window (entry->im_context, NULL); + gtk_im_context_set_client_window (priv->im_context, NULL); clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY); if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry)) gtk_clipboard_clear (clipboard); - if (entry->text_area) + if (priv->text_area) { - gdk_window_set_user_data (entry->text_area, NULL); - gdk_window_destroy (entry->text_area); - entry->text_area = NULL; + gdk_window_set_user_data (priv->text_area, NULL); + gdk_window_destroy (priv->text_area); + priv->text_area = NULL; } - if (entry->popup_menu) + if (priv->popup_menu) { - gtk_widget_destroy (entry->popup_menu); - entry->popup_menu = NULL; + gtk_widget_destroy (priv->popup_menu); + priv->popup_menu = NULL; } GTK_WIDGET_CLASS (gtk_entry_parent_class)->unrealize (widget); @@ -2536,13 +2935,19 @@ _gtk_entry_get_borders (GtkEntry *entry, gint *xborder, gint *yborder) { + GtkEntryPrivate *priv = entry->priv; GtkWidget *widget = GTK_WIDGET (entry); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); - if (entry->has_frame) + if (priv->has_frame) { - *xborder = widget->style->xthickness; - *yborder = widget->style->ythickness; + GtkStyleContext *context; + GtkBorder padding; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_padding (context, 0, &padding); + + *xborder = padding.left; + *yborder = padding.top; } else { @@ -2558,42 +2963,44 @@ _gtk_entry_get_borders (GtkEntry *entry, } static void -gtk_entry_size_request (GtkWidget *widget, - GtkRequisition *requisition) +gtk_entry_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; PangoFontMetrics *metrics; gint xborder, yborder; GtkBorder inner_border; PangoContext *context; - int icon_widths = 0; - int icon_width, i; - - gtk_widget_ensure_style (widget); + GtkStyleContext *style_context; + GtkStateFlags state; + gint icon_widths = 0; + gint icon_width, i; + gint width; + context = gtk_widget_get_pango_context (widget); + + style_context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + metrics = pango_context_get_metrics (context, - widget->style->font_desc, - pango_context_get_language (context)); + gtk_style_context_get_font (style_context, state), + pango_context_get_language (context)); - entry->ascent = pango_font_metrics_get_ascent (metrics); - entry->descent = pango_font_metrics_get_descent (metrics); - _gtk_entry_get_borders (entry, &xborder, &yborder); _gtk_entry_effective_inner_border (entry, &inner_border); - if (entry->width_chars < 0) - requisition->width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right; + if (priv->width_chars < 0) + width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right; else { gint char_width = pango_font_metrics_get_approximate_char_width (metrics); gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics); gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE; - - requisition->width = char_pixels * entry->width_chars + xborder * 2 + inner_border.left + inner_border.right; + + width = char_pixels * priv->width_chars + xborder * 2 + inner_border.left + inner_border.right; } - - requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2 + inner_border.top + inner_border.bottom; for (i = 0; i < MAX_ICONS; i++) { @@ -2602,34 +3009,86 @@ gtk_entry_size_request (GtkWidget *widget, icon_widths += icon_width + 2 * priv->icon_margin; } - if (icon_widths > requisition->width) - requisition->width += icon_widths; + if (icon_widths > width) + width += icon_widths; + + pango_font_metrics_unref (metrics); + + *minimum = width; + *natural = width; +} + +static void +gtk_entry_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + PangoFontMetrics *metrics; + gint xborder, yborder; + GtkBorder inner_border; + GtkStyleContext *style_context; + GtkStateFlags state; + PangoContext *context; + gint height; + + context = gtk_widget_get_pango_context (widget); + + style_context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + + metrics = pango_context_get_metrics (context, + gtk_style_context_get_font (style_context, state), + pango_context_get_language (context)); + + priv->ascent = pango_font_metrics_get_ascent (metrics); + priv->descent = pango_font_metrics_get_descent (metrics); + + _gtk_entry_get_borders (entry, &xborder, &yborder); + _gtk_entry_effective_inner_border (entry, &inner_border); + + height = PANGO_PIXELS (priv->ascent + priv->descent) + yborder * 2 + inner_border.top + inner_border.bottom; pango_font_metrics_unref (metrics); + + *minimum = height; + *natural = height; } static void place_windows (GtkEntry *entry) - { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkWidget *widget = GTK_WIDGET (entry); + GtkEntryPrivate *priv = entry->priv; gint x, y, width, height; + gint frame_x, frame_y; GtkAllocation primary; GtkAllocation secondary; EntryIconInfo *icon_info = NULL; - gtk_entry_get_text_area_size (entry, &x, &y, &width, &height); - + get_frame_size (entry, &frame_x, &frame_y, NULL, NULL); + get_text_area_size (entry, &x, &y, &width, &height); get_icon_allocations (entry, &primary, &secondary); - if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + if (gtk_widget_has_focus (widget) && !priv->interior_focus) + y += priv->focus_width; + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) x += secondary.width; else x += primary.width; width -= primary.width + secondary.width; + x += frame_x; + y += frame_y; + primary.x += frame_x; + primary.y += frame_y; + secondary.x += frame_x; + secondary.y += frame_y; + if ((icon_info = priv->icons[GTK_ENTRY_ICON_PRIMARY]) != NULL) - gdk_window_move_resize (icon_info->window, + gdk_window_move_resize (icon_info->window, primary.x, primary.y, primary.width, primary.height); @@ -2638,7 +3097,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 (priv->text_area, x, y, width, height); } static void @@ -2648,21 +3107,23 @@ gtk_entry_get_text_area_size (GtkEntry *entry, gint *width, gint *height) { + GtkEntryPrivate *priv = entry->priv; 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)) + get_frame_size (entry, NULL, NULL, NULL, &frame_height); 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) @@ -2672,42 +3133,63 @@ 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; } static void -get_widget_window_size (GtkEntry *entry, - gint *x, - gint *y, - gint *width, - gint *height) +get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) { + GtkEntryClass *class; + + g_return_if_fail (GTK_IS_ENTRY (entry)); + + class = GTK_ENTRY_GET_CLASS (entry); + + if (class->get_text_area_size) + class->get_text_area_size (entry, x, y, width, height); +} + + +static void +get_frame_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) +{ + GtkEntryPrivate *priv = entry->priv; + 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; + if (priv->is_cell_renderer) + *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; + if (priv->is_cell_renderer) + *height = allocation.height; else *height = requisition.height; } @@ -2744,88 +3226,31 @@ 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); - 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); } } -/* Kudos to the gnome-panel guys. */ -static void -colorshift_pixbuf (GdkPixbuf *dest, - GdkPixbuf *src, - gint shift) -{ - gint i, j; - gint width, height, has_alpha, src_rowstride, dest_rowstride; - guchar *target_pixels; - guchar *original_pixels; - guchar *pix_src; - guchar *pix_dest; - int val; - guchar r, g, b; - - has_alpha = gdk_pixbuf_get_has_alpha (src); - width = gdk_pixbuf_get_width (src); - height = gdk_pixbuf_get_height (src); - src_rowstride = gdk_pixbuf_get_rowstride (src); - dest_rowstride = gdk_pixbuf_get_rowstride (dest); - original_pixels = gdk_pixbuf_get_pixels (src); - target_pixels = gdk_pixbuf_get_pixels (dest); - - for (i = 0; i < height; i++) - { - pix_dest = target_pixels + i * dest_rowstride; - pix_src = original_pixels + i * src_rowstride; - - for (j = 0; j < width; j++) - { - r = *(pix_src++); - g = *(pix_src++); - b = *(pix_src++); - - val = r + shift; - *(pix_dest++) = CLAMP (val, 0, 255); - - val = g + shift; - *(pix_dest++) = CLAMP (val, 0, 255); - - val = b + shift; - *(pix_dest++) = CLAMP (val, 0, 255); - - if (has_alpha) - *(pix_dest++) = *(pix_src++); - } - } -} - static gboolean should_prelight (GtkEntry *entry, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; gboolean prelight; - if (!icon_info) + if (!icon_info) return FALSE; if (icon_info->nonactivatable && icon_info->target_list == NULL) @@ -2835,7 +3260,7 @@ should_prelight (GtkEntry *entry, return FALSE; gtk_widget_style_get (GTK_WIDGET (entry), - "prelight", &prelight, + "icon-prelight", &prelight, NULL); return prelight; @@ -2843,13 +3268,17 @@ should_prelight (GtkEntry *entry, static void draw_icon (GtkWidget *widget, + cairo_t *cr, GtkEntryIconPosition icon_pos) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; GdkPixbuf *pixbuf; gint x, y, width, height; + GtkStyleContext *context; + GtkIconSource *icon_source; + GtkStateFlags state; if (!icon_info) return; @@ -2859,7 +3288,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. */ @@ -2884,50 +3314,55 @@ 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) || - icon_info->insensitive) - { - GdkPixbuf *temp_pixbuf; + icon_source = gtk_icon_source_new (); + gtk_icon_source_set_pixbuf (icon_source, pixbuf); + gtk_icon_source_set_state_wildcarded (icon_source, TRUE); - temp_pixbuf = gdk_pixbuf_copy (pixbuf); - gdk_pixbuf_saturate_and_pixelate (pixbuf, - temp_pixbuf, - 0.8f, - TRUE); - g_object_unref (pixbuf); - pixbuf = temp_pixbuf; - } + state = 0; + if (!gtk_widget_is_sensitive (widget) || icon_info->insensitive) + state |= GTK_STATE_FLAG_INSENSITIVE; else if (icon_info->prelight) - { - GdkPixbuf *temp_pixbuf; + state |= GTK_STATE_FLAG_PRELIGHT; - temp_pixbuf = gdk_pixbuf_copy (pixbuf); - colorshift_pixbuf (temp_pixbuf, pixbuf, 30); - g_object_unref (pixbuf); - pixbuf = temp_pixbuf; - } + context = gtk_widget_get_style_context (widget); + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + pixbuf = gtk_render_icon_pixbuf (context, icon_source, (GtkIconSize)-1); + gtk_style_context_restore (context); - gdk_draw_pixbuf (icon_info->window, widget->style->black_gc, pixbuf, - 0, 0, x, y, -1, -1, - GDK_RGB_DITHER_NORMAL, 0, 0); + gtk_icon_source_free (icon_source); + + gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); + cairo_paint (cr); g_object_unref (pixbuf); } static void -gtk_entry_draw_frame (GtkWidget *widget, - GdkRectangle *area) +gtk_entry_draw_frame (GtkWidget *widget, + GtkStyleContext *context, + cairo_t *cr) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + GdkWindow *window; gint x = 0, y = 0, width, height; - gboolean state_hint; - GtkStateType state; + GtkAllocation allocation; + gint frame_x, frame_y; + + cairo_save (cr); + + window = gtk_widget_get_window (widget); + + get_frame_size (GTK_ENTRY (widget), &frame_x, &frame_y, &width, &height); + gtk_widget_get_allocation (widget, &allocation); - gdk_drawable_get_size (widget->window, &width, &height); + cairo_translate (cr, frame_x - allocation.x, frame_y - allocation.y); /* 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; @@ -2939,7 +3374,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; @@ -2947,145 +3382,176 @@ 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; + gtk_render_background (context, cr, + x, y, width, height); + + if (priv->has_frame) + gtk_render_frame (context, cr, + x, y, width, height); - gtk_paint_shadow (widget->style, widget->window, - state, priv->shadow_type, - area, widget, "entry", x, y, width, height); + gtk_entry_draw_progress (widget, context, cr); - 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), - area, widget, "entry", - 0, 0, width, height); + + gtk_render_focus (context, cr, + 0, 0, width, height); } + + cairo_restore (cr); } static void -gtk_entry_draw_progress (GtkWidget *widget, - GdkEventExpose *event) +get_progress_area (GtkWidget *widget, + gint *x, + gint *y, + gint *width, + gint *height) { - GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget); GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *private = entry->priv; + GtkBorder *progress_border; + + get_text_area_size (entry, x, y, width, height); + + if (!private->interior_focus) + { + *x -= private->focus_width; + *y -= private->focus_width; + *width += 2 * private->focus_width; + *height += 2 * private->focus_width; + } + + gtk_widget_style_get (widget, "progress-border", &progress_border, NULL); + + if (progress_border) + { + *x += progress_border->left; + *y += progress_border->top; + *width -= progress_border->left + progress_border->right; + *height -= progress_border->top + progress_border->bottom; + + gtk_border_free (progress_border); + } if (private->progress_pulse_mode) { gdouble value = private->progress_pulse_current; - gint area_width, area_height; - gdk_drawable_get_size (entry->text_area, &area_width, &area_height); - - gtk_paint_box (widget->style, entry->text_area, - GTK_STATE_SELECTED, GTK_SHADOW_OUT, - &event->area, widget, "entry-progress", - value * area_width, 0, - private->progress_pulse_fraction * area_width, area_height); + *x += (gint) floor(value * (*width)); + *width = (gint) ceil(private->progress_pulse_fraction * (*width)); } else if (private->progress_fraction > 0) { gdouble value = private->progress_fraction; - gint area_width, area_height; - - gdk_drawable_get_size (entry->text_area, &area_width, &area_height); if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) { - gtk_paint_box (widget->style, entry->text_area, - GTK_STATE_SELECTED, GTK_SHADOW_OUT, - &event->area, widget, "entry-progress", - area_width - value * area_width, 0, - value * area_width, area_height); + gint bar_width; + + bar_width = floor(value * (*width) + 0.5); + *x += *width - bar_width; + *width = bar_width; } else { - gtk_paint_box (widget->style, entry->text_area, - GTK_STATE_SELECTED, GTK_SHADOW_OUT, - &event->area, widget, "entry-progress", - 0, 0, - value * area_width, area_height); + *width = (gint) floor(value * (*width) + 0.5); } } + else + { + *width = 0; + *height = 0; + } +} + +static void +gtk_entry_draw_progress (GtkWidget *widget, + GtkStyleContext *context, + cairo_t *cr) +{ + gint x, y, width, height; + + get_progress_area (widget, &x, &y, &width, &height); + + if ((width <= 0) || (height <= 0)) + return; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR); + + gtk_render_activity (context, cr, + x, y, width, height); + + gtk_style_context_restore (context); } 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; - GtkStateType state; - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); - - 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); + GtkStyleContext *context; + GtkStateFlags state; + GtkEntryPrivate *priv = entry->priv; + int i; - if (widget->window == event->window) - { - gtk_entry_draw_frame (widget, &event->area); - } - else if (entry->text_area == event->window) - { - gint width, height; + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); - gdk_drawable_get_size (entry->text_area, &width, &height); + if (gtk_widget_has_focus (widget)) + state |= GTK_STATE_FLAG_FOCUSED; - gtk_paint_flat_box (widget->style, entry->text_area, - state, GTK_SHADOW_NONE, - &event->area, widget, "entry_bg", - 0, 0, width, height); + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); - gtk_entry_draw_progress (widget, event); + if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) + { + /* Draw entry_bg, shadow, progress and focus */ + gtk_entry_draw_frame (widget, context, cr); + + /* Draw text and cursor */ + cairo_save (cr); - if (entry->dnd_position != -1) - gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND); + gtk_cairo_transform_to_window (cr, widget, priv->text_area); + + if (priv->dnd_position != -1) + 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); - } - else - { - int i; + /* 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) && + priv->selection_bound == priv->current_pos && priv->cursor_visible) + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD); + cairo_restore (cr); + + /* Draw icons */ for (i = 0; i < MAX_ICONS; i++) { EntryIconInfo *icon_info = priv->icons[i]; - if (icon_info != NULL && event->window == icon_info->window) + if (icon_info != NULL) { - gint width, height; - - gdk_drawable_get_size (icon_info->window, &width, &height); + cairo_save (cr); - 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_cairo_transform_to_window (cr, widget, icon_info->window); - draw_icon (widget, i); + draw_icon (widget, cr, i); - break; + cairo_restore (cr); } } } + gtk_style_context_restore (context); + return FALSE; } @@ -3094,7 +3560,7 @@ gtk_entry_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint i; for (i = 0; i < MAX_ICONS; i++) @@ -3121,7 +3587,7 @@ gtk_entry_leave_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint i; for (i = 0; i < MAX_ICONS; i++) @@ -3130,6 +3596,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; @@ -3213,7 +3683,7 @@ gtk_entry_button_press (GtkWidget *widget, { GtkEntry *entry = GTK_ENTRY (widget); GtkEditable *editable = GTK_EDITABLE (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = NULL; gint tmp_pos; gint sel_start, sel_end; @@ -3239,42 +3709,42 @@ gtk_entry_button_press (GtkWidget *widget, icon_info->pressed = TRUE; if (!icon_info->nonactivatable) - g_signal_emit (entry, signals[ICON_PRESSED], 0, i, event); + g_signal_emit (entry, signals[ICON_PRESS], 0, i, event); return TRUE; } } - if (event->window != entry->text_area || - (entry->button && event->button != entry->button)) + if (event->window != priv->text_area || + (priv->button && event->button != priv->button)) return FALSE; gtk_entry_reset_blink_time (entry); - entry->button = event->button; + priv->button = event->button; - if (!GTK_WIDGET_HAS_FOCUS (widget)) + if (!gtk_widget_has_focus (widget)) { - entry->in_click = TRUE; + priv->in_click = TRUE; gtk_widget_grab_focus (widget); - entry->in_click = FALSE; + priv->in_click = FALSE; } - tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); if (event->button == 1) { gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end); - entry->select_words = FALSE; - entry->select_lines = FALSE; + priv->select_words = FALSE; + priv->select_lines = FALSE; if (event->state & GDK_SHIFT_MASK) { _gtk_entry_reset_im_context (entry); if (!have_selection) /* select from the current position to the clicked position */ - sel_start = sel_end = entry->current_pos; + sel_start = sel_end = priv->current_pos; if (tmp_pos > sel_start && tmp_pos < sel_end) { @@ -3297,12 +3767,12 @@ gtk_entry_button_press (GtkWidget *widget, break; case GDK_2BUTTON_PRESS: - entry->select_words = TRUE; + priv->select_words = TRUE; gtk_entry_select_word (entry); break; case GDK_3BUTTON_PRESS: - entry->select_lines = TRUE; + priv->select_lines = TRUE; gtk_entry_select_line (entry); break; @@ -3310,10 +3780,10 @@ gtk_entry_button_press (GtkWidget *widget, break; } - start = MIN (entry->current_pos, entry->selection_bound); + start = MIN (priv->current_pos, priv->selection_bound); start = MIN (sel_start, start); - end = MAX (entry->current_pos, entry->selection_bound); + end = MAX (priv->current_pos, priv->selection_bound); end = MAX (sel_end, end); if (tmp_pos == sel_start || tmp_pos == sel_end) @@ -3331,14 +3801,14 @@ gtk_entry_button_press (GtkWidget *widget, switch (event->type) { case GDK_BUTTON_PRESS: - if (in_selection (entry, event->x + entry->scroll_offset)) + if (in_selection (entry, event->x + priv->scroll_offset)) { /* Click inside the selection - we'll either start a drag, or * clear the selection */ - entry->in_drag = TRUE; - entry->drag_start_x = event->x + entry->scroll_offset; - entry->drag_start_y = event->y; + priv->in_drag = TRUE; + priv->drag_start_x = event->x + priv->scroll_offset; + priv->drag_start_y = event->y; } else gtk_editable_set_position (editable, tmp_pos); @@ -3347,20 +3817,20 @@ gtk_entry_button_press (GtkWidget *widget, case GDK_2BUTTON_PRESS: /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before * receiving a GDK_2BUTTON_PRESS so we need to reset - * entry->in_drag which may have been set above + * priv->in_drag which may have been set above */ - entry->in_drag = FALSE; - entry->select_words = TRUE; + priv->in_drag = FALSE; + priv->select_words = TRUE; gtk_entry_select_word (entry); break; case GDK_3BUTTON_PRESS: /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before * receiving a GDK_3BUTTON_PRESS so we need to reset - * entry->in_drag which may have been set above + * priv->in_drag which may have been set above */ - entry->in_drag = FALSE; - entry->select_lines = TRUE; + priv->in_drag = FALSE; + priv->select_lines = TRUE; gtk_entry_select_line (entry); break; @@ -3372,7 +3842,7 @@ gtk_entry_button_press (GtkWidget *widget, } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { - if (entry->editable) + if (priv->editable) { priv->insert_pos = tmp_pos; gtk_entry_paste (entry, GDK_SELECTION_PRIMARY); @@ -3386,7 +3856,7 @@ gtk_entry_button_press (GtkWidget *widget, else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { gtk_entry_do_popup (entry, event); - entry->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ + priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ return TRUE; } @@ -3399,7 +3869,7 @@ gtk_entry_button_release (GtkWidget *widget, GdkEventButton *event) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = NULL; gint i; @@ -3412,40 +3882,37 @@ 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); } if (!icon_info->nonactivatable) - g_signal_emit (entry, signals[ICON_RELEASED], 0, i, event); + g_signal_emit (entry, signals[ICON_RELEASE], 0, i, event); return TRUE; } } - if (event->window != entry->text_area || entry->button != event->button) + if (event->window != priv->text_area || priv->button != event->button) return FALSE; - if (entry->in_drag) + if (priv->in_drag) { - gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x); + gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x); gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos); - entry->in_drag = 0; + priv->in_drag = 0; } - entry->button = 0; + priv->button = 0; gtk_entry_update_primary_selection (entry); @@ -3470,7 +3937,7 @@ gtk_entry_motion_notify (GtkWidget *widget, GdkEventMotion *event) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = NULL; GdkDragContext *context; gint tmp_pos; @@ -3506,77 +3973,70 @@ gtk_entry_motion_notify (GtkWidget *widget, } } - if (entry->mouse_cursor_obscured) + if (priv->mouse_cursor_obscured) { GdkCursor *cursor; cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM); - gdk_window_set_cursor (entry->text_area, cursor); - gdk_cursor_unref (cursor); - entry->mouse_cursor_obscured = FALSE; + gdk_window_set_cursor (priv->text_area, cursor); + g_object_unref (cursor); + priv->mouse_cursor_obscured = FALSE; } - if (event->window != entry->text_area || entry->button != 1) + if (event->window != priv->text_area || priv->button != 1) return FALSE; - if (entry->select_lines) + if (priv->select_lines) return TRUE; gdk_event_request_motions (event); - if (entry->in_drag) + if (priv->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)) + priv->drag_start_x, priv->drag_start_y, + event->x + priv->scroll_offset, event->y)) { GdkDragContext *context; GtkTargetList *target_list = gtk_target_list_new (NULL, 0); - guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY; + guint actions = priv->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); + priv->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; - entry->button = 0; + priv->in_drag = FALSE; + priv->button = 0; gtk_target_list_unref (target_list); } } 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 (priv->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); - - if (entry->select_words) + tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); + + if (priv->select_words) { gint min, max; gint old_min, old_max; @@ -3584,12 +4044,12 @@ gtk_entry_motion_notify (GtkWidget *widget, min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE); max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE); - - pos = entry->current_pos; - bound = entry->selection_bound; - old_min = MIN(entry->current_pos, entry->selection_bound); - old_max = MAX(entry->current_pos, entry->selection_bound); + pos = priv->current_pos; + bound = priv->selection_bound; + + old_min = MIN(priv->current_pos, priv->selection_bound); + old_max = MAX(priv->current_pos, priv->selection_bound); if (min < old_min) { @@ -3603,19 +4063,19 @@ gtk_entry_motion_notify (GtkWidget *widget, } else if (pos == old_min) { - if (entry->current_pos != min) + if (priv->current_pos != min) pos = max; } else { - if (entry->current_pos != max) + if (priv->current_pos != max) pos = min; } gtk_entry_set_positions (entry, pos, bound); } else - gtk_entry_set_positions (entry, tmp_pos, -1); + gtk_entry_set_positions (entry, tmp_pos, -1); } return TRUE; @@ -3624,39 +4084,28 @@ gtk_entry_motion_notify (GtkWidget *widget, static void set_invisible_cursor (GdkWindow *window) { - GdkBitmap *empty_bitmap; + GdkDisplay *display; GdkCursor *cursor; - GdkColor useless; - char invisible_cursor_bits[] = { 0x0 }; - - useless.red = useless.green = useless.blue = 0; - useless.pixel = 0; - - empty_bitmap = gdk_bitmap_create_from_data (window, - invisible_cursor_bits, - 1, 1); - - cursor = gdk_cursor_new_from_pixmap (empty_bitmap, - empty_bitmap, - &useless, - &useless, 0, 0); - + + display = gdk_window_get_display (window); + cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR); + gdk_window_set_cursor (window, cursor); - - gdk_cursor_unref (cursor); - - g_object_unref (empty_bitmap); + + g_object_unref (cursor); } static void gtk_entry_obscure_mouse_cursor (GtkEntry *entry) { - if (entry->mouse_cursor_obscured) + GtkEntryPrivate *priv = entry->priv; + + if (priv->mouse_cursor_obscured) return; - set_invisible_cursor (entry->text_area); - - entry->mouse_cursor_obscured = TRUE; + set_invisible_cursor (priv->text_area); + + priv->mouse_cursor_obscured = TRUE; } static gint @@ -3664,27 +4113,28 @@ gtk_entry_key_press (GtkWidget *widget, GdkEventKey *event) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; gtk_entry_reset_blink_time (entry); gtk_entry_pend_cursor_blink (entry); - if (entry->editable) + if (priv->editable) { - if (gtk_im_context_filter_keypress (entry->im_context, event)) + if (gtk_im_context_filter_keypress (priv->im_context, event)) { gtk_entry_obscure_mouse_cursor (entry); - entry->need_im_reset = TRUE; + priv->need_im_reset = TRUE; return TRUE; } } - 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); - + if (completion && completion->priv->completion_timeout) { g_source_remove (completion->priv->completion_timeout); @@ -3699,7 +4149,7 @@ gtk_entry_key_press (GtkWidget *widget, */ return TRUE; - if (!entry->editable && event->length) + if (!priv->editable && event->length) gtk_widget_error_bell (widget); return FALSE; @@ -3710,12 +4160,13 @@ gtk_entry_key_release (GtkWidget *widget, GdkEventKey *event) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; - if (entry->editable) + if (priv->editable) { - if (gtk_im_context_filter_keypress (entry->im_context, event)) + if (gtk_im_context_filter_keypress (priv->im_context, event)) { - entry->need_im_reset = TRUE; + priv->need_im_reset = TRUE; return TRUE; } } @@ -3728,16 +4179,17 @@ gtk_entry_focus_in (GtkWidget *widget, GdkEventFocus *event) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; GdkKeymap *keymap; gtk_widget_queue_draw (widget); keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget)); - if (entry->editable) + if (priv->editable) { - entry->need_im_reset = TRUE; - gtk_im_context_focus_in (entry->im_context); + priv->need_im_reset = TRUE; + gtk_im_context_focus_in (priv->im_context); keymap_state_changed (keymap, entry); g_signal_connect (keymap, "state-changed", G_CALLBACK (keymap_state_changed), entry); @@ -3757,17 +4209,18 @@ gtk_entry_focus_out (GtkWidget *widget, GdkEventFocus *event) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; GtkEntryCompletion *completion; GdkKeymap *keymap; - + gtk_widget_queue_draw (widget); keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget)); - if (entry->editable) + if (priv->editable) { - entry->need_im_reset = TRUE; - gtk_im_context_focus_out (entry->im_context); + priv->need_im_reset = TRUE; + gtk_im_context_focus_out (priv->im_context); remove_capslock_feedback (entry); } @@ -3787,11 +4240,12 @@ static void gtk_entry_grab_focus (GtkWidget *widget) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; gboolean select_on_focus; GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_focus (widget); - if (entry->editable && !entry->in_click) + if (priv->editable && !priv->in_click) { g_object_get (gtk_widget_get_settings (widget), "gtk-entry-select-on-focus", @@ -3815,44 +4269,34 @@ gtk_entry_direction_changed (GtkWidget *widget, } static void -gtk_entry_state_changed (GtkWidget *widget, - GtkStateType previous_state) +gtk_entry_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous_state) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntryPrivate *priv = entry->priv; 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)]); - 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)]); - } - - 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; - - gdk_window_set_cursor (entry->text_area, cursor); + + gdk_window_set_cursor (priv->text_area, cursor); if (cursor) - gdk_cursor_unref (cursor); + g_object_unref (cursor); - entry->mouse_cursor_obscured = FALSE; + priv->mouse_cursor_obscured = FALSE; 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); + gtk_editable_select_region (GTK_EDITABLE (entry), priv->current_pos, priv->current_pos); } gtk_widget_queue_draw (widget); @@ -3873,30 +4317,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); } @@ -3906,15 +4334,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); @@ -3928,18 +4347,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 @@ -3947,12 +4371,16 @@ gtk_entry_real_set_position (GtkEditable *editable, gint position) { GtkEntry *entry = GTK_ENTRY (editable); + GtkEntryPrivate *priv = entry->priv; + + guint length; - if (position < 0 || position > entry->text_length) - position = entry->text_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) + if (position != priv->current_pos || + position != priv->selection_bound) { _gtk_entry_reset_im_context (entry); gtk_entry_set_positions (entry, position, position); @@ -3962,7 +4390,10 @@ gtk_entry_real_set_position (GtkEditable *editable, static gint gtk_entry_get_position (GtkEditable *editable) { - return GTK_ENTRY (editable)->current_pos; + GtkEntry *entry = GTK_ENTRY (editable); + GtkEntryPrivate *priv = entry->priv; + + return priv->current_pos; } static void @@ -3971,17 +4402,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); } @@ -3992,17 +4425,18 @@ gtk_entry_get_selection_bounds (GtkEditable *editable, gint *end) { GtkEntry *entry = GTK_ENTRY (editable); + GtkEntryPrivate *priv = entry->priv; - *start = entry->selection_bound; - *end = entry->current_pos; + *start = priv->selection_bound; + *end = priv->current_pos; - return (entry->selection_bound != entry->current_pos); + return (priv->selection_bound != priv->current_pos); } static void icon_theme_changed (GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint i; for (i = 0; i < MAX_ICONS; i++) @@ -4025,7 +4459,7 @@ icon_theme_changed (GtkEntry *entry) static void icon_margin_changed (GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; GtkBorder border; _gtk_entry_effective_inner_border (GTK_ENTRY (entry), &border); @@ -4034,14 +4468,12 @@ icon_margin_changed (GtkEntry *entry) } static void -gtk_entry_style_set (GtkWidget *widget, - GtkStyle *previous_style) +gtk_entry_style_updated (GtkWidget *widget) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint focus_width; gboolean interior_focus; - gint i; gtk_widget_style_get (widget, "focus-line-width", &focus_width, @@ -4052,22 +4484,10 @@ gtk_entry_style_set (GtkWidget *widget, priv->interior_focus = interior_focus; if (!priv->invisible_char_set) - entry->invisible_char = find_invisible_char (GTK_WIDGET (entry)); + priv->invisible_char = find_invisible_char (GTK_WIDGET (entry)); gtk_entry_recompute (entry); - if (previous_style && GTK_WIDGET_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)]); - 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)]); - } - } - icon_theme_changed (entry); icon_margin_changed (entry); } @@ -4086,9 +4506,11 @@ gtk_cell_editable_key_press_event (GtkEntry *entry, GdkEventKey *key_event, gpointer data) { - if (key_event->keyval == GDK_Escape) + GtkEntryPrivate *priv = entry->priv; + + if (key_event->keyval == GDK_KEY_Escape) { - entry->editing_canceled = TRUE; + priv->editing_canceled = TRUE; gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); @@ -4096,7 +4518,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)); @@ -4111,7 +4533,10 @@ static void gtk_entry_start_editing (GtkCellEditable *cell_editable, GdkEvent *event) { - GTK_ENTRY (cell_editable)->is_cell_renderer = TRUE; + GtkEntry *entry = GTK_ENTRY (cell_editable); + GtkEntryPrivate *priv = entry->priv; + + priv->is_cell_renderer = TRUE; g_signal_connect (cell_editable, "activate", G_CALLBACK (gtk_cell_editable_entry_activated), NULL); @@ -4122,12 +4547,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 @@ -4136,82 +4573,59 @@ 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() + */ + + gtk_entry_buffer_delete_text (get_buffer (GTK_ENTRY (editable)), start_pos, end_pos - start_pos); +} - g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index); - memcpy (entry->text + index, new_text, new_text_length); +/* GtkEntryBuffer signal handlers + */ +static void +buffer_inserted_text (GtkEntryBuffer *buffer, + guint position, + const gchar *chars, + guint n_chars, + GtkEntry *entry) +{ + GtkEntryPrivate *priv = entry->priv; + guint password_hint_timeout; - entry->n_bytes += new_text_length; - entry->text_length += n_chars; + if (priv->current_pos > position) + priv->current_pos += n_chars; - /* NUL terminate for safety and convenience */ - entry->text[entry->n_bytes] = '\0'; - - if (entry->current_pos > *position) - entry->current_pos += n_chars; - - if (entry->selection_bound > *position) - entry->selection_bound += n_chars; + if (priv->selection_bound > position) + priv->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 && !priv->visible) { - guint password_hint_timeout; - g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)), "gtk-entry-password-hint-timeout", &password_hint_timeout, NULL); @@ -4220,85 +4634,105 @@ 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); + GtkEntryPrivate *priv = entry->priv; + 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; + current_pos = priv->current_pos; + if (current_pos > position) + current_pos -= MIN (current_pos, end_pos) - position; - 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); + selection_bound = priv->selection_bound; + if (selection_bound > position) + selection_bound -= MIN (selection_bound, end_pos) - position; - /* 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; + gtk_entry_set_positions (entry, current_pos, selection_bound); - selection_bound = entry->selection_bound; - if (selection_bound > start_pos) - selection_bound -= MIN (selection_bound, end_pos) - start_pos; + /* We might have deleted the selection */ + gtk_entry_update_primary_selection (entry); - gtk_entry_set_positions (entry, current_pos, selection_bound); + /* Disable the password hint if one exists. */ + if (!priv->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; + } + } +} - /* We might have deleted the selection - */ - gtk_entry_update_primary_selection (entry); - - gtk_entry_recompute (entry); +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"); +} - emit_changed (entry); - g_object_notify (G_OBJECT (editable), "text"); - g_object_notify (G_OBJECT (editable), "text-length"); - } +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 @@ -4310,6 +4744,7 @@ static gint get_better_cursor_x (GtkEntry *entry, gint offset) { + GtkEntryPrivate *priv = entry->priv; GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry))); PangoDirection keymap_direction = gdk_keymap_get_direction (keymap); gboolean split_cursor; @@ -4329,7 +4764,7 @@ get_better_cursor_x (GtkEntry *entry, if (split_cursor) return strong_pos.x / PANGO_SCALE; else - return (keymap_direction == entry->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE; + return (keymap_direction == priv->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE; } static void @@ -4338,11 +4773,12 @@ gtk_entry_move_cursor (GtkEntry *entry, gint count, gboolean extend_selection) { - gint new_pos = entry->current_pos; + GtkEntryPrivate *priv = entry->priv; + gint new_pos = priv->current_pos; _gtk_entry_reset_im_context (entry); - if (entry->current_pos != entry->selection_bound && !extend_selection) + if (priv->current_pos != priv->selection_bound && !extend_selection) { /* If we have a current selection and aren't extending it, move to the * start/or end of the selection as appropriate @@ -4351,26 +4787,26 @@ gtk_entry_move_cursor (GtkEntry *entry, { case GTK_MOVEMENT_VISUAL_POSITIONS: { - gint current_x = get_better_cursor_x (entry, entry->current_pos); - gint bound_x = get_better_cursor_x (entry, entry->selection_bound); + gint current_x = get_better_cursor_x (entry, priv->current_pos); + gint bound_x = get_better_cursor_x (entry, priv->selection_bound); if (count <= 0) - new_pos = current_x < bound_x ? entry->current_pos : entry->selection_bound; + new_pos = current_x < bound_x ? priv->current_pos : priv->selection_bound; else - new_pos = current_x > bound_x ? entry->current_pos : entry->selection_bound; + new_pos = current_x > bound_x ? priv->current_pos : priv->selection_bound; break; } case GTK_MOVEMENT_LOGICAL_POSITIONS: case GTK_MOVEMENT_WORDS: if (count < 0) - new_pos = MIN (entry->current_pos, entry->selection_bound); + new_pos = MIN (priv->current_pos, priv->selection_bound); else - new_pos = MAX (entry->current_pos, entry->selection_bound); + new_pos = MAX (priv->current_pos, priv->selection_bound); break; case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; + new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry)); break; case GTK_MOVEMENT_DISPLAY_LINES: case GTK_MOVEMENT_PARAGRAPHS: @@ -4388,7 +4824,7 @@ gtk_entry_move_cursor (GtkEntry *entry, break; case GTK_MOVEMENT_VISUAL_POSITIONS: new_pos = gtk_entry_move_visually (entry, new_pos, count); - if (entry->current_pos == new_pos) + if (priv->current_pos == new_pos) { if (!extend_selection) { @@ -4421,14 +4857,14 @@ gtk_entry_move_cursor (GtkEntry *entry, new_pos = gtk_entry_move_backward_word (entry, new_pos, FALSE); count++; } - if (entry->current_pos == new_pos) + if (priv->current_pos == new_pos) gtk_widget_error_bell (GTK_WIDGET (entry)); break; case GTK_MOVEMENT_DISPLAY_LINE_ENDS: case GTK_MOVEMENT_PARAGRAPH_ENDS: case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; - if (entry->current_pos == new_pos) + new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry)); + if (priv->current_pos == new_pos) gtk_widget_error_bell (GTK_WIDGET (entry)); break; case GTK_MOVEMENT_DISPLAY_LINES: @@ -4440,7 +4876,7 @@ gtk_entry_move_cursor (GtkEntry *entry, } if (extend_selection) - gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos); + gtk_editable_select_region (GTK_EDITABLE (entry), priv->selection_bound, new_pos); else gtk_editable_set_position (GTK_EDITABLE (entry), new_pos); @@ -4451,10 +4887,11 @@ static void gtk_entry_insert_at_cursor (GtkEntry *entry, const gchar *str) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); - gint pos = entry->current_pos; + gint pos = priv->current_pos; - if (entry->editable) + if (priv->editable) { _gtk_entry_reset_im_context (entry); @@ -4468,20 +4905,21 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, GtkDeleteType type, gint count) { + GtkEntryPrivate *priv = entry->priv; 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 start_pos = priv->current_pos; + gint end_pos = priv->current_pos; + gint old_n_bytes = gtk_entry_buffer_get_bytes (get_buffer (entry)); _gtk_entry_reset_im_context (entry); - if (!entry->editable) + if (!priv->editable) { gtk_widget_error_bell (GTK_WIDGET (entry)); return; } - if (entry->selection_bound != entry->current_pos) + if (priv->selection_bound != priv->current_pos) { gtk_editable_delete_selection (editable); return; @@ -4490,7 +4928,7 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, switch (type) { case GTK_DELETE_CHARS: - end_pos = gtk_entry_move_logically (entry, entry->current_pos, count); + end_pos = gtk_entry_move_logically (entry, priv->current_pos, count); gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos)); break; case GTK_DELETE_WORDS: @@ -4524,9 +4962,9 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, case GTK_DELETE_DISPLAY_LINE_ENDS: case GTK_DELETE_PARAGRAPH_ENDS: if (count < 0) - gtk_editable_delete_text (editable, 0, entry->current_pos); + gtk_editable_delete_text (editable, 0, priv->current_pos); else - gtk_editable_delete_text (editable, entry->current_pos, -1); + gtk_editable_delete_text (editable, priv->current_pos, -1); break; case GTK_DELETE_DISPLAY_LINES: case GTK_DELETE_PARAGRAPHS: @@ -4537,7 +4975,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); @@ -4546,26 +4984,27 @@ gtk_entry_delete_from_cursor (GtkEntry *entry, static void gtk_entry_backspace (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); gint prev_pos; _gtk_entry_reset_im_context (entry); - if (!entry->editable || !entry->text) + if (!priv->editable) { gtk_widget_error_bell (GTK_WIDGET (entry)); return; } - if (entry->selection_bound != entry->current_pos) + if (priv->selection_bound != priv->current_pos) { gtk_editable_delete_selection (editable); return; } - prev_pos = gtk_entry_move_logically (entry, entry->current_pos, -1); + prev_pos = gtk_entry_move_logically (entry, priv->current_pos, -1); - if (prev_pos < entry->current_pos) + if (prev_pos < priv->current_pos) { PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); PangoLogAttr *log_attrs; @@ -4573,25 +5012,24 @@ 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[priv->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, + priv->current_pos); normalized_text = g_utf8_normalize (cluster_text, strlen (cluster_text), G_NORMALIZE_NFD); len = g_utf8_strlen (normalized_text, -1); - gtk_editable_delete_text (editable, prev_pos, entry->current_pos); + gtk_editable_delete_text (editable, prev_pos, priv->current_pos); if (len > 1) { - gint pos = entry->current_pos; + gint pos = priv->current_pos; gtk_editable_insert_text (editable, normalized_text, g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text, @@ -4604,7 +5042,7 @@ gtk_entry_backspace (GtkEntry *entry) } else { - gtk_editable_delete_text (editable, prev_pos, entry->current_pos); + gtk_editable_delete_text (editable, prev_pos, priv->current_pos); } g_free (log_attrs); @@ -4620,19 +5058,20 @@ gtk_entry_backspace (GtkEntry *entry) static void gtk_entry_copy_clipboard (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); gint start, end; gchar *str; if (gtk_editable_get_selection_bounds (editable, &start, &end)) { - if (!entry->visible) + if (!priv->visible) { gtk_widget_error_bell (GTK_WIDGET (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); @@ -4643,10 +5082,11 @@ gtk_entry_copy_clipboard (GtkEntry *entry) static void gtk_entry_cut_clipboard (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); gint start, end; - if (!entry->visible) + if (!priv->visible) { gtk_widget_error_bell (GTK_WIDGET (entry)); return; @@ -4654,7 +5094,7 @@ gtk_entry_cut_clipboard (GtkEntry *entry) gtk_entry_copy_clipboard (entry); - if (entry->editable) + if (priv->editable) { if (gtk_editable_get_selection_bounds (editable, &start, &end)) gtk_editable_delete_text (editable, start, end); @@ -4668,7 +5108,9 @@ gtk_entry_cut_clipboard (GtkEntry *entry) static void gtk_entry_paste_clipboard (GtkEntry *entry) { - if (entry->editable) + GtkEntryPrivate *priv = entry->priv; + + if (priv->editable) gtk_entry_paste (entry, GDK_NONE); else gtk_widget_error_bell (GTK_WIDGET (entry)); @@ -4677,10 +5119,11 @@ gtk_entry_paste_clipboard (GtkEntry *entry) static void gtk_entry_delete_cb (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); gint start, end; - if (entry->editable) + if (priv->editable) { if (gtk_editable_get_selection_bounds (editable, &start, &end)) gtk_editable_delete_text (editable, start, end); @@ -4690,7 +5133,9 @@ gtk_entry_delete_cb (GtkEntry *entry) static void gtk_entry_toggle_overwrite (GtkEntry *entry) { - entry->overwrite_mode = !entry->overwrite_mode; + GtkEntryPrivate *priv = entry->priv; + + priv->overwrite_mode = !priv->overwrite_mode; gtk_entry_pend_cursor_blink (entry); gtk_widget_queue_draw (GTK_WIDGET (entry)); } @@ -4704,24 +5149,29 @@ gtk_entry_select_all (GtkEntry *entry) static void gtk_entry_real_activate (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GtkWindow *window; + GtkWidget *default_widget, *focus_widget; GtkWidget *toplevel; GtkWidget *widget; widget = GTK_WIDGET (entry); - if (entry->activates_default) + if (priv->activates_default) { toplevel = gtk_widget_get_toplevel (widget); 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); + } } } } @@ -4741,7 +5191,9 @@ gtk_entry_commit_cb (GtkIMContext *context, const gchar *str, GtkEntry *entry) { - if (entry->editable) + GtkEntryPrivate *priv = entry->priv; + + if (priv->editable) gtk_entry_enter_text (entry, str); } @@ -4749,17 +5201,20 @@ static void gtk_entry_preedit_changed_cb (GtkIMContext *context, GtkEntry *entry) { - if (entry->editable) + GtkEntryPrivate *priv = entry->priv; + + if (priv->editable) { gchar *preedit_string; gint cursor_pos; - - gtk_im_context_get_preedit_string (entry->im_context, + + gtk_im_context_get_preedit_string (priv->im_context, &preedit_string, NULL, &cursor_pos); - entry->preedit_length = strlen (preedit_string); + g_signal_emit (entry, signals[PREEDIT_CHANGED], 0, preedit_string); + priv->preedit_length = strlen (preedit_string); cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); - entry->preedit_cursor = cursor_pos; + priv->preedit_cursor = cursor_pos; g_free (preedit_string); gtk_entry_recompute (entry); @@ -4768,12 +5223,16 @@ gtk_entry_preedit_changed_cb (GtkIMContext *context, static gboolean gtk_entry_retrieve_surrounding_cb (GtkIMContext *context, - GtkEntry *entry) + 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); + GtkEntryPrivate *priv = entry->priv; + 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, priv->current_pos) - text); + g_free (text); return TRUE; } @@ -4784,10 +5243,12 @@ gtk_entry_delete_surrounding_cb (GtkIMContext *slave, gint n_chars, GtkEntry *entry) { - if (entry->editable) + GtkEntryPrivate *priv = entry->priv; + + if (priv->editable) gtk_editable_delete_text (GTK_EDITABLE (entry), - entry->current_pos + offset, - entry->current_pos + offset + n_chars); + priv->current_pos + offset, + priv->current_pos + offset + n_chars); return TRUE; } @@ -4800,29 +5261,30 @@ static void gtk_entry_enter_text (GtkEntry *entry, const gchar *str) { + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (entry); gint tmp_pos; gboolean old_need_im_reset; - old_need_im_reset = entry->need_im_reset; - entry->need_im_reset = FALSE; + old_need_im_reset = priv->need_im_reset; + priv->need_im_reset = FALSE; if (gtk_editable_get_selection_bounds (editable, NULL, NULL)) gtk_editable_delete_selection (editable); else { - if (entry->overwrite_mode) + if (priv->overwrite_mode) gtk_entry_delete_from_cursor (entry, GTK_DELETE_CHARS, 1); } - tmp_pos = entry->current_pos; + tmp_pos = priv->current_pos; gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos); gtk_editable_set_position (editable, tmp_pos); - entry->need_im_reset = old_need_im_reset; + priv->need_im_reset = old_need_im_reset; } -/* All changes to entry->current_pos and entry->selection_bound +/* All changes to priv->current_pos and priv->selection_bound * should go through this function. */ static void @@ -4830,23 +5292,24 @@ gtk_entry_set_positions (GtkEntry *entry, gint current_pos, gint selection_bound) { + GtkEntryPrivate *priv = entry->priv; gboolean changed = FALSE; g_object_freeze_notify (G_OBJECT (entry)); if (current_pos != -1 && - entry->current_pos != current_pos) + priv->current_pos != current_pos) { - entry->current_pos = current_pos; + priv->current_pos = current_pos; changed = TRUE; g_object_notify (G_OBJECT (entry), "cursor-position"); } if (selection_bound != -1 && - entry->selection_bound != selection_bound) + priv->selection_bound != selection_bound) { - entry->selection_bound = selection_bound; + priv->selection_bound = selection_bound; changed = TRUE; g_object_notify (G_OBJECT (entry), "selection-bound"); @@ -4864,16 +5327,19 @@ gtk_entry_set_positions (GtkEntry *entry, static void gtk_entry_reset_layout (GtkEntry *entry) { - if (entry->cached_layout) + GtkEntryPrivate *priv = entry->priv; + + if (priv->cached_layout) { - g_object_unref (entry->cached_layout); - entry->cached_layout = NULL; + g_object_unref (priv->cached_layout); + priv->cached_layout = NULL; } } static void update_im_cursor_location (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; GdkRectangle area; gint strong_x; gint strong_xoffset; @@ -4882,7 +5348,7 @@ update_im_cursor_location (GtkEntry *entry) gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL); gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height); - strong_xoffset = strong_x - entry->scroll_offset; + strong_xoffset = strong_x - priv->scroll_offset; if (strong_xoffset < 0) { strong_xoffset = 0; @@ -4896,18 +5362,17 @@ update_im_cursor_location (GtkEntry *entry) area.width = 0; area.height = area_height; - gtk_im_context_set_cursor_location (entry->im_context, &area); + gtk_im_context_set_cursor_location (priv->im_context, &area); } static gboolean recompute_idle_func (gpointer data) { - GtkEntry *entry; + GtkEntry *entry = GTK_ENTRY (data); + GtkEntryPrivate *priv = entry->priv; - entry = GTK_ENTRY (data); + priv->recompute_idle = 0; - entry->recompute_idle = 0; - if (gtk_widget_has_screen (GTK_WIDGET (entry))) { gtk_entry_adjust_scroll (entry); @@ -4922,93 +5387,52 @@ recompute_idle_func (gpointer data) static void gtk_entry_recompute (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; + gtk_entry_reset_layout (entry); gtk_entry_check_cursor_blink (entry); - - if (!entry->recompute_idle) - { - entry->recompute_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */ - recompute_idle_func, entry, NULL); - } -} -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) + if (!priv->recompute_idle) { - g_string_append_len (str, buf, char_len); - ++i; + priv->recompute_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */ + recompute_idle_func, entry, NULL); } } -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) { + GtkEntryPrivate *priv = entry->priv; 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, + gtk_im_context_get_preedit_string (priv->im_context, &preedit_string, &preedit_attrs, NULL); - preedit_length = entry->preedit_length; + preedit_length = priv->preedit_length; } if (preedit_length) { - GString *tmp_string = g_string_new (NULL); - - 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; + GString *tmp_string = g_string_new (display); + gint cursor_index = g_utf8_offset_to_pointer (display, priv->current_pos) - display; - 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); @@ -5021,15 +5445,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); @@ -5050,79 +5473,16 @@ gtk_entry_create_layout (GtkEntry *entry, pango_context_set_base_dir (gtk_widget_get_pango_context (widget), 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); - } + priv->resolved_dir = pango_dir; - 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); @@ -5135,17 +5495,19 @@ static PangoLayout * gtk_entry_ensure_layout (GtkEntry *entry, gboolean include_preedit) { - if (entry->preedit_length > 0 && - !include_preedit != !entry->cache_includes_preedit) + GtkEntryPrivate *priv = entry->priv; + + if (priv->preedit_length > 0 && + !include_preedit != !priv->cache_includes_preedit) gtk_entry_reset_layout (entry); - if (!entry->cached_layout) + if (!priv->cached_layout) { - entry->cached_layout = gtk_entry_create_layout (entry, include_preedit); - entry->cache_includes_preedit = include_preedit; + priv->cached_layout = gtk_entry_create_layout (entry, include_preedit); + priv->cache_includes_preedit = include_preedit; } - - return entry->cached_layout; + + return priv->cached_layout; } static void @@ -5153,6 +5515,7 @@ get_layout_position (GtkEntry *entry, gint *x, gint *y) { + GtkEntryPrivate *priv = entry->priv; PangoLayout *layout; PangoRectangle logical_rect; gint area_width, area_height; @@ -5171,9 +5534,9 @@ get_layout_position (GtkEntry *entry, pango_layout_line_get_extents (line, NULL, &logical_rect); /* Align primarily for locale's ascent/descent */ - y_pos = ((area_height - entry->ascent - entry->descent) / 2 + - entry->ascent + logical_rect.y); - + y_pos = ((area_height - priv->ascent - priv->descent) / 2 + + priv->ascent + logical_rect.y); + /* Now see if we need to adjust to fit in actual drawn string */ if (logical_rect.height > area_height) y_pos = (area_height - logical_rect.height) / 2; @@ -5185,86 +5548,162 @@ get_layout_position (GtkEntry *entry, y_pos = inner_border.top + y_pos / PANGO_SCALE; if (x) - *x = inner_border.left - entry->scroll_offset; + *x = inner_border.left - priv->scroll_offset; if (y) *y = y_pos; } static void -gtk_entry_draw_text (GtkEntry *entry) +draw_text_with_color (GtkEntry *entry, + cairo_t *cr, + GdkRGBA *default_color) { + GtkEntryPrivate *priv = entry->priv; + PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE); GtkWidget *widget; - - if (!entry->visible && entry->invisible_char == 0) - return; - - if (GTK_WIDGET_DRAWABLE (entry)) + gint x, y; + gint start_pos, end_pos; + + widget = GTK_WIDGET (entry); + + cairo_save (cr); + + get_layout_position (entry, &x, &y); + + cairo_move_to (cr, x, y); + gdk_cairo_set_source_rgba (cr, default_color); + pango_cairo_show_layout (cr, layout); + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos)) { - PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE); - cairo_t *cr; - gint x, y; - gint start_pos, end_pos; - - widget = GTK_WIDGET (entry); - - get_layout_position (entry, &x, &y); + gint *ranges; + gint n_ranges, i; + PangoRectangle logical_rect; + GdkRGBA selection_color, text_color; + GtkBorder inner_border; + GtkStyleContext *context; + GtkStateFlags state; + + context = gtk_widget_get_style_context (widget); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); + + state = GTK_STATE_FLAG_SELECTED; - cr = gdk_cairo_create (entry->text_area); + if (gtk_widget_has_focus (widget)) + state |= GTK_STATE_FLAG_FOCUSED; + + gtk_style_context_get_background_color (context, state, &selection_color); + gtk_style_context_get_color (context, state, &text_color); + + _gtk_entry_effective_inner_border (entry, &inner_border); + + for (i = 0; i < n_ranges; ++i) + cairo_rectangle (cr, + inner_border.left - priv->scroll_offset + ranges[2 * i], + y, + ranges[2 * i + 1], + logical_rect.height); + + cairo_clip (cr); + + gdk_cairo_set_source_rgba (cr, &selection_color); + cairo_paint (cr); cairo_move_to (cr, x, y); - gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]); + gdk_cairo_set_source_rgba (cr, &text_color); pango_cairo_show_layout (cr, layout); + + g_free (ranges); + } + cairo_restore (cr); +} - if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos)) - { - gint *ranges; - gint n_ranges, i; - PangoRectangle logical_rect; - GdkColor *selection_color, *text_color; - GtkBorder inner_border; +static void +gtk_entry_draw_text (GtkEntry *entry, + cairo_t *cr) +{ + GtkEntryPrivate *priv = entry->priv; + GtkWidget *widget = GTK_WIDGET (entry); + GtkStateFlags state = 0; + GdkRGBA text_color, bar_text_color; + GtkStyleContext *context; + gint pos_x, pos_y; + gint width, height; + gint progress_x, progress_y, progress_width, progress_height; + gint clip_width, clip_height; - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); + /* Nothing to display at all */ + if (gtk_entry_get_display_mode (entry) == DISPLAY_BLANK) + return; - if (GTK_WIDGET_HAS_FOCUS (entry)) - { - selection_color = &widget->style->base [GTK_STATE_SELECTED]; - text_color = &widget->style->text [GTK_STATE_SELECTED]; - } - else - { - selection_color = &widget->style->base [GTK_STATE_ACTIVE]; - text_color = &widget->style->text [GTK_STATE_ACTIVE]; - } + state = gtk_widget_get_state_flags (widget); + context = gtk_widget_get_style_context (widget); - _gtk_entry_effective_inner_border (entry, &inner_border); + gtk_style_context_get_color (context, state, &text_color); - for (i = 0; i < n_ranges; ++i) - cairo_rectangle (cr, - inner_border.left - entry->scroll_offset + ranges[2 * i], - y, - ranges[2 * i + 1], - logical_rect.height); + /* Get foreground color for progressbars */ + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR); + gtk_style_context_get_color (context, state, &bar_text_color); + gtk_style_context_restore (context); - cairo_clip (cr); - - gdk_cairo_set_source_color (cr, selection_color); - cairo_paint (cr); + get_progress_area (widget, + &progress_x, &progress_y, + &progress_width, &progress_height); - cairo_move_to (cr, x, y); - gdk_cairo_set_source_color (cr, text_color); - pango_cairo_show_layout (cr, layout); - - g_free (ranges); - } + clip_width = gdk_window_get_width (priv->text_area); + clip_height = gdk_window_get_height (priv->text_area); + cairo_rectangle (cr, 0, 0, clip_width, clip_height); + cairo_clip (cr); - cairo_destroy (cr); + /* If the color is the same, or the progress area has a zero + * size, then we only need to draw once. */ + if (gdk_rgba_equal (&text_color, &bar_text_color) || + ((progress_width == 0) || (progress_height == 0))) + { + draw_text_with_color (entry, cr, &text_color); + } + else + { + width = gdk_window_get_width (priv->text_area); + height = gdk_window_get_height (priv->text_area); + + 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); + + gdk_window_get_position (priv->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); + + draw_text_with_color (entry, cr, &bar_text_color); + + cairo_restore (cr); } } static void draw_insertion_cursor (GtkEntry *entry, + cairo_t *cr, GdkRectangle *cursor_location, gboolean is_primary, PangoDirection direction, @@ -5278,155 +5717,222 @@ 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) { + GtkEntryPrivate *priv = entry->priv; + 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; + 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); + _gtk_entry_effective_inner_border (entry, &inner_border); - xoffset = inner_border.left - entry->scroll_offset; + xoffset = inner_border.left - priv->scroll_offset; - gdk_drawable_get_size (entry->text_area, NULL, &text_area_height); + text_area_height = gdk_window_get_height (priv->text_area); - 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); + layout = gtk_entry_ensure_layout (entry, TRUE); + text = pango_layout_get_text (layout); + cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos + priv->preedit_cursor) - text; + if (!priv->overwrite_mode) + block = FALSE; + else + block = _gtk_text_util_get_block_cursor_location (layout, + cursor_index, &cursor_rect, &block_at_line_end); - if (!block) - { - gint strong_x, weak_x; - PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; - PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; - gint x1 = 0; - gint x2 = 0; + if (!block) + { + gint strong_x, weak_x; + PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; + PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; + gint x1 = 0; + gint x2 = 0; - gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); + gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); - g_object_get (gtk_widget_get_settings (widget), - "gtk-split-cursor", &split_cursor, - NULL); + g_object_get (gtk_widget_get_settings (widget), + "gtk-split-cursor", &split_cursor, + NULL); - dir1 = entry->resolved_dir; - - if (split_cursor) - { - x1 = strong_x; + dir1 = priv->resolved_dir; + + if (split_cursor) + { + x1 = strong_x; - if (weak_x != strong_x) - { - dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; - x2 = weak_x; - } - } - else + if (weak_x != strong_x) { - if (keymap_direction == entry->resolved_dir) - x1 = strong_x; - else - x1 = weak_x; + dir2 = (priv->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; + x2 = weak_x; } + } + else + { + if (keymap_direction == priv->resolved_dir) + x1 = strong_x; + else + x1 = weak_x; + } - 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; + 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; - draw_insertion_cursor (entry, - &cursor_location, TRUE, dir1, - dir2 != PANGO_DIRECTION_NEUTRAL); - - if (dir2 != PANGO_DIRECTION_NEUTRAL) - { - cursor_location.x = xoffset + x2; - draw_insertion_cursor (entry, - &cursor_location, FALSE, dir2, - TRUE); - } - } - else /* overwrite_mode */ + draw_insertion_cursor (entry, cr, + &cursor_location, TRUE, dir1, + dir2 != PANGO_DIRECTION_NEUTRAL); + + if (dir2 != PANGO_DIRECTION_NEUTRAL) { - GdkColor cursor_color; - GdkRectangle rect; - cairo_t *cr; - gint x, y; + 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; - get_layout_position (entry, &x, &y); + cairo_save (cr); - 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); + get_layout_position (entry, &x, &y); - cr = gdk_cairo_create (entry->text_area); + 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); + _gtk_widget_get_cursor_color (widget, &cursor_color); + gdk_cairo_set_source_color (cr, &cursor_color); + gdk_cairo_rectangle (cr, &rect); + cairo_fill (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, &widget->style->base[widget->state]); - pango_cairo_show_layout (cr, layout); - } + if (!block_at_line_end) + { + GtkStyleContext *context; + GtkStateFlags state; + GdkRGBA color; - cairo_destroy (cr); + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_background_color (context, state, &color); + + gdk_cairo_rectangle (cr, &rect); + cairo_clip (cr); + cairo_move_to (cr, x, y); + gdk_cairo_set_source_rgba (cr, &color); + pango_cairo_show_layout (cr, layout); } + + cairo_restore (cr); } } static void gtk_entry_queue_draw (GtkEntry *entry) { - if (GTK_WIDGET_DRAWABLE (entry)) - gdk_window_invalidate_rect (entry->text_area, NULL, FALSE); + if (gtk_widget_is_drawable (GTK_WIDGET (entry))) + gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (entry)), + NULL, FALSE); } void _gtk_entry_reset_im_context (GtkEntry *entry) { - if (entry->need_im_reset) + GtkEntryPrivate *priv = entry->priv; + + if (priv->need_im_reset) { - entry->need_im_reset = FALSE; - gtk_im_context_reset (entry->im_context); + priv->need_im_reset = FALSE; + gtk_im_context_reset (priv->im_context); } } +/** + * 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) +{ + GtkEntryPrivate *priv; + + g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); + + priv = entry->priv; + + return gtk_im_context_filter_keypress (priv->im_context, event); +} + +GtkIMContext* +_gtk_entry_get_im_context (GtkEntry *entry) +{ + return entry->priv->im_context; +} + static gint gtk_entry_find_position (GtkEntry *entry, gint x) { + GtkEntryPrivate *priv = entry->priv; PangoLayout *layout; PangoLayoutLine *line; gint index; @@ -5437,15 +5943,15 @@ gtk_entry_find_position (GtkEntry *entry, layout = gtk_entry_ensure_layout (entry, TRUE); text = pango_layout_get_text (layout); - cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text; - + cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos) - text; + line = pango_layout_get_lines_readonly (layout)->data; pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing); - if (index >= cursor_index && entry->preedit_length) + if (index >= cursor_index && priv->preedit_length) { - if (index >= cursor_index + entry->preedit_length) - index -= entry->preedit_length; + if (index >= cursor_index + priv->preedit_length) + index -= priv->preedit_length; else { index = cursor_index; @@ -5465,7 +5971,11 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, gint *strong_x, gint *weak_x) { - if (!entry->visible && !entry->invisible_char) + GtkEntryPrivate *priv = entry->priv; + 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; @@ -5482,20 +5992,20 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, if (type == CURSOR_STANDARD) { - index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text; + index = g_utf8_offset_to_pointer (text, priv->current_pos + priv->preedit_cursor) - text; } else /* type == CURSOR_DND */ { - index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text; + index = g_utf8_offset_to_pointer (text, priv->dnd_position) - text; - if (entry->dnd_position > entry->current_pos) + if (priv->dnd_position > priv->current_pos) { - if (entry->visible) - index += entry->preedit_length; + if (mode == DISPLAY_NORMAL) + index += priv->preedit_length; else { - gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length; - index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL); + 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 (priv->invisible_char, NULL); } } } @@ -5513,7 +6023,7 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, static void gtk_entry_adjust_scroll (GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; gint min_offset, max_offset; gint text_area_width, text_width; GtkBorder inner_border; @@ -5524,12 +6034,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 (priv->text_area); text_area_width -= inner_border.left + inner_border.right; if (text_area_width < 0) text_area_width = 0; @@ -5541,7 +6051,7 @@ gtk_entry_adjust_scroll (GtkEntry *entry) /* Display as much text as we can */ - if (entry->resolved_dir == PANGO_DIRECTION_LTR) + if (priv->resolved_dir == PANGO_DIRECTION_LTR) xalign = priv->xalign; else xalign = 1.0 - priv->xalign; @@ -5559,7 +6069,7 @@ gtk_entry_adjust_scroll (GtkEntry *entry) max_offset = min_offset; } - entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset); + priv->scroll_offset = CLAMP (priv->scroll_offset, min_offset, max_offset); /* And make sure cursors are on screen. Note that the cursor is * actually drawn one pixel into the INNER_BORDER space on @@ -5577,29 +6087,29 @@ gtk_entry_adjust_scroll (GtkEntry *entry) gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x); - strong_xoffset = strong_x - entry->scroll_offset; + strong_xoffset = strong_x - priv->scroll_offset; if (strong_xoffset < 0) { - entry->scroll_offset += strong_xoffset; + priv->scroll_offset += strong_xoffset; strong_xoffset = 0; } else if (strong_xoffset > text_area_width) { - entry->scroll_offset += strong_xoffset - text_area_width; + priv->scroll_offset += strong_xoffset - text_area_width; strong_xoffset = text_area_width; } - weak_xoffset = weak_x - entry->scroll_offset; + weak_xoffset = weak_x - priv->scroll_offset; if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width) { - entry->scroll_offset += weak_xoffset; + priv->scroll_offset += weak_xoffset; } else if (weak_xoffset > text_area_width && strong_xoffset - (weak_xoffset - text_area_width) >= 0) { - entry->scroll_offset += weak_xoffset - text_area_width; + priv->scroll_offset += weak_xoffset - text_area_width; } g_object_notify (G_OBJECT (entry), "scroll-offset"); @@ -5608,26 +6118,35 @@ gtk_entry_adjust_scroll (GtkEntry *entry) static void gtk_entry_move_adjustments (GtkEntry *entry) { + GtkWidget *widget = GTK_WIDGET (entry); + GtkAllocation allocation; + GtkAdjustment *adjustment; PangoContext *context; PangoFontMetrics *metrics; + GtkStyleContext *style_context; + GtkStateFlags state; 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 (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, + context = gtk_widget_get_pango_context (widget); + style_context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + + metrics = pango_context_get_metrics (context, + gtk_style_context_get_font (style_context, state), pango_context_get_language (context)); char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE; @@ -5642,6 +6161,7 @@ gtk_entry_move_visually (GtkEntry *entry, gint start, gint count) { + GtkEntryPrivate *priv = entry->priv; gint index; PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); const gchar *text; @@ -5667,7 +6187,7 @@ gtk_entry_move_visually (GtkEntry *entry, GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry))); PangoDirection keymap_direction = gdk_keymap_get_direction (keymap); - strong = keymap_direction == entry->resolved_dir; + strong = keymap_direction == priv->resolved_dir; } if (count > 0) @@ -5699,13 +6219,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; @@ -5713,11 +6236,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--; } @@ -5742,13 +6265,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; @@ -5777,11 +6303,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; @@ -5805,6 +6331,7 @@ gtk_entry_move_backward_word (GtkEntry *entry, static void gtk_entry_delete_whitespace (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE); PangoLogAttr *log_attrs; gint n_attrs; @@ -5812,7 +6339,7 @@ gtk_entry_delete_whitespace (GtkEntry *entry) pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); - start = end = entry->current_pos; + start = end = priv->current_pos; while (start > 0 && log_attrs[start-1].is_white) start--; @@ -5830,8 +6357,9 @@ gtk_entry_delete_whitespace (GtkEntry *entry) static void gtk_entry_select_word (GtkEntry *entry) { - gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos, TRUE); - gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos, TRUE); + GtkEntryPrivate *priv = entry->priv; + gint start_pos = gtk_entry_move_backward_word (entry, priv->current_pos, TRUE); + gint end_pos = gtk_entry_move_forward_word (entry, priv->current_pos, TRUE); gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos); } @@ -5842,30 +6370,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) { @@ -5885,9 +6389,9 @@ paste_received (GtkClipboard *clipboard, { GtkEntry *entry = GTK_ENTRY (data); GtkEditable *editable = GTK_EDITABLE (entry); - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); - - if (entry->button == 2) + GtkEntryPrivate *priv = entry->priv; + + if (priv->button == 2) { gint pos, start, end; pos = priv->insert_pos; @@ -5905,15 +6409,16 @@ paste_received (GtkClipboard *clipboard, completion = gtk_entry_get_completion (entry); - if (entry->truncate_multiline) + if (priv->truncate_multiline) 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 (priv->current_pos, priv->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) @@ -5925,7 +6430,7 @@ paste_received (GtkClipboard *clipboard, if (gtk_editable_get_selection_bounds (editable, &start, &end)) gtk_editable_delete_text (editable, start, end); - pos = entry->current_pos; + pos = priv->current_pos; gtk_editable_insert_text (editable, text, length, &pos); gtk_editable_set_position (editable, pos); g_object_thaw_notify (G_OBJECT (entry)); @@ -5959,7 +6464,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); } @@ -5970,8 +6475,9 @@ primary_clear_cb (GtkClipboard *clipboard, gpointer data) { GtkEntry *entry = GTK_ENTRY (data); + GtkEntryPrivate *priv = entry->priv; - gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos); + gtk_editable_select_region (GTK_EDITABLE (entry), priv->current_pos, priv->current_pos); } static void @@ -5983,7 +6489,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); @@ -6013,7 +6519,7 @@ static void gtk_entry_clear (GtkEntry *entry, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; if (!icon_info || icon_info->storage_type == GTK_IMAGE_EMPTY) @@ -6037,21 +6543,21 @@ gtk_entry_clear (GtkEntry *entry, { case GTK_IMAGE_PIXBUF: g_object_notify (G_OBJECT (entry), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "pixbuf-primary" : "pixbuf-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-pixbuf" : "secondary-icon-pixbuf"); break; case GTK_IMAGE_STOCK: g_free (icon_info->stock_id); icon_info->stock_id = NULL; g_object_notify (G_OBJECT (entry), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "stock-primary" : "stock-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-stock" : "secondary-icon-stock"); break; case GTK_IMAGE_ICON_NAME: g_free (icon_info->icon_name); icon_info->icon_name = NULL; g_object_notify (G_OBJECT (entry), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "icon-name-primary" : "icon-name-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-name" : "secondary-icon-name"); break; case GTK_IMAGE_GICON: @@ -6061,7 +6567,7 @@ gtk_entry_clear (GtkEntry *entry, icon_info->gicon = NULL; } g_object_notify (G_OBJECT (entry), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "gicon-primary" : "gicon-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-gicon" : "secondary-icon-gicon"); break; default: @@ -6071,7 +6577,7 @@ gtk_entry_clear (GtkEntry *entry, icon_info->storage_type = GTK_IMAGE_EMPTY; g_object_notify (G_OBJECT (entry), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "storage-type-primary" : "storage-type-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-storage-type" : "secondary-icon-storage-type"); g_object_thaw_notify (G_OBJECT (entry)); } @@ -6080,36 +6586,46 @@ static void gtk_entry_ensure_pixbuf (GtkEntry *entry, GtkEntryIconPosition icon_pos) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; - GdkScreen *screen; + GtkIconInfo *info; GtkIconTheme *icon_theme; GtkSettings *settings; + GtkStateFlags state; + GtkWidget *widget; + GdkScreen *screen; gint width, height; - GtkIconInfo *info; 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: - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), - icon_info->stock_id, - GTK_ICON_SIZE_MENU, - NULL); + state = gtk_widget_get_state_flags (widget); + gtk_widget_set_state_flags (widget, 0, TRUE); + icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget, + icon_info->stock_id, + GTK_ICON_SIZE_MENU); + if (!icon_info->pixbuf) + icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget, + GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_MENU); + gtk_widget_set_state_flags (widget, state, TRUE); 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); settings = gtk_settings_get_for_screen (screen); - + gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height); @@ -6120,15 +6636,19 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, 0, NULL); if (icon_info->pixbuf == NULL) - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), - GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_MENU, - NULL); + { + state = gtk_widget_get_state_flags (widget); + gtk_widget_set_state_flags (widget, 0, TRUE); + icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget, + GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_MENU); + gtk_widget_set_state_flags (widget, state, TRUE); + } } 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); @@ -6149,10 +6669,14 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, } if (icon_info->pixbuf == NULL) - icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), - GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_MENU, - NULL); + { + state = gtk_widget_get_state_flags (widget); + gtk_widget_set_state_flags (widget, 0, TRUE); + icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget, + GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_MENU); + gtk_widget_set_state_flags (widget, state, TRUE); + } } break; @@ -6160,9 +6684,9 @@ gtk_entry_ensure_pixbuf (GtkEntry *entry, g_assert_not_reached (); break; } - - if (GDK_IS_WINDOW (icon_info->window)) - gdk_window_show (icon_info->window); + + if (icon_info->pixbuf != NULL && icon_info->window != NULL) + gdk_window_show_unraised (icon_info->window); } @@ -6183,136 +6707,197 @@ 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 = entry->priv; - 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); - tmp_pos = entry->text_length; - gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos); + priv = entry->priv; + + 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_area: * @entry: a #GtkEntry - * @text: the text to prepend + * @text_area: (out): Return location for the text area. * - * Prepends the given text to the contents of the widget. + * Gets the area where the entry's text is drawn. This function is + * useful when drawing something to the entry in a draw callback. * - * Deprecated: 2.0: Use gtk_editable_insert_text() instead. - */ + * If the entry is not realized, @text_area is filled with zeros. + * + * See also gtk_entry_get_icon_area(). + * + * Since: 3.0 + **/ void -gtk_entry_prepend_text (GtkEntry *entry, - const gchar *text) +gtk_entry_get_text_area (GtkEntry *entry, + GdkRectangle *text_area) { - gint tmp_pos; + GtkEntryPrivate *priv; g_return_if_fail (GTK_IS_ENTRY (entry)); - g_return_if_fail (text != NULL); + g_return_if_fail (text_area != NULL); - tmp_pos = 0; - gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos); + priv = entry->priv; + + if (priv->text_area) + { + GtkAllocation allocation; + gint x, y; + + gtk_widget_get_allocation (GTK_WIDGET (entry), &allocation); + gdk_window_get_position (priv->text_area, &x, &y); + + text_area->x = x - allocation.x; + text_area->y = y - allocation.y; + text_area->width = gdk_window_get_width (priv->text_area); + text_area->height = gdk_window_get_height (priv->text_area); + } + else + { + text_area->x = 0; + text_area->y = 0; + text_area->width = 0; + text_area->height = 0; + } } /** - * 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; + 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 (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); - gtk_editable_set_position (GTK_EDITABLE (entry), position); + if (completion && completion->priv->changed_id > 0) + g_signal_handler_unblock (entry, completion->priv->changed_id); } /** @@ -6334,13 +6919,17 @@ void gtk_entry_set_visibility (GtkEntry *entry, gboolean visible) { + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); + priv = entry->priv; + visible = visible != FALSE; - if (entry->visible != visible) + if (priv->visible != visible) { - entry->visible = visible; + priv->visible = visible; g_object_notify (G_OBJECT (entry), "visibility"); gtk_entry_recompute (entry); @@ -6361,7 +6950,7 @@ gtk_entry_get_visibility (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); - return entry->visible; + return entry->priv->visible; } /** @@ -6385,7 +6974,7 @@ gtk_entry_set_invisible_char (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if (!priv->invisible_char_set) { @@ -6393,10 +6982,10 @@ gtk_entry_set_invisible_char (GtkEntry *entry, g_object_notify (G_OBJECT (entry), "invisible-char-set"); } - if (ch == entry->invisible_char) + if (ch == priv->invisible_char) return; - entry->invisible_char = ch; + priv->invisible_char = ch; g_object_notify (G_OBJECT (entry), "invisible-char"); gtk_entry_recompute (entry); } @@ -6416,7 +7005,7 @@ gtk_entry_get_invisible_char (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); - return entry->invisible_char; + return entry->priv->invisible_char; } /** @@ -6437,7 +7026,7 @@ gtk_entry_unset_invisible_char (GtkEntry *entry) g_return_if_fail (GTK_IS_ENTRY (entry)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if (!priv->invisible_char_set) return; @@ -6445,9 +7034,9 @@ gtk_entry_unset_invisible_char (GtkEntry *entry) priv->invisible_char_set = FALSE; ch = find_invisible_char (GTK_WIDGET (entry)); - if (entry->invisible_char != ch) + if (priv->invisible_char != ch) { - entry->invisible_char = ch; + priv->invisible_char = ch; g_object_notify (G_OBJECT (entry), "invisible-char"); } @@ -6455,26 +7044,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 @@ -6488,9 +7057,11 @@ void gtk_entry_set_overwrite_mode (GtkEntry *entry, gboolean overwrite) { + GtkEntryPrivate *priv = entry->priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); - - if (entry->overwrite_mode == overwrite) + + if (priv->overwrite_mode == overwrite) return; gtk_entry_toggle_overwrite (entry); @@ -6513,7 +7084,7 @@ gtk_entry_get_overwrite_mode (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); - return entry->overwrite_mode; + return entry->priv->overwrite_mode; } /** @@ -6523,6 +7094,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 @@ -6533,29 +7110,7 @@ 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)); } /** @@ -6568,20 +7123,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); } /** @@ -6591,6 +7145,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. **/ @@ -6599,7 +7159,7 @@ 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)); } /** @@ -6609,6 +7169,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. * @@ -6619,7 +7185,7 @@ 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)); } /** @@ -6640,12 +7206,17 @@ void gtk_entry_set_activates_default (GtkEntry *entry, gboolean setting) { + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); + + priv = entry->priv; + setting = setting != FALSE; - if (setting != entry->activates_default) + if (setting != priv->activates_default) { - entry->activates_default = setting; + priv->activates_default = setting; g_object_notify (G_OBJECT (entry), "activates-default"); } } @@ -6663,7 +7234,7 @@ gtk_entry_get_activates_default (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); - return entry->activates_default; + return entry->priv->activates_default; } /** @@ -6681,11 +7252,15 @@ void gtk_entry_set_width_chars (GtkEntry *entry, gint n_chars) { + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); - if (entry->width_chars != n_chars) + priv = entry->priv; + + if (priv->width_chars != n_chars) { - entry->width_chars = n_chars; + priv->width_chars = n_chars; g_object_notify (G_OBJECT (entry), "width-chars"); gtk_widget_queue_resize (GTK_WIDGET (entry)); } @@ -6704,7 +7279,7 @@ gtk_entry_get_width_chars (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); - return entry->width_chars; + return entry->priv->width_chars; } /** @@ -6718,15 +7293,19 @@ void gtk_entry_set_has_frame (GtkEntry *entry, gboolean setting) { + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); + priv = entry->priv; + setting = (setting != FALSE); - if (entry->has_frame == setting) + if (priv->has_frame == setting) return; gtk_widget_queue_resize (GTK_WIDGET (entry)); - entry->has_frame = setting; + priv->has_frame = setting; g_object_notify (G_OBJECT (entry), "has-frame"); } @@ -6743,13 +7322,13 @@ gtk_entry_get_has_frame (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); - return entry->has_frame; + return entry->priv->has_frame; } /** * 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 @@ -6787,7 +7366,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 **/ @@ -6813,8 +7392,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) @@ -6845,20 +7424,23 @@ gint gtk_entry_layout_index_to_text_index (GtkEntry *entry, gint layout_index) { + GtkEntryPrivate *priv; PangoLayout *layout; const gchar *text; gint cursor_index; g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); + priv = entry->priv; + layout = gtk_entry_ensure_layout (entry, TRUE); text = pango_layout_get_text (layout); - cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text; - - if (layout_index >= cursor_index && entry->preedit_length) + cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos) - text; + + if (layout_index >= cursor_index && priv->preedit_length) { - if (layout_index >= cursor_index + entry->preedit_length) - layout_index -= entry->preedit_length; + if (layout_index >= cursor_index + priv->preedit_length) + layout_index -= priv->preedit_length; else layout_index = cursor_index; } @@ -6881,17 +7463,21 @@ gint gtk_entry_text_index_to_layout_index (GtkEntry *entry, gint text_index) { + GtkEntryPrivate *priv; PangoLayout *layout; const gchar *text; gint cursor_index; + g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); + priv = entry->priv; + layout = gtk_entry_ensure_layout (entry, TRUE); text = pango_layout_get_text (layout); - cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text; - + cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos) - text; + if (text_index > cursor_index) - text_index += entry->preedit_length; + text_index += priv->preedit_length; return text_index; } @@ -6899,8 +7485,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: (out) (allow-none): location to store X offset of layout, or %NULL + * @y: (out) (allow-none): location to store Y offset of layout, or %NULL * * * Obtains the position of the #PangoLayout used to render text @@ -6962,10 +7548,10 @@ void gtk_entry_set_alignment (GtkEntry *entry, gfloat xalign) { GtkEntryPrivate *priv; - + g_return_if_fail (GTK_IS_ENTRY (entry)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if (xalign < 0.0) xalign = 0.0; @@ -6995,20 +7581,16 @@ gtk_entry_set_alignment (GtkEntry *entry, gfloat xalign) gfloat gtk_entry_get_alignment (GtkEntry *entry) { - GtkEntryPrivate *priv; - g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0); - priv = GTK_ENTRY_GET_PRIVATE (entry); - - return priv->xalign; + return entry->priv->xalign; } /** * 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. * @@ -7027,7 +7609,7 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); @@ -7046,19 +7628,22 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { - g_object_notify (G_OBJECT (entry), "pixbuf-primary"); - g_object_notify (G_OBJECT (entry), "storage-type-primary"); + g_object_notify (G_OBJECT (entry), "primary-icon-pixbuf"); + g_object_notify (G_OBJECT (entry), "primary-icon-storage-type"); } else { - g_object_notify (G_OBJECT (entry), "pixbuf-secondary"); - g_object_notify (G_OBJECT (entry), "storage-type-secondary"); + 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)); @@ -7068,7 +7653,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. @@ -7089,15 +7674,13 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); g_object_freeze_notify (G_OBJECT (entry)); - gtk_widget_ensure_style (GTK_WIDGET (entry)); - /* need to dup before clearing */ new_id = g_strdup (stock_id); @@ -7110,19 +7693,22 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { - g_object_notify (G_OBJECT (entry), "stock-primary"); - g_object_notify (G_OBJECT (entry), "storage-type-primary"); + g_object_notify (G_OBJECT (entry), "primary-icon-stock"); + g_object_notify (G_OBJECT (entry), "primary-icon-storage-type"); } else { - g_object_notify (G_OBJECT (entry), "stock-secondary"); - g_object_notify (G_OBJECT (entry), "storage-type-secondary"); + 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)); @@ -7132,7 +7718,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. @@ -7156,15 +7742,13 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); g_object_freeze_notify (G_OBJECT (entry)); - gtk_widget_ensure_style (GTK_WIDGET (entry)); - /* need to dup before clearing */ new_name = g_strdup (icon_name); @@ -7177,19 +7761,22 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { - g_object_notify (G_OBJECT (entry), "icon-name-primary"); - g_object_notify (G_OBJECT (entry), "storage-type-primary"); + g_object_notify (G_OBJECT (entry), "primary-icon-name"); + g_object_notify (G_OBJECT (entry), "primary-icon-storage-type"); } else { - g_object_notify (G_OBJECT (entry), "icon-name-secondary"); - g_object_notify (G_OBJECT (entry), "storage-type-secondary"); + 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)); @@ -7199,7 +7786,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. @@ -7221,7 +7808,7 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); @@ -7241,19 +7828,22 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry, if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { - g_object_notify (G_OBJECT (entry), "gicon-primary"); - g_object_notify (G_OBJECT (entry), "storage-type-primary"); + g_object_notify (G_OBJECT (entry), "primary-icon-gicon"); + g_object_notify (G_OBJECT (entry), "primary-icon-storage-type"); } else { - g_object_notify (G_OBJECT (entry), "gicon-secondary"); - g_object_notify (G_OBJECT (entry), "storage-type-secondary"); + 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)); @@ -7280,7 +7870,7 @@ gtk_entry_set_icon_activatable (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); @@ -7291,11 +7881,11 @@ 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), - icon_pos == GTK_ENTRY_ICON_PRIMARY ? "activatable-primary" : "activatable-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-activatable" : "secondary-icon-activatable"); } } @@ -7320,14 +7910,14 @@ gtk_entry_get_icon_activatable (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), FALSE); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; icon_info = priv->icons[icon_pos]; - return (icon_info != NULL && !icon_info->nonactivatable); + return (!icon_info || !icon_info->nonactivatable); } /** - * gtk_entry_get_pixbuf: + * gtk_entry_get_icon_pixbuf: * @entry: A #GtkEntry * @icon_pos: Icon position * @@ -7337,13 +7927,14 @@ 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 */ GdkPixbuf * -gtk_entry_get_pixbuf (GtkEntry *entry, - GtkEntryIconPosition icon_pos) +gtk_entry_get_icon_pixbuf (GtkEntry *entry, + GtkEntryIconPosition icon_pos) { GtkEntryPrivate *priv; EntryIconInfo *icon_info; @@ -7351,7 +7942,8 @@ gtk_entry_get_pixbuf (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; + icon_info = priv->icons[icon_pos]; if (!icon_info) @@ -7363,7 +7955,7 @@ gtk_entry_get_pixbuf (GtkEntry *entry, } /** - * gtk_entry_get_gicon: + * gtk_entry_get_icon_gicon: * @entry: A #GtkEntry * @icon_pos: Icon position * @@ -7371,14 +7963,14 @@ gtk_entry_get_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 */ GIcon * -gtk_entry_get_gicon (GtkEntry *entry, - GtkEntryIconPosition icon_pos) +gtk_entry_get_icon_gicon (GtkEntry *entry, + GtkEntryIconPosition icon_pos) { GtkEntryPrivate *priv; EntryIconInfo *icon_info; @@ -7386,7 +7978,7 @@ gtk_entry_get_gicon (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; icon_info = priv->icons[icon_pos]; if (!icon_info) @@ -7396,7 +7988,7 @@ gtk_entry_get_gicon (GtkEntry *entry, } /** - * gtk_entry_get_stock: + * gtk_entry_get_icon_stock: * @entry: A #GtkEntry * @icon_pos: Icon position * @@ -7410,8 +8002,8 @@ gtk_entry_get_gicon (GtkEntry *entry, * Since: 2.16 */ const gchar * -gtk_entry_get_stock (GtkEntry *entry, - GtkEntryIconPosition icon_pos) +gtk_entry_get_icon_stock (GtkEntry *entry, + GtkEntryIconPosition icon_pos) { GtkEntryPrivate *priv; EntryIconInfo *icon_info; @@ -7419,7 +8011,7 @@ gtk_entry_get_stock (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; icon_info = priv->icons[icon_pos]; if (!icon_info) @@ -7452,7 +8044,7 @@ gtk_entry_get_icon_name (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; icon_info = priv->icons[icon_pos]; if (!icon_info) @@ -7483,7 +8075,7 @@ gtk_entry_set_icon_sensitive (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); @@ -7492,11 +8084,16 @@ 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 ? "sensitive-primary" : "sensitive-secondary"); + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-sensitive" : "secondary-icon-sensitive"); } } @@ -7521,14 +8118,16 @@ gtk_entry_get_icon_sensitive (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), TRUE); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), TRUE); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; + icon_info = priv->icons[icon_pos]; - return (icon_info != NULL && !icon_info->insensitive); + return (!icon_info || !icon_info->insensitive); + } /** - * gtk_entry_get_storage_type: + * gtk_entry_get_icon_storage_type: * @entry: a #GtkEntry * @icon_pos: Icon position * @@ -7541,8 +8140,8 @@ gtk_entry_get_icon_sensitive (GtkEntry *entry, * Since: 2.16 **/ GtkImageType -gtk_entry_get_storage_type (GtkEntry *entry, - GtkEntryIconPosition icon_pos) +gtk_entry_get_icon_storage_type (GtkEntry *entry, + GtkEntryIconPosition icon_pos) { GtkEntryPrivate *priv; EntryIconInfo *icon_info; @@ -7550,7 +8149,8 @@ gtk_entry_get_storage_type (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_IMAGE_EMPTY); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), GTK_IMAGE_EMPTY); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; + icon_info = priv->icons[icon_pos]; if (!icon_info) @@ -7581,9 +8181,14 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry, { GtkAllocation primary; GtkAllocation secondary; + gint frame_x, frame_y; g_return_val_if_fail (GTK_IS_ENTRY (entry), -1); + get_frame_size (entry, &frame_x, &frame_y, NULL, NULL); + x -= frame_x; + y -= frame_y; + get_icon_allocations (entry, &primary, &secondary); if (primary.x <= x && x < primary.x + primary.width && @@ -7609,9 +8214,16 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry, * * To handle the drag operation, you need to connect to the usual * #GtkWidget::drag-data-get (or possibly #GtkWidget::drag-data-delete) - * signal, and use gtk_icon_entry_get_current_icon_drag_source() in + * signal, and use gtk_entry_get_current_icon_drag_source() in * your signal handler to find out if the drag was started from * an icon. + * + * By default, GTK+ uses the icon as the drag icon. You can use the + * #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, @@ -7625,7 +8237,7 @@ gtk_entry_set_icon_drag_source (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if ((icon_info = priv->icons[icon_pos]) == NULL) icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); @@ -7651,6 +8263,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) @@ -7661,7 +8275,7 @@ gtk_entry_get_current_icon_drag_source (GtkEntry *entry) g_return_val_if_fail (GTK_IS_ENTRY (entry), -1); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { @@ -7675,6 +8289,59 @@ gtk_entry_get_current_icon_drag_source (GtkEntry *entry) return -1; } +/** + * gtk_entry_get_icon_area: + * @entry: A #GtkEntry + * @icon_pos: Icon position + * @icon_area: (out): Return location for the icon's area + * + * Gets the area where entry's icon at @icon_pos is drawn. + * This function is useful when drawing something to the + * entry in a draw callback. + * + * If the entry is not realized or has no icon at the given position, + * @icon_area is filled with zeros. + * + * See also gtk_entry_get_text_area() + * + * Since: 3.0 + */ +void +gtk_entry_get_icon_area (GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkRectangle *icon_area) +{ + GtkEntryPrivate *priv; + EntryIconInfo *icon_info; + + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (icon_area != NULL); + + priv = entry->priv; + + icon_info = priv->icons[icon_pos]; + + if (icon_info) + { + GtkAllocation primary; + GtkAllocation secondary; + + get_icon_allocations (entry, &primary, &secondary); + + if (icon_pos == GTK_ENTRY_ICON_PRIMARY) + *icon_area = primary; + else + *icon_area = secondary; + } + else + { + icon_area->x = 0; + icon_area->y = 0; + icon_area->width = 0; + icon_area->height = 0; + } +} + static void ensure_has_tooltip (GtkEntry *entry) { @@ -7683,7 +8350,7 @@ ensure_has_tooltip (GtkEntry *entry) int i; gboolean has_tooltip = FALSE; - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { @@ -7700,11 +8367,49 @@ ensure_has_tooltip (GtkEntry *entry) gtk_widget_set_has_tooltip (GTK_WIDGET (entry), has_tooltip); } +/** + * gtk_entry_get_icon_tooltip_text: + * @entry: a #GtkEntry + * @icon_pos: the icon position + * + * Gets the contents of the tooltip on the icon at the specified + * position in @entry. + * + * Returns: the tooltip text, or %NULL. Free the returned string + * with g_free() when done. + * + * Since: 2.16 + */ +gchar * +gtk_entry_get_icon_tooltip_text (GtkEntry *entry, + GtkEntryIconPosition icon_pos) +{ + GtkEntryPrivate *priv; + EntryIconInfo *icon_info; + gchar *text = NULL; + + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); + + priv = entry->priv; + + icon_info = priv->icons[icon_pos]; + + if (!icon_info) + return NULL; + + if (icon_info->tooltip && + !pango_parse_markup (icon_info->tooltip, -1, 0, NULL, &text, NULL, NULL)) + g_assert (NULL == text); /* text should still be NULL in case of markup errors */ + + return text; +} + /** * 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. @@ -7727,24 +8432,63 @@ gtk_entry_set_icon_tooltip_text (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; - if (!(icon_info = priv->icons[icon_pos])) - icon_info = priv->icons[icon_pos]; + if ((icon_info = priv->icons[icon_pos]) == NULL) + icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); if (icon_info->tooltip) g_free (icon_info->tooltip); + /* Treat an empty string as a NULL string, + * because an empty string would be useless for a tooltip: + */ + if (tooltip && tooltip[0] == '\0') + tooltip = NULL; + icon_info->tooltip = tooltip ? g_markup_escape_text (tooltip, -1) : NULL; ensure_has_tooltip (entry); } +/** + * gtk_entry_get_icon_tooltip_markup: + * @entry: a #GtkEntry + * @icon_pos: the icon position + * + * Gets the contents of the tooltip on the icon at the specified + * position in @entry. + * + * Returns: the tooltip text, or %NULL. Free the returned string + * with g_free() when done. + * + * Since: 2.16 + */ +gchar * +gtk_entry_get_icon_tooltip_markup (GtkEntry *entry, + GtkEntryIconPosition icon_pos) +{ + GtkEntryPrivate *priv; + EntryIconInfo *icon_info; + + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); + + priv = entry->priv; + + icon_info = priv->icons[icon_pos]; + + if (!icon_info) + return NULL; + + return g_strdup (icon_info->tooltip); +} + /** * 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 @@ -7768,14 +8512,20 @@ gtk_entry_set_icon_tooltip_markup (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos)); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; - if (!(icon_info = priv->icons[icon_pos])) - icon_info = priv->icons[icon_pos]; + if ((icon_info = priv->icons[icon_pos]) == NULL) + icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos); if (icon_info->tooltip) g_free (icon_info->tooltip); + /* Treat an empty string as a NULL string, + * because an empty string would be useless for a tooltip: + */ + if (tooltip && tooltip[0] == '\0') + tooltip = NULL; + icon_info->tooltip = g_strdup (tooltip); ensure_has_tooltip (entry); @@ -7794,7 +8544,7 @@ gtk_entry_query_tooltip (GtkWidget *widget, gint icon_pos; entry = GTK_ENTRY (widget); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; if (!keyboard_tip) { @@ -7863,7 +8613,10 @@ static void popup_menu_detach (GtkWidget *attach_widget, GtkMenu *menu) { - GTK_ENTRY (attach_widget)->popup_menu = NULL; + GtkEntry *entry_attach = GTK_ENTRY (attach_widget); + GtkEntryPrivate *priv_attach = entry_attach->priv; + + priv_attach->popup_menu = NULL; } static void @@ -7874,6 +8627,7 @@ popup_position_func (GtkMenu *menu, gpointer user_data) { GtkEntry *entry = GTK_ENTRY (user_data); + GtkEntryPrivate *priv = entry->priv; GtkWidget *widget = GTK_WIDGET (entry); GdkScreen *screen; GtkRequisition menu_req; @@ -7881,23 +8635,24 @@ 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); + gdk_window_get_origin (priv->text_area, x, y); screen = gtk_widget_get_screen (widget); - monitor_num = gdk_screen_get_monitor_at_window (screen, entry->text_area); + monitor_num = gdk_screen_get_monitor_at_window (screen, priv->text_area); if (monitor_num < 0) monitor_num = 0; 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 (priv->popup_menu, + &menu_req, NULL); + height = gdk_window_get_height (priv->text_area); gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL); _gtk_entry_effective_inner_border (entry, &inner_border); - *x += inner_border.left + strong_x - entry->scroll_offset; + *x += inner_border.left + strong_x - priv->scroll_offset; if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) *x -= menu_req.width; @@ -7918,8 +8673,9 @@ unichar_chosen_func (const char *text, gpointer data) { GtkEntry *entry = GTK_ENTRY (data); + GtkEntryPrivate *priv = entry->priv; - if (entry->editable) + if (priv->editable) gtk_entry_enter_text (entry, text); } @@ -7937,9 +8693,11 @@ popup_targets_received (GtkClipboard *clipboard, { PopupInfo *info = user_data; GtkEntry *entry = info->entry; - - if (GTK_WIDGET_REALIZED (entry)) + GtkEntryPrivate *info_entry_priv = entry->priv; + + if (gtk_widget_get_realized (GTK_WIDGET (entry))) { + DisplayMode mode; gboolean clipboard_contains_text; GtkWidget *menuitem; GtkWidget *submenu; @@ -7947,38 +8705,43 @@ popup_targets_received (GtkClipboard *clipboard, gboolean show_unicode_menu; clipboard_contains_text = gtk_selection_data_targets_include_text (data); - if (entry->popup_menu) - gtk_widget_destroy (entry->popup_menu); - - entry->popup_menu = gtk_menu_new (); - - gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu), + if (info_entry_priv->popup_menu) + gtk_widget_destroy (info_entry_priv->popup_menu); + + info_entry_priv->popup_menu = gtk_menu_new (); + + gtk_menu_attach_to_widget (GTK_MENU (info_entry_priv->popup_menu), GTK_WIDGET (entry), popup_menu_detach); - append_action_signal (entry, entry->popup_menu, GTK_STOCK_CUT, "cut-clipboard", - entry->editable && entry->visible && 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); - append_action_signal (entry, entry->popup_menu, GTK_STOCK_PASTE, "paste-clipboard", - entry->editable && clipboard_contains_text); - + mode = gtk_entry_get_display_mode (entry); + append_action_signal (entry, info_entry_priv->popup_menu, GTK_STOCK_CUT, "cut-clipboard", + info_entry_priv->editable && mode == DISPLAY_NORMAL && + info_entry_priv->current_pos != info_entry_priv->selection_bound); + + append_action_signal (entry, info_entry_priv->popup_menu, GTK_STOCK_COPY, "copy-clipboard", + mode == DISPLAY_NORMAL && + info_entry_priv->current_pos != info_entry_priv->selection_bound); + + append_action_signal (entry, info_entry_priv->popup_menu, GTK_STOCK_PASTE, "paste-clipboard", + info_entry_priv->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); + gtk_widget_set_sensitive (menuitem, info_entry_priv->editable && info_entry_priv->current_pos != info_entry_priv->selection_bound); g_signal_connect_swapped (menuitem, "activate", G_CALLBACK (gtk_entry_delete_cb), entry); gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); menuitem = gtk_separator_menu_item_new (); gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL); g_signal_connect_swapped (menuitem, "activate", G_CALLBACK (gtk_entry_select_all), entry); gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)), "gtk-show-input-method-menu", &show_input_method_menu, @@ -7989,33 +8752,33 @@ popup_targets_received (GtkClipboard *clipboard, { menuitem = gtk_separator_menu_item_new (); gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); } if (show_input_method_menu) { menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods")); - gtk_widget_set_sensitive (menuitem, entry->editable); + gtk_widget_set_sensitive (menuitem, info_entry_priv->editable); gtk_widget_show (menuitem); submenu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); - - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); - - gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context), + + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); + + gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (info_entry_priv->im_context), GTK_MENU_SHELL (submenu)); } if (show_unicode_menu) { menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character")); - gtk_widget_set_sensitive (menuitem, entry->editable); + gtk_widget_set_sensitive (menuitem, info_entry_priv->editable); gtk_widget_show (menuitem); submenu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); - gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem); - + gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem); + _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu), unichar_chosen_func, entry); @@ -8024,19 +8787,19 @@ popup_targets_received (GtkClipboard *clipboard, g_signal_emit (entry, signals[POPULATE_POPUP], 0, - entry->popup_menu); - + info_entry_priv->popup_menu); + if (info->button) - gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL, + gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL, NULL, NULL, info->button, info->time); else { - gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL, + gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL, popup_position_func, entry, info->button, info->time); - gtk_menu_shell_select_first (GTK_MENU_SHELL (entry->popup_menu), FALSE); + gtk_menu_shell_select_first (GTK_MENU_SHELL (info_entry_priv->popup_menu), FALSE); } } @@ -8084,7 +8847,8 @@ static void gtk_entry_drag_begin (GtkWidget *widget, GdkDragContext *context) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; gint i; for (i = 0; i < MAX_ICONS; i++) @@ -8122,7 +8886,8 @@ static void gtk_entry_drag_end (GtkWidget *widget, GdkDragContext *context) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; gint i; for (i = 0; i < MAX_ICONS; i++) @@ -8140,8 +8905,9 @@ gtk_entry_drag_leave (GtkWidget *widget, guint time) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; - entry->dnd_position = -1; + priv->dnd_position = -1; gtk_widget_queue_draw (widget); } @@ -8153,9 +8919,10 @@ gtk_entry_drag_drop (GtkWidget *widget, guint time) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; GdkAtom target = GDK_NONE; - - if (entry->editable) + + if (priv->editable) target = gtk_drag_dest_find_target (widget, context, NULL); if (target != GDK_NONE) @@ -8174,22 +8941,27 @@ gtk_entry_drag_motion (GtkWidget *widget, guint time) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + GtkStyleContext *style_context; GtkWidget *source_widget; GdkDragAction suggested_action; gint new_position, old_position; gint sel1, sel2; - - x -= widget->style->xthickness; - y -= widget->style->ythickness; - - old_position = entry->dnd_position; - new_position = gtk_entry_find_position (entry, x + entry->scroll_offset); + GtkBorder padding; - if (entry->editable && + style_context = gtk_widget_get_style_context (widget); + gtk_style_context_get_padding (style_context, 0, &padding); + x -= padding.left; + y -= padding.top; + + old_position = priv->dnd_position; + new_position = gtk_entry_find_position (entry, x + priv->scroll_offset); + + if (priv->editable && gtk_drag_dest_find_target (widget, context, NULL) != GDK_NONE) { source_widget = gtk_drag_get_source_widget (context); - suggested_action = context->suggested_action; + suggested_action = gdk_drag_context_get_suggested_action (context); if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) || new_position < sel1 || new_position > sel2) @@ -8199,30 +8971,30 @@ gtk_entry_drag_motion (GtkWidget *widget, /* Default to MOVE, unless the user has * pressed ctrl or alt to affect available actions */ - if ((context->actions & GDK_ACTION_MOVE) != 0) + if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0) suggested_action = GDK_ACTION_MOVE; } - - entry->dnd_position = new_position; + + priv->dnd_position = new_position; } else { if (source_widget == widget) suggested_action = 0; /* Can't drop in selection where drag started */ - - entry->dnd_position = -1; + + priv->dnd_position = -1; } } else { /* Entry not editable, or no text */ suggested_action = 0; - entry->dnd_position = -1; + priv->dnd_position = -1; } gdk_drag_status (context, suggested_action, time); - - if (entry->dnd_position != old_position) + + if (priv->dnd_position != old_position) gtk_widget_queue_draw (widget); return TRUE; @@ -8238,24 +9010,29 @@ gtk_entry_drag_data_received (GtkWidget *widget, guint time) { GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; GtkEditable *editable = GTK_EDITABLE (widget); + GtkStyleContext *style_context; + GtkBorder padding; gchar *str; str = (gchar *) gtk_selection_data_get_text (selection_data); - x -= widget->style->xthickness; - y -= widget->style->ythickness; + style_context = gtk_widget_get_style_context (widget); + gtk_style_context_get_padding (style_context, 0, &padding); + x -= padding.left; + y -= padding.top; - if (str && entry->editable) + if (str && priv->editable) { gint new_position; gint sel1, sel2; gint length = -1; - if (entry->truncate_multiline) + if (priv->truncate_multiline) length = truncate_multiline (str); - new_position = gtk_entry_find_position (entry, x + entry->scroll_offset); + new_position = gtk_entry_find_position (entry, x + priv->scroll_offset); if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) || new_position < sel1 || new_position > sel2) @@ -8273,7 +9050,7 @@ gtk_entry_drag_data_received (GtkWidget *widget, end_change (entry); } - gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, time); + gtk_drag_finish (context, TRUE, gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE, time); } else { @@ -8291,12 +9068,12 @@ gtk_entry_drag_data_get (GtkWidget *widget, guint info, guint time) { + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + GtkEditable *editable = GTK_EDITABLE (widget); gint sel_start, sel_end; gint i; - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); - GtkEditable *editable = GTK_EDITABLE (widget); - /* If there is an icon drag going on, exit early. */ for (i = 0; i < MAX_ICONS; i++) { @@ -8311,7 +9088,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); @@ -8324,12 +9101,12 @@ static void gtk_entry_drag_data_delete (GtkWidget *widget, GdkDragContext *context) { + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + GtkEditable *editable = GTK_EDITABLE (widget); gint sel_start, sel_end; gint i; - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget); - GtkEditable *editable = GTK_EDITABLE (widget); - /* If there is an icon drag going on, exit early. */ for (i = 0; i < MAX_ICONS; i++) { @@ -8341,8 +9118,8 @@ gtk_entry_drag_data_delete (GtkWidget *widget, return; } } - - if (GTK_ENTRY (widget)->editable && + + if (priv->editable && gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end)) gtk_editable_delete_text (editable, sel_start, sel_end); } @@ -8361,9 +9138,11 @@ gtk_entry_drag_data_delete (GtkWidget *widget, static gboolean cursor_blinks (GtkEntry *entry) { - if (GTK_WIDGET_HAS_FOCUS (entry) && - entry->editable && - entry->selection_bound == entry->current_pos) + GtkEntryPrivate *priv = entry->priv; + + if (gtk_widget_has_focus (GTK_WIDGET (entry)) && + priv->editable && + priv->selection_bound == priv->current_pos) { GtkSettings *settings; gboolean blink; @@ -8402,24 +9181,32 @@ get_cursor_blink_timeout (GtkEntry *entry) static void show_cursor (GtkEntry *entry) { - if (!entry->cursor_visible) + GtkEntryPrivate *priv = entry->priv; + GtkWidget *widget; + + if (!priv->cursor_visible) { - entry->cursor_visible = TRUE; + priv->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) && priv->selection_bound == priv->current_pos) + gtk_widget_queue_draw (widget); } } static void hide_cursor (GtkEntry *entry) { - if (entry->cursor_visible) + GtkEntryPrivate *priv = entry->priv; + GtkWidget *widget; + + if (priv->cursor_visible) { - entry->cursor_visible = FALSE; + priv->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) && priv->selection_bound == priv->current_pos) + gtk_widget_queue_draw (widget); } } @@ -8434,9 +9221,9 @@ blink_cb (gpointer data) gint blink_timeout; entry = GTK_ENTRY (data); - priv = GTK_ENTRY_GET_PRIVATE (entry); + priv = entry->priv; - 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" @@ -8447,7 +9234,7 @@ blink_cb (gpointer data) return FALSE; } - g_assert (entry->selection_bound == entry->current_pos); + g_assert (priv->selection_bound == priv->current_pos); blink_timeout = get_cursor_blink_timeout (entry); if (priv->blink_time > 1000 * blink_timeout && @@ -8455,12 +9242,12 @@ blink_cb (gpointer data) { /* we've blinked enough without the user doing anything, stop blinking */ show_cursor (entry); - entry->blink_timeout = 0; + priv->blink_timeout = 0; } - else if (entry->cursor_visible) + else if (priv->cursor_visible) { hide_cursor (entry); - entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER, + priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER, blink_cb, entry); } @@ -8468,7 +9255,7 @@ blink_cb (gpointer data) { show_cursor (entry); priv->blink_time += get_cursor_time (entry); - entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, + priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, blink_cb, entry); } @@ -8480,44 +9267,43 @@ blink_cb (gpointer data) static void gtk_entry_check_cursor_blink (GtkEntry *entry) { - GtkEntryPrivate *priv; - - priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; if (cursor_blinks (entry)) { - if (!entry->blink_timeout) + if (!priv->blink_timeout) { show_cursor (entry); - entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, + priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, blink_cb, entry); } } else { - if (entry->blink_timeout) - { - g_source_remove (entry->blink_timeout); - entry->blink_timeout = 0; + if (priv->blink_timeout) + { + g_source_remove (priv->blink_timeout); + priv->blink_timeout = 0; } - - entry->cursor_visible = TRUE; + + priv->cursor_visible = TRUE; } - } static void gtk_entry_pend_cursor_blink (GtkEntry *entry) { + GtkEntryPrivate *priv = entry->priv; + if (cursor_blinks (entry)) { - if (entry->blink_timeout != 0) - g_source_remove (entry->blink_timeout); - - entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER, - blink_cb, - entry); + if (priv->blink_timeout != 0) + g_source_remove (priv->blink_timeout); + + priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER, + blink_cb, + entry); show_cursor (entry); } } @@ -8525,10 +9311,8 @@ gtk_entry_pend_cursor_blink (GtkEntry *entry) static void gtk_entry_reset_blink_time (GtkEntry *entry) { - GtkEntryPrivate *priv; - - priv = GTK_ENTRY_GET_PRIVATE (entry); - + GtkEntryPrivate *priv = entry->priv; + priv->blink_time = 0; } @@ -8538,6 +9322,7 @@ static gint gtk_entry_completion_timeout (gpointer data) { GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data); + GtkEntryPrivate *completion_entry_priv = GTK_ENTRY (completion->priv->entry)->priv; completion->priv->completion_timeout = 0; @@ -8564,15 +9349,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, completion_entry_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; @@ -8581,16 +9366,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; @@ -8604,7 +9389,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); @@ -8616,21 +9401,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; @@ -8649,7 +9434,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; @@ -8696,6 +9481,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, { GtkTreeIter iter; + GtkTreeIter child_iter; GtkTreeModel *model = NULL; GtkTreeSelection *sel; gboolean entry_set; @@ -8703,12 +9489,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) @@ -8732,11 +9521,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; @@ -8751,7 +9540,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), @@ -8762,9 +9551,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); @@ -8779,11 +9568,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)); @@ -8796,10 +9585,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)); @@ -8807,9 +9599,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)); @@ -8841,15 +9630,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); @@ -8862,27 +9654,38 @@ keypress_completion_out: } static void -gtk_entry_completion_changed (GtkWidget *entry, +gtk_entry_completion_changed (GtkWidget *widget, gpointer user_data) { GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data); + GtkEntry *entry = GTK_ENTRY (widget); + GtkEntryPrivate *priv = entry->priv; + GdkDevice *device; /* (re)install completion timeout */ if (completion->priv->completion_timeout) g_source_remove (completion->priv->completion_timeout); - if (!gtk_entry_get_text (GTK_ENTRY (entry))) + if (!gtk_entry_get_text (entry)) return; /* no need to normalize for this test */ if (completion->priv->minimum_key_length > 0 && - strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))) == 0) + strcmp ("", gtk_entry_get_text (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 && gdk_device_get_source (device) == 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, @@ -8920,7 +9723,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; } @@ -9020,7 +9823,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 @@ -9051,7 +9854,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); @@ -9080,7 +9883,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 */ @@ -9137,9 +9941,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* @@ -9165,26 +9969,38 @@ void gtk_entry_set_progress_fraction (GtkEntry *entry, gdouble fraction) { + GtkWidget *widget; GtkEntryPrivate *private; gdouble old_fraction; + gint x, y, width, height; + gint old_x, old_y, old_width, old_height; g_return_if_fail (GTK_IS_ENTRY (entry)); - private = GTK_ENTRY_GET_PRIVATE (entry); + widget = GTK_WIDGET (entry); + private = entry->priv; if (private->progress_pulse_mode) old_fraction = -1; else old_fraction = private->progress_fraction; + 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); private->progress_fraction = fraction; private->progress_pulse_mode = FALSE; private->progress_pulse_current = 0.0; - if (fabs (fraction - old_fraction) > 0.0001) - gtk_entry_queue_draw (entry); + if (gtk_widget_is_drawable (widget)) + { + 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 (widget); + } if (fraction != old_fraction) g_object_notify (G_OBJECT (entry), "progress-fraction"); @@ -9204,13 +10020,9 @@ gtk_entry_set_progress_fraction (GtkEntry *entry, gdouble gtk_entry_get_progress_fraction (GtkEntry *entry) { - GtkEntryPrivate *private; - g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0); - private = GTK_ENTRY_GET_PRIVATE (entry); - - return private->progress_fraction; + return entry->priv->progress_fraction; } /** @@ -9231,7 +10043,7 @@ gtk_entry_set_progress_pulse_step (GtkEntry *entry, g_return_if_fail (GTK_IS_ENTRY (entry)); - private = GTK_ENTRY_GET_PRIVATE (entry); + private = entry->priv; fraction = CLAMP (fraction, 0.0, 1.0); @@ -9239,7 +10051,7 @@ gtk_entry_set_progress_pulse_step (GtkEntry *entry, { private->progress_pulse_fraction = fraction; - gtk_entry_queue_draw (entry); + gtk_widget_queue_draw (GTK_WIDGET (entry)); g_object_notify (G_OBJECT (entry), "progress-pulse-step"); } @@ -9258,13 +10070,9 @@ gtk_entry_set_progress_pulse_step (GtkEntry *entry, gdouble gtk_entry_get_progress_pulse_step (GtkEntry *entry) { - GtkEntryPrivate *private; - g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0); - private = GTK_ENTRY_GET_PRIVATE (entry); - - return private->progress_pulse_fraction; + return entry->priv->progress_pulse_fraction; } /** @@ -9287,7 +10095,7 @@ gtk_entry_progress_pulse (GtkEntry *entry) g_return_if_fail (GTK_IS_ENTRY (entry)); - private = GTK_ENTRY_GET_PRIVATE (entry); + private = entry->priv; if (private->progress_pulse_mode) { @@ -9320,7 +10128,7 @@ gtk_entry_progress_pulse (GtkEntry *entry) private->progress_pulse_current = 0.0; } - gtk_entry_queue_draw (entry); + gtk_widget_queue_draw (GTK_WIDGET (entry)); } /* Caps Lock warning for password entries */ @@ -9329,11 +10137,11 @@ static void show_capslock_feedback (GtkEntry *entry, const gchar *text) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; - if (gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY) + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY) { - gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_INFO); + gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CAPS_LOCK_WARNING); gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE); priv->caps_lock_warning_shown = TRUE; } @@ -9347,7 +10155,7 @@ show_capslock_feedback (GtkEntry *entry, static void remove_capslock_feedback (GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; if (priv->caps_lock_warning_shown) { @@ -9360,22 +10168,18 @@ static void keymap_state_changed (GdkKeymap *keymap, GtkEntry *entry) { - GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry); + GtkEntryPrivate *priv = entry->priv; char *text = NULL; - if (!entry->visible && priv->caps_lock_warning) + if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL && priv->caps_lock_warning) { - gboolean capslock_on; - gboolean im_on; - - capslock_on = gdk_keymap_get_caps_lock_state (keymap); - im_on = g_strcmp0 (gtk_im_multicontext_get_context_id (GTK_IM_MULTICONTEXT (entry->im_context)), "gtk-im-context-simple") != 0; - if (capslock_on && im_on) - text = _("You have the Caps Lock key on\nand an active input method"); - else if (capslock_on) - text = _("You have the Caps Lock key on"); - else if (im_on) - text = _("You have an active input method"); + 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"); } if (text) @@ -9384,5 +10188,20 @@ keymap_state_changed (GdkKeymap *keymap, remove_capslock_feedback (entry); } -#define __GTK_ENTRY_C__ -#include "gtkaliasdef.c" +/* + * _gtk_entry_set_is_cell_renderer: + * @entry: a #GtkEntry + * @is_cell_renderer: new value + * + * This is a helper function for GtkComboBox. A GtkEntry in a GtkComboBox + * is supposed to behave like a GtkCellEditable when placed in a combo box. + * + * I.e take up it's allocation and get GtkEntry->is_cell_renderer = TRUE. + * + */ +void +_gtk_entry_set_is_cell_renderer (GtkEntry *entry, + gboolean is_cell_renderer) +{ + entry->priv->is_cell_renderer = is_cell_renderer; +}