Mercurial > geeqie.yaz
annotate src/filedata.c @ 896:cf21dc928122
implemented directory rename and delete operations
author | nadvornik |
---|---|
date | Sun, 20 Jul 2008 11:22:19 +0000 |
parents | 2022112583d0 |
children | 5d9c0b4e6d5f |
rev | line source |
---|---|
586 | 1 /* |
2 * Geeqie | |
3 * (C) 2006 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 | |
14 #include "main.h" | |
15 #include "filedata.h" | |
16 | |
17 #include "filefilter.h" | |
18 #include "cache.h" | |
19 #include "rcfile.h" | |
20 #include "secure_save.h" | |
21 #include "thumb_standard.h" | |
22 #include "ui_fileops.h" | |
23 | |
24 | |
785 | 25 static GHashTable *file_data_pool = NULL; |
26 | |
586 | 27 static gint sidecar_file_priority(const gchar *path); |
28 | |
29 | |
30 /* | |
31 *----------------------------------------------------------------------------- | |
32 * text conversion utils | |
33 *----------------------------------------------------------------------------- | |
34 */ | |
35 | |
36 gchar *text_from_size(gint64 size) | |
37 { | |
38 gchar *a, *b; | |
39 gchar *s, *d; | |
40 gint l, n, i; | |
41 | |
42 /* what I would like to use is printf("%'d", size) | |
43 * BUT: not supported on every libc :( | |
44 */ | |
45 if (size > G_MAXUINT) | |
46 { | |
47 /* the %lld conversion is not valid in all libcs, so use a simple work-around */ | |
48 a = g_strdup_printf("%d%09d", (guint)(size / 1000000000), (guint)(size % 1000000000)); | |
49 } | |
50 else | |
51 { | |
52 a = g_strdup_printf("%d", (guint)size); | |
53 } | |
54 l = strlen(a); | |
55 n = (l - 1)/ 3; | |
56 if (n < 1) return a; | |
57 | |
58 b = g_new(gchar, l + n + 1); | |
59 | |
60 s = a; | |
61 d = b; | |
62 i = l - n * 3; | |
63 while (*s != '\0') | |
64 { | |
65 if (i < 1) | |
66 { | |
67 i = 3; | |
68 *d = ','; | |
69 d++; | |
70 } | |
71 | |
72 *d = *s; | |
73 s++; | |
74 d++; | |
75 i--; | |
76 } | |
77 *d = '\0'; | |
78 | |
79 g_free(a); | |
80 return b; | |
81 } | |
82 | |
83 gchar *text_from_size_abrev(gint64 size) | |
84 { | |
85 if (size < (gint64)1024) | |
86 { | |
87 return g_strdup_printf(_("%d bytes"), (gint)size); | |
88 } | |
89 if (size < (gint64)1048576) | |
90 { | |
91 return g_strdup_printf(_("%.1f K"), (double)size / 1024.0); | |
92 } | |
93 if (size < (gint64)1073741824) | |
94 { | |
95 return g_strdup_printf(_("%.1f MB"), (double)size / 1048576.0); | |
96 } | |
97 | |
98 /* to avoid overflowing the double, do division in two steps */ | |
99 size /= 1048576; | |
100 return g_strdup_printf(_("%.1f GB"), (double)size / 1024.0); | |
101 } | |
102 | |
103 /* note: returned string is valid until next call to text_from_time() */ | |
104 const gchar *text_from_time(time_t t) | |
105 { | |
106 static gchar *ret = NULL; | |
107 gchar buf[128]; | |
108 gint buflen; | |
109 struct tm *btime; | |
110 GError *error = NULL; | |
111 | |
112 btime = localtime(&t); | |
113 | |
114 /* the %x warning about 2 digit years is not an error */ | |
115 buflen = strftime(buf, sizeof(buf), "%x %H:%M", btime); | |
116 if (buflen < 1) return ""; | |
117 | |
118 g_free(ret); | |
119 ret = g_locale_to_utf8(buf, buflen, NULL, NULL, &error); | |
120 if (error) | |
121 { | |
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
671
diff
changeset
|
122 log_printf("Error converting locale strftime to UTF-8: %s\n", error->message); |
586 | 123 g_error_free(error); |
124 return ""; | |
125 } | |
126 | |
127 return ret; | |
128 } | |
129 | |
130 /* | |
131 *----------------------------------------------------------------------------- | |
132 * file info struct | |
133 *----------------------------------------------------------------------------- | |
134 */ | |
135 | |
136 FileData *file_data_merge_sidecar_files(FileData *target, FileData *source); | |
137 static void file_data_check_sidecars(FileData *fd); | |
138 FileData *file_data_disconnect_sidecar_file(FileData *target, FileData *sfd); | |
139 | |
140 | |
763
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
141 void file_data_increment_version(FileData *fd) |
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
142 { |
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
143 fd->version++; |
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
144 if (fd->parent) fd->parent->version++; |
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
145 } |
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
146 |
785 | 147 static void file_data_set_collate_keys(FileData *fd) |
148 { | |
149 gchar *caseless_name; | |
150 | |
151 g_assert(g_utf8_validate(fd->name, -1, NULL)); | |
152 | |
153 caseless_name = g_utf8_casefold(fd->name, -1); | |
154 | |
155 g_free(fd->collate_key_name); | |
156 g_free(fd->collate_key_name_nocase); | |
157 | |
158 #if GLIB_CHECK_VERSION(2, 8, 0) | |
159 fd->collate_key_name = g_utf8_collate_key_for_filename(fd->name, -1); | |
160 fd->collate_key_name_nocase = g_utf8_collate_key_for_filename(caseless_name, -1); | |
161 #else | |
162 fd->collate_key_name = g_utf8_collate_key(fd->name, -1); | |
163 fd->collate_key_name_nocase = g_utf8_collate_key(caseless_name, -1); | |
164 #endif | |
165 g_free(caseless_name); | |
166 } | |
763
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
167 |
586 | 168 static void file_data_set_path(FileData *fd, const gchar *path) |
169 { | |
790 | 170 g_assert(path /* && *path*/); /* view_dir_tree uses FileData with zero length path */ |
785 | 171 g_assert(file_data_pool); |
172 | |
173 g_free(fd->path); | |
174 | |
175 if (fd->original_path) | |
176 { | |
177 g_hash_table_remove(file_data_pool, fd->original_path); | |
178 g_free(fd->original_path); | |
179 } | |
180 fd->original_path = g_strdup(path); | |
181 g_hash_table_insert(file_data_pool, fd->original_path, fd); | |
586 | 182 |
725 | 183 if (strcmp(path, G_DIR_SEPARATOR_S) == 0) |
586 | 184 { |
185 fd->path = g_strdup(path); | |
186 fd->name = fd->path; | |
187 fd->extension = fd->name + 1; | |
785 | 188 file_data_set_collate_keys(fd); |
586 | 189 return; |
190 } | |
191 | |
192 fd->path = g_strdup(path); | |
193 fd->name = filename_from_path(fd->path); | |
194 | |
195 if (strcmp(fd->name, "..") == 0) | |
196 { | |
197 gchar *dir = remove_level_from_path(path); | |
198 g_free(fd->path); | |
199 fd->path = remove_level_from_path(dir); | |
200 g_free(dir); | |
201 fd->name = ".."; | |
202 fd->extension = fd->name + 2; | |
785 | 203 file_data_set_collate_keys(fd); |
586 | 204 return; |
205 } | |
206 else if (strcmp(fd->name, ".") == 0) | |
207 { | |
208 g_free(fd->path); | |
209 fd->path = remove_level_from_path(path); | |
210 fd->name = "."; | |
211 fd->extension = fd->name + 1; | |
785 | 212 file_data_set_collate_keys(fd); |
586 | 213 return; |
214 } | |
215 | |
216 fd->extension = extension_from_path(fd->path); | |
217 if (fd->extension == NULL) | |
218 fd->extension = fd->name + strlen(fd->name); | |
785 | 219 |
220 file_data_set_collate_keys(fd); | |
586 | 221 } |
222 | |
801 | 223 static gboolean file_data_check_changed_files_recursive(FileData *fd, struct stat *st) |
586 | 224 { |
801 | 225 gboolean ret = FALSE; |
586 | 226 GList *work; |
806 | 227 |
586 | 228 if (fd->size != st->st_size || |
229 fd->date != st->st_mtime) | |
230 { | |
231 fd->size = st->st_size; | |
232 fd->date = st->st_mtime; | |
845 | 233 if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf); |
234 fd->thumb_pixbuf = NULL; | |
763
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
235 file_data_increment_version(fd); |
800 | 236 file_data_send_notification(fd, NOTIFY_TYPE_REREAD); |
801 | 237 ret = TRUE; |
586 | 238 } |
239 | |
240 work = fd->sidecar_files; | |
241 while (work) | |
242 { | |
243 FileData *sfd = work->data; | |
244 struct stat st; | |
801 | 245 work = work->next; |
586 | 246 |
247 if (!stat_utf8(sfd->path, &st)) | |
248 { | |
801 | 249 fd->size = 0; |
250 fd->date = 0; | |
586 | 251 file_data_disconnect_sidecar_file(fd, sfd); |
801 | 252 ret = TRUE; |
253 continue; | |
586 | 254 } |
255 | |
801 | 256 ret |= file_data_check_changed_files_recursive(sfd, &st); |
586 | 257 } |
801 | 258 return ret; |
259 } | |
260 | |
261 | |
888 | 262 gboolean file_data_check_changed_files(FileData *fd) |
801 | 263 { |
264 gboolean ret = FALSE; | |
265 struct stat st; | |
806 | 266 |
801 | 267 if (fd->parent) fd = fd->parent; |
268 | |
269 if (!stat_utf8(fd->path, &st)) | |
270 { | |
806 | 271 GList *work; |
272 FileData *sfd = NULL; | |
273 | |
801 | 274 /* parent is missing, we have to rebuild whole group */ |
275 ret = TRUE; | |
276 fd->size = 0; | |
277 fd->date = 0; | |
806 | 278 |
279 work = fd->sidecar_files; | |
801 | 280 while (work) |
281 { | |
282 sfd = work->data; | |
283 work = work->next; | |
284 | |
285 file_data_disconnect_sidecar_file(fd, sfd); | |
286 } | |
287 if (sfd) file_data_check_sidecars(sfd); /* this will group the sidecars back together */ | |
288 file_data_send_notification(fd, NOTIFY_TYPE_REREAD); | |
289 } | |
806 | 290 else |
291 { | |
801 | 292 ret |= file_data_check_changed_files_recursive(fd, &st); |
806 | 293 } |
294 | |
801 | 295 return ret; |
586 | 296 } |
297 | |
298 static FileData *file_data_new(const gchar *path_utf8, struct stat *st, gboolean check_sidecars) | |
299 { | |
300 FileData *fd; | |
301 | |
302 DEBUG_2("file_data_new: '%s' %d", path_utf8, check_sidecars); | |
303 | |
304 if (!file_data_pool) | |
305 file_data_pool = g_hash_table_new(g_str_hash, g_str_equal); | |
306 | |
307 fd = g_hash_table_lookup(file_data_pool, path_utf8); | |
308 if (fd) | |
309 { | |
801 | 310 gboolean changed; |
892
2022112583d0
increase reference count before sending notification in file_data_new
nadvornik
parents:
888
diff
changeset
|
311 |
2022112583d0
increase reference count before sending notification in file_data_new
nadvornik
parents:
888
diff
changeset
|
312 file_data_ref(fd); |
806 | 313 |
801 | 314 if (fd->parent) |
315 changed = file_data_check_changed_files(fd); | |
316 else | |
317 changed = file_data_check_changed_files_recursive(fd, st); | |
318 if (changed && check_sidecars && sidecar_file_priority(fd->extension)) | |
319 file_data_check_sidecars(fd); | |
320 DEBUG_2("file_data_pool hit: '%s' %s", fd->path, changed ? "(changed)" : ""); | |
806 | 321 |
892
2022112583d0
increase reference count before sending notification in file_data_new
nadvornik
parents:
888
diff
changeset
|
322 return fd; |
586 | 323 } |
324 | |
325 fd = g_new0(FileData, 1); | |
785 | 326 |
327 fd->path = NULL; | |
328 fd->name = NULL; | |
329 fd->collate_key_name = NULL; | |
330 fd->collate_key_name_nocase = NULL; | |
331 fd->original_path = NULL; | |
586 | 332 |
333 fd->size = st->st_size; | |
334 fd->date = st->st_mtime; | |
845 | 335 fd->thumb_pixbuf = NULL; |
586 | 336 fd->sidecar_files = NULL; |
337 fd->ref = 1; | |
338 fd->magick = 0x12345678; | |
339 | |
785 | 340 file_data_set_path(fd, path_utf8); /* set path, name, collate_key_*, original_path */ |
586 | 341 |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
342 if (check_sidecars) |
586 | 343 file_data_check_sidecars(fd); |
785 | 344 |
586 | 345 return fd; |
346 } | |
347 | |
348 static void file_data_check_sidecars(FileData *fd) | |
349 { | |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
350 int base_len; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
351 GString *fname; |
586 | 352 FileData *parent_fd = NULL; |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
353 GList *work; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
354 |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
355 if (fd->disable_grouping || !sidecar_file_priority(fd->extension)) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
356 return; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
357 |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
358 base_len = fd->extension - fd->path; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
359 fname = g_string_new_len(fd->path, base_len); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
360 work = sidecar_ext_get_list(); |
806 | 361 |
586 | 362 while (work) |
363 { | |
364 /* check for possible sidecar files; | |
365 the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, | |
366 they have fd->ref set to 0 and file_data unref must chack and free them all together | |
367 (using fd->ref would cause loops and leaks) | |
368 */ | |
369 | |
370 FileData *new_fd; | |
806 | 371 gchar *ext = work->data; |
586 | 372 |
373 work = work->next; | |
374 | |
375 if (strcmp(ext, fd->extension) == 0) | |
376 { | |
377 new_fd = fd; /* processing the original file */ | |
378 } | |
379 else | |
380 { | |
381 struct stat nst; | |
382 g_string_truncate(fname, base_len); | |
383 g_string_append(fname, ext); | |
384 | |
385 if (!stat_utf8(fname->str, &nst)) | |
386 continue; | |
387 | |
388 new_fd = file_data_new(fname->str, &nst, FALSE); | |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
389 |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
390 if (new_fd->disable_grouping) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
391 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
392 file_data_unref(new_fd); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
393 continue; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
394 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
395 |
586 | 396 new_fd->ref--; /* do not use ref here */ |
397 } | |
398 | |
399 if (!parent_fd) | |
400 parent_fd = new_fd; /* parent is the one with the highest prio, found first */ | |
401 else | |
402 file_data_merge_sidecar_files(parent_fd, new_fd); | |
403 } | |
404 g_string_free(fname, TRUE); | |
405 } | |
406 | |
407 | |
408 static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars) | |
409 { | |
410 gchar *path_utf8 = path_to_utf8(path); | |
411 FileData *ret = file_data_new(path_utf8, st, check_sidecars); | |
806 | 412 |
586 | 413 g_free(path_utf8); |
414 return ret; | |
415 } | |
416 | |
417 FileData *file_data_new_simple(const gchar *path_utf8) | |
418 { | |
419 struct stat st; | |
420 | |
421 if (!stat_utf8(path_utf8, &st)) | |
422 { | |
423 st.st_size = 0; | |
424 st.st_mtime = 0; | |
425 } | |
426 | |
427 return file_data_new(path_utf8, &st, TRUE); | |
428 } | |
429 | |
430 FileData *file_data_add_sidecar_file(FileData *target, FileData *sfd) | |
431 { | |
432 sfd->parent = target; | |
855 | 433 if (!g_list_find(target->sidecar_files, sfd)) |
586 | 434 target->sidecar_files = g_list_prepend(target->sidecar_files, sfd); |
801 | 435 file_data_increment_version(sfd); /* increments both sfd and target */ |
586 | 436 return target; |
437 } | |
438 | |
439 | |
440 FileData *file_data_merge_sidecar_files(FileData *target, FileData *source) | |
441 { | |
442 GList *work; | |
806 | 443 |
586 | 444 file_data_add_sidecar_file(target, source); |
445 | |
446 work = source->sidecar_files; | |
447 while (work) | |
448 { | |
449 FileData *sfd = work->data; | |
450 file_data_add_sidecar_file(target, sfd); | |
451 work = work->next; | |
452 } | |
453 | |
454 g_list_free(source->sidecar_files); | |
455 source->sidecar_files = NULL; | |
456 | |
457 target->sidecar_files = filelist_sort(target->sidecar_files, SORT_NAME, TRUE); | |
806 | 458 |
586 | 459 return target; |
460 } | |
461 | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
462 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
463 FileData *file_data_ref_debug(const gchar *file, gint line, FileData *fd) |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
464 #else |
586 | 465 FileData *file_data_ref(FileData *fd) |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
466 #endif |
586 | 467 { |
468 if (fd == NULL) return NULL; | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
469 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
470 if (fd->magick != 0x12345678) |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
471 DEBUG_0("fd magick mismatch at %s:%d", file, line); |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
472 #endif |
586 | 473 g_assert(fd->magick == 0x12345678); |
474 fd->ref++; | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
475 |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
476 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
477 DEBUG_2("file_data_ref (%d): '%s' @ %s:%d", fd->ref, fd->path, file, line); |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
478 #else |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
479 DEBUG_2("file_data_ref (%d): '%s'", fd->ref, fd->path); |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
480 #endif |
586 | 481 return fd; |
482 } | |
483 | |
484 static void file_data_free(FileData *fd) | |
485 { | |
486 g_assert(fd->magick == 0x12345678); | |
487 g_assert(fd->ref == 0); | |
488 | |
489 g_hash_table_remove(file_data_pool, fd->original_path); | |
490 | |
491 g_free(fd->path); | |
492 g_free(fd->original_path); | |
785 | 493 g_free(fd->collate_key_name); |
494 g_free(fd->collate_key_name_nocase); | |
845 | 495 if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf); |
586 | 496 |
497 g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */ | |
498 | |
499 file_data_change_info_free(NULL, fd); | |
500 g_free(fd); | |
501 } | |
502 | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
503 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
504 void file_data_unref_debug(const gchar *file, gint line, FileData *fd) |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
505 #else |
586 | 506 void file_data_unref(FileData *fd) |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
507 #endif |
586 | 508 { |
509 if (fd == NULL) return; | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
510 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
511 if (fd->magick != 0x12345678) |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
512 DEBUG_0("fd magick mismatch @ %s:%d", file, line); |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
513 #endif |
586 | 514 g_assert(fd->magick == 0x12345678); |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
515 |
586 | 516 fd->ref--; |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
517 #ifdef DEBUG_FILEDATA |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
518 DEBUG_2("file_data_unref (%d): '%s' @ %s:%d", fd->ref, fd->path, file, line); |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
519 |
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
520 #else |
586 | 521 DEBUG_2("file_data_unref (%d): '%s'", fd->ref, fd->path); |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
522 #endif |
586 | 523 if (fd->ref == 0) |
524 { | |
806 | 525 GList *work; |
586 | 526 FileData *parent = fd->parent ? fd->parent : fd; |
806 | 527 |
586 | 528 if (parent->ref > 0) |
529 return; | |
530 | |
531 work = parent->sidecar_files; | |
532 while (work) | |
533 { | |
534 FileData *sfd = work->data; | |
535 if (sfd->ref > 0) | |
536 return; | |
537 work = work->next; | |
538 } | |
539 | |
540 /* none of parent/children is referenced, we can free everything */ | |
541 | |
874
fa39a4d786ad
Increase debugging info in file_data_ref() and file_data_unref().
zas_
parents:
855
diff
changeset
|
542 DEBUG_2("file_data_unref: deleting '%s', parent '%s'", fd->path, fd->parent ? parent->path : "-"); |
586 | 543 |
544 work = parent->sidecar_files; | |
545 while (work) | |
546 { | |
547 FileData *sfd = work->data; | |
548 file_data_free(sfd); | |
549 work = work->next; | |
550 } | |
551 | |
552 g_list_free(parent->sidecar_files); | |
553 parent->sidecar_files = NULL; | |
554 | |
555 file_data_free(parent); | |
556 } | |
557 } | |
558 | |
559 FileData *file_data_disconnect_sidecar_file(FileData *target, FileData *sfd) | |
560 { | |
561 sfd->parent = target; | |
562 g_assert(g_list_find(target->sidecar_files, sfd)); | |
801 | 563 |
564 file_data_increment_version(sfd); /* increments both sfd and target */ | |
586 | 565 |
566 target->sidecar_files = g_list_remove(target->sidecar_files, sfd); | |
567 sfd->parent = NULL; | |
568 | |
806 | 569 if (sfd->ref == 0) |
570 { | |
586 | 571 file_data_free(sfd); |
572 return NULL; | |
806 | 573 } |
586 | 574 |
575 return sfd; | |
576 } | |
577 | |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
578 /* disables / enables grouping for particular file, sends UPDATE notification */ |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
579 void file_data_disable_grouping(FileData *fd, gboolean disable) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
580 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
581 if (!fd->disable_grouping == !disable) return; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
582 fd->disable_grouping = !!disable; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
583 |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
584 if (disable) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
585 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
586 if (fd->parent) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
587 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
588 FileData *parent = file_data_ref(fd->parent); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
589 file_data_disconnect_sidecar_file(parent, fd); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
590 file_data_send_notification(fd, NOTIFY_TYPE_INTERNAL); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
591 file_data_send_notification(parent, NOTIFY_TYPE_INTERNAL); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
592 file_data_unref(parent); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
593 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
594 else if (fd->sidecar_files) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
595 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
596 GList *sidecar_files = filelist_copy(fd->sidecar_files); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
597 GList *work = sidecar_files; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
598 while (work) |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
599 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
600 FileData *sfd = work->data; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
601 work = work->next; |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
602 file_data_disconnect_sidecar_file(fd, sfd); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
603 file_data_send_notification(sfd, NOTIFY_TYPE_INTERNAL); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
604 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
605 file_data_send_notification(fd, NOTIFY_TYPE_INTERNAL); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
606 file_data_check_sidecars((FileData *)sidecar_files->data); /* this will group the sidecars back together */ |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
607 filelist_free(sidecar_files); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
608 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
609 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
610 else |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
611 { |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
612 file_data_check_sidecars(fd); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
613 file_data_send_notification(fd, NOTIFY_TYPE_INTERNAL); |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
614 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
615 } |
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
616 |
586 | 617 /* compare name without extension */ |
618 gint file_data_compare_name_without_ext(FileData *fd1, FileData *fd2) | |
619 { | |
620 size_t len1 = fd1->extension - fd1->name; | |
621 size_t len2 = fd2->extension - fd2->name; | |
622 | |
623 if (len1 < len2) return -1; | |
624 if (len1 > len2) return 1; | |
625 | |
785 | 626 return strncmp(fd1->name, fd2->name, len1); /* FIXME: utf8 */ |
586 | 627 } |
628 | |
629 gboolean file_data_add_change_info(FileData *fd, FileDataChangeType type, const gchar *src, const gchar *dest) | |
630 { | |
631 FileDataChangeInfo *fdci; | |
632 | |
633 if (fd->change) return FALSE; | |
634 | |
635 fdci = g_new0(FileDataChangeInfo, 1); | |
636 fdci->type = type; | |
637 | |
638 if (src) | |
639 fdci->source = g_strdup(src); | |
640 else | |
641 fdci->source = g_strdup(fd->path); | |
642 | |
643 if (dest) | |
644 fdci->dest = g_strdup(dest); | |
645 | |
646 fd->change = fdci; | |
806 | 647 |
586 | 648 return TRUE; |
649 } | |
650 | |
651 void file_data_change_info_free(FileDataChangeInfo *fdci, FileData *fd) | |
652 { | |
653 if (!fdci && fd) | |
654 fdci = fd->change; | |
655 | |
656 if (!fdci) | |
657 return; | |
658 | |
659 g_free(fdci->source); | |
660 g_free(fdci->dest); | |
661 | |
662 g_free(fdci); | |
663 | |
664 if (fd) | |
665 fd->change = NULL; | |
666 } | |
667 | |
668 | |
669 | |
670 | |
671 /* | |
672 *----------------------------------------------------------------------------- | |
673 * sidecar file info struct | |
674 *----------------------------------------------------------------------------- | |
675 */ | |
676 | |
677 | |
678 | |
679 static gint sidecar_file_priority(const gchar *path) | |
680 { | |
681 const char *extension = extension_from_path(path); | |
682 int i = 1; | |
683 GList *work; | |
806 | 684 |
586 | 685 if (extension == NULL) |
686 return 0; | |
687 | |
688 work = sidecar_ext_get_list(); | |
689 | |
690 while (work) { | |
691 gchar *ext = work->data; | |
806 | 692 |
586 | 693 work = work->next; |
694 if (strcmp(extension, ext) == 0) return i; | |
695 i++; | |
696 } | |
697 return 0; | |
698 } | |
699 | |
700 | |
701 /* | |
702 *----------------------------------------------------------------------------- | |
703 * load file list | |
704 *----------------------------------------------------------------------------- | |
705 */ | |
706 | |
707 static SortType filelist_sort_method = SORT_NONE; | |
708 static gint filelist_sort_ascend = TRUE; | |
709 | |
710 | |
711 gint filelist_sort_compare_filedata(FileData *fa, FileData *fb) | |
712 { | |
713 if (!filelist_sort_ascend) | |
714 { | |
715 FileData *tmp = fa; | |
716 fa = fb; | |
717 fb = tmp; | |
718 } | |
719 | |
720 switch (filelist_sort_method) | |
721 { | |
785 | 722 case SORT_NAME: |
723 break; | |
586 | 724 case SORT_SIZE: |
725 if (fa->size < fb->size) return -1; | |
726 if (fa->size > fb->size) return 1; | |
785 | 727 /* fall back to name */ |
586 | 728 break; |
729 case SORT_TIME: | |
730 if (fa->date < fb->date) return -1; | |
731 if (fa->date > fb->date) return 1; | |
785 | 732 /* fall back to name */ |
586 | 733 break; |
734 #ifdef HAVE_STRVERSCMP | |
735 case SORT_NUMBER: | |
736 return strverscmp(fa->name, fb->name); | |
737 break; | |
738 #endif | |
739 default: | |
740 break; | |
741 } | |
785 | 742 |
743 if (options->file_sort.case_sensitive) | |
744 return strcmp(fa->collate_key_name, fb->collate_key_name); | |
745 else | |
746 return strcmp(fa->collate_key_name_nocase, fb->collate_key_name_nocase); | |
586 | 747 } |
748 | |
749 gint filelist_sort_compare_filedata_full(FileData *fa, FileData *fb, SortType method, gint ascend) | |
750 { | |
751 filelist_sort_method = method; | |
752 filelist_sort_ascend = ascend; | |
753 return filelist_sort_compare_filedata(fa, fb); | |
754 } | |
755 | |
756 static gint filelist_sort_file_cb(void *a, void *b) | |
757 { | |
758 return filelist_sort_compare_filedata(a, b); | |
759 } | |
760 | |
761 GList *filelist_sort_full(GList *list, SortType method, gint ascend, GCompareFunc cb) | |
762 { | |
763 filelist_sort_method = method; | |
764 filelist_sort_ascend = ascend; | |
765 return g_list_sort(list, cb); | |
766 } | |
767 | |
768 GList *filelist_insert_sort_full(GList *list, void *data, SortType method, gint ascend, GCompareFunc cb) | |
769 { | |
770 filelist_sort_method = method; | |
771 filelist_sort_ascend = ascend; | |
772 return g_list_insert_sorted(list, data, cb); | |
773 } | |
774 | |
775 GList *filelist_sort(GList *list, SortType method, gint ascend) | |
776 { | |
777 return filelist_sort_full(list, method, ascend, (GCompareFunc) filelist_sort_file_cb); | |
778 } | |
779 | |
780 GList *filelist_insert_sort(GList *list, FileData *fd, SortType method, gint ascend) | |
781 { | |
782 return filelist_insert_sort_full(list, fd, method, ascend, (GCompareFunc) filelist_sort_file_cb); | |
783 } | |
784 | |
785 | |
786 static GList *filelist_filter_out_sidecars(GList *flist) | |
787 { | |
788 GList *work = flist; | |
789 GList *flist_filtered = NULL; | |
790 | |
791 while (work) | |
792 { | |
793 FileData *fd = work->data; | |
806 | 794 |
586 | 795 work = work->next; |
796 if (fd->parent) /* remove fd's that are children */ | |
797 file_data_unref(fd); | |
798 else | |
799 flist_filtered = g_list_prepend(flist_filtered, fd); | |
800 } | |
801 g_list_free(flist); | |
806 | 802 |
586 | 803 return flist_filtered; |
804 } | |
805 | |
783 | 806 static gint filelist_read_real(FileData *dir_fd, GList **files, GList **dirs, gint follow_symlinks) |
586 | 807 { |
808 DIR *dp; | |
809 struct dirent *dir; | |
810 gchar *pathl; | |
779 | 811 GList *dlist = NULL; |
812 GList *flist = NULL; | |
813 int (*stat_func)(const char *path, struct stat *buf); | |
586 | 814 |
779 | 815 g_assert(files || dirs); |
816 | |
817 if (files) *files = NULL; | |
818 if (dirs) *dirs = NULL; | |
586 | 819 |
783 | 820 pathl = path_from_utf8(dir_fd->path); |
779 | 821 if (!pathl) return FALSE; |
822 | |
823 dp = opendir(pathl); | |
824 if (dp == NULL) | |
586 | 825 { |
826 g_free(pathl); | |
827 return FALSE; | |
828 } | |
829 | |
779 | 830 if (follow_symlinks) |
831 stat_func = stat; | |
832 else | |
833 stat_func = lstat; | |
834 | |
586 | 835 while ((dir = readdir(dp)) != NULL) |
836 { | |
779 | 837 struct stat ent_sbuf; |
838 const gchar *name = dir->d_name; | |
839 gchar *filepath; | |
840 | |
841 if (!options->file_filter.show_hidden_files && ishidden(name)) | |
842 continue; | |
843 | |
844 filepath = g_build_filename(pathl, name, NULL); | |
845 if (stat_func(filepath, &ent_sbuf) >= 0) | |
586 | 846 { |
779 | 847 if (S_ISDIR(ent_sbuf.st_mode)) |
586 | 848 { |
779 | 849 /* we ignore the .thumbnails dir for cleanliness */ |
850 if (dirs && | |
851 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) && | |
852 strcmp(name, GQ_CACHE_LOCAL_THUMB) != 0 && | |
853 strcmp(name, GQ_CACHE_LOCAL_METADATA) != 0 && | |
854 strcmp(name, THUMB_FOLDER_LOCAL) != 0) | |
586 | 855 { |
779 | 856 dlist = g_list_prepend(dlist, file_data_new_local(filepath, &ent_sbuf, FALSE)); |
586 | 857 } |
858 } | |
779 | 859 else |
860 { | |
861 if (files && filter_name_exists(name)) | |
862 { | |
863 flist = g_list_prepend(flist, file_data_new_local(filepath, &ent_sbuf, TRUE)); | |
864 } | |
865 } | |
586 | 866 } |
779 | 867 g_free(filepath); |
586 | 868 } |
869 | |
870 closedir(dp); | |
779 | 871 |
586 | 872 g_free(pathl); |
873 | |
874 if (dirs) *dirs = dlist; | |
779 | 875 if (files) *files = filelist_filter_out_sidecars(flist); |
586 | 876 |
877 return TRUE; | |
878 } | |
879 | |
783 | 880 gint filelist_read(FileData *dir_fd, GList **files, GList **dirs) |
586 | 881 { |
783 | 882 return filelist_read_real(dir_fd, files, dirs, TRUE); |
586 | 883 } |
884 | |
783 | 885 gint filelist_read_lstat(FileData *dir_fd, GList **files, GList **dirs) |
586 | 886 { |
783 | 887 return filelist_read_real(dir_fd, files, dirs, FALSE); |
586 | 888 } |
889 | |
890 void filelist_free(GList *list) | |
891 { | |
892 GList *work; | |
893 | |
894 work = list; | |
895 while (work) | |
896 { | |
897 file_data_unref((FileData *)work->data); | |
898 work = work->next; | |
899 } | |
900 | |
901 g_list_free(list); | |
902 } | |
903 | |
904 | |
905 GList *filelist_copy(GList *list) | |
906 { | |
907 GList *new_list = NULL; | |
908 GList *work; | |
909 | |
910 work = list; | |
911 while (work) | |
912 { | |
913 FileData *fd; | |
914 | |
915 fd = work->data; | |
916 work = work->next; | |
917 | |
918 new_list = g_list_prepend(new_list, file_data_ref(fd)); | |
919 } | |
920 | |
921 return g_list_reverse(new_list); | |
922 } | |
923 | |
924 GList *filelist_from_path_list(GList *list) | |
925 { | |
926 GList *new_list = NULL; | |
927 GList *work; | |
928 | |
929 work = list; | |
930 while (work) | |
931 { | |
932 gchar *path; | |
933 | |
934 path = work->data; | |
935 work = work->next; | |
936 | |
937 new_list = g_list_prepend(new_list, file_data_new_simple(path)); | |
938 } | |
939 | |
940 return g_list_reverse(new_list); | |
941 } | |
942 | |
943 GList *filelist_to_path_list(GList *list) | |
944 { | |
945 GList *new_list = NULL; | |
946 GList *work; | |
947 | |
948 work = list; | |
949 while (work) | |
950 { | |
951 FileData *fd; | |
952 | |
953 fd = work->data; | |
954 work = work->next; | |
955 | |
956 new_list = g_list_prepend(new_list, g_strdup(fd->path)); | |
957 } | |
958 | |
959 return g_list_reverse(new_list); | |
960 } | |
961 | |
962 GList *filelist_filter(GList *list, gint is_dir_list) | |
963 { | |
964 GList *work; | |
965 | |
966 if (!is_dir_list && options->file_filter.disable && options->file_filter.show_hidden_files) return list; | |
967 | |
968 work = list; | |
969 while (work) | |
970 { | |
971 FileData *fd = (FileData *)(work->data); | |
972 const gchar *name = fd->name; | |
973 | |
974 if ((!options->file_filter.show_hidden_files && ishidden(name)) || | |
975 (!is_dir_list && !filter_name_exists(name)) || | |
976 (is_dir_list && name[0] == '.' && (strcmp(name, GQ_CACHE_LOCAL_THUMB) == 0 || | |
977 strcmp(name, GQ_CACHE_LOCAL_METADATA) == 0)) ) | |
978 { | |
979 GList *link = work; | |
806 | 980 |
586 | 981 list = g_list_remove_link(list, link); |
982 file_data_unref(fd); | |
983 g_list_free(link); | |
984 } | |
806 | 985 |
986 work = work->next; | |
586 | 987 } |
988 | |
989 return list; | |
990 } | |
991 | |
992 /* | |
993 *----------------------------------------------------------------------------- | |
994 * filelist recursive | |
995 *----------------------------------------------------------------------------- | |
996 */ | |
997 | |
998 static gint filelist_sort_path_cb(gconstpointer a, gconstpointer b) | |
999 { | |
1000 return CASE_SORT(((FileData *)a)->path, ((FileData *)b)->path); | |
1001 } | |
1002 | |
1003 GList *filelist_sort_path(GList *list) | |
1004 { | |
1005 return g_list_sort(list, filelist_sort_path_cb); | |
1006 } | |
1007 | |
1008 static void filelist_recursive_append(GList **list, GList *dirs) | |
1009 { | |
1010 GList *work; | |
1011 | |
1012 work = dirs; | |
1013 while (work) | |
1014 { | |
1015 FileData *fd = (FileData *)(work->data); | |
780
44128da39e13
Drop initialization to NULL since filelist_read() will take care of it.
zas_
parents:
779
diff
changeset
|
1016 GList *f; |
44128da39e13
Drop initialization to NULL since filelist_read() will take care of it.
zas_
parents:
779
diff
changeset
|
1017 GList *d; |
586 | 1018 |
783 | 1019 if (filelist_read(fd, &f, &d)) |
586 | 1020 { |
1021 f = filelist_filter(f, FALSE); | |
1022 f = filelist_sort_path(f); | |
1023 *list = g_list_concat(*list, f); | |
1024 | |
1025 d = filelist_filter(d, TRUE); | |
1026 d = filelist_sort_path(d); | |
1027 filelist_recursive_append(list, d); | |
1028 filelist_free(d); | |
1029 } | |
1030 | |
1031 work = work->next; | |
1032 } | |
1033 } | |
1034 | |
783 | 1035 GList *filelist_recursive(FileData *dir_fd) |
586 | 1036 { |
780
44128da39e13
Drop initialization to NULL since filelist_read() will take care of it.
zas_
parents:
779
diff
changeset
|
1037 GList *list; |
44128da39e13
Drop initialization to NULL since filelist_read() will take care of it.
zas_
parents:
779
diff
changeset
|
1038 GList *d; |
586 | 1039 |
783 | 1040 if (!filelist_read(dir_fd, &list, &d)) return NULL; |
586 | 1041 list = filelist_filter(list, FALSE); |
1042 list = filelist_sort_path(list); | |
1043 | |
1044 d = filelist_filter(d, TRUE); | |
1045 d = filelist_sort_path(d); | |
1046 filelist_recursive_append(&list, d); | |
1047 filelist_free(d); | |
1048 | |
1049 return list; | |
1050 } | |
590 | 1051 |
1052 | |
800 | 1053 /* |
1054 * marks and orientation | |
1055 */ | |
1056 | |
1057 | |
1058 gboolean file_data_get_mark(FileData *fd, gint n) | |
1059 { | |
1060 return !!(fd->marks & (1 << n)); | |
1061 } | |
1062 | |
1063 void file_data_set_mark(FileData *fd, gint n, gboolean value) | |
1064 { | |
1065 if (!value == !(fd->marks & (1 << n))) return; | |
1066 | |
1067 fd->marks = fd->marks ^ (1 << n); | |
1068 file_data_increment_version(fd); | |
1069 file_data_send_notification(fd, NOTIFY_TYPE_INTERNAL); | |
1070 } | |
1071 | |
1072 gint file_data_get_user_orientation(FileData *fd) | |
1073 { | |
1074 return fd->user_orientation; | |
1075 } | |
1076 | |
1077 void file_data_set_user_orientation(FileData *fd, gint value) | |
1078 { | |
1079 if (fd->user_orientation == value) return; | |
1080 | |
1081 fd->user_orientation = value; | |
1082 file_data_increment_version(fd); | |
1083 file_data_send_notification(fd, NOTIFY_TYPE_INTERNAL); | |
1084 } | |
1085 | |
1086 | |
590 | 1087 |
1088 /* | |
1089 * file_data - operates on the given fd | |
1090 * file_data_sc - operates on the given fd + sidecars - all fds linked via fd->sidecar_files or fd->parent | |
1091 */ | |
1092 | |
1093 | |
1094 /* return list of sidecar file extensions in a string */ | |
596 | 1095 gchar *file_data_sc_list_to_string(FileData *fd) |
1096 { | |
1097 GList *work; | |
1098 GString *result = g_string_new(""); | |
1099 | |
1100 work = fd->sidecar_files; | |
1101 while (work) | |
1102 { | |
1103 FileData *sfd = work->data; | |
806 | 1104 |
596 | 1105 result = g_string_append(result, "+ "); |
1106 result = g_string_append(result, sfd->extension); | |
1107 work = work->next; | |
1108 if (work) result = g_string_append_c(result, ' '); | |
1109 } | |
1110 | |
1111 return g_string_free(result, FALSE); | |
1112 } | |
590 | 1113 |
1114 | |
849
db68d673448f
added possibility to disable grouping of selected files
nadvornik
parents:
846
diff
changeset
|
1115 |
590 | 1116 /* |
1117 * add FileDataChangeInfo (see typedefs.h) for the given operation | |
1118 * uses file_data_add_change_info | |
1119 * | |
1120 * fails if the fd->change already exists - change operations can't run in parallel | |
1121 * fd->change_info works as a lock | |
1122 * | |
1123 * dest can be NULL - in this case the current name is used for now, it will | |
1124 * be changed later | |
1125 */ | |
1126 | |
1127 /* | |
1128 FileDataChangeInfo types: | |
1129 COPY | |
1130 MOVE - patch is changed, name may be changed too | |
1131 RENAME - path remains unchanged, name is changed | |
1132 extension should remain (FIXME should we allow editing extension? it will make problems wth grouping) | |
1133 sidecar names are changed too, extensions are not changed | |
1134 DELETE | |
1135 UPDATE - file size, date or grouping has been changed | |
1136 */ | |
1137 | |
1138 gboolean file_data_add_ci(FileData *fd, FileDataChangeType type, const gchar *src, const gchar *dest) | |
1139 { | |
1140 FileDataChangeInfo *fdci; | |
1141 | |
1142 if (fd->change) return FALSE; | |
1143 | |
1144 fdci = g_new0(FileDataChangeInfo, 1); | |
1145 | |
1146 fdci->type = type; | |
1147 | |
1148 if (src) | |
1149 fdci->source = g_strdup(src); | |
1150 else | |
1151 fdci->source = g_strdup(fd->path); | |
1152 | |
1153 if (dest) | |
1154 fdci->dest = g_strdup(dest); | |
1155 | |
1156 fd->change = fdci; | |
1157 | |
1158 return TRUE; | |
1159 } | |
1160 | |
1161 void file_data_free_ci(FileData *fd) | |
1162 { | |
1163 FileDataChangeInfo *fdci = fd->change; | |
1164 | |
1165 if (!fdci) | |
1166 return; | |
1167 | |
1168 g_free(fdci->source); | |
1169 g_free(fdci->dest); | |
1170 | |
1171 g_free(fdci); | |
1172 | |
1173 fd->change = NULL; | |
1174 } | |
1175 | |
1176 | |
1177 static gboolean file_data_sc_add_ci(FileData *fd, FileDataChangeType type) | |
1178 { | |
1179 GList *work; | |
806 | 1180 |
590 | 1181 if (fd->parent) fd = fd->parent; |
1182 | |
1183 if (fd->change) return FALSE; | |
806 | 1184 |
590 | 1185 work = fd->sidecar_files; |
1186 while (work) | |
1187 { | |
1188 FileData *sfd = work->data; | |
806 | 1189 |
590 | 1190 if (sfd->change) return FALSE; |
1191 work = work->next; | |
1192 } | |
1193 | |
1194 file_data_add_ci(fd, type, NULL, NULL); | |
1195 | |
1196 work = fd->sidecar_files; | |
1197 while (work) | |
1198 { | |
1199 FileData *sfd = work->data; | |
806 | 1200 |
590 | 1201 file_data_add_ci(sfd, type, NULL, NULL); |
1202 work = work->next; | |
1203 } | |
1204 | |
1205 return TRUE; | |
1206 } | |
1207 | |
1208 static gboolean file_data_sc_check_ci(FileData *fd, FileDataChangeType type) | |
1209 { | |
1210 GList *work; | |
806 | 1211 |
590 | 1212 if (fd->parent) fd = fd->parent; |
1213 | |
806 | 1214 if (!fd->change || fd->change->type != type) return FALSE; |
1215 | |
590 | 1216 work = fd->sidecar_files; |
1217 while (work) | |
1218 { | |
1219 FileData *sfd = work->data; | |
806 | 1220 |
1221 if (!sfd->change || sfd->change->type != type) return FALSE; | |
590 | 1222 work = work->next; |
1223 } | |
806 | 1224 |
590 | 1225 return TRUE; |
1226 } | |
1227 | |
1228 | |
751 | 1229 gboolean file_data_sc_add_ci_copy(FileData *fd, const gchar *dest_path) |
590 | 1230 { |
1231 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_COPY)) return FALSE; | |
1232 file_data_sc_update_ci_copy(fd, dest_path); | |
1233 return TRUE; | |
1234 } | |
1235 | |
751 | 1236 gboolean file_data_sc_add_ci_move(FileData *fd, const gchar *dest_path) |
590 | 1237 { |
1238 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_MOVE)) return FALSE; | |
1239 file_data_sc_update_ci_move(fd, dest_path); | |
1240 return TRUE; | |
1241 } | |
1242 | |
751 | 1243 gboolean file_data_sc_add_ci_rename(FileData *fd, const gchar *dest_path) |
590 | 1244 { |
1245 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_RENAME)) return FALSE; | |
1246 file_data_sc_update_ci_rename(fd, dest_path); | |
1247 return TRUE; | |
1248 } | |
1249 | |
1250 gboolean file_data_sc_add_ci_delete(FileData *fd) | |
1251 { | |
1252 return file_data_sc_add_ci(fd, FILEDATA_CHANGE_DELETE); | |
1253 } | |
1254 | |
753 | 1255 gboolean file_data_sc_add_ci_unspecified(FileData *fd, const gchar *dest_path) |
590 | 1256 { |
753 | 1257 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_UNSPECIFIED)) return FALSE; |
1258 file_data_sc_update_ci_unspecified(fd, dest_path); | |
1259 return TRUE; | |
590 | 1260 } |
1261 | |
1262 void file_data_sc_free_ci(FileData *fd) | |
1263 { | |
1264 GList *work; | |
806 | 1265 |
590 | 1266 if (fd->parent) fd = fd->parent; |
1267 | |
1268 file_data_free_ci(fd); | |
1269 | |
1270 work = fd->sidecar_files; | |
1271 while (work) | |
1272 { | |
1273 FileData *sfd = work->data; | |
806 | 1274 |
590 | 1275 file_data_free_ci(sfd); |
1276 work = work->next; | |
1277 } | |
1278 } | |
1279 | |
751 | 1280 gboolean file_data_sc_add_ci_delete_list(GList *fd_list) |
1281 { | |
1282 GList *work; | |
1283 gboolean ret = TRUE; | |
806 | 1284 |
751 | 1285 work = fd_list; |
1286 while (work) | |
1287 { | |
1288 FileData *fd = work->data; | |
806 | 1289 |
751 | 1290 if (!file_data_sc_add_ci_delete(fd)) ret = FALSE; |
1291 work = work->next; | |
1292 } | |
806 | 1293 |
751 | 1294 return ret; |
1295 } | |
1296 | |
1297 gboolean file_data_sc_add_ci_copy_list(GList *fd_list, const gchar *dest) | |
1298 { | |
1299 GList *work; | |
1300 gboolean ret = TRUE; | |
806 | 1301 |
751 | 1302 work = fd_list; |
1303 while (work) | |
1304 { | |
1305 FileData *fd = work->data; | |
806 | 1306 |
751 | 1307 if (!file_data_sc_add_ci_copy(fd, dest)) ret = FALSE; |
1308 work = work->next; | |
1309 } | |
806 | 1310 |
751 | 1311 return ret; |
1312 } | |
1313 | |
1314 gboolean file_data_sc_add_ci_move_list(GList *fd_list, const gchar *dest) | |
1315 { | |
1316 GList *work; | |
1317 gboolean ret = TRUE; | |
806 | 1318 |
751 | 1319 work = fd_list; |
1320 while (work) | |
1321 { | |
1322 FileData *fd = work->data; | |
806 | 1323 |
751 | 1324 if (!file_data_sc_add_ci_move(fd, dest)) ret = FALSE; |
1325 work = work->next; | |
1326 } | |
806 | 1327 |
751 | 1328 return ret; |
1329 } | |
1330 | |
1331 gboolean file_data_sc_add_ci_rename_list(GList *fd_list, const gchar *dest) | |
1332 { | |
1333 GList *work; | |
1334 gboolean ret = TRUE; | |
806 | 1335 |
751 | 1336 work = fd_list; |
1337 while (work) | |
1338 { | |
1339 FileData *fd = work->data; | |
806 | 1340 |
751 | 1341 if (!file_data_sc_add_ci_rename(fd, dest)) ret = FALSE; |
1342 work = work->next; | |
1343 } | |
806 | 1344 |
751 | 1345 return ret; |
1346 } | |
1347 | |
753 | 1348 gboolean file_data_sc_add_ci_unspecified_list(GList *fd_list, const gchar *dest) |
1349 { | |
1350 GList *work; | |
1351 gboolean ret = TRUE; | |
806 | 1352 |
753 | 1353 work = fd_list; |
1354 while (work) | |
1355 { | |
1356 FileData *fd = work->data; | |
806 | 1357 |
753 | 1358 if (!file_data_sc_add_ci_unspecified(fd, dest)) ret = FALSE; |
1359 work = work->next; | |
1360 } | |
806 | 1361 |
753 | 1362 return ret; |
1363 } | |
1364 | |
751 | 1365 void file_data_sc_free_ci_list(GList *fd_list) |
1366 { | |
1367 GList *work; | |
806 | 1368 |
751 | 1369 work = fd_list; |
1370 while (work) | |
1371 { | |
1372 FileData *fd = work->data; | |
806 | 1373 |
751 | 1374 file_data_sc_free_ci(fd); |
1375 work = work->next; | |
1376 } | |
1377 } | |
590 | 1378 |
1379 /* | |
1380 * update existing fd->change, it will be used from dialog callbacks for interactive editing | |
1381 * fails if fd->change does not exist or the change type does not match | |
1382 */ | |
1383 | |
751 | 1384 static void file_data_update_ci_dest(FileData *fd, const gchar *dest_path) |
590 | 1385 { |
1386 g_free(fd->change->dest); | |
1387 fd->change->dest = g_strdup(dest_path); | |
1388 } | |
1389 | |
751 | 1390 static void file_data_update_ci_dest_preserve_ext(FileData *fd, const gchar *dest_path) |
590 | 1391 { |
1392 const char *extension = extension_from_path(fd->change->source); | |
751 | 1393 gchar *base = remove_extension_from_path(dest_path); |
806 | 1394 |
590 | 1395 g_free(fd->change->dest); |
751 | 1396 fd->change->dest = g_strdup_printf("%s%s", base, extension); |
806 | 1397 |
751 | 1398 g_free(base); |
590 | 1399 } |
1400 | |
751 | 1401 static void file_data_sc_update_ci(FileData *fd, const gchar *dest_path) |
590 | 1402 { |
1403 GList *work; | |
751 | 1404 gchar *dest_path_full = NULL; |
806 | 1405 |
590 | 1406 if (fd->parent) fd = fd->parent; |
1407 | |
751 | 1408 if (!dest_path) dest_path = fd->path; |
1409 | |
1410 if (!strchr(dest_path, G_DIR_SEPARATOR)) /* we got only filename, not a full path */ | |
1411 { | |
1412 gchar *dir = remove_level_from_path(fd->path); | |
806 | 1413 |
751 | 1414 dest_path_full = g_build_filename(dir, dest_path, NULL); |
1415 g_free(dir); | |
1416 dest_path = dest_path_full; | |
1417 } | |
1418 | |
1419 if (isdir(dest_path)) | |
1420 { | |
1421 dest_path_full = g_build_filename(dest_path, fd->name, NULL); | |
1422 dest_path = dest_path_full; | |
1423 } | |
806 | 1424 |
1425 file_data_update_ci_dest(fd, dest_path); | |
751 | 1426 |
590 | 1427 work = fd->sidecar_files; |
1428 while (work) | |
1429 { | |
1430 FileData *sfd = work->data; | |
806 | 1431 |
590 | 1432 file_data_update_ci_dest_preserve_ext(sfd, dest_path); |
1433 work = work->next; | |
1434 } | |
806 | 1435 |
751 | 1436 g_free(dest_path_full); |
590 | 1437 } |
1438 | |
751 | 1439 gint file_data_sc_update_ci_copy(FileData *fd, const gchar *dest_path) |
590 | 1440 { |
1441 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_COPY)) return FALSE; | |
1442 file_data_sc_update_ci(fd, dest_path); | |
1443 return TRUE; | |
1444 } | |
1445 | |
751 | 1446 gint file_data_sc_update_ci_move(FileData *fd, const gchar *dest_path) |
590 | 1447 { |
1448 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_MOVE)) return FALSE; | |
1449 file_data_sc_update_ci(fd, dest_path); | |
1450 return TRUE; | |
1451 } | |
1452 | |
751 | 1453 gint file_data_sc_update_ci_rename(FileData *fd, const gchar *dest_path) |
590 | 1454 { |
1455 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_RENAME)) return FALSE; | |
1456 file_data_sc_update_ci(fd, dest_path); | |
1457 return TRUE; | |
1458 } | |
1459 | |
753 | 1460 gint file_data_sc_update_ci_unspecified(FileData *fd, const gchar *dest_path) |
1461 { | |
1462 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_UNSPECIFIED)) return FALSE; | |
1463 file_data_sc_update_ci(fd, dest_path); | |
1464 return TRUE; | |
1465 } | |
1466 | |
590 | 1467 |
751 | 1468 gboolean file_data_sc_update_ci_move_list(GList *fd_list, const gchar *dest) |
1469 { | |
1470 GList *work; | |
1471 gboolean ret = TRUE; | |
806 | 1472 |
751 | 1473 work = fd_list; |
1474 while (work) | |
1475 { | |
1476 FileData *fd = work->data; | |
806 | 1477 |
751 | 1478 if (!file_data_sc_update_ci_move(fd, dest)) ret = FALSE; |
1479 work = work->next; | |
1480 } | |
806 | 1481 |
751 | 1482 return ret; |
1483 } | |
1484 | |
1485 gboolean file_data_sc_update_ci_copy_list(GList *fd_list, const gchar *dest) | |
1486 { | |
1487 GList *work; | |
1488 gboolean ret = TRUE; | |
806 | 1489 |
751 | 1490 work = fd_list; |
1491 while (work) | |
1492 { | |
1493 FileData *fd = work->data; | |
806 | 1494 |
751 | 1495 if (!file_data_sc_update_ci_copy(fd, dest)) ret = FALSE; |
1496 work = work->next; | |
1497 } | |
806 | 1498 |
751 | 1499 return ret; |
1500 } | |
1501 | |
753 | 1502 gboolean file_data_sc_update_ci_unspecified_list(GList *fd_list, const gchar *dest) |
1503 { | |
1504 GList *work; | |
1505 gboolean ret = TRUE; | |
806 | 1506 |
753 | 1507 work = fd_list; |
1508 while (work) | |
1509 { | |
1510 FileData *fd = work->data; | |
806 | 1511 |
753 | 1512 if (!file_data_sc_update_ci_unspecified(fd, dest)) ret = FALSE; |
1513 work = work->next; | |
1514 } | |
806 | 1515 |
753 | 1516 return ret; |
1517 } | |
1518 | |
590 | 1519 |
1520 /* | |
1521 * check dest paths - dest image exists, etc. | |
1522 * returns FIXME | |
1523 * it should detect all possible problems with the planned operation | |
1524 */ | |
1525 | |
1526 gint file_data_sc_check_ci_dest(FileData *fd) | |
1527 { | |
1528 } | |
1529 | |
1530 | |
1531 | |
1532 | |
1533 /* | |
1534 * perform the change described by FileFataChangeInfo | |
1535 * it is used for internal operations, | |
1536 * this function actually operates with files on the filesystem | |
1537 * it should implement safe delete | |
1538 */ | |
1539 | |
1540 static gboolean file_data_perform_move(FileData *fd) | |
1541 { | |
1542 g_assert(!strcmp(fd->change->source, fd->path)); | |
1543 return move_file(fd->change->source, fd->change->dest); | |
1544 } | |
1545 | |
1546 static gboolean file_data_perform_copy(FileData *fd) | |
1547 { | |
1548 g_assert(!strcmp(fd->change->source, fd->path)); | |
1549 return copy_file(fd->change->source, fd->change->dest); | |
1550 } | |
1551 | |
1552 static gboolean file_data_perform_delete(FileData *fd) | |
1553 { | |
896
cf21dc928122
implemented directory rename and delete operations
nadvornik
parents:
892
diff
changeset
|
1554 if (isdir(fd->path) && !islink(fd->path)) |
cf21dc928122
implemented directory rename and delete operations
nadvornik
parents:
892
diff
changeset
|
1555 return rmdir_utf8(fd->path); |
cf21dc928122
implemented directory rename and delete operations
nadvornik
parents:
892
diff
changeset
|
1556 else |
cf21dc928122
implemented directory rename and delete operations
nadvornik
parents:
892
diff
changeset
|
1557 return unlink_file(fd->path); |
590 | 1558 } |
1559 | |
1560 static gboolean file_data_perform_ci(FileData *fd) | |
1561 { | |
1562 FileDataChangeType type = fd->change->type; | |
1563 switch (type) | |
1564 { | |
1565 case FILEDATA_CHANGE_MOVE: | |
1566 return file_data_perform_move(fd); | |
1567 case FILEDATA_CHANGE_COPY: | |
1568 return file_data_perform_copy(fd); | |
1569 case FILEDATA_CHANGE_RENAME: | |
1570 return file_data_perform_move(fd); /* the same as move */ | |
1571 case FILEDATA_CHANGE_DELETE: | |
1572 return file_data_perform_delete(fd); | |
753 | 1573 case FILEDATA_CHANGE_UNSPECIFIED: |
596 | 1574 /* nothing to do here */ |
590 | 1575 break; |
1576 } | |
1577 return TRUE; | |
1578 } | |
1579 | |
1580 | |
1581 | |
1582 gboolean file_data_sc_perform_ci(FileData *fd) | |
1583 { | |
1584 GList *work; | |
1585 gboolean ret = TRUE; | |
1586 FileDataChangeType type = fd->change->type; | |
806 | 1587 |
590 | 1588 if (!file_data_sc_check_ci(fd, type)) return FALSE; |
1589 | |
1590 work = fd->sidecar_files; | |
1591 while (work) | |
1592 { | |
1593 FileData *sfd = work->data; | |
806 | 1594 |
590 | 1595 if (!file_data_perform_ci(sfd)) ret = FALSE; |
1596 work = work->next; | |
1597 } | |
806 | 1598 |
590 | 1599 if (!file_data_perform_ci(fd)) ret = FALSE; |
806 | 1600 |
590 | 1601 return ret; |
1602 } | |
1603 | |
1604 /* | |
1605 * updates FileData structure according to FileDataChangeInfo | |
1606 */ | |
1607 | |
1608 static void file_data_apply_ci(FileData *fd) | |
1609 { | |
1610 FileDataChangeType type = fd->change->type; | |
806 | 1611 |
590 | 1612 /* FIXME delete ?*/ |
773 | 1613 if (type == FILEDATA_CHANGE_MOVE || type == FILEDATA_CHANGE_RENAME) |
590 | 1614 { |
1615 file_data_set_path(fd, fd->change->dest); | |
1616 } | |
763
81f9e8dbb4bf
improved infrastructure for tracing changes, optimized vflist_populate_view
nadvornik
parents:
753
diff
changeset
|
1617 file_data_increment_version(fd); |
800 | 1618 file_data_send_notification(fd, NOTIFY_TYPE_CHANGE); |
590 | 1619 } |
1620 | |
596 | 1621 gint file_data_sc_apply_ci(FileData *fd) |
590 | 1622 { |
1623 GList *work; | |
1624 FileDataChangeType type = fd->change->type; | |
806 | 1625 |
590 | 1626 if (!file_data_sc_check_ci(fd, type)) return FALSE; |
1627 | |
1628 work = fd->sidecar_files; | |
1629 while (work) | |
1630 { | |
1631 FileData *sfd = work->data; | |
806 | 1632 |
590 | 1633 file_data_apply_ci(sfd); |
1634 work = work->next; | |
1635 } | |
806 | 1636 |
590 | 1637 file_data_apply_ci(fd); |
806 | 1638 |
590 | 1639 return TRUE; |
1640 } | |
1641 | |
1642 | |
1643 /* | |
1644 * notify other modules about the change described by FileFataChangeInfo | |
1645 */ | |
1646 | |
1647 /* might use file_maint_ functions for now, later it should be changed to a system of callbacks | |
1648 FIXME do we need the ignore_list? It looks like a workaround for ineffective | |
1649 implementation in view_file_list.c */ | |
1650 | |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1651 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1652 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1653 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1654 typedef struct _NotifyData NotifyData; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1655 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1656 struct _NotifyData { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1657 FileDataNotifyFunc func; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1658 gpointer data; |
791 | 1659 NotifyPriority priority; |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1660 }; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1661 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1662 static GList *notify_func_list = NULL; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1663 |
791 | 1664 static gint file_data_notify_sort(gconstpointer a, gconstpointer b) |
1665 { | |
1666 NotifyData *nda = (NotifyData *)a; | |
1667 NotifyData *ndb = (NotifyData *)b; | |
806 | 1668 |
791 | 1669 if (nda->priority < ndb->priority) return -1; |
1670 if (nda->priority > ndb->priority) return 1; | |
1671 return 0; | |
1672 } | |
1673 | |
1674 gint file_data_register_notify_func(FileDataNotifyFunc func, gpointer data, NotifyPriority priority) | |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1675 { |
806 | 1676 NotifyData *nd; |
1677 | |
1678 nd = g_new(NotifyData, 1); | |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1679 nd->func = func; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1680 nd->data = data; |
791 | 1681 nd->priority = priority; |
806 | 1682 |
791 | 1683 notify_func_list = g_list_insert_sorted(notify_func_list, nd, file_data_notify_sort); |
1684 DEBUG_1("Notify func registered: %p", nd); | |
806 | 1685 |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1686 return TRUE; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1687 } |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1688 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1689 gint file_data_unregister_notify_func(FileDataNotifyFunc func, gpointer data) |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1690 { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1691 GList *work = notify_func_list; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1692 |
806 | 1693 while (work) |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1694 { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1695 NotifyData *nd = (NotifyData *)work->data; |
806 | 1696 |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1697 if (nd->func == func && nd->data == data) |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1698 { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1699 notify_func_list = g_list_delete_link(notify_func_list, work); |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1700 g_free(nd); |
791 | 1701 DEBUG_1("Notify func unregistered: %p", nd); |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1702 return TRUE; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1703 } |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1704 work = work->next; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1705 } |
806 | 1706 |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1707 return FALSE; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1708 } |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1709 |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1710 |
792 | 1711 void file_data_send_notification(FileData *fd, NotifyType type) |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1712 { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1713 GList *work = notify_func_list; |
806 | 1714 |
1715 while (work) | |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1716 { |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1717 NotifyData *nd = (NotifyData *)work->data; |
806 | 1718 |
791 | 1719 DEBUG_1("Notify func calling: %p %s", nd, fd->path); |
792 | 1720 nd->func(fd, type, nd->data); |
784
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1721 work = work->next; |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1722 } |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1723 } |
16b3a5c8aedc
new notification system (used only in vflist for now)
nadvornik
parents:
783
diff
changeset
|
1724 |
791 | 1725 static GHashTable *file_data_monitor_pool = NULL; |
1726 static gint realtime_monitor_id = -1; | |
1727 | |
1728 static void realtime_monitor_check_cb(gpointer key, gpointer value, gpointer data) | |
1729 { | |
1730 FileData *fd = key; | |
1731 | |
801 | 1732 file_data_check_changed_files(fd); |
791 | 1733 |
1734 DEBUG_1("monitor %s", fd->path); | |
1735 } | |
1736 | |
1737 static gboolean realtime_monitor_cb(gpointer data) | |
1738 { | |
1739 g_hash_table_foreach(file_data_monitor_pool, realtime_monitor_check_cb, NULL); | |
1740 return TRUE; | |
1741 } | |
1742 | |
1743 gint file_data_register_real_time_monitor(FileData *fd) | |
1744 { | |
1745 gint count = 0; | |
1746 | |
1747 file_data_ref(fd); | |
1748 | |
1749 if (!file_data_monitor_pool) | |
1750 file_data_monitor_pool = g_hash_table_new(g_direct_hash, g_direct_equal); | |
1751 | |
1752 count = GPOINTER_TO_INT(g_hash_table_lookup(file_data_monitor_pool, fd)); | |
1753 | |
1754 DEBUG_1("Register realtime %d %s", count, fd->path); | |
1755 | |
1756 count++; | |
1757 g_hash_table_insert(file_data_monitor_pool, fd, GINT_TO_POINTER(count)); | |
1758 | |
1759 if (realtime_monitor_id == -1) | |
1760 { | |
1761 realtime_monitor_id = g_timeout_add(5000, realtime_monitor_cb, NULL); | |
1762 } | |
806 | 1763 |
791 | 1764 return TRUE; |
1765 } | |
1766 | |
1767 gint file_data_unregister_real_time_monitor(FileData *fd) | |
1768 { | |
1769 gint count; | |
806 | 1770 |
791 | 1771 g_assert(file_data_monitor_pool); |
1772 | |
1773 count = GPOINTER_TO_INT(g_hash_table_lookup(file_data_monitor_pool, fd)); | |
1774 | |
1775 DEBUG_1("Unregister realtime %d %s", count, fd->path); | |
1776 | |
1777 g_assert(count > 0); | |
1778 | |
1779 count--; | |
1780 | |
1781 if (count == 0) | |
1782 g_hash_table_remove(file_data_monitor_pool, fd); | |
1783 else | |
1784 g_hash_table_insert(file_data_monitor_pool, fd, GINT_TO_POINTER(count)); | |
1785 | |
1786 file_data_unref(fd); | |
1787 | |
1788 if (g_hash_table_size(file_data_monitor_pool) == 0) | |
1789 { | |
1790 g_source_remove(realtime_monitor_id); | |
1791 realtime_monitor_id = -1; | |
1792 return FALSE; | |
1793 } | |
806 | 1794 |
791 | 1795 return TRUE; |
1796 } |