Mercurial > geeqie.yaz
annotate src/collect-io.c @ 313:a955b7fd626b
Secure save now unlinks temporary file on error by default.
It will prevent left-behind temporary files, but also prevent
potential data recovery from partially written files (it
should not be a problem here).
author | zas_ |
---|---|
date | Fri, 11 Apr 2008 16:46:21 +0000 |
parents | 07def8e708e1 |
children | b16b9b8979e5 |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
9 | 3 * (C) 2004 John Ellis |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 | |
281 | 13 #include "main.h" |
9 | 14 #include "collect-io.h" |
15 | |
16 #include "collect.h" | |
312 | 17 #include "filelist.h" |
9 | 18 #include "layout_util.h" |
19 #include "rcfile.h" | |
312 | 20 #include "secure_save.h" |
9 | 21 #include "thumb.h" |
22 #include "ui_fileops.h" | |
23 | |
24 | |
288
d1f74154463e
Replace occurences of Geeqie / geeqie by constants defined in main.h.
zas_
parents:
283
diff
changeset
|
25 #define GQ_COLLECTION_MARKER "#" GQ_APPNAME |
9 | 26 |
283 | 27 #define GQ_COLLECTION_FAIL_MIN 300 |
28 #define GQ_COLLECTION_FAIL_PERCENT 98 | |
9 | 29 |
138 | 30 typedef struct _CollectManagerEntry CollectManagerEntry; |
9 | 31 |
32 static void collection_load_thumb_step(CollectionData *cd); | |
138 | 33 static gint collection_save_private(CollectionData *cd, const gchar *path); |
34 | |
35 static CollectManagerEntry *collect_manager_get_entry(const gchar *path); | |
36 static void collect_manager_entry_reset(CollectManagerEntry *entry); | |
235 | 37 static gint collect_manager_process_action(CollectManagerEntry *entry, gchar **path_ptr); |
9 | 38 |
39 | |
40 static gint scan_geometry(gchar *buffer, gint *x, gint *y, gint *w, gint *h) | |
41 { | |
42 gint nx, ny, nw, nh; | |
43 | |
44 if(sscanf(buffer, "%d %d %d %d", &nx, &ny, &nw, &nh) != 4) return FALSE; | |
45 | |
46 *x = nx; | |
47 *y = ny; | |
48 *w = nw; | |
49 *h = nh; | |
50 | |
51 return TRUE; | |
52 } | |
53 | |
54 static gint collection_load_private(CollectionData *cd, const gchar *path, gint append, gint flush) | |
55 { | |
56 gchar s_buf[2048]; | |
57 FILE *f; | |
58 gchar *pathl; | |
59 gint official = FALSE; | |
60 gint success = TRUE; | |
61 guint total = 0; | |
62 guint fail = 0; | |
138 | 63 gboolean changed = FALSE; |
64 CollectManagerEntry *entry = NULL; | |
9 | 65 |
66 collection_load_stop(cd); | |
67 | |
138 | 68 if (flush) |
69 collect_manager_flush(); | |
70 else | |
71 entry = collect_manager_get_entry(path); | |
9 | 72 |
73 if (!append) | |
74 { | |
75 collection_list_free(cd->list); | |
76 cd->list = NULL; | |
77 } | |
78 | |
79 if (!path && !cd->path) return FALSE; | |
80 | |
81 if (!path) path = cd->path; | |
82 | |
83 /* load it */ | |
84 pathl = path_from_utf8(path); | |
85 f = fopen(pathl, "r"); | |
86 g_free(pathl); | |
87 if (!f) | |
88 { | |
89 printf("Failed to open collection file: \"%s\"\n", path); | |
90 return FALSE; | |
91 } | |
92 | |
93 while (fgets(s_buf, sizeof(s_buf), f)) | |
94 { | |
95 gchar *buf; | |
96 if (s_buf[0]=='#') | |
97 { | |
283 | 98 if (strncasecmp(s_buf, GQ_COLLECTION_MARKER, strlen(GQ_COLLECTION_MARKER)) == 0) |
9 | 99 { |
100 /* Looks like an official collection, allow unchecked input. | |
101 * All this does is allow adding files that may not exist, | |
102 * which is needed for the collection manager to work. | |
103 * Also unofficial files abort after too many invalid entries. | |
104 */ | |
105 official = TRUE; | |
106 } | |
107 else if (strncmp(s_buf, "#geometry:", 10 ) == 0 && | |
108 scan_geometry(s_buf + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h) ) | |
109 { | |
110 cd->window_read = TRUE; | |
111 } | |
112 continue; | |
113 } | |
114 if (s_buf[0]=='\n') continue; | |
115 | |
217 | 116 buf = quoted_value(s_buf, NULL); |
9 | 117 if (buf) |
118 { | |
119 gint valid; | |
138 | 120 |
121 if (!flush) | |
122 changed |= collect_manager_process_action(entry, &buf); | |
123 | |
124 valid = (buf[0] == '/' && collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE)); | |
9 | 125 g_free(buf); |
126 | |
127 total++; | |
128 if (!valid && !official) | |
129 { | |
130 fail++; | |
283 | 131 if (fail > GQ_COLLECTION_FAIL_MIN && |
132 fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) | |
9 | 133 { |
134 printf("Too many invalid filenames in unoffical collection file, closing: %s\n", path); | |
135 success = FALSE; | |
136 break; | |
137 } | |
138 } | |
139 } | |
140 } | |
141 | |
142 fclose(f); | |
138 | 143 |
144 if (!flush) | |
145 { | |
146 gchar *buf = NULL; | |
147 while (collect_manager_process_action(entry, &buf)) | |
148 { | |
149 collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE); | |
150 changed = TRUE; | |
151 g_free(buf); | |
152 } | |
153 } | |
9 | 154 |
155 cd->list = collection_list_sort(cd->list, cd->sort_method); | |
138 | 156 |
157 if (!flush && changed && success) | |
158 collection_save_private(cd, path); | |
159 | |
160 if (!flush) | |
161 collect_manager_entry_reset(entry); | |
162 | |
9 | 163 if (!append) cd->changed = FALSE; |
164 | |
165 return success; | |
166 } | |
167 | |
168 gint collection_load(CollectionData *cd, const gchar *path, gint append) | |
169 { | |
170 if (collection_load_private(cd, path, append, TRUE)) | |
171 { | |
172 layout_recent_add_path(cd->path); | |
173 return TRUE; | |
174 } | |
175 | |
176 return FALSE; | |
177 } | |
178 | |
179 static void collection_load_thumb_do(CollectionData *cd) | |
180 { | |
181 GdkPixbuf *pixbuf; | |
182 | |
183 if (!cd->thumb_loader || !g_list_find(cd->list, cd->thumb_info)) return; | |
184 | |
185 pixbuf = thumb_loader_get_pixbuf(cd->thumb_loader, TRUE); | |
186 collection_info_set_thumb(cd->thumb_info, pixbuf); | |
187 g_object_unref(pixbuf); | |
188 | |
189 if (cd->info_updated_func) cd->info_updated_func(cd, cd->thumb_info, cd->info_updated_data); | |
190 } | |
191 | |
192 static void collection_load_thumb_error_cb(ThumbLoader *tl, gpointer data) | |
193 { | |
194 CollectionData *cd = data; | |
195 | |
196 collection_load_thumb_do(cd); | |
197 collection_load_thumb_step(cd); | |
198 } | |
199 | |
200 static void collection_load_thumb_done_cb(ThumbLoader *tl, gpointer data) | |
201 { | |
202 CollectionData *cd = data; | |
203 | |
204 collection_load_thumb_do(cd); | |
205 collection_load_thumb_step(cd); | |
206 } | |
207 | |
208 static void collection_load_thumb_step(CollectionData *cd) | |
209 { | |
210 GList *work; | |
211 CollectInfo *ci; | |
212 | |
213 if (!cd->list) | |
214 { | |
215 collection_load_stop(cd); | |
216 return; | |
217 } | |
218 | |
219 work = cd->list; | |
220 ci = work->data; | |
221 work = work->next; | |
222 /* find first unloaded thumb */ | |
223 while (work && ci->pixbuf) | |
224 { | |
225 ci = work->data; | |
226 work = work->next; | |
227 } | |
228 | |
229 if (!ci || ci->pixbuf) | |
230 { | |
231 /* done */ | |
232 collection_load_stop(cd); | |
233 | |
234 /* send a NULL CollectInfo to notify end */ | |
235 if (cd->info_updated_func) cd->info_updated_func(cd, NULL, cd->info_updated_data); | |
236 | |
237 return; | |
238 } | |
239 | |
240 /* setup loader and call it */ | |
241 cd->thumb_info = ci; | |
242 thumb_loader_free(cd->thumb_loader); | |
243 cd->thumb_loader = thumb_loader_new(thumb_max_width, thumb_max_height); | |
244 thumb_loader_set_callbacks(cd->thumb_loader, | |
245 collection_load_thumb_done_cb, | |
246 collection_load_thumb_error_cb, | |
247 NULL, | |
248 cd); | |
249 | |
250 /* start it */ | |
138 | 251 if (!thumb_loader_start(cd->thumb_loader, ci->fd->path)) |
9 | 252 { |
253 /* error, handle it, do next */ | |
138 | 254 if (debug) printf("error loading thumb for %s\n", ci->fd->path); |
9 | 255 collection_load_thumb_do(cd); |
256 collection_load_thumb_step(cd); | |
257 } | |
258 } | |
259 | |
260 void collection_load_thumb_idle(CollectionData *cd) | |
261 { | |
262 if (!cd->thumb_loader) collection_load_thumb_step(cd); | |
263 } | |
264 | |
265 gint collection_load_begin(CollectionData *cd, const gchar *path, gint append) | |
266 { | |
267 if (!collection_load(cd, path, append)) return FALSE; | |
268 | |
269 collection_load_thumb_idle(cd); | |
270 | |
271 return TRUE; | |
272 } | |
273 | |
274 void collection_load_stop(CollectionData *cd) | |
275 { | |
276 if (!cd->thumb_loader) return; | |
277 | |
278 thumb_loader_free(cd->thumb_loader); | |
279 cd->thumb_loader = NULL; | |
280 } | |
281 | |
282 static gint collection_save_private(CollectionData *cd, const gchar *path) | |
283 { | |
312 | 284 SecureSaveInfo *ssi; |
9 | 285 GList *work; |
286 gchar *pathl; | |
287 | |
288 if (!path && !cd->path) return FALSE; | |
289 | |
290 if (!path) | |
291 { | |
292 path = cd->path; | |
293 } | |
294 | |
295 | |
312 | 296 pathl = path_from_utf8(path); |
297 ssi = secure_open(pathl); | |
9 | 298 g_free(pathl); |
312 | 299 if (!ssi) |
300 { | |
301 gchar *buf; | |
9 | 302 |
312 | 303 buf = g_strdup_printf(_("failed to open collection (write) \"%s\"\n"), path); |
304 print_term(buf); | |
305 g_free(buf); | |
9 | 306 return FALSE; |
307 } | |
308 | |
312 | 309 secure_fprintf(ssi, "%s collection\n", GQ_COLLECTION_MARKER); |
310 secure_fprintf(ssi, "#created with %s version %s\n", GQ_APPNAME, VERSION); | |
9 | 311 |
312 collection_update_geometry(cd); | |
313 if (cd->window_read) | |
314 { | |
312 | 315 secure_fprintf(ssi, "#geometry: %d %d %d %d\n", cd->window_x, cd->window_y, cd->window_w, cd->window_h); |
9 | 316 } |
317 | |
318 work = cd->list; | |
312 | 319 while (work && secsave_errno == SS_ERR_NONE) |
9 | 320 { |
321 CollectInfo *ci = work->data; | |
312 | 322 secure_fprintf(ssi, "\"%s\"\n", ci->fd->path); |
9 | 323 work = work->next; |
324 } | |
325 | |
312 | 326 secure_fprintf(ssi, "#end\n"); |
9 | 327 |
312 | 328 if (secure_close(ssi)) |
9 | 329 { |
312 | 330 gchar *buf; |
331 | |
332 buf = g_strdup_printf(_("error saving collection file: %s\nerror: %s\n"), path, | |
333 secsave_strerror(secsave_errno)); | |
334 print_term(buf); | |
335 g_free(buf); | |
9 | 336 return FALSE; |
337 } | |
338 | |
339 if (!cd->path || strcmp(path, cd->path) != 0) | |
340 { | |
341 gchar *buf = cd->path; | |
342 cd->path = g_strdup(path); | |
343 path = cd->path; | |
344 g_free(buf); | |
345 | |
346 g_free(cd->name); | |
347 cd->name = g_strdup(filename_from_path(cd->path)); | |
348 | |
349 collection_path_changed(cd); | |
350 } | |
351 | |
352 cd->changed = FALSE; | |
353 | |
354 return TRUE; | |
355 } | |
356 | |
357 gint collection_save(CollectionData *cd, const gchar *path) | |
358 { | |
359 if (collection_save_private(cd, path)) | |
360 { | |
361 layout_recent_add_path(cd->path); | |
362 return TRUE; | |
363 } | |
364 | |
365 return FALSE; | |
366 } | |
367 | |
368 gint collection_load_only_geometry(CollectionData *cd, const gchar *path) | |
369 { | |
370 gchar s_buf[2048]; | |
371 FILE *f; | |
372 gchar *pathl; | |
373 | |
374 if (!path && !cd->path) return FALSE; | |
375 | |
376 if (!path) path = cd->path; | |
377 | |
378 /* load it */ | |
379 pathl = path_from_utf8(path); | |
380 f = fopen(pathl, "r"); | |
381 g_free(pathl); | |
382 if (!f) return FALSE; | |
383 | |
384 while (fgets(s_buf, sizeof(s_buf), f)) | |
385 { | |
386 if (s_buf[0]=='#' && | |
387 strncmp(s_buf, "#geometry:", 10 ) == 0 && | |
388 scan_geometry(s_buf + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h) ) | |
389 { | |
390 cd->window_read = TRUE; | |
391 fclose(f); | |
392 return TRUE; | |
393 } | |
394 } | |
395 fclose(f); | |
396 return FALSE; | |
397 } | |
398 | |
399 | |
400 /* | |
401 *------------------------------------------------------------------- | |
402 * collection manager | |
403 *------------------------------------------------------------------- | |
404 */ | |
405 | |
406 #define COLLECT_MANAGER_ACTIONS_PER_IDLE 1000 | |
407 #define COLLECT_MANAGER_FLUSH_DELAY 10000 | |
408 | |
409 struct _CollectManagerEntry | |
410 { | |
411 gchar *path; | |
138 | 412 GList *add_list; |
413 GHashTable *oldpath_hash; | |
414 GHashTable *newpath_hash; | |
415 gboolean empty; | |
9 | 416 }; |
417 | |
418 typedef enum { | |
419 COLLECTION_MANAGER_UPDATE, | |
420 COLLECTION_MANAGER_ADD, | |
421 COLLECTION_MANAGER_REMOVE | |
422 } CollectManagerType; | |
423 | |
424 typedef struct _CollectManagerAction CollectManagerAction; | |
425 struct _CollectManagerAction | |
426 { | |
427 gchar *oldpath; | |
428 gchar *newpath; | |
429 | |
430 CollectManagerType type; | |
431 | |
432 gint ref; | |
433 }; | |
434 | |
435 | |
436 static GList *collection_manager_entry_list = NULL; | |
437 static GList *collection_manager_action_list = NULL; | |
438 static GList *collection_manager_action_tail = NULL; | |
439 static gint collection_manager_timer_id = -1; | |
440 | |
441 | |
442 static CollectManagerAction *collect_manager_action_new(const gchar *oldpath, const gchar *newpath, | |
443 CollectManagerType type) | |
444 { | |
445 CollectManagerAction *action; | |
446 | |
447 action = g_new0(CollectManagerAction, 1); | |
448 action->ref = 1; | |
449 | |
450 action->oldpath = g_strdup(oldpath); | |
451 action->newpath = g_strdup(newpath); | |
452 | |
453 action->type = type; | |
454 | |
455 return action; | |
456 } | |
457 | |
458 static void collect_manager_action_ref(CollectManagerAction *action) | |
459 { | |
460 action->ref++; | |
461 } | |
462 | |
463 static void collect_manager_action_unref(CollectManagerAction *action) | |
464 { | |
465 action->ref--; | |
466 | |
467 if (action->ref > 0) return; | |
468 | |
469 g_free(action->oldpath); | |
470 g_free(action->newpath); | |
471 g_free(action); | |
472 } | |
473 | |
138 | 474 static void collect_manager_entry_free_data(CollectManagerEntry *entry) |
9 | 475 { |
476 GList *work; | |
477 | |
138 | 478 work = entry->add_list; |
9 | 479 while (work) |
480 { | |
481 CollectManagerAction *action; | |
482 | |
483 action = work->data; | |
484 work = work->next; | |
485 | |
486 collect_manager_action_unref(action); | |
487 } | |
138 | 488 g_list_free(entry->add_list); |
489 g_hash_table_destroy(entry->oldpath_hash); | |
490 g_hash_table_destroy(entry->newpath_hash); | |
491 } | |
492 | |
493 static void collect_manager_entry_init_data(CollectManagerEntry *entry) | |
494 { | |
495 entry->add_list = NULL; | |
496 entry->oldpath_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) collect_manager_action_unref); | |
497 entry->newpath_hash = g_hash_table_new(g_str_hash, g_str_equal); | |
498 entry->empty = TRUE; | |
499 | |
500 } | |
501 | |
502 static CollectManagerEntry *collect_manager_entry_new(const gchar *path) | |
503 { | |
504 CollectManagerEntry *entry; | |
505 | |
506 entry = g_new0(CollectManagerEntry, 1); | |
507 entry->path = g_strdup(path); | |
508 collect_manager_entry_init_data(entry); | |
509 | |
510 collection_manager_entry_list = g_list_append(collection_manager_entry_list, entry); | |
511 | |
512 return entry; | |
513 } | |
514 | |
515 | |
516 static void collect_manager_entry_free(CollectManagerEntry *entry) | |
517 { | |
518 collection_manager_entry_list = g_list_remove(collection_manager_entry_list, entry); | |
519 | |
520 collect_manager_entry_free_data(entry); | |
9 | 521 |
522 g_free(entry->path); | |
523 g_free(entry); | |
524 } | |
525 | |
138 | 526 static void collect_manager_entry_reset(CollectManagerEntry *entry) |
527 { | |
528 collect_manager_entry_free_data(entry); | |
529 collect_manager_entry_init_data(entry); | |
530 } | |
531 | |
532 static CollectManagerEntry *collect_manager_get_entry(const gchar *path) | |
533 { | |
534 GList *work; | |
535 | |
536 work = collection_manager_entry_list; | |
537 while (work) | |
538 { | |
539 CollectManagerEntry *entry; | |
540 | |
541 entry = work->data; | |
542 work = work->next; | |
543 if (strcmp(entry->path, path) == 0) | |
544 { | |
545 return entry; | |
546 } | |
547 } | |
548 return NULL; | |
549 | |
550 } | |
551 | |
552 static void collect_manager_entry_add_action(CollectManagerEntry *entry, CollectManagerAction *action) | |
553 { | |
554 | |
555 CollectManagerAction *orig_action; | |
556 | |
557 entry->empty = FALSE; | |
558 | |
559 if (action->oldpath == NULL) | |
560 { | |
561 /* add file */ | |
562 if (action->newpath == NULL) | |
563 { | |
564 return; | |
565 } | |
566 | |
567 orig_action = g_hash_table_lookup(entry->newpath_hash, action->newpath); | |
568 if (orig_action) | |
569 { | |
570 /* target already exists */ | |
571 printf("collection manager failed to add another action for target %s in collection %s\n", | |
572 action->newpath, entry->path); | |
573 return; | |
574 } | |
575 entry->add_list = g_list_append(entry->add_list, action); | |
576 g_hash_table_insert(entry->newpath_hash, action->newpath, action); | |
577 collect_manager_action_ref(action); | |
578 return; | |
579 } | |
580 | |
581 orig_action = g_hash_table_lookup(entry->newpath_hash, action->oldpath); | |
582 if (orig_action) | |
583 { | |
584 /* new action with the same file */ | |
585 CollectManagerAction *new_action = collect_manager_action_new(orig_action->oldpath, action->newpath, action->type); | |
586 | |
587 if (new_action->oldpath) | |
588 { | |
589 g_hash_table_steal(entry->oldpath_hash, orig_action->oldpath); | |
590 g_hash_table_insert(entry->oldpath_hash, new_action->oldpath, new_action); | |
591 } | |
592 else | |
593 { | |
594 GList *work = g_list_find(entry->add_list, orig_action); | |
595 work->data = new_action; | |
596 } | |
597 | |
598 g_hash_table_steal(entry->newpath_hash, orig_action->newpath); | |
599 if (new_action->newpath) | |
600 { | |
601 g_hash_table_insert(entry->newpath_hash, new_action->newpath, new_action); | |
602 } | |
603 collect_manager_action_unref(orig_action); | |
604 return; | |
605 } | |
606 | |
607 | |
608 orig_action = g_hash_table_lookup(entry->oldpath_hash, action->oldpath); | |
609 if (orig_action) | |
610 { | |
611 /* another action for the same source, ignore */ | |
612 printf("collection manager failed to add another action for source %s in collection %s\n", | |
613 action->oldpath, entry->path); | |
614 return; | |
615 } | |
616 | |
617 g_hash_table_insert(entry->oldpath_hash, action->oldpath, action); | |
618 if (action->newpath) | |
619 { | |
620 g_hash_table_insert(entry->newpath_hash, action->newpath, action); | |
621 } | |
622 collect_manager_action_ref(action); | |
623 } | |
624 | |
235 | 625 static gint collect_manager_process_action(CollectManagerEntry *entry, gchar **path_ptr) |
138 | 626 { |
627 gchar *path = *path_ptr; | |
628 CollectManagerAction *action; | |
629 | |
630 if (path == NULL) | |
631 { | |
632 /* get new files */ | |
633 if (entry->add_list) | |
634 { | |
635 action = entry->add_list->data; | |
636 g_assert(action->oldpath == NULL); | |
637 entry->add_list = g_list_remove(entry->add_list, action); | |
638 path = g_strdup(action->newpath); | |
639 g_hash_table_remove(entry->newpath_hash, path); | |
640 collect_manager_action_unref(action); | |
641 } | |
642 *path_ptr = path; | |
643 return (path != NULL); | |
644 } | |
645 | |
646 action = g_hash_table_lookup(entry->oldpath_hash, path); | |
647 | |
648 if (action) | |
649 { | |
650 g_free(path); | |
651 path = g_strdup(action->newpath); | |
652 *path_ptr = path; | |
653 return TRUE; | |
654 } | |
655 | |
656 return FALSE; /* no change */ | |
657 } | |
658 | |
9 | 659 static void collect_manager_refresh(void) |
660 { | |
661 GList *list = NULL; | |
662 GList *work; | |
663 gchar *base; | |
664 | |
283 | 665 base = g_strconcat(homedir(), "/", GQ_RC_DIR_COLLECTIONS, NULL); |
9 | 666 path_list(base, &list, NULL); |
667 g_free(base); | |
668 | |
669 work = collection_manager_entry_list; | |
670 while (work && list) | |
671 { | |
672 CollectManagerEntry *entry; | |
673 GList *list_step; | |
674 | |
675 entry = work->data; | |
676 work = work->next; | |
677 | |
678 list_step = list; | |
679 while (list_step && entry) | |
680 { | |
681 gchar *path; | |
682 | |
683 path = list_step->data; | |
684 list_step = list_step->next; | |
685 | |
686 if (strcmp(path, entry->path) == 0) | |
687 { | |
688 list = g_list_remove(list, path); | |
689 g_free(path); | |
690 | |
691 entry = NULL; | |
692 } | |
693 else | |
694 { | |
695 collect_manager_entry_free(entry); | |
696 } | |
697 } | |
698 } | |
699 | |
700 work = list; | |
701 while (work) | |
702 { | |
703 gchar *path; | |
704 | |
705 path = work->data; | |
706 work = work->next; | |
707 | |
708 collect_manager_entry_new(path); | |
709 g_free(path); | |
710 } | |
711 | |
712 g_list_free(list); | |
713 } | |
714 | |
715 static void collect_manager_process_actions(gint max) | |
716 { | |
717 if (debug && collection_manager_action_list) | |
718 { | |
719 printf("collection manager processing actions\n"); | |
720 } | |
721 | |
722 while (collection_manager_action_list != NULL && max > 0) | |
723 { | |
724 CollectManagerAction *action; | |
725 GList *work; | |
726 | |
727 action = collection_manager_action_list->data; | |
728 work = collection_manager_entry_list; | |
729 while (work) | |
730 { | |
731 CollectManagerEntry *entry; | |
732 | |
733 entry = work->data; | |
734 work = work->next; | |
735 | |
736 if (action->type == COLLECTION_MANAGER_UPDATE) | |
737 { | |
138 | 738 collect_manager_entry_add_action(entry, action); |
9 | 739 } |
740 else if (action->oldpath && action->newpath && | |
741 strcmp(action->newpath, entry->path) == 0) | |
742 { | |
743 /* convert action to standard add format */ | |
744 g_free(action->newpath); | |
745 if (action->type == COLLECTION_MANAGER_ADD) | |
746 { | |
747 action->newpath = action->oldpath; | |
748 action->oldpath = NULL; | |
749 } | |
750 else if (action->type == COLLECTION_MANAGER_REMOVE) | |
751 { | |
752 action->newpath = NULL; | |
753 } | |
138 | 754 collect_manager_entry_add_action(entry, action); |
9 | 755 } |
756 | |
757 max--; | |
758 } | |
759 | |
760 if (action->type != COLLECTION_MANAGER_UPDATE && | |
761 action->oldpath && action->newpath) | |
762 { | |
763 printf("collection manager failed to %s %s for collection %s\n", | |
764 (action->type == COLLECTION_MANAGER_ADD) ? "add" : "remove", | |
765 action->oldpath, action->newpath); | |
766 } | |
767 | |
768 if (collection_manager_action_tail == collection_manager_action_list) | |
769 { | |
770 collection_manager_action_tail = NULL; | |
771 } | |
772 collection_manager_action_list = g_list_remove(collection_manager_action_list, action); | |
773 collect_manager_action_unref(action); | |
774 } | |
775 } | |
776 | |
777 static gint collect_manager_process_entry(CollectManagerEntry *entry) | |
778 { | |
779 CollectionData *cd; | |
780 gint success; | |
781 | |
138 | 782 if (entry->empty) return FALSE; |
9 | 783 |
784 cd = collection_new(entry->path); | |
785 success = collection_load_private(cd, entry->path, FALSE, FALSE); | |
786 | |
787 collection_unref(cd); | |
788 | |
789 return TRUE; | |
790 } | |
791 | |
792 static gint collect_manager_process_entry_list(void) | |
793 { | |
794 GList *work; | |
795 | |
796 work = collection_manager_entry_list; | |
797 while (work) | |
798 { | |
799 CollectManagerEntry *entry; | |
800 | |
801 entry = work->data; | |
802 work = work->next; | |
803 if (collect_manager_process_entry(entry)) return TRUE; | |
804 } | |
805 | |
806 return FALSE; | |
807 } | |
808 | |
138 | 809 |
810 | |
9 | 811 static gint collect_manager_process_cb(gpointer data) |
812 { | |
813 if (collection_manager_action_list) collect_manager_refresh(); | |
814 collect_manager_process_actions(COLLECT_MANAGER_ACTIONS_PER_IDLE); | |
815 if (collection_manager_action_list) return TRUE; | |
816 | |
817 if (collect_manager_process_entry_list()) return TRUE; | |
818 | |
819 if (debug) printf("collection manager is up to date\n"); | |
820 return FALSE; | |
821 } | |
822 | |
823 static gint collect_manager_timer_cb(gpointer data) | |
824 { | |
825 if (debug) printf("collection manager timer expired\n"); | |
826 | |
827 g_idle_add_full(G_PRIORITY_LOW, collect_manager_process_cb, NULL, NULL); | |
828 | |
829 collection_manager_timer_id = -1; | |
830 return FALSE; | |
831 } | |
832 | |
833 static void collect_manager_timer_push(gint stop) | |
834 { | |
835 if (collection_manager_timer_id != -1) | |
836 { | |
837 if (!stop) return; | |
838 | |
839 g_source_remove(collection_manager_timer_id); | |
840 collection_manager_timer_id = -1; | |
841 } | |
842 | |
843 if (!stop) | |
844 { | |
845 collection_manager_timer_id = g_timeout_add(COLLECT_MANAGER_FLUSH_DELAY, | |
846 collect_manager_timer_cb, NULL); | |
847 if (debug) printf("collection manager timer started\n"); | |
848 } | |
849 } | |
850 | |
851 static void collect_manager_add_action(CollectManagerAction *action) | |
852 { | |
853 if (!action) return; | |
854 | |
855 /* we keep track of the list's tail to keep this a n(1) operation */ | |
856 | |
857 if (collection_manager_action_tail) | |
858 { | |
66
ebbff299ad0d
Fri Sep 1 02:12:45 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
859 collection_manager_action_tail = g_list_append(collection_manager_action_tail, action); |
9 | 860 collection_manager_action_tail = collection_manager_action_tail->next; |
861 } | |
862 else | |
863 { | |
864 collection_manager_action_list = g_list_append(collection_manager_action_list, action); | |
865 collection_manager_action_tail = collection_manager_action_list; | |
866 } | |
867 | |
868 collect_manager_timer_push(FALSE); | |
869 } | |
870 | |
138 | 871 void collect_manager_moved(FileData *fd) |
9 | 872 { |
873 CollectManagerAction *action; | |
138 | 874 const gchar *oldpath = fd->change->source; |
875 const gchar *newpath = fd->change->dest; | |
9 | 876 |
877 action = collect_manager_action_new(oldpath, newpath, COLLECTION_MANAGER_UPDATE); | |
878 collect_manager_add_action(action); | |
879 } | |
880 | |
138 | 881 void collect_manager_add(FileData *fd, const gchar *collection) |
9 | 882 { |
883 CollectManagerAction *action; | |
884 CollectWindow *cw; | |
885 | |
138 | 886 if (!fd || !collection) return; |
9 | 887 |
888 cw = collection_window_find_by_path(collection); | |
889 if (cw) | |
890 { | |
138 | 891 if (collection_list_find(cw->cd->list, fd->path) == NULL) |
9 | 892 { |
138 | 893 collection_add(cw->cd, fd, FALSE); |
9 | 894 } |
895 return; | |
896 } | |
897 | |
138 | 898 action = collect_manager_action_new(fd->path, collection, COLLECTION_MANAGER_ADD); |
9 | 899 collect_manager_add_action(action); |
900 } | |
901 | |
138 | 902 void collect_manager_remove(FileData *fd, const gchar *collection) |
9 | 903 { |
904 CollectManagerAction *action; | |
905 CollectWindow *cw; | |
906 | |
138 | 907 if (!fd || !collection) return; |
9 | 908 |
909 cw = collection_window_find_by_path(collection); | |
910 if (cw) | |
911 { | |
138 | 912 while (collection_remove(cw->cd, fd)); |
9 | 913 return; |
914 } | |
915 | |
138 | 916 action = collect_manager_action_new(fd->path, collection, COLLECTION_MANAGER_REMOVE); |
9 | 917 collect_manager_add_action(action); |
918 } | |
919 | |
920 void collect_manager_flush(void) | |
921 { | |
922 collect_manager_timer_push(TRUE); | |
923 | |
924 if (debug) printf("collection manager flushing\n"); | |
925 while (collect_manager_process_cb(NULL)); | |
926 } | |
927 |