1603 lines
41 KiB
C
1603 lines
41 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"
|
|
|
|
#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)
|
|
|
|
#define GTK_ICON_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ICON_ENTRY, GtkIconEntryPrivate))
|
|
|
|
typedef struct
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
gboolean highlight;
|
|
gboolean hovered;
|
|
GdkWindow *window;
|
|
gchar *tooltip_text;
|
|
GdkCursorType cursor_type;
|
|
gboolean custom_cursor;
|
|
GtkImageType storage_type;
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
GIcon *gicon;
|
|
#endif
|
|
gchar *icon_name;
|
|
gboolean insensitive;
|
|
} EntryIconInfo;
|
|
|
|
typedef struct _GtkIconEntryPrivate
|
|
{
|
|
EntryIconInfo icons[MAX_ICONS];
|
|
|
|
gulong icon_released_id;
|
|
} GtkIconEntryPrivate;
|
|
|
|
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_class_init (GtkIconEntryClass *klass);
|
|
static void gtk_icon_entry_editable_init (GtkEditableClass *iface);
|
|
static void gtk_icon_entry_init (GtkIconEntry *entry);
|
|
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.
|
|
*/
|
|
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-released:
|
|
* @entry: The entry on which the signal is emitted.
|
|
* @icon_pos: The position of the clicked icon.
|
|
* @button: The mouse button clicked.
|
|
*
|
|
* The ::icon-released signal is emitted on the button release from a
|
|
* mouse click.
|
|
*/
|
|
signals[ICON_RELEASED] =
|
|
g_signal_new ("icon_released",
|
|
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));
|
|
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
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));
|
|
#endif
|
|
|
|
g_type_class_add_private (klass, sizeof (GtkIconEntryPrivate));
|
|
}
|
|
|
|
static void
|
|
gtk_icon_entry_editable_init (GtkEditableClass *iface)
|
|
{
|
|
};
|
|
|
|
static void
|
|
gtk_icon_entry_init (GtkIconEntry *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_GET_PRIVATE (widget);
|
|
|
|
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_GET_PRIVATE (widget);
|
|
|
|
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;
|
|
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
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;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
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));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static gint
|
|
get_icon_width (GtkIconEntry *entry, GtkIconEntryPosition icon_pos)
|
|
{
|
|
gint menu_icon_width;
|
|
gint width;
|
|
GtkIconEntryPrivate *priv;
|
|
EntryIconInfo *icon_info;
|
|
|
|
priv = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (icon_entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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;
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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.
|
|
*/
|
|
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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.
|
|
*/
|
|
|
|
|
|
#if GLIB_CHECK_VERSION (2, 16, 0)
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
icon_info = &priv->icons[icon_pos];
|
|
|
|
return icon_info->storage_type == _GTK_IMAGE_GICON ? icon_info->gicon : NULL;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (entry);
|
|
|
|
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 = GTK_ICON_ENTRY_GET_PRIVATE (icon_entry);
|
|
|
|
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);
|
|
}
|
|
}
|