converted image loader to a GObject and use signals for notification
[geeqie.git] / src / cache-loader.c
1 /*
2  * Geeqie
3  * (C) 2005 John Ellis
4  * Copyright (C) 2008 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #include "main.h"
14 #include "cache-loader.h"
15 #include "cache.h"
16
17 #include "filedata.h"
18 #include "exif.h"
19 #include "md5-util.h"
20 #include "ui_fileops.h"
21
22
23 static gboolean cache_loader_process(CacheLoader *cl);
24
25
26 static void cache_loader_done_cb(ImageLoader *il, gpointer data)
27 {
28         CacheLoader *cl = data;
29
30         cache_loader_process(cl);
31 }
32
33 static void cache_loader_error_cb(ImageLoader *il, gpointer data)
34 {
35         CacheLoader *cl = data;
36
37         cl->error = TRUE;
38         cache_loader_done_cb(il, data);
39 }
40
41 static gboolean cache_loader_process(CacheLoader *cl)
42 {
43         if (cl->todo_mask & CACHE_LOADER_SIMILARITY &&
44             !cl->cd->similarity)
45                 {
46                 GdkPixbuf *pixbuf;
47
48                 if (!cl->il && !cl->error)
49                         {
50                         cl->il = image_loader_new(cl->fd);
51                         g_signal_connect (G_OBJECT(cl->il), "error", (GCallback)cache_loader_error_cb, cl);
52                         g_signal_connect (G_OBJECT(cl->il), "done", (GCallback)cache_loader_done_cb, cl);
53                         if (image_loader_start(cl->il))
54                                 {
55                                 return FALSE;
56                                 }
57
58                         cl->error = TRUE;
59                         }
60
61                 pixbuf = image_loader_get_pixbuf(cl->il);
62                 if (pixbuf)
63                         {
64                         if (!cl->error)
65                                 {
66                                 ImageSimilarityData *sim;
67
68                                 sim = image_sim_new_from_pixbuf(pixbuf);
69                                 cache_sim_data_set_similarity(cl->cd, sim);
70                                 image_sim_free(sim);
71
72                                 cl->done_mask |= CACHE_LOADER_SIMILARITY;
73                                 }
74
75                         /* we have the dimensions via pixbuf */
76                         if (!cl->cd->dimensions)
77                                 {
78                                 cache_sim_data_set_dimensions(cl->cd, gdk_pixbuf_get_width(pixbuf),
79                                                                       gdk_pixbuf_get_height(pixbuf));
80                                 if (cl->todo_mask & CACHE_LOADER_DIMENSIONS)
81                                         {
82                                         cl->todo_mask &= ~CACHE_LOADER_DIMENSIONS;
83                                         cl->done_mask |= CACHE_LOADER_DIMENSIONS;
84                                         }
85                                 }
86                         }
87
88                 image_loader_free(cl->il);
89                 cl->il = NULL;
90
91                 cl->todo_mask &= ~CACHE_LOADER_SIMILARITY;
92                 }
93         else if (cl->todo_mask & CACHE_LOADER_DIMENSIONS &&
94                  !cl->cd->dimensions)
95                 {
96                 if (!cl->error &&
97                     image_load_dimensions(cl->fd, &cl->cd->width, &cl->cd->height))
98                         {
99                         cl->cd->dimensions = TRUE;
100                         cl->done_mask |= CACHE_LOADER_DIMENSIONS;
101                         }
102                 else
103                         {
104                         cl->error = TRUE;
105                         }
106
107                 cl->todo_mask &= ~CACHE_LOADER_DIMENSIONS;
108                 }
109         else if (cl->todo_mask & CACHE_LOADER_MD5SUM &&
110                  !cl->cd->have_md5sum)
111                 {
112                 if (md5_get_digest_from_file_utf8(cl->fd->path, cl->cd->md5sum))
113                         {
114                         cl->cd->have_md5sum = TRUE;
115                         cl->done_mask |= CACHE_LOADER_MD5SUM;
116                         }
117                 else
118                         {
119                         cl->error = TRUE;
120                         }
121
122                 cl->todo_mask &= ~CACHE_LOADER_MD5SUM;
123                 }
124         else if (cl->todo_mask & CACHE_LOADER_DATE &&
125                  !cl->cd->have_date)
126                 {
127                 time_t date = -1;
128                 ExifData *exif;
129
130                 exif = exif_read_fd(cl->fd);
131                 if (exif)
132                         {
133                         gchar *text;
134
135                         text = exif_get_data_as_text(exif, "formatted.DateTime");
136                         if (text)
137                                 {
138                                 struct tm t;
139
140                                 memset(&t, 0, sizeof(t));
141
142                                 if (sscanf(text, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
143                                            &t.tm_hour, &t.tm_min, &t.tm_sec) == 6)
144                                         {
145                                         t.tm_year -= 1900;
146                                         t.tm_mon -= 1;
147                                         t.tm_isdst = -1;
148                                         date = mktime(&t);
149                                         }
150                                 g_free(text);
151                                 }
152                         exif_free_fd(cl->fd, exif);
153                         }
154
155                 cl->cd->date = date;
156                 cl->cd->have_date = TRUE;
157
158                 cl->done_mask |= CACHE_LOADER_DATE;
159                 cl->todo_mask &= ~CACHE_LOADER_DATE;
160                 }
161         else
162                 {
163                 /* done, save then call done function */
164                 if (options->thumbnails.enable_caching &&
165                     cl->done_mask != CACHE_LOADER_NONE)
166                         {
167                         gchar *base;
168                         mode_t mode = 0755;
169
170                         base = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, FALSE, &mode);
171                         if (cache_ensure_dir_exists(base, mode))
172                                 {
173                                 g_free(cl->cd->path);
174                                 cl->cd->path = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, TRUE, NULL);
175                                 if (cache_sim_data_save(cl->cd))
176                                         {
177                                         filetime_set(cl->cd->path, filetime(cl->fd->path));
178                                         }
179                                 }
180                         g_free(base);
181                         }
182
183                 cl->idle_id = -1;
184
185                 if (cl->done_func)
186                         {
187                         cl->done_func(cl, cl->error, cl->done_data);
188                         }
189
190                 return FALSE;
191                 }
192
193         return TRUE;
194 }
195
196 static gboolean cache_loader_idle_cb(gpointer data)
197 {
198         CacheLoader *cl = data;
199
200         return cache_loader_process(cl);
201 }
202
203 CacheLoader *cache_loader_new(FileData *fd, CacheDataType load_mask,
204                               CacheLoaderDoneFunc done_func, gpointer done_data)
205 {
206         CacheLoader *cl;
207         gchar *found;
208
209         if (!fd || !isfile(fd->path)) return NULL;
210
211         cl = g_new0(CacheLoader, 1);
212         cl->fd = file_data_ref(fd);
213
214         cl->done_func = done_func;
215         cl->done_data = done_data;
216
217         found = cache_find_location(CACHE_TYPE_SIM, cl->fd->path);
218         if (found && filetime(found) == filetime(cl->fd->path))
219                 {
220                 cl->cd = cache_sim_data_load(found);
221                 }
222         g_free(found);
223
224         if (!cl->cd) cl->cd = cache_sim_data_new();
225
226         cl->todo_mask = load_mask;
227         cl->done_mask = CACHE_LOADER_NONE;
228
229         cl->il = NULL;
230         cl->idle_id = g_idle_add(cache_loader_idle_cb, cl);
231
232         cl->error = FALSE;
233
234         return cl;
235 }
236
237 void cache_loader_free(CacheLoader *cl)
238 {
239         if (!cl) return;
240
241         if (cl->idle_id != -1)
242                 {
243                 g_source_remove(cl->idle_id);
244                 cl->idle_id = -1;
245                 }
246
247         image_loader_free(cl->il);
248         cache_sim_data_free(cl->cd);
249
250         file_data_unref(cl->fd);
251         g_free(cl);
252 }