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