[Xfce4-commits] <xfdesktop:eric/wallpaper-and-settings-improvements> Thumbnail service support to xfdesktop-settings (Bug #6536)
Eric Koegel
noreply at xfce.org
Sun Mar 3 06:46:04 CET 2013
Updating branch refs/heads/eric/wallpaper-and-settings-improvements
to 59921a68c40f8115460553ae69bde5bda3bc7d76 (commit)
from 3cec6972530e4e4af47dbb84358fa8fedcc00f82 (commit)
commit 59921a68c40f8115460553ae69bde5bda3bc7d76
Author: Eric Koegel <eric.koegel at gmail.com>
Date: Mon Feb 25 11:49:16 2013 +0300
Thumbnail service support to xfdesktop-settings (Bug #6536)
common/xfdesktop-common.c | 61 +++++++++-
common/xfdesktop-common.h | 2 +
common/xfdesktop-thumbnailer.c | 49 +++----
common/xfdesktop-thumbnailer.h | 3 +
settings/main.c | 235 ++++++++++++++++++++++++++++++----
settings/xfdesktop-settings-ui.glade | 4 +-
6 files changed, 298 insertions(+), 56 deletions(-)
diff --git a/common/xfdesktop-common.c b/common/xfdesktop-common.c
index 344611a..755e273 100644
--- a/common/xfdesktop-common.c
+++ b/common/xfdesktop-common.c
@@ -188,13 +188,70 @@ xfdesktop_backdrop_choose_random(const gchar *filename)
return file;
}
+gchar *
+xfdesktop_get_file_mimetype(const 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);
+
+ g_return_val_if_fail(temp_file != NULL, NULL);
+
+ file_info = g_file_query_info(temp_file,
+ "standard::content-type",
+ 0,
+ NULL,
+ NULL);
+
+ if(file_info != 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_image_file_is_valid(const gchar *filename)
{
+ static GSList *pixbuf_formats = NULL;
+ GSList *l;
+ gboolean image_valid = FALSE;
+ gchar *file_mimetype;
+
g_return_val_if_fail(filename, FALSE);
- /* if gdk can get pixbuf info from the file then it's an image file */
- return (gdk_pixbuf_get_file_info(filename, NULL, NULL) == NULL ? FALSE : TRUE);
+ if(pixbuf_formats == NULL) {
+ pixbuf_formats = gdk_pixbuf_get_formats();
+ }
+
+ file_mimetype = xfdesktop_get_file_mimetype(filename);
+
+ if(file_mimetype == NULL)
+ return FALSE;
+
+ /* Every pixbuf format has a list of mime types we can compare against */
+ for(l = pixbuf_formats; l != NULL && image_valid == FALSE; l = g_slist_next(l)) {
+ gint i;
+ gchar ** mimetypes = gdk_pixbuf_format_get_mime_types(l->data);
+
+ for(i = 0; mimetypes[i] != NULL && image_valid == FALSE; i++) {
+ if(g_strcmp0(file_mimetype, mimetypes[i]) == 0)
+ image_valid = TRUE;
+ }
+ g_strfreev(mimetypes);
+ }
+
+ g_free(file_mimetype);
+
+ return image_valid;
}
gboolean
diff --git a/common/xfdesktop-common.h b/common/xfdesktop-common.h
index 7c7570d..5334ba8 100644
--- a/common/xfdesktop-common.h
+++ b/common/xfdesktop-common.h
@@ -76,6 +76,8 @@ gchar *xfdesktop_backdrop_choose_random(const gchar *filename);
gboolean xfdesktop_image_file_is_valid(const gchar *filename);
+gchar *xfdesktop_get_file_mimetype(const gchar *file);
+
gboolean xfdesktop_check_is_running(Window *xid);
void xfdesktop_send_client_message(Window xid, const gchar *msg);
diff --git a/common/xfdesktop-thumbnailer.c b/common/xfdesktop-thumbnailer.c
index 8f39fe9..2c735df 100644
--- a/common/xfdesktop-thumbnailer.c
+++ b/common/xfdesktop-thumbnailer.c
@@ -41,6 +41,7 @@
#include <libxfce4util/libxfce4util.h>
#include "xfdesktop-thumbnailer.h"
#include "xfdesktop-marshal.h"
+#include "xfdesktop-common.h"
static void xfdesktop_thumbnailer_init(GObject *);
static void xfdesktop_thumbnailer_class_init(GObjectClass *);
@@ -257,34 +258,14 @@ xfdesktop_thumbnailer_new(void)
return thumbnailer_object;
}
-static gchar *
-xfdesktop_get_file_mimetype(gchar *file)
+gboolean xfdesktop_thumbnailer_service_available(XfdesktopThumbnailer *thumbnailer)
{
- 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);
-
- g_return_val_if_fail(temp_file != NULL, NULL);
-
- file_info = g_file_query_info(temp_file,
- "standard::content-type",
- 0,
- NULL,
- NULL);
-
- if(file_info != NULL) {
- mime_type = g_strdup(g_file_info_get_content_type(file_info));
+ g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
- g_object_unref(file_info);
- }
+ if(thumbnailer->priv->proxy == NULL)
+ return FALSE;
- g_object_unref(temp_file);
-
- return mime_type;
+ return TRUE;
}
gboolean
@@ -370,6 +351,12 @@ xfdesktop_thumbnailer_queue_thumbnail(XfdesktopThumbnailer *thumbnailer,
return TRUE;
}
+static void
+xfdesktop_thumbnailer_dequeue_foreach(gpointer data, gpointer user_data)
+{
+ xfdesktop_thumbnailer_dequeue_thumbnail(user_data, data);
+}
+
/**
* xfdesktop_thumbnailer_dequeue_thumbnail:
*
@@ -402,9 +389,8 @@ xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
}
if(g_slist_find(thumbnailer->priv->queue, file) != NULL) {
- thumbnailer->priv->queue = g_slist_remove_all(
- thumbnailer->priv->queue,
- file);
+ thumbnailer->priv->queue = g_slist_remove_all(thumbnailer->priv->queue,
+ file);
}
thumbnailer->priv->request_timer_id = g_timeout_add_full(
@@ -415,6 +401,13 @@ xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
NULL);
}
+void xfdesktop_thumbnailer_dequeue_all_thumbnails(XfdesktopThumbnailer *thumbnailer)
+{
+ g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));
+
+ g_slist_foreach(thumbnailer->priv->queue, (GFunc)xfdesktop_thumbnailer_dequeue_foreach, thumbnailer);
+}
+
static gboolean
xfdesktop_thumbnailer_queue_request_timer(XfdesktopThumbnailer *thumbnailer)
{
diff --git a/common/xfdesktop-thumbnailer.h b/common/xfdesktop-thumbnailer.h
index 842f155..c7ea4c5 100644
--- a/common/xfdesktop-thumbnailer.h
+++ b/common/xfdesktop-thumbnailer.h
@@ -60,6 +60,8 @@ XfdesktopThumbnailer * xfdesktop_thumbnailer_new(void);
GType xfdesktop_thumbnailer_get_type(void);
+gboolean xfdesktop_thumbnailer_service_available(XfdesktopThumbnailer *thumbnailer);
+
gboolean xfdesktop_thumbnailer_is_supported(XfdesktopThumbnailer *thumbnailer,
gchar *file);
@@ -67,6 +69,7 @@ gboolean xfdesktop_thumbnailer_queue_thumbnail(XfdesktopThumbnailer *thumbnailer
gchar *file);
void xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
gchar *file);
+void xfdesktop_thumbnailer_dequeue_all_thumbnails(XfdesktopThumbnailer *thumbnailer);
void xfdesktop_thumbnailer_delete_thumbnail(XfdesktopThumbnailer *thumbnailer,
gchar *src_file);
diff --git a/settings/main.c b/settings/main.c
index 1308b21..d0d7996 100644
--- a/settings/main.c
+++ b/settings/main.c
@@ -50,6 +50,7 @@
#include <libwnck/libwnck.h>
#include "xfdesktop-common.h"
+#include "xfdesktop-thumbnailer.h"
#include "xfdesktop-settings-ui.h"
#include "xfdesktop-settings-appearance-frame-ui.h"
@@ -82,6 +83,12 @@
typedef struct
{
+ GtkTreeModel *model;
+ GSList *iters;
+} PreviewData;
+
+typedef struct
+{
XfconfChannel *channel;
gint screen;
gint monitor;
@@ -105,6 +112,11 @@ typedef struct
GtkWidget *random_backdrop_order_chkbox;
GThread *preview_thread;
+ PreviewData *pdata;
+
+ XfdesktopThumbnailer *thumbnailer;
+
+ gint request_timer_id;
} AppearancePanel;
@@ -113,6 +125,7 @@ enum
COL_PIX = 0,
COL_NAME,
COL_FILENAME,
+ COL_THUMBNAIL,
COL_COLLATE_KEY,
N_COLS,
};
@@ -133,15 +146,22 @@ static void
xfdesktop_settings_do_single_preview(GtkTreeModel *model,
GtkTreeIter *iter)
{
- gchar *name = NULL, *new_name = NULL, *filename = NULL;
+ gchar *name = NULL, *new_name = NULL, *filename = NULL, *thumbnail = NULL;
GdkPixbuf *pix, *pix_scaled = NULL;
gtk_tree_model_get(model, iter,
COL_NAME, &name,
COL_FILENAME, &filename,
+ COL_THUMBNAIL, &thumbnail,
-1);
- pix = gdk_pixbuf_new_from_file(filename, NULL);
+ if(thumbnail == NULL) {
+ pix = gdk_pixbuf_new_from_file(filename, NULL);
+ } else {
+ pix = gdk_pixbuf_new_from_file(thumbnail, NULL);
+ g_free(thumbnail);
+ }
+
g_free(filename);
if(pix) {
gint width, height;
@@ -185,6 +205,27 @@ xfdesktop_settings_do_single_preview(GtkTreeModel *model,
}
static gpointer
+xfdesktop_settings_create_some_previews(gpointer data)
+{
+ PreviewData *pdata = data;
+ GSList *l;
+
+ GDK_THREADS_ENTER ();
+
+ for(l = pdata->iters; l && l->data != NULL; l = l->next)
+ xfdesktop_settings_do_single_preview(pdata->model, l->data);
+
+ g_object_unref(G_OBJECT(pdata->model));
+ g_slist_foreach(pdata->iters, (GFunc)gtk_tree_iter_free, NULL);
+ g_slist_free(pdata->iters);
+ g_free(pdata);
+
+ GDK_THREADS_LEAVE ();
+
+ return NULL;
+}
+
+static gpointer
xfdesktop_settings_create_all_previews(gpointer data)
{
GtkTreeModel *model = data;
@@ -221,6 +262,90 @@ xfdesktop_settings_create_all_previews(gpointer data)
}
static void
+cb_request_timer(gpointer data)
+{
+ AppearancePanel *panel = data;
+ PreviewData *pdata = panel->pdata;
+
+ TRACE("entering");
+
+ if(pdata == NULL)
+ return;
+
+ panel->pdata = NULL;
+ g_source_remove(panel->request_timer_id);
+ panel->request_timer_id = 0;
+
+ if(!g_thread_try_new("xfdesktop_settings_create_some_previews",
+ xfdesktop_settings_create_some_previews,
+ pdata, NULL))
+ {
+ g_critical("Unable to create thread for image previews.");
+ g_object_unref(G_OBJECT(pdata->model));
+ g_slist_foreach(pdata->iters, (GFunc)gtk_tree_iter_free, NULL);
+ g_slist_free(pdata->iters);
+ g_free(pdata);
+ }
+}
+
+static void
+cb_thumbnail_ready(XfdesktopThumbnailer *thumbnailer,
+ gchar *src_file, gchar *thumb_file,
+ gpointer user_data)
+{
+ AppearancePanel *panel = user_data;
+ GtkTreeModel *model = gtk_icon_view_get_model(GTK_ICON_VIEW(panel->image_iconview));
+ GtkTreeIter iter;
+
+ if(gtk_tree_model_get_iter_first(model, &iter)) {
+ do {
+ gchar *filename = NULL;
+ gtk_tree_model_get(model, &iter, COL_FILENAME, &filename, -1);
+
+ if(g_strcmp0(filename, src_file) == 0) {
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+ COL_THUMBNAIL, thumb_file, -1);
+
+ if(panel->request_timer_id != 0) {
+ g_source_remove(panel->request_timer_id);
+ }
+
+ if(panel->pdata == NULL) {
+ panel->pdata = g_new0(PreviewData, 1);
+ panel->pdata->model = g_object_ref(G_OBJECT(model));
+ }
+
+ panel->pdata->iters = g_slist_prepend(panel->pdata->iters, gtk_tree_iter_copy(&iter));
+
+ panel->request_timer_id = g_timeout_add_full(
+ G_PRIORITY_LOW,
+ 100,
+ (GSourceFunc)cb_request_timer,
+ panel,
+ NULL);
+
+ g_free(filename);
+ return;
+ }
+
+ g_free(filename);
+ } while(gtk_tree_model_iter_next(model, &iter));
+ }
+}
+
+/* Attempts to queue a thumbnail preview */
+static void
+xfdesktop_settings_create_thumbnail_preview(GtkTreeModel *model,
+ GtkTreeIter *iter,
+ AppearancePanel *panel)
+{
+ gchar *filename;
+
+ gtk_tree_model_get(model, iter, COL_FILENAME, &filename, -1);
+ xfdesktop_thumbnailer_queue_thumbnail(panel->thumbnailer, filename);
+}
+
+static void
cb_special_icon_toggled(GtkCellRendererToggle *render, gchar *path, gpointer user_data)
{
XfconfChannel *channel = g_object_get_data(G_OBJECT(user_data),
@@ -345,7 +470,8 @@ image_list_compare(GtkTreeModel *model,
static GtkTreeIter *
xfdesktop_settings_image_iconview_add(GtkTreeModel *model,
- const char *path)
+ const char *path,
+ AppearancePanel *panel)
{
gboolean added = FALSE, found = FALSE, valid = FALSE;
GtkTreeIter iter, search_iter;
@@ -388,6 +514,8 @@ xfdesktop_settings_image_iconview_add(GtkTreeModel *model,
COL_COLLATE_KEY, lower,
-1);
+ xfdesktop_settings_create_thumbnail_preview(model, &iter, panel);
+
added = TRUE;
}
}
@@ -406,13 +534,17 @@ xfdesktop_settings_image_iconview_add(GtkTreeModel *model,
static GtkTreeIter *
xfdesktop_image_list_add_dir(GtkListStore *ls,
const char *path,
- const char *cur_image_file)
+ const char *cur_image_file,
+ AppearancePanel *panel)
{
GDir *dir;
gboolean needs_slash = TRUE;
const gchar *file;
GtkTreeIter *iter, *iter_ret = NULL;
gchar buf[PATH_MAX];
+#ifdef G_ENABLE_DEBUG
+ GTimer *timer = g_timer_new();
+#endif
dir = g_dir_open(path, 0, 0);
if(!dir)
@@ -425,7 +557,7 @@ xfdesktop_image_list_add_dir(GtkListStore *ls,
g_snprintf(buf, sizeof(buf), needs_slash ? "%s/%s" : "%s%s",
path, file);
- iter = xfdesktop_settings_image_iconview_add(GTK_TREE_MODEL(ls), buf);
+ iter = xfdesktop_settings_image_iconview_add(GTK_TREE_MODEL(ls), buf, panel);
if(iter) {
if(cur_image_file && !iter_ret && !strcmp(buf, cur_image_file))
iter_ret = iter;
@@ -436,6 +568,11 @@ xfdesktop_image_list_add_dir(GtkListStore *ls,
g_dir_close(dir);
+#ifdef G_ENABLE_DEBUG
+ DBG("time %f", g_timer_elapsed(timer, NULL));
+ g_timer_destroy(timer);
+#endif
+
return iter_ret;
}
@@ -606,11 +743,44 @@ cb_xfdesktop_spin_icon_size_changed(GtkSpinButton *button,
}
static void
+xfdesktop_settings_stop_image_loading(AppearancePanel *panel)
+{
+ /* stop any thumbnailing in progress */
+ xfdesktop_thumbnailer_dequeue_all_thumbnails(panel->thumbnailer);
+
+ /* Remove any pending thumbnail updates */
+ if(panel->request_timer_id != 0) {
+ PreviewData *pdata = panel->pdata;
+ g_source_remove(panel->request_timer_id);
+ panel->request_timer_id = 0;
+ g_object_unref(G_OBJECT(pdata->model));
+ g_slist_foreach(pdata->iters, (GFunc)gtk_tree_iter_free, NULL);
+ g_slist_free(pdata->iters);
+ g_free(pdata);
+ }
+
+ /* Remove any preview threads that may still be running */
+ if(panel->preview_thread != NULL) {
+ g_thread_unref(panel->preview_thread);
+ panel->preview_thread = NULL;
+ }
+}
+
+static void
+cb_xfdesktop_bnt_exit_clicked(GtkButton *button, gpointer user_data)
+{
+ AppearancePanel *panel = user_data;
+
+ xfdesktop_settings_stop_image_loading(panel);
+}
+
+static void
cb_folder_selection_changed(GtkWidget *button,
gpointer user_data)
{
AppearancePanel *panel = user_data;
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(button));
+ static gchar *previous_filename = NULL;
GtkListStore *ls;
GtkTreeIter *iter;
GtkTreePath *path;
@@ -618,8 +788,17 @@ cb_folder_selection_changed(GtkWidget *button,
TRACE("entering");
+ /* Check to see if the folder actually did change */
+ if(g_strcmp0(filename, previous_filename) == 0)
+ return;
+
+ TRACE("folder changed to: %s", filename);
+ previous_filename = filename;
+
+ xfdesktop_settings_stop_image_loading(panel);
+
ls = gtk_list_store_new(N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_STRING);
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
property = xfdesktop_settings_generate_per_workspace_binding_string(panel, "last-image");
@@ -628,7 +807,7 @@ cb_folder_selection_changed(GtkWidget *button,
if(last_image == NULL)
last_image = DEFAULT_BACKDROP;
- iter = xfdesktop_image_list_add_dir(ls, filename, last_image);
+ iter = xfdesktop_image_list_add_dir(ls, filename, last_image, panel);
gtk_icon_view_set_model(GTK_ICON_VIEW(panel->image_iconview),
GTK_TREE_MODEL(ls));
@@ -642,22 +821,18 @@ cb_folder_selection_changed(GtkWidget *button,
}
}
- /* remove any preview threads that may still be running since we've probably
- * changed to a new monitor/workspace */
- if(panel->preview_thread != NULL) {
- g_thread_unref(panel->preview_thread);
- panel->preview_thread = NULL;
- }
-
- /* generate previews of each image -- the new thread will own
- * the reference on the list store, so let's not unref it here */
- panel->preview_thread = g_thread_try_new("xfdesktop_settings_create_all_previews",
- xfdesktop_settings_create_all_previews,
- ls, NULL);
-
- if(panel->preview_thread == NULL) {
- g_critical("Failed to spawn thread; backdrop previews will be unavailable.");
- g_object_unref(G_OBJECT(ls));
+ /* Thumbnailer not available, fallback to loading the images in a thread */
+ if(!xfdesktop_thumbnailer_service_available(panel->thumbnailer)) {
+ /* generate previews of each image -- the new thread will own
+ * the reference on the list store, so let's not unref it here */
+ panel->preview_thread = g_thread_try_new("xfdesktop_settings_create_all_previews",
+ xfdesktop_settings_create_all_previews,
+ ls, NULL);
+
+ if(panel->preview_thread == NULL) {
+ g_critical("Failed to spawn thread; backdrop previews will be unavailable.");
+ g_object_unref(G_OBJECT(ls));
+ }
}
g_free(property);
@@ -890,6 +1065,8 @@ xfdesktop_settings_setup_image_iconview(AppearancePanel *panel)
TRACE("entering");
+ panel->thumbnailer = xfdesktop_thumbnailer_new();
+
g_object_set(G_OBJECT(iconview),
"pixbuf-column", COL_PIX,
"item-width", PREVIEW_WIDTH,
@@ -899,6 +1076,9 @@ xfdesktop_settings_setup_image_iconview(AppearancePanel *panel)
g_signal_connect(G_OBJECT(iconview), "selection-changed",
G_CALLBACK(cb_image_selection_changed), panel);
+
+ g_signal_connect(panel->thumbnailer, "thumbnail-ready",
+ G_CALLBACK(cb_thumbnail_ready), panel);
}
static void
@@ -909,7 +1089,8 @@ xfdesktop_settings_dialog_setup_tabs(GtkBuilder *main_gxml,
{
GtkWidget *appearance_container, *chk_custom_font_size,
*spin_font_size, *w, *box, *spin_icon_size,
- *chk_show_thumbnails, *chk_single_click, *appearance_settings;
+ *chk_show_thumbnails, *chk_single_click, *appearance_settings,
+ *bnt_exit;
GtkBuilder *appearance_gxml;
AppearancePanel *panel = g_new0(AppearancePanel, 1);
GError *error = NULL;
@@ -922,6 +1103,12 @@ xfdesktop_settings_dialog_setup_tabs(GtkBuilder *main_gxml,
appearance_container = GTK_WIDGET(gtk_builder_get_object(main_gxml,
"notebook_screens"));
+ bnt_exit = GTK_WIDGET(gtk_builder_get_object(main_gxml, "bnt_exit"));
+
+ g_signal_connect(G_OBJECT(bnt_exit), "clicked",
+ G_CALLBACK(cb_xfdesktop_bnt_exit_clicked),
+ panel);
+
/* Icons tab */
/* icon size */
spin_icon_size = GTK_WIDGET(gtk_builder_get_object(main_gxml, "spin_icon_size"));
diff --git a/settings/xfdesktop-settings-ui.glade b/settings/xfdesktop-settings-ui.glade
index 7bccb6b..b69fe4b 100644
--- a/settings/xfdesktop-settings-ui.glade
+++ b/settings/xfdesktop-settings-ui.glade
@@ -769,7 +769,7 @@
</object>
</child>
<child>
- <object class="GtkButton" id="button1">
+ <object class="GtkButton" id="bnt_exit">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -791,7 +791,7 @@
</child>
<action-widgets>
<action-widget response="-11">button2</action-widget>
- <action-widget response="-3">button1</action-widget>
+ <action-widget response="-3">bnt_exit</action-widget>
</action-widgets>
</object>
</interface>
More information about the Xfce4-commits
mailing list