[glib/gio-thumbnail-sizes] file-info: Add a set of attributes for large thumbnails




commit 8d2962a05b9e6c222b1c72efbd55c25a7c2ddc57
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Sep 22 16:29:41 2022 -0400

    file-info: Add a set of attributes for large thumbnails
    
    Some applications (eg., gnome-photos) really want a large thumbnail,
    if one can be created. Simply falling back to a smaller one (probably
    created by an old nautilus), without giving the application a chance
    to create a bigger thumbnail, is undesirable because they will appear
    fuzzy.
    
    Therefore, at separate attribute sets for all the thumbnail sizes
    that are supported in the spec: normal/large/x-large/xx-large.
    
    The old attribute will now return by default the biggest available, as
    it used to be, but also including the x-large and xx-large cases.
    
    Co-Authored-by: Marco Trevisan <mail 3v1n0 net>

 docs/reference/gio/gio-sections-common.txt |  12 ++
 gio/gfileinfo-priv.h                       |  12 ++
 gio/gfileinfo.c                            |  12 ++
 gio/gfileinfo.h                            | 174 ++++++++++++++++++++++++++-
 gio/glocalfileinfo.c                       | 159 +++++++++++++++++++++---
 gio/tests/file-thumbnail.c                 | 187 +++++++++++++++++++++++++++++
 6 files changed, 538 insertions(+), 18 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index 0ef50d747c..2ec1f0bb23 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -350,6 +350,18 @@ G_FILE_ATTRIBUTE_OWNER_GROUP
 G_FILE_ATTRIBUTE_THUMBNAIL_PATH
 G_FILE_ATTRIBUTE_THUMBNAILING_FAILED
 G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID
+G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL
+G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL
+G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL
+G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE
+G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE
+G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE
+G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE
+G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE
+G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE
+G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE
+G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE
+G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE
 G_FILE_ATTRIBUTE_PREVIEW_ICON
 G_FILE_ATTRIBUTE_FILESYSTEM_SIZE
 G_FILE_ATTRIBUTE_FILESYSTEM_FREE
diff --git a/gio/gfileinfo-priv.h b/gio/gfileinfo-priv.h
index 8fc085973b..4d31818c3b 100644
--- a/gio/gfileinfo-priv.h
+++ b/gio/gfileinfo-priv.h
@@ -99,6 +99,18 @@
 #define G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH (10485760 + 1)
 #define G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED (10485760 + 2)
 #define G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID (10485760 + 3)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL (10485760 + 4)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL (10485760 + 5)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL (10485760 + 6)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE (10485760 + 7)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE (10485760 + 8)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE (10485760 + 9)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE (10485760 + 10)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE (10485760 + 11)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE (10485760 + 12)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE (10485760 + 13)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE (10485760 + 14)
+#define G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE (10485760 + 15)
 #define G_FILE_ATTRIBUTE_ID_PREVIEW_ICON (11534336 + 1)
 #define G_FILE_ATTRIBUTE_ID_FILESYSTEM_SIZE (12582912 + 1)
 #define G_FILE_ATTRIBUTE_ID_FILESYSTEM_FREE (12582912 + 2)
diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c
index f709bf4f1f..43a73ee386 100644
--- a/gio/gfileinfo.c
+++ b/gio/gfileinfo.c
@@ -265,6 +265,18 @@ ensure_attribute_hash (void)
   REGISTER_ATTRIBUTE (THUMBNAIL_PATH);
   REGISTER_ATTRIBUTE (THUMBNAILING_FAILED);
   REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID);
+  REGISTER_ATTRIBUTE (THUMBNAIL_PATH_NORMAL);
+  REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_NORMAL);
+  REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_NORMAL);
+  REGISTER_ATTRIBUTE (THUMBNAIL_PATH_LARGE);
+  REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_LARGE);
+  REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_LARGE);
+  REGISTER_ATTRIBUTE (THUMBNAIL_PATH_XLARGE);
+  REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_XLARGE);
+  REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_XLARGE);
+  REGISTER_ATTRIBUTE (THUMBNAIL_PATH_XXLARGE);
+  REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_XXLARGE);
+  REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_XXLARGE);
   REGISTER_ATTRIBUTE (PREVIEW_ICON);
   REGISTER_ATTRIBUTE (FILESYSTEM_SIZE);
   REGISTER_ATTRIBUTE (FILESYSTEM_FREE);
diff --git a/gio/gfileinfo.h b/gio/gfileinfo.h
index b8123c34ed..74b25a2b86 100644
--- a/gio/gfileinfo.h
+++ b/gio/gfileinfo.h
@@ -917,7 +917,7 @@ typedef struct _GFileInfoClass   GFileInfoClass;
  * G_FILE_ATTRIBUTE_THUMBNAIL_PATH:
  *
  * A key in the "thumbnail" namespace for getting the path to the thumbnail
- * image.
+ * image with the biggest size available.
  *
  * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BYTE_STRING.
  **/
@@ -949,6 +949,178 @@ typedef struct _GFileInfoClass   GFileInfoClass;
  */
 #define G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID "thumbnail::is-valid"        /* boolean */
 
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL:
+ *
+ * A key in the "thumbnail" namespace for getting the path to the thumbnail
+ * image with the biggest size available.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BYTE_STRING.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL "thumbnail::path-normal"         /* bytestring */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL:
+ *
+ * A key in the "thumbnail" namespace for checking if thumbnailing failed
+ * for the image with the biggest size available.
+ *
+ * This attribute is %TRUE if thumbnailing failed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL "thumbnail::failed-normal"         /* boolean */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL:
+ *
+ * A key in the "thumbnail" namespace for checking whether the normal
+ * thumbnail is outdated.
+ *
+ * This attribute is %TRUE if the normal thumbnail is up-to-date with the file
+ * it represents, and %FALSE if the file has been modified since the thumbnail
+ * was generated.
+ *
+ * If %G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL is %TRUE and this attribute
+ * is %FALSE, it indicates that thumbnailing may be attempted again and may succeed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL "thumbnail::is-valid-normal"        /* boolean */
+
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE:
+ *
+ * A key in the "thumbnail" namespace for getting the path to the large thumbnail
+ * image.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BYTE_STRING.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE "thumbnail::path-large"         /* bytestring */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE:
+ *
+ * A key in the "thumbnail" namespace for checking if thumbnailing failed
+ * for the large image.
+ *
+ * This attribute is %TRUE if thumbnailing failed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE "thumbnail::failed-large"         /* boolean */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE:
+ *
+ * A key in the "thumbnail" namespace for checking whether the large
+ * thumbnail is outdated.
+ *
+ * This attribute is %TRUE if the large thumbnail is up-to-date with the file
+ * it represents, and %FALSE if the file has been modified since the thumbnail
+ * was generated.
+ *
+ * If %G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE is %TRUE and this attribute
+ * is %FALSE, it indicates that thumbnailing may be attempted again and may succeed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE "thumbnail::is-valid-large"        /* boolean */
+
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE:
+ *
+ * A key in the "thumbnail" namespace for getting the path to the x-large thumbnail
+ * image.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BYTE_STRING.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE "thumbnail::path-xlarge"         /* bytestring */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE:
+ *
+ * A key in the "thumbnail" namespace for checking if thumbnailing failed
+ * for the x-large image.
+ *
+ * This attribute is %TRUE if thumbnailing failed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE "thumbnail::failed-xlarge"         /* boolean */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE:
+ *
+ * A key in the "thumbnail" namespace for checking whether the x-large
+ * thumbnail is outdated.
+ *
+ * This attribute is %TRUE if the x-large thumbnail is up-to-date with the file
+ * it represents, and %FALSE if the file has been modified since the thumbnail
+ * was generated.
+ *
+ * If %G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE is %TRUE and this attribute
+ * is %FALSE, it indicates that thumbnailing may be attempted again and may succeed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE "thumbnail::is-valid-xlarge"        /* boolean */
+
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE:
+ *
+ * A key in the "thumbnail" namespace for getting the path to the xx-large thumbnail
+ * image.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BYTE_STRING.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE "thumbnail::path-xxlarge"         /* bytestring */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE:
+ *
+ * A key in the "thumbnail" namespace for checking if thumbnailing failed
+ * for the xx-large image.
+ *
+ * This attribute is %TRUE if thumbnailing failed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE "thumbnail::failed-xxlarge"         /* boolean */
+/**
+ * G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE:
+ *
+ * A key in the "thumbnail" namespace for checking whether the xx-large
+ * thumbnail is outdated.
+ *
+ * This attribute is %TRUE if the x-large thumbnail is up-to-date with the file
+ * it represents, and %FALSE if the file has been modified since the thumbnail
+ * was generated.
+ *
+ * If %G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE is %TRUE and this attribute
+ * is %FALSE, it indicates that thumbnailing may be attempted again and may succeed.
+ *
+ * Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
+ *
+ * Since: 2.76
+ */
+#define G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE "thumbnail::is-valid-xxlarge"        /* boolean */
+
 /* Preview */
 
 /**
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c
index 661d2266ab..24c5475bbb 100644
--- a/gio/glocalfileinfo.c
+++ b/gio/glocalfileinfo.c
@@ -1418,19 +1418,90 @@ get_content_type (const char          *basename,
   
 }
 
+typedef enum {
+  THUMBNAIL_SIZE_AUTO,
+  THUMBNAIL_SIZE_NORMAL,
+  THUMBNAIL_SIZE_LARGE,
+  THUMBNAIL_SIZE_XLARGE,
+  THUMBNAIL_SIZE_XXLARGE,
+  THUMBNAIL_SIZE_LAST,
+} ThumbnailSize;
+
+static const char *
+get_thumbnail_dirname_from_size (ThumbnailSize size)
+{
+  switch (size)
+    {
+    case THUMBNAIL_SIZE_AUTO:
+      return NULL;
+      break;
+    case THUMBNAIL_SIZE_NORMAL:
+      return "normal";
+      break;
+    case THUMBNAIL_SIZE_LARGE:
+      return "large";
+      break;
+    case THUMBNAIL_SIZE_XLARGE:
+      return "x-large";
+      break;
+    case THUMBNAIL_SIZE_XXLARGE:
+      return "xx-large";
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  g_return_val_if_reached (NULL);
+}
+
 /* @stat_buf is the pre-calculated result of stat(path), or %NULL if that failed. */
 static void
 get_thumbnail_attributes (const char     *path,
                           GFileInfo      *info,
-                          const GLocalFileStat *stat_buf)
+                          const GLocalFileStat *stat_buf,
+                          ThumbnailSize   size)
 {
   GChecksum *checksum;
+  const char *dirname;
   char *uri;
   char *filename = NULL;
   char *basename;
-  const char *size_dirs[4] = { "xx-large", "x-large", "large", "normal" };
-  gsize i;
-
+  guint32 failed_attr_id;
+  guint32 is_valid_attr_id;
+  guint32 path_attr_id;
+
+  switch (size)
+    {
+    case THUMBNAIL_SIZE_AUTO:
+      failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED;
+      is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID;
+      path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH;
+      break;
+    case THUMBNAIL_SIZE_NORMAL:
+      failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL;
+      is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL;
+      path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL;
+      break;
+    case THUMBNAIL_SIZE_LARGE:
+      failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE;
+      is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE;
+      path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE;
+      break;
+    case THUMBNAIL_SIZE_XLARGE:
+      failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE;
+      is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE;
+      path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE;
+      break;
+    case THUMBNAIL_SIZE_XXLARGE:
+      failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE;
+      is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE;
+      path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE;
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  dirname = get_thumbnail_dirname_from_size (size);
   uri = g_filename_to_uri (path, NULL, NULL);
 
   checksum = g_checksum_new (G_CHECKSUM_MD5);
@@ -1439,21 +1510,37 @@ get_thumbnail_attributes (const char     *path,
   basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
   g_checksum_free (checksum);
 
-  for (i = 0; i < G_N_ELEMENTS (size_dirs); i++)
+  if (dirname)
     {
       filename = g_build_filename (g_get_user_cache_dir (),
-                                   "thumbnails", size_dirs[i], basename,
+                                   "thumbnails", dirname, basename,
                                    NULL);
-      if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
-        break;
 
-      g_clear_pointer (&filename, g_free);
+      if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+        g_clear_pointer (&filename, g_free);
+    }
+  else
+    {
+      gssize i;
+
+      for (i = THUMBNAIL_SIZE_LAST - 1; i >= 0 ; i--)
+        {
+          filename = g_build_filename (g_get_user_cache_dir (),
+                                       "thumbnails",
+                                       get_thumbnail_dirname_from_size (i),
+                                       basename,
+                                      NULL);
+          if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+            break;
+
+          g_clear_pointer (&filename, g_free);
+        }
     }
 
   if (filename)
     {
-      _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename);
-      _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID,
+      _g_file_info_set_attribute_byte_string_by_id (info, path_attr_id, filename);
+      _g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
                                                 thumbnail_verify (filename, uri, stat_buf));
     }
   else
@@ -1466,11 +1553,12 @@ get_thumbnail_attributes (const char     *path,
 
       if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
         {
-          _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED, TRUE);
-          _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID,
+          _g_file_info_set_attribute_boolean_by_id (info, failed_attr_id, TRUE);
+          _g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
                                                     thumbnail_verify (filename, uri, stat_buf));
         }
     }
+
   g_free (basename);
   g_free (filename);
   g_free (uri);
@@ -2109,10 +2197,47 @@ _g_local_file_info_get (const char             *basename,
       _g_file_attribute_matcher_matches_id (attribute_matcher,
                                             G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED))
     {
-      if (stat_ok)
-          get_thumbnail_attributes (path, info, &statbuf);
-      else
-          get_thumbnail_attributes (path, info, NULL);
+      get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_AUTO);
+    }
+
+  if (_g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL))
+    {
+      get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_NORMAL);
+    }
+
+  if (_g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE))
+    {
+      get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_LARGE);
+    }
+
+  if (_g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE))
+    {
+      get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XLARGE);
+    }
+
+  if (_g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                            G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE))
+    {
+      get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XXLARGE);
     }
 
   vfs = g_vfs_get_default ();
diff --git a/gio/tests/file-thumbnail.c b/gio/tests/file-thumbnail.c
index 5fd265f36f..4c7e44a5e6 100644
--- a/gio/tests/file-thumbnail.c
+++ b/gio/tests/file-thumbnail.c
@@ -29,6 +29,18 @@
   G_FILE_ATTRIBUTE_THUMBNAIL_PATH "," \
   G_FILE_ATTRIBUTE_THUMBNAILING_FAILED "," \
   G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL "," \
+  G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE "," \
+  G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE "," \
 )
 
 /* Must be kept in order, for priority */
@@ -202,6 +214,48 @@ create_thumbnail_from_test_file (const gchar  *source_name,
   return thumbnail;
 }
 
+static gboolean
+get_size_attributes (const char   *size,
+                     const gchar **path,
+                     const gchar **is_valid,
+                     const gchar **failed)
+{
+  if (g_str_equal (size, "normal"))
+    {
+      *path = G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL;
+      *is_valid = G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL;
+      *failed = G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL;
+      return TRUE;
+    }
+  else if (g_str_equal (size, "large"))
+    {
+      *path = G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE;
+      *is_valid = G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE;
+      *failed = G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE;
+      return TRUE;
+    }
+  else if (g_str_equal (size, "x-large"))
+    {
+      *path = G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE;
+      *is_valid = G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE;
+      *failed = G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE;
+      return TRUE;
+    }
+  else if (g_str_equal (size, "xx-large"))
+    {
+      *path = G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE;
+      *is_valid = G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE;
+      *failed = G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE;
+      return TRUE;
+    }
+
+  *path = NULL;
+  *is_valid = NULL;
+  *failed = NULL;
+
+  return FALSE;
+}
+
 static void
 test_valid_thumbnail_size (gconstpointer data)
 {
@@ -211,6 +265,7 @@ test_valid_thumbnail_size (gconstpointer data)
   GError *error = NULL;
   GFileInfo *info;
   const gchar *size = data;
+  const gchar *path_attr, *failed_attr, *is_valid_attr;
 
   thumbnail = create_thumbnail_from_test_file ("valid.png", size, &source);
   info = g_file_query_info (source, THUMBNAILS_ATTRIBS, G_FILE_QUERY_INFO_NONE,
@@ -233,6 +288,22 @@ test_valid_thumbnail_size (gconstpointer data)
      g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID));
   */
 
+  g_assert_true (get_size_attributes (size, &path_attr, &is_valid_attr, &failed_attr));
+
+  g_assert_true (g_file_info_has_attribute (info, path_attr));
+  g_assert_true (g_file_info_has_attribute (info, is_valid_attr));
+  g_assert_false (g_file_info_has_attribute (info, failed_attr));
+
+  g_assert_cmpstr (
+    g_file_info_get_attribute_byte_string (info, path_attr),
+    ==,
+    g_file_peek_path (thumbnail)
+  );
+
+  /* TODO: We can't really test this without having a proper thumbnail created
+  g_assert_true (g_file_info_get_attribute_boolean (info, is_valid_attr));
+  */
+
   g_clear_object (&source);
   g_clear_object (&thumbnail);
   g_clear_error (&error);
@@ -258,6 +329,22 @@ test_unknown_thumbnail_size (gconstpointer data)
   g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID));
   g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED));
 
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL));
+
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE));
+
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE));
+
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE));
+  g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE));
+
   g_clear_object (&source);
   g_clear_object (&thumbnail);
   g_clear_error (&error);
@@ -309,6 +396,7 @@ test_thumbnails_size_priority (void)
   for (i = 0; i < G_N_ELEMENTS (SIZES_NAMES); i++)
     {
       GFile *thumbnail = create_thumbnail (source, SIZES_NAMES[i]);
+      const gchar *path_attr, *failed_attr, *is_valid_attr;
       GFile *f;
 
       g_ptr_array_add (sized_thumbnails, thumbnail);
@@ -327,6 +415,21 @@ test_thumbnails_size_priority (void)
         ==,
         g_file_peek_path (thumbnail)
       );
+      g_clear_object (&f);
+
+      g_assert_true (get_size_attributes (SIZES_NAMES[i],
+                     &path_attr, &is_valid_attr, &failed_attr));
+
+      g_assert_true (g_file_info_has_attribute (info, path_attr));
+      g_assert_true (g_file_info_has_attribute (info, is_valid_attr));
+      g_assert_false (g_file_info_has_attribute (info, failed_attr));
+
+      f = g_file_new_for_path (g_file_info_get_attribute_byte_string (info, path_attr));
+      g_assert_cmpstr (
+        g_file_peek_path (f),
+        ==,
+        g_file_peek_path (thumbnail)
+      );
 
       g_clear_object (&info);
       g_clear_object (&f);
@@ -334,11 +437,38 @@ test_thumbnails_size_priority (void)
 
   g_assert_cmpuint (sized_thumbnails->len, ==, G_N_ELEMENTS (SIZES_NAMES));
 
+  /* Ensuring we can access to all the thumbnails by explicit size request */
+  for (i = 0; i < G_N_ELEMENTS (SIZES_NAMES); i++)
+    {
+      GFile *thumbnail = g_ptr_array_index (sized_thumbnails, i);
+      const gchar *path_attr, *failed_attr, *is_valid_attr;
+      gchar *thumbnail_path = g_file_get_path (thumbnail);
+
+      info = g_file_query_info (source, THUMBNAILS_ATTRIBS,
+                                G_FILE_QUERY_INFO_NONE, NULL, &error);
+      g_assert_no_error (error);
+
+      g_assert_true (get_size_attributes (SIZES_NAMES[i],
+                     &path_attr, &is_valid_attr, &failed_attr));
+
+      g_assert_true (g_file_info_has_attribute (info, path_attr));
+      g_assert_true (g_file_info_has_attribute (info, is_valid_attr));
+      g_assert_false (g_file_info_has_attribute (info, failed_attr));
+
+      g_assert_cmpstr (
+        g_file_info_get_attribute_byte_string (info, path_attr), ==, thumbnail_path
+      );
+
+      g_free (thumbnail_path);
+      g_clear_object (&info);
+    }
+
   /* Now removing them in the inverse order, to check this again */
   for (i = G_N_ELEMENTS (SIZES_NAMES); i > 1; i--)
     {
       GFile *thumbnail = g_ptr_array_index (sized_thumbnails, i - 1);
       GFile *less_priority_thumbnail = g_ptr_array_index (sized_thumbnails, i - 2);
+      const gchar *path_attr, *failed_attr, *is_valid_attr;
       GFile *f;
 
       g_file_delete (thumbnail, NULL, &error);
@@ -358,6 +488,21 @@ test_thumbnails_size_priority (void)
         ==,
         g_file_peek_path (less_priority_thumbnail)
       );
+      g_clear_object (&f);
+
+      g_assert_true (get_size_attributes (SIZES_NAMES[i-2],
+                     &path_attr, &is_valid_attr, &failed_attr));
+
+      g_assert_true (g_file_info_has_attribute (info, path_attr));
+      g_assert_true (g_file_info_has_attribute (info, is_valid_attr));
+      g_assert_false (g_file_info_has_attribute (info, failed_attr));
+
+      f = g_file_new_for_path (g_file_info_get_attribute_byte_string (info, path_attr));
+      g_assert_cmpstr (
+        g_file_peek_path (f),
+        ==,
+        g_file_peek_path (less_priority_thumbnail)
+      );
 
       g_clear_object (&info);
       g_clear_object (&f);
@@ -382,6 +527,28 @@ test_thumbnails_size_priority (void)
 
   g_clear_object (&info);
 
+  /* And check if we get the failed state for all explicit requests */
+  for (i = 0; i < G_N_ELEMENTS (SIZES_NAMES); i++)
+    {
+      const gchar *path_attr, *failed_attr, *is_valid_attr;
+
+      info = g_file_query_info (source, THUMBNAILS_ATTRIBS,
+                                G_FILE_QUERY_INFO_NONE, NULL, &error);
+      g_assert_no_error (error);
+
+      g_assert_true (get_size_attributes (SIZES_NAMES[i],
+                     &path_attr, &is_valid_attr, &failed_attr));
+
+      g_assert_false (g_file_info_has_attribute (info, path_attr));
+      g_assert_true (g_file_info_has_attribute (info, is_valid_attr));
+      g_assert_true (g_file_info_has_attribute (info, failed_attr));
+
+      g_assert_false (g_file_info_get_attribute_boolean (info, is_valid_attr));
+      g_assert_true (g_file_info_get_attribute_boolean (info, failed_attr));
+
+      g_clear_object (&info);
+    }
+
   /* Removing the failed thumbnail too, so no thumbnail should be available */
   g_file_delete (failed_thumbnail, NULL, &error);
   g_assert_no_error (error);
@@ -394,6 +561,26 @@ test_thumbnails_size_priority (void)
   g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID));
   g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED));
 
+  g_clear_object (&info);
+
+  for (i = 0; i < G_N_ELEMENTS (SIZES_NAMES); i++)
+    {
+      const gchar *path_attr, *failed_attr, *is_valid_attr;
+
+      info = g_file_query_info (source, THUMBNAILS_ATTRIBS,
+                                G_FILE_QUERY_INFO_NONE, NULL, &error);
+      g_assert_no_error (error);
+
+      g_assert_true (get_size_attributes (SIZES_NAMES[i],
+                     &path_attr, &is_valid_attr, &failed_attr));
+
+      g_assert_false (g_file_info_has_attribute (info, path_attr));
+      g_assert_false (g_file_info_has_attribute (info, is_valid_attr));
+      g_assert_false (g_file_info_has_attribute (info, failed_attr));
+
+      g_clear_object (&info);
+    }
+
   g_clear_object (&source);
   g_clear_pointer (&sized_thumbnails, g_ptr_array_unref);
   g_clear_object (&failed_thumbnail);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]