/* * Copyright (C) 2004-2006 Christian Hammond. * Copyright (C) 2008 Cody Russell * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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. */ #include "gtkiconentry.h" #if GTK_CHECK_VERSION (2, 16, 0) void gtk_icon_entry_set_icon_from_pixbuf (GtkEntry* entry, GtkEntryIconPosition position, GdkPixbuf* pixbuf) { gboolean activatable; /* Without this ugly hack pixbuf icons don't work */ activatable = gtk_entry_get_icon_activatable (entry, position); gtk_entry_set_icon_from_pixbuf (entry, position, pixbuf); gtk_entry_set_icon_activatable (entry, position, !activatable); gtk_entry_set_icon_activatable (entry, position, activatable); } #else #include #if GTK_CHECK_VERSION (2, 14, 0) #define _GTK_IMAGE_GICON GTK_IMAGE_GICON #else #define _GTK_IMAGE_GICON 8 #endif #ifndef GTK_PARAM_READABLE #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB #endif #ifndef GTK_PARAM_WRITABLE #define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB #endif #ifndef GTK_PARAM_READWRITE #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB #endif #define P_(s) (s) #define ICON_MARGIN 2 #define MAX_ICONS 2 #define IS_VALID_ICON_ENTRY_POSITION(pos) \ ((pos) == GTK_ICON_ENTRY_PRIMARY || \ (pos) == GTK_ICON_ENTRY_SECONDARY) typedef struct { GdkPixbuf *pixbuf; gboolean highlight; gboolean hovered; GdkWindow *window; gchar *tooltip_text; GdkCursorType cursor_type; gboolean custom_cursor; GtkImageType storage_type; GIcon *gicon; gchar *icon_name; gboolean insensitive; } EntryIconInfo; struct _GtkIconEntryPrivate { gdouble fraction; EntryIconInfo icons[MAX_ICONS]; gulong icon_released_id; }; enum { ICON_PRESSED, ICON_RELEASED, LAST_SIGNAL }; enum { PROP_0, PROP_PIXBUF_PRIMARY, PROP_PIXBUF_SECONDARY, PROP_STOCK_PRIMARY, PROP_STOCK_SECONDARY, PROP_ICON_NAME_PRIMARY, PROP_ICON_NAME_SECONDARY, PROP_GICON_PRIMARY, PROP_GICON_SECONDARY, PROP_SENSITIVITY_PRIMARY, PROP_SENSITIVITY_SECONDARY }; static void gtk_icon_entry_editable_init (GtkEditableClass *iface); static void gtk_icon_entry_finalize (GObject *obj); static void gtk_icon_entry_dispose (GObject *obj); static void gtk_icon_entry_map (GtkWidget *widget); static void gtk_icon_entry_unmap (GtkWidget *widget); static void gtk_icon_entry_realize (GtkWidget *widget); static void gtk_icon_entry_unrealize (GtkWidget *widget); static void gtk_icon_entry_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_icon_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint gtk_icon_entry_expose (GtkWidget *widget, GdkEventExpose *event); static gint gtk_icon_entry_enter_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_icon_entry_leave_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_icon_entry_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_icon_entry_button_release (GtkWidget *widget, GdkEventButton *event); static void gtk_icon_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gtk_icon_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gtk_icon_entry_style_set (GtkWidget *widget, GtkStyle *prev_style); static void gtk_icon_entry_set_icon_internal (GtkIconEntry *entry, GtkIconEntryPosition icon_pos, GdkPixbuf *pixbuf); static void icon_theme_changed (GtkIconEntry *entry); static GtkEntryClass *parent_class = NULL; static guint signals[LAST_SIGNAL] = {0}; G_DEFINE_TYPE_EXTENDED (GtkIconEntry, gtk_icon_entry, GTK_TYPE_ENTRY, 0, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_icon_entry_editable_init)); static void gtk_icon_entry_class_init (GtkIconEntryClass *klass) { GObjectClass *gobject_class; GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkEntryClass *entry_class; parent_class = g_type_class_peek_parent(klass); gobject_class = G_OBJECT_CLASS(klass); object_class = GTK_OBJECT_CLASS(klass); widget_class = GTK_WIDGET_CLASS(klass); entry_class = GTK_ENTRY_CLASS(klass); gobject_class->finalize = gtk_icon_entry_finalize; gobject_class->dispose = gtk_icon_entry_dispose; gobject_class->set_property = gtk_icon_entry_set_property; gobject_class->get_property = gtk_icon_entry_get_property; widget_class->map = gtk_icon_entry_map; widget_class->unmap = gtk_icon_entry_unmap; widget_class->realize = gtk_icon_entry_realize; widget_class->unrealize = gtk_icon_entry_unrealize; widget_class->size_request = gtk_icon_entry_size_request; widget_class->size_allocate = gtk_icon_entry_size_allocate; widget_class->expose_event = gtk_icon_entry_expose; widget_class->enter_notify_event = gtk_icon_entry_enter_notify; widget_class->leave_notify_event = gtk_icon_entry_leave_notify; widget_class->button_press_event = gtk_icon_entry_button_press; widget_class->button_release_event = gtk_icon_entry_button_release; widget_class->style_set = gtk_icon_entry_style_set; /** * GtkIconEntry::icon-pressed: * @entry: The entry on which the signal is emitted. * @icon_pos: The position of the clicked icon. * @button: The mouse button clicked. * * The ::icon-pressed signal is emitted when an icon is clicked. */ if (!(signals[ICON_PRESSED] = g_signal_lookup ("icon-pressed", GTK_TYPE_ENTRY))) signals[ICON_PRESSED] = g_signal_new ("icon-pressed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GtkIconEntryClass, icon_pressed), NULL, NULL, gtk_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); /** * GtkIconEntry::icon-release: * @entry: The entry on which the signal is emitted. * @icon_pos: The position of the clicked icon. * @button: The mouse button clicked. * * The ::icon-release signal is emitted on the button release from a * mouse click. */ if (!(signals[ICON_RELEASED] = g_signal_lookup ("icon-release", GTK_TYPE_ENTRY))) signals[ICON_RELEASED] = g_signal_new ("icon-release", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GtkIconEntryClass, icon_released), NULL, NULL, gtk_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); /** * GtkIconEntry:pixbuf-primary: * * An image to use as the primary icon for the entry. */ g_object_class_install_property (gobject_class, PROP_PIXBUF_PRIMARY, g_param_spec_object ("pixbuf-primary", P_("Primary pixbuf"), P_("Primary pixbuf for the entry"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); /** * GtkIconEntry:pixbuf-secondary: * * An image to use as the secondary icon for the entry. */ g_object_class_install_property (gobject_class, PROP_PIXBUF_SECONDARY, g_param_spec_object ("pixbuf-secondary", P_("Secondary pixbuf"), P_("Secondary pixbuf for the entry"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_STOCK_PRIMARY, g_param_spec_string ("stock-primary", P_("Primary stock ID"), P_("Stock ID for primary icon"), NULL, GTK_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_STOCK_SECONDARY, g_param_spec_string ("stock-secondary", P_("Secondary stock ID"), P_("Stock ID for secondary icon"), NULL, GTK_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_ICON_NAME_PRIMARY, g_param_spec_string ("icon-name-primary", P_("Primary icon name"), P_("Icon name for primary icon"), NULL, GTK_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_ICON_NAME_SECONDARY, g_param_spec_string ("icon-name-secondary", P_("Secondary icon name"), P_("Icon name for secondary icon"), NULL, GTK_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_GICON_PRIMARY, g_param_spec_object ("gicon-primary", P_("Primary GIcon"), P_("GIcon for primary icon"), G_TYPE_ICON, GTK_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_GICON_SECONDARY, g_param_spec_object ("gicon-secondary", P_("Secondary GIcon"), P_("GIcon for secondary icon"), G_TYPE_ICON, GTK_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (GtkIconEntryPrivate)); } static void gtk_icon_entry_editable_init (GtkEditableClass *iface) { }; /* GTK+/ GtkEntry internal helper function Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald Modified by the GTK+ Team and others 1997-2000 Copied from Gtk+ 2.13, whitespace adjusted */ static void gtk_entry_get_pixel_ranges (GtkEntry *entry, gint **ranges, gint *n_ranges) { gint start_char, end_char; if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char)) { PangoLayout *layout = gtk_entry_get_layout (entry); PangoLayoutLine *line = pango_layout_get_lines (layout)->data; const char *text = pango_layout_get_text (layout); gsize start_index = g_utf8_offset_to_pointer (text, start_char) - text; gsize end_index = g_utf8_offset_to_pointer (text, end_char) - text; gint real_n_ranges, i; pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges); if (ranges) { gint *r = *ranges; for (i = 0; i < real_n_ranges; ++i) { r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE; r[2 * i] = r[2 * i] / PANGO_SCALE; } } if (n_ranges) *n_ranges = real_n_ranges; } else { if (n_ranges) *n_ranges = 0; if (ranges) *ranges = NULL; } } /* GTK+/ GtkEntry internal helper function Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald Modified by the GTK+ Team and others 1997-2000 Copied from Gtk+ 2.13, whitespace adjusted Code adjusted to not rely on internal qdata */ static void _gtk_entry_effective_inner_border (GtkEntry *entry, GtkBorder *border) { static const GtkBorder default_inner_border = { 2, 2, 2, 2 }; GtkBorder *tmp_border; tmp_border = (GtkBorder*) gtk_entry_get_inner_border (entry); 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; } *border = default_inner_border; } static void gtk_entry_borders (GtkEntry* entry, gint* xborder, gint* yborder, gboolean* interior_focus, gint* focus_width) { GtkWidget *widget = GTK_WIDGET (entry); if (entry->has_frame) { *xborder = widget->style->xthickness; *yborder = widget->style->ythickness; } else { *xborder = 0; *yborder = 0; } gtk_widget_style_get (widget, "interior-focus", interior_focus, "focus-line-width", focus_width, NULL); if (interior_focus) { *xborder += *focus_width; *yborder += *focus_width; } } /* GTK+/ GtkEntry internal helper function Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald Modified by the GTK+ Team and others 1997-2000 Copied from Gtk+ 2.13, whitespace adjusted */ static void gtk_entry_get_text_area_size (GtkEntry *entry, gint *x, gint *y, gint *width, gint *height) { gint frame_height; gint xborder, yborder; gboolean interior_focus; gint focus_width; GtkRequisition requisition; GtkWidget *widget = GTK_WIDGET (entry); gtk_widget_get_child_requisition (widget, &requisition); gtk_entry_borders (entry, &xborder, &yborder, &interior_focus, &focus_width); if (GTK_WIDGET_REALIZED (widget)) gdk_drawable_get_size (widget->window, NULL, &frame_height); else frame_height = requisition.height; if (GTK_WIDGET_HAS_FOCUS (widget) && interior_focus) frame_height -= 2 * focus_width; if (x) *x = xborder; if (y) *y = frame_height / 2 - (requisition.height - yborder * 2) / 2; if (width) *width = GTK_WIDGET (entry)->allocation.width - xborder * 2; if (height) *height = requisition.height - yborder * 2; } /* GTK+/ GtkEntry internal helper function Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald Modified by the GTK+ Team and others 1997-2000 Copied from Gtk+ 2.13, whitespace adjusted */ static void get_layout_position (GtkEntry *entry, gint *x, gint *y) { PangoLayout *layout; PangoRectangle logical_rect; gint area_width, area_height; GtkBorder inner_border; gint y_pos; PangoLayoutLine *line; layout = gtk_entry_get_layout (entry); 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); line = pango_layout_get_lines (layout)->data; 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); /* 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; else if (y_pos < 0) y_pos = 0; 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; if (x) *x = inner_border.left - entry->scroll_offset; if (y) *y = y_pos; } /* GTK+/ GtkEntry internal helper function Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald Modified by the GTK+ Team and others 1997-2000 Copied from Gtk+ 2.13, whitespace adjusted Code adjusted to not rely on internal _gtk_entry_ensure_layout */ static void gtk_entry_draw_text (GtkEntry *entry) { GtkWidget *widget; if (!entry->visible && entry->invisible_char == 0) return; if (GTK_WIDGET_DRAWABLE (entry)) { PangoLayout *layout = gtk_entry_get_layout (entry); cairo_t *cr; gint x, y; gint start_pos, end_pos; widget = GTK_WIDGET (entry); get_layout_position (entry, &x, &y); cr = gdk_cairo_create (entry->text_area); cairo_move_to (cr, x, y); gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]); pango_cairo_show_layout (cr, layout); 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; pango_layout_get_pixel_extents (layout, NULL, &logical_rect); gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); 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]; } _gtk_entry_effective_inner_border (entry, &inner_border); 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); cairo_clip (cr); gdk_cairo_set_source_color (cr, selection_color); cairo_paint (cr); cairo_move_to (cr, x, y); gdk_cairo_set_source_color (cr, text_color); pango_cairo_show_layout (cr, layout); g_free (ranges); } cairo_destroy (cr); } } static gboolean entry_expose_event (GtkWidget* entry, GdkEventExpose* event, GtkIconEntry* icon_entry) { GtkIconEntryPrivate *priv; GdkWindow* text_area; gint width, height; priv = icon_entry->priv; text_area = GTK_ENTRY (entry)->text_area; gdk_drawable_get_size (text_area, &width, &height); if (priv->fraction > 0.0) { gtk_paint_box (entry->style, text_area, GTK_STATE_SELECTED, GTK_SHADOW_OUT, &event->area, entry, "entry-progress", 0, 0, priv->fraction * width, height); gtk_entry_draw_text (GTK_ENTRY (entry)); } return FALSE; } static void gtk_icon_entry_init (GtkIconEntry *entry) { entry->priv = G_TYPE_INSTANCE_GET_PRIVATE (entry, GTK_TYPE_ICON_ENTRY, GtkIconEntryPrivate); g_signal_connect_after (entry, "expose-event", G_CALLBACK (entry_expose_event), entry); } static void gtk_icon_entry_finalize (GObject *obj) { GtkIconEntry *entry; g_return_if_fail (obj != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY(obj)); entry = GTK_ICON_ENTRY (obj); G_OBJECT_CLASS (parent_class)->finalize (obj); } static void gtk_icon_entry_dispose (GObject *obj) { GtkIconEntry *entry; entry = GTK_ICON_ENTRY (obj); gtk_icon_entry_set_icon_from_pixbuf (entry, GTK_ICON_ENTRY_PRIMARY, NULL); gtk_icon_entry_set_icon_from_pixbuf (entry, GTK_ICON_ENTRY_SECONDARY, NULL); G_OBJECT_CLASS (parent_class)->dispose (obj); } static void gtk_icon_entry_map (GtkWidget *widget) { GtkIconEntryPrivate *priv; GdkCursor *cursor; if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget)) { int i; GTK_WIDGET_CLASS (parent_class)->map (widget); priv = GTK_ICON_ENTRY (widget)->priv; for (i = 0; i < MAX_ICONS; i++) { if (priv->icons[i].pixbuf != NULL) gdk_window_show (priv->icons[i].window); if (priv->icons[i].custom_cursor == TRUE && !priv->icons[i].insensitive) { cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), priv->icons[i].cursor_type); gdk_window_set_cursor (priv->icons[i].window, cursor); gdk_cursor_unref (cursor); } } GTK_WIDGET_CLASS (parent_class)->map (widget); } } static void gtk_icon_entry_unmap (GtkWidget *widget) { GtkIconEntryPrivate *priv; if (GTK_WIDGET_MAPPED (widget)) { int i; priv = GTK_ICON_ENTRY (widget)->priv; for (i = 0; i < MAX_ICONS; i++) { if (priv->icons[i].pixbuf != NULL) { gdk_window_hide (priv->icons[i].window); } } GTK_WIDGET_CLASS (parent_class)->unmap (widget); } } static void gtk_icon_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GtkIconEntry *entry = GTK_ICON_ENTRY (object); switch (prop_id) { case PROP_PIXBUF_PRIMARY: gtk_icon_entry_set_icon_from_pixbuf (entry, GTK_ICON_ENTRY_PRIMARY, g_value_get_object (value)); break; case PROP_PIXBUF_SECONDARY: gtk_icon_entry_set_icon_from_pixbuf (entry, GTK_ICON_ENTRY_SECONDARY, g_value_get_object (value)); break; case PROP_STOCK_PRIMARY: gtk_icon_entry_set_icon_from_stock (entry, GTK_ICON_ENTRY_PRIMARY, g_value_get_string (value)); break; case PROP_STOCK_SECONDARY: gtk_icon_entry_set_icon_from_stock (entry, GTK_ICON_ENTRY_SECONDARY, g_value_get_string (value)); break; case PROP_ICON_NAME_PRIMARY: gtk_icon_entry_set_icon_from_icon_name (entry, GTK_ICON_ENTRY_PRIMARY, g_value_get_string (value)); break; case PROP_ICON_NAME_SECONDARY: gtk_icon_entry_set_icon_from_icon_name (entry, GTK_ICON_ENTRY_SECONDARY, g_value_get_string (value)); break; case PROP_GICON_PRIMARY: gtk_icon_entry_set_icon_from_gicon (entry, GTK_ICON_ENTRY_PRIMARY, g_value_get_object (value)); break; case PROP_GICON_SECONDARY: gtk_icon_entry_set_icon_from_gicon (entry, GTK_ICON_ENTRY_SECONDARY, g_value_get_object (value)); break; } } static void gtk_icon_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtkIconEntry *entry = GTK_ICON_ENTRY (object); switch (prop_id) { case PROP_PIXBUF_PRIMARY: g_value_set_object (value, gtk_icon_entry_get_pixbuf (entry, GTK_ICON_ENTRY_PRIMARY)); break; case PROP_PIXBUF_SECONDARY: g_value_set_object (value, gtk_icon_entry_get_pixbuf (entry, GTK_ICON_ENTRY_SECONDARY)); break; case PROP_GICON_PRIMARY: g_value_set_object (value, gtk_icon_entry_get_gicon (entry, GTK_ICON_ENTRY_PRIMARY)); break; case PROP_GICON_SECONDARY: g_value_set_object (value, gtk_icon_entry_get_gicon (entry, GTK_ICON_ENTRY_SECONDARY)); } } static gint get_icon_width (GtkIconEntry *entry, GtkIconEntryPosition icon_pos) { gint menu_icon_width; gint width; GtkIconEntryPrivate *priv; EntryIconInfo *icon_info; priv = entry->priv; icon_info = &priv->icons[icon_pos]; if (icon_info->pixbuf == NULL) return 0; gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &menu_icon_width, NULL); width = MAX (gdk_pixbuf_get_width (icon_info->pixbuf), menu_icon_width); return width; } static void get_borders (GtkIconEntry *entry, gint *xborder, gint *yborder) { GtkWidget *widget = GTK_WIDGET (entry); gint focus_width; gboolean interior_focus; gtk_widget_style_get (widget, "interior-focus", &interior_focus, "focus-line-width", &focus_width, NULL); if (gtk_entry_get_has_frame (GTK_ENTRY (entry))) { *xborder = widget->style->xthickness; *yborder = widget->style->ythickness; } else { *xborder = 0; *yborder = 0; } if (!interior_focus) { *xborder += focus_width; *yborder += focus_width; } } static void get_text_area_size (GtkIconEntry *entry, GtkAllocation *alloc) { GtkWidget *widget = GTK_WIDGET (entry); GtkRequisition requisition; gint xborder, yborder; gtk_widget_get_child_requisition (widget, &requisition); get_borders (entry, &xborder, &yborder); alloc->x = xborder; alloc->y = yborder; alloc->width = widget->allocation.width - xborder * 2; alloc->height = requisition.height - yborder * 2; } static void get_icon_allocation (GtkIconEntry *icon_entry, gboolean left, GtkAllocation *widget_alloc, GtkAllocation *text_area_alloc, GtkAllocation *allocation, GtkIconEntryPosition *icon_pos) { gboolean rtl; rtl = (gtk_widget_get_direction (GTK_WIDGET (icon_entry)) == GTK_TEXT_DIR_RTL); if (left) *icon_pos = (rtl ? GTK_ICON_ENTRY_SECONDARY : GTK_ICON_ENTRY_PRIMARY); else *icon_pos = (rtl ? GTK_ICON_ENTRY_PRIMARY : GTK_ICON_ENTRY_SECONDARY); allocation->y = text_area_alloc->y; allocation->width = get_icon_width(icon_entry, *icon_pos); allocation->height = text_area_alloc->height; if (left) { allocation->x = text_area_alloc->x + ICON_MARGIN; } else { allocation->x = text_area_alloc->x + text_area_alloc->width - allocation->width - ICON_MARGIN; } } static void gtk_icon_entry_realize (GtkWidget *widget) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; GdkWindowAttr attributes; gint attributes_mask; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; GTK_WIDGET_CLASS (parent_class)->realize (widget); attributes.x = 0; attributes.y = 0; 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.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; for (i = 0; i < MAX_ICONS; i++) { EntryIconInfo *icon_info; icon_info = &priv->icons[i]; icon_info->window = gdk_window_new (widget->window, &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); } static void gtk_icon_entry_unrealize (GtkWidget *widget) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; GTK_WIDGET_CLASS (parent_class)->unrealize (widget); for (i = 0; i < MAX_ICONS; i++) { EntryIconInfo *icon_info = &priv->icons[i]; gdk_window_destroy (icon_info->window); icon_info->window = NULL; } } static void gtk_icon_entry_size_request (GtkWidget *widget, GtkRequisition *requisition) { GtkEntry *gtkentry; GtkIconEntry *entry; gint icon_widths = 0; int i; gtkentry = GTK_ENTRY(widget); entry = GTK_ICON_ENTRY(widget); for (i = 0; i < MAX_ICONS; i++) { int icon_width = get_icon_width (entry, i); if (icon_width > 0) { icon_widths += icon_width + ICON_MARGIN; } } GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition); if (icon_widths > requisition->width) requisition->width += icon_widths; } static void place_windows (GtkIconEntry *icon_entry, GtkAllocation *widget_alloc) { GtkIconEntryPosition left_icon_pos; GtkIconEntryPosition right_icon_pos; GtkAllocation left_icon_alloc; GtkAllocation right_icon_alloc; GtkAllocation text_area_alloc; GtkIconEntryPrivate *priv; gint y; priv = icon_entry->priv; get_text_area_size (icon_entry, &text_area_alloc); /* DJW center text/icon * TODO flicker needs to be eliminated */ gdk_window_get_geometry (GTK_ENTRY (icon_entry)->text_area, NULL, &y, NULL, NULL, NULL); text_area_alloc.y = y; get_icon_allocation (icon_entry, TRUE, widget_alloc, &text_area_alloc, &left_icon_alloc, &left_icon_pos); get_icon_allocation (icon_entry, FALSE, widget_alloc, &text_area_alloc, &right_icon_alloc, &right_icon_pos); if (left_icon_alloc.width > 0) { text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width + ICON_MARGIN; } if (right_icon_alloc.width > 0) { text_area_alloc.width -= right_icon_alloc.width + ICON_MARGIN; } text_area_alloc.width -= text_area_alloc.x; gdk_window_move_resize (priv->icons[left_icon_pos].window, left_icon_alloc.x, left_icon_alloc.y, left_icon_alloc.width, left_icon_alloc.height); gdk_window_move_resize (priv->icons[right_icon_pos].window, right_icon_alloc.x, right_icon_alloc.y, right_icon_alloc.width, right_icon_alloc.height); gdk_window_move_resize (GTK_ENTRY (icon_entry)->text_area, text_area_alloc.x, text_area_alloc.y, text_area_alloc.width, text_area_alloc.height); } static void gtk_icon_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { g_return_if_fail (GTK_IS_ICON_ENTRY(widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); if (GTK_WIDGET_REALIZED (widget)) place_windows (GTK_ICON_ENTRY (widget), allocation); } static GdkPixbuf * get_pixbuf_from_icon (GtkIconEntry *entry, GtkIconEntryPosition icon_pos) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; priv = entry->priv; icon_info = &priv->icons[icon_pos]; g_object_ref (icon_info->pixbuf); return icon_info->pixbuf; } /* Kudos to the gnome-panel guys. */ static void colorshift_pixbuf (GdkPixbuf *dest, GdkPixbuf *src, int 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 void draw_icon (GtkWidget *widget, GtkIconEntryPosition icon_pos) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; EntryIconInfo *icon_info; GdkPixbuf *pixbuf; gint x, y, width, height; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; icon_info = &priv->icons[icon_pos]; if (icon_info->pixbuf == NULL || !GTK_WIDGET_REALIZED (widget)) return; if ((pixbuf = get_pixbuf_from_icon (entry, icon_pos)) == NULL) return; gdk_drawable_get_size (icon_info->window, &width, &height); if (width == 1 || height == 1) { /* * size_allocate hasn't been called yet. These are the default values. */ return; } if (gdk_pixbuf_get_height (pixbuf) > height) { GdkPixbuf *temp_pixbuf; int scale; scale = height - (2 * 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; if (icon_info->insensitive) { GdkPixbuf *temp_pixbuf; temp_pixbuf = gdk_pixbuf_copy (pixbuf); gdk_pixbuf_saturate_and_pixelate (pixbuf, temp_pixbuf, 0.8f, TRUE); g_object_unref (pixbuf); pixbuf = temp_pixbuf; } else if (icon_info->hovered) { GdkPixbuf *temp_pixbuf; temp_pixbuf = gdk_pixbuf_copy (pixbuf); colorshift_pixbuf (temp_pixbuf, pixbuf, 30); g_object_unref (pixbuf); pixbuf = temp_pixbuf; } gdk_draw_pixbuf (icon_info->window, widget->style->black_gc, pixbuf, 0, 0, x, y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0); g_object_unref (pixbuf); } static gint gtk_icon_entry_expose (GtkWidget *widget, GdkEventExpose *event) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; g_return_val_if_fail (GTK_IS_ICON_ENTRY (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); entry = GTK_ICON_ENTRY (widget); priv = entry->priv; if (GTK_WIDGET_DRAWABLE (widget)) { gboolean found = FALSE; int i; for (i = 0; i < MAX_ICONS && !found; i++) { EntryIconInfo *icon_info = &priv->icons[i]; if (event->window == icon_info->window) { gint width; GtkAllocation text_area_alloc; get_text_area_size (entry, &text_area_alloc); gdk_drawable_get_size (icon_info->window, &width, NULL); gtk_paint_flat_box (widget->style, icon_info->window, GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE, NULL, widget, "entry_bg", 0, 0, width, text_area_alloc.height); draw_icon (widget, i); found = TRUE; } } if (!found) GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event); } return FALSE; } static gint gtk_icon_entry_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { if (event->window == priv->icons[i].window) { if (gtk_icon_entry_get_icon_highlight (entry, i)) { priv->icons[i].hovered = TRUE; if (priv->icons[i].tooltip_text != NULL) { gtk_widget_set_tooltip_text (widget, priv->icons[i].tooltip_text); gtk_widget_set_has_tooltip (widget, TRUE); } else { gtk_widget_set_has_tooltip (widget, FALSE); } gtk_widget_queue_draw (widget); break; } } } return FALSE; } static gint gtk_icon_entry_leave_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { if (event->window == priv->icons[i].window) { if (gtk_icon_entry_get_icon_highlight (entry, i)) { priv->icons[i].hovered = FALSE; gtk_widget_set_has_tooltip (widget, FALSE); gtk_widget_queue_draw (widget); break; } } } return FALSE; } static gint gtk_icon_entry_button_press (GtkWidget *widget, GdkEventButton *event) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { if (event->window == priv->icons[i].window) { if (event->button == 1 && gtk_icon_entry_get_icon_highlight (entry, i)) { priv->icons[i].hovered = FALSE; gtk_widget_queue_draw (widget); } g_signal_emit (entry, signals[ICON_PRESSED], 0, i, event->button); return TRUE; } } if (GTK_WIDGET_CLASS (parent_class)->button_press_event) return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); return FALSE; } static gint gtk_icon_entry_button_release (GtkWidget *widget, GdkEventButton *event) { GtkIconEntry *entry; GtkIconEntryPrivate *priv; int i; entry = GTK_ICON_ENTRY (widget); priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { GdkWindow *icon_window = priv->icons[i].window; if (event->window == icon_window) { int width, height; gdk_drawable_get_size (icon_window, &width, &height); if (event->button == 1 && gtk_icon_entry_get_icon_highlight (entry, i) && event->x >= 0 && event->y >= 0 && event->x <= width && event->y <= height) { priv->icons[i].hovered = TRUE; gtk_widget_queue_draw (widget); } g_signal_emit (entry, signals[ICON_RELEASED], 0, i, event->button); return TRUE; } } if (GTK_WIDGET_CLASS (parent_class)->button_release_event) return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event); return FALSE; } static void gtk_icon_entry_style_set (GtkWidget *widget, GtkStyle *prev_style) { GtkIconEntry *icon_entry; icon_entry = GTK_ICON_ENTRY (widget); if (GTK_WIDGET_CLASS (gtk_icon_entry_parent_class)->style_set) GTK_WIDGET_CLASS (gtk_icon_entry_parent_class)->style_set (widget, prev_style); icon_theme_changed (icon_entry); } static void icon_theme_changed (GtkIconEntry *entry) { GtkIconEntryPrivate *priv; int i; priv = entry->priv; for (i = 0; i < MAX_ICONS; i++) { if (priv->icons[i].storage_type == GTK_IMAGE_ICON_NAME) { g_object_unref (priv->icons[i].pixbuf); priv->icons[i].pixbuf = NULL; gtk_icon_entry_set_icon_from_icon_name (entry, i, priv->icons[i].icon_name); } #if GLIB_CHECK_VERSION (2, 16, 0) else if (priv->icons[i].storage_type == _GTK_IMAGE_GICON) { g_object_unref (priv->icons[i].pixbuf); priv->icons[i].pixbuf = NULL; gtk_icon_entry_set_icon_from_gicon (entry, i, priv->icons[i].gicon); } #endif } gtk_widget_queue_draw (GTK_WIDGET (entry)); } static void gtk_icon_entry_set_icon_internal (GtkIconEntry *entry, GtkIconEntryPosition icon_pos, GdkPixbuf *pixbuf) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); priv = entry->priv; icon_info = &priv->icons[icon_pos]; if (pixbuf == icon_info->pixbuf) return; if (icon_pos == GTK_ICON_ENTRY_SECONDARY && priv->icon_released_id != 0) { g_signal_handler_disconnect (entry, priv->icon_released_id); priv->icon_released_id = 0; } if (pixbuf == NULL) { if (icon_info->pixbuf != NULL) { g_object_unref (icon_info->pixbuf); icon_info->pixbuf = NULL; /* Explicitly check, as the pointer may become invalidated * during destruction. */ if (icon_info->window != NULL && GDK_IS_WINDOW (icon_info->window)) gdk_window_hide (icon_info->window); } } else { if (icon_info->window != NULL && icon_info->pixbuf == NULL) gdk_window_show (icon_info->window); icon_info->pixbuf = pixbuf; g_object_ref (pixbuf); } gtk_widget_queue_draw (GTK_WIDGET (entry)); } /** * gtk_icon_entry_new * * Creates a new GtkIconEntry widget. * * Returns a new #GtkIconEntry. */ GtkWidget * gtk_icon_entry_new (void) { return GTK_WIDGET (g_object_new (GTK_TYPE_ICON_ENTRY, NULL)); } /** * gtk_icon_entry_set_icon_from_pixbuf * @entry: A #GtkIconEntry. * @position: Icon position. * @pixbuf: A #GdkPixbuf. * * Sets the icon shown in the specified position using a pixbuf. */ void gtk_icon_entry_set_icon_from_pixbuf (GtkIconEntry *entry, GtkIconEntryPosition icon_pos, GdkPixbuf *pixbuf) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); priv = entry->priv; icon_info = &priv->icons[icon_pos]; if (pixbuf == icon_info->pixbuf) return; if (icon_pos == GTK_ICON_ENTRY_SECONDARY && priv->icon_released_id != 0) { g_signal_handler_disconnect (entry, priv->icon_released_id); priv->icon_released_id = 0; } if (pixbuf == NULL) { if (icon_info->pixbuf != NULL) { g_object_unref (icon_info->pixbuf); icon_info->pixbuf = NULL; /* Explicitly check, as the pointer may become invalidated * during destruction. */ if (icon_info->window != NULL && GDK_IS_WINDOW (icon_info->window)) gdk_window_hide (icon_info->window); } } else { if (icon_info->window != NULL && icon_info->pixbuf == NULL) gdk_window_show (icon_info->window); icon_info->pixbuf = pixbuf; g_object_ref (pixbuf); } gtk_widget_queue_draw (GTK_WIDGET (entry)); } /** * gtk_icon_entry_set_icon_from_stock * @entry: A #GtkIconEntry. * @position: Icon position. * @stock_id: The name of the stock item. * * Sets the icon shown in the entry at the specified position from a stock image. */ void gtk_icon_entry_set_icon_from_stock (GtkIconEntry *entry, GtkIconEntryPosition icon_pos, const gchar *stock_id) { GdkPixbuf *pixbuf; /* FIXME: Due to a bug in GtkIconEntry we need to set a non-NULL icon */ if (! stock_id) stock_id = GTK_STOCK_INFO; pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), stock_id, GTK_ICON_SIZE_MENU, NULL); gtk_icon_entry_set_icon_internal (entry, icon_pos, pixbuf); } /** * gtk_icon_entry_set_icon_from_icon_name * @entry: A #GtkIconEntry; * @icon_pos: The position at which to set the icon * @icon_name: An icon name * * Sets the icon shown in the entry at the specified position from the current * icon theme. If the icon name isn't known, a "broken image" icon will be * displayed instead. If the current icon theme is changed, the icon will be * updated appropriately. */ void gtk_icon_entry_set_icon_from_icon_name (GtkIconEntry *entry, GtkIconEntryPosition icon_pos, const gchar *icon_name) { GdkPixbuf *pixbuf = NULL; EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; GdkScreen *screen; GtkIconTheme *icon_theme; GtkSettings *settings; gint width, height; GError *error = NULL; g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); priv = entry->priv; icon_info = &priv->icons[icon_pos]; screen = gtk_widget_get_screen (GTK_WIDGET (entry)); icon_theme = gtk_icon_theme_get_for_screen (screen); settings = gtk_settings_get_for_screen (screen); if (icon_name != NULL) { gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height); pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name, MIN (width, height), 0, &error); if (pixbuf == NULL) { g_error_free (error); pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); } } gtk_icon_entry_set_icon_internal (entry, icon_pos, pixbuf); } /** * gtk_icon_entry_set_icon_from_gicon * @entry: A #GtkIconEntry; * @icon_pos: The position at which to set the icon * @icon: The icon to set * * Sets the icon shown in the entry at the specified position from the current * icon theme. If the icon isn't known, a "broken image" icon will be displayed * instead. If the current icon theme is changed, the icon will be updated * appropriately. */ void gtk_icon_entry_set_icon_from_gicon (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos, GIcon *icon) { GdkPixbuf *pixbuf = NULL; GtkIconEntryPrivate *priv; EntryIconInfo *icon_info; GdkScreen *screen; GtkIconTheme *icon_theme; GtkSettings *settings; gint width, height; GError *error = NULL; GtkIconInfo *info; priv = entry->priv; icon_info = &priv->icons[icon_pos]; screen = gtk_widget_get_screen (GTK_WIDGET (entry)); icon_theme = gtk_icon_theme_get_for_screen (screen); settings = gtk_settings_get_for_screen (screen); if (icon != NULL) { gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height); #if GTK_CHECK_VERSION (2, 14, 0) info = gtk_icon_theme_lookup_by_gicon (icon_theme, icon, MIN (width, height), 0); #else info = NULL; #endif pixbuf = gtk_icon_info_load_icon (info, &error); if (pixbuf == NULL) { g_error_free (error); pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); } } gtk_icon_entry_set_icon_internal ((GtkIconEntry*)entry, icon_pos, pixbuf); } /** * gtk_icon_entry_set_cursor * @entry: A #GtkIconEntry; * @icon_pos: The position at which to set the cursor * @cursor_type: A #GdkCursorType; describing the cursor to set * * Sets an alternate mouse cursor used for the specified icon. */ void gtk_icon_entry_set_cursor (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos, GdkCursorType cursor_type) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; GdkCursor *cursor; priv = entry->priv; icon_info = &priv->icons[icon_pos]; icon_info->cursor_type = cursor_type; icon_info->custom_cursor = TRUE; if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry))) { cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (entry)), cursor_type); gdk_window_set_cursor (icon_info->window, cursor); gdk_cursor_unref (cursor); } } /** * gtk_icon_entry_set_icon_highlight * @entry: A #GtkIconEntry; * @position: Icon position. * @highlight: TRUE if the icon should highlight on mouse-over * * Determines whether the icon will highlight on mouse-over. */ void gtk_icon_entry_set_icon_highlight (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos, gboolean highlight) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; priv = entry->priv; g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); icon_info = &priv->icons[icon_pos]; if (icon_info->highlight == highlight) return; icon_info->highlight = highlight; } /** * gtk_icon_entry_get_pixbuf * @entry: A #GtkIconEntry. * @position: Icon position. * * Retrieves the image used for the icon. Unlike the other methods of setting * and getting icon data, this 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. */ GdkPixbuf * gtk_icon_entry_get_pixbuf (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos) { GtkIconEntryPrivate *priv; g_return_val_if_fail (entry != NULL, NULL); g_return_val_if_fail (GTK_IS_ICON_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos), NULL); priv = entry->priv; return priv->icons[icon_pos].pixbuf; } /** * gtk_icon_entry_get_gicon * @entry: A #GtkIconEntry * @position: Icon position. * * Retrieves the GIcon used for the icon, or NULL if there is 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. */ GIcon * gtk_icon_entry_get_gicon (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos) { GtkIconEntryPrivate *priv; EntryIconInfo *icon_info; g_return_val_if_fail (entry != NULL, NULL); g_return_val_if_fail (GTK_IS_ICON_ENTRY (entry), NULL); g_return_val_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos), NULL); priv = entry->priv; icon_info = &priv->icons[icon_pos]; return icon_info->storage_type == _GTK_IMAGE_GICON ? icon_info->gicon : NULL; } /** * gtk_icon_entry_get_icon_highlight * @entry: A #GtkIconEntry. * @position: Icon position. * * Retrieves whether entry will highlight the icon on mouseover. * * Returns: TRUE if icon highlights. */ gboolean gtk_icon_entry_get_icon_highlight (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos) { GtkIconEntryPrivate *priv; g_return_val_if_fail (entry != NULL, FALSE); g_return_val_if_fail (GTK_IS_ICON_ENTRY (entry), FALSE); g_return_val_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos), FALSE); priv = entry->priv; return priv->icons[icon_pos].highlight; } /** * gtk_icon_entry_set_tooltip * @entry: A #GtkIconEntry. * @position: Icon position. * @text: The text to be used for the tooltip. * * Sets the tooltip text used for the specified icon. */ void gtk_icon_entry_set_tooltip (const GtkIconEntry *entry, GtkIconEntryPosition icon_pos, const gchar *text) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; gchar *new_tooltip; g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); priv = entry->priv; icon_info = &priv->icons[icon_pos]; new_tooltip = g_strdup (text); if (icon_info->tooltip_text != NULL) g_free (icon_info->tooltip_text); icon_info->tooltip_text = new_tooltip; } /** * gtk_icon_entry_set_icon_sensitive * @entry: A #GtkIconEntry. * @position: Icon position. * @sensitive: Specifies whether the icon should appear sensitive or insensitive. * * Sets the sensitivity for the specified icon. */ void gtk_icon_entry_set_icon_sensitive (const GtkIconEntry *icon_entry, GtkIconEntryPosition icon_pos, gboolean sensitive) { EntryIconInfo *icon_info; GtkIconEntryPrivate *priv; g_return_if_fail (icon_entry != NULL); g_return_if_fail (GTK_IS_ICON_ENTRY (icon_entry)); g_return_if_fail (IS_VALID_ICON_ENTRY_POSITION (icon_pos)); priv = icon_entry->priv; icon_info = &priv->icons[icon_pos]; icon_info->insensitive = !sensitive; if (icon_info->custom_cursor == TRUE && GTK_WIDGET_REALIZED (GTK_WIDGET (icon_entry))) { GdkCursor *cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (icon_entry)), sensitive ? icon_info->cursor_type : GDK_ARROW); gdk_window_set_cursor (icon_info->window, cursor); gdk_cursor_unref (cursor); } } void gtk_icon_entry_set_progress_fraction (GtkIconEntry *icon_entry, gdouble fraction) { GtkIconEntryPrivate *priv; g_return_if_fail (GTK_IS_ICON_ENTRY (icon_entry)); priv = icon_entry->priv; priv->fraction = CLAMP (fraction, 0.0, 1.0); if (GTK_ENTRY (icon_entry)->text_area) gdk_window_invalidate_rect (GTK_ENTRY (icon_entry)->text_area, NULL, FALSE); } #endif