From 9ca3ce715935cc97c1f832ea698934ee1b45f768 Mon Sep 17 00:00:00 2001 From: Eric Koegel Date: Sat, 17 Dec 2011 10:18:24 +0300 Subject: [PATCH] Adds support for drawing thumbnails from the dbus thumbnail service. --- common/Makefile.am | 37 +++- common/xfdesktop-common.h | 2 + common/xfdesktop-marshal.list | 4 + common/xfdesktop-thumbnailer.c | 579 +++++++++++++++++++++++++++++++++++++ common/xfdesktop-thumbnailer.h | 98 +++++++ doc/README.xfconf | 1 + src/Makefile.am | 16 +- src/xfdesktop-file-icon-manager.c | 40 +++- src/xfdesktop-icon.c | 31 ++ src/xfdesktop-icon.h | 6 + src/xfdesktop-marshal.list | 2 - src/xfdesktop-regular-file-icon.c | 87 ++++++- 12 files changed, 883 insertions(+), 20 deletions(-) create mode 100644 common/xfdesktop-marshal.list create mode 100644 common/xfdesktop-thumbnailer.c create mode 100644 common/xfdesktop-thumbnailer.h delete mode 100644 src/xfdesktop-marshal.list diff --git a/common/Makefile.am b/common/Makefile.am index b6145ba..1af6ac8 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -2,9 +2,44 @@ noinst_LTLIBRARIES = libxfdesktop.la libxfdesktop_la_SOURCES = \ xfdesktop-common.c \ - xfdesktop-common.h + xfdesktop-common.h \ + xfdesktop-marshal.c \ + xfdesktop-marshal.h libxfdesktop_la_CFLAGS = \ -I$(top_srcdir)/src \ $(LIBXFCE4UTIL_CFLAGS) \ $(GTK_CFLAGS) + +if ENABLE_DESKTOP_ICONS +if ENABLE_FILE_ICONS + +libxfdesktop_la_SOURCES += \ + xfdesktop-thumbnailer.c \ + xfdesktop-thumbnailer.h + +libxfdesktop_la_CFLAGS += \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + $(DBUS_CFLAGS) + +endif +endif + +DISTCLEANFILES = \ + $(xfdesktop_built_sources) \ + stamp-xfdesktop-marshal.h \ + xfdesktop-marshal.c \ + xfdesktop-marshal.h + +xfdesktop-marshal.h: stamp-xfdesktop-marshal.h + @true +stamp-xfdesktop-marshal.h: xfdesktop-marshal.list Makefile + $(AM_V_GEN) glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h && \ + echo timestamp > $(@F) +xfdesktop-marshal.c: xfdesktop-marshal.list Makefile + $(AM_V_GEN) echo '#include "xfdesktop-marshal.h"' > xfdesktop-marshal.c && \ + glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --body >> xfdesktop-marshal.c && \ + glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h + +EXTRA_DIST = \ + xfdesktop-marshal.list diff --git a/common/xfdesktop-common.h b/common/xfdesktop-common.h index 58a6f45..c8b2221 100644 --- a/common/xfdesktop-common.h +++ b/common/xfdesktop-common.h @@ -43,6 +43,8 @@ #define LIST_TEXT "# xfce backdrop list" #define XFDESKTOP_SELECTION_FMT "XFDESKTOP_SELECTION_%d" #define XFDESKTOP_IMAGE_FILE_FMT "XFDESKTOP_IMAGE_FILE_%d" +#define XFCONF_THUMNAILS_PROPERTY "/desktop-icons/show-thumbnails" +#define EMBLEM_SYMLINK "emblem-symbolic-link" #define RELOAD_MESSAGE "reload" #define MENU_MESSAGE "menu" diff --git a/common/xfdesktop-marshal.list b/common/xfdesktop-marshal.list new file mode 100644 index 0000000..8fe4148 --- /dev/null +++ b/common/xfdesktop-marshal.list @@ -0,0 +1,4 @@ +BOOLEAN:VOID +BOOLEAN:ENUM,INT +VOID:UINT,BOXED +VOID:STRING,STRING diff --git a/common/xfdesktop-thumbnailer.c b/common/xfdesktop-thumbnailer.c new file mode 100644 index 0000000..2cdf49e --- /dev/null +++ b/common/xfdesktop-thumbnailer.c @@ -0,0 +1,579 @@ +/* + * xfdesktop - xfce4's desktop manager + * + * Copyright(c) 2006 Brian Tarricone, + * Copyright(c) 2006 Benedikt Meurer, + * Copyright(c) 2010-2011 Jannis Pohlmann, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * xfdesktop-thumbnailer is based on thumbnailer code from Ristretto + * Copyright (c) Stephan Arts 2009-2011 + * + * Thumbnailer Spec + * http://live.gnome.org/ThumbnailerSpec + * Thumbnail Managing Standard + * http://people.freedesktop.org/~vuntz/thumbnail-spec-cache/creation.html + */ + +#include + +#include + +#include +#include +#include + +#include + +#include "xfdesktop-thumbnailer.h" +#include "xfdesktop-marshal.h" + +static void +xfdesktop_thumbnailer_init (GObject *); +static void +xfdesktop_thumbnailer_class_init (GObjectClass *); + +static void +xfdesktop_thumbnailer_dispose (GObject *object); +static void +xfdesktop_thumbnailer_finalize (GObject *object); + +static void +xfdesktop_thumbnailer_request_finished_dbus ( + DBusGProxy *proxy, + gint handle, + gpointer data); +static void +xfdesktop_thumbnailer_thumbnail_ready_dbus ( + DBusGProxy *proxy, + gint handle, + const gchar **uri, + gpointer data); + +static gboolean +xfdesktop_thumbnailer_queue_request_timer (XfdesktopThumbnailer *thumbnailer); + +static GObjectClass *parent_class = NULL; +static XfdesktopThumbnailer *thumbnailer_object = NULL; + +typedef enum +{ + XFDESKTOP_NULL_SERVICE, + XFDESKTOP_THUMBNAILER_SERVICE, + XFDESKTOP_GTK_SERVICE, + XFDESKTOP_SERVICE_COUNT +} XFDESKTOP_ICON_SERVICE; + +GType +xfdesktop_thumbnailer_get_type (void) +{ + static GType xfdesktop_thumbnailer_type = 0; + + if (!xfdesktop_thumbnailer_type) { + static const GTypeInfo xfdesktop_thumbnailer_info = + { + sizeof (XfdesktopThumbnailerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) xfdesktop_thumbnailer_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (XfdesktopThumbnailer), + 0, + (GInstanceInitFunc) xfdesktop_thumbnailer_init, + NULL + }; + + xfdesktop_thumbnailer_type = g_type_register_static ( + G_TYPE_OBJECT, + "XfdesktopThumbnailer", + &xfdesktop_thumbnailer_info, + 0); + } + return xfdesktop_thumbnailer_type; +} + +struct _XfdesktopThumbnailerPriv +{ + DBusGProxy *proxy; + + GSList *queue; + gchar **supported_mimetypes; + gint handle; + XFDESKTOP_ICON_SERVICE service; + + gint request_timer_id; +}; + +static void +xfdesktop_thumbnailer_init (GObject *object) +{ + XfdesktopThumbnailer *thumbnailer; + DBusGConnection *connection; + + thumbnailer = XFDESKTOP_THUMBNAILER (object); + + thumbnailer->priv = g_new0 (XfdesktopThumbnailerPriv, 1); + + connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); + + if (connection) { + thumbnailer->priv->proxy = dbus_g_proxy_new_for_name ( + connection, + "org.freedesktop.thumbnails.Thumbnailer1", + "/org/freedesktop/thumbnails/Thumbnailer1", + "org.freedesktop.thumbnails.Thumbnailer1"); + + if(thumbnailer->priv->proxy) { + gchar **supported_uris; + + /* We have a thumbnail service */ + thumbnailer->priv->service = XFDESKTOP_THUMBNAILER_SERVICE; + + dbus_g_object_register_marshaller ( + (GClosureMarshal) xfdesktop_marshal_VOID__UINT_BOXED, + G_TYPE_NONE, G_TYPE_UINT, + G_TYPE_STRV, G_TYPE_INVALID); + + dbus_g_proxy_add_signal ( + thumbnailer->priv->proxy, + "Finished", G_TYPE_UINT, G_TYPE_INVALID); + dbus_g_proxy_add_signal ( + thumbnailer->priv->proxy, + "Ready", G_TYPE_UINT, G_TYPE_STRV, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal ( + thumbnailer->priv->proxy, + "Finished", G_CALLBACK (xfdesktop_thumbnailer_request_finished_dbus), + thumbnailer, NULL); + dbus_g_proxy_connect_signal ( + thumbnailer->priv->proxy, + "Ready", G_CALLBACK(xfdesktop_thumbnailer_thumbnail_ready_dbus), + thumbnailer, NULL); + + dbus_g_proxy_call (thumbnailer->priv->proxy, "GetSupported", NULL, G_TYPE_INVALID, + G_TYPE_STRV, &supported_uris, + G_TYPE_STRV, &thumbnailer->priv->supported_mimetypes, + G_TYPE_INVALID); + + } else { + /* We don't have a thumbnail service, use the GTK one */ + thumbnailer->priv->service = XFDESKTOP_GTK_SERVICE; + } + + dbus_g_connection_unref (connection); + } +} + +static void +xfdesktop_thumbnailer_class_init (GObjectClass *object_class) +{ + XfdesktopThumbnailerClass *thumbnailer_class = XFDESKTOP_THUMBNAILER_CLASS ( + object_class); + + parent_class = g_type_class_peek_parent (thumbnailer_class); + + object_class->dispose = xfdesktop_thumbnailer_dispose; + object_class->finalize = xfdesktop_thumbnailer_finalize; + + g_signal_new ("thumbnail-ready", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + xfdesktop_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); +} + +/** + * xfdesktop_thumbnailer_dispose: + * @object: + * + */ +static void +xfdesktop_thumbnailer_dispose (GObject *object) +{ + XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER (object); + + g_debug("xfdesktop_thumbnailer_dispose"); + + if(thumbnailer->priv->proxy) + g_object_unref(thumbnailer->priv->proxy); + + if(thumbnailer->priv->supported_mimetypes) + g_free(thumbnailer->priv->supported_mimetypes); + + if (thumbnailer->priv) { + g_free (thumbnailer->priv); + thumbnailer->priv = NULL; + } +} + +/** + * xfdesktop_thumbnailer_finalize: + * @object: + * + */ +static void +xfdesktop_thumbnailer_finalize (GObject *object) +{ + if(thumbnailer_object) { + g_object_unref(thumbnailer_object); + thumbnailer_object = NULL; + } +} + + + +/** + * xfdesktop_thumbnailer_new: + * + * + * Singleton + */ +XfdesktopThumbnailer * +xfdesktop_thumbnailer_new (void) +{ + if (thumbnailer_object == NULL) { + thumbnailer_object = g_object_new (XFDESKTOP_TYPE_THUMBNAILER, NULL); + } else { + g_object_ref (thumbnailer_object); + } + + return thumbnailer_object; +} + +static gchar * +xfdesktop_get_file_mimetype(gchar *file) +{ + GFile *temp_file; + GFileInfo *file_info; + gchar *mime_type = NULL; + + g_return_val_if_fail (file != NULL, NULL); + + temp_file = g_file_new_for_path (file); + file_info = g_file_query_info (temp_file, + "standard::content-type", + 0, + NULL, + NULL); + + mime_type = g_strdup(g_file_info_get_content_type (file_info)); + + g_object_unref (file_info); + g_object_unref (temp_file); + + return mime_type; +} + +gboolean +xfdesktop_thumbnailer_is_supported (XfdesktopThumbnailer *thumbnailer, + gchar *file) +{ + guint n; + gchar *mime_type = NULL; + + g_return_val_if_fail (XFDESKTOP_IS_THUMBNAILER (thumbnailer), FALSE); + g_return_val_if_fail (file != NULL, FALSE); + + mime_type = xfdesktop_get_file_mimetype (file); + + if (!mime_type) { + g_warning ("File has no mime type"); + return FALSE; + } + + if(thumbnailer->priv->service == XFDESKTOP_GTK_SERVICE) { + /* This is a hack because I don't want to test and hard code + * every mime type gdk supports. */ + gboolean ret = g_str_has_prefix(mime_type, "image/"); + + g_free(mime_type); + return ret; + } else if (thumbnailer->priv->supported_mimetypes != NULL) { + for (n = 0; thumbnailer->priv->supported_mimetypes[n] != NULL; ++n) { + if (g_content_type_is_a (mime_type, thumbnailer->priv->supported_mimetypes[n])) { + g_free(mime_type); + return TRUE; + } + } + } + + g_free(mime_type); + return FALSE; +} + +gboolean +xfdesktop_thumbnailer_queue_thumbnail ( + XfdesktopThumbnailer *thumbnailer, + gchar *file) +{ + g_return_val_if_fail (XFDESKTOP_IS_THUMBNAILER (thumbnailer), FALSE); + g_return_val_if_fail (file != NULL, FALSE); + + if(!xfdesktop_thumbnailer_is_supported(thumbnailer, file)) { + g_debug("file: %s not supported", file); + return FALSE; + } + if (thumbnailer->priv->request_timer_id) { + g_source_remove (thumbnailer->priv->request_timer_id); + + if (thumbnailer->priv->handle) { + if(thumbnailer->priv->service == XFDESKTOP_THUMBNAILER_SERVICE) { + if(dbus_g_proxy_call(thumbnailer->priv->proxy, + "Dequeue", + NULL, + G_TYPE_UINT, thumbnailer->priv->handle, + G_TYPE_INVALID) == FALSE) + { + g_warning("Dequeue of thumbnailer->priv->handle: %d failed", thumbnailer->priv->handle); + } + } + thumbnailer->priv->handle = 0; + } + } + + if (g_slist_find (thumbnailer->priv->queue, file) == NULL) { + thumbnailer->priv->queue = g_slist_prepend (thumbnailer->priv->queue, + file); + } + + thumbnailer->priv->request_timer_id = g_timeout_add_full ( + G_PRIORITY_LOW, + 300, + (GSourceFunc)xfdesktop_thumbnailer_queue_request_timer, + thumbnailer, + NULL); + + + return TRUE; +} + +void +xfdesktop_thumbnailer_dequeue_thumbnail ( + XfdesktopThumbnailer *thumbnailer, + gchar *file) +{ + g_return_if_fail ( XFDESKTOP_IS_THUMBNAILER (thumbnailer) ); + g_return_if_fail ( file != NULL ); + + if (thumbnailer->priv->request_timer_id) { + g_source_remove (thumbnailer->priv->request_timer_id); + + if (thumbnailer->priv->handle) { + if(thumbnailer->priv->service == XFDESKTOP_THUMBNAILER_SERVICE) { + if(dbus_g_proxy_call(thumbnailer->priv->proxy, + "Dequeue", + NULL, + G_TYPE_UINT, thumbnailer->priv->handle, + G_TYPE_INVALID) == FALSE) + { + g_warning("Dequeue of thumbnailer->priv->handle: %d failed", thumbnailer->priv->handle); + } + } + } + thumbnailer->priv->handle = 0; + } + + if (g_slist_find (thumbnailer->priv->queue, file) != NULL) { + thumbnailer->priv->queue = g_slist_remove_all ( + thumbnailer->priv->queue, + file); + } + + thumbnailer->priv->request_timer_id = g_timeout_add_full ( + G_PRIORITY_LOW, + 300, + (GSourceFunc)xfdesktop_thumbnailer_queue_request_timer, + thumbnailer, + NULL); +} + +static gboolean +xfdesktop_thumbnailer_queue_request_timer ( + XfdesktopThumbnailer *thumbnailer) +{ + gchar **uris; + gchar **mimetypes; + GSList *iter; + gint i = 0; + GFile *file; + GError *error = NULL; + + g_return_val_if_fail ( XFDESKTOP_IS_THUMBNAILER (thumbnailer), FALSE); + + uris = g_new0 (gchar *, + g_slist_length(thumbnailer->priv->queue) + 1); + mimetypes = g_new0 (gchar *, + g_slist_length (thumbnailer->priv->queue) + 1); + + iter = thumbnailer->priv->queue; + while (iter) { + if (iter->data) { + file = g_file_new_for_path(iter->data); + uris[i] = g_file_get_uri (file); + mimetypes[i] = xfdesktop_get_file_mimetype (iter->data); + g_object_unref(file); + } + iter = g_slist_next(iter); + i++; + } + + if(thumbnailer->priv->service == XFDESKTOP_THUMBNAILER_SERVICE) { + if(dbus_g_proxy_call(thumbnailer->priv->proxy, + "Queue", + &error, + G_TYPE_STRV, uris, + G_TYPE_STRV, mimetypes, + G_TYPE_STRING, "normal", + G_TYPE_STRING, "default", + G_TYPE_UINT, 0, + G_TYPE_INVALID, + G_TYPE_UINT, &thumbnailer->priv->handle, + G_TYPE_INVALID) == FALSE) + { + if (NULL != error) { + g_warning("DBUS-call failed:%s", error->message); + if ((error->domain == DBUS_GERROR) && + (error->code == DBUS_GERROR_SERVICE_UNKNOWN)) + { + /* TODO: fall back to gtk */ + } + } + } + } + + g_free(uris); + g_free(mimetypes); + + if(error) + g_object_unref(error); + + thumbnailer->priv->request_timer_id = 0; + + return FALSE; +} + +static void +xfdesktop_thumbnailer_request_finished_dbus ( + DBusGProxy *proxy, + gint handle, + gpointer data) +{ + XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER (data); + + g_return_if_fail ( XFDESKTOP_IS_THUMBNAILER (thumbnailer) ); + + thumbnailer->priv->handle = 0; +} + +static void +xfdesktop_thumbnailer_thumbnail_ready_dbus ( + DBusGProxy *proxy, + gint handle, + const gchar **uri, + gpointer data) +{ + XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER (data); + gchar *thumbnail_location; + GFile *file; + GSList *iter = thumbnailer->priv->queue; + gchar *f_uri, *f_uri_checksum, *filename; + gint x = 0; + + g_return_if_fail ( XFDESKTOP_IS_THUMBNAILER (thumbnailer) ); + + while (iter) { + if ((uri[x] == NULL) || (iter->data == NULL)) { + break; + } + + file = g_file_new_for_path(iter->data); + f_uri = g_file_get_uri (file); + + if (strcmp (uri[x], f_uri) == 0) { + /* The thumbnail is in the format/location + * /homedir/.thumbnails/normal/MD5_Hash_Of_URI.png + */ + f_uri_checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, + f_uri, strlen (f_uri)); + filename = g_strconcat (f_uri_checksum, ".png", NULL); + + thumbnail_location = g_build_path ("/", g_get_home_dir(), + ".thumbnails", "normal", + filename, NULL); + + g_debug("thumbnail-ready src: %s thumbnail: %s", + (char*)iter->data, + thumbnail_location); + g_signal_emit_by_name(thumbnailer, "thumbnail-ready", + iter->data, thumbnail_location); + + thumbnailer->priv->queue = g_slist_remove (thumbnailer->priv->queue, + iter->data); + + iter = thumbnailer->priv->queue; + x++; + + g_free (filename); + g_free (f_uri_checksum); + } else { + iter = g_slist_next(iter); + } + + g_object_unref (file); + g_free (f_uri); + } +} + +void +xfdesktop_thumbnailer_delete_thumbnail(XfdesktopThumbnailer *thumbnailer, gchar *src_file) +{ + DBusGConnection *connection; + gchar **uris; + GFile *file; + GError *error = NULL; + static DBusGProxy *cache = NULL; + + if(!cache) { + connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + if (connection != NULL) { + cache = dbus_g_proxy_new_for_name(connection, + "org.freedesktop.thumbnails.Cache1", + "/org/freedesktop/thumbnails/Cache1", + "org.freedesktop.thumbnails.Cache1"); + + dbus_g_connection_unref (connection); + } + } + + file = g_file_new_for_path(src_file); + + if(cache) { + uris = g_new0 (gchar *, 2); + uris[0] = g_file_get_uri(file); + dbus_g_proxy_call(cache, "Delete", &error, G_TYPE_STRV, uris, G_TYPE_INVALID, G_TYPE_INVALID); + if(error != NULL) { + g_warning("DBUS-call failed:%s", error->message); + } + g_free(uris); + } + + g_object_unref(file); + if(error) + g_object_unref(error); +} diff --git a/common/xfdesktop-thumbnailer.h b/common/xfdesktop-thumbnailer.h new file mode 100644 index 0000000..dafa828 --- /dev/null +++ b/common/xfdesktop-thumbnailer.h @@ -0,0 +1,98 @@ +/* + * xfdesktop - xfce4's desktop manager + * + * Copyright(c) 2006 Brian Tarricone, + * Copyright(c) 2006 Benedikt Meurer, + * Copyright(c) 2010-2011 Jannis Pohlmann, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * xfdesktop-thumbnailer is based on thumbnailer code from Ristretto + * Copyright (c) Stephan Arts 2009-2011 + */ + +#ifndef __XFDESKTOP_THUMBNAILER_H__ +#define __XFDESKTOP_THUMBNAILER_H__ + +#include + +G_BEGIN_DECLS + + +#define XFDESKTOP_TYPE_THUMBNAILER (xfdesktop_thumbnailer_get_type()) +#define XFDESKTOP_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDESKTOP_TYPE_THUMBNAILER, XfdesktopThumbnailer)) +#define XFDESKTOP_IS_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDESKTOP_TYPE_THUMBNAILER)) +#define XFDESKTOP_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFDESKTOP_TYPE_THUMBNAILER, XfdesktopThumbnailerClass)) +#define XFDESKTOP_IS_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFDESKTOP_TYPE_THUMBNAILER())) + +typedef struct _XfdesktopThumbnailer XfdesktopThumbnailer; +typedef struct _XfdesktopThumbnailerPriv XfdesktopThumbnailerPriv; + +struct _XfdesktopThumbnailer +{ + GObject parent; + + XfdesktopThumbnailerPriv *priv; +}; + +typedef struct _XfdesktopThumbnailerClass XfdesktopThumbnailerClass; + +struct _XfdesktopThumbnailerClass +{ + GObjectClass parent_class; +}; + +XfdesktopThumbnailer * +xfdesktop_thumbnailer_new (void); + +GType +xfdesktop_thumbnailer_get_type (void); + +gboolean +xfdesktop_thumbnailer_is_supported (XfdesktopThumbnailer *thumbnailer, + gchar *file); + +/* Queues a file for thumbnail creation. + * A "thumbnail-ready" signal will be emitted when the thumbnail is ready. + * The signal will pass 2 parameters: a gchar *file which will be file + * that's passed in here and a gchar *thumbnail_file which will be the + * location of the thumbnail. + */ +gboolean +xfdesktop_thumbnailer_queue_thumbnail ( + XfdesktopThumbnailer *thumbnailer, + gchar *file); + +/* Removes a file from the list of pending thumbnail creations. + * This is not guaranteed to always remove the file, if processing + * of that thumbnail has started it won't stop. + */ +void +xfdesktop_thumbnailer_dequeue_thumbnail ( + XfdesktopThumbnailer *thumbnailer, + gchar *file); + +/* This function tells the thumbnail service the src_file will be deleted. + * This function should be called when the file is deleted or moved so + * the thumbnail file doesn't take up space on the user's drive. + */ +void +xfdesktop_thumbnailer_delete_thumbnail ( + XfdesktopThumbnailer *thumbnailer, + gchar *src_file); + +G_END_DECLS + +#endif /* __XFDESKTOP_THUMBNAILER_H__ */ diff --git a/doc/README.xfconf b/doc/README.xfconf index 2fa1c40..3832521 100644 --- a/doc/README.xfconf +++ b/doc/README.xfconf @@ -37,6 +37,7 @@ property is listd after the name. + diff --git a/src/Makefile.am b/src/Makefile.am index 5d1fd4d..3adb3d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,9 +4,7 @@ bin_PROGRAMS = xfdesktop xfdesktop_built_sources = \ xfce-desktop-enum-types.c \ - xfce-desktop-enum-types.h \ - xfdesktop-marshal.c \ - xfdesktop-marshal.h + xfce-desktop-enum-types.h if HAVE_LIBNOTIFY xfdesktop_notify_sources = \ @@ -149,17 +147,8 @@ BUILT_SOURCES = \ DISTCLEANFILES = \ $(xfdesktop_built_sources) \ - stamp-xfdesktop-marshal.h \ stamp-xfce-desktop-enum-types.h -xfdesktop-marshal.h: stamp-xfdesktop-marshal.h - @true -stamp-xfdesktop-marshal.h: xfdesktop-marshal.list Makefile - $(AM_V_GEN) glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h && \ - echo timestamp > $(@F) -xfdesktop-marshal.c: xfdesktop-marshal.list Makefile - $(AM_V_GEN) echo '#include "xfdesktop-marshal.h"' > xfdesktop-marshal.c && \ - glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --body >> xfdesktop-marshal.c enum_headers = \ xfce-backdrop.h \ @@ -227,5 +216,4 @@ endif EXTRA_DIST = \ $(desktop_menu_sources) \ $(desktop_icon_sources) \ - $(desktop_file_icon_sources) \ - xfdesktop-marshal.list + $(desktop_file_icon_sources) diff --git a/src/xfdesktop-file-icon-manager.c b/src/xfdesktop-file-icon-manager.c index d3ca2eb..a40c77e 100644 --- a/src/xfdesktop-file-icon-manager.c +++ b/src/xfdesktop-file-icon-manager.c @@ -71,6 +71,7 @@ #include "xfdesktop-special-file-icon.h" #include "xfdesktop-trash-proxy.h" #include "xfdesktop-volume-icon.h" +#include "xfdesktop-thumbnailer.h" #include #include @@ -129,6 +130,8 @@ struct _XfdesktopFileIconManagerPrivate GList *thunarx_menu_providers; GList *thunarx_properties_providers; #endif + + XfdesktopThumbnailer *thumbnailer; }; static void xfdesktop_file_icon_manager_set_property(GObject *object, @@ -175,6 +178,7 @@ static void xfdesktop_file_icon_manager_remove_removable_media(XfdesktopFileIcon static void xfdesktop_file_icon_position_changed(XfdesktopFileIcon *icon, gpointer user_data); +static void xfdesktop_file_icon_manager_update_image (GtkWidget *widget, gchar *srcfile, gchar *thumbfile, XfdesktopFileIconManager *fmanager); G_DEFINE_TYPE_EXTENDED(XfdesktopFileIconManager, xfdesktop_file_icon_manager, @@ -282,6 +286,10 @@ xfdesktop_file_icon_manager_init(XfdesktopFileIconManager *fmanager) n_drag_targets); fmanager->priv->drop_targets = gtk_target_list_new(drop_targets, n_drop_targets); + + fmanager->priv->thumbnailer = xfdesktop_thumbnailer_new(); + + g_signal_connect(G_OBJECT(fmanager->priv->thumbnailer), "thumbnail-ready", G_CALLBACK(xfdesktop_file_icon_manager_update_image), fmanager); } static void @@ -377,6 +385,7 @@ xfdesktop_file_icon_manager_finalize(GObject *obj) gtk_target_list_unref(fmanager->priv->drop_targets); g_object_unref(fmanager->priv->folder); + g_object_unref(fmanager->priv->thumbnailer); G_OBJECT_CLASS(xfdesktop_file_icon_manager_parent_class)->finalize(obj); } @@ -1829,6 +1838,12 @@ xfdesktop_file_icon_manager_add_icon(XfdesktopFileIconManager *fmanager, gint16 row = -1, col = -1; gboolean do_add = FALSE; const gchar *name; + GFile *file; + + file = xfdesktop_file_icon_peek_file(icon); + xfdesktop_thumbnailer_queue_thumbnail(fmanager->priv->thumbnailer, + g_file_get_path(file)); + name = xfdesktop_icon_peek_label(XFDESKTOP_ICON(icon)); if(xfdesktop_file_icon_manager_get_cached_icon_position(fmanager, name, @@ -1839,7 +1854,6 @@ xfdesktop_file_icon_manager_add_icon(XfdesktopFileIconManager *fmanager, do_add = TRUE; } else { if(defer_if_missing) { - GFile *file = xfdesktop_file_icon_peek_file(icon); fmanager->priv->deferred_icons = g_list_prepend(fmanager->priv->deferred_icons, g_object_ref(file)); } else @@ -2195,6 +2209,10 @@ xfdesktop_file_icon_manager_file_changed(GFileMonitor *monitor, icon = g_hash_table_lookup(fmanager->priv->icons, file); if(icon) { + xfdesktop_thumbnailer_delete_thumbnail(fmanager->priv->thumbnailer, + g_file_get_path(file)); + xfdesktop_icon_delete_thumbnail(XFDESKTOP_ICON(icon)); + xfdesktop_icon_view_remove_item(fmanager->priv->icon_view, XFDESKTOP_ICON(icon)); g_hash_table_remove(fmanager->priv->icons, file); @@ -3068,3 +3086,23 @@ xfdesktop_file_icon_manager_get_show_special_file(XfdesktopFileIconManager *mana return manager->priv->show_special[type]; } + +static void +xfdesktop_file_icon_manager_update_image (GtkWidget *widget, gchar *srcfile, gchar *thumbfile, XfdesktopFileIconManager *manager) +{ + GFile *file; + XfdesktopIcon *icon; + + g_return_if_fail(srcfile && thumbfile); + g_return_if_fail(XFDESKTOP_FILE_ICON_MANAGER(manager)); + + file = g_file_new_for_path(srcfile); + + icon = g_hash_table_lookup(manager->priv->icons, file); + if(icon) + { + g_object_unref(file); + file = g_file_new_for_path(thumbfile); + xfdesktop_icon_set_thumbnail_file(icon, file); + } +} diff --git a/src/xfdesktop-icon.c b/src/xfdesktop-icon.c index 431ba79..31c082b 100644 --- a/src/xfdesktop-icon.c +++ b/src/xfdesktop-icon.c @@ -283,6 +283,37 @@ xfdesktop_icon_peek_tooltip(XfdesktopIcon *icon) } /*< optional >*/ +void xfdesktop_icon_delete_thumbnail(XfdesktopIcon *icon) +{ + XfdesktopIconClass *klass; + + g_return_if_fail(XFDESKTOP_IS_ICON(icon)); + + klass = XFDESKTOP_ICON_GET_CLASS(icon); + + if(!klass->delete_thumbnail_file) + return; + + klass->delete_thumbnail_file(icon); +} + +/*< optional >*/ +void +xfdesktop_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file) +{ + XfdesktopIconClass *klass; + + g_return_if_fail(XFDESKTOP_IS_ICON(icon)); + + klass = XFDESKTOP_ICON_GET_CLASS(icon); + + if(!klass->set_thumbnail_file) + return; + + klass->set_thumbnail_file(icon, file); +} + +/*< optional >*/ gboolean xfdesktop_icon_populate_context_menu(XfdesktopIcon *icon, GtkWidget *menu) diff --git a/src/xfdesktop-icon.h b/src/xfdesktop-icon.h index b838ed5..36e4925 100644 --- a/src/xfdesktop-icon.h +++ b/src/xfdesktop-icon.h @@ -73,6 +73,9 @@ struct _XfdesktopIconClass G_CONST_RETURN gchar *(*peek_tooltip)(XfdesktopIcon *icon); + void (*set_thumbnail_file)(XfdesktopIcon *icon, GFile *file); + void (*delete_thumbnail_file)(XfdesktopIcon *icon); + gboolean (*populate_context_menu)(XfdesktopIcon *icon, GtkWidget *menu); }; @@ -105,6 +108,9 @@ gboolean xfdesktop_icon_populate_context_menu(XfdesktopIcon *icon, GtkWidget *xfdesktop_icon_peek_icon_view(XfdesktopIcon *icon); +void xfdesktop_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file); +void xfdesktop_icon_delete_thumbnail(XfdesktopIcon *icon); + /*< signal triggers >*/ void xfdesktop_icon_pixbuf_changed(XfdesktopIcon *icon); diff --git a/src/xfdesktop-marshal.list b/src/xfdesktop-marshal.list deleted file mode 100644 index 819c32e..0000000 --- a/src/xfdesktop-marshal.list +++ /dev/null @@ -1,2 +0,0 @@ -BOOLEAN:VOID -BOOLEAN:ENUM,INT diff --git a/src/xfdesktop-regular-file-icon.c b/src/xfdesktop-regular-file-icon.c index e14256a..ed74a8b 100644 --- a/src/xfdesktop-regular-file-icon.c +++ b/src/xfdesktop-regular-file-icon.c @@ -47,6 +47,7 @@ #include #include +#include #ifdef HAVE_THUNARX #include @@ -56,7 +57,6 @@ #include "xfdesktop-common.h" #include "xfdesktop-regular-file-icon.h" -#define EMBLEM_SYMLINK "emblem-symbolic-link" struct _XfdesktopRegularFileIconPrivate { @@ -68,11 +68,15 @@ struct _XfdesktopRegularFileIconPrivate GFileInfo *file_info; GFileInfo *filesystem_info; GFile *file; + GFile *thumbnail_file; GdkScreen *gscreen; }; static void xfdesktop_regular_file_icon_finalize(GObject *obj); +static void xfdesktop_regular_file_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file); +static void xfdesktop_regular_file_icon_delete_thumbnail_file(XfdesktopIcon *icon); + static GdkPixbuf *xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon, gint size); static G_CONST_RETURN gchar *xfdesktop_regular_file_icon_peek_label(XfdesktopIcon *icon); @@ -127,6 +131,8 @@ xfdesktop_regular_file_icon_class_init(XfdesktopRegularFileIconClass *klass) icon_class->get_allowed_drag_actions = xfdesktop_regular_file_icon_get_allowed_drag_actions; icon_class->get_allowed_drop_actions = xfdesktop_regular_file_icon_get_allowed_drop_actions; icon_class->do_drop_dest = xfdesktop_regular_file_icon_do_drop_dest; + icon_class->set_thumbnail_file = xfdesktop_regular_file_icon_set_thumbnail_file; + icon_class->delete_thumbnail_file = xfdesktop_regular_file_icon_delete_thumbnail_file; file_icon_class->peek_file_info = xfdesktop_regular_file_icon_peek_file_info; file_icon_class->peek_filesystem_info = xfdesktop_regular_file_icon_peek_filesystem_info; @@ -171,6 +177,9 @@ xfdesktop_regular_file_icon_finalize(GObject *obj) if(icon->priv->tooltip) g_free(icon->priv->tooltip); + + if(icon->priv->thumbnail_file) + g_object_unref(icon->priv->thumbnail_file); G_OBJECT_CLASS(xfdesktop_regular_file_icon_parent_class)->finalize(obj); } @@ -201,6 +210,40 @@ xfdesktop_regular_file_icon_invalidate_pixbuf(XfdesktopRegularFileIcon *icon) } } +static void +xfdesktop_regular_file_icon_delete_thumbnail_file(XfdesktopIcon *icon) +{ + XfdesktopRegularFileIcon *file_icon; + + if(!XFDESKTOP_IS_REGULAR_FILE_ICON(icon)) + return; + + file_icon = XFDESKTOP_REGULAR_FILE_ICON(icon); + + if(file_icon->priv->thumbnail_file) { + g_object_unref(file_icon->priv->thumbnail_file); + file_icon->priv->thumbnail_file = NULL; + } +} + +static void +xfdesktop_regular_file_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file) +{ + XfdesktopRegularFileIcon *file_icon; + + if(!XFDESKTOP_IS_REGULAR_FILE_ICON(icon)) + return; + + file_icon = XFDESKTOP_REGULAR_FILE_ICON(icon); + + if(file_icon->priv->thumbnail_file) + g_object_unref(file_icon->priv->thumbnail_file); + + file_icon->priv->thumbnail_file = file; + + xfdesktop_regular_file_icon_invalidate_pixbuf(file_icon); + xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon)); +} static GdkPixbuf * xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon, @@ -248,6 +291,32 @@ xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon, g_key_file_free(key_file); g_free(contents); } + } else { + gboolean show_thumbnails = FALSE; + gboolean have_xfconf = FALSE; + XfconfChannel *desktop_channel = NULL; + + have_xfconf = xfconf_init(NULL); + if(have_xfconf) + { + desktop_channel = xfconf_channel_get(XFDESKTOP_CHANNEL); + if(xfconf_channel_has_property(desktop_channel, XFCONF_THUMNAILS_PROPERTY)) + { + show_thumbnails = xfconf_channel_get_bool(desktop_channel, XFCONF_THUMNAILS_PROPERTY, TRUE); + } else { + xfconf_channel_set_bool(desktop_channel, XFCONF_THUMNAILS_PROPERTY, TRUE); + } + } + + if(show_thumbnails && file_icon->priv->thumbnail_file) + { + file_icon->priv->pix = gdk_pixbuf_new_from_file_at_scale(g_file_get_path(file_icon->priv->thumbnail_file), + size, size, + FALSE, NULL); + } + + if(have_xfconf) + xfconf_shutdown(); } /* release thumbnail path */ @@ -280,10 +349,24 @@ xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon, if(file_icon->priv->file_info) gicon = g_file_info_get_icon(file_icon->priv->file_info); - + + if(file_icon->priv->pix) { + if(emblem_pix) { + gint emblem_pix_size = gdk_pixbuf_get_width(emblem_pix); + gint dest_size = size - emblem_pix_size; + + /* We have to add the emblem */ + gdk_pixbuf_composite(emblem_pix, file_icon->priv->pix, + dest_size, dest_size, + emblem_pix_size, emblem_pix_size, + dest_size, dest_size, + 1.0, 1.0, GDK_INTERP_BILINEAR, 255); + } + } else { file_icon->priv->pix = xfdesktop_file_utils_get_icon(icon_name, gicon, size, emblem_pix, file_icon->priv->pix_opacity); + } file_icon->priv->cur_pix_size = size; -- 1.7.5.4