3
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the Free
7
* Software Foundation; either version 2 of the License, or (at your option)
10
* This program is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
* You should have received a copy of the GNU General Public License along with
16
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17
* Place, Suite 330, Boston, MA 02111-1307 USA
24
#include <thunar/thunar-private.h>
25
#include <thunar/thunar-thumbnail-generator.h>
29
typedef struct _ThunarThumbnailInfo ThunarThumbnailInfo;
33
static void thunar_thumbnail_generator_class_init (ThunarThumbnailGeneratorClass *klass);
34
static void thunar_thumbnail_generator_init (ThunarThumbnailGenerator *generator);
35
static void thunar_thumbnail_generator_finalize (GObject *object);
36
static gboolean thunar_thumbnail_generator_idle (gpointer user_data);
37
static gpointer thunar_thumbnail_generator_thread (gpointer user_data);
38
static void thunar_thumbnail_info_free (ThunarThumbnailInfo *info);
42
struct _ThunarThumbnailGeneratorClass
44
GObjectClass __parent__;
47
struct _ThunarThumbnailGenerator
51
ThunarVfsThumbFactory *factory;
52
volatile GThread *thread;
61
struct _ThunarThumbnailInfo
69
static GObjectClass *thunar_thumbnail_generator_parent_class;
74
thunar_thumbnail_generator_get_type (void)
76
static GType type = G_TYPE_INVALID;
78
if (G_UNLIKELY (type == G_TYPE_INVALID))
80
static const GTypeInfo info =
82
sizeof (ThunarThumbnailGeneratorClass),
85
(GClassInitFunc) thunar_thumbnail_generator_class_init,
88
sizeof (ThunarThumbnailGenerator),
90
(GInstanceInitFunc) thunar_thumbnail_generator_init,
94
type = g_type_register_static (G_TYPE_OBJECT, I_("ThunarThumbnailGenerator"), &info, 0);
103
thunar_thumbnail_generator_class_init (ThunarThumbnailGeneratorClass *klass)
105
GObjectClass *gobject_class;
107
/* determine the parent type class */
108
thunar_thumbnail_generator_parent_class = g_type_class_peek_parent (klass);
110
gobject_class = G_OBJECT_CLASS (klass);
111
gobject_class->finalize = thunar_thumbnail_generator_finalize;
117
thunar_thumbnail_generator_init (ThunarThumbnailGenerator *generator)
119
generator->lock = g_mutex_new ();
120
generator->cond = g_cond_new ();
121
generator->idle_id = -1;
127
thunar_thumbnail_generator_finalize (GObject *object)
129
ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (object);
131
/* acquire the generator lock */
132
g_mutex_lock (generator->lock);
134
/* release all requests */
135
g_list_foreach (generator->requests, (GFunc) thunar_thumbnail_info_free, NULL);
136
g_list_free (generator->requests);
137
generator->requests = NULL;
139
/* wait for the generator thread to terminate */
140
while (G_UNLIKELY (generator->thread != NULL))
141
g_cond_wait (generator->cond, generator->lock);
143
/* release all replies */
144
g_list_foreach (generator->replies, (GFunc) thunar_thumbnail_info_free, NULL);
145
g_list_free (generator->replies);
146
generator->replies = NULL;
148
/* drop the idle source (if any) */
149
if (G_UNLIKELY (generator->idle_id >= 0))
150
g_source_remove (generator->idle_id);
152
/* release the thumbnail factory */
153
g_object_unref (G_OBJECT (generator->factory));
155
/* release the generator lock */
156
g_mutex_unlock (generator->lock);
158
/* release the cond and mutex */
159
g_mutex_free (generator->lock);
160
g_cond_free (generator->cond);
162
(*G_OBJECT_CLASS (thunar_thumbnail_generator_parent_class)->finalize) (object);
168
thunar_thumbnail_generator_idle (gpointer user_data)
170
ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (user_data);
171
ThunarThumbnailInfo *info;
175
/* acquire the lock on the generator */
176
g_mutex_lock (generator->lock);
178
/* grab the infos returned from the thumbnailer thread */
179
infos = generator->replies;
180
generator->replies = NULL;
182
/* reset the process idle id */
183
generator->idle_id = -1;
185
/* release the lock on the generator */
186
g_mutex_unlock (generator->lock);
188
/* acquire the GDK thread lock */
189
GDK_THREADS_ENTER ();
191
/* invoke "changed" signals on all files */
192
for (lp = infos; lp != NULL; lp = lp->next)
194
/* invoke "changed" and release the info */
195
info = (ThunarThumbnailInfo *) lp->data;
196
thunar_file_changed (THUNAR_FILE (info->file));
197
thunar_thumbnail_info_free (info);
201
/* release the GDK thread lock */
202
GDK_THREADS_LEAVE ();
210
thunar_thumbnail_generator_thread (gpointer user_data)
212
ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (user_data);
213
ThunarThumbnailInfo *info;
218
/* lock the factory */
219
g_mutex_lock (generator->lock);
221
/* grab the first thumbnail from the request list */
222
if (G_LIKELY (generator->requests != NULL))
224
info = generator->requests->data;
225
generator->requests = g_list_remove (generator->requests, info);
232
/* check if we have something to generate */
233
if (G_UNLIKELY (info == NULL))
235
/* reset the thread pointer */
236
generator->thread = NULL;
237
g_cond_signal (generator->cond);
238
g_mutex_unlock (generator->lock);
242
/* release the lock */
243
g_mutex_unlock (generator->lock);
245
/* don't generate thumbnails for files for which only we own a reference */
246
if (G_LIKELY (G_OBJECT (info->file)->ref_count > 1))
248
/* try to generate the thumbnail */
249
icon = thunar_vfs_thumb_factory_generate_thumbnail (generator->factory, info->info);
251
/* store the thumbnail (or the failed notice) */
252
thunar_vfs_thumb_factory_store_thumbnail (generator->factory, icon, info->info, NULL);
259
/* place the thumbnail on the reply list and schedule the idle source */
260
g_mutex_lock (generator->lock);
261
generator->replies = g_list_prepend (generator->replies, info);
262
if (G_UNLIKELY (generator->idle_id < 0))
263
generator->idle_id = g_idle_add_full (G_PRIORITY_LOW, thunar_thumbnail_generator_idle, generator, NULL);
264
g_mutex_unlock (generator->lock);
266
/* release the icon (if any) */
267
if (G_LIKELY (icon != NULL))
268
g_object_unref (G_OBJECT (icon));
277
thunar_thumbnail_info_free (ThunarThumbnailInfo *info)
279
g_object_unref (G_OBJECT (info->file));
280
thunar_vfs_info_unref (info->info);
281
_thunar_slice_free (ThunarThumbnailInfo, info);
287
* thunar_thumbnail_generator_new:
288
* @factory : a #ThunarVfsThumbFactory.
290
* Allocates a new #ThunarThumbnailGenerator object,
291
* which can be used to generate and store thumbnails
294
* The caller is responsible to free the returned
295
* object using g_object_unref() when no longer needed.
297
* Return value: a newly allocated #ThunarThumbnailGenerator.
299
ThunarThumbnailGenerator*
300
thunar_thumbnail_generator_new (ThunarVfsThumbFactory *factory)
302
ThunarThumbnailGenerator *generator;
304
_thunar_return_val_if_fail (THUNAR_VFS_IS_THUMB_FACTORY (factory), NULL);
306
/* allocate the generator object */
307
generator = g_object_new (THUNAR_TYPE_THUMBNAIL_GENERATOR, NULL);
308
generator->factory = g_object_ref (G_OBJECT (factory));
316
* thunar_thumbnail_generator_enqueue:
321
thunar_thumbnail_generator_enqueue (ThunarThumbnailGenerator *generator,
324
ThunarThumbnailInfo *info;
325
GError *error = NULL;
328
_thunar_return_if_fail (THUNAR_IS_THUMBNAIL_GENERATOR (generator));
329
_thunar_return_if_fail (THUNAR_IS_FILE (file));
331
/* acquire the generator lock */
332
g_mutex_lock (generator->lock);
334
/* check if the file is already on the request list */
335
for (lp = generator->requests; lp != NULL; lp = lp->next)
336
if (((ThunarThumbnailInfo *) lp->data)->file == file)
339
/* schedule a request for the file if it's not already done */
340
if (G_LIKELY (lp == NULL))
342
/* allocate a thumbnail info for the file */
343
info = _thunar_slice_new (ThunarThumbnailInfo);
344
info->file = g_object_ref (G_OBJECT (file));
345
info->info = thunar_vfs_info_copy (thunar_file_get_info (file));
347
/* schedule the request */
348
generator->requests = g_list_append (generator->requests, info);
350
/* start the generator thread on-demand */
351
if (G_UNLIKELY (generator->thread == NULL))
353
generator->thread = g_thread_create_full (thunar_thumbnail_generator_thread, generator, 0,
354
FALSE, FALSE, G_THREAD_PRIORITY_LOW, &error);
355
if (G_UNLIKELY (generator->thread == NULL))
357
g_warning ("Failed to launch thumbnail generator thread: %s", error->message);
358
g_error_free (error);
363
/* release the generator lock */
364
g_mutex_unlock (generator->lock);