[gtk+/wip/window-scales: 52/69] icon helper: Support scaled icons
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/window-scales: 52/69] icon helper: Support scaled icons
- Date: Fri, 28 Jun 2013 10:23:13 +0000 (UTC)
commit 721c384f4ffa9e65ebe049dc38ac65c70655d68b
Author: Alexander Larsson <alexl redhat com>
Date: Tue Jun 25 14:27:21 2013 +0200
icon helper: Support scaled icons
gtk/gtkiconhelper.c | 186 ++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 153 insertions(+), 33 deletions(-)
---
diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c
index 7c54549..1272e49 100644
--- a/gtk/gtkiconhelper.c
+++ b/gtk/gtkiconhelper.c
@@ -19,6 +19,7 @@
#include "config.h"
+#include <math.h>
#include "gtkiconhelperprivate.h"
G_DEFINE_TYPE (GtkIconHelper, _gtk_icon_helper, G_TYPE_OBJECT)
@@ -45,7 +46,10 @@ struct _GtkIconHelperPrivate {
GtkStateFlags last_rendered_state;
cairo_pattern_t *rendered_pattern;
+ gint rendered_pattern_width;
+ gint rendered_pattern_height;
GtkStateFlags last_pattern_state;
+ gint last_pattern_scale;
};
void
@@ -57,6 +61,12 @@ _gtk_icon_helper_clear (GtkIconHelper *self)
g_clear_object (&self->priv->rendered_pixbuf);
g_clear_object (&self->priv->window);
+ if (self->priv->rendered_pattern)
+ {
+ cairo_pattern_destroy (self->priv->rendered_pattern);
+ self->priv->rendered_pattern = NULL;
+ }
+
if (self->priv->icon_set != NULL)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
@@ -74,6 +84,8 @@ _gtk_icon_helper_clear (GtkIconHelper *self)
self->priv->storage_type = GTK_IMAGE_EMPTY;
self->priv->icon_size = GTK_ICON_SIZE_INVALID;
self->priv->last_rendered_state = GTK_STATE_FLAG_NORMAL;
+ self->priv->last_pattern_state = GTK_STATE_FLAG_NORMAL;
+ self->priv->last_pattern_scale = 0;
}
void
@@ -382,19 +394,40 @@ _gtk_icon_helper_ensure_pixbuf (GtkIconHelper *self,
return pixbuf;
}
+static gint
+get_scale_factor (GtkIconHelper *self,
+ GtkStyleContext *context)
+{
+ GdkScreen *screen;
+
+ if (self->priv->window)
+ return gdk_window_get_scale_factor (self->priv->window);
+
+ screen = gtk_style_context_get_screen (context);
+
+ /* else fall back to something that is more likely to be right than
+ * just returning 1:
+ */
+ return gdk_screen_get_monitor_scale_factor (screen, 0);
+}
+
static gboolean
check_invalidate_pattern (GtkIconHelper *self,
GtkStyleContext *context)
{
GtkStateFlags state;
+ int scale;
state = gtk_style_context_get_state (context);
+ scale = get_scale_factor (self, context);
if ((self->priv->rendered_pattern != NULL) &&
- (self->priv->last_pattern_state == state))
+ (self->priv->last_pattern_state == state) &&
+ (self->priv->last_pattern_scale == scale))
return FALSE;
self->priv->last_pattern_state = state;
+ self->priv->last_pattern_scale = scale;
if (self->priv->rendered_pattern)
cairo_pattern_destroy (self->priv->rendered_pattern);
@@ -410,6 +443,8 @@ ensure_pattern_at_size (GtkIconHelper *self,
gint width, height;
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
+ cairo_matrix_t matrix;
+ int scale;
if (!check_invalidate_pattern (self, context))
return;
@@ -417,11 +452,15 @@ ensure_pattern_at_size (GtkIconHelper *self,
if (self->priv->rendered_pattern)
return;
+ scale = get_scale_factor (self, context);
+
if (self->priv->force_scale_pixbuf &&
(self->priv->pixel_size != -1 ||
self->priv->icon_size != GTK_ICON_SIZE_INVALID))
{
ensure_icon_size (self, context, &width, &height);
+ width *= scale;
+ height *= scale;
if (width < gdk_pixbuf_get_width (self->priv->orig_pixbuf) ||
height < gdk_pixbuf_get_height (self->priv->orig_pixbuf))
@@ -434,13 +473,21 @@ ensure_pattern_at_size (GtkIconHelper *self,
pixbuf = g_object_ref (self->priv->orig_pixbuf);
}
else
- pixbuf = g_object_ref (self->priv->orig_pixbuf);
+ {
+ pixbuf = g_object_ref (self->priv->orig_pixbuf);
+ scale = 1;
+ }
+
+ self->priv->rendered_pattern_width = (gdk_pixbuf_get_width (pixbuf) + scale - 1) / scale;
+ self->priv->rendered_pattern_height = (gdk_pixbuf_get_height (pixbuf) + scale - 1) / scale;
surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
g_object_unref (pixbuf);
self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
+ cairo_matrix_init_scale (&matrix, scale, scale);
+ cairo_pattern_set_matrix (self->priv->rendered_pattern, &matrix);
}
static void
@@ -448,19 +495,99 @@ ensure_pattern_for_icon_set (GtkIconHelper *self,
GtkStyleContext *context,
GtkIconSet *icon_set)
{
- GdkPixbuf *pixbuf;
cairo_surface_t *surface;
+ gint scale;
if (!check_invalidate_pattern (self, context))
return;
- pixbuf =
- gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
+ scale = get_scale_factor (self, context);
- surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
- g_object_unref (pixbuf);
- self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
- cairo_surface_destroy (surface);
+ self->priv->rendered_pattern =
+ gtk_icon_set_render_icon_pattern (icon_set, context, self->priv->icon_size,
+ scale, self->priv->window);
+
+ if (self->priv->rendered_pattern &&
+ !cairo_pattern_get_surface (self->priv->rendered_pattern,
+ &surface))
+ {
+ cairo_matrix_t matrix;
+ cairo_pattern_get_matrix (self->priv->rendered_pattern, &matrix);
+ self->priv->rendered_pattern_width =
+ ceil (cairo_image_surface_get_width (surface) / matrix.xx);
+ self->priv->rendered_pattern_height =
+ ceil (cairo_image_surface_get_height (surface) / matrix.yy);
+ }
+}
+
+static void
+ensure_stated_pattern_from_info (GtkIconHelper *self,
+ GtkStyleContext *context,
+ GtkIconInfo *info,
+ int scale)
+{
+ GdkPixbuf *destination = NULL;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ gboolean symbolic;
+ cairo_matrix_t matrix;
+
+ symbolic = FALSE;
+
+ if (info)
+ destination =
+ gtk_icon_info_load_symbolic_for_context (info,
+ context,
+ &symbolic,
+ NULL);
+
+ if (destination == NULL)
+ {
+ GtkIconSet *icon_set;
+ icon_set = gtk_style_context_lookup_icon_set (context, GTK_STOCK_MISSING_IMAGE);
+
+ destination =
+ gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
+ }
+ else if (!symbolic)
+ {
+ GtkIconSource *source;
+ GdkPixbuf *rendered;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ source = gtk_icon_source_new ();
+ gtk_icon_source_set_pixbuf (source, destination);
+ /* The size here is arbitrary; since size isn't
+ * wildcarded in the source, it isn't supposed to be
+ * scaled by the engine function
+ */
+ gtk_icon_source_set_size (source,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_icon_source_set_size_wildcarded (source, FALSE);
+
+ rendered = gtk_render_icon_pixbuf (context, source, (GtkIconSize) -1);
+ gtk_icon_source_free (source);
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ g_object_unref (destination);
+ destination = rendered;
+ }
+
+ pattern = NULL;
+ if (destination)
+ {
+ surface = gdk_cairo_pixbuf_to_surface (destination, self->priv->window);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_matrix_init_scale (&matrix, scale, scale);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ self->priv->rendered_pattern_width = (gdk_pixbuf_get_width (destination) + scale - 1) / scale;
+ self->priv->rendered_pattern_height = (gdk_pixbuf_get_height (destination) + scale - 1) / scale;
+ }
+
+ self->priv->rendered_pattern = pattern;
}
static void
@@ -468,10 +595,8 @@ ensure_pattern_for_icon_name_or_gicon (GtkIconHelper *self,
GtkStyleContext *context)
{
GtkIconTheme *icon_theme;
- gint width, height;
+ gint width, height, scale;
GtkIconInfo *info;
- GdkPixbuf *pixbuf;
- cairo_surface_t *surface;
GtkIconLookupFlags flags;
if (!check_invalidate_pattern (self, context))
@@ -481,20 +606,23 @@ ensure_pattern_for_icon_name_or_gicon (GtkIconHelper *self,
flags = get_icon_lookup_flags (self);
ensure_icon_size (self, context, &width, &height);
+ scale = get_scale_factor (self, context);
if (self->priv->storage_type == GTK_IMAGE_ICON_NAME &&
self->priv->icon_name != NULL)
{
- info = gtk_icon_theme_lookup_icon (icon_theme,
- self->priv->icon_name,
- MIN (width, height), flags);
+ info = gtk_icon_theme_lookup_icon_for_scale (icon_theme,
+ self->priv->icon_name,
+ MIN (width, height),
+ scale, flags);
}
else if (self->priv->storage_type == GTK_IMAGE_GICON &&
self->priv->gicon != NULL)
{
- info = gtk_icon_theme_lookup_by_gicon (icon_theme,
- self->priv->gicon,
- MIN (width, height), flags);
+ info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme,
+ self->priv->gicon,
+ MIN (width, height),
+ scale, flags);
}
else
{
@@ -502,14 +630,7 @@ ensure_pattern_for_icon_name_or_gicon (GtkIconHelper *self,
return;
}
- pixbuf = ensure_stated_icon_from_info (self, context, info);
- if (pixbuf)
- {
- surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
- g_object_unref (pixbuf);
- self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
- cairo_surface_destroy (surface);
- }
+ ensure_stated_pattern_from_info (self, context, info, scale);
if (info)
g_object_unref (info);
@@ -566,18 +687,17 @@ _gtk_icon_helper_get_size (GtkIconHelper *self,
gint *width_out,
gint *height_out)
{
- GdkPixbuf *pix;
+ cairo_pattern_t *pattern;
gint width, height;
width = height = 0;
- pix = _gtk_icon_helper_ensure_pixbuf (self, context);
+ pattern = _gtk_icon_helper_ensure_pattern (self, context);
- if (pix != NULL)
+ if (pattern != NULL)
{
- width = gdk_pixbuf_get_width (pix);
- height = gdk_pixbuf_get_height (pix);
-
- g_object_unref (pix);
+ width = self->priv->rendered_pattern_width;
+ height = self->priv->rendered_pattern_height;
+ cairo_pattern_destroy (pattern);
}
else if (self->priv->storage_type == GTK_IMAGE_ANIMATION)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]