+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);
+}
+