Skip to content

Instantly share code, notes, and snippets.

@Dudemanguy
Forked from ahodesuka/glib-thumbnailer.patch
Last active October 8, 2026 22:17
Show Gist options
  • Select an option

  • Save Dudemanguy/d199759b46a79782cc1b301649dec8a5 to your computer and use it in GitHub Desktop.

Select an option

Save Dudemanguy/d199759b46a79782cc1b301649dec8a5 to your computer and use it in GitHub Desktop.
Sends a dbus signal for generating thumbnails.
From 26e26aa7db761e3b92177907da26e752a0b8a9cc Mon Sep 17 00:00:00 2001
From: Dudemanguy <random342@airmail.cc>
Date: Fri, 20 Sep 2024 12:50:10 -0500
Subject: [PATCH 1/1] glocalfileinfo: add dbus thumbnail generation requests
Send a dbus signal to thumbnailing generators so they can make
thumbnails if needed.
Co-authored-by: ahoka <ahodesuka@users.noreply.github.com>
---
gio/glocalfileinfo.c | 190 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 181 insertions(+), 9 deletions(-)
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c
index eea266813..07cc073cd 100644
--- a/gio/glocalfileinfo.c
+++ b/gio/glocalfileinfo.c
@@ -65,6 +65,12 @@
#include "glib-unix.h"
#endif
+#ifdef HAVE_DBUS1
+#include <gio/gdbusproxy.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+#endif /* HAVE_DBUS1 */
+
#include "glib-private.h"
#include "thumbnail-verify.h"
@@ -102,6 +108,15 @@
#include "gcontenttypeprivate.h"
#include "glibintl.h"
+#ifdef HAVE_DBUS1
+typedef struct
+{
+ GMainLoop *mainloop;
+ guint32 handle;
+ gboolean success;
+ const char *error_message;
+} ThumbnailerState;
+#endif /* HAVE_DBUS1 */
#ifndef G_OS_WIN32
@@ -1417,18 +1432,145 @@ get_thumbnail_dirname_from_size (ThumbnailSize size)
g_return_val_if_reached (NULL);
}
+#ifdef HAVE_DBUS1
+static void
+thumbnailer_signal_cb (GDBusProxy *proxy,
+ gchar *sender_name,
+ gchar *signal_name,
+ GVariant *parameters,
+ gpointer thumbnailer_state)
+{
+ ThumbnailerState *state = (ThumbnailerState *) thumbnailer_state;
+ guint32 signal_handle;
+ const gchar **uris;
+
+ if (g_strcmp0 (signal_name, "Error") == 0)
+ {
+ g_variant_get (parameters, "(uasis)", &signal_handle, NULL, NULL, &state->error_message);
+ state->success = FALSE;
+ }
+ else if (g_strcmp0 (signal_name, "Ready") == 0)
+ {
+ g_variant_get (parameters, "(u^as)", &signal_handle, &uris);
+ state->success = TRUE;
+ }
+ else if (g_strcmp0 (signal_name, "Finished") == 0)
+ {
+ g_main_loop_quit (state->mainloop);
+ }
+}
+
+static gboolean
+generate_thumbnail (const char *uri, const char *mime_type)
+{
+ GMainContext *thread_context;
+ GDBusConnection *connection;
+ GDBusProxy *proxy = NULL;
+ GVariant *result = NULL;
+ GError *error = NULL;
+ gchar *address = NULL;
+ ThumbnailerState state;
+ const gchar *uris[2] = { uri, NULL };
+ const gchar *mime_types[2] = { mime_type, NULL };
+
+ thread_context = g_main_context_new ();
+ state.mainloop = g_main_loop_new (thread_context, FALSE);
+ state.success = FALSE;
+
+ address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ if (!address)
+ {
+ g_warning ("generate_thumbnail (): g_dbus_address_get_for_bus_sync failed");
+ goto done;
+ }
+
+ connection = g_dbus_connection_new_for_address_sync (
+ address,
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL,
+ NULL,
+ &error);
+
+ g_main_context_push_thread_default (thread_context);
+ proxy = g_dbus_proxy_new_sync (connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ "org.freedesktop.thumbnails.Thumbnailer1",
+ "/org/freedesktop/thumbnails/Thumbnailer1",
+ "org.freedesktop.thumbnails.Thumbnailer1",
+ NULL,
+ &error);
+ if (!proxy)
+ {
+ g_warning ("generate_thumbnail (): g_dbus_proxy_new_sync failed");
+ goto done;
+ }
+ else
+ g_debug ("generate_thumbnail (): connected to D-Bus");
+
+ g_signal_connect (G_OBJECT (proxy), "g-signal",
+ G_CALLBACK (thumbnailer_signal_cb), &state);
+
+ result = g_dbus_proxy_call_sync (proxy,
+ "Queue",
+ g_variant_new ("(^as^asssu)",
+ uris,
+ mime_types,
+ "normal",
+ "default",
+ 0),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (!result || error)
+ {
+ g_warning ("generate_thumbnail (): g_dbus_proxy_call_sync() failed: %s", error->message);
+ goto done;
+ }
+ g_variant_get (result, "(u)", &(state.handle));
+ g_variant_unref (result);
+ // block until the loop is terminated in thumbnailer_signal_cb ()
+ g_main_loop_run (state.mainloop);
+
+done:
+ if (address)
+ g_free (address);
+
+ if (proxy)
+ g_object_unref (proxy);
+
+ if (connection)
+ g_object_unref (connection);
+
+ g_main_loop_unref (state.mainloop);
+ g_main_context_pop_thread_default (thread_context);
+ g_main_context_unref (thread_context);
+
+ if (state.success)
+ {
+ g_debug ("generate_thumbnail (): Thumbnail generated for %s", uris[0]);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+#endif /* HAVE_DBUS1 */
+
/* @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,
+get_thumbnail_attributes (const char *path,
+ GFileInfo *info,
const GLocalFileStat *stat_buf,
- ThumbnailSize size)
+ ThumbnailSize size,
+ gboolean generate)
{
GChecksum *checksum;
const char *dirname;
char *uri;
char *filename = NULL;
char *basename;
+ const char *content_type;
guint32 failed_attr_id;
guint32 is_valid_attr_id;
guint32 path_attr_id;
@@ -1505,6 +1647,7 @@ get_thumbnail_attributes (const char *path,
_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));
+ generate = FALSE;
}
else
{
@@ -1519,9 +1662,26 @@ get_thumbnail_attributes (const char *path,
_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));
+ generate = FALSE;
}
}
+ if (generate)
+ {
+#ifdef HAVE_DBUS1
+ content_type = g_file_info_get_content_type (info);
+ if (content_type)
+ {
+ g_debug ("invoking Freedesktop Thumbnailer for %s (%s)", uri, content_type);
+ if (generate_thumbnail (uri, content_type))
+ {
+ /* Now that the thumbnail is generated, find it. */
+ get_thumbnail_attributes (path, info, stat_buf, size, FALSE);
+ }
+ }
+#endif /* HAVE_DBUS1 */
+ }
+
g_free (basename);
g_free (filename);
g_free (uri);
@@ -1918,6 +2078,16 @@ _g_local_file_info_get (const char *basename,
info = g_file_info_new ();
+ /* Thumbnail generation requires a content-type. */
+ if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH) && !_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE))
+ {
+ char *attributes = g_file_attribute_matcher_to_string (attribute_matcher);
+ char *_attributes = g_strdup_printf ("%s,standard::content-type", attributes);
+ attribute_matcher = g_file_attribute_matcher_new (_attributes);
+ g_free (attributes);
+ g_free (_attributes);
+ }
+
/* Make sure we don't set any unwanted attributes */
g_file_info_set_attribute_mask (info, attribute_matcher);
@@ -2056,7 +2226,9 @@ _g_local_file_info_get (const char *basename,
query_icons = _g_file_attribute_matcher_matches_id (attribute_matcher,
G_FILE_ATTRIBUTE_ID_STANDARD_ICON) ||
_g_file_attribute_matcher_matches_id (attribute_matcher,
- G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON);
+ G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON) ||
+ _g_file_attribute_matcher_matches_id (attribute_matcher,
+ G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH);
icon_content_type = NULL;
if (query_full_content_type ||
@@ -2180,7 +2352,7 @@ _g_local_file_info_get (const char *basename,
_g_file_attribute_matcher_matches_id (attribute_matcher,
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED))
{
- get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_AUTO);
+ get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_AUTO, TRUE);
}
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
@@ -2190,7 +2362,7 @@ _g_local_file_info_get (const char *basename,
_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);
+ get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_NORMAL, TRUE);
}
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
@@ -2200,7 +2372,7 @@ _g_local_file_info_get (const char *basename,
_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);
+ get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_LARGE, TRUE);
}
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
@@ -2210,7 +2382,7 @@ _g_local_file_info_get (const char *basename,
_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);
+ get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XLARGE, TRUE);
}
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
@@ -2220,7 +2392,7 @@ _g_local_file_info_get (const char *basename,
_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);
+ get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XXLARGE, TRUE);
}
vfs = g_vfs_get_default ();
--
2.56.0
@titan-speakerman

Copy link
Copy Markdown

Thanks, I got it to work.

For anyone else struggling to get this patch to work in Portage, or using the meson build system for some other reason, just add this patch as well and it should work:

--- a/glib/glibconfig.h.in      2025-02-20 08:08:16.000000000 -0500
+++ b/glib/glibconfig.h.in      2025-04-25 22:58:07.841968626 -0400
@@ -60,6 +60,7 @@ 
 #define G_GINT32_FORMAT @gint32_format@
 #define G_GUINT32_FORMAT @guint32_format@
 
+#define HAVE_DBUS1 1
 
 #define G_HAVE_GINT64 1          /* deprecated, always true */ 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment