diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index ff0ee486d5..8231f02886 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1258,7 +1258,11 @@ gtk_icon_info_load_icon gtk_icon_info_load_icon_async gtk_icon_info_load_icon_finish gtk_icon_info_load_symbolic +gtk_icon_info_load_symbolic_async +gtk_icon_info_load_symbolic_finish gtk_icon_info_load_symbolic_for_context +gtk_icon_info_load_symbolic_for_context_async +gtk_icon_info_load_symbolic_for_context_finish gtk_icon_info_load_symbolic_for_style gtk_icon_info_new_for_pixbuf gtk_icon_info_set_raw_coordinates diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index de5c96c6b9..e2c9eaa340 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -3766,7 +3766,8 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, const GdkRGBA *success_color, const GdkRGBA *warning_color, const GdkRGBA *error_color, - GError **error) + gboolean use_cache, + GError **error) { GInputStream *stream; GdkPixbuf *pixbuf; @@ -3778,10 +3779,13 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, gchar *width, *height, *uri; SymbolicPixbufCache *symbolic_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); + 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 */ @@ -3882,11 +3886,16 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, if (pixbuf != NULL) { - 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); + 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; @@ -3960,6 +3969,7 @@ gtk_icon_info_load_symbolic (GtkIconInfo *icon_info, return _gtk_icon_info_load_symbolic_internal (icon_info, fg, success_color, warning_color, error_color, + TRUE, error); } @@ -4046,9 +4056,332 @@ gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info, 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_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) { @@ -4134,6 +4467,7 @@ gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info, return _gtk_icon_info_load_symbolic_internal (icon_info, &fg, success_colorp, warning_colorp, error_colorp, + TRUE, error); } diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h index 3888cdab7b..4b3ba79867 100644 --- a/gtk/gtkicontheme.h +++ b/gtk/gtkicontheme.h @@ -219,10 +219,35 @@ GdkPixbuf * gtk_icon_info_load_symbolic (GtkIconInfo *icon_info const GdkRGBA *error_color, gboolean *was_symbolic, GError **error); +GDK_AVAILABLE_IN_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); +GDK_AVAILABLE_IN_3_8 +GdkPixbuf * gtk_icon_info_load_symbolic_finish (GtkIconInfo *icon_info, + GAsyncResult *res, + gboolean *was_symbolic, + GError **error); GdkPixbuf * gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info, GtkStyleContext *context, gboolean *was_symbolic, GError **error); +GDK_AVAILABLE_IN_3_8 +void gtk_icon_info_load_symbolic_for_context_async (GtkIconInfo *icon_info, + GtkStyleContext *context, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GDK_AVAILABLE_IN_3_8 +GdkPixbuf * gtk_icon_info_load_symbolic_for_context_finish (GtkIconInfo *icon_info, + GAsyncResult *res, + gboolean *was_symbolic, + GError **error); GDK_DEPRECATED_IN_3_0_FOR(gtk_icon_info_load_symbol_for_context) GdkPixbuf * gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info, GtkStyle *style,