+ /* Instead of returning the pixbuf directly we
+ return a proxy to it that we don't own (but that
+ shares the data with the one we own). This way
+ we can know when it is freed and ensure the
+ IconInfo is alive (and thus cached) while
+ the pixbuf is still alive. */
+
+ if (icon_info->proxy_pixbuf != NULL)
+ return g_object_ref (icon_info->proxy_pixbuf);
+
+ icon_info->proxy_pixbuf =
+ gdk_pixbuf_new_from_data (gdk_pixbuf_get_pixels (icon_info->pixbuf),
+ gdk_pixbuf_get_colorspace (icon_info->pixbuf),
+ gdk_pixbuf_get_has_alpha (icon_info->pixbuf),
+ gdk_pixbuf_get_bits_per_sample (icon_info->pixbuf),
+ gdk_pixbuf_get_width (icon_info->pixbuf),
+ gdk_pixbuf_get_height (icon_info->pixbuf),
+ gdk_pixbuf_get_rowstride (icon_info->pixbuf),
+ proxy_pixbuf_destroy,
+ g_object_ref (icon_info));
+
+ return icon_info->proxy_pixbuf;
+}
+
+static void
+load_icon_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GtkIconInfo *dup = task_data;
+
+ icon_info_ensure_scale_and_pixbuf (dup, FALSE);
+ g_task_return_pointer (task, NULL, NULL);
+}
+
+/**
+ * gtk_icon_info_load_icon_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale an icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_icon() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_icon_async (GtkIconInfo *icon_info,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GdkPixbuf *pixbuf;
+ GtkIconInfo *dup;
+ GError *error = NULL;
+
+ task = g_task_new (icon_info, cancellable, callback, user_data);
+
+ if (icon_info_get_pixbuf_ready (icon_info))
+ {
+ pixbuf = gtk_icon_info_load_icon (icon_info, &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ g_object_unref (task);
+ }
+ else
+ {
+ dup = icon_info_dup (icon_info);
+ g_task_set_task_data (task, dup, g_object_unref);
+ g_task_run_in_thread (task, load_icon_thread);
+ g_object_unref (task);
+ }
+}
+
+/**
+ * gtk_icon_info_load_icon_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_icon_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_icon_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = G_TASK (result);
+ GtkIconInfo *dup;
+
+ g_return_val_if_fail (g_task_is_valid (result, icon_info), NULL);
+
+ dup = g_task_get_task_data (task);
+ if (dup == NULL || g_task_had_error (task))
+ return g_task_propagate_pointer (task, error);
+
+ /* We ran the thread and it was not cancelled */
+
+ /* Check if someone else updated the icon_info in between */
+ if (!icon_info_get_pixbuf_ready (icon_info))
+ {
+ /* If not, copy results from dup back to icon_info */
+
+ icon_info->emblems_applied = dup->emblems_applied;
+ icon_info->scale = dup->scale;
+ g_clear_object (&icon_info->pixbuf);
+ if (dup->pixbuf)
+ icon_info->pixbuf = g_object_ref (dup->pixbuf);
+ g_clear_error (&icon_info->load_error);
+ if (dup->load_error)
+ icon_info->load_error = g_error_copy (dup->load_error);
+ }
+
+ g_assert (icon_info_get_pixbuf_ready (icon_info));
+
+ /* This is now guaranteed to not block */
+ return gtk_icon_info_load_icon (icon_info, error);
+}
+
+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 void
+proxy_symbolic_pixbuf_destroy (guchar *pixels, gpointer data)
+{
+ GtkIconInfo *icon_info = data;
+ GtkIconTheme *icon_theme = icon_info->in_cache;
+ SymbolicPixbufCache *symbolic_cache;
+
+ for (symbolic_cache = icon_info->symbolic_pixbuf_cache;
+ symbolic_cache != NULL;
+ symbolic_cache = symbolic_cache->next)
+ {
+ if (symbolic_cache->proxy_pixbuf != NULL &&
+ gdk_pixbuf_get_pixels (symbolic_cache->proxy_pixbuf) == pixels)
+ break;
+ }
+
+ g_assert (symbolic_cache != NULL);
+ g_assert (symbolic_cache->proxy_pixbuf != NULL);
+
+ symbolic_cache->proxy_pixbuf = NULL;
+
+ /* Keep it alive a bit longer */
+ if (icon_theme != NULL)
+ ensure_in_lru_cache (icon_theme, icon_info);
+
+ g_object_unref (icon_info);
+}
+
+static GdkPixbuf *
+symbolic_cache_get_proxy (SymbolicPixbufCache *symbolic_cache,
+ GtkIconInfo *icon_info)
+{
+ if (symbolic_cache->proxy_pixbuf)
+ return g_object_ref (symbolic_cache->proxy_pixbuf);
+
+ symbolic_cache->proxy_pixbuf =
+ gdk_pixbuf_new_from_data (gdk_pixbuf_get_pixels (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_colorspace (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_has_alpha (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_bits_per_sample (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_width (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_height (symbolic_cache->pixbuf),
+ gdk_pixbuf_get_rowstride (symbolic_cache->pixbuf),
+ proxy_symbolic_pixbuf_destroy,
+ g_object_ref (icon_info));
+
+ return symbolic_cache->proxy_pixbuf;
+}
+
+static GdkPixbuf *
+_gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ gboolean use_cache,
+ GError **error)
+{
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+ gchar *css_fg;
+ gchar *css_success;
+ gchar *css_warning;
+ gchar *css_error;
+ gchar *data;
+ gchar *width, *height, *uri;
+ SymbolicPixbufCache *symbolic_cache;
+
+ if (use_cache)
+ {
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ fg, success_color, warning_color, error_color);
+ if (symbolic_cache)
+ return symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ }
+
+ /* css_fg can't possibly have failed, otherwise
+ * that would mean we have a broken style */
+ g_return_val_if_fail (fg != NULL, NULL);
+
+ 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);
+
+ if (!css_success)
+ {
+ GdkColor success_default_color = { 0, 0x4e00, 0x9a00, 0x0600 };
+ css_success = gdk_color_to_css (&success_default_color);
+ }
+ if (!css_warning)
+ {
+ GdkColor warning_default_color = { 0, 0xf500, 0x7900, 0x3e00 };
+ css_warning = gdk_color_to_css (&warning_default_color);
+ }
+ if (!css_error)
+ {
+ GdkColor error_default_color = { 0, 0xcc00, 0x0000, 0x0000 };
+ css_error = gdk_color_to_css (&error_default_color);
+ }
+
+ if (!icon_info->symbolic_pixbuf_size)
+ {
+ stream = G_INPUT_STREAM (g_file_read (icon_info->icon_file, NULL, error));
+
+ if (!stream)
+ return NULL;
+
+ /* Fetch size from the original icon */
+ pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+ g_object_unref (stream);
+
+ if (!pixbuf)
+ return NULL;
+
+ icon_info->symbolic_pixbuf_size = gtk_requisition_new ();
+ icon_info->symbolic_pixbuf_size->width = gdk_pixbuf_get_width (pixbuf);
+ icon_info->symbolic_pixbuf_size->height = gdk_pixbuf_get_height (pixbuf);
+ g_object_unref (pixbuf);
+ }
+
+ width = g_strdup_printf ("%d", icon_info->symbolic_pixbuf_size->width);
+ height = g_strdup_printf ("%d", icon_info->symbolic_pixbuf_size->height);
+ uri = g_file_get_uri (icon_info->icon_file);
+
+ 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=\"", width, "\"\n"
+ " height=\"", height, "\">\n"
+ " <style type=\"text/css\">\n"
+ " rect,path {\n"
+ " fill: ", css_fg," !important;\n"
+ " }\n"
+ " .warning {\n"
+ " fill: ", css_warning, " !important;\n"
+ " }\n"
+ " .error {\n"
+ " fill: ", css_error ," !important;\n"
+ " }\n"
+ " .success {\n"
+ " fill: ", css_success, " !important;\n"
+ " }\n"
+ " </style>\n"
+ " <xi:include href=\"", uri, "\"/>\n"
+ "</svg>",
+ NULL);
+ g_free (css_fg);
+ g_free (css_warning);
+ g_free (css_error);
+ g_free (css_success);
+ g_free (width);
+ g_free (height);
+ g_free (uri);
+
+ 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);
+
+ if (pixbuf != NULL)
+ {
+ if (use_cache)
+ {
+ icon_info->symbolic_pixbuf_cache =
+ symbolic_pixbuf_cache_new (pixbuf, fg, success_color, warning_color, error_color,
+ icon_info->symbolic_pixbuf_cache);
+ g_object_unref (pixbuf);
+ return symbolic_cache_get_proxy (icon_info->symbolic_pixbuf_cache, icon_info);
+ }
+ else
+ return pixbuf;
+ }
+
+ return NULL;
+}
+
+/**
+ * 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)
+{
+ gchar *icon_uri;
+ gboolean is_symbolic;
+
+ g_return_val_if_fail (icon_info != NULL, NULL);
+ g_return_val_if_fail (fg != NULL, NULL);
+
+ icon_uri = NULL;
+ if (icon_info->icon_file)
+ icon_uri = g_file_get_uri (icon_info->icon_file);
+
+ is_symbolic = (icon_uri != NULL) && (g_str_has_suffix (icon_uri, "-symbolic.svg"));
+ g_free (icon_uri);
+
+ if (was_symbolic)
+ *was_symbolic = is_symbolic;
+
+ if (!is_symbolic)
+ return gtk_icon_info_load_icon (icon_info, error);
+
+ return _gtk_icon_info_load_symbolic_internal (icon_info,
+ fg, success_color,
+ warning_color, error_color,
+ TRUE,
+ error);
+}
+
+/**
+ * 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)
+{
+ GdkRGBA *color = NULL;
+ GdkRGBA fg;
+ GdkRGBA *fgp;
+ GdkRGBA success_color;
+ GdkRGBA *success_colorp;
+ GdkRGBA warning_color;
+ GdkRGBA *warning_colorp;
+ GdkRGBA error_color;
+ GdkRGBA *error_colorp;
+ GtkStateFlags state;
+ gchar *icon_uri;
+ gboolean is_symbolic;
+
+ g_return_val_if_fail (icon_info != NULL, NULL);
+ g_return_val_if_fail (context != NULL, NULL);
+
+ icon_uri = NULL;
+ if (icon_info->icon_file)
+ icon_uri = g_file_get_uri (icon_info->icon_file);
+
+ is_symbolic = (icon_uri != NULL) && (g_str_has_suffix (icon_uri, "-symbolic.svg"));
+ g_free (icon_uri);
+
+ if (was_symbolic)
+ *was_symbolic = is_symbolic;
+
+ if (!is_symbolic)
+ return gtk_icon_info_load_icon (icon_info, error);
+
+ fgp = success_colorp = warning_colorp = error_colorp = NULL;
+
+ state = gtk_style_context_get_state (context);
+ gtk_style_context_get (context, state, "color", &color, NULL);
+ if (color)
+ {
+ fg = *color;
+ fgp = &fg;
+ gdk_rgba_free (color);
+ }
+
+ if (gtk_style_context_lookup_color (context, "success_color", &success_color))
+ success_colorp = &success_color;
+
+ if (gtk_style_context_lookup_color (context, "warning_color", &warning_color))
+ warning_colorp = &warning_color;
+
+ if (gtk_style_context_lookup_color (context, "error_color", &error_color))
+ error_colorp = &error_color;
+
+ return _gtk_icon_info_load_symbolic_internal (icon_info,
+ fgp, success_colorp,
+ warning_colorp, error_colorp,
+ TRUE,
+ error);
+}
+
+typedef struct {
+ gboolean is_symbolic;
+ GtkIconInfo *dup;
+ GdkRGBA fg;
+ gboolean fg_set;
+ GdkRGBA success_color;
+ gboolean success_color_set;
+ GdkRGBA warning_color;
+ gboolean warning_color_set;
+ GdkRGBA error_color;
+ gboolean error_color_set;
+} AsyncSymbolicData;
+
+static void
+async_symbolic_data_free (AsyncSymbolicData *data)
+{
+ if (data->dup)
+ g_object_unref (data->dup);
+ g_slice_free (AsyncSymbolicData, data);
+}
+
+static void
+async_load_no_symbolic_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkIconInfo *icon_info = GTK_ICON_INFO (source_object);
+ GTask *task = user_data;
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+
+ pixbuf = gtk_icon_info_load_icon_finish (icon_info, res, &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+load_symbolic_icon_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ AsyncSymbolicData *data = task_data;
+ GError *error;
+ GdkPixbuf *pixbuf;
+
+ error = NULL;
+ pixbuf =
+ _gtk_icon_info_load_symbolic_internal (data->dup,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL,
+ FALSE,
+ &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @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)
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale a symbolic icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_symbolic() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_symbolic_async (GtkIconInfo *icon_info,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ AsyncSymbolicData *data;
+ gchar *icon_uri;
+ SymbolicPixbufCache *symbolic_cache;
+ GdkPixbuf *pixbuf;
+
+ g_return_if_fail (icon_info != NULL);
+ g_return_if_fail (fg != NULL);
+
+ task = g_task_new (icon_info, cancellable, callback, user_data);
+
+ data = g_slice_new0 (AsyncSymbolicData);
+ g_task_set_task_data (task, data, (GDestroyNotify) async_symbolic_data_free);
+
+ icon_uri = NULL;
+ if (icon_info->icon_file)
+ icon_uri = g_file_get_uri (icon_info->icon_file);
+
+ data->is_symbolic = (icon_uri != NULL) && (g_str_has_suffix (icon_uri, "-symbolic.svg"));
+ g_free (icon_uri);
+
+ if (!data->is_symbolic)
+ {
+ gtk_icon_info_load_icon_async (icon_info, cancellable, async_load_no_symbolic_cb, g_object_ref (task));
+ }
+ else
+ {
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ fg, success_color, warning_color, error_color);
+ if (symbolic_cache)
+ {
+ pixbuf = symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ }
+ else
+ {
+ if (fg)
+ {
+ data->fg = *fg;
+ data->fg_set = TRUE;
+ }
+
+ if (success_color)
+ {
+ data->success_color = *success_color;
+ data->success_color_set = TRUE;
+ }
+
+ if (warning_color)
+ {
+ data->warning_color = *warning_color;
+ data->warning_color_set = TRUE;
+ }
+
+ if (error_color)
+ {
+ data->error_color = *error_color;
+ data->error_color_set = TRUE;
+ }
+
+ data->dup = icon_info_dup (icon_info);
+ g_task_run_in_thread (task, load_symbolic_icon_thread);
+ }
+ }
+ g_object_unref (task);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @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.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_symbolic_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ GTask *task = G_TASK (result);
+ AsyncSymbolicData *data = g_task_get_task_data (task);
+ SymbolicPixbufCache *symbolic_cache;
+ GdkPixbuf *pixbuf;
+
+ if (was_symbolic)
+ *was_symbolic = data->is_symbolic;
+
+ if (data->dup && !g_task_had_error (task))
+ {
+ pixbuf = g_task_propagate_pointer (task, NULL);
+
+ g_assert (pixbuf != NULL); /* we checked for !had_error above */
+
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL);
+
+ if (symbolic_cache == NULL)
+ {
+ symbolic_cache = icon_info->symbolic_pixbuf_cache =
+ symbolic_pixbuf_cache_new (pixbuf,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL,
+ icon_info->symbolic_pixbuf_cache);
+ }
+
+ g_object_unref (pixbuf);
+
+ return symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ }
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_context_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @context: a #GtkStyleContext
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale a symbolic icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_symbolic_for_context() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_symbolic_for_context_async (GtkIconInfo *icon_info,
+ GtkStyleContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkRGBA *color = NULL;
+ GdkRGBA fg;
+ GdkRGBA *fgp;
+ GdkRGBA success_color;
+ GdkRGBA *success_colorp;
+ GdkRGBA warning_color;
+ GdkRGBA *warning_colorp;
+ GdkRGBA error_color;
+ GdkRGBA *error_colorp;
+ GtkStateFlags state;
+
+ g_return_if_fail (icon_info != NULL);
+ g_return_if_fail (context != NULL);
+
+ fgp = success_colorp = warning_colorp = error_colorp = NULL;
+
+ state = gtk_style_context_get_state (context);
+ gtk_style_context_get (context, state, "color", &color, NULL);
+ if (color)
+ {
+ fg = *color;
+ fgp = &fg;
+ gdk_rgba_free (color);
+ }
+
+ if (gtk_style_context_lookup_color (context, "success_color", &success_color))
+ success_colorp = &success_color;
+
+ if (gtk_style_context_lookup_color (context, "warning_color", &warning_color))
+ warning_colorp = &warning_color;
+
+ if (gtk_style_context_lookup_color (context, "error_color", &error_color))
+ error_colorp = &error_color;
+
+ gtk_icon_info_load_symbolic_async (icon_info,
+ fgp, success_colorp,
+ warning_colorp, error_colorp,
+ cancellable, callback, user_data);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_context_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @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.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_symbolic_for_context_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_for_context_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ return gtk_icon_info_load_symbolic_finish (icon_info, result, was_symbolic, error);
+}
+
+static GdkRGBA *
+color_to_rgba (GdkColor *color, GdkRGBA *rgba)
+{
+ rgba->red = color->red / 65535.0;
+ rgba->green = color->green / 65535.0;
+ rgba->blue = color->blue / 65535.0;
+ rgba->alpha = 1.0;
+ return rgba;
+}
+
+/**
+ * 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)
+{
+ GdkColor color;
+ GdkRGBA fg;
+ GdkRGBA success_color;
+ GdkRGBA *success_colorp;
+ GdkRGBA warning_color;
+ GdkRGBA *warning_colorp;
+ GdkRGBA error_color;
+ GdkRGBA *error_colorp;
+ gchar *icon_uri;
+ gboolean is_symbolic;
+
+ g_return_val_if_fail (icon_info != NULL, NULL);
+ g_return_val_if_fail (style != NULL, NULL);
+
+ icon_uri = NULL;
+ if (icon_info->icon_file)
+ icon_uri = g_file_get_uri (icon_info->icon_file);
+
+ is_symbolic = (icon_uri != NULL) && (g_str_has_suffix (icon_uri, "-symbolic.svg"));
+ g_free (icon_uri);
+
+ if (was_symbolic)
+ *was_symbolic = is_symbolic;
+
+ if (!is_symbolic)
+ return gtk_icon_info_load_icon (icon_info, error);
+
+ color_to_rgba (&style->fg[state], &fg);
+
+ success_colorp = warning_colorp = error_colorp = NULL;
+
+ if (gtk_style_lookup_color (style, "success_color", &color))
+ success_colorp = color_to_rgba (&color, &success_color);
+
+ if (gtk_style_lookup_color (style, "warning_color", &color))
+ warning_colorp = color_to_rgba (&color, &warning_color);
+
+ if (gtk_style_lookup_color (style, "error_color", &color))
+ error_colorp = color_to_rgba (&color, &error_color);
+
+ return _gtk_icon_info_load_symbolic_internal (icon_info,
+ &fg, success_colorp,
+ warning_colorp, error_colorp,
+ TRUE,
+ error);