210
186
if (available_width >= 0 && available_height >= 0)
212
// This should keep the aspect ratio of the image intact, because if
213
// available_width < (available_height * width) / height
215
// (available_width * height) / width < available_height
216
// So we are guaranteed to either scale the image to have an available_width
217
// for width and height scaled accordingly OR have the available_height
218
// for height and width scaled accordingly, whichever scaling results
219
// in the image that can fit both available dimensions.
188
/* This should keep the aspect ratio of the image intact, because if
189
* available_width < (available_height * width) / height
191
* (available_width * height) / width < available_height
192
* So we are guaranteed to either scale the image to have an available_width
193
* for width and height scaled accordingly OR have the available_height
194
* for height and width scaled accordingly, whichever scaling results
195
* in the image that can fit both available dimensions.
220
197
scaled_width = MIN (available_width, (available_height * width) / height);
221
198
scaled_height = MIN (available_height, (available_width * height) / width);
309
// A private structure for keeping width and height.
286
/* A private structure for keeping width and height. */
292
/* This struct corresponds to a request for an texture.
293
* It's creasted when something needs a new texture,
294
* and destroyed when the texture data is loaded. */
296
StTextureCache *cache;
297
StTextureCachePolicy policy;
301
gboolean enforced_square;
309
GtkIconInfo *icon_info;
310
StIconColors *colors;
311
GtkRecentInfo *recent_info;
313
} AsyncTextureLoadData;
316
icon_lookup_data_destroy (gpointer p)
316
texture_load_data_destroy (gpointer p)
318
AsyncIconLookupData *data = p;
318
AsyncTextureLoadData *data = p;
322
322
g_object_unref (data->icon);
323
323
gtk_icon_info_free (data->icon_info);
325
st_icon_colors_unref (data->colors);
325
327
else if (data->uri)
326
328
g_free (data->uri);
329
else if (data->recent_info)
330
gtk_recent_info_unref (data->recent_info);
335
g_free (data->checksum);
327
336
if (data->mimetype)
328
337
g_free (data->mimetype);
329
if (data->recent_info)
330
gtk_recent_info_unref (data->recent_info);
332
st_icon_colors_unref (data->colors);
340
g_slist_free_full (data->textures, (GDestroyNotify) g_object_unref);
401
407
rotated_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
402
408
width_after_rotation = gdk_pixbuf_get_width (rotated_pixbuf);
404
// There is currently no way to tell if the pixbuf will need to be rotated before it is loaded,
405
// so we only check that once it is loaded, and reload it again if it needs to be rotated in order
406
// to use the available width and height correctly.
407
// http://bugzilla.gnome.org/show_bug.cgi?id=579003
410
/* There is currently no way to tell if the pixbuf will need to be rotated before it is loaded,
411
* so we only check that once it is loaded, and reload it again if it needs to be rotated in order
412
* to use the available width and height correctly.
413
* See http://bugzilla.gnome.org/show_bug.cgi?id=579003
408
415
if (width_before_rotation != width_after_rotation)
410
417
g_object_unref (pixbuf_loader);
531
impl_load_thumbnail (StTextureCache *cache,
533
const char *mime_type,
537
GnomeDesktopThumbnailFactory *thumbnail_factory;
538
GdkPixbuf *pixbuf = NULL;
540
GFileInfo *file_info;
543
char *existing_thumbnail;
545
file = g_file_new_for_uri (uri);
546
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
547
g_object_unref (file);
550
g_file_info_get_modification_time (file_info, &mtime_g);
551
g_object_unref (file_info);
552
mtime = (time_t) mtime_g.tv_sec;
555
thumbnail_factory = cache->priv->thumbnails;
557
existing_thumbnail = gnome_desktop_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
559
if (existing_thumbnail != NULL)
561
pixbuf = gdk_pixbuf_new_from_file_at_size (existing_thumbnail, size, size, error);
562
g_free (existing_thumbnail);
564
else if (gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
565
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Has failed thumbnail");
566
else if (gnome_desktop_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime))
568
pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
571
// we need to save the thumbnail so that we don't need to generate it again in the future
572
gnome_desktop_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
576
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to generate thumbnail");
577
gnome_desktop_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
584
538
icon_for_mimetype (const char *mimetype)
601
555
GCancellable *cancellable)
603
557
GdkPixbuf *pixbuf;
604
AsyncIconLookupData *data;
558
AsyncTextureLoadData *data;
605
559
GError *error = NULL;
607
data = g_object_get_data (G_OBJECT (result), "load_pixbuf_async");
561
data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
608
562
g_assert (data != NULL);
613
const char *mimetype;
615
if (data->recent_info)
617
uri = gtk_recent_info_get_uri (data->recent_info);
618
mimetype = gtk_recent_info_get_mime_type (data->recent_info);
623
mimetype = data->mimetype;
625
pixbuf = impl_load_thumbnail (data->cache, uri, mimetype, data->width, &error);
628
565
pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
629
566
else if (data->icon)
630
567
pixbuf = impl_load_pixbuf_gicon (data->icon, data->icon_info, data->width, data->colors, &error);
646
* load_icon_pixbuf_async:
648
* Asynchronously load the #GdkPixbuf associated with a #GIcon. Currently
649
* the #GtkIconInfo must have already been provided.
652
load_icon_pixbuf_async (StTextureCache *cache,
654
GtkIconInfo *icon_info,
656
StIconColors *colors,
657
GCancellable *cancellable,
658
GAsyncReadyCallback callback,
661
GSimpleAsyncResult *result;
662
AsyncIconLookupData *data;
664
data = g_new0 (AsyncIconLookupData, 1);
666
data->icon = g_object_ref (icon);
667
data->icon_info = gtk_icon_info_copy (icon_info);
668
data->width = data->height = size;
670
data->colors = st_icon_colors_ref (colors);
673
data->user_data = user_data;
675
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_icon_pixbuf_async);
677
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
678
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
680
g_object_unref (result);
684
load_uri_pixbuf_async (StTextureCache *cache,
688
GCancellable *cancellable,
689
GAsyncReadyCallback callback,
692
GSimpleAsyncResult *result;
693
AsyncIconLookupData *data;
695
data = g_new0 (AsyncIconLookupData, 1);
697
data->uri = g_strdup (uri);
699
data->height = height;
700
data->user_data = user_data;
702
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_uri_pixbuf_async);
704
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
705
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
707
g_object_unref (result);
711
load_thumbnail_async (StTextureCache *cache,
713
const char *mimetype,
715
GCancellable *cancellable,
716
GAsyncReadyCallback callback,
719
GSimpleAsyncResult *result;
720
AsyncIconLookupData *data;
722
data = g_new0 (AsyncIconLookupData, 1);
724
data->uri = g_strdup (uri);
725
data->mimetype = g_strdup (mimetype);
726
data->thumbnail = TRUE;
729
data->user_data = user_data;
731
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_thumbnail_async);
733
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
734
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
736
g_object_unref (result);
740
load_recent_thumbnail_async (StTextureCache *cache,
743
GCancellable *cancellable,
744
GAsyncReadyCallback callback,
747
GSimpleAsyncResult *result;
748
AsyncIconLookupData *data;
750
data = g_new0 (AsyncIconLookupData, 1);
752
data->thumbnail = TRUE;
753
data->recent_info = gtk_recent_info_ref (info);
756
data->user_data = user_data;
758
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_recent_thumbnail_async);
760
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
761
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
763
g_object_unref (result);
766
582
static GdkPixbuf *
767
583
load_pixbuf_async_finish (StTextureCache *cache, GAsyncResult *result, GError **error)
857
load_pixbuf_fallback(AsyncTextureLoadData *data)
859
GdkPixbuf *pixbuf = NULL;
864
GtkIconTheme *theme = gtk_icon_theme_get_default ();
866
if (data->recent_info)
867
pixbuf = gtk_recent_info_get_icon (data->recent_info, data->width);
870
GIcon *icon = icon_for_mimetype (data->mimetype);
873
GtkIconInfo *icon_info = gtk_icon_theme_lookup_by_gicon (theme,
876
GTK_ICON_LOOKUP_USE_BUILTIN);
877
g_object_unref (icon);
878
if (icon_info != NULL)
879
pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
884
pixbuf = gtk_icon_theme_load_icon (theme,
887
GTK_ICON_LOOKUP_USE_BUILTIN,
890
/* Maybe we could need a fallback for outher image types? */
896
657
on_pixbuf_loaded (GObject *source,
897
658
GAsyncResult *result,
943
702
cogl_handle_unref (texdata);
948
gtk_icon_info_free (data->icon_info);
949
g_object_unref (data->icon);
954
if (data->recent_info)
955
gtk_recent_info_unref (data->recent_info);
957
g_free (data->mimetype);
959
/* Alternatively we could weakref and just do nothing if the texture
961
for (iter = data->textures; iter; iter = iter->next)
963
ClutterTexture *texture = iter->data;
964
g_object_unref (texture);
704
texture_load_data_destroy (data);
967
707
g_clear_error (&error);
711
load_texture_async (StTextureCache *cache,
712
AsyncTextureLoadData *data)
714
GSimpleAsyncResult *result;
715
result = g_simple_async_result_new (G_OBJECT (cache), on_pixbuf_loaded, data, load_texture_async);
716
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, NULL);
717
g_object_unref (result);
1182
931
GtkIconInfo *info;
1183
932
StTextureCachePolicy policy;
934
/* Do theme lookups in the main thread to avoid thread-unsafety */
935
theme = cache->priv->icon_theme;
937
info = gtk_icon_theme_lookup_by_gicon (theme, icon, size, GTK_ICON_LOOKUP_USE_BUILTIN);
940
/* gah, the icon doesn't exist. Return a blank texture that will never load */
941
texture = CLUTTER_ACTOR (create_default_texture (cache));
942
clutter_actor_set_size (texture, size, size);
1185
946
gicon_string = g_icon_to_string (icon);
1186
947
/* A return value of NULL indicates that the icon can not be serialized,
1187
948
* so don't have a unique identifier for it as a cache key, and thus can't
1209
970
if (create_texture_and_ensure_request (cache, key, size, policy, &request, &texture))
972
/* If there's an outstanding request, we've just added ourselves to it */
1215
/* Do theme lookups in the main thread to avoid thread-unsafety */
1216
theme = cache->priv->icon_theme;
1218
info = gtk_icon_theme_lookup_by_gicon (theme, icon, size, GTK_ICON_LOOKUP_USE_BUILTIN);
977
/* Else, make a new request */
979
request->cache = cache;
1221
980
/* Transfer ownership of key */
1222
981
request->key = key;
1223
982
request->policy = policy;
1224
983
request->icon = g_object_ref (icon);
984
request->colors = colors ? st_icon_colors_ref (colors) : NULL;
1225
985
request->icon_info = info;
1226
986
request->width = request->height = size;
1227
987
request->enforced_square = TRUE;
1229
load_icon_pixbuf_async (cache, icon, info, size, colors, NULL, on_pixbuf_loaded, request);
1233
/* Blah; we failed to find the icon, but we've added our texture to the outstanding
1234
* requests. In that case, just undo what create_texture_and_ensure_request() did.
1236
g_slist_foreach (request->textures, (GFunc) g_object_unref, NULL);
1237
g_slist_free (request->textures);
1239
g_hash_table_remove (cache->priv->outstanding_requests, key);
1241
g_object_unref (texture);
989
load_texture_async (cache, request);
1245
992
return CLUTTER_ACTOR (texture);
1583
1330
texture = create_default_texture (cache);
1585
1332
data = g_new0 (AsyncTextureLoadData, 1);
1333
data->cache = cache;
1586
1334
data->key = g_strconcat (CACHE_PREFIX_URI, uri, NULL);
1587
1335
data->policy = ST_TEXTURE_CACHE_POLICY_NONE;
1588
1336
data->uri = g_strdup (uri);
1589
1337
data->width = available_width;
1590
1338
data->height = available_height;
1591
1339
data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
1592
load_uri_pixbuf_async (cache, uri, available_width, available_height, NULL, on_pixbuf_loaded, data);
1340
load_texture_async (cache, data);
1594
1342
return CLUTTER_ACTOR (texture);
1941
1689
return CLUTTER_ACTOR (texture);
1945
* st_texture_cache_load_thumbnail:
1947
* @size: Size in pixels to use for thumbnail
1949
* @mimetype: Source mime type
1951
* Asynchronously load a thumbnail image of a URI into a texture. The
1952
* returned texture object will be a new instance; however, its texture data
1953
* may be shared with other objects. This implies the texture data is cached.
1955
* The current caching policy is permanent; to uncache, you must explicitly
1956
* call st_texture_cache_unref_thumbnail().
1958
* Returns: (transfer none): A new #ClutterActor
1961
st_texture_cache_load_thumbnail (StTextureCache *cache,
1964
const char *mimetype)
1966
ClutterTexture *texture;
1967
AsyncTextureLoadData *data;
1971
/* Don't attempt to load thumbnails for non-local URIs */
1972
if (!g_str_has_prefix (uri, "file://"))
1974
GIcon *icon = icon_for_mimetype (mimetype);
1975
return st_texture_cache_load_gicon (cache, NULL, icon, size);
1978
texture = create_default_texture (cache);
1979
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
1981
key = g_strdup_printf (CACHE_PREFIX_THUMBNAIL_URI "uri=%s,size=%d", uri, size);
1983
texdata = g_hash_table_lookup (cache->priv->keyed_cache, key);
1986
data = g_new0 (AsyncTextureLoadData, 1);
1987
data->key = g_strdup (key);
1988
data->policy = ST_TEXTURE_CACHE_POLICY_FOREVER;
1989
data->uri = g_strdup (uri);
1990
data->mimetype = g_strdup (mimetype);
1991
data->thumbnail = TRUE;
1993
data->height = size;
1994
data->enforced_square = TRUE;
1995
data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
1996
load_thumbnail_async (cache, uri, mimetype, size, NULL, on_pixbuf_loaded, data);
2000
set_texture_cogl_texture (texture, texdata);
2004
return CLUTTER_ACTOR (texture);
2008
1693
icon_for_recent (GtkRecentInfo *info)
2018
1703
return icon_for_mimetype (mimetype);
2022
* st_texture_cache_load_recent_thumbnail:
2024
* @size: Size in pixels to use for thumbnail
2025
* @info: Recent item info
2027
* Asynchronously load a thumbnail image of a #GtkRecentInfo into a texture. The
2028
* returned texture object will be a new instance; however, its texture data
2029
* may be shared with other objects. This implies the texture data is cached.
2031
* The current caching policy is permanent; to uncache, you must explicitly
2032
* call st_texture_cache_unref_recent_thumbnail().
2034
* Returns: (transfer none): A new #ClutterActor
2037
st_texture_cache_load_recent_thumbnail (StTextureCache *cache,
2039
GtkRecentInfo *info)
2041
ClutterTexture *texture;
2042
AsyncTextureLoadData *data;
2047
uri = gtk_recent_info_get_uri (info);
2049
/* Don't attempt to load thumbnails for non-local URIs */
2050
if (!g_str_has_prefix (uri, "file://"))
2052
GIcon *icon = icon_for_recent (info);
2053
return st_texture_cache_load_gicon (cache, NULL, icon, size);
2056
texture = CLUTTER_TEXTURE (clutter_texture_new ());
2057
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
2059
key = g_strdup_printf (CACHE_PREFIX_THUMBNAIL_URI "uri=%s,size=%d", uri, size);
2061
texdata = g_hash_table_lookup (cache->priv->keyed_cache, key);
2064
data = g_new0 (AsyncTextureLoadData, 1);
2065
data->key = g_strdup (key);
2066
data->policy = ST_TEXTURE_CACHE_POLICY_FOREVER;
2067
data->thumbnail = TRUE;
2068
data->recent_info = gtk_recent_info_ref (info);
2070
data->height = size;
2071
data->enforced_square = TRUE;
2072
data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
2073
load_recent_thumbnail_async (cache, info, size, NULL, on_pixbuf_loaded, data);
2077
set_texture_cogl_texture (texture, texdata);
2081
return CLUTTER_ACTOR (texture);
2085
* st_texture_cache_evict_thumbnail:
2089
* Removes all references added by st_texture_cache_load_thumbnail() function
2090
* created for the given URI.
2093
st_texture_cache_evict_thumbnail (StTextureCache *cache,
2098
target_key = g_strconcat (CACHE_PREFIX_THUMBNAIL_URI, uri, NULL);
2099
g_hash_table_remove (cache->priv->keyed_cache, target_key);
2100
g_free (target_key);
2104
* st_texture_cache_evict_recent_thumbnail:
2106
* @info: A recent info
2108
* Removes all references added by st_texture_cache_load_recent_thumbnail() function
2109
* for the URI associated with the given @info.
2112
st_texture_cache_evict_recent_thumbnail (StTextureCache *cache,
2113
GtkRecentInfo *info)
2115
st_texture_cache_evict_thumbnail (cache, gtk_recent_info_get_uri (info));
2119
1707
pixbuf_byte_size (GdkPixbuf *pixbuf)