X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkentry.c;h=db83f058d46e8f60d7e5bbbd2532f77fc5f32f8f;hb=f30eab099bdc4044738c6df77fa6088abc666961;hp=a7c73d60f56970c59797e08129286ce127be0942;hpb=fd9aac8225564c3eb9993f9c4bdb0074d4bab2ef;p=~andy%2Fgtk diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index a7c73d60f..db83f058d 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -16,9 +16,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -33,13 +31,13 @@ #include #include -#include "gtkalignment.h" #include "gtkbindings.h" #include "gtkcelleditable.h" #include "gtkclipboard.h" #include "gtkdnd.h" #include "gtkentry.h" #include "gtkentrybuffer.h" +#include "gtkiconhelperprivate.h" #include "gtkimagemenuitem.h" #include "gtkimcontextsimple.h" #include "gtkimmulticontext.h" @@ -68,6 +66,8 @@ #include "gtkwidgetprivate.h" #include "gtkstylecontextprivate.h" +#include "a11y/gtkentryaccessible.h" + /** * SECTION:gtkentry * @Short_description: A single line text entry field @@ -118,6 +118,7 @@ #define DRAW_TIMEOUT 20 #define COMPLETION_TIMEOUT 300 #define PASSWORD_HINT_MAX 8 +#define PAGE_STEP 14 #define MAX_ICONS 2 @@ -144,6 +145,8 @@ struct _GtkEntryPrivate GtkShadowType shadow_type; GtkWidget *popup_menu; + GdkDevice *device; + GdkDevice *completion_device; GdkWindow *text_area; @@ -166,7 +169,6 @@ struct _GtkEntryPrivate gint drag_start_x; gint drag_start_y; gint focus_width; - gint icon_margin; gint insert_pos; gint selection_bound; gint scroll_offset; @@ -225,11 +227,7 @@ struct _EntryIconInfo guint in_drag : 1; guint pressed : 1; - GtkImageType storage_type; - GdkPixbuf *pixbuf; - gchar *stock_id; - gchar *icon_name; - GIcon *gicon; + GtkIconHelper *icon_helper; GtkTargetList *target_list; GdkDragAction actions; @@ -549,6 +547,8 @@ 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_grab_notify (GtkWidget *widget, + gboolean was_grabbed); 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); @@ -569,9 +569,10 @@ static void get_frame_size (GtkEntry *entry, gint *width, gint *height); static void gtk_entry_move_adjustments (GtkEntry *entry); -static void gtk_entry_ensure_pixbuf (GtkEntry *entry, +static GdkPixbuf * gtk_entry_ensure_pixbuf (GtkEntry *entry, GtkEntryIconPosition icon_pos); - +static void gtk_entry_update_cached_style_values(GtkEntry *entry); +static gboolean get_middle_click_paste (GtkEntry *entry); /* Completion */ static gint gtk_entry_completion_timeout (gpointer data); @@ -693,6 +694,7 @@ gtk_entry_class_init (GtkEntryClass *class) 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; + widget_class->grab_notify = gtk_entry_grab_notify; widget_class->drag_drop = gtk_entry_drag_drop; widget_class->drag_motion = gtk_entry_drag_motion; @@ -784,13 +786,23 @@ gtk_entry_class_init (GtkEntryClass *class) TRUE, GTK_PARAM_READWRITE)); + /** + * GtkEntry:inner-border: + * + * Sets the text area's border between the text and the frame. + * + * Deprecated: 3.4: Use the standard border and padding CSS properties + * (through objects like #GtkStyleContext and #GtkCssProvider); the value + * of this style property is ignored. + */ g_object_class_install_property (gobject_class, PROP_INNER_BORDER, g_param_spec_boxed ("inner-border", P_("Inner Border"), P_("Border between text and frame. Overrides the inner-border style property"), GTK_TYPE_BORDER, - GTK_PARAM_READWRITE)); + GTK_PARAM_READWRITE | + G_PARAM_DEPRECATED)); g_object_class_install_property (gobject_class, PROP_INVISIBLE_CHAR, @@ -932,7 +944,7 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READWRITE)); /** - * GtkEntry:caps-lock-warning + * GtkEntry:caps-lock-warning: * * Whether password entries will show a warning when Caps Lock is on. * @@ -988,7 +1000,8 @@ gtk_entry_class_init (GtkEntryClass *class) /** * GtkEntry:placeholder-text: * - * The text that will be displayed in the #GtkEntry when it is empty and unfocused. + * The text that will be displayed in the #GtkEntry when it is empty + * and unfocused. * * Since: 3.2 */ @@ -1367,20 +1380,25 @@ gtk_entry_class_init (GtkEntryClass *class) * The border around the progress bar in the entry. * * Since: 2.16 + * + * Deprecated: 3.4: Use the standard margin CSS property (through objects + * like #GtkStyleContext and #GtkCssProvider); the value of this style + * property is ignored. */ 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)); + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); /** * 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 + * #GtkEntry:invisible-char property, GTK+ determines the character * to use from a list of possible candidates, depending on availability * in the current font. * @@ -1423,12 +1441,13 @@ gtk_entry_class_init (GtkEntryClass *class) * GtkEntry::activate: * @entry: The entry on which the signal is emitted * - * A keybinding signal - * 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 activation - * programmatically. + * The ::activate signal is emitted when the user hits + * the Enter key. + * + * While this signal is used as a + * keybinding signal, + * it is also commonly used by applications to intercept + * activation of entries. * * The default bindings for this signal are all forms of the Enter key. */ @@ -1859,15 +1878,22 @@ gtk_entry_class_init (GtkEntryClass *class) * Sets the text area's border between the text and the frame. * * Since: 2.10 + * + * Deprecated: 3.4: Use the standard border and padding CSS properties + * (through objects like #GtkStyleContext and #GtkCssProvider); the value + * of this style property is ignored. */ gtk_widget_class_install_style_property (widget_class, g_param_spec_boxed ("inner-border", P_("Inner Border"), P_("Border between text and frame."), GTK_TYPE_BORDER, - GTK_PARAM_READABLE)); + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE); } static void @@ -1890,6 +1916,27 @@ gtk_entry_cell_editable_init (GtkCellEditableIface *iface) iface->start_editing = gtk_entry_start_editing; } +/* for deprecated properties */ +static void +gtk_entry_do_set_inner_border (GtkEntry *entry, + const GtkBorder *border) +{ + if (border) + g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border, + gtk_border_copy (border), + (GDestroyNotify) gtk_border_free); + else + g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL); + + g_object_notify (G_OBJECT (entry), "inner-border"); +} + +static const GtkBorder * +gtk_entry_do_get_inner_border (GtkEntry *entry) +{ + return g_object_get_qdata (G_OBJECT (entry), quark_inner_border); +} + static void gtk_entry_set_property (GObject *object, guint prop_id, @@ -1946,7 +1993,7 @@ gtk_entry_set_property (GObject *object, break; case PROP_INNER_BORDER: - gtk_entry_set_inner_border (entry, g_value_get_boxed (value)); + gtk_entry_do_set_inner_border (entry, g_value_get_boxed (value)); break; case PROP_INVISIBLE_CHAR: @@ -2163,7 +2210,7 @@ gtk_entry_get_property (GObject *object, break; case PROP_INNER_BORDER: - g_value_set_boxed (value, gtk_entry_get_inner_border (entry)); + g_value_set_boxed (value, gtk_entry_do_get_inner_border (entry)); break; case PROP_INVISIBLE_CHAR: @@ -2409,7 +2456,6 @@ gtk_entry_init (GtkEntry *entry) 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; @@ -2445,6 +2491,49 @@ gtk_entry_init (GtkEntry *entry) context = gtk_widget_get_style_context (GTK_WIDGET (entry)); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY); + + gtk_entry_update_cached_style_values (entry); +} + +static void +gtk_entry_prepare_context_for_icon (GtkEntry *entry, + GtkStyleContext *context, + GtkEntryIconPosition icon_pos) +{ + GtkEntryPrivate *priv = entry->priv; + EntryIconInfo *icon_info = priv->icons[icon_pos]; + GtkWidget *widget; + GtkStateFlags state; + + widget = GTK_WIDGET (entry); + state = gtk_widget_get_state_flags (widget); + + state &= ~(GTK_STATE_FLAG_PRELIGHT); + + if ((state & GTK_STATE_FLAG_INSENSITIVE) || icon_info->insensitive) + state |= GTK_STATE_FLAG_INSENSITIVE; + else if (icon_info->prelight) + state |= GTK_STATE_FLAG_PRELIGHT; + + gtk_style_context_save (context); + + gtk_style_context_set_state (context, state); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_IMAGE); + + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + { + if (icon_pos == GTK_ENTRY_ICON_PRIMARY) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + else + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + } + else + { + if (icon_pos == GTK_ENTRY_ICON_PRIMARY) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + else + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + } } static gint @@ -2453,20 +2542,25 @@ get_icon_width (GtkEntry *entry, { GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; - GdkScreen *screen; - GtkSettings *settings; - gint menu_icon_width; + GtkStyleContext *context; + GtkBorder padding; + gint width; - if (!icon_info || icon_info->pixbuf == NULL) + if (!icon_info) return 0; - screen = gtk_widget_get_screen (GTK_WIDGET (entry)); - settings = gtk_settings_get_for_screen (screen); + context = gtk_widget_get_style_context (GTK_WIDGET (entry)); + gtk_entry_prepare_context_for_icon (entry, context, icon_pos); + gtk_style_context_get_padding (context, 0, &padding); + + _gtk_icon_helper_get_size (icon_info->icon_helper, context, + &width, NULL); + gtk_style_context_restore (context); - gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, - &menu_icon_width, NULL); + if (width > 0) + width += padding.left + padding.right; - return MAX (gdk_pixbuf_get_width (icon_info->pixbuf), menu_icon_width); + return width; } static void @@ -2486,14 +2580,10 @@ get_icon_allocations (GtkEntry *entry, primary->y = y; primary->height = height; primary->width = get_icon_width (entry, GTK_ENTRY_ICON_PRIMARY); - if (primary->width > 0) - primary->width += 2 * priv->icon_margin; secondary->y = y; secondary->height = height; secondary->width = get_icon_width (entry, GTK_ENTRY_ICON_SECONDARY); - if (secondary->width > 0) - secondary->width += 2 * priv->icon_margin; if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) { @@ -2514,6 +2604,8 @@ begin_change (GtkEntry *entry) GtkEntryPrivate *priv = entry->priv; priv->change_count++; + + g_object_freeze_notify (G_OBJECT (entry)); } static void @@ -2524,6 +2616,8 @@ end_change (GtkEntry *entry) g_return_if_fail (priv->change_count > 0); + g_object_thaw_notify (G_OBJECT (entry)); + priv->change_count--; if (priv->change_count == 0) @@ -2578,6 +2672,7 @@ gtk_entry_dispose (GObject *object) { GtkEntry *entry = GTK_ENTRY (object); GtkEntryPrivate *priv = entry->priv; + GdkKeymap *keymap; gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, NULL); gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY, NULL); @@ -2591,6 +2686,9 @@ gtk_entry_dispose (GObject *object) priv->buffer = NULL; } + keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (object))); + g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry); + g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry); G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object); } @@ -2612,6 +2710,8 @@ gtk_entry_finalize (GObject *object) icon_info->target_list = NULL; } + g_clear_object (&icon_info->icon_helper); + g_slice_free (EntryIconInfo, icon_info); priv->icons[i] = NULL; } @@ -2733,7 +2833,8 @@ update_cursors (GtkWidget *widget) { if ((icon_info = priv->icons[i]) != NULL) { - if (icon_info->pixbuf != NULL && icon_info->window != NULL) + if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) && + icon_info->window != NULL) gdk_window_show_unraised (icon_info->window); /* The icon windows are not children of the visible entry window, @@ -2808,6 +2909,8 @@ construct_icon_info (GtkWidget *widget, icon_info = g_slice_new0 (EntryIconInfo); priv->icons[icon_pos] = icon_info; + icon_info->icon_helper = _gtk_icon_helper_new (); + if (gtk_widget_get_realized (widget)) realize_icon_info (widget, icon_pos); @@ -2830,7 +2933,8 @@ gtk_entry_map (GtkWidget *widget) { if ((icon_info = priv->icons[i]) != NULL) { - if (icon_info->pixbuf != NULL && icon_info->window != NULL) + if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) && + icon_info->window != NULL) gdk_window_show (icon_info->window); } } @@ -2850,7 +2954,8 @@ gtk_entry_unmap (GtkWidget *widget) { if ((icon_info = priv->icons[i]) != NULL) { - if (icon_info->pixbuf != NULL && icon_info->window != NULL) + if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) && + icon_info->window != NULL) gdk_window_hide (icon_info->window); } } @@ -2981,34 +3086,37 @@ gtk_entry_unrealize (GtkWidget *widget) void _gtk_entry_get_borders (GtkEntry *entry, - gint *xborder, - gint *yborder) + GtkBorder *border_out) { GtkEntryPrivate *priv = entry->priv; GtkWidget *widget = GTK_WIDGET (entry); + GtkBorder tmp = { 0, 0, 0, 0 }; + GtkStyleContext *context; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_padding (context, 0, &tmp); if (priv->has_frame) { - GtkStyleContext *context; - GtkBorder padding; - - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, 0, &padding); + GtkBorder border; - *xborder = padding.left; - *yborder = padding.top; - } - else - { - *xborder = 0; - *yborder = 0; + gtk_style_context_get_border (context, 0, &border); + tmp.top += border.top; + tmp.right += border.right; + tmp.bottom += border.bottom; + tmp.left += border.left; } if (!priv->interior_focus) { - *xborder += priv->focus_width; - *yborder += priv->focus_width; + tmp.top += priv->focus_width; + tmp.right += priv->focus_width; + tmp.bottom += priv->focus_width; + tmp.left += priv->focus_width; } + + if (border_out != NULL) + *border_out = tmp; } static void @@ -3019,8 +3127,7 @@ gtk_entry_get_preferred_width (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *priv = entry->priv; PangoFontMetrics *metrics; - gint xborder, yborder; - GtkBorder inner_border; + GtkBorder borders; PangoContext *context; GtkStyleContext *style_context; GtkStateFlags state; @@ -3037,25 +3144,24 @@ gtk_entry_get_preferred_width (GtkWidget *widget, gtk_style_context_get_font (style_context, state), pango_context_get_language (context)); - _gtk_entry_get_borders (entry, &xborder, &yborder); - _gtk_entry_effective_inner_border (entry, &inner_border); + _gtk_entry_get_borders (entry, &borders); if (priv->width_chars < 0) - width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right; + width = MIN_ENTRY_WIDTH + borders.left + borders.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; - width = char_pixels * priv->width_chars + xborder * 2 + inner_border.left + inner_border.right; + width = char_pixels * priv->width_chars + borders.left + borders.right; } for (i = 0; i < MAX_ICONS; i++) { icon_width = get_icon_width (entry, i); if (icon_width > 0) - icon_widths += icon_width + 2 * priv->icon_margin; + icon_widths += icon_width; } if (icon_widths > width) @@ -3075,8 +3181,7 @@ gtk_entry_get_preferred_height (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *priv = entry->priv; PangoFontMetrics *metrics; - gint xborder, yborder; - GtkBorder inner_border; + GtkBorder borders; GtkStyleContext *style_context; GtkStateFlags state; PangoContext *context; @@ -3094,10 +3199,9 @@ gtk_entry_get_preferred_height (GtkWidget *widget, 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); + _gtk_entry_get_borders (entry, &borders); - height = PANGO_PIXELS (priv->ascent + priv->descent) + yborder * 2 + inner_border.top + inner_border.bottom; + height = PANGO_PIXELS (priv->ascent + priv->descent) + borders.top + borders.bottom; pango_font_metrics_unref (metrics); @@ -3160,32 +3264,35 @@ gtk_entry_get_text_area_size (GtkEntry *entry, GtkWidget *widget = GTK_WIDGET (entry); GtkAllocation allocation; GtkRequisition requisition; + gint req_height; gint frame_height; - gint xborder, yborder; + GtkBorder borders; gtk_widget_get_preferred_size (widget, &requisition, NULL); + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); + gtk_widget_get_allocation (widget, &allocation); - _gtk_entry_get_borders (entry, &xborder, &yborder); + _gtk_entry_get_borders (entry, &borders); if (gtk_widget_get_realized (widget)) get_frame_size (entry, TRUE, NULL, NULL, NULL, &frame_height); else - frame_height = requisition.height; + frame_height = req_height; if (gtk_widget_has_focus (widget) && !priv->interior_focus) frame_height -= 2 * priv->focus_width; if (x) - *x = xborder; + *x = borders.left; if (y) - *y = frame_height / 2 - (requisition.height - yborder * 2) / 2; + *y = floor ((frame_height - req_height) / 2) + borders.top; if (width) - *width = allocation.width - xborder * 2; + *width = allocation.width - borders.left - borders.right; if (height) - *height = requisition.height - yborder * 2; + *height = req_height - borders.top - borders.bottom; } static void @@ -3218,8 +3325,12 @@ get_frame_size (GtkEntry *entry, GtkAllocation allocation; GtkRequisition requisition; GtkWidget *widget = GTK_WIDGET (entry); + gint req_height; gtk_widget_get_preferred_size (widget, &requisition, NULL); + + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); + gtk_widget_get_allocation (widget, &allocation); if (x) @@ -3228,9 +3339,9 @@ get_frame_size (GtkEntry *entry, if (y) { if (priv->is_cell_renderer) - *y = 0; + *y = 0; else - *y = (allocation.height - requisition.height) / 2; + *y = (allocation.height - req_height) / 2; if (relative_to_window) *y += allocation.y; @@ -3242,36 +3353,10 @@ get_frame_size (GtkEntry *entry, if (height) { if (priv->is_cell_renderer) - *height = allocation.height; + *height = allocation.height; else - *height = requisition.height; - } -} - -void -_gtk_entry_effective_inner_border (GtkEntry *entry, - GtkBorder *border) -{ - GtkBorder *tmp_border; - - tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border); - - if (tmp_border) - { - *border = *tmp_border; - return; - } - - gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL); - - if (tmp_border) - { - *border = *tmp_border; - gtk_border_free (tmp_border); - return; + *height = req_height; } - - *border = default_inner_border; } static void @@ -3327,20 +3412,13 @@ draw_icon (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; - GdkPixbuf *pixbuf; - gint x, y, width, height; + gint x, y, width, height, pix_width, pix_height; GtkStyleContext *context; - GtkIconSource *icon_source; - GtkStateFlags state; + GtkBorder padding; if (!icon_info) return; - gtk_entry_ensure_pixbuf (entry, icon_pos); - - if (icon_info->pixbuf == NULL) - return; - width = gdk_window_get_width (icon_info->window); height = gdk_window_get_height (icon_info->window); @@ -3349,46 +3427,24 @@ draw_icon (GtkWidget *widget, if (width == 1 || height == 1) return; - pixbuf = icon_info->pixbuf; - g_object_ref (pixbuf); - - if (gdk_pixbuf_get_height (pixbuf) > height) - { - GdkPixbuf *temp_pixbuf; - gint scale; - - scale = height - 2 * priv->icon_margin; - temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf, scale, scale, - GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - pixbuf = temp_pixbuf; - } - - x = (width - gdk_pixbuf_get_width (pixbuf)) / 2; - y = (height - gdk_pixbuf_get_height (pixbuf)) / 2; - - icon_source = gtk_icon_source_new (); - gtk_icon_source_set_pixbuf (icon_source, pixbuf); - gtk_icon_source_set_state_wildcarded (icon_source, TRUE); - - state = 0; - if (!gtk_widget_is_sensitive (widget) || icon_info->insensitive) - state |= GTK_STATE_FLAG_INSENSITIVE; - else if (icon_info->prelight) - state |= GTK_STATE_FLAG_PRELIGHT; + cairo_save (cr); + gtk_cairo_transform_to_window (cr, widget, icon_info->window); 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); + gtk_entry_prepare_context_for_icon (entry, context, icon_pos); + _gtk_icon_helper_get_size (icon_info->icon_helper, context, + &pix_width, &pix_height); + gtk_style_context_get_padding (context, 0, &padding); - gtk_icon_source_free (icon_source); + x = MAX (0, padding.left); + y = MAX (0, (height - pix_height) / 2); - gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); - cairo_paint (cr); + _gtk_icon_helper_draw (icon_info->icon_helper, + context, cr, + x, y); - g_object_unref (pixbuf); + gtk_style_context_restore (context); + cairo_restore (cr); } @@ -3400,28 +3456,26 @@ gtk_entry_draw_frame (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *priv = entry->priv; gint x = 0, y = 0, width, height; - GtkAllocation allocation; gint frame_x, frame_y; cairo_save (cr); - get_frame_size (GTK_ENTRY (widget), TRUE, &frame_x, &frame_y, &width, &height); - gtk_widget_get_allocation (widget, &allocation); + get_frame_size (GTK_ENTRY (widget), FALSE, &frame_x, &frame_y, &width, &height); - cairo_translate (cr, frame_x - allocation.x, frame_y - allocation.y); + cairo_translate (cr, frame_x, frame_y); /* Fix a problem with some themes which assume that entry->text_area's * width equals widget->window's width * http://bugzilla.gnome.org/show_bug.cgi?id=466000 */ if (GTK_IS_SPIN_BUTTON (widget)) { - gint xborder, yborder; + GtkBorder borders; gtk_entry_get_text_area_size (GTK_ENTRY (widget), &x, NULL, &width, NULL); - _gtk_entry_get_borders (GTK_ENTRY (widget), &xborder, &yborder); + _gtk_entry_get_borders (GTK_ENTRY (widget), &borders); - x -= xborder; - width += xborder * 2; + x -= borders.left; + width += borders.left + borders.right; } if (gtk_widget_has_focus (widget) && !priv->interior_focus) @@ -3441,7 +3495,7 @@ gtk_entry_draw_frame (GtkWidget *widget, gtk_entry_draw_progress (widget, context, cr); - if (gtk_widget_has_focus (widget) && !priv->interior_focus) + if (gtk_widget_has_visible_focus (widget) && !priv->interior_focus) { x -= priv->focus_width; y -= priv->focus_width; @@ -3455,6 +3509,18 @@ gtk_entry_draw_frame (GtkWidget *widget, cairo_restore (cr); } +static void +gtk_entry_prepare_context_for_progress (GtkEntry *entry, + GtkStyleContext *context) +{ + GtkEntryPrivate *private = entry->priv; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR); + if (private->progress_pulse_mode) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_PULSE); +} + static void get_progress_area (GtkWidget *widget, gint *x, @@ -3464,29 +3530,51 @@ get_progress_area (GtkWidget *widget, { GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *private = entry->priv; - GtkBorder *progress_border; + GtkStyleContext *context; + GtkBorder margin, border, entry_borders; + gint frame_width, text_area_width, text_area_height; + + context = gtk_widget_get_style_context (widget); + _gtk_entry_get_borders (entry, &entry_borders); + get_text_area_size (entry, + NULL, NULL, + &text_area_width, &text_area_height); + get_frame_size (entry, FALSE, + NULL, NULL, + &frame_width, NULL); - get_text_area_size (entry, x, y, width, height); + *x = 0; + *y = 0; + *width = text_area_width + entry_borders.left + entry_borders.right; + *height = text_area_height + entry_borders.top + entry_borders.bottom; - if (!private->interior_focus) + /* if the text area got resized by a subclass, subtract the left/right + * border width, so that the progress bar won't extend over the resized + * text area. + */ + if (frame_width > *width) { - *x -= private->focus_width; - *y -= private->focus_width; - *width += 2 * private->focus_width; - *height += 2 * private->focus_width; + gtk_style_context_get_border (context, 0, &border); + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + { + *x = (frame_width - *width) + border.left; + *width -= border.left; + } + else + { + *width -= border.right; + } } - gtk_widget_style_get (widget, "progress-border", &progress_border, NULL); + gtk_entry_prepare_context_for_progress (entry, context); + gtk_style_context_get_margin (context, 0, &margin); - 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_style_context_restore (context); - gtk_border_free (progress_border); - } + *x += margin.left; + *y += margin.top; + *width -= margin.left + margin.right; + *height -= margin.top + margin.bottom; if (private->progress_pulse_mode) { @@ -3524,16 +3612,15 @@ gtk_entry_draw_progress (GtkWidget *widget, GtkStyleContext *context, cairo_t *cr) { + GtkEntry *entry = GTK_ENTRY (widget); 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_entry_prepare_context_for_progress (entry, context); gtk_render_activity (context, cr, x, y, width, height); @@ -3546,59 +3633,41 @@ gtk_entry_draw (GtkWidget *widget, { GtkEntry *entry = GTK_ENTRY (widget); GtkStyleContext *context; - GtkStateFlags state; GtkEntryPrivate *priv = entry->priv; int i; context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - - 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); - - 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), cr); + /* Draw entry_bg, shadow, progress and focus */ + gtk_entry_draw_frame (widget, context, cr); - /* 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); + /* Draw text and cursor */ + cairo_save (cr); - cairo_restore (cr); + gtk_cairo_transform_to_window (cr, widget, priv->text_area); - /* Draw icons */ - for (i = 0; i < MAX_ICONS; i++) - { - EntryIconInfo *icon_info = priv->icons[i]; + if (priv->dnd_position != -1) + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND); + + gtk_entry_draw_text (GTK_ENTRY (widget), cr); - if (icon_info != NULL) - { - cairo_save (cr); + /* 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); - gtk_cairo_transform_to_window (cr, widget, icon_info->window); + cairo_restore (cr); - draw_icon (widget, cr, i); + /* Draw icons */ + for (i = 0; i < MAX_ICONS; i++) + { + EntryIconInfo *icon_info = priv->icons[i]; - cairo_restore (cr); - } - } + if (icon_info != NULL) + draw_icon (widget, cr, i); } - gtk_style_context_restore (context); - return FALSE; } @@ -3769,27 +3838,38 @@ gtk_entry_button_press (GtkWidget *widget, gtk_entry_reset_blink_time (entry); priv->button = event->button; - + priv->device = gdk_event_get_device ((GdkEvent *) event); + if (!gtk_widget_has_focus (widget)) { priv->in_click = TRUE; gtk_widget_grab_focus (widget); priv->in_click = FALSE; } - + tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); - - if (event->button == 1) + + if (gdk_event_triggers_context_menu ((GdkEvent *) event)) + { + gtk_entry_do_popup (entry, event); + priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ + priv->device = NULL; + + return TRUE; + } + else if (event->button == GDK_BUTTON_PRIMARY) { gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end); - + priv->select_words = FALSE; priv->select_lines = FALSE; - if (event->state & GDK_SHIFT_MASK) + if (event->state & + gtk_widget_get_modifier_mask (widget, + GDK_MODIFIER_INTENT_EXTEND_SELECTION)) { _gtk_entry_reset_im_context (entry); - + if (!have_selection) /* select from the current position to the clicked position */ sel_start = sel_end = priv->current_pos; @@ -3887,7 +3967,9 @@ gtk_entry_button_press (GtkWidget *widget, return TRUE; } - else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) + else if (event->type == GDK_BUTTON_PRESS && + event->button == GDK_BUTTON_MIDDLE && + get_middle_click_paste (entry)) { if (priv->editable) { @@ -3900,13 +3982,6 @@ gtk_entry_button_press (GtkWidget *widget, gtk_widget_error_bell (widget); } } - else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) - { - gtk_entry_do_popup (entry, event); - priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ - - return TRUE; - } return FALSE; } @@ -3958,9 +4033,10 @@ gtk_entry_button_release (GtkWidget *widget, priv->in_drag = 0; } - + priv->button = 0; - + priv->device = NULL; + gtk_entry_update_primary_selection (entry); return TRUE; @@ -4029,7 +4105,7 @@ gtk_entry_motion_notify (GtkWidget *widget, priv->mouse_cursor_obscured = FALSE; } - if (event->window != priv->text_area || priv->button != 1) + if (event->window != priv->text_area || priv->button != GDK_BUTTON_PRIMARY) return FALSE; if (priv->select_lines) @@ -4069,7 +4145,8 @@ gtk_entry_motion_notify (GtkWidget *widget, priv->in_drag = FALSE; priv->button = 0; - + priv->device = NULL; + gtk_target_list_unref (target_list); } } @@ -4294,17 +4371,17 @@ gtk_entry_focus_out (GtkWidget *widget, completion = gtk_entry_get_completion (entry); if (completion) _gtk_entry_completion_popdown (completion); - + return FALSE; } static void -gtk_entry_grab_focus (GtkWidget *widget) +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 (priv->editable && !priv->in_click) @@ -4313,20 +4390,20 @@ gtk_entry_grab_focus (GtkWidget *widget) "gtk-entry-select-on-focus", &select_on_focus, NULL); - + if (select_on_focus) gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); } } -static void +static void gtk_entry_direction_changed (GtkWidget *widget, - GtkTextDirection previous_dir) + GtkTextDirection previous_dir) { GtkEntry *entry = GTK_ENTRY (widget); gtk_entry_recompute (entry); - + GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir); } @@ -4337,12 +4414,12 @@ gtk_entry_state_flags_changed (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEntryPrivate *priv = entry->priv; GdkCursor *cursor; - + if (gtk_widget_get_realized (widget)) { if (gtk_widget_is_sensitive (widget)) cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM); - else + else cursor = NULL; gdk_window_set_cursor (priv->text_area, cursor); @@ -4360,8 +4437,8 @@ gtk_entry_state_flags_changed (GtkWidget *widget, /* Clear any selection */ gtk_editable_select_region (GTK_EDITABLE (entry), priv->current_pos, priv->current_pos); } - - gtk_widget_queue_draw (widget); + + gtk_entry_update_cached_style_values (entry); } static void @@ -4505,55 +4582,50 @@ icon_theme_changed (GtkEntry *entry) { EntryIconInfo *icon_info = priv->icons[i]; if (icon_info != NULL) - { - if (icon_info->storage_type == GTK_IMAGE_ICON_NAME) - gtk_entry_set_icon_from_icon_name (entry, i, icon_info->icon_name); - else if (icon_info->storage_type == GTK_IMAGE_STOCK) - gtk_entry_set_icon_from_stock (entry, i, icon_info->stock_id); - else if (icon_info->storage_type == GTK_IMAGE_GICON) - gtk_entry_set_icon_from_gicon (entry, i, icon_info->gicon); - } + _gtk_icon_helper_invalidate (icon_info->icon_helper); } gtk_widget_queue_draw (GTK_WIDGET (entry)); } static void -icon_margin_changed (GtkEntry *entry) +gtk_entry_update_cached_style_values (GtkEntry *entry) { GtkEntryPrivate *priv = entry->priv; - GtkBorder border; + gint focus_width; + gboolean interior_focus; + + gtk_widget_style_get (GTK_WIDGET (entry), + "focus-line-width", &focus_width, + "interior-focus", &interior_focus, + NULL); + priv->focus_width = focus_width; + priv->interior_focus = interior_focus; - _gtk_entry_effective_inner_border (GTK_ENTRY (entry), &border); + if (!priv->invisible_char_set) + { + gunichar ch = find_invisible_char (GTK_WIDGET (entry)); - priv->icon_margin = border.left; + if (priv->invisible_char != ch) + { + priv->invisible_char = ch; + g_object_notify (G_OBJECT (entry), "invisible-char"); + } + } } static void gtk_entry_style_updated (GtkWidget *widget) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = entry->priv; - gint focus_width; - gboolean interior_focus; GTK_WIDGET_CLASS (gtk_entry_parent_class)->style_updated (widget); - gtk_widget_style_get (widget, - "focus-line-width", &focus_width, - "interior-focus", &interior_focus, - NULL); - - priv->focus_width = focus_width; - priv->interior_focus = interior_focus; - - if (!priv->invisible_char_set) - priv->invisible_char = find_invisible_char (GTK_WIDGET (entry)); + gtk_entry_update_cached_style_values (entry); gtk_entry_recompute (entry); icon_theme_changed (entry); - icon_margin_changed (entry); } /* GtkCellEditable method implementations @@ -4647,8 +4719,12 @@ gtk_entry_real_insert_text (GtkEditable *editable, * following signal handlers: buffer_inserted_text(), buffer_notify_display_text(), * buffer_notify_text(), buffer_notify_length() */ + begin_change (GTK_ENTRY (editable)); + n_inserted = gtk_entry_buffer_insert_text (get_buffer (GTK_ENTRY (editable)), *position, new_text, n_chars); + end_change (GTK_ENTRY (editable)); + if (n_inserted != n_chars) gtk_widget_error_bell (GTK_WIDGET (editable)); @@ -4666,7 +4742,11 @@ gtk_entry_real_delete_text (GtkEditable *editable, * buffer_notify_text(), buffer_notify_length() */ + begin_change (GTK_ENTRY (editable)); + gtk_entry_buffer_delete_text (get_buffer (GTK_ENTRY (editable)), start_pos, end_pos - start_pos); + + end_change (GTK_ENTRY (editable)); } /* GtkEntryBuffer signal handlers @@ -4680,12 +4760,18 @@ buffer_inserted_text (GtkEntryBuffer *buffer, { GtkEntryPrivate *priv = entry->priv; guint password_hint_timeout; + guint current_pos; + gint selection_bound; - if (priv->current_pos > position) - priv->current_pos += n_chars; + current_pos = priv->current_pos; + if (current_pos > position) + current_pos += n_chars; - if (priv->selection_bound > position) - priv->selection_bound += n_chars; + selection_bound = priv->selection_bound; + if (selection_bound > position) + selection_bound += n_chars; + + gtk_entry_set_positions (entry, current_pos, selection_bound); /* Calculate the password hint if it needs to be displayed. */ if (n_chars == 1 && !priv->visible) @@ -5624,16 +5710,13 @@ get_layout_position (GtkEntry *entry, PangoLayout *layout; PangoRectangle logical_rect; gint area_width, area_height; - GtkBorder inner_border; gint y_pos; PangoLayoutLine *line; layout = gtk_entry_ensure_layout (entry, TRUE); gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height); - _gtk_entry_effective_inner_border (entry, &inner_border); - - area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom); + area_height = PANGO_SCALE * area_height; line = pango_layout_get_lines_readonly (layout)->data; pango_layout_line_get_extents (line, NULL, &logical_rect); @@ -5650,10 +5733,10 @@ get_layout_position (GtkEntry *entry, else if (y_pos + logical_rect.height > area_height) y_pos = area_height - logical_rect.height; - y_pos = inner_border.top + y_pos / PANGO_SCALE; + y_pos = y_pos / PANGO_SCALE; if (x) - *x = inner_border.left - priv->scroll_offset; + *x = - priv->scroll_offset; if (y) *y = y_pos; @@ -5686,7 +5769,6 @@ draw_text_with_color (GtkEntry *entry, gint n_ranges, i; PangoRectangle logical_rect; GdkRGBA selection_color, text_color; - GtkBorder inner_border; GtkStyleContext *context; GtkStateFlags state; @@ -5694,19 +5776,15 @@ draw_text_with_color (GtkEntry *entry, pango_layout_get_pixel_extents (layout, NULL, &logical_rect); gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); - state = GTK_STATE_FLAG_SELECTED; - - if (gtk_widget_has_focus (widget)) - state |= GTK_STATE_FLAG_FOCUSED; + state = gtk_widget_get_state_flags (widget); + state |= GTK_STATE_FLAG_SELECTED; 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], + - priv->scroll_offset + ranges[2 * i], y, ranges[2 * i + 1], logical_rect.height); @@ -5734,7 +5812,6 @@ gtk_entry_draw_text (GtkEntry *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; @@ -5749,8 +5826,7 @@ gtk_entry_draw_text (GtkEntry *entry, gtk_style_context_get_color (context, state, &text_color); /* Get foreground color for progressbars */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR); + gtk_entry_prepare_context_for_progress (entry, context); gtk_style_context_get_color (context, state, &bar_text_color); gtk_style_context_restore (context); @@ -5758,6 +5834,8 @@ gtk_entry_draw_text (GtkEntry *entry, &progress_x, &progress_y, &progress_width, &progress_height); + cairo_save (cr); + 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); @@ -5772,21 +5850,22 @@ gtk_entry_draw_text (GtkEntry *entry, } else { + int frame_x, frame_y, area_x, area_y; + 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; + /* progres area is frame-relative, we need it text-area window + * relative */ + get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL); + gdk_window_get_position (priv->text_area, &area_x, &area_y); + progress_x += frame_x - area_x; + progress_y += frame_y - area_y; cairo_rectangle (cr, progress_x, progress_y, progress_width, progress_height); @@ -5796,6 +5875,8 @@ gtk_entry_draw_text (GtkEntry *entry, draw_text_with_color (entry, cr, &text_color); cairo_restore (cr); + cairo_save (cr); + cairo_rectangle (cr, progress_x, progress_y, progress_width, progress_height); cairo_clip (cr); @@ -5804,27 +5885,8 @@ gtk_entry_draw_text (GtkEntry *entry, cairo_restore (cr); } -} - -static void -draw_insertion_cursor (GtkEntry *entry, - cairo_t *cr, - GdkRectangle *cursor_location, - gboolean is_primary, - PangoDirection direction, - gboolean draw_arrow) -{ - GtkWidget *widget = GTK_WIDGET (entry); - GtkTextDirection text_dir; - - if (direction == PANGO_DIRECTION_LTR) - text_dir = GTK_TEXT_DIR_LTR; - else - text_dir = GTK_TEXT_DIR_RTL; - gtk_draw_insertion_cursor (widget, cr, - cursor_location, - is_primary, text_dir, draw_arrow); + cairo_restore (cr); } static void @@ -5834,29 +5896,22 @@ gtk_entry_draw_cursor (GtkEntry *entry, { 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); - GdkRectangle cursor_location; - gboolean split_cursor; + GtkStyleContext *context; 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; + gint x, y; - _gtk_entry_effective_inner_border (entry, &inner_border); - - xoffset = inner_border.left - priv->scroll_offset; - - text_area_height = gdk_window_get_height (priv->text_area); + context = gtk_widget_get_style_context (widget); 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; + get_layout_position (entry, &x, &y); + if (!priv->overwrite_mode) block = FALSE; else @@ -5865,73 +5920,22 @@ gtk_entry_draw_cursor (GtkEntry *entry, 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); - - g_object_get (gtk_widget_get_settings (widget), - "gtk-split-cursor", &split_cursor, - NULL); - - dir1 = priv->resolved_dir; - - if (split_cursor) - { - x1 = strong_x; - - if (weak_x != strong_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; - - draw_insertion_cursor (entry, cr, - &cursor_location, TRUE, dir1, - dir2 != PANGO_DIRECTION_NEUTRAL); - - if (dir2 != PANGO_DIRECTION_NEUTRAL) - { - cursor_location.x = xoffset + x2; - draw_insertion_cursor (entry, cr, - &cursor_location, FALSE, dir2, - TRUE); - } + gtk_render_insertion_cursor (context, cr, + x, y, + layout, cursor_index, priv->resolved_dir); } else /* overwrite_mode */ { - GtkStyleContext *context; GdkRGBA cursor_color; GdkRectangle rect; - gint x, y; cairo_save (cr); - get_layout_position (entry, &x, &y); - 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); - context = gtk_widget_get_style_context (widget); - _gtk_style_context_get_cursor_color (context, &cursor_color, NULL); gdk_cairo_set_source_rgba (cr, &cursor_color); gdk_cairo_rectangle (cr, &rect); @@ -6124,7 +6128,6 @@ gtk_entry_adjust_scroll (GtkEntry *entry) GtkEntryPrivate *priv = entry->priv; gint min_offset, max_offset; gint text_area_width, text_width; - GtkBorder inner_border; gint strong_x, weak_x; gint strong_xoffset, weak_xoffset; gfloat xalign; @@ -6135,10 +6138,8 @@ gtk_entry_adjust_scroll (GtkEntry *entry) if (!gtk_widget_get_realized (GTK_WIDGET (entry))) return; - _gtk_entry_effective_inner_border (entry, &inner_border); - 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; @@ -6223,7 +6224,8 @@ gtk_entry_move_adjustments (GtkEntry *entry) PangoFontMetrics *metrics; GtkStyleContext *style_context; GtkStateFlags state; - gint x, layout_x, border_x, border_y; + GtkBorder borders; + gint x, layout_x; gint char_width; adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment); @@ -6235,8 +6237,8 @@ gtk_entry_move_adjustments (GtkEntry *entry) /* 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 += allocation.x + layout_x + border_x; + _gtk_entry_get_borders (entry, &borders); + x += allocation.x + layout_x + borders.left; /* Approximate width of a char, so user can see what is ahead/behind */ context = gtk_widget_get_pango_context (widget); @@ -6489,7 +6491,7 @@ paste_received (GtkClipboard *clipboard, GtkEditable *editable = GTK_EDITABLE (entry); GtkEntryPrivate *priv = entry->priv; - if (priv->button == 2) + if (priv->button == GDK_BUTTON_MIDDLE) { gint pos, start, end; pos = priv->insert_pos; @@ -6524,14 +6526,12 @@ paste_received (GtkClipboard *clipboard, } begin_change (entry); - g_object_freeze_notify (G_OBJECT (entry)); if (gtk_editable_get_selection_bounds (editable, &start, &end)) gtk_editable_delete_text (editable, start, end); 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)); end_change (entry); if (completion && @@ -6619,8 +6619,9 @@ gtk_entry_clear (GtkEntry *entry, { GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; + GtkImageType storage_type; - if (!icon_info || icon_info->storage_type == GTK_IMAGE_EMPTY) + if (icon_info && _gtk_icon_helper_get_is_empty (icon_info->icon_helper)) return; g_object_freeze_notify (G_OBJECT (entry)); @@ -6631,13 +6632,9 @@ gtk_entry_clear (GtkEntry *entry, if (GDK_IS_WINDOW (icon_info->window)) gdk_window_hide (icon_info->window); - if (icon_info->pixbuf) - { - g_object_unref (icon_info->pixbuf); - icon_info->pixbuf = NULL; - } + storage_type = _gtk_icon_helper_get_storage_type (icon_info->icon_helper); - switch (icon_info->storage_type) + switch (storage_type) { case GTK_IMAGE_PIXBUF: g_object_notify (G_OBJECT (entry), @@ -6645,25 +6642,16 @@ gtk_entry_clear (GtkEntry *entry, 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 ? "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 ? "primary-icon-name" : "secondary-icon-name"); break; case GTK_IMAGE_GICON: - if (icon_info->gicon) - { - g_object_unref (icon_info->gicon); - icon_info->gicon = NULL; - } g_object_notify (G_OBJECT (entry), icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-gicon" : "secondary-icon-gicon"); break; @@ -6673,7 +6661,8 @@ gtk_entry_clear (GtkEntry *entry, break; } - icon_info->storage_type = GTK_IMAGE_EMPTY; + _gtk_icon_helper_clear (icon_info->icon_helper); + g_object_notify (G_OBJECT (entry), icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-storage-type" : "secondary-icon-storage-type"); @@ -6681,122 +6670,25 @@ gtk_entry_clear (GtkEntry *entry, } static GdkPixbuf * -create_normal_pixbuf (GtkStyleContext *context, - const gchar *stock_id, - GtkIconSize icon_size) -{ - GtkIconSet *icon_set; - GdkPixbuf *pixbuf; - - gtk_style_context_save (context); - - /* Unset any state */ - gtk_style_context_set_state (context, 0); - - icon_set = gtk_style_context_lookup_icon_set (context, stock_id); - pixbuf = gtk_icon_set_render_icon_pixbuf (icon_set, context, icon_size); - - gtk_style_context_restore (context); - - return pixbuf; -} - -static void gtk_entry_ensure_pixbuf (GtkEntry *entry, GtkEntryIconPosition icon_pos) { GtkEntryPrivate *priv = entry->priv; EntryIconInfo *icon_info = priv->icons[icon_pos]; GtkStyleContext *context; - GtkIconInfo *info; - GtkIconTheme *icon_theme; - GtkSettings *settings; - GtkWidget *widget; - GdkScreen *screen; - gint width, height; - - if (!icon_info || icon_info->pixbuf) - return; - - widget = GTK_WIDGET (entry); - context = gtk_widget_get_style_context (widget); - - switch (icon_info->storage_type) - { - case GTK_IMAGE_EMPTY: - case GTK_IMAGE_PIXBUF: - break; - case GTK_IMAGE_STOCK: - icon_info->pixbuf = create_normal_pixbuf (context, icon_info->stock_id, - GTK_ICON_SIZE_MENU); - - if (!icon_info->pixbuf) - icon_info->pixbuf = create_normal_pixbuf (context, - GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_MENU); - break; + GdkPixbuf *pix; - case GTK_IMAGE_ICON_NAME: - 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); - - icon_info->pixbuf = gtk_icon_theme_load_icon (icon_theme, - icon_info->icon_name, - MIN (width, height), - 0, NULL); - - if (icon_info->pixbuf == NULL) - icon_info->pixbuf = create_normal_pixbuf (context, - GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_MENU); - } - break; + context = gtk_widget_get_style_context (GTK_WIDGET (entry)); + gtk_entry_prepare_context_for_icon (entry, context, icon_pos); - case GTK_IMAGE_GICON: - 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); - - info = gtk_icon_theme_lookup_by_gicon (icon_theme, - icon_info->gicon, - MIN (width, height), - GTK_ICON_LOOKUP_USE_BUILTIN); - if (info) - { - icon_info->pixbuf = gtk_icon_info_load_icon (info, NULL); - gtk_icon_info_free (info); - } + pix = _gtk_icon_helper_ensure_pixbuf (icon_info->icon_helper, + context); - if (icon_info->pixbuf == NULL) - icon_info->pixbuf = create_normal_pixbuf (context, - GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_MENU); - } - break; + gtk_style_context_restore (context); - default: - g_assert_not_reached (); - break; - } - - if (icon_info->pixbuf != NULL && icon_info->window != NULL) - gdk_window_show_unraised (icon_info->window); + return pix; } - /* Public API */ @@ -6996,11 +6888,9 @@ gtk_entry_set_text (GtkEntry *entry, g_signal_handler_block (entry, completion->priv->changed_id); begin_change (entry); - g_object_freeze_notify (G_OBJECT (entry)); gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); tmp_pos = 0; gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos); - g_object_thaw_notify (G_OBJECT (entry)); end_change (entry); if (completion && completion->priv->changed_id > 0) @@ -7212,7 +7102,7 @@ gtk_entry_get_overwrite_mode (GtkEntry *entry) * storage in the widget and must not be freed, modified or * stored. **/ -G_CONST_RETURN gchar* +const gchar* gtk_entry_get_text (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); @@ -7307,7 +7197,7 @@ gtk_entry_get_text_length (GtkEntry *entry) * * (For experts: if @setting is %TRUE, the entry calls * gtk_window_activate_default() on the window containing the entry, in - * the default handler for the #GtkWidget::activate signal.) + * the default handler for the #GtkEntry::activate signal.) **/ void gtk_entry_set_activates_default (GtkEntry *entry, @@ -7447,6 +7337,10 @@ gtk_entry_get_has_frame (GtkEntry *entry) * pixel-exact positioning of the entry is important. * * Since: 2.10 + * + * Deprecated: 3.4: Use the standard border and padding CSS properties (through + * objects like #GtkStyleContext and #GtkCssProvider); the value set with + * this function is ignored by #GtkEntry. **/ void gtk_entry_set_inner_border (GtkEntry *entry, @@ -7454,16 +7348,7 @@ gtk_entry_set_inner_border (GtkEntry *entry, { g_return_if_fail (GTK_IS_ENTRY (entry)); - gtk_widget_queue_resize (GTK_WIDGET (entry)); - - if (border) - g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border, - gtk_border_copy (border), - (GDestroyNotify) gtk_border_free); - else - g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL); - - g_object_notify (G_OBJECT (entry), "inner-border"); + gtk_entry_do_set_inner_border (entry, border); } /** @@ -7476,13 +7361,17 @@ gtk_entry_set_inner_border (GtkEntry *entry, * Return value: (transfer none): the entry's #GtkBorder, or %NULL if none was set. * * Since: 2.10 + * + * Deprecated: 3.4: Use the standard border and padding CSS properties (through + * objects like #GtkStyleContext and #GtkCssProvider); the value returned by + * this function is ignored by #GtkEntry. **/ -G_CONST_RETURN GtkBorder * +const GtkBorder * gtk_entry_get_inner_border (GtkEntry *entry) { g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - return g_object_get_qdata (G_OBJECT (entry), quark_inner_border); + return gtk_entry_do_get_inner_border (entry); } /** @@ -7730,8 +7619,7 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, if (pixbuf) { - icon_info->storage_type = GTK_IMAGE_PIXBUF; - icon_info->pixbuf = pixbuf; + _gtk_icon_helper_set_pixbuf (icon_info->icon_helper, pixbuf); if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { @@ -7746,9 +7634,9 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, if (gtk_widget_get_mapped (GTK_WIDGET (entry))) gdk_window_show_unraised (icon_info->window); - } - gtk_entry_ensure_pixbuf (entry, icon_pos); + g_object_unref (pixbuf); + } if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); @@ -7795,8 +7683,7 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, if (new_id != NULL) { - icon_info->storage_type = GTK_IMAGE_STOCK; - icon_info->stock_id = new_id; + _gtk_icon_helper_set_stock_id (icon_info->icon_helper, new_id, GTK_ICON_SIZE_MENU); if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { @@ -7811,9 +7698,9 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry, if (gtk_widget_get_mapped (GTK_WIDGET (entry))) gdk_window_show_unraised (icon_info->window); - } - gtk_entry_ensure_pixbuf (entry, icon_pos); + g_free (new_id); + } if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); @@ -7863,8 +7750,7 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, if (new_name != NULL) { - icon_info->storage_type = GTK_IMAGE_ICON_NAME; - icon_info->icon_name = new_name; + _gtk_icon_helper_set_icon_name (icon_info->icon_helper, new_name, GTK_ICON_SIZE_MENU); if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { @@ -7879,9 +7765,9 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry, if (gtk_widget_get_mapped (GTK_WIDGET (entry))) gdk_window_show_unraised (icon_info->window); - } - gtk_entry_ensure_pixbuf (entry, icon_pos); + g_free (new_name); + } if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); @@ -7930,8 +7816,7 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry, if (icon) { - icon_info->storage_type = GTK_IMAGE_GICON; - icon_info->gicon = icon; + _gtk_icon_helper_set_gicon (icon_info->icon_helper, icon, GTK_ICON_SIZE_MENU); if (icon_pos == GTK_ENTRY_ICON_PRIMARY) { @@ -7946,9 +7831,9 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry, if (gtk_widget_get_mapped (GTK_WIDGET (entry))) gdk_window_show_unraised (icon_info->window); - } - gtk_entry_ensure_pixbuf (entry, icon_pos); + g_object_unref (icon); + } if (gtk_widget_get_visible (GTK_WIDGET (entry))) gtk_widget_queue_resize (GTK_WIDGET (entry)); @@ -8045,6 +7930,7 @@ gtk_entry_get_icon_pixbuf (GtkEntry *entry, { GtkEntryPrivate *priv; EntryIconInfo *icon_info; + GdkPixbuf *pixbuf; g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL); @@ -8056,9 +7942,14 @@ gtk_entry_get_icon_pixbuf (GtkEntry *entry, if (!icon_info) return NULL; - gtk_entry_ensure_pixbuf (entry, icon_pos); + /* HACK: unfortunately this is transfer none, so we need to return + * the icon helper's cache ref directly. + */ + pixbuf = gtk_entry_ensure_pixbuf (entry, icon_pos); + if (pixbuf) + g_object_unref (pixbuf); - return icon_info->pixbuf; + return pixbuf; } /** @@ -8091,7 +7982,7 @@ gtk_entry_get_icon_gicon (GtkEntry *entry, if (!icon_info) return NULL; - return icon_info->storage_type == GTK_IMAGE_GICON ? icon_info->gicon : NULL; + return _gtk_icon_helper_peek_gicon (icon_info->icon_helper); } /** @@ -8124,7 +8015,7 @@ gtk_entry_get_icon_stock (GtkEntry *entry, if (!icon_info) return NULL; - return icon_info->storage_type == GTK_IMAGE_STOCK ? icon_info->stock_id : NULL; + return _gtk_icon_helper_get_stock_id (icon_info->icon_helper); } /** @@ -8157,7 +8048,7 @@ gtk_entry_get_icon_name (GtkEntry *entry, if (!icon_info) return NULL; - return icon_info->storage_type == GTK_IMAGE_ICON_NAME ? icon_info->icon_name : NULL; + return _gtk_icon_helper_get_icon_name (icon_info->icon_helper); } /** @@ -8263,7 +8154,7 @@ gtk_entry_get_icon_storage_type (GtkEntry *entry, if (!icon_info) return GTK_IMAGE_EMPTY; - return icon_info->storage_type; + return _gtk_icon_helper_get_storage_type (icon_info->icon_helper); } /** @@ -8272,7 +8163,8 @@ gtk_entry_get_icon_storage_type (GtkEntry *entry, * @x: the x coordinate of the position to find * @y: the y coordinate of the position to find * - * Finds the icon at the given position and return its index. + * Finds the icon at the given position and return its index. The + * position's coordinates are relative to the @entry's top left corner. * If @x, @y doesn't lie inside an icon, -1 is returned. * This function is intended for use in a #GtkWidget::query-tooltip * signal handler. @@ -8292,7 +8184,7 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry, g_return_val_if_fail (GTK_IS_ENTRY (entry), -1); - get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL); + get_frame_size (entry, FALSE, &frame_x, &frame_y, NULL, NULL); x -= frame_x; y -= frame_y; @@ -8311,7 +8203,7 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry, /** * gtk_entry_set_icon_drag_source: - * @entry: a #GtkIconEntry + * @entry: a #GtkEntry * @icon_pos: icon position * @target_list: the targets (data formats) in which the data can be provided * @actions: a bitmask of the allowed drag actions @@ -8604,7 +8496,7 @@ gtk_entry_get_icon_tooltip_markup (GtkEntry *entry, * Use %NULL for @tooltip to remove an existing tooltip. * * See also gtk_widget_set_tooltip_markup() and - * gtk_enty_set_icon_tooltip_text(). + * gtk_entry_set_icon_tooltip_text(). * * Since: 2.16 */ @@ -8697,6 +8589,26 @@ gtk_entry_mnemonic_activate (GtkWidget *widget, return TRUE; } +static void +gtk_entry_grab_notify (GtkWidget *widget, + gboolean was_grabbed) +{ + GtkEntryPrivate *priv; + + priv = GTK_ENTRY (widget)->priv; + + if (priv->device && + gtk_widget_device_is_shadowed (widget, priv->device)) + { + /* Unset button so we don't expect + * a button release anymore + */ + priv->button = 0; + priv->device = NULL; + priv->in_drag = FALSE; + } +} + static void append_action_signal (GtkEntry *entry, GtkWidget *menu, @@ -8739,7 +8651,7 @@ popup_position_func (GtkMenu *menu, GdkScreen *screen; GtkRequisition menu_req; GdkRectangle monitor; - GtkBorder inner_border; + GtkBorder borders; gint monitor_num, strong_x, height; g_return_if_fail (gtk_widget_get_realized (widget)); @@ -8752,14 +8664,14 @@ popup_position_func (GtkMenu *menu, monitor_num = 0; gtk_menu_set_monitor (menu, monitor_num); - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); 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); + _gtk_entry_get_borders (entry, &borders); - *x += inner_border.left + strong_x - priv->scroll_offset; + *x += borders.left + strong_x - priv->scroll_offset; if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) *x -= menu_req.width; @@ -8791,6 +8703,7 @@ typedef struct GtkEntry *entry; gint button; guint time; + GdkDevice *device; } PopupInfo; static void @@ -8845,6 +8758,7 @@ popup_targets_received (GtkClipboard *clipboard, 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); + gtk_widget_set_sensitive (menuitem, gtk_entry_buffer_get_length (info_entry_priv->buffer) > 0); g_signal_connect_swapped (menuitem, "activate", G_CALLBACK (gtk_entry_select_all), entry); gtk_widget_show (menuitem); @@ -8897,15 +8811,15 @@ popup_targets_received (GtkClipboard *clipboard, info_entry_priv->popup_menu); - if (info->button) - gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL, - NULL, NULL, + if (info->device) + gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu), + info->device, NULL, NULL, NULL, NULL, NULL, info->button, info->time); else { gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL, popup_position_func, entry, - info->button, info->time); + 0, gtk_get_current_event_time ()); gtk_menu_shell_select_first (GTK_MENU_SHELL (info_entry_priv->popup_menu), FALSE); } } @@ -8930,11 +8844,13 @@ gtk_entry_do_popup (GtkEntry *entry, { info->button = event->button; info->time = event->time; + info->device = event->device; } else { info->button = 0; info->time = gtk_get_current_event_time (); + info->device = NULL; } gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD), @@ -8966,24 +8882,14 @@ gtk_entry_drag_begin (GtkWidget *widget, { if (icon_info->in_drag) { - switch (icon_info->storage_type) - { - case GTK_IMAGE_STOCK: - gtk_drag_set_icon_stock (context, icon_info->stock_id, -2, -2); - break; - - case GTK_IMAGE_ICON_NAME: - gtk_drag_set_icon_name (context, icon_info->icon_name, -2, -2); - break; - - /* FIXME: No GIcon support for dnd icons */ - case GTK_IMAGE_GICON: - case GTK_IMAGE_PIXBUF: - gtk_drag_set_icon_pixbuf (context, icon_info->pixbuf, -2, -2); - break; - default: - g_assert_not_reached (); - } + GdkPixbuf *pix; + + pix = _gtk_icon_helper_ensure_pixbuf + (icon_info->icon_helper, + gtk_widget_get_style_context (GTK_WIDGET (entry))); + gtk_drag_set_icon_pixbuf (context, pix, -2, -2); + + g_object_unref (pix); } } } @@ -9150,10 +9056,8 @@ gtk_entry_drag_data_received (GtkWidget *widget, { /* Replacing selection */ begin_change (entry); - g_object_freeze_notify (G_OBJECT (entry)); gtk_editable_delete_text (editable, sel1, sel2); gtk_editable_insert_text (editable, str, length, &sel1); - g_object_thaw_notify (G_OBJECT (entry)); end_change (entry); } @@ -9263,6 +9167,18 @@ cursor_blinks (GtkEntry *entry) return FALSE; } +static gboolean +get_middle_click_paste (GtkEntry *entry) +{ + GtkSettings *settings; + gboolean paste; + + settings = gtk_widget_get_settings (GTK_WIDGET (entry)); + g_object_get (settings, "gtk-enable-primary-paste", &paste, NULL); + + return paste; +} + static gint get_cursor_time (GtkEntry *entry) { @@ -9530,13 +9446,13 @@ gtk_entry_completion_key_press (GtkWidget *widget, completion->priv->current_selected = -1; else if (completion->priv->current_selected < matches) { - completion->priv->current_selected -= 14; + completion->priv->current_selected -= PAGE_STEP; if (completion->priv->current_selected < 0) completion->priv->current_selected = 0; } else { - completion->priv->current_selected -= 14; + completion->priv->current_selected -= PAGE_STEP; if (completion->priv->current_selected < matches - 1) completion->priv->current_selected = matches - 1; } @@ -9547,7 +9463,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, completion->priv->current_selected = 0; else if (completion->priv->current_selected < matches - 1) { - completion->priv->current_selected += 14; + completion->priv->current_selected += PAGE_STEP; if (completion->priv->current_selected > matches - 1) completion->priv->current_selected = matches - 1; } @@ -9557,7 +9473,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, } else { - completion->priv->current_selected += 14; + completion->priv->current_selected += PAGE_STEP; if (completion->priv->current_selected > matches + actions - 1) completion->priv->current_selected = matches + actions - 1; } @@ -9656,14 +9572,15 @@ gtk_entry_completion_key_press (GtkWidget *widget, gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), ""); } - /* Move the cursor to the end for Right/Esc, to the - beginning for Left */ + /* Move the cursor to the end for Right/Esc */ 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); + /* Let the default keybindings run for Left, i.e. either move to the + * previous character or select word if a modifier is used */ else - gtk_editable_set_position (GTK_EDITABLE (widget), 0); + retval = FALSE; } keypress_completion_out: @@ -9679,18 +9596,13 @@ keypress_completion_out: event->keyval == GDK_KEY_KP_Tab || event->keyval == GDK_KEY_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)); _gtk_entry_completion_popdown (completion); g_free (completion->priv->completion_prefix); completion->priv->completion_prefix = NULL; - gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir); - - return TRUE; + return FALSE; } else if (event->keyval == GDK_KEY_ISO_Enter || event->keyval == GDK_KEY_KP_Enter || @@ -9965,6 +9877,12 @@ gtk_entry_set_completion (GtkEntry *entry, old->priv->completion_timeout = 0; } + if (old->priv->check_completion_idle) + { + g_source_destroy (old->priv->check_completion_idle); + old->priv->check_completion_idle = NULL; + } + if (gtk_widget_get_mapped (old->priv->popup_window)) _gtk_entry_completion_popdown (old); @@ -10249,9 +10167,15 @@ gtk_entry_progress_pulse (GtkEntry *entry) * @entry: a #GtkEntry * @text: a string to be displayed when @entry is empty an unfocused, or %NULL * - * Sets text to be displayed in @entry when - * it is empty and unfocused. This can be used to give a visual hint - * of the expected contents of the #GtkEntry. + * Sets text to be displayed in @entry when it is empty and unfocused. + * This can be used to give a visual hint of the expected contents of + * the #GtkEntry. + * + * Note that since the placeholder text gets removed when the entry + * received focus, using this feature is a bit problematic if the entry + * is given the initial focus in a window. Sometimes this can be + * worked around by delaying the initial focus setting until the + * first key event arrives. * * Since: 3.2 **/ @@ -10287,7 +10211,7 @@ gtk_entry_set_placeholder_text (GtkEntry *entry, * * Since: 3.2 **/ -G_CONST_RETURN gchar * +const gchar * gtk_entry_get_placeholder_text (GtkEntry *entry) { GtkEntryPrivate *priv; @@ -10341,12 +10265,7 @@ keymap_state_changed (GdkKeymap *keymap, if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL && priv->caps_lock_warning) { - 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)) + if (gdk_keymap_get_caps_lock_state (keymap)) text = _("Caps Lock is on"); }