Documentation: Use G_SOURCE_CONTINUE and G_SOURCE_REMOVE
[geeqie.git] / src / cache-loader.cc
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "cache-loader.h"
24
25 #include "filedata.h"
26 #include "metadata.h"
27 #include "ui-fileops.h"
28
29
30 static gboolean cache_loader_phase2_idle_cb(gpointer data);
31
32 static void cache_loader_phase1_done_cb(ImageLoader *UNUSED(il), gpointer data)
33 {
34         CacheLoader *cl = static_cast<CacheLoader *>(data);
35
36         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
37 }
38
39 static void cache_loader_phase1_error_cb(ImageLoader *UNUSED(il), gpointer data)
40 {
41         CacheLoader *cl = static_cast<CacheLoader *>(data);
42
43         cl->error = TRUE;
44         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
45 }
46
47 static gboolean cache_loader_phase1_process(CacheLoader *cl)
48 {
49         if (cl->todo_mask & CACHE_LOADER_SIMILARITY && !cl->cd->similarity)
50                 {
51
52                 if (!cl->il && !cl->error)
53                         {
54                         cl->il = image_loader_new(cl->fd);
55                         g_signal_connect(G_OBJECT(cl->il), "error", (GCallback)cache_loader_phase1_error_cb, cl);
56                         g_signal_connect(G_OBJECT(cl->il), "done", (GCallback)cache_loader_phase1_done_cb, cl);
57                         if (image_loader_start(cl->il))
58                                 {
59                                 return G_SOURCE_REMOVE;
60                                 }
61
62                         cl->error = TRUE;
63                         }
64                 }
65
66         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
67
68         return G_SOURCE_REMOVE;
69 }
70
71 static gboolean cache_loader_phase2_process(CacheLoader *cl)
72 {
73         if (cl->todo_mask & CACHE_LOADER_SIMILARITY && !cl->cd->similarity && cl->il)
74                 {
75                 GdkPixbuf *pixbuf;
76                 pixbuf = image_loader_get_pixbuf(cl->il);
77                 if (pixbuf)
78                         {
79                         if (!cl->error)
80                                 {
81                                 ImageSimilarityData *sim;
82
83                                 sim = image_sim_new_from_pixbuf(pixbuf);
84                                 cache_sim_data_set_similarity(cl->cd, sim);
85                                 image_sim_free(sim);
86
87                                 cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_SIMILARITY);
88                                 cl->done_mask = static_cast<CacheDataType>(cl->done_mask | CACHE_LOADER_SIMILARITY);
89                                 }
90
91                         /* we have the dimensions via pixbuf */
92                         if (!cl->cd->dimensions)
93                                 {
94                                 cache_sim_data_set_dimensions(cl->cd, gdk_pixbuf_get_width(pixbuf),
95                                                                       gdk_pixbuf_get_height(pixbuf));
96                                 if (cl->todo_mask & CACHE_LOADER_DIMENSIONS)
97                                         {
98                                         cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_DIMENSIONS);
99                                         cl->done_mask = static_cast<CacheDataType>(cl->done_mask | CACHE_LOADER_DIMENSIONS);
100                                         }
101                                 }
102                         }
103
104                 image_loader_free(cl->il);
105                 cl->il = NULL;
106
107                 cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_SIMILARITY);
108                 }
109         else if (cl->todo_mask & CACHE_LOADER_DIMENSIONS &&
110                  !cl->cd->dimensions)
111                 {
112                 if (!cl->error &&
113                     image_load_dimensions(cl->fd, &cl->cd->width, &cl->cd->height))
114                         {
115                         cl->cd->dimensions = TRUE;
116                         cl->done_mask = static_cast<CacheDataType>(cl->done_mask | CACHE_LOADER_DIMENSIONS);
117                         }
118                 else
119                         {
120                         cl->error = TRUE;
121                         }
122
123                 cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_DIMENSIONS);
124                 }
125         else if (cl->todo_mask & CACHE_LOADER_MD5SUM &&
126                  !cl->cd->have_md5sum)
127                 {
128                 if (md5_get_digest_from_file_utf8(cl->fd->path, cl->cd->md5sum))
129                         {
130                         cl->cd->have_md5sum = TRUE;
131                         cl->done_mask = static_cast<CacheDataType>(cl->done_mask | CACHE_LOADER_MD5SUM);
132                         }
133                 else
134                         {
135                         cl->error = TRUE;
136                         }
137
138                 cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_MD5SUM);
139                 }
140         else if (cl->todo_mask & CACHE_LOADER_DATE &&
141                  !cl->cd->have_date)
142                 {
143                 time_t date = -1;
144                 gchar *text;
145
146                 text =  metadata_read_string(cl->fd, "Exif.Image.DateTime", METADATA_FORMATTED);
147                 if (text)
148                         {
149                         struct tm t;
150
151                         memset(&t, 0, sizeof(t));
152
153                         if (sscanf(text, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
154                                    &t.tm_hour, &t.tm_min, &t.tm_sec) == 6)
155                                 {
156                                 t.tm_year -= 1900;
157                                 t.tm_mon -= 1;
158                                 t.tm_isdst = -1;
159                                 date = mktime(&t);
160                                 }
161                         g_free(text);
162                         }
163
164                 cl->cd->date = date;
165                 cl->cd->have_date = TRUE;
166
167                 cl->done_mask = static_cast<CacheDataType>(cl->done_mask | CACHE_LOADER_DATE);
168                 cl->todo_mask = static_cast<CacheDataType>(cl->todo_mask & ~CACHE_LOADER_DATE);
169                 }
170         else
171                 {
172                 /* done, save then call done function */
173                 if (options->thumbnails.enable_caching &&
174                     cl->done_mask != CACHE_LOADER_NONE)
175                         {
176                         gchar *base;
177                         mode_t mode = 0755;
178
179                         base = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, FALSE, &mode);
180                         if (recursive_mkdir_if_not_exists(base, mode))
181                                 {
182                                 g_free(cl->cd->path);
183                                 cl->cd->path = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, TRUE, NULL);
184                                 if (cache_sim_data_save(cl->cd))
185                                         {
186                                         filetime_set(cl->cd->path, filetime(cl->fd->path));
187                                         }
188                                 }
189                         g_free(base);
190                         }
191
192                 cl->idle_id = 0;
193
194                 if (cl->done_func)
195                         {
196                         cl->done_func(cl, cl->error, cl->done_data);
197                         }
198
199                 return G_SOURCE_REMOVE;
200                 }
201
202         return G_SOURCE_CONTINUE;
203 }
204
205 static gboolean cache_loader_phase1_idle_cb(gpointer data)
206 {
207         CacheLoader *cl = static_cast<CacheLoader *>(data);
208
209         return cache_loader_phase1_process(cl);
210 }
211
212 static gboolean cache_loader_phase2_idle_cb(gpointer data)
213 {
214         CacheLoader *cl = static_cast<CacheLoader *>(data);
215
216         return cache_loader_phase2_process(cl);
217 }
218
219 CacheLoader *cache_loader_new(FileData *fd, CacheDataType load_mask,
220                               CacheLoaderDoneFunc done_func, gpointer done_data)
221 {
222         CacheLoader *cl;
223         gchar *found;
224
225         if (!fd || !isfile(fd->path)) return NULL;
226
227         cl = g_new0(CacheLoader, 1);
228         cl->fd = file_data_ref(fd);
229
230         cl->done_func = done_func;
231         cl->done_data = done_data;
232
233         found = cache_find_location(CACHE_TYPE_SIM, cl->fd->path);
234         if (found && filetime(found) == filetime(cl->fd->path))
235                 {
236                 cl->cd = cache_sim_data_load(found);
237                 }
238         g_free(found);
239
240         if (!cl->cd) cl->cd = cache_sim_data_new();
241
242         cl->todo_mask = load_mask;
243         cl->done_mask = CACHE_LOADER_NONE;
244
245         cl->il = NULL;
246         cl->idle_id = g_idle_add(cache_loader_phase1_idle_cb, cl);
247
248         cl->error = FALSE;
249
250         return cl;
251 }
252
253 void cache_loader_free(CacheLoader *cl)
254 {
255         if (!cl) return;
256
257         if (cl->idle_id)
258                 {
259                 g_source_remove_by_user_data(cl);
260                 cl->idle_id = 0;
261                 }
262
263         image_loader_free(cl->il);
264         cache_sim_data_free(cl->cd);
265
266         file_data_unref(cl->fd);
267         g_free(cl);
268 }
269 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */