forked from AuroraMiddleware/gtk
Add gtk_icon_info_load_icon_async
This lets you asynchronously load icons. We need this for gnome-shell to replace its current non-threadsafe use of GtkIconTheme. https://bugzilla.gnome.org/show_bug.cgi?id=693802
This commit is contained in:
parent
e2d0846386
commit
7690846c3f
@ -1255,6 +1255,8 @@ gtk_icon_info_get_embedded_rect
|
|||||||
gtk_icon_info_get_filename
|
gtk_icon_info_get_filename
|
||||||
gtk_icon_info_get_type
|
gtk_icon_info_get_type
|
||||||
gtk_icon_info_load_icon
|
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
|
||||||
gtk_icon_info_load_symbolic_for_context
|
gtk_icon_info_load_symbolic_for_context
|
||||||
gtk_icon_info_load_symbolic_for_style
|
gtk_icon_info_load_symbolic_for_style
|
||||||
|
@ -350,6 +350,7 @@ static void do_theme_change (GtkIconTheme *icon_theme);
|
|||||||
static void blow_themes (GtkIconTheme *icon_themes);
|
static void blow_themes (GtkIconTheme *icon_themes);
|
||||||
static gboolean rescan_themes (GtkIconTheme *icon_themes);
|
static gboolean rescan_themes (GtkIconTheme *icon_themes);
|
||||||
|
|
||||||
|
static GtkIconData *icon_data_dup (GtkIconData *icon_data);
|
||||||
static void icon_data_free (GtkIconData *icon_data);
|
static void icon_data_free (GtkIconData *icon_data);
|
||||||
static void load_icon_data (IconThemeDir *dir,
|
static void load_icon_data (IconThemeDir *dir,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -2972,6 +2973,26 @@ icon_data_free (GtkIconData *icon_data)
|
|||||||
g_slice_free (GtkIconData, icon_data);
|
g_slice_free (GtkIconData, icon_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GtkIconData *
|
||||||
|
icon_data_dup (GtkIconData *icon_data)
|
||||||
|
{
|
||||||
|
GtkIconData *dup = NULL;
|
||||||
|
if (icon_data)
|
||||||
|
{
|
||||||
|
dup = g_slice_new0 (GtkIconData);
|
||||||
|
*dup = *icon_data;
|
||||||
|
if (dup->n_attach_points > 0)
|
||||||
|
{
|
||||||
|
dup->attach_points = g_memdup (dup->attach_points,
|
||||||
|
sizeof (GdkPoint) * dup->n_attach_points);
|
||||||
|
}
|
||||||
|
dup->display_name = g_strdup (dup->display_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GtkIconInfo
|
* GtkIconInfo
|
||||||
*/
|
*/
|
||||||
@ -2992,6 +3013,45 @@ icon_info_new (void)
|
|||||||
return g_object_new (GTK_TYPE_ICON_INFO, NULL);
|
return g_object_new (GTK_TYPE_ICON_INFO, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This only copies whatever is needed to load the pixbuf, so that we can do
|
||||||
|
* a load in a thread without affecting the original IconInfo from the thread.
|
||||||
|
*/
|
||||||
|
static GtkIconInfo *
|
||||||
|
icon_info_dup (GtkIconInfo *icon_info)
|
||||||
|
{
|
||||||
|
GtkIconInfo *dup;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
dup = icon_info_new ();
|
||||||
|
|
||||||
|
dup->filename = g_strdup (icon_info->filename);
|
||||||
|
if (icon_info->icon_file)
|
||||||
|
dup->icon_file = g_object_ref (icon_info->icon_file);
|
||||||
|
if (icon_info->loadable)
|
||||||
|
dup->loadable = g_object_ref (icon_info->loadable);
|
||||||
|
|
||||||
|
for (l = icon_info->emblem_infos; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
dup->emblem_infos =
|
||||||
|
g_slist_append (dup->emblem_infos,
|
||||||
|
icon_info_dup (l->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon_info->cache_pixbuf)
|
||||||
|
dup->cache_pixbuf = g_object_ref (icon_info->cache_pixbuf);
|
||||||
|
|
||||||
|
dup->data = icon_data_dup (icon_info->data);
|
||||||
|
dup->dir_type = icon_info->dir_type;
|
||||||
|
dup->dir_size = icon_info->dir_size;
|
||||||
|
dup->threshold = icon_info->threshold;
|
||||||
|
dup->desired_size = icon_info->desired_size;
|
||||||
|
dup->raw_coordinates = icon_info->raw_coordinates;
|
||||||
|
dup->forced_size = icon_info->forced_size;
|
||||||
|
dup->emblems_applied = icon_info->emblems_applied;
|
||||||
|
|
||||||
|
return dup;
|
||||||
|
}
|
||||||
|
|
||||||
static GtkIconInfo *
|
static GtkIconInfo *
|
||||||
icon_info_new_builtin (BuiltinIcon *icon)
|
icon_info_new_builtin (BuiltinIcon *icon)
|
||||||
{
|
{
|
||||||
@ -3238,6 +3298,21 @@ apply_emblems (GtkIconInfo *info)
|
|||||||
info->emblems_applied = TRUE;
|
info->emblems_applied = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this returns TRUE, its safe to call
|
||||||
|
icon_info_ensure_scale_and_pixbuf without blocking */
|
||||||
|
static gboolean
|
||||||
|
icon_info_get_pixbuf_ready (GtkIconInfo *icon_info)
|
||||||
|
{
|
||||||
|
if (icon_info->pixbuf &&
|
||||||
|
(icon_info->emblem_infos == NULL || icon_info->emblems_applied))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (icon_info->load_error)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function contains the complicated logic for deciding
|
/* This function contains the complicated logic for deciding
|
||||||
* on the size at which to load the icon and loading it at
|
* on the size at which to load the icon and loading it at
|
||||||
* that size.
|
* that size.
|
||||||
@ -3504,6 +3579,119 @@ gtk_icon_info_load_icon (GtkIconInfo *icon_info,
|
|||||||
return icon_info->proxy_pixbuf;
|
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 *
|
static gchar *
|
||||||
gdk_color_to_css (GdkColor *color)
|
gdk_color_to_css (GdkColor *color)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +203,15 @@ const gchar * gtk_icon_info_get_filename (GtkIconInfo *icon_info
|
|||||||
GdkPixbuf * gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info);
|
GdkPixbuf * gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info);
|
||||||
GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info,
|
GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
GDK_AVAILABLE_IN_3_8
|
||||||
|
void gtk_icon_info_load_icon_async (GtkIconInfo *icon_info,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
GDK_AVAILABLE_IN_3_8
|
||||||
|
GdkPixbuf * gtk_icon_info_load_icon_finish (GtkIconInfo *icon_info,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
GdkPixbuf * gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
|
GdkPixbuf * gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
|
||||||
const GdkRGBA *fg,
|
const GdkRGBA *fg,
|
||||||
const GdkRGBA *success_color,
|
const GdkRGBA *success_color,
|
||||||
|
@ -34,6 +34,28 @@ usage (void)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
icon_loaded_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
pixbuf = gtk_icon_info_load_icon_finish (GTK_ICON_INFO (source_object),
|
||||||
|
res, &error);
|
||||||
|
|
||||||
|
if (pixbuf == NULL)
|
||||||
|
{
|
||||||
|
g_print ("%s\n", error->message);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_image_set_from_pixbuf (GTK_IMAGE (user_data), pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
@ -101,6 +123,45 @@ main (int argc, char *argv[])
|
|||||||
G_CALLBACK (gtk_main_quit), window);
|
G_CALLBACK (gtk_main_quit), window);
|
||||||
gtk_widget_show_all (window);
|
gtk_widget_show_all (window);
|
||||||
|
|
||||||
|
gtk_main ();
|
||||||
|
}
|
||||||
|
else if (strcmp (argv[1], "display-async") == 0)
|
||||||
|
{
|
||||||
|
GtkWidget *window, *image;
|
||||||
|
GtkIconSize size;
|
||||||
|
GtkIconInfo *info;
|
||||||
|
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
g_object_unref (icon_theme);
|
||||||
|
usage ();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc >= 5)
|
||||||
|
size = atoi (argv[4]);
|
||||||
|
else
|
||||||
|
size = GTK_ICON_SIZE_BUTTON;
|
||||||
|
|
||||||
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||||
|
image = gtk_image_new ();
|
||||||
|
gtk_container_add (GTK_CONTAINER (window), image);
|
||||||
|
g_signal_connect (window, "delete-event",
|
||||||
|
G_CALLBACK (gtk_main_quit), window);
|
||||||
|
gtk_widget_show_all (window);
|
||||||
|
|
||||||
|
info = gtk_icon_theme_lookup_icon (icon_theme, argv[3], size,
|
||||||
|
GTK_ICON_LOOKUP_USE_BUILTIN);
|
||||||
|
|
||||||
|
if (info == NULL)
|
||||||
|
{
|
||||||
|
g_print ("Icon not found\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_icon_info_load_icon_async (info,
|
||||||
|
NULL, icon_loaded_cb, image);
|
||||||
|
|
||||||
gtk_main ();
|
gtk_main ();
|
||||||
}
|
}
|
||||||
else if (strcmp (argv[1], "list") == 0)
|
else if (strcmp (argv[1], "list") == 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user