nsxiv5e48191
Revised handling of GIF animations
- New option `-a`: Play animations at startup - Ctrl-Space toggles animation for all GIF files - Infinite loop for all animations
+36 −49
9 files changed
- M Makefile +1 −1
- M README.md +2 −1
- M commands.c +8 −4
- M config.def.h +0 −7
- M image.c +13 −30
- M image.h +0 −2
- M options.c +6 −2
- M options.h +1 −0
- M sxiv.1 +5 −2
| @@ -1,4 +1,4 @@ | |||
| 1 | − | VERSION = git-20140723 | |
| 1 | + | VERSION = git-20140725 | |
| 2 | 2 | ||
| 3 | 3 | PREFIX = /usr/local | |
| 4 | 4 | MANPREFIX = $(PREFIX)/share/man | |
| @@ -68,6 +68,7 @@ of small previews is displayed, making it easy to choose an image to open. | |||
| 68 | 68 | ||
| 69 | 69 | **Command line options:** | |
| 70 | 70 | ||
| 71 | + | -a Play animations of multi-frame images | |
| 71 | 72 | -b Do not show info bar on bottom of window | |
| 72 | 73 | -c Remove all orphaned cache files from thumbnail cache and exit | |
| 73 | 74 | -f Start in fullscreen mode | |
| @@ -117,7 +118,7 @@ of small previews is displayed, making it easy to choose an image to open. | |||
| 117 | 118 | p,Backspace Go [count] images backward | |
| 118 | 119 | [,] Go [count] * 10 images backward/forward | |
| 119 | 120 | Ctrl-n,p Go to the next/previous frame of a multi-frame image | |
| 120 | − | Ctrl-Space Play/pause animation of a multi-frame image | |
| 121 | + | Ctrl-Space Play/stop animations of multi-frame images | |
| 121 | 122 | h,j,k,l Scroll image 1/5 of window width/height or [count] pixels | |
| 122 | 123 | left/down/up/right (also with arrow keys) | |
| 123 | 124 | H,J,K,L Scroll to left/bottom/top/right image edge | |
| @@ -282,13 +282,17 @@ bool ci_navigate_frame(arg_t a) | |||
| 282 | 282 | ||
| 283 | 283 | bool ci_toggle_animation(arg_t a) | |
| 284 | 284 | { | |
| 285 | + | bool dirty = false; | |
| 286 | + | ||
| 287 | + | img.multi.animate = !img.multi.animate; | |
| 288 | + | ||
| 285 | 289 | if (img.multi.animate) { | |
| 286 | − | reset_timeout(animate); | |
| 287 | − | img.multi.animate = false; | |
| 288 | − | } else if (img_frame_animate(&img, true)) { | |
| 290 | + | dirty = img_frame_animate(&img, true); | |
| 289 | 291 | set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); | |
| 292 | + | } else { | |
| 293 | + | reset_timeout(animate); | |
| 290 | 294 | } | |
| 291 | − | return true; | |
| 295 | + | return dirty; | |
| 292 | 296 | } | |
| 293 | 297 | ||
| 294 | 298 | bool ci_scroll(arg_t a) | |
| @@ -34,13 +34,6 @@ static const float zoom_levels[] = { | |||
| 34 | 34 | /* default slideshow delay (in sec, overwritten via -S option): */ | |
| 35 | 35 | enum { SLIDESHOW_DELAY = 5 }; | |
| 36 | 36 | ||
| 37 | − | /* default settings for multi-frame gif images: */ | |
| 38 | − | enum { | |
| 39 | − | GIF_DELAY = 100, /* delay time (in ms) */ | |
| 40 | − | GIF_AUTOPLAY = 1, /* autoplay when loaded [0/1] */ | |
| 41 | − | GIF_LOOP = 0 /* loop? [0: no, 1: endless, -1: as specified in file] */ | |
| 42 | − | }; | |
| 43 | − | ||
| 44 | 37 | /* gamma correction: the user-visible ranges [-GAMMA_RANGE, 0] and | |
| 45 | 38 | * (0, GAMMA_RANGE] are mapped to the ranges [0, 1], and (1, GAMMA_MAX]. | |
| 46 | 39 | * */ | |
| @@ -35,7 +35,7 @@ | |||
| 35 | 35 | ||
| 36 | 36 | #if HAVE_GIFLIB | |
| 37 | 37 | #include <gif_lib.h> | |
| 38 | − | enum { MIN_GIF_DELAY = 25 }; | |
| 38 | + | enum { DEF_GIF_DELAY = 75 }; | |
| 39 | 39 | #endif | |
| 40 | 40 | ||
| 41 | 41 | float zoom_min; | |
| @@ -85,8 +85,8 @@ void img_init(img_t *img, win_t *win) | |||
| 85 | 85 | img->aa = ANTI_ALIAS; | |
| 86 | 86 | img->alpha = ALPHA_LAYER; | |
| 87 | 87 | img->multi.cap = img->multi.cnt = 0; | |
| 88 | − | img->multi.animate = false; | |
| 89 | − | img->multi.length = img->multi.repeat = 0; | |
| 88 | + | img->multi.animate = options->animate; | |
| 89 | + | img->multi.length = 0; | |
| 90 | 90 | ||
| 91 | 91 | img->cmod = imlib_create_color_modifier(); | |
| 92 | 92 | img->gamma = MIN(MAX(options->gamma, -GAMMA_RANGE), GAMMA_RANGE); | |
| @@ -160,7 +160,7 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||
| 160 | 160 | s_malloc(sizeof(img_frame_t) * img->multi.cap); | |
| 161 | 161 | } | |
| 162 | 162 | img->multi.cnt = img->multi.sel = 0; | |
| 163 | − | img->multi.length = img->multi.repeat = 0; | |
| 163 | + | img->multi.length = 0; | |
| 164 | 164 | ||
| 165 | 165 | #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 | |
| 166 | 166 | gif = DGifOpenFileName(file->path, NULL); | |
| @@ -194,16 +194,7 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||
| 194 | 194 | transp = -1; | |
| 195 | 195 | ||
| 196 | 196 | delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]); | |
| 197 | − | if (delay) | |
| 198 | − | delay = MAX(delay, MIN_GIF_DELAY); | |
| 199 | − | ||
| 200 | 197 | disposal = (unsigned int) ext[1] >> 2 & 0x7; | |
| 201 | − | } else if (ext_code == APPLICATION_EXT_FUNC_CODE) { | |
| 202 | − | if (ext[0] == 11 && memcmp(ext+1, "NETSCAPE2.0", 11) == 0) { | |
| 203 | − | DGifGetExtensionNext(gif, &ext); | |
| 204 | − | if (ext && ext[0] == 3 && ext[1] == 1) | |
| 205 | − | img->multi.repeat = ((int) ext[3] << 8 | (int) ext[2]) - 1; | |
| 206 | − | } | |
| 207 | 198 | } | |
| 208 | 199 | ext = NULL; | |
| 209 | 200 | DGifGetExtensionNext(gif, &ext); | |
| @@ -289,7 +280,7 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||
| 289 | 280 | img->multi.cap * sizeof(img_frame_t)); | |
| 290 | 281 | } | |
| 291 | 282 | img->multi.frames[img->multi.cnt].im = im; | |
| 292 | − | img->multi.frames[img->multi.cnt].delay = delay ? delay : GIF_DELAY; | |
| 283 | + | img->multi.frames[img->multi.cnt].delay = delay > 0 ? delay : DEF_GIF_DELAY; | |
| 293 | 284 | img->multi.length += img->multi.frames[img->multi.cnt].delay; | |
| 294 | 285 | img->multi.cnt++; | |
| 295 | 286 | } | |
| @@ -308,12 +299,10 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||
| 308 | 299 | imlib_context_set_image(img->im); | |
| 309 | 300 | imlib_free_image(); | |
| 310 | 301 | img->im = img->multi.frames[0].im; | |
| 311 | − | img->multi.animate = GIF_AUTOPLAY; | |
| 312 | 302 | } else if (img->multi.cnt == 1) { | |
| 313 | 303 | imlib_context_set_image(img->multi.frames[0].im); | |
| 314 | 304 | imlib_free_image(); | |
| 315 | 305 | img->multi.cnt = 0; | |
| 316 | − | img->multi.animate = false; | |
| 317 | 306 | } | |
| 318 | 307 | ||
| 319 | 308 | imlib_context_set_image(img->im); | |
| @@ -841,21 +830,15 @@ bool img_frame_animate(img_t *img, bool restart) | |||
| 841 | 830 | return false; | |
| 842 | 831 | ||
| 843 | 832 | if (img->multi.sel + 1 >= img->multi.cnt) { | |
| 844 | − | if (restart || GIF_LOOP == 1) { | |
| 845 | − | img_frame_goto(img, 0); | |
| 846 | − | } else if (GIF_LOOP == -1 && img->multi.repeat != 0) { | |
| 847 | − | if (img->multi.repeat > 0) | |
| 848 | − | img->multi.repeat--; | |
| 849 | − | img_frame_goto(img, 0); | |
| 850 | − | } else { | |
| 851 | − | img->multi.animate = false; | |
| 852 | − | return false; | |
| 853 | − | } | |
| 833 | + | img_frame_goto(img, 0); | |
| 834 | + | img->dirty = true; | |
| 835 | + | return true; | |
| 854 | 836 | } else if (!restart) { | |
| 855 | 837 | img_frame_goto(img, img->multi.sel + 1); | |
| 838 | + | img->dirty = true; | |
| 839 | + | return true; | |
| 840 | + | } else { | |
| 841 | + | return false; | |
| 856 | 842 | } | |
| 857 | − | img->multi.animate = true; | |
| 858 | − | img->dirty = true; | |
| 859 | − | ||
| 860 | − | return true; | |
| 861 | 843 | } | |
| 844 | + | ||
| @@ -36,7 +36,6 @@ typedef struct { | |||
| 36 | 36 | int sel; | |
| 37 | 37 | bool animate; | |
| 38 | 38 | int length; | |
| 39 | − | int repeat; | |
| 40 | 39 | } multi_img_t; | |
| 41 | 40 | ||
| 42 | 41 | typedef struct { | |
| @@ -51,7 +50,6 @@ typedef struct { | |||
| 51 | 50 | scalemode_t scalemode; | |
| 52 | 51 | float zoom; | |
| 53 | 52 | ||
| 54 | − | bool re; | |
| 55 | 53 | bool checkpan; | |
| 56 | 54 | bool dirty; | |
| 57 | 55 | bool aa; | |
| @@ -33,7 +33,7 @@ const options_t *options = (const options_t*) &_options; | |||
| 33 | 33 | ||
| 34 | 34 | void print_usage(void) | |
| 35 | 35 | { | |
| 36 | − | printf("usage: sxiv [-bcfhioqrtvZ] [-G GAMMA] [-g GEOMETRY] [-n NUM] " | |
| 36 | + | printf("usage: sxiv [-abcfhioqrtvZ] [-G GAMMA] [-g GEOMETRY] [-n NUM] " | |
| 37 | 37 | "[-N NAME] [-S DELAY] [-s MODE] [-z ZOOM] FILES...\n"); | |
| 38 | 38 | } | |
| 39 | 39 | ||
| @@ -55,6 +55,7 @@ void parse_options(int argc, char **argv) | |||
| 55 | 55 | ||
| 56 | 56 | _options.scalemode = SCALE_DOWN; | |
| 57 | 57 | _options.zoom = 1.0; | |
| 58 | + | _options.animate = false; | |
| 58 | 59 | _options.gamma = 0; | |
| 59 | 60 | _options.slideshow = 0; | |
| 60 | 61 | ||
| @@ -67,11 +68,14 @@ void parse_options(int argc, char **argv) | |||
| 67 | 68 | _options.thumb_mode = false; | |
| 68 | 69 | _options.clean_cache = false; | |
| 69 | 70 | ||
| 70 | − | while ((opt = getopt(argc, argv, "bcfG:g:hin:N:oqrS:s:tvZz:")) != -1) { | |
| 71 | + | while ((opt = getopt(argc, argv, "abcfG:g:hin:N:oqrS:s:tvZz:")) != -1) { | |
| 71 | 72 | switch (opt) { | |
| 72 | 73 | case '?': | |
| 73 | 74 | print_usage(); | |
| 74 | 75 | exit(EXIT_FAILURE); | |
| 76 | + | case 'a': | |
| 77 | + | _options.animate = true; | |
| 78 | + | break; | |
| 75 | 79 | case 'b': | |
| 76 | 80 | _options.hide_bar = true; | |
| 77 | 81 | break; | |
| @@ -34,6 +34,7 @@ typedef struct { | |||
| 34 | 34 | /* image: */ | |
| 35 | 35 | scalemode_t scalemode; | |
| 36 | 36 | float zoom; | |
| 37 | + | bool animate; | |
| 37 | 38 | int gamma; | |
| 38 | 39 | int slideshow; | |
| 39 | 40 | ||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | sxiv \- Simple X Image Viewer | |
| 4 | 4 | .SH SYNOPSIS | |
| 5 | 5 | .B sxiv | |
| 6 | − | .RB [ \-bcfhioqrtvZ ] | |
| 6 | + | .RB [ \-abcfhioqrtvZ ] | |
| 7 | 7 | .RB [ \-G | |
| 8 | 8 | .IR GAMMA ] | |
| 9 | 9 | .RB [ \-g | |
| @@ -31,6 +31,9 @@ Please note, that the fullscreen mode requires an EWMH/NetWM compliant window | |||
| 31 | 31 | manager. | |
| 32 | 32 | .SH OPTIONS | |
| 33 | 33 | .TP | |
| 34 | + | .B \-a | |
| 35 | + | Play animations of multi-frame images. | |
| 36 | + | .TP | |
| 34 | 37 | .B \-b | |
| 35 | 38 | Do not show info bar on bottom of window. | |
| 36 | 39 | .TP | |
| @@ -208,7 +211,7 @@ Go to the next frame of a multi-frame image. | |||
| 208 | 211 | Go to the previous frame of a multi-frame image. | |
| 209 | 212 | .TP | |
| 210 | 213 | .B Ctrl-Space | |
| 211 | − | Play/pause animation of a multi-frame image. | |
| 214 | + | Play/stop animations of multi-frame images. | |
| 212 | 215 | .SS Panning | |
| 213 | 216 | .TP | |
| 214 | 217 | .BR h ", " Left | |