midori/midori/gtkiconentry.c
2010-04-17 01:42:09 +02:00

1933 lines
50 KiB
C

/*
* Copyright (C) 2004-2006 Christian Hammond.
* Copyright (C) 2008 Cody Russell <bratsche@gnome.org>
*
* 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 <string.h>
#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