[gtk+/wip/window-scales: 77/84] icon factory: Support scaled icons
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/window-scales: 77/84] icon factory: Support scaled icons
- Date: Wed, 26 Jun 2013 15:11:22 +0000 (UTC)
commit d67701fa9f7910ba98ab0a8a9d66df6e8ffa9cb7
Author: Alexander Larsson <alexl redhat com>
Date: Tue Jun 25 13:59:51 2013 +0200
icon factory: Support scaled icons
Support setting a custom scale (or wildcarding) of a GtkIconSource, which
will cause that icon to only be used for a particular scale. This is useful
when you want to add two pixbufs as icon sources for two scales.
We also support scales when falling back to loading icons from the
icon theme.
In order to actually render scaled icons we add gtk_icon_set_render_icon_pattern
which renders to a cairo_pattern_t which includes whatever scaling you
need for scaled icons.
gtk/gtkiconfactory.c | 270 ++++++++++++++++++++++++++++++++++++++++++-------
gtk/gtkiconfactory.h | 11 ++-
gtk/gtkstylecontext.h | 12 ++
3 files changed, 253 insertions(+), 40 deletions(-)
---
diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
index 7dfd888..92994d3 100644
--- a/gtk/gtkiconfactory.c
+++ b/gtk/gtkiconfactory.c
@@ -172,6 +172,7 @@ struct _GtkIconSource
GtkTextDirection direction;
GtkStateType state;
GtkIconSize size;
+ int scale;
/* If TRUE, then the parameter is wildcarded, and the above
* fields should be ignored. If FALSE, the parameter is
@@ -180,6 +181,7 @@ struct _GtkIconSource
guint any_direction : 1;
guint any_state : 1;
guint any_size : 1;
+ guint any_scale : 1;
};
@@ -205,10 +207,10 @@ static GtkIconSize icon_size_register_intern (const gchar *name,
gint width,
gint height);
-#define GTK_ICON_SOURCE_INIT(any_direction, any_state, any_size) \
+#define GTK_ICON_SOURCE_INIT(any_direction, any_state, any_size, any_scale) \
{ GTK_ICON_SOURCE_EMPTY, { NULL }, NULL, \
- 0, 0, 0, \
- any_direction, any_state, any_size }
+ 0, 0, 0, 1, \
+ any_direction, any_state, any_size, any_scale }
G_DEFINE_TYPE_WITH_CODE (GtkIconFactory, gtk_icon_factory, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
@@ -482,7 +484,7 @@ register_stock_icon (GtkIconFactory *factory,
const gchar *icon_name)
{
GtkIconSet *set = gtk_icon_set_new ();
- GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
+ GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
source.source.icon_name = (gchar *)icon_name;
@@ -499,7 +501,7 @@ register_bidi_stock_icon (GtkIconFactory *factory,
const gchar *icon_name)
{
GtkIconSet *set = gtk_icon_set_new ();
- GtkIconSource source = GTK_ICON_SOURCE_INIT (FALSE, TRUE, TRUE);
+ GtkIconSource source = GTK_ICON_SOURCE_INIT (FALSE, TRUE, TRUE, TRUE);
source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
source.source.icon_name = (gchar *)icon_name;
@@ -1208,12 +1210,14 @@ static GdkPixbuf *find_in_cache (GtkIconSet *icon_set,
GtkStyleContext *style_context,
GtkTextDirection direction,
GtkStateType state,
- GtkIconSize size);
+ GtkIconSize size,
+ gint scale);
static void add_to_cache (GtkIconSet *icon_set,
GtkStyleContext *style_context,
GtkTextDirection direction,
GtkStateType state,
GtkIconSize size,
+ gint scale,
GdkPixbuf *pixbuf);
/* Clear icon set contents, drop references to all contained
* GdkPixbuf objects and forget all GtkIconSources. Used to
@@ -1293,7 +1297,7 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
{
GtkIconSet *set;
- GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
+ GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
g_return_val_if_fail (pixbuf != NULL, NULL);
@@ -1424,6 +1428,7 @@ find_best_matching_source (GtkIconSet *icon_set,
GtkTextDirection direction,
GtkStateType state,
GtkIconSize size,
+ gint scale,
GSList *failed)
{
GtkIconSource *source;
@@ -1445,7 +1450,8 @@ find_best_matching_source (GtkIconSet *icon_set,
if ((s->any_direction || (s->direction == direction)) &&
(s->any_state || (s->state == state)) &&
- (s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))))
+ (s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))) &&
+ (s->any_scale || (s->scale == scale)))
{
if (!g_slist_find (failed, s))
{
@@ -1492,7 +1498,8 @@ ensure_filename_pixbuf (GtkIconSet *icon_set,
static GdkPixbuf *
render_icon_name_pixbuf (GtkIconSource *icon_source,
GtkStyleContext *context,
- GtkIconSize size)
+ GtkIconSize size,
+ gint scale)
{
GdkPixbuf *pixbuf;
GdkPixbuf *tmp_pixbuf;
@@ -1562,9 +1569,10 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
names[1] = icon_source->source.icon_name;
names[2] = NULL;
- info = gtk_icon_theme_choose_icon (icon_theme,
- (const char **) names,
- pixel_size, GTK_ICON_LOOKUP_USE_BUILTIN);
+ info = gtk_icon_theme_choose_icon_for_scale (icon_theme,
+ (const char **) names,
+ pixel_size, scale,
+ GTK_ICON_LOOKUP_USE_BUILTIN);
g_free (names[0]);
if (info)
{
@@ -1576,10 +1584,10 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
}
else
{
- tmp_pixbuf = gtk_icon_theme_load_icon (icon_theme,
- icon_source->source.icon_name,
- pixel_size, 0,
- &error);
+ tmp_pixbuf = gtk_icon_theme_load_icon_for_scale (icon_theme,
+ icon_source->source.icon_name,
+ pixel_size, scale, 0,
+ &error);
}
if (!tmp_pixbuf)
@@ -1610,7 +1618,8 @@ find_and_render_icon_source (GtkIconSet *icon_set,
GtkStyleContext *context,
GtkTextDirection direction,
GtkStateType state,
- GtkIconSize size)
+ GtkIconSize size,
+ gint scale)
{
GSList *failed = NULL;
GdkPixbuf *pixbuf = NULL;
@@ -1627,7 +1636,7 @@ find_and_render_icon_source (GtkIconSet *icon_set,
*/
while (pixbuf == NULL)
{
- GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, failed);
+ GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, scale, failed);
if (source == NULL)
break;
@@ -1645,10 +1654,21 @@ find_and_render_icon_source (GtkIconSet *icon_set,
g_warning ("Failed to render icon");
failed = g_slist_prepend (failed, source);
}
+
+ if (scale != source->scale)
+ {
+ GdkPixbuf *tmp = pixbuf;
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) * scale * source->scale,
+ gdk_pixbuf_get_height (pixbuf) * scale * source->scale,
+ GDK_INTERP_BILINEAR);
+ g_object_unref (tmp);
+ }
break;
case GTK_ICON_SOURCE_ICON_NAME:
case GTK_ICON_SOURCE_STATIC_ICON_NAME:
- pixbuf = render_icon_name_pixbuf (source, context, size);
+ pixbuf = render_icon_name_pixbuf (source, context,
+ size, scale);
if (!pixbuf)
failed = g_slist_prepend (failed, source);
break;
@@ -1671,7 +1691,7 @@ render_fallback_image (GtkStyleContext *context,
GtkIconSize size)
{
/* This icon can be used for any direction/state/size */
- static GtkIconSource fallback_source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
+ static GtkIconSource fallback_source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
if (fallback_source.type == GTK_ICON_SOURCE_EMPTY)
{
@@ -1693,27 +1713,28 @@ render_fallback_image (GtkStyleContext *context,
}
/**
- * gtk_icon_set_render_icon_pixbuf:
+ * gtk_icon_set_render_icon_pixbuf_for_scale:
* @icon_set: a #GtkIconSet
* @context: a #GtkStyleContext
* @size: (type int): icon size. A size of (GtkIconSize)-1
* means render at the size of the source and don't scale.
+ * @scale: the window scale to render for
*
- * Renders an icon using gtk_render_icon_pixbuf(). In most cases,
- * gtk_widget_render_icon_pixbuf() is better, since it automatically provides
- * most of the arguments from the current widget settings. This
- * function never returns %NULL; if the icon can't be rendered
+ * Renders an icon using gtk_render_icon_pixbuf().
+ *
+ * This function never returns %NULL; if the icon can't be rendered
* (perhaps because an image file fails to load), a default "missing
* image" icon will be returned instead.
*
* Return value: (transfer full): a #GdkPixbuf to be displayed
*
- * Since: 3.0
+ * Since: 3.10
*/
-GdkPixbuf *
-gtk_icon_set_render_icon_pixbuf (GtkIconSet *icon_set,
- GtkStyleContext *context,
- GtkIconSize size)
+GdkPixbuf*
+gtk_icon_set_render_icon_pixbuf_for_scale (GtkIconSet *icon_set,
+ GtkStyleContext *context,
+ GtkIconSize size,
+ gint scale)
{
GdkPixbuf *icon = NULL;
GtkStateFlags flags = 0;
@@ -1737,26 +1758,98 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
if (icon_set->sources)
{
- icon = find_in_cache (icon_set, context, direction, state, size);
+ icon = find_in_cache (icon_set, context, direction, state, size, scale);
if (icon)
- {
- g_object_ref (icon);
- return icon;
- }
+ return g_object_ref (icon);
}
if (icon_set->sources)
- icon = find_and_render_icon_source (icon_set, context, direction, state, size);
+ icon = find_and_render_icon_source (icon_set, context, direction, state,
+ size, scale);
if (icon == NULL)
icon = render_fallback_image (context, direction, state, size);
- add_to_cache (icon_set, context, direction, state, size, icon);
+ add_to_cache (icon_set, context, direction, state, size, scale, icon);
return icon;
}
/**
+ * gtk_icon_set_render_icon_pixbuf:
+ * @icon_set: a #GtkIconSet
+ * @context: a #GtkStyleContext
+ * @size: (type int): icon size. A size of (GtkIconSize)-1
+ * means render at the size of the source and don't scale.
+ *
+ * Renders an icon using gtk_render_icon_pixbuf(). In most cases,
+ * gtk_widget_render_icon_pixbuf() is better, since it automatically provides
+ * most of the arguments from the current widget settings. This
+ * function never returns %NULL; if the icon can't be rendered
+ * (perhaps because an image file fails to load), a default "missing
+ * image" icon will be returned instead.
+ *
+ * Return value: (transfer full): a #GdkPixbuf to be displayed
+ *
+ * Since: 3.0
+ */
+GdkPixbuf *
+gtk_icon_set_render_icon_pixbuf (GtkIconSet *icon_set,
+ GtkStyleContext *context,
+ GtkIconSize size)
+{
+ g_return_val_if_fail (icon_set != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ return gtk_icon_set_render_icon_pixbuf_for_scale (icon_set, context, size, 1);
+}
+
+/**
+ * gtk_icon_set_render_icon_pattern:
+ * @icon_set: a #GtkIconSet
+ * @context: a #GtkStyleContext
+ * @size: (type int): icon size. A size of (GtkIconSize)-1
+ * means render at the size of the source and don't scale.
+ * @scale: the window scale to render for
+ * @for_window: (allow-none): #GdkWindow to optimize drawing for, or %NULL
+ *
+ * Renders an icon using gtk_render_icon_pixbuf() and converts it to a
+ * cairo pattern.
+ *
+ * This function never returns %NULL; if the icon can't be rendered
+ * (perhaps because an image file fails to load), a default "missing
+ * image" icon will be returned instead.
+ *
+ * Return value: (transfer full): a #cairo_pattern_t to be displayed
+ *
+ * Since: 3.10
+ */
+cairo_pattern_t *
+gtk_icon_set_render_icon_pattern (GtkIconSet *icon_set,
+ GtkStyleContext *context,
+ GtkIconSize size,
+ gint scale,
+ GdkWindow *for_window)
+{
+ GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ pixbuf = gtk_icon_set_render_icon_pixbuf_for_scale (icon_set, context, size, scale);
+
+ surface = gdk_cairo_pixbuf_to_surface (pixbuf, for_window);
+ g_object_unref (pixbuf);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_matrix_init_scale (&matrix, scale, scale);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ return pattern;
+}
+
+/**
* gtk_icon_set_render_icon:
* @icon_set: a #GtkIconSet
* @style: (allow-none): a #GtkStyle associated with @widget, or %NULL
@@ -1844,7 +1937,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
/* Order sources by their "wildness", so that "wilder" sources are
* greater than "specific" sources; for determining ordering,
- * direction beats state beats size.
+ * direction beats state beats size beats scale.
*/
static int
@@ -1865,6 +1958,10 @@ icon_source_compare (gconstpointer ap, gconstpointer bp)
return -1;
else if (a->any_size && !b->any_size)
return 1;
+ else if (!a->any_scale && b->any_scale)
+ return -1;
+ else if (a->any_scale && !b->any_scale)
+ return 1;
else
return 0;
}
@@ -2378,6 +2475,35 @@ gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
}
/**
+ * gtk_icon_source_set_scale_wildcarded:
+ * @source: a #GtkIconSource
+ * @setting: %TRUE to wildcard the scale
+ *
+ * If the icon scale is wildcarded, this source can be used as the base
+ * image for an icon of any scale. If the size is not wildcarded, then
+ * the scale the source applies to should be set with
+ * gtk_icon_source_set_scale() and the icon source will only be used
+ * with that specific size.
+ *
+ * #GtkIconSet prefers non-wildcarded sources (exact matches) over
+ * wildcarded sources, and will use an exact match when possible.
+ *
+ * #GtkIconSet will normally scale wildcarded source images to produce
+ * an appropriate icon at a given size, but will not change the size
+ * of source images that match exactly.
+ *
+ * Since: 3.10
+ */
+void
+gtk_icon_source_set_scale_wildcarded (GtkIconSource *source,
+ gboolean setting)
+{
+ g_return_if_fail (source != NULL);
+
+ source->any_scale = setting != FALSE;
+}
+
+/**
* gtk_icon_source_get_size_wildcarded:
* @source: a #GtkIconSource
*
@@ -2426,6 +2552,24 @@ gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
}
/**
+ * gtk_icon_source_get_scale_wildcarded:
+ * @source: a #GtkIconSource
+ *
+ * Gets the value set by gtk_icon_source_set_scale_wildcarded().
+ *
+ * Return value: %TRUE if this icon source is a base for any icon scale variant
+ *
+ * Since: 3.10
+ */
+gboolean
+gtk_icon_source_get_scale_wildcarded (const GtkIconSource *source)
+{
+ g_return_val_if_fail (source != NULL, TRUE);
+
+ return source->any_scale;
+}
+
+/**
* gtk_icon_source_set_direction:
* @source: a #GtkIconSource
* @direction: text direction this source applies to
@@ -2492,6 +2636,30 @@ gtk_icon_source_set_size (GtkIconSource *source,
}
/**
+ * gtk_icon_source_set_scale:
+ * @source: a #GtkIconSource
+ * @scale: scale this source applies to
+ *
+ * Sets the scale this icon source is intended to be used
+ * with.
+ *
+ * Setting the icon scale on an icon source makes no difference
+ * if the scale is wildcarded. Therefore, you should usually
+ * call gtk_icon_source_set_scale_wildcarded() to un-wildcard it
+ * in addition to calling this function.
+ *
+ * Since: 3.10
+ */
+void
+gtk_icon_source_set_scale (GtkIconSource *source,
+ gint scale)
+{
+ g_return_if_fail (source != NULL);
+
+ source->scale = scale;
+}
+
+/**
* gtk_icon_source_get_direction:
* @source: a #GtkIconSource
*
@@ -2544,6 +2712,25 @@ gtk_icon_source_get_size (const GtkIconSource *source)
return source->size;
}
+/**
+ * gtk_icon_source_get_scale:
+ * @source: a #GtkIconSource
+ *
+ * Obtains the scale this source applies to. The return value
+ * is only useful/meaningful if the scale is <emphasis>not</emphasis> wildcarded.
+ *
+ * Return value: scale this source matches.
+ *
+ * Since: 3.10
+ */
+gint
+gtk_icon_source_get_scale (const GtkIconSource *source)
+{
+ g_return_val_if_fail (source != NULL, 0);
+
+ return source->scale;
+}
+
#define NUM_CACHED_ICONS 8
typedef struct _CachedIcon CachedIcon;
@@ -2557,6 +2744,7 @@ struct _CachedIcon
GtkTextDirection direction;
GtkStateType state;
GtkIconSize size;
+ gint scale;
GdkPixbuf *pixbuf;
};
@@ -2585,7 +2773,8 @@ find_in_cache (GtkIconSet *icon_set,
GtkStyleContext *style_context,
GtkTextDirection direction,
GtkStateType state,
- GtkIconSize size)
+ GtkIconSize size,
+ gint scale)
{
GSList *tmp_list;
GSList *prev;
@@ -2601,6 +2790,7 @@ find_in_cache (GtkIconSet *icon_set,
if (icon->style == style_context &&
icon->direction == direction &&
icon->state == state &&
+ icon->scale == scale &&
(size == (GtkIconSize)-1 || icon->size == size))
{
if (prev)
@@ -2627,6 +2817,7 @@ add_to_cache (GtkIconSet *icon_set,
GtkTextDirection direction,
GtkStateType state,
GtkIconSize size,
+ gint scale,
GdkPixbuf *pixbuf)
{
CachedIcon *icon;
@@ -2643,6 +2834,7 @@ add_to_cache (GtkIconSet *icon_set,
icon->direction = direction;
icon->state = state;
icon->size = size;
+ icon->scale = scale;
icon->pixbuf = pixbuf;
attach_to_style (icon_set, icon->style);
diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h
index 8aeebdd..65848d1 100644
--- a/gtk/gtkiconfactory.h
+++ b/gtk/gtkiconfactory.h
@@ -193,12 +193,17 @@ void gtk_icon_source_set_state_wildcarded (GtkIconSource *
GDK_AVAILABLE_IN_ALL
void gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
gboolean setting);
+GDK_AVAILABLE_IN_3_10
+void gtk_icon_source_set_scale_wildcarded (GtkIconSource *source,
+ gboolean setting);
GDK_AVAILABLE_IN_ALL
gboolean gtk_icon_source_get_size_wildcarded (const GtkIconSource *source);
GDK_AVAILABLE_IN_ALL
gboolean gtk_icon_source_get_state_wildcarded (const GtkIconSource *source);
GDK_AVAILABLE_IN_ALL
gboolean gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source);
+GDK_AVAILABLE_IN_3_10
+gboolean gtk_icon_source_get_scale_wildcarded (const GtkIconSource *source);
GDK_AVAILABLE_IN_ALL
void gtk_icon_source_set_direction (GtkIconSource *source,
GtkTextDirection direction);
@@ -208,13 +213,17 @@ void gtk_icon_source_set_state (GtkIconSource *
GDK_AVAILABLE_IN_ALL
void gtk_icon_source_set_size (GtkIconSource *source,
GtkIconSize size);
+GDK_AVAILABLE_IN_3_10
+void gtk_icon_source_set_scale (GtkIconSource *source,
+ gint scale);
GDK_AVAILABLE_IN_ALL
GtkTextDirection gtk_icon_source_get_direction (const GtkIconSource *source);
GDK_AVAILABLE_IN_ALL
GtkStateType gtk_icon_source_get_state (const GtkIconSource *source);
GDK_AVAILABLE_IN_ALL
GtkIconSize gtk_icon_source_get_size (const GtkIconSource *source);
-
+GDK_AVAILABLE_IN_3_10
+gint gtk_icon_source_get_scale (const GtkIconSource *source);
/* ignore this */
void _gtk_icon_set_invalidate_caches (void);
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index a7719f0..f3ca674 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -879,6 +879,18 @@ GDK_AVAILABLE_IN_ALL
GdkPixbuf * gtk_icon_set_render_icon_pixbuf (GtkIconSet *icon_set,
GtkStyleContext *context,
GtkIconSize size);
+GDK_AVAILABLE_IN_3_10
+GdkPixbuf * gtk_icon_set_render_icon_pixbuf_for_scale (GtkIconSet *icon_set,
+ GtkStyleContext *context,
+ GtkIconSize size,
+ int scale);
+GDK_AVAILABLE_IN_3_10
+cairo_pattern_t *
+gtk_icon_set_render_icon_pattern (GtkIconSet *icon_set,
+ GtkStyleContext *context,
+ GtkIconSize size,
+ int scale,
+ GdkWindow *for_window);
GDK_AVAILABLE_IN_ALL
void gtk_style_context_set_screen (GtkStyleContext *context,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]