navigator: Simplify file polling

We don't need to know when all paths were last touched, just when we
switched to the current path, and the last time that the file changed.

This also fixes a bug where imv would double-load images as it refreshed
its internal mtime.
This commit is contained in:
Harry Jeffery 2019-02-16 18:48:01 +00:00
parent 4eaa1c89ae
commit 28eb7b50dc

View file

@ -17,8 +17,8 @@ struct imv_navigator {
int num_paths;
int cur_path;
char **paths;
time_t *mtimes;
time_t *ctimes;
time_t last_change;
time_t last_check;
int last_move_direction;
int changed;
int wrapped;
@ -36,52 +36,35 @@ struct imv_navigator *imv_navigator_create(void)
void imv_navigator_free(struct imv_navigator *nav)
{
if(nav->paths) {
for(int i = 0; i < nav->num_paths; ++i) {
if(nav->paths[i] != NULL) {
for (int i = 0; i < nav->num_paths; ++i) {
if (nav->paths[i] != NULL) {
free(nav->paths[i]);
}
}
free(nav->paths);
}
if(nav->mtimes) {
free(nav->mtimes);
}
if(nav->ctimes) {
free(nav->ctimes);
}
free(nav);
}
static int add_item(struct imv_navigator *nav, const char *path,
time_t mtime)
static int add_item(struct imv_navigator *nav, const char *path)
{
const size_t buf_size = 512;
if(nav->num_paths % buf_size == 0) {
if (nav->num_paths % buf_size == 0) {
char **new_paths;
time_t *new_mtimes;
time_t *new_ctimes;
size_t new_size = nav->num_paths + buf_size;
new_paths = realloc(nav->paths, sizeof(char*) * new_size);
new_mtimes = realloc(nav->mtimes, sizeof(time_t) * new_size);
new_ctimes = realloc(nav->ctimes, sizeof(time_t) * new_size);
if (new_paths == NULL || new_mtimes == NULL || new_ctimes == NULL) {
if (new_paths == NULL) {
return 1;
}
nav->paths = new_paths;
nav->mtimes = new_mtimes;
nav->ctimes = new_ctimes;
}
if((nav->paths[nav->num_paths] = strndup(path, PATH_MAX)) == NULL) {
if ((nav->paths[nav->num_paths] = strndup(path, PATH_MAX)) == NULL) {
return 1;
}
nav->mtimes[nav->num_paths] = mtime;
nav->ctimes[nav->num_paths] = time(NULL);
nav->num_paths += 1;
if(nav->num_paths == 1) {
if (nav->num_paths == 1) {
nav->changed = 1;
}
@ -94,22 +77,21 @@ int imv_navigator_add(struct imv_navigator *nav, const char *path,
char path_buf[PATH_MAX];
struct stat path_info;
stat(path, &path_info);
if(S_ISDIR(path_info.st_mode)) {
if (S_ISDIR(path_info.st_mode)) {
DIR *d = opendir(path);
if(d) {
if (d) {
struct dirent *dir;
while((dir = readdir(d)) != NULL) {
if(strcmp(dir->d_name, "..") == 0 || strcmp(dir->d_name, ".") == 0) {
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, "..") == 0 || strcmp(dir->d_name, ".") == 0) {
continue;
}
snprintf(path_buf, sizeof(path_buf), "%s/%s", path, dir->d_name);
if(recursive) {
if(imv_navigator_add(nav, path_buf, recursive) != 0) {
if (recursive) {
if (imv_navigator_add(nav, path_buf, recursive) != 0) {
return 1;
}
} else {
stat(path_buf, &path_info);
if(add_item(nav, path_buf, path_info.st_mtim.tv_sec) != 0) {
if (add_item(nav, path_buf) != 0) {
return 1;
}
}
@ -117,7 +99,7 @@ int imv_navigator_add(struct imv_navigator *nav, const char *path,
closedir(d);
}
} else {
return add_item(nav, path, path_info.st_mtim.tv_sec);
return add_item(nav, path);
}
return 0;
@ -125,7 +107,7 @@ int imv_navigator_add(struct imv_navigator *nav, const char *path,
const char *imv_navigator_selection(struct imv_navigator *nav)
{
if(nav->num_paths == 0) {
if (nav->num_paths == 0) {
return "";
}
return nav->paths[nav->cur_path];
@ -139,24 +121,24 @@ size_t imv_navigator_index(struct imv_navigator *nav)
void imv_navigator_select_rel(struct imv_navigator *nav, int direction)
{
const int prev_path = nav->cur_path;
if(nav->num_paths == 0) {
if (nav->num_paths == 0) {
return;
}
if(direction > 1) {
if (direction > 1) {
direction = 1;
} else if(direction < -1) {
} else if (direction < -1) {
direction = -1;
} else if(direction == 0) {
} else if (direction == 0) {
return;
}
nav->cur_path += direction;
if(nav->cur_path == nav->num_paths) {
if (nav->cur_path == nav->num_paths) {
/* Wrap after the end of the list */
nav->cur_path = 0;
nav->wrapped = 1;
} else if(nav->cur_path < 0) {
} else if (nav->cur_path < 0) {
/* Wrap before the start of the list */
nav->cur_path = nav->num_paths - 1;
nav->wrapped = 1;
@ -170,17 +152,17 @@ void imv_navigator_select_abs(struct imv_navigator *nav, int index)
{
const int prev_path = nav->cur_path;
/* allow -1 to indicate the last image */
if(index < 0) {
if (index < 0) {
index += nav->num_paths;
/* but if they go farther back than the first image, stick to first image */
if(index < 0) {
if (index < 0) {
index = 0;
}
}
/* stick to last image if we go beyond it */
if(index >= nav->num_paths) {
if (index >= nav->num_paths) {
index = nav->num_paths - 1;
}
@ -192,32 +174,32 @@ void imv_navigator_select_abs(struct imv_navigator *nav, int index)
void imv_navigator_remove(struct imv_navigator *nav, const char *path)
{
int removed = -1;
for(int i = 0; i < nav->num_paths; ++i) {
if(strcmp(path, nav->paths[i]) == 0) {
for (int i = 0; i < nav->num_paths; ++i) {
if (strcmp(path, nav->paths[i]) == 0) {
removed = i;
free(nav->paths[i]);
break;
}
}
if(removed == -1) {
if (removed == -1) {
return;
}
for(int i = removed; i < nav->num_paths - 1; ++i) {
for (int i = removed; i < nav->num_paths - 1; ++i) {
nav->paths[i] = nav->paths[i+1];
}
nav->num_paths -= 1;
if(nav->cur_path == removed) {
if (nav->cur_path == removed) {
/* We just removed the current path */
if(nav->last_move_direction < 0) {
if (nav->last_move_direction < 0) {
/* Move left */
imv_navigator_select_rel(nav, -1);
} else {
/* Try to stay where we are, unless we ran out of room */
if(nav->cur_path == nav->num_paths) {
if (nav->cur_path == nav->num_paths) {
nav->cur_path = 0;
nav->wrapped = 1;
}
@ -228,7 +210,7 @@ void imv_navigator_remove(struct imv_navigator *nav, const char *path)
void imv_navigator_select_str(struct imv_navigator *nav, const int path)
{
if(path <= 0 || path >= nav->num_paths) {
if (path <= 0 || path >= nav->num_paths) {
return;
}
int prev_path = nav->cur_path;
@ -239,16 +221,16 @@ void imv_navigator_select_str(struct imv_navigator *nav, const int path)
int imv_navigator_find_path(struct imv_navigator *nav, const char *path)
{
/* first try to match the exact path */
for(int i = 0; i < nav->num_paths; ++i) {
if(strcmp(path, nav->paths[i]) == 0) {
for (int i = 0; i < nav->num_paths; ++i) {
if (strcmp(path, nav->paths[i]) == 0) {
return i;
}
}
/* no exact matches, try the final portion of the path */
for(int i = 0; i < nav->num_paths; ++i) {
for (int i = 0; i < nav->num_paths; ++i) {
char *last_sep = strrchr(nav->paths[i], '/');
if(last_sep && strcmp(last_sep+1, path) == 0) {
if (last_sep && strcmp(last_sep+1, path) == 0) {
return i;
}
}
@ -259,26 +241,29 @@ int imv_navigator_find_path(struct imv_navigator *nav, const char *path)
int imv_navigator_poll_changed(struct imv_navigator *nav)
{
if(nav->changed) {
if (nav->changed) {
nav->changed = 0;
nav->last_change = time(NULL);
return 1;
}
if(nav->paths == NULL) {
if (nav->paths == NULL) {
return 0;
};
time_t cur_time = time(NULL);
/* limit polling to once per second */
if(nav->ctimes[nav->cur_path] < cur_time - 1) {
nav->ctimes[nav->cur_path] = cur_time;
if (nav->last_check < cur_time - 1) {
nav->last_check = cur_time;
struct stat file_info;
if(stat(nav->paths[nav->cur_path], &file_info) == -1) {
if (stat(nav->paths[nav->cur_path], &file_info) == -1) {
return 0;
}
if(nav->mtimes[nav->cur_path] != file_info.st_mtim.tv_sec) {
nav->mtimes[nav->cur_path] = file_info.st_mtim.tv_sec;
time_t file_changed = file_info.st_mtim.tv_sec;
if (file_changed > nav->last_change) {
nav->last_change = file_changed;
return 1;
}
}
@ -297,7 +282,7 @@ size_t imv_navigator_length(struct imv_navigator *nav)
char *imv_navigator_at(struct imv_navigator *nav, int index)
{
if(index >= 0 && index < nav->num_paths) {
if (index >= 0 && index < nav->num_paths) {
return nav->paths[index];
}
return NULL;