summaryrefslogtreecommitdiff
path: root/font-viewer
diff options
context:
space:
mode:
authorraveit65 <[email protected]>2017-01-08 19:20:19 +0100
committerraveit65 <[email protected]>2017-02-17 12:28:22 +0100
commit37052d6d0b5d63e7be05237e79eea38a8cb564e5 (patch)
tree2a928e72cc3c966382a6c846333a13eed5f494d5 /font-viewer
parentd31b6df0d02cb8cc8276f40c3636fd1ca257cf17 (diff)
downloadmate-control-center-37052d6d0b5d63e7be05237e79eea38a8cb564e5.tar.bz2
mate-control-center-37052d6d0b5d63e7be05237e79eea38a8cb564e5.tar.xz
Fontviewer: font-model, use g_io_scheduler_push_job() to refactor thumbnailing code
Always set the fallback pixbuf by default as icon in the model. At the same time, wrap the thumbnailing code in a single thread spawned with g_io_scheduler_push_job(). This makes the code more robust and avoids being too resource-greedy, as described in https://bugzilla.gnome.org/show_bug.cgi?id=677605 taken from: https://git.gnome.org/browse/gnome-font-viewer/commit/?id=1fc4a85
Diffstat (limited to 'font-viewer')
-rw-r--r--font-viewer/font-model.c332
1 files changed, 135 insertions, 197 deletions
diff --git a/font-viewer/font-model.c b/font-viewer/font-model.c
index f6fefa27..8d2912ab 100644
--- a/font-viewer/font-model.c
+++ b/font-viewer/font-model.c
@@ -62,91 +62,12 @@ static void ensure_thumbnail (FontViewModel *self, const gchar *path);
G_DEFINE_TYPE (FontViewModel, font_view_model, GTK_TYPE_LIST_STORE);
-#define ATTRIBUTES_FOR_THUMBNAIL \
- G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE"," \
- G_FILE_ATTRIBUTE_TIME_MODIFIED
-
-static gboolean
-create_thumbnail (GIOSchedulerJob *job,
- GCancellable *cancellable,
- gpointer user_data)
-{
- GSimpleAsyncResult *result = user_data;
- GFile *file = G_FILE (g_async_result_get_source_object (G_ASYNC_RESULT (result)));
- MateDesktopThumbnailFactory *factory;
- GFileInfo *info;
- gchar *uri;
- GdkPixbuf *pixbuf;
- guint64 mtime;
-
- uri = g_file_get_uri (file);
- info = g_file_query_info (file, ATTRIBUTES_FOR_THUMBNAIL,
- G_FILE_QUERY_INFO_NONE,
- NULL, NULL);
-
- /* we don't care about reporting errors here, just fail the
- * thumbnail.
- */
- if (info == NULL)
- {
- g_simple_async_result_set_op_res_gboolean (result, FALSE);
- goto out;
- }
-
- mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
-
- factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
- pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail
- (factory,
- uri, g_file_info_get_content_type (info));
-
- if (pixbuf != NULL)
- {
- mate_desktop_thumbnail_factory_save_thumbnail (factory, pixbuf,
- uri, (time_t) mtime);
- g_simple_async_result_set_op_res_gboolean (result, TRUE);
- }
- else
- {
- mate_desktop_thumbnail_factory_create_failed_thumbnail (factory,
- uri, (time_t) mtime);
- g_simple_async_result_set_op_res_gboolean (result, FALSE);
- }
-
- g_object_unref (info);
- g_object_unref (factory);
- g_clear_object (&pixbuf);
-
- out:
- g_simple_async_result_complete_in_idle (result);
- g_object_unref (result);
-
- return FALSE;
-}
-
-static void
-gd_queue_thumbnail_job_for_file_async (GFile *file,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *result;
-
- result = g_simple_async_result_new (G_OBJECT (file),
- callback, user_data,
- gd_queue_thumbnail_job_for_file_async);
-
- g_io_scheduler_push_job (create_thumbnail,
- result, NULL,
- G_PRIORITY_DEFAULT, NULL);
-}
-
-static gboolean
-gd_queue_thumbnail_job_for_file_finish (GAsyncResult *res)
-{
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
-
- return g_simple_async_result_get_op_res_gboolean (simple);
-}
+#define ATTRIBUTES_FOR_CREATING_THUMBNAIL \
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE"," \
+ G_FILE_ATTRIBUTE_TIME_MODIFIED
+#define ATTRIBUTES_FOR_EXISTING_THUMBNAIL \
+ G_FILE_ATTRIBUTE_THUMBNAIL_PATH"," \
+ G_FILE_ATTRIBUTE_THUMBNAILING_FAILED
typedef struct {
const gchar *file;
@@ -235,43 +156,28 @@ font_view_model_get_iter_for_face (FontViewModel *self,
typedef struct {
FontViewModel *self;
+ GFile *font_file;
gchar *font_path;
+ GdkPixbuf *pixbuf;
} LoadThumbnailData;
static void
load_thumbnail_data_free (LoadThumbnailData *data)
{
g_object_unref (data->self);
+ g_object_unref (data->font_file);
+ g_clear_object (&data->pixbuf);
g_free (data->font_path);
- g_slice_free (LoadThumbnailData, data);
-}
-
-static void
-thumbnail_ready_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
-{
- FontViewModel *self = user_data;
- gchar *path;
- GFile *file;
- gd_queue_thumbnail_job_for_file_finish (G_ASYNC_RESULT (res));
- file = G_FILE (source);
- path = g_file_get_path (file);
- ensure_thumbnail (self, path);
-
- g_free (path);
+ g_slice_free (LoadThumbnailData, data);
}
-static void
-set_fallback_icon (FontViewModel *self,
- GFile *file)
+static GdkPixbuf *
+get_fallback_icon (void)
{
- GtkTreeIter iter;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
GdkPixbuf *pix;
- gchar *path;
GIcon *icon = NULL;
icon_theme = gtk_icon_theme_get_default ();
@@ -281,129 +187,151 @@ set_fallback_icon (FontViewModel *self,
g_object_unref (icon);
if (!icon_info)
- return;
+ return NULL;
pix = gtk_icon_info_load_icon (icon_info, NULL);
gtk_icon_info_free (icon_info);
- if (!pix)
- return;
-
- path = g_file_get_path (file);
- if (font_view_model_get_iter_for_file (self, path, &iter))
- gtk_list_store_set (GTK_LIST_STORE (self), &iter,
- COLUMN_ICON, pix,
- -1);
-
- g_free (path);
- g_object_unref (pix);
+ return pix;
}
-static void
-pixbuf_async_ready_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+static gboolean
+ensure_thumbnail_job_done (gpointer user_data)
{
LoadThumbnailData *data = user_data;
- GdkPixbuf *pix;
GtkTreeIter iter;
- GFile *file;
-
- pix = gdk_pixbuf_new_from_stream_finish (res, NULL);
- if (pix != NULL) {
- if (font_view_model_get_iter_for_file (data->self, data->font_path, &iter))
- gtk_list_store_set (GTK_LIST_STORE (data->self), &iter,
- COLUMN_ICON, pix,
- -1);
-
- g_object_unref (pix);
- } else {
- file = g_file_new_for_path (data->font_path);
- set_fallback_icon (data->self, file);
- g_object_unref (file);
- }
+ if ((data->pixbuf != NULL) &&
+ (font_view_model_get_iter_for_file (data->self, data->font_path, &iter)))
+ gtk_list_store_set (GTK_LIST_STORE (data->self), &iter,
+ COLUMN_ICON, data->pixbuf,
+ -1);
load_thumbnail_data_free (data);
+
+ return FALSE;
}
-static void
-thumb_file_read_async_ready_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+static GdkPixbuf *
+create_thumbnail (LoadThumbnailData *data)
{
- LoadThumbnailData *data = user_data;
- GFileInputStream *is;
+ GFile *file = data->font_file;
+ MateDesktopThumbnailFactory *factory;
+ gchar *uri;
+ guint64 mtime;
+
+ GdkPixbuf *pixbuf = NULL;
+ GFileInfo *info = NULL;
+
+ uri = g_file_get_uri (file);
+ info = g_file_query_info (file, ATTRIBUTES_FOR_CREATING_THUMBNAIL,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ /* we don't care about reporting errors here, just fail the
+ * thumbnail.
+ */
+ if (info == NULL)
+ goto out;
- is = g_file_read_finish (G_FILE (source),
- res, NULL);
+ mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
- if (is != NULL) {
- gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (is),
- 128, 128, TRUE,
- NULL, pixbuf_async_ready_cb, data);
- g_object_unref (is);
- } else {
- set_fallback_icon (data->self, G_FILE (source));
- load_thumbnail_data_free (data);
- }
+ factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+ pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail
+ (factory,
+ uri, g_file_info_get_content_type (info));
+
+ if (pixbuf != NULL)
+ mate_desktop_thumbnail_factory_save_thumbnail (factory, pixbuf,
+ uri, (time_t) mtime);
+ else
+ mate_desktop_thumbnail_factory_create_failed_thumbnail (factory,
+ uri, (time_t) mtime);
+
+ g_object_unref (factory);
+
+ out:
+ g_clear_object (&info);
+
+ return pixbuf;
}
-static void
-thumbnail_query_info_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+static gboolean
+ensure_thumbnail_job (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ gpointer user_data)
{
- FontViewModel *self = user_data;
- GFile *file = G_FILE (source);
- GFile *thumb_file = NULL;
- GFileInfo *info;
+ LoadThumbnailData *data = user_data;
+ gboolean thumb_failed;
const gchar *thumb_path;
- LoadThumbnailData *data;
- info = g_file_query_info_finish (file, res, NULL);
+ GError *error = NULL;
+ GFile *thumb_file = NULL;
+ GFileInputStream *is = NULL;
+ GFileInfo *info = NULL;
+
+ info = g_file_query_info (data->font_file,
+ ATTRIBUTES_FOR_EXISTING_THUMBNAIL,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
- if (!info ||
- g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)) {
- set_fallback_icon (self, file);
+ if (error != NULL) {
+ g_debug ("Can't query info for file %s: %s\n", data->font_path, error->message);
goto out;
}
+ thumb_failed = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
+ if (thumb_failed)
+ goto out;
+
thumb_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
- if (thumb_path)
+
+ if (thumb_path != NULL) {
thumb_file = g_file_new_for_path (thumb_path);
- else
- gd_queue_thumbnail_job_for_file_async (file, thumbnail_ready_cb, self);
+ is = g_file_read (thumb_file, NULL, &error);
- if (thumb_file != NULL) {
- data = g_slice_new0 (LoadThumbnailData);
- data->self = g_object_ref (self);
- data->font_path = g_file_get_path (file);
+ if (error != NULL) {
+ g_debug ("Can't read file %s: %s\n", thumb_path, error->message);
+ goto out;
+ }
- g_file_read_async (thumb_file, G_PRIORITY_DEFAULT, NULL,
- thumb_file_read_async_ready_cb, data);
+ data->pixbuf = gdk_pixbuf_new_from_stream_at_scale (G_INPUT_STREAM (is),
+ 128, 128, TRUE,
+ NULL, &error);
- g_object_unref (thumb_file);
+ if (error != NULL) {
+ g_debug ("Can't read thumbnail pixbuf %s: %s\n", thumb_path, error->message);
+ goto out;
+ }
+ } else {
+ data->pixbuf = create_thumbnail (data);
}
out:
+ g_clear_error (&error);
+ g_clear_object (&is);
+ g_clear_object (&thumb_file);
g_clear_object (&info);
+
+ g_io_scheduler_job_send_to_mainloop_async (job, ensure_thumbnail_job_done,
+ data, NULL);
+
+ return FALSE;
}
static void
ensure_thumbnail (FontViewModel *self,
const gchar *path)
{
- GFile *file;
+ LoadThumbnailData *data;
+
+ data = g_slice_new0 (LoadThumbnailData);
+ data->self = g_object_ref (self);
+ data->font_file = g_file_new_for_path (path);
+ data->font_path = g_strdup (path);
- file = g_file_new_for_path (path);
- g_file_query_info_async (file,
- G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
- G_FILE_ATTRIBUTE_THUMBNAILING_FAILED,
- G_FILE_QUERY_INFO_NONE,
- G_PRIORITY_DEFAULT, NULL,
- thumbnail_query_info_cb, self);
- g_object_unref (file);
+ g_io_scheduler_push_job (ensure_thumbnail_job, data,
+ NULL, G_PRIORITY_DEFAULT, NULL);
}
/* make sure the font list is valid */
@@ -413,9 +341,9 @@ ensure_font_list (FontViewModel *self)
FcPattern *pat;
FcObjectSet *os;
gint i;
- GtkTreeIter iter;
FcChar8 *file;
gchar *font_name;
+ GdkPixbuf *pix;
if (self->priv->font_list) {
FcFontSetDestroy (self->priv->font_list);
@@ -446,18 +374,29 @@ ensure_font_list (FontViewModel *self)
if (!font_name)
continue;
- gtk_list_store_append (GTK_LIST_STORE (self), &iter);
- gtk_list_store_set (GTK_LIST_STORE (self), &iter,
- COLUMN_NAME, font_name,
- COLUMN_POINTER, self->priv->font_list->fonts[i],
- COLUMN_PATH, file,
- -1);
+ pix = get_fallback_icon ();
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (self), NULL, -1,
+ COLUMN_NAME, font_name,
+ COLUMN_POINTER, self->priv->font_list->fonts[i],
+ COLUMN_PATH, file,
+ COLUMN_ICON, pix,
+ -1);
ensure_thumbnail (self, (const gchar *) file);
g_free (font_name);
+ g_object_unref (pix);
}
}
+static gboolean
+ensure_font_list_idle (gpointer user_data)
+{
+ FontViewModel *self = user_data;
+ ensure_font_list (self);
+
+ return FALSE;
+}
+
static int
font_view_model_sort_func (GtkTreeModel *model,
GtkTreeIter *a,
@@ -550,8 +489,7 @@ font_view_model_init (FontViewModel *self)
font_view_model_sort_func,
NULL, NULL);
-
- ensure_font_list (self);
+ g_idle_add (ensure_font_list_idle, self);
create_file_monitors (self);
}