"Fossies" - the Fresh Open Source Software Archive

Member "feh-3.4.1/src/slideshow.c" (29 May 2020, 18072 Bytes) of package /linux/privat/feh-3.4.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "slideshow.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.4_vs_3.4.1.

    1 /* slideshow.c
    2 
    3 Copyright (C) 1999-2003 Tom Gilbert.
    4 Copyright (C) 2010-2020 Daniel Friesel.
    5 
    6 Permission is hereby granted, free of charge, to any person obtaining a copy
    7 of this software and associated documentation files (the "Software"), to
    8 deal in the Software without restriction, including without limitation the
    9 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   10 sell copies of the Software, and to permit persons to whom the Software is
   11 furnished to do so, subject to the following conditions:
   12 
   13 The above copyright notice and this permission notice shall be included in
   14 all copies of the Software and its documentation and acknowledgment shall be
   15 given in the documentation and software packages that this Software was
   16 used.
   17 
   18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   21 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   22 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   24 
   25 */
   26 
   27 #include "feh.h"
   28 #include "filelist.h"
   29 #include "timers.h"
   30 #include "winwidget.h"
   31 #include "options.h"
   32 #include "signals.h"
   33 
   34 void init_slideshow_mode(void)
   35 {
   36     winwidget w = NULL;
   37     int success = 0;
   38     gib_list *l = filelist, *last = NULL;
   39 
   40     /*
   41      * In theory, --start-at FILENAME is simple: Look for a file called
   42      * FILENAME, start the filelist there, done.
   43      *
   44      * In practice, there are cases where this isn't sufficient. For instance,
   45      * a user running 'feh --start-at hello.jpg /tmp' will expect feh to start
   46      * at /tmp/hello.jpg, as if they had used
   47      * 'feh --start-at /tmp/hello.jpg /tmp'. Similarly, XDG Desktop files
   48      * may lead to the invocation 'feh --start-at /tmp/hello.jpg .' in /tmp,
   49      * expecting the behaviour of 'feh --start-at ./hello.jpg .'.
   50      *
   51      * Since a good user experience is not about being technically correct, but
   52      * about delivering the expected behaviour, we do some fuzzy matching
   53      * here. In the worst case, this will cause --start-at to start at the
   54      * wrong file.
   55      */
   56 
   57     // Try finding an exact filename match first
   58     for (; l && opt.start_list_at; l = l->next) {
   59         if (!strcmp(opt.start_list_at, FEH_FILE(l->data)->filename)) {
   60             opt.start_list_at = NULL;
   61             break;
   62         }
   63     }
   64 
   65     /*
   66      * If it didn't work (opt.start_list_at is still set): Fall back to
   67      * comparing just the filenames without directory prefixes. This may lead
   68      * to false positives, but for now that's just the way it is.
   69      */
   70     if (opt.start_list_at) {
   71         char *current_filename;
   72         char *start_at_filename = strrchr(opt.start_list_at, '/');
   73         if (start_at_filename) {
   74             start_at_filename++; // We only care about the part after the '/'
   75         } else {
   76             start_at_filename = opt.start_list_at;
   77         }
   78         for (l = filelist; l && opt.start_list_at; l = l->next) {
   79             current_filename = strrchr(FEH_FILE(l->data)->filename, '/');
   80             if (current_filename) {
   81                 current_filename++; // We only care about the part after the '/'
   82             } else {
   83                 current_filename = FEH_FILE(l->data)->filename;
   84             }
   85             if (!strcmp(start_at_filename, current_filename)) {
   86                 opt.start_list_at = NULL;
   87                 break;
   88             }
   89         }
   90     }
   91 
   92     // If that didn't work either, we're out of luck.
   93     if (opt.start_list_at)
   94         eprintf("--start-at %s: File not found in filelist",
   95                 opt.start_list_at);
   96 
   97     if (!opt.title)
   98         opt.title = PACKAGE " [%u of %l] - %f";
   99 
  100     mode = "slideshow";
  101     for (; l; l = l->next) {
  102         if (last) {
  103             filelist = feh_file_remove_from_list(filelist, last);
  104             last = NULL;
  105         }
  106         current_file = l;
  107         if ((w = winwidget_create_from_file(l, WIN_TYPE_SLIDESHOW)) != NULL) {
  108             success = 1;
  109             winwidget_show(w);
  110             if (opt.slideshow_delay > 0.0)
  111                 feh_add_timer(cb_slide_timer, w, opt.slideshow_delay, "SLIDE_CHANGE");
  112             if (opt.reload > 0)
  113                 feh_add_unique_timer(cb_reload_timer, w, opt.reload);
  114             break;
  115         } else {
  116             last = l;
  117         }
  118     }
  119     if (!success)
  120         show_mini_usage();
  121 
  122     return;
  123 }
  124 
  125 void cb_slide_timer(void *data)
  126 {
  127     slideshow_change_image((winwidget) data, SLIDE_NEXT, 1);
  128     return;
  129 }
  130 
  131 void cb_reload_timer(void *data)
  132 {
  133     gib_list *l;
  134     char *current_filename;
  135 
  136     winwidget w = (winwidget) data;
  137 
  138     /* save the current filename for refinding it in new list */
  139     current_filename = estrdup(FEH_FILE(current_file->data)->filename);
  140 
  141     for (l = filelist; l; l = l->next) {
  142         feh_file_free(l->data);
  143         l->data = NULL;
  144     }
  145     gib_list_free_and_data(filelist);
  146     filelist = NULL;
  147     filelist_len = 0;
  148     current_file = NULL;
  149 
  150     /* rebuild filelist from original_file_items */
  151     if (gib_list_length(original_file_items) > 0)
  152         for (l = gib_list_last(original_file_items); l; l = l->prev)
  153             add_file_to_filelist_recursively(l->data, FILELIST_FIRST);
  154     else if (!opt.filelistfile && !opt.bgmode)
  155         add_file_to_filelist_recursively(".", FILELIST_FIRST);
  156 
  157     if (opt.filelistfile) {
  158         filelist = gib_list_cat(filelist, feh_read_filelist(opt.filelistfile));
  159     }
  160     
  161     if (!(filelist_len = gib_list_length(filelist))) {
  162         eprintf("No files found to reload.");
  163     }
  164 
  165     feh_prepare_filelist();
  166 
  167     /* find the previously current file */
  168     for (l = filelist; l; l = l->next)
  169         if (strcmp(FEH_FILE(l->data)->filename, current_filename) == 0) {
  170             current_file = l;
  171             break;
  172         }
  173 
  174     free(current_filename);
  175 
  176     if (!current_file)
  177         current_file = filelist;
  178     w->file = current_file;
  179 
  180     feh_reload_image(w, 1, 0);
  181     feh_add_unique_timer(cb_reload_timer, w, opt.reload);
  182     return;
  183 }
  184 
  185 void slideshow_change_image(winwidget winwid, int change, int render)
  186 {
  187     gib_list *last = NULL;
  188     gib_list *previous_file = current_file;
  189     int i = 0;
  190     int jmp = 1;
  191     /* We can't use filelist_len in the for loop, since that changes when we
  192      * encounter invalid images.
  193      */
  194     int our_filelist_len = filelist_len;
  195 
  196     if (opt.slideshow_delay > 0.0)
  197         feh_add_timer(cb_slide_timer, winwid, opt.slideshow_delay, "SLIDE_CHANGE");
  198 
  199     /* Without this, clicking a one-image slideshow reloads it. Not very *
  200        intelligent behaviour :-) */
  201     if (filelist_len < 2 && opt.on_last_slide != ON_LAST_SLIDE_QUIT)
  202         return;
  203 
  204     /* Ok. I do this in such an odd way to ensure that if the last or first *
  205        image is not loadable, it will go through in the right direction to *
  206        find the correct one. Otherwise SLIDE_LAST would try the last file, *
  207        then loop forward to find a loadable one. */
  208     if (change == SLIDE_FIRST) {
  209         current_file = gib_list_last(filelist);
  210         change = SLIDE_NEXT;
  211         previous_file = NULL;
  212     } else if (change == SLIDE_LAST) {
  213         current_file = filelist;
  214         change = SLIDE_PREV;
  215         previous_file = NULL;
  216     }
  217 
  218     /* The for loop prevents us looping infinitely */
  219     for (i = 0; i < our_filelist_len; i++) {
  220         winwidget_free_image(winwid);
  221         switch (change) {
  222         case SLIDE_NEXT:
  223             current_file = feh_list_jump(filelist, current_file, FORWARD, 1);
  224             break;
  225         case SLIDE_PREV:
  226             current_file = feh_list_jump(filelist, current_file, BACK, 1);
  227             break;
  228         case SLIDE_RAND:
  229             if (filelist_len > 1) {
  230                 current_file = feh_list_jump(filelist, current_file, FORWARD,
  231                     (random() % (filelist_len - 1)) + 1);
  232                 change = SLIDE_NEXT;
  233             }
  234             break;
  235         case SLIDE_JUMP_FWD:
  236             if (filelist_len < 5)
  237                 jmp = 1;
  238             else if (filelist_len < 40)
  239                 jmp = 2;
  240             else
  241                 jmp = filelist_len / 20;
  242             if (!jmp)
  243                 jmp = 2;
  244             current_file = feh_list_jump(filelist, current_file, FORWARD, jmp);
  245             /* important. if the load fails, we only want to step on ONCE to
  246                try the next file, not another jmp */
  247             change = SLIDE_NEXT;
  248             break;
  249         case SLIDE_JUMP_BACK:
  250             if (filelist_len < 5)
  251                 jmp = 1;
  252             else if (filelist_len < 40)
  253                 jmp = 2;
  254             else
  255                 jmp = filelist_len / 20;
  256             if (!jmp)
  257                 jmp = 2;
  258             current_file = feh_list_jump(filelist, current_file, BACK, jmp);
  259             /* important. if the load fails, we only want to step back ONCE to
  260                try the previous file, not another jmp */
  261             change = SLIDE_NEXT;
  262             break;
  263         case SLIDE_JUMP_NEXT_DIR:
  264             {
  265                 char old_dir[PATH_MAX], new_dir[PATH_MAX];
  266                 int j;
  267 
  268                 feh_file_dirname(old_dir, FEH_FILE(current_file->data), PATH_MAX);
  269 
  270                 for (j = 0; j < our_filelist_len; j++) {
  271                     current_file = feh_list_jump(filelist, current_file, FORWARD, 1);
  272                     feh_file_dirname(new_dir, FEH_FILE(current_file->data), PATH_MAX);
  273                     if (strcmp(old_dir, new_dir) != 0)
  274                         break;
  275                 }
  276             }
  277             change = SLIDE_NEXT;
  278             break;
  279         case SLIDE_JUMP_PREV_DIR:
  280             {
  281                 char old_dir[PATH_MAX], new_dir[PATH_MAX];
  282                 int j;
  283 
  284                 /* Start the search from the previous file in case we are on
  285                    the first file of a directory */
  286                 current_file = feh_list_jump(filelist, current_file, BACK, 1);
  287                 feh_file_dirname(old_dir, FEH_FILE(current_file->data), PATH_MAX);
  288 
  289                 for (j = 0; j < our_filelist_len; j++) {
  290                     current_file = feh_list_jump(filelist, current_file, BACK, 1);
  291                     feh_file_dirname(new_dir, FEH_FILE(current_file->data), PATH_MAX);
  292                     if (strcmp(old_dir, new_dir) != 0)
  293                         break;
  294                 }
  295 
  296                 /* Next file is the first entry of prev_dir */
  297                 current_file = feh_list_jump(filelist, current_file, FORWARD, 1);
  298             }
  299             change = SLIDE_NEXT;
  300             break;
  301         default:
  302             eprintf("BUG!\n");
  303             break;
  304         }
  305 
  306         if (last) {
  307             filelist = feh_file_remove_from_list(filelist, last);
  308             last = NULL;
  309         }
  310 
  311         if (opt.on_last_slide == ON_LAST_SLIDE_HOLD && previous_file &&
  312             ((current_file == filelist && change == SLIDE_NEXT) ||
  313             (previous_file == filelist && change == SLIDE_PREV))) {
  314                 current_file = previous_file;
  315         }
  316 
  317         if (winwidget_loadimage(winwid, FEH_FILE(current_file->data))) {
  318             int w = gib_imlib_image_get_width(winwid->im);
  319             int h = gib_imlib_image_get_height(winwid->im);
  320             if (feh_should_ignore_image(winwid->im)) {
  321                 last = current_file;
  322                 continue;
  323             }
  324             winwid->mode = MODE_NORMAL;
  325             winwid->file = current_file;
  326             if ((winwid->im_w != w) || (winwid->im_h != h))
  327                 winwid->had_resize = 1;
  328             winwidget_reset_image(winwid);
  329             winwid->im_w = w;
  330             winwid->im_h = h;
  331             if (render) {
  332                 winwidget_render_image(winwid, 1, 0);
  333             }
  334             break;
  335         } else
  336             last = current_file;
  337     }
  338     if (last)
  339         filelist = feh_file_remove_from_list(filelist, last);
  340 
  341     if (filelist_len == 0)
  342         eprintf("No more slides in show");
  343 
  344     return;
  345 }
  346 
  347 void slideshow_pause_toggle(winwidget w)
  348 {
  349     if (!opt.paused) {
  350         opt.paused = 1;
  351     } else {
  352         opt.paused = 0;
  353     }
  354 
  355     winwidget_rename(w, NULL);
  356 }
  357 
  358 void feh_action_run(feh_file * file, char *action, winwidget winwid)
  359 {
  360     if (action) {
  361         char *sys;
  362         D(("Running action %s\n", action));
  363         sys = feh_printf(action, file, winwid);
  364 
  365         if (opt.verbose && !opt.list && !opt.customlist)
  366             fprintf(stderr, "Running action -->%s<--\n", sys);
  367         system(sys);
  368     }
  369     return;
  370 }
  371 
  372 char *format_size(double size)
  373 {
  374     static char ret[5];
  375     char units[] = {' ', 'k', 'M', 'G', 'T'};
  376     unsigned char postfix = 0;
  377     while (size >= 1000) {
  378         size /= 1000;
  379         postfix++;
  380     }
  381     snprintf(ret, 5, "%3.0f%c", size, units[postfix]);
  382     return ret;
  383 }
  384 
  385 char *feh_printf(char *str, feh_file * file, winwidget winwid)
  386 {
  387     char *c;
  388     char buf[20];
  389     static char ret[4096];
  390     char *filelist_tmppath;
  391 
  392     ret[0] = '\0';
  393     filelist_tmppath = NULL;
  394     gib_list *f;
  395 
  396     for (c = str; *c != '\0'; c++) {
  397         if ((*c == '%') && (*(c+1) != '\0')) {
  398             c++;
  399             switch (*c) {
  400             case 'f':
  401                 if (file)
  402                     strncat(ret, file->filename, sizeof(ret) - strlen(ret) - 1);
  403                 break;
  404             case 'F':
  405                 if (file)
  406                     strncat(ret, shell_escape(file->filename), sizeof(ret) - strlen(ret) - 1);
  407                 break;
  408             case 'g':
  409                 if (winwid) {
  410                     snprintf(buf, sizeof(buf), "%d,%d", winwid->w, winwid->h);
  411                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  412                 }
  413                 break;
  414             case 'h':
  415                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  416                     snprintf(buf, sizeof(buf), "%d", file->info->height);
  417                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  418                 }
  419                 break;
  420             case 'l':
  421                 snprintf(buf, sizeof(buf), "%d", gib_list_length(filelist));
  422                 strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  423                 break;
  424             case 'L':
  425                 if (filelist_tmppath != NULL) {
  426                     strncat(ret, filelist_tmppath, sizeof(ret) - strlen(ret) - 1);
  427                 } else {
  428                     filelist_tmppath = feh_unique_filename("/tmp/","filelist");
  429                     feh_write_filelist(filelist, filelist_tmppath);
  430                     strncat(ret, filelist_tmppath, sizeof(ret) - strlen(ret) - 1);
  431                 }
  432                 break;
  433             case 'm':
  434                 strncat(ret, mode, sizeof(ret) - strlen(ret) - 1);
  435                 break;
  436             case 'n':
  437                 if (file)
  438                     strncat(ret, file->name, sizeof(ret) - strlen(ret) - 1);
  439                 break;
  440             case 'N':
  441                 if (file)
  442                     strncat(ret, shell_escape(file->name), sizeof(ret) - strlen(ret) - 1);
  443                 break;
  444             case 'o':
  445                 if (winwid) {
  446                     snprintf(buf, sizeof(buf), "%d,%d", winwid->im_x,
  447                         winwid->im_y);
  448                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  449                 }
  450                 break;
  451             case 'p':
  452                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  453                     snprintf(buf, sizeof(buf), "%d", file->info->pixels);
  454                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  455                 }
  456                 break;
  457             case 'P':
  458                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  459                     strncat(ret, format_size(file->info->pixels), sizeof(ret) - strlen(ret) - 1);
  460                 }
  461                 break;
  462             case 'r':
  463                 if (winwid) {
  464                     snprintf(buf, sizeof(buf), "%.1f", winwid->im_angle);
  465                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  466                 }
  467                 break;
  468             case 's':
  469                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  470                     snprintf(buf, sizeof(buf), "%d", file->info->size);
  471                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  472                 }
  473                 break;
  474             case 'S':
  475                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  476                     strncat(ret, format_size(file->info->size), sizeof(ret) - strlen(ret) - 1);
  477                 }
  478                 break;
  479             case 't':
  480                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  481                     strncat(ret, file->info->format, sizeof(ret) - strlen(ret) - 1);
  482                 }
  483                 break;
  484             case 'u':
  485                 f = current_file ? current_file : gib_list_find_by_data(filelist, file);
  486                 snprintf(buf, sizeof(buf), "%d", f ? gib_list_num(filelist, f) + 1 : 0);
  487                 strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  488                 break;
  489             case 'v':
  490                 strncat(ret, VERSION, sizeof(ret) - strlen(ret) - 1);
  491                 break;
  492             case 'V':
  493                 snprintf(buf, sizeof(buf), "%d", getpid());
  494                 strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  495                 break;
  496             case 'w':
  497                 if (file && (file->info || !feh_file_info_load(file, NULL))) {
  498                     snprintf(buf, sizeof(buf), "%d", file->info->width);
  499                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  500                 }
  501                 break;
  502             case 'z':
  503                 if (winwid) {
  504                     snprintf(buf, sizeof(buf), "%.2f", winwid->zoom);
  505                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  506                 } else {
  507                     strncat(ret, "1.00", sizeof(ret) - strlen(ret) - 1);
  508                 }
  509                 break;
  510             case 'Z':
  511                 if (winwid) {
  512                     snprintf(buf, sizeof(buf), "%f", winwid->zoom);
  513                     strncat(ret, buf, sizeof(ret) - strlen(ret) - 1);
  514                 }
  515                 break;
  516             case '%':
  517                 strncat(ret, "%", sizeof(ret) - strlen(ret) - 1);
  518                 break;
  519             default:
  520                 weprintf("Unrecognized format specifier %%%c", *c);
  521                 if ((strlen(ret) + 3) < sizeof(ret))
  522                     strncat(ret, c - 1, 2);
  523                 break;
  524             }
  525         } else if ((*c == '\\') && (*(c+1) != '\0') && ((strlen(ret) + 3) < sizeof(ret))) {
  526             c++;
  527             switch (*c) {
  528             case 'n':
  529                 strcat(ret, "\n");
  530                 break;
  531             default:
  532                 strncat(ret, c - 1, 2);
  533                 break;
  534             }
  535         } else if ((strlen(ret) + 2) < sizeof(ret))
  536             strncat(ret, c, 1);
  537     }
  538     if (filelist_tmppath != NULL)
  539         free(filelist_tmppath);
  540     return(ret);
  541 }
  542 
  543 void feh_filelist_image_remove(winwidget winwid, char do_delete)
  544 {
  545     if (winwid->type == WIN_TYPE_SLIDESHOW) {
  546         gib_list *doomed;
  547 
  548         doomed = current_file;
  549         /*
  550          * work around feh_list_jump exiting if ON_LAST_SLIDE_QUIT is set
  551          * and no further files are left (we need to delete first)
  552          */
  553         if (opt.on_last_slide == ON_LAST_SLIDE_QUIT && ! doomed->next && do_delete) {
  554             feh_file_rm_and_free(filelist, doomed);
  555             exit(0);
  556         }
  557         if (doomed->next) {
  558             slideshow_change_image(winwid, SLIDE_NEXT, 0);
  559         }
  560         else {
  561             slideshow_change_image(winwid, SLIDE_PREV, 0);
  562         }
  563         if (do_delete)
  564             filelist = feh_file_rm_and_free(filelist, doomed);
  565         else
  566             filelist = feh_file_remove_from_list(filelist, doomed);
  567         if (!filelist) {
  568             /* No more images. Game over ;-) */
  569             winwidget_destroy(winwid);
  570             return;
  571         }
  572         winwidget_render_image(winwid, 1, 0);
  573     } else if ((winwid->type == WIN_TYPE_SINGLE)
  574            || (winwid->type == WIN_TYPE_THUMBNAIL_VIEWER)) {
  575         if (do_delete)
  576             filelist = feh_file_rm_and_free(filelist, winwid->file);
  577         else
  578             filelist = feh_file_remove_from_list(filelist, winwid->file);
  579         winwid->file = NULL;
  580         winwidget_destroy(winwid);
  581     }
  582 }
  583 
  584 void slideshow_save_image(winwidget win)
  585 {
  586     char *tmpname;
  587     Imlib_Load_Error err;
  588     char *base_dir = "";
  589     if (opt.output_dir) {
  590         base_dir = estrjoin("", opt.output_dir, "/", NULL);
  591     }
  592 
  593     if (win->file) {
  594         tmpname = feh_unique_filename(base_dir, FEH_FILE(win->file->data)->name);
  595     } else if (mode) {
  596         char *tmp;
  597         tmp = estrjoin(".", mode, "png", NULL);
  598         tmpname = feh_unique_filename(base_dir, tmp);
  599         free(tmp);
  600     } else {
  601         tmpname = feh_unique_filename(base_dir, "noname.png");
  602     }
  603 
  604     if (opt.output_dir) {
  605         free(base_dir);
  606     }
  607 
  608     if (opt.verbose)
  609         fprintf(stderr, "saving image to filename '%s'\n", tmpname);
  610 
  611     gib_imlib_save_image_with_error_return(win->im, tmpname, &err);
  612 
  613     if (err)
  614         feh_imlib_print_load_error(tmpname, win, err);
  615 
  616     free(tmpname);
  617     return;
  618 }
  619 
  620 gib_list *feh_list_jump(gib_list * root, gib_list * l, int direction, int num)
  621 {
  622     int i;
  623     gib_list *ret = NULL;
  624 
  625     if (!root)
  626         return (NULL);
  627     if (!l)
  628         return (root);
  629 
  630     ret = l;
  631 
  632     for (i = 0; i < num; i++) {
  633         if (direction == FORWARD) {
  634             if (ret->next) {
  635                 ret = ret->next;
  636             } else {
  637                 if (opt.on_last_slide == ON_LAST_SLIDE_QUIT) {
  638                     exit(0);
  639                 }
  640                 if (opt.randomize) {
  641                     /* Randomize the filename order */
  642                     filelist = gib_list_randomize(filelist);
  643                     ret = filelist;
  644                 } else {
  645                     ret = root;
  646                 }
  647             }
  648         } else {
  649             if (ret->prev)
  650                 ret = ret->prev;
  651             else
  652                 ret = gib_list_last(ret);
  653         }
  654     }
  655     return (ret);
  656 }