/* * libsexy/sexy-icon-entry.c Entry widget * Copyright (C) 2004-2006 Christian Hammond. * modified for NetSurf * Copyright 2009 Mark Benjamin * * This file is part of NetSurf, http://www.netsurf-browser.org/ * This file before modifications was originally part of LibSexy, * http://www.chipx86.com/; it is redistributed under GPLv2 * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * or write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gtk/sexy_icon_entry.h" #include #include #define ICON_MARGIN 2 #define MAX_ICONS 2 #define IS_VALID_ICON_ENTRY_POSITION(pos) \ ((pos) == SEXY_ICON_ENTRY_PRIMARY || \ (pos) == SEXY_ICON_ENTRY_SECONDARY) typedef struct { GtkImage *icon; gboolean highlight; gboolean hovered; GdkWindow *window; } SexyIconInfo; struct _SexyIconEntryPriv { SexyIconInfo icons[MAX_ICONS]; gulong icon_released_id; }; enum { ICON_PRESSED, ICON_RELEASED, LAST_SIGNAL }; /* static void sexy_icon_entry_class_init(SexyIconEntryClass *klass); */ static void sexy_icon_entry_editable_init(GtkEditableClass *iface); /* static void sexy_icon_entry_init(SexyIconEntry *entry); */ static void sexy_icon_entry_finalize(GObject *obj); static void sexy_icon_entry_destroy(GtkObject *obj); static void sexy_icon_entry_map(GtkWidget *widget); static void sexy_icon_entry_unmap(GtkWidget *widget); static void sexy_icon_entry_realize(GtkWidget *widget); static void sexy_icon_entry_unrealize(GtkWidget *widget); static void sexy_icon_entry_size_request(GtkWidget *widget, GtkRequisition *requisition); static void sexy_icon_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation); static gint sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event); static gint sexy_icon_entry_enter_notify(GtkWidget *widget, GdkEventCrossing *event); static gint sexy_icon_entry_leave_notify(GtkWidget *widget, GdkEventCrossing *event); static gint sexy_icon_entry_button_press(GtkWidget *widget, GdkEventButton *event); static gint sexy_icon_entry_button_release(GtkWidget *widget, GdkEventButton *event); static GtkEntryClass *parent_class = NULL; static guint signals[LAST_SIGNAL] = {0}; G_DEFINE_TYPE_EXTENDED(SexyIconEntry, sexy_icon_entry, GTK_TYPE_ENTRY, 0, G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE, sexy_icon_entry_editable_init)); void sexy_icon_entry_class_init(SexyIconEntryClass *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 = sexy_icon_entry_finalize; object_class->destroy = sexy_icon_entry_destroy; widget_class->map = sexy_icon_entry_map; widget_class->unmap = sexy_icon_entry_unmap; widget_class->realize = sexy_icon_entry_realize; widget_class->unrealize = sexy_icon_entry_unrealize; widget_class->size_request = sexy_icon_entry_size_request; widget_class->size_allocate = sexy_icon_entry_size_allocate; widget_class->expose_event = sexy_icon_entry_expose; widget_class->enter_notify_event = sexy_icon_entry_enter_notify; widget_class->leave_notify_event = sexy_icon_entry_leave_notify; widget_class->button_press_event = sexy_icon_entry_button_press; widget_class->button_release_event = sexy_icon_entry_button_release; /** * SexyIconEntry::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. */ /* signal modified to compile directly in NetSurf - param 8 of * g_signal_new() changed from marshal type to NULL - so there may * well be no working signal */ signals[ICON_PRESSED] = g_signal_new("icon_pressed", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(SexyIconEntryClass, icon_pressed), NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); /** * SexyIconEntry::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. */ /* signal modified to compile directly in NetSurf - param 8 of * g_signal_new() changed from marshal type to NULL - so there may * well be no working signal */ signals[ICON_RELEASED] = g_signal_new("icon_released", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(SexyIconEntryClass, icon_released), NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); } static void sexy_icon_entry_editable_init(GtkEditableClass *iface) { }; void sexy_icon_entry_init(SexyIconEntry *entry) { entry->priv = g_new0(SexyIconEntryPriv, 1); } static void sexy_icon_entry_finalize(GObject *obj) { SexyIconEntry *entry; g_return_if_fail(obj != NULL); g_return_if_fail(SEXY_IS_ICON_ENTRY(obj)); entry = SEXY_ICON_ENTRY(obj); g_free(entry->priv); if (G_OBJECT_CLASS(parent_class)->finalize) G_OBJECT_CLASS(parent_class)->finalize(obj); } static void sexy_icon_entry_destroy(GtkObject *obj) { SexyIconEntry *entry; entry = SEXY_ICON_ENTRY(obj); sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_PRIMARY, NULL); sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_SECONDARY, NULL); if (GTK_OBJECT_CLASS(parent_class)->destroy) GTK_OBJECT_CLASS(parent_class)->destroy(obj); } static void sexy_icon_entry_map(GtkWidget *widget) { if (GTK_WIDGET_REALIZED(widget) && !GTK_WIDGET_MAPPED(widget)) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; GTK_WIDGET_CLASS(parent_class)->map(widget); for (i = 0; i < MAX_ICONS; i++) { if (entry->priv->icons[i].icon != NULL) gdk_window_show(entry->priv->icons[i].window); } } } static void sexy_icon_entry_unmap(GtkWidget *widget) { if (GTK_WIDGET_MAPPED(widget)) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; for (i = 0; i < MAX_ICONS; i++) { if (entry->priv->icons[i].icon != NULL) gdk_window_hide(entry->priv->icons[i].window); } GTK_WIDGET_CLASS(parent_class)->unmap(widget); } } static gint get_icon_width(SexyIconEntry *entry, SexyIconEntryPosition icon_pos) { GtkRequisition requisition; gint menu_icon_width; gint width; SexyIconInfo *icon_info = &entry->priv->icons[icon_pos]; if (icon_info->icon == NULL) return 0; gtk_widget_size_request(GTK_WIDGET(icon_info->icon), &requisition); gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &menu_icon_width, NULL); width = MAX(requisition.width, menu_icon_width); return width; } static void get_borders(SexyIconEntry *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(SexyIconEntry *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(SexyIconEntry *icon_entry, gboolean left, GtkAllocation *widget_alloc, GtkAllocation *text_area_alloc, GtkAllocation *allocation, SexyIconEntryPosition *icon_pos) { gboolean rtl; rtl = (gtk_widget_get_direction(GTK_WIDGET(icon_entry)) == GTK_TEXT_DIR_RTL); if (left) *icon_pos = (rtl ? SEXY_ICON_ENTRY_SECONDARY : SEXY_ICON_ENTRY_PRIMARY); else *icon_pos = (rtl ? SEXY_ICON_ENTRY_PRIMARY : SEXY_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 sexy_icon_entry_realize(GtkWidget *widget) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); GdkWindowAttr attributes; gint attributes_mask; int i; 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++) { SexyIconInfo *icon_info; icon_info = &entry->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 sexy_icon_entry_unrealize(GtkWidget *widget) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; GTK_WIDGET_CLASS(parent_class)->unrealize(widget); for (i = 0; i < MAX_ICONS; i++) { SexyIconInfo *icon_info = &entry->priv->icons[i]; gdk_window_destroy(icon_info->window); icon_info->window = NULL; } } static void sexy_icon_entry_size_request(GtkWidget *widget, GtkRequisition *requisition) { GtkEntry *gtkentry; SexyIconEntry *entry; gint icon_widths = 0; int i; gtkentry = GTK_ENTRY(widget); entry = SEXY_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(SexyIconEntry *icon_entry, GtkAllocation *widget_alloc) { SexyIconEntryPosition left_icon_pos; SexyIconEntryPosition right_icon_pos; GtkAllocation left_icon_alloc; GtkAllocation right_icon_alloc; GtkAllocation text_area_alloc; get_text_area_size(icon_entry, &text_area_alloc); 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(icon_entry->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(icon_entry->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 sexy_icon_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { g_return_if_fail(SEXY_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(SEXY_ICON_ENTRY(widget), allocation); } static GdkPixbuf * get_pixbuf_from_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos) { GdkPixbuf *pixbuf = NULL; gchar *stock_id; SexyIconInfo *icon_info = &entry->priv->icons[icon_pos]; GtkIconSize size; switch (gtk_image_get_storage_type(GTK_IMAGE(icon_info->icon))) { case GTK_IMAGE_PIXBUF: pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(icon_info->icon)); g_object_ref(pixbuf); break; case GTK_IMAGE_STOCK: gtk_image_get_stock(GTK_IMAGE(icon_info->icon), &stock_id, &size); pixbuf = gtk_widget_render_icon(GTK_WIDGET(entry), stock_id, size, NULL); break; default: return NULL; } return 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, SexyIconEntryPosition icon_pos) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); SexyIconInfo *icon_info = &entry->priv->icons[icon_pos]; GdkPixbuf *pixbuf; gint x, y, width, height; if (icon_info->icon == 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->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 sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event) { SexyIconEntry *entry; g_return_val_if_fail(SEXY_IS_ICON_ENTRY(widget), FALSE); g_return_val_if_fail(event != NULL, FALSE); entry = SEXY_ICON_ENTRY(widget); if (GTK_WIDGET_DRAWABLE(widget)) { gboolean found = FALSE; int i; for (i = 0; i < MAX_ICONS && !found; i++) { SexyIconInfo *icon_info = &entry->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 void update_icon(GObject *obj, GParamSpec *param, SexyIconEntry *entry) { if (param != NULL) { const char *name = g_param_spec_get_name(param); if (strcmp(name, "pixbuf") && strcmp(name, "stock") && strcmp(name, "image") && strcmp(name, "pixmap") && strcmp(name, "icon_set") && strcmp(name, "pixbuf_animation")) { return; } } gtk_widget_queue_resize(GTK_WIDGET(entry)); } static gint sexy_icon_entry_enter_notify(GtkWidget *widget, GdkEventCrossing *event) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; for (i = 0; i < MAX_ICONS; i++) { if (event->window == entry->priv->icons[i].window) { if (sexy_icon_entry_get_icon_highlight(entry, i)) { entry->priv->icons[i].hovered = TRUE; update_icon(NULL, NULL, entry); break; } } } return FALSE; } static gint sexy_icon_entry_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; for (i = 0; i < MAX_ICONS; i++) { if (event->window == entry->priv->icons[i].window) { if (sexy_icon_entry_get_icon_highlight(entry, i)) { entry->priv->icons[i].hovered = FALSE; update_icon(NULL, NULL, entry); break; } } } return FALSE; } static gint sexy_icon_entry_button_press(GtkWidget *widget, GdkEventButton *event) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; for (i = 0; i < MAX_ICONS; i++) { if (event->window == entry->priv->icons[i].window) { if (event->button == 1 && sexy_icon_entry_get_icon_highlight(entry, i)) { entry->priv->icons[i].hovered = FALSE; update_icon(NULL, NULL, entry); } 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 sexy_icon_entry_button_release(GtkWidget *widget, GdkEventButton *event) { SexyIconEntry *entry = SEXY_ICON_ENTRY(widget); int i; for (i = 0; i < MAX_ICONS; i++) { GdkWindow *icon_window = entry->priv->icons[i].window; if (event->window == icon_window) { int width, height; gdk_drawable_get_size(icon_window, &width, &height); if (event->button == 1 && sexy_icon_entry_get_icon_highlight(entry, i) && event->x >= 0 && event->y >= 0 && event->x <= width && event->y <= height) { entry->priv->icons[i].hovered = TRUE; update_icon(NULL, NULL, entry); } 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; } /** * sexy_icon_entry_new * * Creates a new SexyIconEntry widget. * * Returns a new #SexyIconEntry. */ GtkWidget * sexy_icon_entry_new(void) { return GTK_WIDGET(g_object_new(SEXY_TYPE_ICON_ENTRY, NULL)); } /** * sexy_icon_entry_set_icon * @entry: A #SexyIconEntry. * @position: Icon position. * @icon: A #GtkImage to set as the icon. * * Sets the icon shown in the entry */ void sexy_icon_entry_set_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos, GtkImage *icon) { SexyIconInfo *icon_info; g_return_if_fail(entry != NULL); g_return_if_fail(SEXY_IS_ICON_ENTRY(entry)); g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos)); g_return_if_fail(icon == NULL || GTK_IS_IMAGE(icon)); icon_info = &entry->priv->icons[icon_pos]; if (icon == icon_info->icon) return; if (icon_pos == SEXY_ICON_ENTRY_SECONDARY && entry->priv->icon_released_id != 0) { g_signal_handler_disconnect(entry, entry->priv->icon_released_id); entry->priv->icon_released_id = 0; } if (icon == NULL) { if (icon_info->icon != NULL) { gtk_widget_destroy(GTK_WIDGET(icon_info->icon)); icon_info->icon = 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->icon == NULL) gdk_window_show(icon_info->window); g_signal_connect(G_OBJECT(icon), "notify", G_CALLBACK(update_icon), entry); icon_info->icon = icon; g_object_ref(icon); } update_icon(NULL, NULL, entry); } /** * sexy_icon_entry_set_icon_highlight * @entry: A #SexyIconEntry; * @position: Icon position. * @highlight: TRUE if the icon should highlight on mouse-over * * Determines whether the icon will highlight on mouse-over. */ void sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry, SexyIconEntryPosition icon_pos, gboolean highlight) { SexyIconInfo *icon_info; g_return_if_fail(entry != NULL); g_return_if_fail(SEXY_IS_ICON_ENTRY(entry)); g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos)); icon_info = &entry->priv->icons[icon_pos]; if (icon_info->highlight == highlight) return; icon_info->highlight = highlight; } /** * sexy_icon_entry_get_icon * @entry: A #SexyIconEntry. * @position: Icon position. * * Retrieves the image used for the icon * * Returns: A #GtkImage. */ GtkImage * sexy_icon_entry_get_icon(const SexyIconEntry *entry, SexyIconEntryPosition icon_pos) { g_return_val_if_fail(entry != NULL, NULL); g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), NULL); g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), NULL); return entry->priv->icons[icon_pos].icon; } /** * sexy_icon_entry_get_icon_highlight * @entry: A #SexyIconEntry. * @position: Icon position. * * Retrieves whether entry will highlight the icon on mouseover. * * Returns: TRUE if icon highlights. */ gboolean sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry, SexyIconEntryPosition icon_pos) { g_return_val_if_fail(entry != NULL, FALSE); g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), FALSE); g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), FALSE); return entry->priv->icons[icon_pos].highlight; } static void clear_button_clicked_cb(SexyIconEntry *icon_entry, SexyIconEntryPosition icon_pos, int button) { if (icon_pos != SEXY_ICON_ENTRY_SECONDARY || button != 1) return; gtk_entry_set_text(GTK_ENTRY(icon_entry), ""); } /** * sexy_icon_entry_add_clear_button * @icon_entry: A #SexyIconEntry. * * A convenience function to add a clear button to the end of the entry. * This is useful for search boxes. */ void sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry) { GtkWidget *icon; g_return_if_fail(icon_entry != NULL); g_return_if_fail(SEXY_IS_ICON_ENTRY(icon_entry)); icon = gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU); gtk_widget_show(icon); sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(icon_entry), SEXY_ICON_ENTRY_SECONDARY, GTK_IMAGE(icon)); sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(icon_entry), SEXY_ICON_ENTRY_SECONDARY, TRUE); if (icon_entry->priv->icon_released_id != 0) { g_signal_handler_disconnect(icon_entry, icon_entry->priv->icon_released_id); } icon_entry->priv->icon_released_id = g_signal_connect(G_OBJECT(icon_entry), "icon_released", G_CALLBACK(clear_button_clicked_cb), NULL); }