+static gchar *
+gdk_color_to_css (GdkColor *color)
+{
+ return g_strdup_printf ("rgb(%d,%d,%d)",
+ color->red >> 8,
+ color->green >> 8,
+ color->blue >> 8);
+}
+
+static gchar *
+gdk_rgba_to_css (const GdkRGBA *color)
+{
+ /* drop alpha for now, since librsvg does not understand rgba() */
+ return g_strdup_printf ("rgb(%d,%d,%d)",
+ (gint)(color->red * 255),
+ (gint)(color->green * 255),
+ (gint)(color->blue * 255));
+}
+
+static GdkPixbuf *
+_gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
+ const gchar *css_fg,
+ const gchar *css_success,
+ const gchar *css_warning,
+ const gchar *css_error,
+ GError **error)
+{
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+ gchar *data;
+ gchar *success, *warning, *err;
+
+ /* css_fg can't possibly have failed, otherwise
+ * that would mean we have a broken style */
+ g_return_val_if_fail (css_fg != NULL, NULL);
+
+ success = warning = err = NULL;
+
+ if (!css_success)
+ {
+ GdkColor success_default_color = { 0, 0x4e00, 0x9a00, 0x0600 };
+ success = gdk_color_to_css (&success_default_color);
+ }
+ if (!css_warning)
+ {
+ GdkColor warning_default_color = { 0, 0xf500, 0x7900, 0x3e00 };
+ warning = gdk_color_to_css (&warning_default_color);
+ }
+ if (!css_error)
+ {
+ GdkColor error_default_color = { 0, 0xcc00, 0x0000, 0x0000 };
+ err = gdk_color_to_css (&error_default_color);
+ }
+
+
+ data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<svg version=\"1.1\"\n"
+ " xmlns=\"http://www.w3.org/2000/svg\"\n"
+ " xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
+ " width=\"16\"\n"
+ " height=\"16\">\n"
+ " <style type=\"text/css\">\n"
+ " rect,path {\n"
+ " fill: ", css_fg," !important;\n"
+ " }\n"
+ " .warning {\n"
+ " fill: ", css_warning ? css_warning : warning," !important;\n"
+ " }\n"
+ " .error {\n"
+ " fill: ", css_error ? css_error : err," !important;\n"
+ " }\n"
+ " .success {\n"
+ " fill: ", css_success ? css_success : success," !important;\n"
+ " }\n"
+ " </style>\n"
+ " <xi:include href=\"", icon_info->filename, "\"/>\n"
+ "</svg>",
+ NULL);
+ g_free (warning);
+ g_free (err);
+ g_free (success);
+
+ stream = g_memory_input_stream_new_from_data (data, -1, g_free);
+ pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
+ icon_info->desired_size,
+ icon_info->desired_size,
+ TRUE,
+ NULL,
+ error);
+ g_object_unref (stream);
+
+ return pixbuf;
+}
+
+/**
+ * gtk_icon_info_load_symbolic:
+ * @icon_info: a #GtkIconInfo
+ * @fg: a #GdkRGBA representing the foreground color of the icon
+ * @success_color: (allow-none): a #GdkRGBA representing the warning color
+ * of the icon or %NULL to use the default color
+ * @warning_color: (allow-none): a #GdkRGBA representing the warning color
+ * of the icon or %NULL to use the default color
+ * @error_color: (allow-none): a #GdkRGBA representing the error color
+ * of the icon or %NULL to use the default color (allow-none)
+ * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
+ * loaded icon was a symbolic one and whether the @fg color was
+ * applied to it.
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Loads an icon, modifying it to match the system colours for the foreground,
+ * success, warning and error colors provided. If the icon is not a symbolic
+ * one, the function will return the result from gtk_icon_info_load_icon().
+ *
+ * This allows loading symbolic icons that will match the system theme.
+ *
+ * Unless you are implementing a widget, you will want to use
+ * g_themed_icon_new_with_default_fallbacks() to load the icon.
+ *
+ * As implementation details, the icon loaded needs to be of SVG type,
+ * contain the "symbolic" term as the last component of the icon name,
+ * and use the 'fg', 'success', 'warning' and 'error' CSS styles in the
+ * SVG file itself.
+ *
+ * See the <ulink url="http://www.freedesktop.org/wiki/SymbolicIcons">Symbolic Icons spec</ulink>
+ * for more information about symbolic icons.
+ *
+ * Return value: (transfer full): a #GdkPixbuf representing the loaded icon
+ *
+ * Since: 3.0
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ gchar *css_fg;
+ gchar *css_success;
+ gchar *css_warning;
+ gchar *css_error;
+
+ g_return_val_if_fail (fg != NULL, NULL);
+
+ if (!icon_info->filename ||
+ !g_str_has_suffix (icon_info->filename, "-symbolic.svg"))
+ {
+ if (was_symbolic)
+ *was_symbolic = FALSE;
+ return gtk_icon_info_load_icon (icon_info, error);
+ }
+
+ if (was_symbolic)
+ *was_symbolic = TRUE;
+
+ css_fg = gdk_rgba_to_css (fg);
+
+ css_success = css_warning = css_error = NULL;
+
+ if (warning_color)
+ css_warning = gdk_rgba_to_css (warning_color);
+
+ if (error_color)
+ css_error = gdk_rgba_to_css (error_color);
+
+ if (success_color)
+ css_success = gdk_rgba_to_css (success_color);
+
+ pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info,
+ css_fg, css_success,
+ css_warning, css_error,
+ error);
+ g_free (css_fg);
+ g_free (css_warning);
+ g_free (css_success);
+ g_free (css_error);
+
+ return pixbuf;
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_context:
+ * @icon_info: a #GtkIconInfo
+ * @context: a #GtkStyleContext
+ * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
+ * loaded icon was a symbolic one and whether the @fg color was
+ * applied to it.
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Loads an icon, modifying it to match the system colors for the foreground,
+ * success, warning and error colors provided. If the icon is not a symbolic
+ * one, the function will return the result from gtk_icon_info_load_icon().
+ * This function uses the regular foreground color and the symbolic colors
+ * with the names "success_color", "warning_color" and "error_color" from
+ * the context.
+ *
+ * This allows loading symbolic icons that will match the system theme.
+ *
+ * See gtk_icon_info_load_symbolic() for more details.
+ *
+ * Return value: (transfer full): a #GdkPixbuf representing the loaded icon
+ *
+ * Since: 3.0
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info,
+ GtkStyleContext *context,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ GdkRGBA *color = NULL;
+ GdkRGBA rgba;
+ gchar *css_fg = NULL, *css_success;
+ gchar *css_warning, *css_error;
+ GtkStateFlags state;
+
+ if (!icon_info->filename ||
+ !g_str_has_suffix (icon_info->filename, "-symbolic.svg"))
+ {
+ if (was_symbolic)
+ *was_symbolic = FALSE;
+ return gtk_icon_info_load_icon (icon_info, error);
+ }
+
+ if (was_symbolic)
+ *was_symbolic = TRUE;
+
+ state = gtk_style_context_get_state (context);
+ gtk_style_context_get (context, state, "color", &color, NULL);
+ if (color)
+ {
+ css_fg = gdk_rgba_to_css (color);
+ gdk_rgba_free (color);
+ }
+
+ css_success = css_warning = css_error = NULL;
+
+ if (gtk_style_context_lookup_color (context, "success_color", &rgba))
+ css_success = gdk_rgba_to_css (&rgba);
+
+ if (gtk_style_context_lookup_color (context, "warning_color", &rgba))
+ css_warning = gdk_rgba_to_css (&rgba);
+
+ if (gtk_style_context_lookup_color (context, "error_color", &rgba))
+ css_error = gdk_rgba_to_css (&rgba);
+
+ pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info,
+ css_fg, css_success,
+ css_warning, css_error,
+ error);
+
+ g_free (css_fg);
+ g_free (css_success);
+ g_free (css_warning);
+ g_free (css_error);
+
+ return pixbuf;
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_style:
+ * @icon_info: a #GtkIconInfo
+ * @style: a #GtkStyle to take the colors from
+ * @state: the widget state to use for colors
+ * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
+ * loaded icon was a symbolic one and whether the @fg color was
+ * applied to it.
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Loads an icon, modifying it to match the system colours for the foreground,
+ * success, warning and error colors provided. If the icon is not a symbolic
+ * one, the function will return the result from gtk_icon_info_load_icon().
+ *
+ * This allows loading symbolic icons that will match the system theme.
+ *
+ * See gtk_icon_info_load_symbolic() for more details.
+ *
+ * Return value: (transfer full): a #GdkPixbuf representing the loaded icon
+ *
+ * Since: 3.0
+ *
+ * Deprecated: 3.0: Use gtk_icon_info_load_symbolic_for_context() instead
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info,
+ GtkStyle *style,
+ GtkStateType state,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ GdkColor success_color;
+ GdkColor warning_color;
+ GdkColor error_color;
+ GdkColor *fg;
+ gchar *css_fg, *css_success;
+ gchar *css_warning, *css_error;
+
+ if (!icon_info->filename ||
+ !g_str_has_suffix (icon_info->filename, "-symbolic.svg"))
+ {
+ if (was_symbolic)
+ *was_symbolic = FALSE;
+ return gtk_icon_info_load_icon (icon_info, error);
+ }
+
+ if (was_symbolic)
+ *was_symbolic = TRUE;
+
+ fg = &style->fg[state];
+ css_fg = gdk_color_to_css (fg);
+
+ css_success = css_warning = css_error = NULL;
+
+ if (gtk_style_lookup_color (style, "success_color", &success_color))
+ css_success = gdk_color_to_css (&success_color);
+
+ if (gtk_style_lookup_color (style, "warning_color", &warning_color))
+ css_warning = gdk_color_to_css (&warning_color);
+
+ if (gtk_style_lookup_color (style, "error_color", &error_color))
+ css_error = gdk_color_to_css (&error_color);
+
+ pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info,
+ css_fg, css_success,
+ css_warning, css_error,
+ error);
+
+ g_free (css_fg);
+ g_free (css_success);
+ g_free (css_warning);
+ g_free (css_error);
+
+ return pixbuf;
+}
+