~noskcaj/ubuntu/vivid/thunar/1.6.4

« back to all changes in this revision

Viewing changes to thunar/thunar-thumbnail-generator.c

  • Committer: Bazaar Package Importer
  • Author(s): Lionel Le Folgoc
  • Date: 2010-12-04 16:46:20 UTC
  • mto: (2.1.3 experimental) (1.3.1)
  • mto: This revision was merged to the branch mainline in revision 69.
  • Revision ID: james.westby@ubuntu.com-20101204164620-h7p4t2e9z6hfhz6l
Tags: upstream-1.1.4
ImportĀ upstreamĀ versionĀ 1.1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id$ */
2
 
/*-
3
 
 * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
4
 
 *
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)
8
 
 * any later version.
9
 
 *
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
13
 
 * more details.
14
 
 *
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
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include <config.h>
22
 
#endif
23
 
 
24
 
#include <thunar/thunar-private.h>
25
 
#include <thunar/thunar-thumbnail-generator.h>
26
 
 
27
 
 
28
 
 
29
 
typedef struct _ThunarThumbnailInfo ThunarThumbnailInfo;
30
 
 
31
 
 
32
 
 
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);
39
 
 
40
 
 
41
 
 
42
 
struct _ThunarThumbnailGeneratorClass
43
 
{
44
 
  GObjectClass __parent__;
45
 
};
46
 
 
47
 
struct _ThunarThumbnailGenerator
48
 
{
49
 
  GObject __parent__;
50
 
 
51
 
  ThunarVfsThumbFactory *factory;
52
 
  volatile GThread      *thread;
53
 
  GMutex                *lock;
54
 
  GCond                 *cond;
55
 
  gint                   idle_id;
56
 
 
57
 
  GList                 *requests;
58
 
  GList                 *replies;
59
 
};
60
 
 
61
 
struct _ThunarThumbnailInfo
62
 
{
63
 
  ThunarFile    *file;
64
 
  ThunarVfsInfo *info;
65
 
};
66
 
 
67
 
 
68
 
 
69
 
static GObjectClass *thunar_thumbnail_generator_parent_class;
70
 
 
71
 
 
72
 
 
73
 
GType
74
 
thunar_thumbnail_generator_get_type (void)
75
 
{
76
 
  static GType type = G_TYPE_INVALID;
77
 
 
78
 
  if (G_UNLIKELY (type == G_TYPE_INVALID))
79
 
    {
80
 
      static const GTypeInfo info =
81
 
      {
82
 
        sizeof (ThunarThumbnailGeneratorClass),
83
 
        NULL,
84
 
        NULL,
85
 
        (GClassInitFunc) thunar_thumbnail_generator_class_init,
86
 
        NULL,
87
 
        NULL,
88
 
        sizeof (ThunarThumbnailGenerator),
89
 
        0,
90
 
        (GInstanceInitFunc) thunar_thumbnail_generator_init,
91
 
        NULL,
92
 
      };
93
 
 
94
 
      type = g_type_register_static (G_TYPE_OBJECT, I_("ThunarThumbnailGenerator"), &info, 0);
95
 
    }
96
 
 
97
 
  return type;
98
 
}
99
 
 
100
 
 
101
 
 
102
 
static void
103
 
thunar_thumbnail_generator_class_init (ThunarThumbnailGeneratorClass *klass)
104
 
{
105
 
  GObjectClass *gobject_class;
106
 
 
107
 
  /* determine the parent type class */
108
 
  thunar_thumbnail_generator_parent_class = g_type_class_peek_parent (klass);
109
 
 
110
 
  gobject_class = G_OBJECT_CLASS (klass);
111
 
  gobject_class->finalize = thunar_thumbnail_generator_finalize;
112
 
}
113
 
 
114
 
 
115
 
 
116
 
static void
117
 
thunar_thumbnail_generator_init (ThunarThumbnailGenerator *generator)
118
 
{
119
 
  generator->lock = g_mutex_new ();
120
 
  generator->cond = g_cond_new ();
121
 
  generator->idle_id = -1;
122
 
}
123
 
 
124
 
 
125
 
 
126
 
static void
127
 
thunar_thumbnail_generator_finalize (GObject *object)
128
 
{
129
 
  ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (object);
130
 
 
131
 
  /* acquire the generator lock */
132
 
  g_mutex_lock (generator->lock);
133
 
 
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;
138
 
 
139
 
  /* wait for the generator thread to terminate */
140
 
  while (G_UNLIKELY (generator->thread != NULL))
141
 
    g_cond_wait (generator->cond, generator->lock);
142
 
 
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;
147
 
 
148
 
  /* drop the idle source (if any) */
149
 
  if (G_UNLIKELY (generator->idle_id >= 0))
150
 
    g_source_remove (generator->idle_id);
151
 
 
152
 
  /* release the thumbnail factory */
153
 
  g_object_unref (G_OBJECT (generator->factory));
154
 
 
155
 
  /* release the generator lock */
156
 
  g_mutex_unlock (generator->lock);
157
 
 
158
 
  /* release the cond and mutex */
159
 
  g_mutex_free (generator->lock);
160
 
  g_cond_free (generator->cond);
161
 
 
162
 
  (*G_OBJECT_CLASS (thunar_thumbnail_generator_parent_class)->finalize) (object);
163
 
}
164
 
 
165
 
 
166
 
 
167
 
static gboolean
168
 
thunar_thumbnail_generator_idle (gpointer user_data)
169
 
{
170
 
  ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (user_data);
171
 
  ThunarThumbnailInfo      *info;
172
 
  GList                    *infos;
173
 
  GList                    *lp;
174
 
 
175
 
  /* acquire the lock on the generator */
176
 
  g_mutex_lock (generator->lock);
177
 
 
178
 
  /* grab the infos returned from the thumbnailer thread */
179
 
  infos = generator->replies;
180
 
  generator->replies = NULL;
181
 
 
182
 
  /* reset the process idle id */
183
 
  generator->idle_id = -1;
184
 
 
185
 
  /* release the lock on the generator */
186
 
  g_mutex_unlock (generator->lock);
187
 
 
188
 
  /* acquire the GDK thread lock */
189
 
  GDK_THREADS_ENTER ();
190
 
 
191
 
  /* invoke "changed" signals on all files */
192
 
  for (lp = infos; lp != NULL; lp = lp->next)
193
 
    {
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);
198
 
    }
199
 
  g_list_free (infos);
200
 
 
201
 
  /* release the GDK thread lock */
202
 
  GDK_THREADS_LEAVE ();
203
 
 
204
 
  return FALSE;
205
 
}
206
 
 
207
 
 
208
 
 
209
 
static gpointer
210
 
thunar_thumbnail_generator_thread (gpointer user_data)
211
 
{
212
 
  ThunarThumbnailGenerator *generator = THUNAR_THUMBNAIL_GENERATOR (user_data);
213
 
  ThunarThumbnailInfo      *info;
214
 
  GdkPixbuf                *icon;
215
 
 
216
 
  for (;;)
217
 
    {
218
 
      /* lock the factory */
219
 
      g_mutex_lock (generator->lock);
220
 
 
221
 
      /* grab the first thumbnail from the request list */
222
 
      if (G_LIKELY (generator->requests != NULL))
223
 
        {
224
 
          info = generator->requests->data;
225
 
          generator->requests = g_list_remove (generator->requests, info);
226
 
        }
227
 
      else
228
 
        {
229
 
          info = NULL;
230
 
        }
231
 
 
232
 
      /* check if we have something to generate */
233
 
      if (G_UNLIKELY (info == NULL))
234
 
        {
235
 
          /* reset the thread pointer */
236
 
          generator->thread = NULL;
237
 
          g_cond_signal (generator->cond);
238
 
          g_mutex_unlock (generator->lock);
239
 
          break;
240
 
        }
241
 
 
242
 
      /* release the lock */
243
 
      g_mutex_unlock (generator->lock);
244
 
 
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))
247
 
        {
248
 
          /* try to generate the thumbnail */
249
 
          icon = thunar_vfs_thumb_factory_generate_thumbnail (generator->factory, info->info);
250
 
 
251
 
          /* store the thumbnail (or the failed notice) */
252
 
          thunar_vfs_thumb_factory_store_thumbnail (generator->factory, icon, info->info, NULL);
253
 
        }
254
 
      else
255
 
        {
256
 
          icon = NULL;
257
 
        }
258
 
 
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);
265
 
 
266
 
      /* release the icon (if any) */
267
 
      if (G_LIKELY (icon != NULL))
268
 
        g_object_unref (G_OBJECT (icon));
269
 
    }
270
 
 
271
 
  return NULL;
272
 
}
273
 
 
274
 
 
275
 
 
276
 
static void
277
 
thunar_thumbnail_info_free (ThunarThumbnailInfo *info)
278
 
{
279
 
  g_object_unref (G_OBJECT (info->file));
280
 
  thunar_vfs_info_unref (info->info);
281
 
  _thunar_slice_free (ThunarThumbnailInfo, info);
282
 
}
283
 
 
284
 
 
285
 
 
286
 
/**
287
 
 * thunar_thumbnail_generator_new:
288
 
 * @factory : a #ThunarVfsThumbFactory.
289
 
 *
290
 
 * Allocates a new #ThunarThumbnailGenerator object,
291
 
 * which can be used to generate and store thumbnails
292
 
 * for files.
293
 
 *
294
 
 * The caller is responsible to free the returned
295
 
 * object using g_object_unref() when no longer needed.
296
 
 *
297
 
 * Return value: a newly allocated #ThunarThumbnailGenerator.
298
 
 **/
299
 
ThunarThumbnailGenerator*
300
 
thunar_thumbnail_generator_new (ThunarVfsThumbFactory *factory)
301
 
{
302
 
  ThunarThumbnailGenerator *generator;
303
 
 
304
 
  _thunar_return_val_if_fail (THUNAR_VFS_IS_THUMB_FACTORY (factory), NULL);
305
 
 
306
 
  /* allocate the generator object */
307
 
  generator = g_object_new (THUNAR_TYPE_THUMBNAIL_GENERATOR, NULL);
308
 
  generator->factory = g_object_ref (G_OBJECT (factory));
309
 
 
310
 
  return generator;
311
 
}
312
 
 
313
 
 
314
 
 
315
 
/**
316
 
 * thunar_thumbnail_generator_enqueue:
317
 
 * @generator
318
 
 * @file
319
 
 **/
320
 
void
321
 
thunar_thumbnail_generator_enqueue (ThunarThumbnailGenerator *generator,
322
 
                                    ThunarFile               *file)
323
 
{
324
 
  ThunarThumbnailInfo *info;
325
 
  GError              *error = NULL;
326
 
  GList               *lp;
327
 
 
328
 
  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_GENERATOR (generator));
329
 
  _thunar_return_if_fail (THUNAR_IS_FILE (file));
330
 
 
331
 
  /* acquire the generator lock */
332
 
  g_mutex_lock (generator->lock);
333
 
 
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)
337
 
      break;
338
 
 
339
 
  /* schedule a request for the file if it's not already done */
340
 
  if (G_LIKELY (lp == NULL))
341
 
    {
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));
346
 
 
347
 
      /* schedule the request */
348
 
      generator->requests = g_list_append (generator->requests, info);
349
 
 
350
 
      /* start the generator thread on-demand */
351
 
      if (G_UNLIKELY (generator->thread == NULL))
352
 
        {
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))
356
 
            {
357
 
              g_warning ("Failed to launch thumbnail generator thread: %s", error->message);
358
 
              g_error_free (error);
359
 
            }
360
 
        }
361
 
    }
362
 
 
363
 
  /* release the generator lock */
364
 
  g_mutex_unlock (generator->lock);
365
 
}
366
 
 
367
 
 
368