From efb148f58ec7760e36c7f63e1a1ae993e42b0195 Mon Sep 17 00:00:00 2001 From: Dale Whittaker Date: Thu, 17 Jul 2008 21:02:14 +0200 Subject: [PATCH] Introduce MidoriLocationEntry and GtkIconEntry --- README | 2 +- configure.in | 8 - midori/Makefile.am | 28 +- midori/gtkiconentry.c | 1601 +++++++++++++++++++++++++++++++++ midori/gtkiconentry.h | 119 +++ midori/midori-browser.c | 114 ++- midori/midori-locationentry.c | 384 ++++++++ midori/midori-locationentry.h | 77 ++ midori/midori-searchentry.c | 20 +- midori/midori-searchentry.h | 4 +- wscript | 1 - 11 files changed, 2292 insertions(+), 66 deletions(-) create mode 100644 midori/gtkiconentry.c create mode 100644 midori/gtkiconentry.h create mode 100644 midori/midori-locationentry.c create mode 100644 midori/midori-locationentry.h diff --git a/README b/README index 6a32c278..2537f5c3 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ Midori is a lightweight web browser. * User scripts and user styles support. * Extensible via Javascript. -Requirements: GTK+ 2.6, libsexy, WebkitGtk, libXML2 +Requirements: GTK+ 2.6, WebkitGtk, libXML2 For installation instructions read INSTALL. diff --git a/configure.in b/configure.in index b00a35ad..097f30ba 100644 --- a/configure.in +++ b/configure.in @@ -51,14 +51,6 @@ fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) -# Checks for libsexy -PKG_CHECK_MODULES(LIBSEXY, libsexy, have_libsexy=true, have_libsexy=false) -if test "x${have_libsexy}" = "xfalse" ; then - AC_MSG_ERROR([No Libsexy package information found]) -fi -AC_SUBST(LIBSEXY_CFLAGS) -AC_SUBST(LIBSEXY_LIBS) - # Checks for gtksourceview PKG_CHECK_MODULES(GTKSOURCEVIEW, gtksourceview, have_gtksourceview=true, have_gtksourceview=false) AC_SUBST(GTKSOURCEVIEW_CFLAGS) diff --git a/midori/Makefile.am b/midori/Makefile.am index 13b237bd..71629568 100644 --- a/midori/Makefile.am +++ b/midori/Makefile.am @@ -1,7 +1,6 @@ INCLUDES = \ $(GIO_CFLAGS) \ $(GTK_CFLAGS) \ - $(LIBSEXY_CFLAGS) \ $(GTKSOURCEVIEW_CFLAGS) \ $(WEBKIT_CFLAGS) \ -I../katze @@ -11,7 +10,6 @@ AM_CFLAGS = -DMIDORI_LOCALEDIR=\""$(localedir)"\" LDADD = \ $(GIO_LIBS) \ $(GTK_LIBS) \ - $(LIBSEXY_LIBS) \ $(GTKSOURCEVIEW_LIBS)\ $(WEBKIT_LIBS) \ $(INTLLIBS) \ @@ -21,18 +19,20 @@ bin_PROGRAMS = \ midori midori_SOURCES = \ - main.c main.h \ - midori-webitem.c midori-webitem.h \ - midori-weblist.c midori-weblist.h \ - midori-app.c midori-app.h \ - midori-browser.c midori-browser.h \ - midori-panel.c midori-panel.h \ - midori-addons.c midori-addons.h \ - midori-console.c midori-console.h \ - midori-webview.c midori-webview.h \ - midori-websettings.c midori-websettings.h \ - midori-preferences.c midori-preferences.h \ - midori-searchentry.c midori-searchentry.h \ + main.c main.h \ + gtkiconentry.c gtkiconentry.h \ + midori-webitem.c midori-webitem.h \ + midori-weblist.c midori-weblist.h \ + midori-app.c midori-app.h \ + midori-browser.c midori-browser.h \ + midori-panel.c midori-panel.h \ + midori-addons.c midori-addons.h \ + midori-console.c midori-console.h \ + midori-webview.c midori-webview.h \ + midori-websettings.c midori-websettings.h \ + midori-preferences.c midori-preferences.h \ + midori-searchentry.c midori-searchentry.h \ + midori-locationentry.c midori-locationentry.h \ gjs.c gjs.h \ sokoke.c sokoke.h \ compat.c compat.h diff --git a/midori/gtkiconentry.c b/midori/gtkiconentry.c new file mode 100644 index 00000000..0745d5ba --- /dev/null +++ b/midori/gtkiconentry.c @@ -0,0 +1,1601 @@ +/* + * Copyright (C) 2004-2006 Christian Hammond. + * Copyright (C) 2008 Cody Russell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifndef GTK_IMAGE_GICON +#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) + +#include "gtkiconentry.h" + +#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); + } +} diff --git a/midori/gtkiconentry.h b/midori/gtkiconentry.h new file mode 100644 index 00000000..314eccb6 --- /dev/null +++ b/midori/gtkiconentry.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2004-2006 Christian Hammond. + * Copyright (C) 2008 Cody Russell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_ICON_ENTRY_H__ +#define __GTK_ICON_ENTRY_H__ + + +#include +#if GLIB_CHECK_VERSION (2, 16, 0) +#include +#endif +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_ICON_ENTRY (gtk_icon_entry_get_type()) +#define GTK_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_ICON_ENTRY, GtkIconEntry)) +#define GTK_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_ICON_ENTRY, GtkIconEntryClass)) +#define GTK_IS_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_ICON_ENTRY)) +#define GTK_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_ICON_ENTRY)) +#define GTK_ICON_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ICON_ENTRY, GtkIconEntryClass)) + +typedef enum +{ + GTK_ICON_ENTRY_PRIMARY, + GTK_ICON_ENTRY_SECONDARY +} GtkIconEntryPosition; + +typedef struct _GtkIconEntry GtkIconEntry; +typedef struct _GtkIconEntryClass GtkIconEntryClass; + +struct _GtkIconEntry +{ + GtkEntry parent_object; +}; + +struct _GtkIconEntryClass +{ + GtkEntryClass parent_class; + + /* Signals */ + void (*icon_pressed) (GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + int button); + void (*icon_released) (GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + int button); + + void (*gtk_reserved1) (void); + void (*gtk_reserved2) (void); + void (*gtk_reserved3) (void); + void (*gtk_reserved4) (void); +}; + +GType gtk_icon_entry_get_type (void) G_GNUC_CONST; + +GtkWidget* gtk_icon_entry_new (void); + +void gtk_icon_entry_set_icon_from_pixbuf (GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + GdkPixbuf *pixbuf); +void gtk_icon_entry_set_icon_from_stock (GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + const gchar *stock_id); +void gtk_icon_entry_set_icon_from_icon_name (GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + const gchar *icon_name); + +#if GLIB_CHECK_VERSION (2, 16, 0) +void gtk_icon_entry_set_icon_from_gicon (const GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + GIcon *icon); +#endif +GdkPixbuf* gtk_icon_entry_get_pixbuf (const GtkIconEntry *entry, + GtkIconEntryPosition icon_pos); +#if GLIB_CHECK_VERSION (2, 16, 0) +GIcon* gtk_icon_entry_get_gicon (const GtkIconEntry *entry, + GtkIconEntryPosition icon_pos); +#endif + +void gtk_icon_entry_set_icon_highlight (const GtkIconEntry *entry, + GtkIconEntryPosition icon_pos, + gboolean highlight); + +gboolean gtk_icon_entry_get_icon_highlight (const GtkIconEntry *entry, + GtkIconEntryPosition icon_pos); + +void gtk_icon_entry_set_cursor (const GtkIconEntry *icon_entry, + GtkIconEntryPosition icon_pos, + GdkCursorType cursor_type); + +void gtk_icon_entry_set_tooltip (const GtkIconEntry *icon_entry, + GtkIconEntryPosition icon_pos, + const gchar *text); + +void gtk_icon_entry_set_icon_sensitive (const GtkIconEntry *icon_entry, + GtkIconEntryPosition icon_pos, + gboolean sensitive); + +G_END_DECLS + +#endif /* __GTK_ICON_ENTRY_H__ */ diff --git a/midori/midori-browser.c b/midori/midori-browser.c index d8542690..10b1e974 100644 --- a/midori/midori-browser.c +++ b/midori/midori-browser.c @@ -14,6 +14,7 @@ #include "midori-browser.h" #include "main.h" +#include "gtkiconentry.h" #include "sokoke.h" #include "midori-webview.h" #include "midori-preferences.h" @@ -21,6 +22,7 @@ #include "midori-addons.h" #include "midori-console.h" #include "midori-searchentry.h" +#include "midori-locationentry.h" #include "compat.h" #if GLIB_CHECK_VERSION (2, 16, 0) @@ -29,7 +31,6 @@ #include #include #include -#include #if HAVE_GTKSOURCEVIEW #include #include @@ -50,7 +51,6 @@ struct _MidoriBrowser GtkWidget* navigationbar; GtkWidget* button_tab_new; GtkWidget* button_homepage; - GtkWidget* location_icon; GtkWidget* location; GtkWidget* search; GtkWidget* button_trash; @@ -123,12 +123,19 @@ midori_browser_set_property (GObject* object, const GValue* value, GParamSpec* pspec); +static void +midori_browser_location_active_changed_cb (MidoriLocationEntry* location_entry, + gint index, + MidoriBrowser* browser); + static void midori_browser_get_property (GObject* object, guint prop_id, GValue* value, GParamSpec* pspec); + + static GtkAction* _action_by_name (MidoriBrowser* browser, const gchar* name) @@ -278,7 +285,6 @@ _midori_browser_update_interface (MidoriBrowser* browser) katze_throbber_set_animated (KATZE_THROBBER (browser->throbber), loading); icon = katze_throbber_get_static_pixbuf (KATZE_THROBBER ( g_object_get_data (G_OBJECT (widget), "browser-tab-icon"))); - gtk_image_set_from_pixbuf (GTK_IMAGE (browser->location_icon), icon); } static GtkWidget* @@ -411,12 +417,29 @@ midori_web_view_title_changed_cb (GtkWidget* web_view, { if (web_view == midori_browser_get_current_web_view (browser)) { + MidoriLocationEntryItem item; + const gchar* title = midori_web_view_get_display_title ( MIDORI_WEB_VIEW (web_view)); gchar* window_title = g_strconcat (title, " - ", g_get_application_name (), NULL); gtk_window_set_title (GTK_WINDOW (browser), window_title); g_free (window_title); + + item.favicon = midori_web_view_get_icon (MIDORI_WEB_VIEW (web_view)); + item.uri = midori_location_entry_get_text ( + MIDORI_LOCATION_ENTRY (browser->location)); + item.title = title; + + g_signal_handlers_block_by_func (browser->location, + midori_browser_location_active_changed_cb, browser); + + midori_location_entry_add_item (MIDORI_LOCATION_ENTRY + (browser->location), &item); + + g_signal_handlers_unblock_by_func (browser->location, + midori_browser_location_active_changed_cb, browser); + g_object_unref (item.favicon); } } @@ -444,7 +467,7 @@ midori_web_view_load_committed_cb (GtkWidget* web_view, if (web_view == midori_browser_get_current_web_view (browser)) { const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); - gtk_entry_set_text (GTK_ENTRY (browser->location), uri); + midori_location_entry_set_text (MIDORI_LOCATION_ENTRY (browser->location), uri); _midori_browser_set_statusbar_text (browser, NULL); } } @@ -1611,10 +1634,8 @@ _action_find_activate(GtkAction* action, } else { - GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND, - GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (browser->find_text), - SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (icon)); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (browser->find_text), + GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FIND); gtk_entry_set_text (GTK_ENTRY (browser->find_text), ""); gtk_widget_show (browser->find); gtk_widget_grab_focus (GTK_WIDGET (browser->find_text)); @@ -1635,13 +1656,9 @@ _midori_browser_find (MidoriBrowser* browser, text, case_sensitive, forward); if (GTK_WIDGET_VISIBLE (browser->find)) { - GtkWidget* icon; - if (found) - icon = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); - else - icon = gtk_image_new_from_stock (GTK_STOCK_STOP, GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (browser->find_text), - SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (icon)); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (browser->find_text), + GTK_ICON_ENTRY_PRIMARY, + (found) ? GTK_STOCK_FIND : GTK_STOCK_STOP); _midori_browser_tab_mark_text_matches (browser, widget, text, case_sensitive); const gboolean highlight = gtk_toggle_tool_button_get_active ( @@ -1993,6 +2010,22 @@ _action_homepage_activate (GtkAction* action, g_free (homepage); } +/* catch the active-changed signal so that we can display the pack + when selected from the list */ +static void +midori_browser_location_active_changed_cb (MidoriLocationEntry* location_entry, + gint index, + MidoriBrowser* browser) +{ + const gchar* uri; + + if (index > -1) + { + uri = midori_location_entry_get_text (location_entry); + _midori_browser_open_uri (browser, uri); + } +} + static gboolean midori_browser_location_key_press_event_cb (GtkWidget* widget, GdkEventKey* event, @@ -2020,7 +2053,7 @@ midori_browser_location_key_press_event_cb (GtkWidget* widget, /* TODO: Use new_uri intermediately when completion is better Completion should be generated from history, that is the uri as well as the title. */ - sokoke_entry_append_completion (GTK_ENTRY (widget), uri); + /* sokoke_entry_append_completion (GTK_ENTRY (widget), uri); */ _midori_browser_open_uri (browser, new_uri); g_free (new_uri); gtk_widget_grab_focus (midori_browser_get_current_tab (browser)); @@ -2518,7 +2551,14 @@ gtk_notebook_switch_page_cb (GtkWidget* notebook, widget = midori_browser_get_current_tab (browser); uri = _midori_browser_get_tab_uri (browser, widget); - gtk_entry_set_text (GTK_ENTRY (browser->location), uri); + + g_signal_handlers_block_by_func (browser->location, + midori_browser_location_active_changed_cb, browser); + midori_location_entry_set_item_from_uri (MIDORI_LOCATION_ENTRY + (browser->location), uri); + g_signal_handlers_unblock_by_func (browser->location, + midori_browser_location_active_changed_cb, browser); + title = _midori_browser_get_tab_title (browser, widget); window_title = g_strconcat (title, " - ", g_get_application_name (), NULL); @@ -3095,6 +3135,16 @@ midori_browser_search_activate_cb (GtkWidget* widget, g_free (location_entry_search); } +static void +midori_browser_entry_clear_icon_released_cb (GtkIconEntry* entry, + gint icon_pos, + gint button, + gpointer user_data) +{ + if (icon_pos == GTK_ICON_ENTRY_SECONDARY) + gtk_entry_set_text (GTK_ENTRY (entry), ""); +} + static void midori_browser_search_notify_current_item_cb (GObject *gobject, GParamSpec *arg1, @@ -3227,13 +3277,12 @@ midori_browser_init (MidoriBrowser* browser) ui_manager, "/toolbar_navigation/Homepage"); /* Location */ - browser->location = sexy_icon_entry_new (); - sokoke_entry_setup_completion (GTK_ENTRY (browser->location)); - browser->location_icon = gtk_image_new (); - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (browser->location) - , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (browser->location_icon)); - sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (browser->location)); + browser->location = midori_location_entry_new (); + /* FIXME: sokoke_entry_setup_completion (GTK_ENTRY (browser->location)); */ g_object_connect (browser->location, + "signal::active-changed", + midori_browser_location_active_changed_cb, browser, NULL); + g_object_connect (gtk_bin_get_child (GTK_BIN (browser->location)), "signal::key-press-event", midori_browser_location_key_press_event_cb, browser, "signal::focus-out-event", @@ -3243,7 +3292,9 @@ midori_browser_init (MidoriBrowser* browser) NULL); GtkToolItem* toolitem = gtk_tool_item_new (); gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); - gtk_container_add (GTK_CONTAINER(toolitem), browser->location); + GtkWidget* align = gtk_alignment_new (0, 0.5, 1, 0.1); + gtk_container_add (GTK_CONTAINER (align), browser->location); + gtk_container_add (GTK_CONTAINER(toolitem), align); gtk_toolbar_insert (GTK_TOOLBAR (browser->navigationbar), toolitem, -1); /* Search */ @@ -3462,12 +3513,15 @@ midori_browser_init (MidoriBrowser* browser) gtk_container_add (GTK_CONTAINER (toolitem), gtk_label_new_with_mnemonic (_("_Inline find:"))); gtk_toolbar_insert (GTK_TOOLBAR (browser->find), toolitem, -1); - browser->find_text = sexy_icon_entry_new (); - GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND, - GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY(browser->find_text), - SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (icon)); - sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (browser->find_text)); + browser->find_text = gtk_icon_entry_new (); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY(browser->find_text), + GTK_ICON_ENTRY_PRIMARY, + GTK_STOCK_FIND); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (browser->find_text), + GTK_ICON_ENTRY_SECONDARY, + GTK_STOCK_CLEAR); + g_signal_connect (browser->find_text, "icon_released", + G_CALLBACK (midori_browser_entry_clear_icon_released_cb), NULL); g_signal_connect (browser->find_text, "activate", G_CALLBACK (_action_find_next_activate), browser); toolitem = gtk_tool_item_new (); diff --git a/midori/midori-locationentry.c b/midori/midori-locationentry.c new file mode 100644 index 00000000..3e9c8728 --- /dev/null +++ b/midori/midori-locationentry.c @@ -0,0 +1,384 @@ +/* + Copyright (C) 2008 Dale Whittaker + + 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.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-locationentry.h" +#include "gtkiconentry.h" +#include "sokoke.h" + +#include + +#define DEFAULT_ICON GTK_STOCK_FILE + +G_DEFINE_TYPE (MidoriLocationEntry, midori_location_entry, GTK_TYPE_COMBO_BOX_ENTRY) + +enum +{ + FAVICON_COL, + URI_COL, + TITLE_COL, + N_COLS +}; + +enum +{ + ACTIVE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + + +static void +entry_icon_released (GtkIconEntry* entry, + gint icon_pos, + gint button, + gpointer user_data); + +static gboolean +entry_key_press_event (GtkWidget* widget, + GdkEventKey* event, + MidoriLocationEntry* location_entry); + +static void +midori_location_entry_active_changed (GtkComboBox* combo_box, + gpointer user_data); + +static void +midori_location_entry_class_init (MidoriLocationEntryClass* class) +{ + signals[ACTIVE_CHANGED] = g_signal_new ("active-changed", + G_TYPE_FROM_CLASS (class), + (GSignalFlags) (G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); +} + +static void +midori_location_entry_init (MidoriLocationEntry* location_entry) +{ + GtkWidget* entry; + GtkListStore* store; + GtkCellRenderer* renderer; + + /* we want the widget to have appears-as-list applied */ + gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n" + " GtkComboBox::appears-as-list = 1\n }\n" + "widget_class \"*MidoriLocationEntry\" " + "style \"midori-location-entry-style\"\n"); + + entry = gtk_icon_entry_new (); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), GTK_ICON_ENTRY_PRIMARY, DEFAULT_ICON); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_CLEAR); + gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry), GTK_ICON_ENTRY_SECONDARY, TRUE); + g_signal_connect (entry, "icon_released", G_CALLBACK (entry_icon_released), NULL); + g_signal_connect (entry, "key-press-event", G_CALLBACK (entry_key_press_event), location_entry); + + gtk_widget_show (entry); + gtk_container_add (GTK_CONTAINER (location_entry), entry); + + store = gtk_list_store_new (N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); + g_object_set (G_OBJECT (location_entry), "model", GTK_TREE_MODEL (store), NULL); + g_object_unref(store); + + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (location_entry), URI_COL); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (location_entry)); + + /* setup the renderer for the favicon */ + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (location_entry), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (location_entry), renderer, "pixbuf", FAVICON_COL, NULL); + g_object_set (G_OBJECT (renderer), "xpad", 5, "ypad", 5, "yalign", 0.0, NULL); + + /* setup the renderer for the uri/title */ + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (location_entry), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (location_entry), renderer, "markup", TITLE_COL, NULL); + g_object_set (G_OBJECT (renderer), "xpad", 5, "ypad", 5, NULL); + g_object_set (G_OBJECT (renderer), "ellipsize-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (location_entry), -1); + + g_signal_connect (location_entry, "changed", G_CALLBACK (midori_location_entry_active_changed), NULL); +} + +static gboolean +entry_key_press_event (GtkWidget* widget, + GdkEventKey* event, + MidoriLocationEntry* location_entry) +{ + switch (event->keyval) + { + case GDK_Down: + case GDK_Up: + { + if (!sokoke_object_get_boolean (location_entry, "popup-shown")) + gtk_combo_box_popup (GTK_COMBO_BOX (location_entry)); + return TRUE; + } + } + + return FALSE; +} + +static void +entry_icon_released (GtkIconEntry* entry, + gint icon_pos, + gint button, + gpointer user_data) +{ + if (icon_pos == GTK_ICON_ENTRY_SECONDARY) + gtk_entry_set_text (GTK_ENTRY (entry), ""); +} + +static void +midori_location_entry_active_changed (GtkComboBox* combo_box, + gpointer user_data) +{ + GtkTreeIter iter; + GtkIconEntry* entry; + GtkTreeModel* model; + GdkPixbuf* pixbuf; + + if (gtk_combo_box_get_active_iter (combo_box, &iter)) + { + entry = GTK_ICON_ENTRY (GTK_BIN (combo_box)->child); + + if (entry) + { + pixbuf = NULL; + + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get (model, &iter, FAVICON_COL, &pixbuf, -1); + + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, pixbuf); + g_object_unref (pixbuf); + + g_signal_emit (MIDORI_LOCATION_ENTRY (combo_box), + signals[ACTIVE_CHANGED], 0, gtk_combo_box_get_active (combo_box)); + } + } +} + +static void +midori_location_entry_set_item (GtkTreeModel* model, + GtkTreeIter* iter, + MidoriLocationEntryItem* item) +{ + gchar* desc = NULL; + + if (item->title) + desc = g_strdup_printf ("%s - %s", item->uri, item->title); + else + desc = g_strdup_printf ("%s", item->uri); + + gtk_list_store_set (GTK_LIST_STORE (model), iter, + FAVICON_COL, item->favicon, URI_COL, item->uri, TITLE_COL, desc, -1); + + g_free (desc); +} + +/** + * midori_location_entry_new: + * + * Creates a new #MidoriLocationEntry. + * + * Return value: a new #MidoriLocationEntry + **/ +GtkWidget* +midori_location_entry_new (void) +{ + return (g_object_new (MIDORI_TYPE_LOCATION_ENTRY, NULL)); +} + +/** + * midori_location_entry_item_index: + * @location_entry: a #MidoriLocationEntry + * @uri: a string + * + * Gets the index of the item matching @uri. + * + * Return value: an integer + **/ +gint +midori_location_entry_item_index (MidoriLocationEntry* location_entry, + const gchar* uri) +{ + GtkTreeModel* model; + GtkTreeIter iter; + gint index; + gchar* tmpuri; + gint tmpindex; + + g_return_val_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry), -1); + g_return_val_if_fail (uri != NULL, -1); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (location_entry)); + + index = -1; + if (gtk_tree_model_get_iter_first (model, &iter)) + { + tmpuri = NULL; + tmpindex = 0; + do + { + gtk_tree_model_get (model, &iter, URI_COL, &tmpuri, -1); + if (g_ascii_strcasecmp (uri, tmpuri) == 0) + { + g_free (tmpuri); + index = tmpindex; + break; + } + g_free (tmpuri); + tmpindex++; + } + while (gtk_tree_model_iter_next (model, &iter)); + } + return index; +} + +/** + * midori_location_entry_get_text: + * @location_entry: a #MidoriLocationEntry + * + * Gets the entry text. + * + * Return value: a string + **/ +const gchar* +midori_location_entry_get_text (MidoriLocationEntry* location_entry) +{ + GtkWidget* entry; + + g_return_val_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry), NULL); + + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + g_return_val_if_fail (GTK_IS_ICON_ENTRY (entry), NULL); + + return gtk_entry_get_text (GTK_ENTRY (entry)); +} + +/** + * midori_location_entry_set_text: + * @location_entry: a #MidoriLocationEntry + * @text: a string + * + * Sets the entry text to @text. + **/ +void +midori_location_entry_set_text (MidoriLocationEntry* location_entry, + const gchar* text) +{ + GtkWidget* entry; + + g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); + + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); + + gtk_entry_set_text (GTK_ENTRY (entry), text); +} + +/** + * midori_location_entry_clear: + * @location_entry: a #MidoriLocationEntry + * + * Clears the entry text and resets the entry favicon. + **/ +void +midori_location_entry_clear (MidoriLocationEntry* location_entry) +{ + GtkWidget* entry; + + g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); + + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); + + gtk_entry_set_text (GTK_ENTRY (entry), ""); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, DEFAULT_ICON); +} + +/** + * midori_location_entry_set_item_from_uri: + * @location_entry: a #MidoriLocationEntry + * @uri: a string + * + * Finds the item from the list matching @uri and sets it as the active item. + * If @uri is not found it clears the active item. + **/ +void +midori_location_entry_set_item_from_uri (MidoriLocationEntry* location_entry, + const gchar* uri) +{ + gint index; + + g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); + + index = midori_location_entry_item_index ( + MIDORI_LOCATION_ENTRY (location_entry), uri); + gtk_combo_box_set_active (GTK_COMBO_BOX (location_entry), index); + + if(index == -1) + midori_location_entry_clear (location_entry); +} + +/** + * midori_location_entry_add_item: + * @location_entry: a #MidoriLocationEntry + * @item: a MidoriLocationItem + * + * Adds @item if it is not already in the list. + * Sets @item to be active. + **/ +void +midori_location_entry_add_item (MidoriLocationEntry* location_entry, + MidoriLocationEntryItem* item) +{ + GtkTreeModel* model; + GtkTreeIter iter; + gboolean item_exists = FALSE; + gchar* uri; + + g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); + g_return_if_fail (item->uri != NULL); + g_return_if_fail (item->favicon != NULL); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (location_entry)); + if (gtk_tree_model_get_iter_first (model, &iter)) + { + uri = NULL; + do + { + gtk_tree_model_get (model, &iter, URI_COL, &uri, -1); + if (g_ascii_strcasecmp (item->uri, uri) == 0) + { + item_exists = TRUE; + g_free (uri); + break; + } + g_free (uri); + } + while (gtk_tree_model_iter_next (model, &iter)); + } + + if (!item_exists) + gtk_list_store_prepend (GTK_LIST_STORE (model), &iter); + + midori_location_entry_set_item (model, &iter, item); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (location_entry), &iter); +} + diff --git a/midori/midori-locationentry.h b/midori/midori-locationentry.h new file mode 100644 index 00000000..02a00e1d --- /dev/null +++ b/midori/midori-locationentry.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2008 Dale Whittaker + + 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.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_LOCATION_ENTRY_H__ +#define __MIDORI_LOCATION_ENTRY_H__ + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_LOCATION_ENTRY (midori_location_entry_get_type ()) +#define MIDORI_LOCATION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntry)) +#define MIDORI_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntryClass)) +#define MIDORI_IS_LOCATION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_LOCATION_ENTRY)) +#define MIDORI_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_LOCATION_ENTRY)) +#define MIDORI_LOCATION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntryClass)) + +typedef struct _MidoriLocationEntry MidoriLocationEntry; +typedef struct _MidoriLocationEntryClass MidoriLocationEntryClass; +typedef struct _MidoriLocationEntryItem MidoriLocationEntryItem; + +struct _MidoriLocationEntry +{ + GtkComboBoxEntry parent_instance; +}; + +struct _MidoriLocationEntryClass +{ + GtkComboBoxEntryClass parent_class; +}; + +struct _MidoriLocationEntryItem +{ + GdkPixbuf* favicon; + const gchar* uri; + const gchar* title; +}; + +GType +midori_location_entry_get_type (void); + +GtkWidget* +midori_location_entry_new (void); + +gint +midori_location_entry_item_index (MidoriLocationEntry* location_entry, + const gchar* uri); + +const gchar* +midori_location_entry_get_text (MidoriLocationEntry* location_entry); + +void +midori_location_entry_set_text (MidoriLocationEntry* location_entry, + const gchar* text); + +void +midori_location_entry_clear (MidoriLocationEntry* location_entry); + +void +midori_location_entry_set_item_from_uri (MidoriLocationEntry* location_entry, + const gchar* uri); + +void +midori_location_entry_add_item (MidoriLocationEntry* location_entry, + MidoriLocationEntryItem* item); + +G_END_DECLS + +#endif /* __MIDORI_LOCATION_ENTRY_H__ */ diff --git a/midori/midori-searchentry.c b/midori/midori-searchentry.c index a8b37cfe..cb8680e8 100644 --- a/midori/midori-searchentry.c +++ b/midori/midori-searchentry.c @@ -19,13 +19,13 @@ struct _MidoriSearchEntry { - SexyIconEntry parent_instance; + GtkIconEntry parent_instance; MidoriWebList* search_engines; MidoriWebItem* current_item; }; -G_DEFINE_TYPE (MidoriSearchEntry, midori_search_entry, SEXY_TYPE_ICON_ENTRY) +G_DEFINE_TYPE (MidoriSearchEntry, midori_search_entry, GTK_TYPE_ICON_ENTRY) enum { @@ -112,7 +112,7 @@ midori_search_entry_manage_activate_cb (GtkWidget* menuitem, static void midori_search_entry_icon_released_cb (GtkWidget* widget, - SexyIconEntryPosition* pos, + GtkIconEntryPosition* pos, gint button) { MidoriSearchEntry* search_entry; @@ -240,8 +240,8 @@ midori_search_entry_engines_remove_item_cb (MidoriWebList* web_list, midori_search_entry_set_current_item (search_entry, web_item); else { - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (search_entry), - SEXY_ICON_ENTRY_PRIMARY, NULL); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (search_entry), + GTK_ICON_ENTRY_PRIMARY, NULL); sokoke_entry_set_default_text (GTK_ENTRY (search_entry), ""); katze_object_assign (search_entry->current_item, NULL); @@ -256,8 +256,8 @@ midori_search_entry_init (MidoriSearchEntry* search_entry) search_entry->search_engines = midori_web_list_new (); search_entry->current_item = NULL; - sexy_icon_entry_set_icon_highlight (SEXY_ICON_ENTRY (search_entry), - SEXY_ICON_ENTRY_PRIMARY, TRUE); + gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (search_entry), + GTK_ICON_ENTRY_PRIMARY, TRUE); g_object_connect (search_entry, "signal::icon-released", midori_search_entry_icon_released_cb, NULL, @@ -412,9 +412,9 @@ midori_search_entry_set_current_item (MidoriSearchEntry* search_entry, pixbuf = sokoke_web_icon (midori_web_item_get_icon (web_item), GTK_ICON_SIZE_MENU, GTK_WIDGET (search_entry)); - sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (search_entry), - SEXY_ICON_ENTRY_PRIMARY, - GTK_IMAGE (gtk_image_new_from_pixbuf (pixbuf))); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (search_entry), + GTK_ICON_ENTRY_PRIMARY, + pixbuf); g_object_unref (pixbuf); sokoke_entry_set_default_text (GTK_ENTRY (search_entry), midori_web_item_get_name (web_item)); diff --git a/midori/midori-searchentry.h b/midori/midori-searchentry.h index 588277d6..ec379dd9 100644 --- a/midori/midori-searchentry.h +++ b/midori/midori-searchentry.h @@ -13,9 +13,9 @@ #define __MIDORI_SEARCH_ENTRY_H__ #include "midori-weblist.h" +#include "gtkiconentry.h" #include -#include G_BEGIN_DECLS @@ -37,7 +37,7 @@ typedef struct _MidoriSearchEntryClass MidoriSearchEntryClass; struct _MidoriSearchEntryClass { - SexyIconEntryClass parent_class; + GtkIconEntryClass parent_class; }; GType diff --git a/wscript b/wscript index 7fe577af..c42e0dca 100644 --- a/wscript +++ b/wscript @@ -37,7 +37,6 @@ def configure (conf): conf.check_pkg ('gio-2.0', destvar='GIO', vnum='2.16.0', mandatory=False) conf.check_pkg ('gtk+-2.0', destvar='GTK', vnum='2.6.0', mandatory=True) - conf.check_pkg ('libsexy', destvar='LIBSEXY', vnum='0.1', mandatory=True) conf.check_pkg ('gtksourceview-2.0', destvar='GTKSOURCEVIEW', vnum='2.0', mandatory=False) conf.check_pkg ('webkit-1.0', destvar='WEBKIT', vnum='0.1', mandatory=True) conf.check_pkg ('libxml-2.0', destvar='LIBXML', vnum='2.6', mandatory=True)