diff --git a/src/defaults.c b/src/defaults.c index 033c3a4..5e1488d 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -163,6 +163,17 @@ static WDECallbackUpdate updateDock; * this value */ #define TOTAL_VALUES_LENGTH 80 +/* Return non-zero if file's mtime is newer than the saved timestamp. + * Uses nanosecond precision to handle multiple writes within the same + * second (e.g., wmsetbg invokes wdwrite twice in rapid succession). */ +#define MTIME_NEWER(stbuf, ts) \ + ((stbuf).st_mtim.tv_sec > (ts).tv_sec || \ + ((stbuf).st_mtim.tv_sec == (ts).tv_sec && \ + (stbuf).st_mtim.tv_nsec > (ts).tv_nsec)) + +#define MTIME_FROM_STAT(stbuf) \ + ((struct timespec){ (stbuf).st_mtim.tv_sec, (stbuf).st_mtim.tv_nsec }) + #define REFRESH_WINDOW_TEXTURES (1<<0) #define REFRESH_MENU_TEXTURE (1<<1) #define REFRESH_MENU_FONT (1<<2) @@ -992,7 +1003,7 @@ WDDomain *wDefaultsInitDomain(const char *domain, Bool requireDictionary) db->dictionary = NULL; wwarning(_("Domain %s (%s) of defaults database is corrupted!"), domain, db->path); } - db->timestamp = stbuf.st_mtime; + db->timestamp = MTIME_FROM_STAT(stbuf); } else { wwarning(_("could not load domain %s from user defaults database"), domain); } @@ -1006,12 +1017,12 @@ WDDomain *wDefaultsInitDomain(const char *domain, Bool requireDictionary) WMMergePLDictionaries(shared_dict, db->dictionary, True); WMReleasePropList(db->dictionary); db->dictionary = shared_dict; - if (stbuf.st_mtime > db->timestamp) - db->timestamp = stbuf.st_mtime; + if (MTIME_NEWER(stbuf, db->timestamp)) + db->timestamp = MTIME_FROM_STAT(stbuf); } else if (!db->dictionary) { db->dictionary = shared_dict; - if (stbuf.st_mtime > db->timestamp) - db->timestamp = stbuf.st_mtime; + if (MTIME_NEWER(stbuf, db->timestamp)) + db->timestamp = MTIME_FROM_STAT(stbuf); } return db; @@ -1056,8 +1067,8 @@ void wDefaultsCheckDomains(void* arg) /* Parameter not used, but tell the compiler that it is ok */ (void) arg; - if (stat(w_global.domain.wmaker->path, &stbuf) >= 0 && w_global.domain.wmaker->timestamp < stbuf.st_mtime) { - w_global.domain.wmaker->timestamp = stbuf.st_mtime; + if (stat(w_global.domain.wmaker->path, &stbuf) >= 0 && MTIME_NEWER(stbuf, w_global.domain.wmaker->timestamp)) { + w_global.domain.wmaker->timestamp = MTIME_FROM_STAT(stbuf); /* Global dictionary */ shared_dict = readGlobalDomain("WindowMaker", True); @@ -1099,7 +1110,7 @@ void wDefaultsCheckDomains(void* arg) } - if (stat(w_global.domain.window_attr->path, &stbuf) >= 0 && w_global.domain.window_attr->timestamp < stbuf.st_mtime) { + if (stat(w_global.domain.window_attr->path, &stbuf) >= 0 && MTIME_NEWER(stbuf, w_global.domain.window_attr->timestamp)) { /* global dictionary */ shared_dict = readGlobalDomain("WMWindowAttributes", True); /* user dictionary */ @@ -1138,12 +1149,12 @@ void wDefaultsCheckDomains(void* arg) wwarning(_("could not load domain %s from user defaults database"), "WMWindowAttributes"); } - w_global.domain.window_attr->timestamp = stbuf.st_mtime; + w_global.domain.window_attr->timestamp = MTIME_FROM_STAT(stbuf); if (shared_dict) WMReleasePropList(shared_dict); } - if (stat(w_global.domain.root_menu->path, &stbuf) >= 0 && w_global.domain.root_menu->timestamp < stbuf.st_mtime) { + if (stat(w_global.domain.root_menu->path, &stbuf) >= 0 && MTIME_NEWER(stbuf, w_global.domain.root_menu->timestamp)) { dict = WMReadPropListFromFile(w_global.domain.root_menu->path); if (dict) { if (!WMIsPLArray(dict) && !WMIsPLString(dict)) { @@ -1161,7 +1172,7 @@ void wDefaultsCheckDomains(void* arg) } else { wwarning(_("could not load domain %s from user defaults database"), "WMRootMenu"); } - w_global.domain.root_menu->timestamp = stbuf.st_mtime; + w_global.domain.root_menu->timestamp = MTIME_FROM_STAT(stbuf); } #ifndef HAVE_INOTIFY if (!arg) diff --git a/src/defaults.h b/src/defaults.h index a03ff34..6514f07 100644 --- a/src/defaults.h +++ b/src/defaults.h @@ -25,7 +25,7 @@ typedef struct WDDomain { const char *domain_name; WMPropList *dictionary; const char *path; - time_t timestamp; + struct timespec timestamp; } WDDomain; WDDomain * wDefaultsInitDomain(const char *domain, Bool requireDictionary); diff --git a/src/rootmenu.c b/src/rootmenu.c index 765dfeb..b8f5510 100644 --- a/src/rootmenu.c +++ b/src/rootmenu.c @@ -1458,7 +1458,7 @@ WMenu *configureMenu(WScreen *scr, WMPropList *definition) if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp /* if the pointer in WMRootMenu has changed */ - || w_global.domain.root_menu->timestamp > scr->root_menu->timestamp) { + || w_global.domain.root_menu->timestamp.tv_sec > scr->root_menu->timestamp) { WMPropList *menu_from_file = NULL; if (menu_is_default) { @@ -1476,7 +1476,7 @@ WMenu *configureMenu(WScreen *scr, WMPropList *definition) } if (menu) - menu->timestamp = WMAX(stat_buf.st_mtime, w_global.domain.root_menu->timestamp); + menu->timestamp = WMAX(stat_buf.st_mtime, w_global.domain.root_menu->timestamp.tv_sec); } else { menu = NULL; } @@ -1615,12 +1615,12 @@ void OpenRootMenu(WScreen * scr, int x, int y, int keyboard) */ if (definition) { if (WMIsPLArray(definition)) { - if (!scr->root_menu || w_global.domain.root_menu->timestamp > scr->root_menu->timestamp) { + if (!scr->root_menu || w_global.domain.root_menu->timestamp.tv_sec > scr->root_menu->timestamp) { wwarning("rootmenu: configureMenu begin"); menu = configureMenu(scr, definition); wwarning("rootmenu: configureMenu done, menu=%p", (void*)menu); if (menu) - menu->timestamp = w_global.domain.root_menu->timestamp; + menu->timestamp = w_global.domain.root_menu->timestamp.tv_sec; } else menu = NULL;