diff options
-rw-r--r-- | .github/workflows/c.yml | 10 | ||||
-rw-r--r-- | ChangeLog | 42 | ||||
-rw-r--r-- | man/feh.pre | 62 | ||||
-rw-r--r-- | src/feh.h | 10 | ||||
-rw-r--r-- | src/filelist.c | 11 | ||||
-rw-r--r-- | src/imlib.c | 194 | ||||
-rw-r--r-- | src/index.c | 2 | ||||
-rw-r--r-- | src/menu.c | 17 | ||||
-rw-r--r-- | src/slideshow.c | 93 | ||||
-rw-r--r-- | src/thumbnail.c | 2 | ||||
-rw-r--r-- | src/timers.c | 33 | ||||
-rw-r--r-- | src/timers.h | 2 | ||||
-rw-r--r-- | src/winwidget.c | 7 | ||||
-rw-r--r-- | test/feh.t | 2 |
14 files changed, 390 insertions, 97 deletions
diff --git a/.github/workflows/c.yml b/.github/workflows/c.yml index 941075e..e7a4207 100644 --- a/.github/workflows/c.yml +++ b/.github/workflows/c.yml @@ -21,16 +21,18 @@ jobs: steps: - uses: actions/checkout@v2 + - name: APT + run: sudo apt-get -y update - name: Install Dependencies - run: sudo apt install build-essential libx11-dev libxt-dev libimlib2-dev libtest-command-perl libtest-simple-perl + run: sudo apt-get -y install build-essential libx11-dev libxt-dev libimlib2-dev libtest-command-perl libtest-simple-perl - name: Install libcurl if: matrix.curl - run: sudo apt install libcurl4-openssl-dev + run: sudo apt-get -y install libcurl4-openssl-dev - name: Install libexif if: matrix.exif - run: sudo apt install libexif-dev + run: sudo apt-get -y install libexif-dev - name: Install Xinerama if: matrix.xinerama - run: sudo apt install libxinerama-dev + run: sudo apt-get -y install libxinerama-dev - name: Build and Test run: for inotify in 0 1; do for verscmp in 0 1; do make curl=${{ matrix.curl }} exif=${{ matrix.exif }} inotify=$inotify verscmp=$verscmp xinerama=${{ matrix.xinerama }} && make test && make clean; done; done @@ -1,3 +1,45 @@ +Sat, 09 Jan 2021 12:28:06 +0100 Daniel Friesel <derf+feh@finalrewind.org> + +* Release v3.6.2 + * Fix save_filelist not respecting --output-dir + * Fix file descriptor leak when attempting to load truncated image files. + The issue was introduced in v3.6. + +Sun, 06 Dec 2020 08:34:15 +0100 Daniel Friesel <derf+feh@finalrewind.org> + +* Release v3.6.1 + * Fix excessive memory consumption when showing long-running slideshows + with thousands to tens of thousands of images and feh has been compiled + with exif=1 (see https://github.com/derf/feh/issues/553) + * Fix memory leak when showing long-running slideshows with relatively few + images and feh has been compiled with exif=1 (ibid.) + * Fix memory leak when reloading an image and feh has been compiled with + exif=1 + * Fix memory leak in --draw-exif + * Fix memory leak when reloading HTTP files with --no-conversion-cache + +Mon, 30 Nov 2020 19:44:47 +0100 Daniel Friesel <derf+feh@finalrewind.org> +* Release v3.6 + * Add flip and rotate options to the menu + * Improve unloadable image detection time (e.g. for large video files) by + checking a file's header before passing it to Imlib2. For rarely used + image formats, there is a very small chance that an image which could be + loaded by feh 3.5 is reported as unloadable by feh 3.6 due to this + change. Set FEH_SKIP_MAGIC=1 to bypass the header check in this case. See + <https://phab.enlightenment.org/T8739> and + <https://github.com/derf/feh/issues/505> for details. + + +Sat, 29 Aug 2020 08:49:08 +0200 Daniel Friesel <derf+feh@finalrewind.org> + +* Release v3.5 + * Enable --version-sort on systems without strverscmp support. This + works by bundling the strverscmp of musl libc with feh and using it + when feh is compiled without the verscmp flag (i.e., when the system + libc does not provide the verscmp function). Patch by Tim van der Molen + * Add %a format specifier (slideshow state: "playing" / "paused") + * Fix crashes when combining --reload and --multiwindow + Fri, 29 May 2020 23:52:35 +0200 Daniel Friesel <derf+feh@finalrewind.org> * Release v3.4.1 diff --git a/man/feh.pre b/man/feh.pre index da6fafa..0d78390 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -13,6 +13,7 @@ . .Nm .Op Ar options +.Op Cm -- .Op Ar files | Ar directories | Ar URLs ... . . @@ -29,13 +30,13 @@ Compile-time switches in this build: .Bl -bullet -compact . .It -remote file support: libcurl $MAN_CURL$ +libcurl remote file support $MAN_CURL$ . .It Xinerama multi-monitor support $MAN_XINERAMA$ . .It -builtin EXIF reader $MAN_EXIF$ +libexif builtin EXIF reader $MAN_EXIF$ . .It inotify-based auto-reload of changed files $MAN_INOTIFY$ @@ -162,6 +163,23 @@ Use .Cm --conversion-timeout Ar timeout with a non-negative value to enable support for these formats. . +.Pp +. +As Imlib2 may take several seconds to determine whether it can load a file or +not +.Pq e.g. when attempting to open a large video , +.Nm +checks each file's header before loading it. +If it looks like an image, it is passed on to Imlib2, otherwise, it is +assumed to be unloadable. +This greatly improves performance when working in directories with mixed files +.Pq i.e., directories which do not exclusively contain image files . +If you think that Imlib2 can load a file which +.Nm +has determined to be likely not an image, set the environment variable +.Qq FEH_SKIP_MAGIC +to pass all files directly to Imlib2, bypassing the header check. +The environment variable's value does not matter, it just needs to be set. . .Sh OPTIONS . @@ -218,7 +236,7 @@ Use format specifiers to refer to image info, see .Sx FORMAT SPECIFIERS for details. Example usage: -.Qq feh -A Qo mv ~/images/%N Qc * . +.Qq feh -A Qo mv %F ~/images/%N Qc * . . .It Cm --action1 No .. Cm --action9 Oo Ar flag Oc Ns Oo [ Ar title ] Oc Ns Ar action . @@ -236,6 +254,10 @@ disabled by a preceding .Cm --reload=0 option. . +.Pp +. +Automatic reload is not supported in montage, index, or thumbnail mode. +. .It Cm --auto-rotate . .Pq optional feature, $MAN_EXIF$ in this build @@ -581,7 +603,8 @@ When loading images via HTTP, ImageMagick or dcraw, .Nm will only load/convert them once and re-use the cached file on subsequent slideshow passes. -This option disables the cache. It is also disabled when +This option disables the cache. +It is also disabled when .Cm --reload is used. Use it if you rely on frequently changing files loaded via one of these @@ -649,7 +672,7 @@ Save files to .Ar directory when using .Cm --keep-http -or the save_image command. +or the save_image or save_filelist command. By default, files are saved in the current working directory. . .It Cm -p , --preload @@ -708,6 +731,7 @@ will continue to try loading it. .Pp . Setting this option causes inotify-based auto-reload to be disabled. +Reload is not supported in montage, index, or thumbnail mode. . .It Cm -n , --reverse . @@ -1558,7 +1582,10 @@ will keep zoom and X, Y offset when switching images. .It L Bq save_filelist . Save the current filelist as -.Qq feh_PID_ID_filelist +.Qq feh_PID_ID_filelist . +It is saved in the directory specified by +.Cm --output-dir , +if set, and in the current working directory otherwise. . .It m Bq toggle_menu . @@ -1594,7 +1621,10 @@ Useful for webcams .It s Bq save_image . Save the current image as -.Qq feh_PID_ID_FILENAME +.Qq feh_PID_ID_FILENAME . +It is saved in the directory specified by +.Cm --output-dir , +if set, and in the current working directory otherwise. . .It w Bq size_to_image . @@ -2118,23 +2148,11 @@ Please include the feh version steps to reproduce the bug and, if necessary, images to reproduce it. . . -.Sh FUTURE PLANS -. -Plans for the following releases: -. -.Bl -bullet -compact -. -.It -Make zoom options more intuitive -. -.El -. -. .Sh LICENSE . Copyright (C) 1999, 2000 by Paul Duncan. -Copyright (C) 1999, 2000 by Tom Gilbert (and various contributors). -Copyright (C) 2010-2020 by Daniel Friesel (and even more contributors). +Copyright (C) 1999, 2000 by Tom Gilbert and contributors. +Copyright (C) 2010-2020 by Daniel Friesel and contributors. . .Pp . @@ -2176,5 +2194,5 @@ Tom Gilbert . .Pp . -See also: +Website: https://feh.finalrewind.org @@ -115,6 +115,14 @@ enum slide_change { SLIDE_NEXT, SLIDE_PREV, SLIDE_RAND, SLIDE_FIRST, SLIDE_LAST, SLIDE_JUMP_PREV_DIR }; +enum feh_load_error { + LOAD_ERROR_IMLIB = 0, + LOAD_ERROR_IMAGEMAGICK, + LOAD_ERROR_CURL, + LOAD_ERROR_DCRAW, + LOAD_ERROR_MAGICBYTES +}; + #define INPLACE_EDIT_FLIP -1 #define INPLACE_EDIT_MIRROR -2 @@ -172,7 +180,7 @@ void feh_display_status(char stat); void real_loadables_mode(int loadable); void feh_reload_image(winwidget w, int resize, int force_new); void feh_filelist_image_remove(winwidget winwid, char do_delete); -void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err); +void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum feh_load_error feh_err); void slideshow_save_image(winwidget win); void feh_edit_inplace(winwidget w, int orientation); void feh_edit_inplace_lossless(winwidget w, int orientation); diff --git a/src/filelist.c b/src/filelist.c index 361ac19..ae8d7b2 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -659,8 +659,17 @@ char *feh_absolute_path(char *path) void feh_save_filelist() { char *tmpname; + char *base_dir = ""; - tmpname = feh_unique_filename("", "filelist"); + if (opt.output_dir) { + base_dir = estrjoin("", opt.output_dir, "/", NULL); + } + + tmpname = feh_unique_filename(base_dir, "filelist"); + + if (opt.output_dir) { + free(base_dir); + } if (opt.verbose) fprintf(stderr, "saving filelist to filename '%s'\n", tmpname); diff --git a/src/imlib.c b/src/imlib.c index e06a813..9ee4c08 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -164,11 +164,31 @@ int feh_load_image_char(Imlib_Image * im, char *filename) return(i); } -void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) +void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum feh_load_error feh_err) { if (err == IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS) eprintf("%s - Out of file descriptors while loading", file); else if (!opt.quiet || w) { + switch (feh_err) { + case LOAD_ERROR_IMLIB: + // handled in the next switch/case statement + break; + case LOAD_ERROR_IMAGEMAGICK: + im_weprintf(w, "%s - No ImageMagick loader for that file format", file); + break; + case LOAD_ERROR_CURL: + im_weprintf(w, "%s - libcurl was unable to retrieve the file", file); + break; + case LOAD_ERROR_DCRAW: + im_weprintf(w, "%s - Unable to open preview via dcraw", file); + break; + case LOAD_ERROR_MAGICBYTES: + im_weprintf(w, "%s - Does not look like an image (magic bytes missing)", file); + break; + } + if (feh_err != LOAD_ERROR_IMLIB) { + return; + } switch (err) { case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: im_weprintf(w, "%s - File does not exist", file); @@ -215,9 +235,104 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) } } +/* + * This is a workaround for an Imlib2 regression, causing unloadable image + * detection to be excessively slow (and, thus, causing feh to hang for a while + * when encountering an unloadable image). We use magic byte detection to + * avoid calling Imlib2 for files it probably cannot handle. See + * <https://phab.enlightenment.org/T8739> and + * <https://github.com/derf/feh/issues/505>. + * + * Note that this drops support for bz2-compressed files, unless + * FEH_SKIP_MAGIC is set + */ +int feh_is_image(feh_file * file) +{ + unsigned char buf[16]; + FILE *fh = fopen(file->filename, "r"); + if (!fh) { + return 0; + } + if (fread(buf, 1, 16, fh) != 16) { + fclose(fh); + return 0; + } + fclose(fh); + + if (buf[0] == 0xff && buf[1] == 0xd8) { + // JPEG + return 1; + } + if (!memcmp(buf, "\x89PNG\x0d\x0a\x1a\x0a", 8)) { + // PNG + return 1; + } + if (buf[0] == 'A' && buf[1] == 'R' && buf[2] == 'G' && buf[3] == 'B') { + // ARGB + return 1; + } + if (buf[0] == 'B' && buf[1] == 'M') { + // BMP + return 1; + } + if (!memcmp(buf, "farbfeld", 8)) { + // farbfeld + return 1; + } + if (buf[0] == 'G' && buf[1] == 'I' && buf[2] == 'F') { + // GIF + return 1; + } + if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] <= 0x02 && buf[3] == 0x00) { + // ICO + return 1; + } + if (!memcmp(buf, "FORM", 4)) { + // Amiga IFF ILBM + return 1; + } + if (buf[0] == 'P' && buf[1] >= '1' && buf[1] <= '7') { + // PNM et al. + return 1; + } + if (strstr(file->filename, ".tga")) { + // TGA + return 1; + } + if (!memcmp(buf, "II\x2a\x00", 4) || !memcmp(buf, "MM\x00\x2a", 4)) { + // TIFF + return 1; + } + if (!memcmp(buf, "RIFF", 4)) { + // might be webp + return 1; + } + if (!memcmp(buf + 4, "ftyphei", 7) || !memcmp(buf + 4, "ftypmif1", 8)) { + // HEIC/HEIF - note that this is only supported in imlib2-heic. Ordinary + // imlib2 releases do not support heic/heif images as of 2021-01. + return 1; + } + buf[15] = 0; + if (strstr((char *)buf, "XPM")) { + // XPM + return 1; + } + if (strstr(file->filename, ".bz2") || strstr(file->filename, ".gz")) { + // Imlib2 supports compressed images. It relies on the filename to + // determine the appropriate loader and does not use magic bytes here. + return 1; + } + // moved to the end as this variable won't be set in most cases + if (getenv("FEH_SKIP_MAGIC")) { + return 1; + } + return 0; +} + int feh_load_image(Imlib_Image * im, feh_file * file) { Imlib_Load_Error err = IMLIB_LOAD_ERROR_NONE; + enum feh_load_error feh_err = LOAD_ERROR_IMLIB; enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK, SRC_DCRAW } image_source = SRC_IMLIB; char *tmpname = NULL; char *real_filename = NULL; @@ -230,23 +345,37 @@ int feh_load_image(Imlib_Image * im, feh_file * file) if (path_is_url(file->filename)) { image_source = SRC_HTTP; - if ((tmpname = feh_http_load_image(file->filename)) == NULL) + if ((tmpname = feh_http_load_image(file->filename)) == NULL) { + feh_err = LOAD_ERROR_CURL; err = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST; + } } - else if (opt.conversion_timeout >= 0 && feh_file_is_raw(file->filename)) { - image_source = SRC_DCRAW; - tmpname = feh_dcraw_load_image(file->filename); - if (!tmpname) + else { + if (feh_is_image(file)) { + *im = imlib_load_image_with_error_return(file->filename, &err); + } else { + feh_err = LOAD_ERROR_MAGICBYTES; err = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; + } } - else - *im = imlib_load_image_with_error_return(file->filename, &err); if (opt.conversion_timeout >= 0 && ( (err == IMLIB_LOAD_ERROR_UNKNOWN) || (err == IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT))) { - image_source = SRC_MAGICK; - tmpname = feh_magick_load_image(file->filename); + if (feh_file_is_raw(file->filename)) { + image_source = SRC_DCRAW; + tmpname = feh_dcraw_load_image(file->filename); + if (!tmpname) { + feh_err = LOAD_ERROR_DCRAW; + } + } else { + image_source = SRC_MAGICK; + feh_err = LOAD_ERROR_IMLIB; + tmpname = feh_magick_load_image(file->filename); + if (!tmpname) { + feh_err = LOAD_ERROR_IMAGEMAGICK; + } + } } if (tmpname) { @@ -269,7 +398,14 @@ int feh_load_image(Imlib_Image * im, feh_file * file) file->filename = real_filename; #ifdef HAVE_LIBEXIF - file->ed = exif_get_data(tmpname); + /* + * if we're called from within feh_reload_image, file->ed is already + * populated. + */ + if (file->ed) { + exif_data_unref(file->ed); + } + file->ed = exif_data_new_from_file(tmpname); #endif } if (!opt.use_conversion_cache && ((image_source != SRC_HTTP) || !opt.keep_http)) @@ -279,8 +415,19 @@ int feh_load_image(Imlib_Image * im, feh_file * file) // add_file_to_rm_filelist duplicates tmpname add_file_to_rm_filelist(tmpname); - if (image_source != SRC_HTTP && !opt.use_conversion_cache) + if (!opt.use_conversion_cache) free(tmpname); + } else if (im) { +#ifdef HAVE_LIBEXIF + /* + * if we're called from within feh_reload_image, file->ed is already + * populated. + */ + if (file->ed) { + exif_data_unref(file->ed); + } + file->ed = exif_data_new_from_file(file->filename); +#endif } if ((err) || (!im)) { @@ -288,7 +435,7 @@ int feh_load_image(Imlib_Image * im, feh_file * file) fputs("\n", stderr); reset_output = 1; } - feh_imlib_print_load_error(file->filename, NULL, err); + feh_print_load_error(file->filename, NULL, err, feh_err); D(("Load *failed*\n")); return(0); } @@ -305,14 +452,12 @@ int feh_load_image(Imlib_Image * im, feh_file * file) #ifdef HAVE_LIBEXIF int orientation = 0; - ExifData *exifData = exif_data_new_from_file(file->filename); - if (exifData) { - ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); - ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); + if (file->ed) { + ExifByteOrder byteOrder = exif_data_get_byte_order(file->ed); + ExifEntry *exifEntry = exif_data_get_entry(file->ed, EXIF_TAG_ORIENTATION); if (exifEntry && opt.auto_rotate) orientation = exif_get_short(exifEntry->data, byteOrder); } - file->ed = exifData; if (orientation == 2) gib_imlib_image_flip_horizontal(*im); @@ -430,11 +575,9 @@ static int feh_file_is_raw(char *filename) } if (childpid == 0) { - if (opt.quiet) { - int devnull = open("/dev/null", O_WRONLY); - dup2(devnull, 1); - dup2(devnull, 2); - } + int devnull = open("/dev/null", O_WRONLY); + dup2(devnull, 1); + dup2(devnull, 2); execlp("dcraw", "dcraw", "-i", filename, NULL); _exit(1); } else { @@ -1087,6 +1230,7 @@ void feh_draw_exif(winwidget w) info_buf[i], IMLIB_TEXT_TO_RIGHT, 0, 0, 0, 255); gib_imlib_text_draw(im, fn, NULL, 1, (i * line_height) + 1, info_buf[i], IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + free(info_buf[i]); } @@ -1417,8 +1561,8 @@ void feh_edit_inplace(winwidget w, int op) FEH_FILE(w->file->data)->filename, &err); gib_imlib_free_image(old); if (err) - feh_imlib_print_load_error(FEH_FILE(w->file->data)->filename, - w, err); + feh_print_load_error(FEH_FILE(w->file->data)->filename, + w, err, LOAD_ERROR_IMLIB); feh_reload_image(w, 1, 1); } else { /* diff --git a/src/index.c b/src/index.c index 3633c96..85a3ee8 100644 --- a/src/index.c +++ b/src/index.c @@ -332,7 +332,7 @@ void init_index_mode(void) gib_imlib_save_image_with_error_return(im_main, output_buf, &err); if (err) { - feh_imlib_print_load_error(output_buf, im_main, err); + feh_print_load_error(output_buf, im_main, err, LOAD_ERROR_IMLIB); } else if (opt.verbose) { int tw, th; @@ -80,6 +80,8 @@ enum { CB_OPT_FREEZE_WINDOW, CB_OPT_FULLSCREEN, CB_EDIT_ROTATE, + CB_EDIT_MIRROR, + CB_EDIT_FLIP, CB_OPT_AUTO_ZOOM, CB_OPT_KEEP_ZOOM_VP }; @@ -920,7 +922,12 @@ void feh_menu_init_main(void) feh_menu_add_entry(m, "Reload", NULL, CB_RELOAD, 0, NULL); feh_menu_add_entry(m, "Save Image", NULL, CB_SAVE_IMAGE, 0, NULL); feh_menu_add_entry(m, "Save List", NULL, CB_SAVE_FILELIST, 0, NULL); - feh_menu_add_entry(m, "Edit in Place", "EDIT", 0, 0, NULL); + if (opt.edit) { + feh_menu_add_entry(m, "Edit in Place", "EDIT", 0, 0, NULL); + } + else { + feh_menu_add_entry(m, "Change View", "EDIT", 0, 0, NULL); + } feh_menu_add_entry(m, "Background", "BACKGROUND", 0, 0, NULL); feh_menu_add_entry(m, NULL, NULL, 0, 0, NULL); feh_menu_add_entry(m, "Hide", NULL, CB_REMOVE, 0, NULL); @@ -963,6 +970,8 @@ void feh_menu_init_common() feh_menu_add_entry(m, "Rotate 90 CW", NULL, CB_EDIT_ROTATE, 1, NULL); feh_menu_add_entry(m, "Rotate 180", NULL, CB_EDIT_ROTATE, 2, NULL); feh_menu_add_entry(m, "Rotate 90 CCW", NULL, CB_EDIT_ROTATE, 3, NULL); + feh_menu_add_entry(m, "Mirror", NULL, CB_EDIT_MIRROR, 0, NULL); + feh_menu_add_entry(m, "Flip", NULL, CB_EDIT_FLIP, 0, NULL); menu_bg = feh_menu_new(); menu_bg->name = estrdup("BACKGROUND"); @@ -1309,6 +1318,12 @@ void feh_menu_cb(feh_menu * m, feh_menu_item * i, int action, unsigned short dat case CB_EDIT_ROTATE: feh_edit_inplace(m->fehwin, data); break; + case CB_EDIT_MIRROR: + feh_edit_inplace(m->fehwin, INPLACE_EDIT_MIRROR); + break; + case CB_EDIT_FLIP: + feh_edit_inplace(m->fehwin, INPLACE_EDIT_FLIP); + break; case CB_SAVE_IMAGE: slideshow_save_image(m->fehwin); break; diff --git a/src/slideshow.c b/src/slideshow.c index 03e8e06..3a3cd0a 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -135,47 +135,54 @@ void cb_reload_timer(void *data) winwidget w = (winwidget) data; - /* save the current filename for refinding it in new list */ - current_filename = estrdup(FEH_FILE(current_file->data)->filename); + /* + * 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); - 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)); - } - - if (!(filelist_len = gib_list_length(filelist))) { - eprintf("No files found to reload."); - } + 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)); + } + + if (!(filelist_len = gib_list_length(filelist))) { + eprintf("No files found to reload."); + } - feh_prepare_filelist(); + feh_prepare_filelist(); - /* 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; - } + /* 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; + } - free(current_filename); + free(current_filename); - if (!current_file) - current_file = filelist; - w->file = current_file; + if (!current_file) + current_file = filelist; + w->file = current_file; + } feh_reload_image(w, 1, 0); feh_add_unique_timer(cb_reload_timer, w, opt.reload); @@ -218,6 +225,18 @@ void slideshow_change_image(winwidget winwid, int change, int render) /* 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); @@ -619,7 +638,7 @@ void slideshow_save_image(winwidget win) gib_imlib_save_image_with_error_return(win->im, tmpname, &err); if (err) - feh_imlib_print_load_error(tmpname, win, err); + feh_print_load_error(tmpname, win, err, LOAD_ERROR_IMLIB); free(tmpname); return; diff --git a/src/thumbnail.c b/src/thumbnail.c index 41bd1a0..e7b05a8 100644 --- a/src/thumbnail.c +++ b/src/thumbnail.c @@ -392,7 +392,7 @@ void init_thumbnail_mode(void) } gib_imlib_save_image_with_error_return(td.im_main, output_buf, &err); if (err) { - feh_imlib_print_load_error(output_buf, td.im_main, err); + feh_print_load_error(output_buf, td.im_main, err, LOAD_ERROR_IMLIB); } else if (opt.verbose) { int tw, th; diff --git a/src/timers.c b/src/timers.c index 4bdd64e..b2cdbc7 100644 --- a/src/timers.c +++ b/src/timers.c @@ -58,7 +58,37 @@ double feh_get_time(void) return((double) timev.tv_sec + (((double) timev.tv_usec) / 1000000)); } -void feh_remove_timer(char *name) +void feh_remove_timer_by_data(void *data) +{ + fehtimer ft, ptr, pptr; + + D(("removing timer for %p\n", data)); + pptr = NULL; + ptr = first_timer; + while (ptr) { + D(("Stepping through event list\n")); + ft = ptr; + if (ft->data == data) { + D(("Found it. Removing\n")); + if (pptr) + pptr->next = ft->next; + else + first_timer = ft->next; + if (ft->next) + ft->next->in += ft->in; + if (ft->name) + free(ft->name); + if (ft) + free(ft); + return; + } + pptr = ptr; + ptr = ptr->next; + } + return; +} + +static void feh_remove_timer(char *name) { fehtimer ft, ptr, pptr; @@ -88,6 +118,7 @@ void feh_remove_timer(char *name) return; } + void feh_add_timer(void (*func) (void *data), void *data, double in, char *name) { fehtimer ft, ptr, pptr; diff --git a/src/timers.h b/src/timers.h index a4243ca..e95d9b5 100644 --- a/src/timers.h +++ b/src/timers.h @@ -37,7 +37,7 @@ struct __fehtimer { void feh_handle_timer(void); double feh_get_time(void); -void feh_remove_timer(char *name); +void feh_remove_timer_by_data(void *data); void feh_add_timer(void (*func) (void *data), void *data, double in, char *name); void feh_add_unique_timer(void (*func) (void *data), void *data, double in); diff --git a/src/winwidget.c b/src/winwidget.c index 696f3db..37031ec 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -29,6 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "winwidget.h" #include "options.h" #include "events.h" +#include "timers.h" #ifdef HAVE_INOTIFY #include <sys/inotify.h> @@ -694,6 +695,9 @@ void winwidget_destroy(winwidget winwid) #ifdef HAVE_INOTIFY winwidget_inotify_remove(winwid); #endif + if (opt.reload > 0 && opt.multiwindow) { + feh_remove_timer_by_data(winwid); + } winwidget_destroy_xwin(winwid); if (winwid->name) free(winwid->name); @@ -1031,8 +1035,9 @@ void winwidget_rename(winwidget winwid, char *newname) void winwidget_free_image(winwidget w) { - if (w->im) + if (w->im) { gib_imlib_free_image(w->im); + } w->im = NULL; w->im_w = 0; w->im_h = 0; @@ -47,7 +47,7 @@ if ( $version =~ m{ Compile-time \s switches : \s .* help }ox ) { } my $re_warning - = qr{${feh_name} WARNING: test/fail/... \- No Imlib2 loader for that file format\n}; + = qr{${feh_name} WARNING: test/fail/... \- Does not look like an image \(magic bytes missing\)\n}; my $re_loadable = qr{test/ok/...}; my $re_unloadable = qr{test/fail/...}; my $re_list_action = qr{test/ok/... 16x16}; |