Skip to content

Commit 6edcb9b

Browse files
committed
manage XMP sidecar files
1 parent f928758 commit 6edcb9b

File tree

7 files changed

+826
-183
lines changed

7 files changed

+826
-183
lines changed

data/darktableconfig.xml.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,13 @@
35193519
<shortdescription>look for updated XMP files on startup</shortdescription>
35203520
<longdescription>check file modification times of all XMP files on startup to check if any got updated in the meantime</longdescription>
35213521
</dtconfig>
3522+
<dtconfig prefs="storage" section="XMP">
3523+
<name>xmp_full_scan_next_time</name>
3524+
<type>bool</type>
3525+
<default>false</default>
3526+
<shortdescription>scan all XMP files for changes on next startup</shortdescription>
3527+
<longdescription/>
3528+
</dtconfig>
35223529
<dtconfig>
35233530
<name>colorlabel/red</name>
35243531
<type>string</type>

src/common/exif.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6061,6 +6061,7 @@ gboolean dt_exif_xmp_write(const dt_imgid_t imgid,
60616061
fprintf(fout, "%s", xml_header);
60626062
fprintf(fout, "%s", xmpPacket.c_str());
60636063
fclose(fout);
6064+
dt_diratime_action(filename, "update");
60646065
}
60656066
else
60666067
{

src/control/control.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,90 @@ void dt_control_set_mouse_over_id(const dt_imgid_t imgid)
817817
dt_pthread_mutex_unlock(&dc->global_mutex);
818818
}
819819

820+
time_t dt_diratime_action(const char *dir_path, const char *action)
821+
{
822+
time_t timestamp = 0;
823+
gchar *_dir = g_strdup(dir_path);
824+
size_t name_len = strlen(dir_path);
825+
const char *ext = dir_path + name_len - 4;
826+
if (((!g_strcmp0(action, "update") && (!g_strcmp0(ext, ".xmp") || !g_strcmp0(ext, ".XMP")))
827+
|| !g_strcmp0(action, "delete"))
828+
&& name_len > 4)
829+
{
830+
size_t len = strlen(dir_path);
831+
const char *c = dir_path + len;
832+
while((c > dir_path) && ((*c) != G_DIR_SEPARATOR)) c--;
833+
size_t vers_len = c - dir_path + 1;
834+
g_strlcpy(_dir, dir_path, vers_len + 1);
835+
}
836+
837+
GError *error = NULL;
838+
GFile *_g_dir = g_file_new_for_path(_dir);
839+
GFileInfo *info = g_file_query_info(_g_dir,
840+
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
841+
G_FILE_ATTRIBUTE_STANDARD_TYPE,
842+
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL);
843+
const char *dirname = g_file_info_get_attribute_string(info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
844+
845+
const char *dir_mark = g_strconcat(_dir, dirname, ".dt", NULL);
846+
time_t dir_mark_time = 0;
847+
848+
GFile *_g_dir_mark = g_file_new_for_path(dir_mark);
849+
if (!g_strcmp0(action, "create"))
850+
{
851+
if(!g_file_test(dir_mark, G_FILE_TEST_EXISTS))
852+
{
853+
GFileEnumerator *dir_files = g_file_enumerate_children(_g_dir,
854+
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
855+
G_FILE_ATTRIBUTE_TIME_MODIFIED ","
856+
G_FILE_ATTRIBUTE_STANDARD_TYPE,
857+
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
858+
if(dir_files)
859+
{
860+
while((info = g_file_enumerator_next_file(dir_files, NULL, &error)))
861+
{
862+
const char *filename = g_file_info_get_display_name(info);
863+
if(!filename) continue;
864+
const GFileType filetype = g_file_info_get_attribute_uint32(info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
865+
if(filetype == G_FILE_TYPE_REGULAR)
866+
{
867+
name_len = strlen(filename);
868+
ext = filename + name_len - 4;
869+
if ((strcmp(ext, ".xmp") == 0 || strcmp(ext, ".XMP") == 0) && name_len > 4)
870+
{
871+
time_t _timestamp = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
872+
if (_timestamp > dir_mark_time)
873+
dir_mark_time = _timestamp;
874+
}
875+
}
876+
}
877+
}
878+
GFileOutputStream *out = g_file_replace(_g_dir_mark, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &error);
879+
g_object_unref(out);
880+
info = g_file_query_info(_g_dir_mark,
881+
G_FILE_ATTRIBUTE_TIME_MODIFIED,
882+
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
883+
g_file_set_attribute_uint64(_g_dir_mark, G_FILE_ATTRIBUTE_TIME_MODIFIED, dir_mark_time, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,FALSE,&error);
884+
g_object_unref(dir_files);
885+
}
886+
}
887+
else if (!g_strcmp0(action, "update") || !g_strcmp0(action, "delete"))
888+
{
889+
GFileOutputStream *out = g_file_replace(_g_dir_mark, NULL, FALSE,
890+
G_FILE_CREATE_REPLACE_DESTINATION, NULL, &error);
891+
g_object_unref(out);
892+
}
893+
info = g_file_query_info(_g_dir_mark,
894+
G_FILE_ATTRIBUTE_TIME_MODIFIED,
895+
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
896+
timestamp = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
897+
g_object_unref(info);
898+
g_object_unref(_g_dir_mark);
899+
g_object_unref(_g_dir);
900+
901+
return timestamp;
902+
}
903+
820904
// clang-format off
821905
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
822906
// vim: shiftwidth=2 expandtab tabstop=2 cindent

src/control/control.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ gboolean dt_control_running(void);
255255
dt_imgid_t dt_control_get_mouse_over_id(void);
256256
void dt_control_set_mouse_over_id(const dt_imgid_t value);
257257

258+
/** actions on directory access mark file.
259+
'action' must be one of "create", "update", "delete" */
260+
time_t dt_diratime_action(const char *dir_path, const char *action);
261+
258262
G_END_DECLS
259263

260264
// clang-format off

0 commit comments

Comments
 (0)