diff options
Diffstat (limited to 'src/slideshow.c')
-rw-r--r-- | src/slideshow.c | 539 |
1 files changed, 359 insertions, 180 deletions
diff --git a/src/slideshow.c b/src/slideshow.c index de10300..266cb2e 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -1,6 +1,7 @@ /* slideshow.c Copyright (C) 1999-2003 Tom Gilbert. +Copyright (C) 2010-2024 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -34,158 +35,179 @@ void init_slideshow_mode(void) { winwidget w = NULL; int success = 0; - char *s = NULL; gib_list *l = filelist, *last = NULL; - feh_file *file = NULL; - for (l = filelist; l && opt.start_list_at; l = l->next) { + /* + * In theory, --start-at FILENAME is simple: Look for a file called + * FILENAME, start the filelist there, done. + * + * In practice, there are cases where this isn't sufficient. For instance, + * a user running 'feh --start-at hello.jpg /tmp' will expect feh to start + * at /tmp/hello.jpg, as if they had used + * 'feh --start-at /tmp/hello.jpg /tmp'. Similarly, XDG Desktop files + * may lead to the invocation 'feh --start-at /tmp/hello.jpg .' in /tmp, + * expecting the behaviour of 'feh --start-at ./hello.jpg .'. + * + * Since a good user experience is not about being technically correct, but + * about delivering the expected behaviour, we do some fuzzy matching + * here. In the worst case, this will cause --start-at to start at the + * wrong file. + */ + + // Try finding an exact filename match first + for (; l && opt.start_list_at; l = l->next) { if (!strcmp(opt.start_list_at, FEH_FILE(l->data)->filename)) { + free(opt.start_list_at); opt.start_list_at = NULL; break; } } + /* + * If it didn't work (opt.start_list_at is still set): Fall back to + * comparing just the filenames without directory prefixes. This may lead + * to false positives, but for now that's just the way it is. + */ + if (opt.start_list_at) { + char *current_filename; + char *start_at_filename = strrchr(opt.start_list_at, '/'); + if (start_at_filename) { + start_at_filename++; // We only care about the part after the '/' + } else { + start_at_filename = opt.start_list_at; + } + for (l = filelist; l && opt.start_list_at; l = l->next) { + current_filename = strrchr(FEH_FILE(l->data)->filename, '/'); + if (current_filename) { + current_filename++; // We only care about the part after the '/' + } else { + current_filename = FEH_FILE(l->data)->filename; + } + if (!strcmp(start_at_filename, current_filename)) { + free(opt.start_list_at); + opt.start_list_at = NULL; + break; + } + } + } + + // If that didn't work either, we're out of luck. if (opt.start_list_at) eprintf("--start-at %s: File not found in filelist", opt.start_list_at); + if (!opt.title) + opt.title = PACKAGE " [%u of %l] - %f"; + mode = "slideshow"; for (; l; l = l->next) { - file = FEH_FILE(l->data); if (last) { filelist = feh_file_remove_from_list(filelist, last); last = NULL; } current_file = l; - s = slideshow_create_name(file); - if ((w = winwidget_create_from_file(l, s, WIN_TYPE_SLIDESHOW)) != NULL) { - free(s); + if ((w = winwidget_create_from_file(l, WIN_TYPE_SLIDESHOW)) != NULL) { success = 1; winwidget_show(w); if (opt.slideshow_delay > 0.0) feh_add_timer(cb_slide_timer, w, opt.slideshow_delay, "SLIDE_CHANGE"); - else if (opt.reload > 0) + if (opt.reload > 0) feh_add_unique_timer(cb_reload_timer, w, opt.reload); break; } else { - free(s); last = l; } } if (!success) show_mini_usage(); - setup_signal_handlers(); - return; } void cb_slide_timer(void *data) { - slideshow_change_image((winwidget) data, SLIDE_NEXT); + slideshow_change_image((winwidget) data, SLIDE_NEXT, 1); return; } void cb_reload_timer(void *data) { - winwidget w = (winwidget) data; + gib_list *l; + char *current_filename; - feh_reload_image(w, 0, 0); - feh_add_unique_timer(cb_reload_timer, w, opt.reload); - return; -} + winwidget w = (winwidget) data; -void feh_reload_image(winwidget w, int resize, int force_new) -{ - char *title, *new_title; - int len; - Imlib_Image tmp; + /* + * multi-window mode has no concept of a "current file" and + * dynamically adding/removing windows is not implemented at the moment. + * So don't reload filelists in multi-window mode. + */ + if (current_file != NULL) { + /* save the current filename for refinding it in new list */ + current_filename = estrdup(FEH_FILE(current_file->data)->filename); - if (!w->file) { - weprintf("couldn't reload, this image has no file associated with it."); - return; - } + for (l = filelist; l; l = l->next) { + feh_file_free(l->data); + l->data = NULL; + } + gib_list_free_and_data(filelist); + filelist = NULL; + filelist_len = 0; + current_file = NULL; + + /* rebuild filelist from original_file_items */ + if (gib_list_length(original_file_items) > 0) + for (l = gib_list_last(original_file_items); l; l = l->prev) + add_file_to_filelist_recursively(l->data, FILELIST_FIRST); + else if (!opt.filelistfile && !opt.bgmode) + add_file_to_filelist_recursively(".", FILELIST_FIRST); + + if (opt.filelistfile) { + filelist = gib_list_cat(filelist, feh_read_filelist(opt.filelistfile)); + } - free(FEH_FILE(w->file->data)->caption); - FEH_FILE(w->file->data)->caption = NULL; + if (!(filelist_len = gib_list_length(filelist))) { + eprintf("No files found to reload."); + } - len = strlen(w->name) + sizeof("Reloading: ") + 1; - new_title = emalloc(len); - snprintf(new_title, len, "Reloading: %s", w->name); - title = estrdup(w->name); - winwidget_rename(w, new_title); + feh_prepare_filelist(); - /* force imlib2 not to cache */ - if (force_new) { - winwidget_free_image(w); - } + /* find the previously current file */ + for (l = filelist; l; l = l->next) + if (strcmp(FEH_FILE(l->data)->filename, current_filename) == 0) { + current_file = l; + break; + } - /* if the image has changed in dimensions - we gotta resize */ - if ((feh_load_image(&tmp, FEH_FILE(w->file->data))) == 0) { - if (force_new) { - eprintf("failed to reload image\n"); - } else { - weprintf("Couldn't reload image. Is it still there?"); - } - winwidget_rename(w, title); - free(title); - free(new_title); - filelist = feh_file_remove_from_list(filelist, w->file); - return; - } - if (force_new) { - w->im = tmp; - resize = 1; - winwidget_reset_image(w); - } else { - if ((gib_imlib_image_get_width(w->im) != gib_imlib_image_get_width(tmp)) - || (gib_imlib_image_get_height(w->im) != gib_imlib_image_get_height(tmp))) { - resize = 1; - winwidget_reset_image(w); - } - winwidget_free_image(w); - w->im = tmp; - } + free(current_filename); - w->mode = MODE_NORMAL; - if ((w->im_w != gib_imlib_image_get_width(w->im)) - || (w->im_h != gib_imlib_image_get_height(w->im))) - w->had_resize = 1; - if (w->has_rotated) { - Imlib_Image temp; - - temp = gib_imlib_create_rotated_image(w->im, 0.0); - w->im_w = gib_imlib_image_get_width(temp); - w->im_h = gib_imlib_image_get_height(temp); - gib_imlib_free_image_and_decache(temp); - } else { - w->im_w = gib_imlib_image_get_width(w->im); - w->im_h = gib_imlib_image_get_height(w->im); + if (!current_file) + current_file = filelist; + w->file = current_file; } - winwidget_render_image(w, resize, 1); - - winwidget_rename(w, title); - free(title); - free(new_title); + feh_reload_image(w, 1, 0); + feh_add_unique_timer(cb_reload_timer, w, opt.reload); return; } -void slideshow_change_image(winwidget winwid, int change) +void slideshow_change_image(winwidget winwid, int change, int render) { - int success = 0; gib_list *last = NULL; + gib_list *previous_file = current_file; int i = 0; int jmp = 1; /* We can't use filelist_len in the for loop, since that changes when we * encounter invalid images. */ int our_filelist_len = filelist_len; - char *s; + + if (opt.slideshow_delay > 0.0) + feh_add_timer(cb_slide_timer, winwid, opt.slideshow_delay, "SLIDE_CHANGE"); /* Without this, clicking a one-image slideshow reloads it. Not very * intelligent behaviour :-) */ - if (filelist_len < 2 && opt.cycle_once == 0) + if (filelist_len < 2 && opt.on_last_slide != ON_LAST_SLIDE_QUIT) return; /* Ok. I do this in such an odd way to ensure that if the last or first * @@ -195,14 +217,28 @@ void slideshow_change_image(winwidget winwid, int change) if (change == SLIDE_FIRST) { current_file = gib_list_last(filelist); change = SLIDE_NEXT; + previous_file = NULL; } else if (change == SLIDE_LAST) { current_file = filelist; change = SLIDE_PREV; + previous_file = NULL; } /* The for loop prevents us looping infinitely */ for (i = 0; i < our_filelist_len; i++) { winwidget_free_image(winwid); +#ifdef HAVE_LIBEXIF + /* + * An EXIF data chunk requires up to 50 kB of space. For large and + * long-running slideshows, this would acculumate gigabytes of + * EXIF data after a few days. We therefore do not cache EXIF data + * in slideshows. + */ + if (FEH_FILE(winwid->file->data)->ed) { + exif_data_unref(FEH_FILE(winwid->file->data)->ed); + FEH_FILE(winwid->file->data)->ed = NULL; + } +#endif switch (change) { case SLIDE_NEXT: current_file = feh_list_jump(filelist, current_file, FORWARD, 1); @@ -211,8 +247,11 @@ void slideshow_change_image(winwidget winwid, int change) current_file = feh_list_jump(filelist, current_file, BACK, 1); break; case SLIDE_RAND: - current_file = feh_list_jump(filelist, current_file, FORWARD, rand() % filelist_len); - change = SLIDE_NEXT; + if (filelist_len > 1) { + current_file = feh_list_jump(filelist, current_file, FORWARD, + (random() % (filelist_len - 1)) + 1); + change = SLIDE_NEXT; + } break; case SLIDE_JUMP_FWD: if (filelist_len < 5) @@ -242,6 +281,44 @@ void slideshow_change_image(winwidget winwid, int change) try the previous file, not another jmp */ change = SLIDE_NEXT; break; + case SLIDE_JUMP_NEXT_DIR: + { + char old_dir[PATH_MAX], new_dir[PATH_MAX]; + int j; + + feh_file_dirname(old_dir, FEH_FILE(current_file->data), PATH_MAX); + + for (j = 0; j < our_filelist_len; j++) { + current_file = feh_list_jump(filelist, current_file, FORWARD, 1); + feh_file_dirname(new_dir, FEH_FILE(current_file->data), PATH_MAX); + if (strcmp(old_dir, new_dir) != 0) + break; + } + } + change = SLIDE_NEXT; + break; + case SLIDE_JUMP_PREV_DIR: + { + char old_dir[PATH_MAX], new_dir[PATH_MAX]; + int j; + + /* Start the search from the previous file in case we are on + the first file of a directory */ + current_file = feh_list_jump(filelist, current_file, BACK, 1); + feh_file_dirname(old_dir, FEH_FILE(current_file->data), PATH_MAX); + + for (j = 0; j < our_filelist_len; j++) { + current_file = feh_list_jump(filelist, current_file, BACK, 1); + feh_file_dirname(new_dir, FEH_FILE(current_file->data), PATH_MAX); + if (strcmp(old_dir, new_dir) != 0) + break; + } + + /* Next file is the first entry of prev_dir */ + current_file = feh_list_jump(filelist, current_file, FORWARD, 1); + } + change = SLIDE_NEXT; + break; default: eprintf("BUG!\n"); break; @@ -251,23 +328,30 @@ void slideshow_change_image(winwidget winwid, int change) filelist = feh_file_remove_from_list(filelist, last); last = NULL; } - s = slideshow_create_name(FEH_FILE(current_file->data)); - winwidget_rename(winwid, s); - free(s); + if (opt.on_last_slide == ON_LAST_SLIDE_HOLD && previous_file && + ((current_file == filelist && change == SLIDE_NEXT) || + (previous_file == filelist && change == SLIDE_PREV))) { + current_file = previous_file; + } - if ((winwidget_loadimage(winwid, FEH_FILE(current_file->data))) - != 0) { - success = 1; + if (winwidget_loadimage(winwid, FEH_FILE(current_file->data))) { + int w = gib_imlib_image_get_width(winwid->im); + int h = gib_imlib_image_get_height(winwid->im); + if (feh_should_ignore_image(winwid->im)) { + last = current_file; + continue; + } winwid->mode = MODE_NORMAL; winwid->file = current_file; - if ((winwid->im_w != gib_imlib_image_get_width(winwid->im)) - || (winwid->im_h != gib_imlib_image_get_height(winwid->im))) + if ((winwid->im_w != w) || (winwid->im_h != h)) winwid->had_resize = 1; winwidget_reset_image(winwid); - winwid->im_w = gib_imlib_image_get_width(winwid->im); - winwid->im_h = gib_imlib_image_get_height(winwid->im); - winwidget_render_image(winwid, 1, 1); + winwid->im_w = w; + winwid->im_h = h; + if (render) { + winwidget_render_image(winwid, 1, 0); + } break; } else last = current_file; @@ -278,8 +362,6 @@ void slideshow_change_image(winwidget winwid, int change) if (filelist_len == 0) eprintf("No more slides in show"); - if (opt.slideshow_delay > 0.0) - feh_add_timer(cb_slide_timer, winwid, opt.slideshow_delay, "SLIDE_CHANGE"); return; } @@ -294,143 +376,226 @@ void slideshow_pause_toggle(winwidget w) winwidget_rename(w, NULL); } -char *slideshow_create_name(feh_file * file) -{ - char *s = NULL; - int len = 0; - - if (!opt.title) { - len = strlen(PACKAGE " [slideshow mode] - ") + strlen(file->filename) + 1; - s = emalloc(len); - snprintf(s, len, PACKAGE " [%d of %d] - %s", - gib_list_num(filelist, current_file) + 1, gib_list_length(filelist), file->filename); - } else { - s = estrdup(feh_printf(opt.title, file)); - } - - return(s); -} - -void feh_action_run(feh_file * file, char *action) +void feh_action_run(feh_file * file, char *action, winwidget winwid) { if (action) { char *sys; D(("Running action %s\n", action)); - sys = feh_printf(action, file); + sys = feh_printf(action, file, winwid); if (opt.verbose && !opt.list && !opt.customlist) fprintf(stderr, "Running action -->%s<--\n", sys); - system(sys); + if (system(sys) == -1) + perror("running action via system() failed"); } return; } -char *feh_printf(char *str, feh_file * file) +char *format_size(double size) +{ + static char ret[5]; + char units[] = {' ', 'k', 'M', 'G', 'T'}; + unsigned char postfix = 0; + while (size >= 1000) { + size /= 1000; + postfix++; + } + snprintf(ret, 5, "%3.0f%c", size, units[postfix]); + return ret; +} + +char *feh_printf(char *str, feh_file * file, winwidget winwid) { char *c; char buf[20]; static char ret[4096]; + char *filelist_tmppath; ret[0] = '\0'; + filelist_tmppath = NULL; + gib_list *f; for (c = str; *c != '\0'; c++) { - if (*c == '%') { + if ((*c == '%') && (*(c+1) != '\0')) { c++; switch (*c) { + case 'a': + if (opt.paused == 1) { + strncat(ret, "paused", sizeof(ret) - strlen(ret) - 1); + } + else { + strncat(ret, "playing", sizeof(ret) - strlen(ret) - 1); + } + break; case 'f': if (file) - strcat(ret, file->filename); + strncat(ret, file->filename, sizeof(ret) - strlen(ret) - 1); break; - case 'n': + case 'F': if (file) - strcat(ret, file->name); + strncat(ret, shell_escape(file->filename), sizeof(ret) - strlen(ret) - 1); break; - case 'w': - if (file) { - if (!file->info) - feh_file_info_load(file, NULL); - snprintf(buf, sizeof(buf), "%d", file->info->width); - strcat(ret, buf); + case 'g': + if (winwid) { + snprintf(buf, sizeof(buf), "%d,%d", winwid->w, winwid->h); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); } break; case 'h': - if (file) { - if (!file->info) - feh_file_info_load(file, NULL); + if (file && (file->info || !feh_file_info_load(file, NULL))) { snprintf(buf, sizeof(buf), "%d", file->info->height); - strcat(ret, buf); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); } break; - case 's': - if (file) { - if (!file->info) - feh_file_info_load(file, NULL); - snprintf(buf, sizeof(buf), "%d", file->info->size); - strcat(ret, buf); + case 'l': + snprintf(buf, sizeof(buf), "%d", gib_list_length(filelist)); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + break; + case 'L': + if (filelist_tmppath != NULL) { + strncat(ret, filelist_tmppath, sizeof(ret) - strlen(ret) - 1); + } else { + filelist_tmppath = feh_unique_filename("/tmp/","filelist"); + feh_write_filelist(filelist, filelist_tmppath); + strncat(ret, filelist_tmppath, sizeof(ret) - strlen(ret) - 1); + } + break; + case 'm': + strncat(ret, mode, sizeof(ret) - strlen(ret) - 1); + break; + case 'n': + if (file) + strncat(ret, file->name, sizeof(ret) - strlen(ret) - 1); + break; + case 'N': + if (file) + strncat(ret, shell_escape(file->name), sizeof(ret) - strlen(ret) - 1); + break; + case 'o': + if (winwid) { + snprintf(buf, sizeof(buf), "%d,%d", winwid->im_x, + winwid->im_y); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); } break; case 'p': - if (file) { - if (!file->info) - feh_file_info_load(file, NULL); + if (file && (file->info || !feh_file_info_load(file, NULL))) { snprintf(buf, sizeof(buf), "%d", file->info->pixels); - strcat(ret, buf); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; + case 'P': + if (file && (file->info || !feh_file_info_load(file, NULL))) { + strncat(ret, format_size(file->info->pixels), sizeof(ret) - strlen(ret) - 1); + } + break; + case 'r': + if (winwid) { + snprintf(buf, sizeof(buf), "%.1f", winwid->im_angle); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; + case 's': + if (file && (file->size >= 0 || !feh_file_stat(file))) { + snprintf(buf, sizeof(buf), "%d", file->size); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; + case 'S': + if (file && (file->size >= 0 || !feh_file_stat(file))) { + strncat(ret, format_size(file->size), sizeof(ret) - strlen(ret) - 1); } break; case 't': - if (file) { - if (!file->info) - feh_file_info_load(file, NULL); - strcat(ret, file->info->format); + if (file && (file->info || !feh_file_info_load(file, NULL))) { + strncat(ret, file->info->format, sizeof(ret) - strlen(ret) - 1); } break; - case 'P': - strcat(ret, PACKAGE); + case 'u': + f = current_file ? current_file : gib_list_find_by_data(filelist, file); + snprintf(buf, sizeof(buf), "%d", f ? gib_list_num(filelist, f) + 1 : 0); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); break; case 'v': - strcat(ret, VERSION); + strncat(ret, VERSION, sizeof(ret) - strlen(ret) - 1); break; - case 'm': - strcat(ret, mode); + case 'V': + snprintf(buf, sizeof(buf), "%d", getpid()); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); break; - case 'l': - snprintf(buf, sizeof(buf), "%d", gib_list_length(filelist)); - strcat(ret, buf); + case 'w': + if (file && (file->info || !feh_file_info_load(file, NULL))) { + snprintf(buf, sizeof(buf), "%d", file->info->width); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } break; - case 'u': - snprintf(buf, sizeof(buf), "%d", - current_file != NULL ? gib_list_num(filelist, current_file) - + 1 : 0); - strcat(ret, buf); + case 'W': + if (winwid) { + snprintf(buf, sizeof(buf), "%dx%d+%d+%d", winwid->w, winwid->h, winwid->x, winwid->y); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; + case 'z': + if (winwid) { + snprintf(buf, sizeof(buf), "%.2f", winwid->zoom); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } else { + strncat(ret, "1.00", sizeof(ret) - strlen(ret) - 1); + } + break; + case 'Z': + if (winwid) { + snprintf(buf, sizeof(buf), "%f", winwid->zoom); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; + case '%': + strncat(ret, "%", sizeof(ret) - strlen(ret) - 1); break; default: - strncat(ret, c, 1); + weprintf("Unrecognized format specifier %%%c", *c); + if ((strlen(ret) + 3) < sizeof(ret)) + strncat(ret, c - 1, 2); break; } - } else if (*c == '\\') { + } else if ((*c == '\\') && (*(c+1) != '\0') && ((strlen(ret) + 3) < sizeof(ret))) { c++; switch (*c) { case 'n': strcat(ret, "\n"); break; default: - strncat(ret, c, 1); + strncat(ret, c - 1, 2); break; } - } else + } else if ((strlen(ret) + 2) < sizeof(ret)) strncat(ret, c, 1); } + if (filelist_tmppath != NULL) + free(filelist_tmppath); return(ret); } void feh_filelist_image_remove(winwidget winwid, char do_delete) { if (winwid->type == WIN_TYPE_SLIDESHOW) { - char *s; gib_list *doomed; doomed = current_file; - slideshow_change_image(winwid, SLIDE_NEXT); + /* + * work around feh_list_jump exiting if ON_LAST_SLIDE_QUIT is set + * and no further files are left (we need to delete first) + */ + if (opt.on_last_slide == ON_LAST_SLIDE_QUIT && ! doomed->next && do_delete) { + feh_file_rm_and_free(filelist, doomed); + exit(0); + } + if (doomed->next) { + slideshow_change_image(winwid, SLIDE_NEXT, 0); + } + else { + slideshow_change_image(winwid, SLIDE_PREV, 0); + } if (do_delete) filelist = feh_file_rm_and_free(filelist, doomed); else @@ -440,15 +605,14 @@ void feh_filelist_image_remove(winwidget winwid, char do_delete) winwidget_destroy(winwid); return; } - s = slideshow_create_name(FEH_FILE(winwid->file->data)); - winwidget_rename(winwid, s); - free(s); + winwidget_render_image(winwid, 1, 0); } else if ((winwid->type == WIN_TYPE_SINGLE) || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)) { if (do_delete) filelist = feh_file_rm_and_free(filelist, winwid->file); else filelist = feh_file_remove_from_list(filelist, winwid->file); + winwid->file = NULL; winwidget_destroy(winwid); } } @@ -457,24 +621,33 @@ void slideshow_save_image(winwidget win) { char *tmpname; Imlib_Load_Error err; + char *base_dir = ""; + if (opt.output_dir) { + base_dir = estrjoin("", opt.output_dir, "/", NULL); + } if (win->file) { - tmpname = feh_unique_filename("", FEH_FILE(win->file->data)->name); + tmpname = feh_unique_filename(base_dir, FEH_FILE(win->file->data)->name); } else if (mode) { char *tmp; tmp = estrjoin(".", mode, "png", NULL); - tmpname = feh_unique_filename("", tmp); + tmpname = feh_unique_filename(base_dir, tmp); free(tmp); } else { - tmpname = feh_unique_filename("", "noname.png"); + tmpname = feh_unique_filename(base_dir, "noname.png"); } - if (!opt.quiet) - printf("saving image to filename '%s'\n", tmpname); + if (opt.output_dir) { + free(base_dir); + } + + if (opt.verbose) + fprintf(stderr, "saving image to filename '%s'\n", tmpname); gib_imlib_save_image_with_error_return(win->im, tmpname, &err); + if (err) - weprintf("Can't save image %s:", tmpname); + feh_print_load_error(tmpname, win, err, LOAD_ERROR_IMLIB); free(tmpname); return; @@ -497,10 +670,16 @@ gib_list *feh_list_jump(gib_list * root, gib_list * l, int direction, int num) if (ret->next) { ret = ret->next; } else { - if (opt.cycle_once) { + if (opt.on_last_slide == ON_LAST_SLIDE_QUIT) { exit(0); } - ret = root; + if (opt.randomize) { + /* Randomize the filename order */ + filelist = gib_list_randomize(filelist); + ret = filelist; + } else { + ret = root; + } } } else { if (ret->prev) |