diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c index 6c4530261b..9aba0fa6ea 100644 --- a/gtk/gtkstyle.c +++ b/gtk/gtkstyle.c @@ -327,6 +327,9 @@ static void hls_to_rgb (gdouble *h, static void style_unrealize_cursors (GtkStyle *style); +static void transform_detail_string (const gchar *detail, + GtkStyleContext *context); + /* * Data for default check and radio buttons */ @@ -1607,54 +1610,6 @@ out: cairo_restore (cr); } -static GdkPixbuf * -scale_or_ref (GdkPixbuf *src, - gint width, - gint height) -{ - if (width == gdk_pixbuf_get_width (src) && - height == gdk_pixbuf_get_height (src)) - { - return g_object_ref (src); - } - else - { - return gdk_pixbuf_scale_simple (src, - width, height, - GDK_INTERP_BILINEAR); - } -} - -static gboolean -lookup_icon_size (GtkStyle *style, - GtkWidget *widget, - GtkIconSize size, - gint *width, - gint *height) -{ - GdkScreen *screen; - GtkSettings *settings; - - if (widget && gtk_widget_has_screen (widget)) - { - screen = gtk_widget_get_screen (widget); - settings = gtk_settings_get_for_screen (screen); - } - else if (style && style->visual) - { - screen = gdk_visual_get_screen (style->visual); - settings = gtk_settings_get_for_screen (screen); - } - else - { - settings = gtk_settings_get_default (); - GTK_NOTE (MULTIHEAD, - g_warning ("Using the default screen for gtk_default_render_icon()")); - } - - return gtk_icon_size_lookup_for_settings (settings, size, width, height); -} - static GdkPixbuf * gtk_default_render_icon (GtkStyle *style, const GtkIconSource *source, @@ -1664,65 +1619,31 @@ gtk_default_render_icon (GtkStyle *style, GtkWidget *widget, const gchar *detail) { - gint width = 1; - gint height = 1; - GdkPixbuf *scaled; - GdkPixbuf *stated; - GdkPixbuf *base_pixbuf; + GtkStyleContext *context; + GtkStylePrivate *priv; + GdkPixbuf *pixbuf; - /* Oddly, style can be NULL in this function, because - * GtkIconSet can be used without a style and if so - * it uses this function. - */ - - base_pixbuf = gtk_icon_source_get_pixbuf (source); - - g_return_val_if_fail (base_pixbuf != NULL, NULL); - - if (size != (GtkIconSize) -1 && !lookup_icon_size(style, widget, size, &width, &height)) + if (widget) + context = gtk_widget_get_style_context (widget); + else { - g_warning (G_STRLOC ": invalid icon size '%d'", size); - return NULL; + priv = GTK_STYLE_GET_PRIVATE (style); + context = priv->context; } - /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise, - * leave it alone. - */ - if (size != (GtkIconSize)-1 && gtk_icon_source_get_size_wildcarded (source)) - scaled = scale_or_ref (base_pixbuf, width, height); - else - scaled = g_object_ref (base_pixbuf); + if (!context) + return NULL; - /* If the state was wildcarded, then generate a state. */ - if (gtk_icon_source_get_state_wildcarded (source)) - { - if (state == GTK_STATE_INSENSITIVE) - { - stated = gdk_pixbuf_copy (scaled); - - gdk_pixbuf_saturate_and_pixelate (scaled, stated, - 0.8, TRUE); - - g_object_unref (scaled); - } - else if (state == GTK_STATE_PRELIGHT) - { - stated = gdk_pixbuf_copy (scaled); - - gdk_pixbuf_saturate_and_pixelate (scaled, stated, - 1.2, FALSE); - - g_object_unref (scaled); - } - else - { - stated = scaled; - } - } - else - stated = scaled; - - return stated; + gtk_style_context_save (context); + + if (detail) + transform_detail_string (detail, context); + + pixbuf = gtk_render_icon_pixbuf (context, source, size); + + gtk_style_context_restore (context); + + return pixbuf; } static void diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index fe4084e79a..aaaf78209d 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -3270,3 +3270,36 @@ gtk_render_activity (GtkStyleContext *context, _gtk_theming_engine_set_context (priv->theming_engine, context); engine_class->render_activity (priv->theming_engine, cr, x, y, width, height); } + +/** + * gtk_render_icon_pixbuf: + * @context: a #GtkStyleContext + * @source: the #GtkIconSource specifying the icon to render + * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1 + * means render at the size of the source and don't scale. + * + * Renders the icon specified by @source at the given @size, returning the result + * in a pixbuf. + * + * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon + * + * Since: 3.0 + **/ +GdkPixbuf * +gtk_render_icon_pixbuf (GtkStyleContext *context, + const GtkIconSource *source, + GtkIconSize size) +{ + GtkStyleContextPrivate *priv; + GtkThemingEngineClass *engine_class; + + g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); + g_return_val_if_fail (size >= -1, NULL); + g_return_val_if_fail (source != NULL, NULL); + + priv = context->priv; + engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + + _gtk_theming_engine_set_context (priv->theming_engine, context); + return engine_class->render_icon_pixbuf (priv->theming_engine, source, size); +} diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h index c57d914c9c..30c08b8b2b 100644 --- a/gtk/gtkstylecontext.h +++ b/gtk/gtkstylecontext.h @@ -404,6 +404,10 @@ void gtk_render_activity (GtkStyleContext *context, gdouble width, gdouble height); +GdkPixbuf * gtk_render_icon_pixbuf (GtkStyleContext *context, + const GtkIconSource *source, + GtkIconSize size); + G_END_DECLS #endif /* __GTK_STYLE_CONTEXT_H__ */ diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c index bd299f3202..65a3a55600 100644 --- a/gtk/gtkthemingengine.c +++ b/gtk/gtkthemingengine.c @@ -168,6 +168,9 @@ static void gtk_theming_engine_render_activity (GtkThemingEngine *engine, gdouble y, gdouble width, gdouble height); +static GdkPixbuf * gtk_theming_engine_render_icon_pixbuf (GtkThemingEngine *engine, + const GtkIconSource *source, + GtkIconSize size); G_DEFINE_TYPE (GtkThemingEngine, gtk_theming_engine, G_TYPE_OBJECT) @@ -220,6 +223,7 @@ gtk_theming_engine_class_init (GtkThemingEngineClass *klass) klass->render_extension = gtk_theming_engine_render_extension; klass->render_handle = gtk_theming_engine_render_handle; klass->render_activity = gtk_theming_engine_render_activity; + klass->render_icon_pixbuf = gtk_theming_engine_render_icon_pixbuf; /** * GtkThemingEngine:name: @@ -2807,3 +2811,91 @@ gtk_theming_engine_render_activity (GtkThemingEngine *engine, gtk_theming_engine_render_frame (engine, cr, x, y, width, height); } } + +static GdkPixbuf * +scale_or_ref (GdkPixbuf *src, + gint width, + gint height) +{ + if (width == gdk_pixbuf_get_width (src) && + height == gdk_pixbuf_get_height (src)) + return g_object_ref (src); + else + return gdk_pixbuf_scale_simple (src, + width, height, + GDK_INTERP_BILINEAR); +} + +static gboolean +lookup_icon_size (GtkThemingEngine *engine, + GtkIconSize size, + gint *width, + gint *height) +{ + GdkScreen *screen; + GtkSettings *settings; + + screen = gtk_theming_engine_get_screen (engine); + settings = gtk_settings_get_for_screen (screen); + + return gtk_icon_size_lookup_for_settings (settings, size, width, height); +} + +static GdkPixbuf * +gtk_theming_engine_render_icon_pixbuf (GtkThemingEngine *engine, + const GtkIconSource *source, + GtkIconSize size) +{ + GdkPixbuf *scaled; + GdkPixbuf *stated; + GdkPixbuf *base_pixbuf; + GtkStateFlags state; + gint width = 1; + gint height = 1; + + base_pixbuf = gtk_icon_source_get_pixbuf (source); + state = gtk_theming_engine_get_state (engine); + + g_return_val_if_fail (base_pixbuf != NULL, NULL); + + if (size != (GtkIconSize) -1 && + !lookup_icon_size (engine, size, &width, &height)) + { + g_warning (G_STRLOC ": invalid icon size '%d'", size); + return NULL; + } + + /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise, + * leave it alone. + */ + if (size != (GtkIconSize) -1 && + gtk_icon_source_get_size_wildcarded (source)) + scaled = scale_or_ref (base_pixbuf, width, height); + else + scaled = g_object_ref (base_pixbuf); + + /* If the state was wildcarded, then generate a state. */ + if (gtk_icon_source_get_state_wildcarded (source)) + { + if (state & GTK_STATE_FLAG_INSENSITIVE) + { + stated = gdk_pixbuf_copy (scaled); + gdk_pixbuf_saturate_and_pixelate (scaled, stated, + 0.8, TRUE); + g_object_unref (scaled); + } + else if (state & GTK_STATE_FLAG_PRELIGHT) + { + stated = gdk_pixbuf_copy (scaled); + gdk_pixbuf_saturate_and_pixelate (scaled, stated, + 1.2, FALSE); + g_object_unref (scaled); + } + else + stated = scaled; + } + else + stated = scaled; + + return stated; +} diff --git a/gtk/gtkthemingengine.h b/gtk/gtkthemingengine.h index 78842c6f16..bc830b37f2 100644 --- a/gtk/gtkthemingengine.h +++ b/gtk/gtkthemingengine.h @@ -157,6 +157,10 @@ struct _GtkThemingEngineClass gdouble y, gdouble width, gdouble height); + + GdkPixbuf * (* render_icon_pixbuf) (GtkThemingEngine *engine, + const GtkIconSource *source, + GtkIconSize size); }; GType gtk_theming_engine_get_type (void) G_GNUC_CONST;