- New option `-a`: Play animations at startup - Ctrl-Space toggles animation for all GIF files - Infinite loop for all animationsmaster
@@ -1,4 +1,4 @@ | |||||
VERSION = git-20140723 | VERSION = git-20140725 | ||||
PREFIX = /usr/local | PREFIX = /usr/local | ||||
MANPREFIX = $(PREFIX)/share/man | MANPREFIX = $(PREFIX)/share/man | ||||
@@ -68,6 +68,7 @@ of small previews is displayed, making it easy to choose an image to open. | |||||
**Command line options:** | **Command line options:** | ||||
-a Play animations of multi-frame images | |||||
-b Do not show info bar on bottom of window | -b Do not show info bar on bottom of window | ||||
-c Remove all orphaned cache files from thumbnail cache and exit | -c Remove all orphaned cache files from thumbnail cache and exit | ||||
-f Start in fullscreen mode | -f Start in fullscreen mode | ||||
@@ -117,7 +118,7 @@ of small previews is displayed, making it easy to choose an image to open. | |||||
p,Backspace Go [count] images backward | p,Backspace Go [count] images backward | ||||
[,] Go [count] * 10 images backward/forward | [,] Go [count] * 10 images backward/forward | ||||
Ctrl-n,p Go to the next/previous frame of a multi-frame image | Ctrl-n,p Go to the next/previous frame of a multi-frame image | ||||
Ctrl-Space Play/pause animation of a multi-frame image | Ctrl-Space Play/stop animations of multi-frame images | ||||
h,j,k,l Scroll image 1/5 of window width/height or [count] pixels | h,j,k,l Scroll image 1/5 of window width/height or [count] pixels | ||||
left/down/up/right (also with arrow keys) | left/down/up/right (also with arrow keys) | ||||
H,J,K,L Scroll to left/bottom/top/right image edge | H,J,K,L Scroll to left/bottom/top/right image edge | ||||
@@ -282,13 +282,17 @@ bool ci_navigate_frame(arg_t a) | |||||
bool ci_toggle_animation(arg_t a) | bool ci_toggle_animation(arg_t a) | ||||
{ | { | ||||
bool dirty = false; | |||||
img.multi.animate = !img.multi.animate; | |||||
if (img.multi.animate) { | if (img.multi.animate) { | ||||
reset_timeout(animate); | dirty = img_frame_animate(&img, true); | ||||
img.multi.animate = false; | |||||
} else if (img_frame_animate(&img, true)) { | |||||
set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); | set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); | ||||
} else { | |||||
reset_timeout(animate); | |||||
} | } | ||||
return true; | return dirty; | ||||
} | } | ||||
bool ci_scroll(arg_t a) | bool ci_scroll(arg_t a) | ||||
@@ -34,13 +34,6 @@ static const float zoom_levels[] = { | |||||
/* default slideshow delay (in sec, overwritten via -S option): */ | /* default slideshow delay (in sec, overwritten via -S option): */ | ||||
enum { SLIDESHOW_DELAY = 5 }; | enum { SLIDESHOW_DELAY = 5 }; | ||||
/* default settings for multi-frame gif images: */ | |||||
enum { | |||||
GIF_DELAY = 100, /* delay time (in ms) */ | |||||
GIF_AUTOPLAY = 1, /* autoplay when loaded [0/1] */ | |||||
GIF_LOOP = 0 /* loop? [0: no, 1: endless, -1: as specified in file] */ | |||||
}; | |||||
/* gamma correction: the user-visible ranges [-GAMMA_RANGE, 0] and | /* gamma correction: the user-visible ranges [-GAMMA_RANGE, 0] and | ||||
* (0, GAMMA_RANGE] are mapped to the ranges [0, 1], and (1, GAMMA_MAX]. | * (0, GAMMA_RANGE] are mapped to the ranges [0, 1], and (1, GAMMA_MAX]. | ||||
* */ | * */ | ||||
@@ -35,7 +35,7 @@ | |||||
#if HAVE_GIFLIB | #if HAVE_GIFLIB | ||||
#include <gif_lib.h> | #include <gif_lib.h> | ||||
enum { MIN_GIF_DELAY = 25 }; | enum { DEF_GIF_DELAY = 75 }; | ||||
#endif | #endif | ||||
float zoom_min; | float zoom_min; | ||||
@@ -85,8 +85,8 @@ void img_init(img_t *img, win_t *win) | |||||
img->aa = ANTI_ALIAS; | img->aa = ANTI_ALIAS; | ||||
img->alpha = ALPHA_LAYER; | img->alpha = ALPHA_LAYER; | ||||
img->multi.cap = img->multi.cnt = 0; | img->multi.cap = img->multi.cnt = 0; | ||||
img->multi.animate = false; | img->multi.animate = options->animate; | ||||
img->multi.length = img->multi.repeat = 0; | img->multi.length = 0; | ||||
img->cmod = imlib_create_color_modifier(); | img->cmod = imlib_create_color_modifier(); | ||||
img->gamma = MIN(MAX(options->gamma, -GAMMA_RANGE), GAMMA_RANGE); | 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) | |||||
s_malloc(sizeof(img_frame_t) * img->multi.cap); | s_malloc(sizeof(img_frame_t) * img->multi.cap); | ||||
} | } | ||||
img->multi.cnt = img->multi.sel = 0; | img->multi.cnt = img->multi.sel = 0; | ||||
img->multi.length = img->multi.repeat = 0; | img->multi.length = 0; | ||||
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 | #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 | ||||
gif = DGifOpenFileName(file->path, NULL); | gif = DGifOpenFileName(file->path, NULL); | ||||
@@ -194,16 +194,7 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||||
transp = -1; | transp = -1; | ||||
delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]); | delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]); | ||||
if (delay) | |||||
delay = MAX(delay, MIN_GIF_DELAY); | |||||
disposal = (unsigned int) ext[1] >> 2 & 0x7; | disposal = (unsigned int) ext[1] >> 2 & 0x7; | ||||
} else if (ext_code == APPLICATION_EXT_FUNC_CODE) { | |||||
if (ext[0] == 11 && memcmp(ext+1, "NETSCAPE2.0", 11) == 0) { | |||||
DGifGetExtensionNext(gif, &ext); | |||||
if (ext && ext[0] == 3 && ext[1] == 1) | |||||
img->multi.repeat = ((int) ext[3] << 8 | (int) ext[2]) - 1; | |||||
} | |||||
} | } | ||||
ext = NULL; | ext = NULL; | ||||
DGifGetExtensionNext(gif, &ext); | DGifGetExtensionNext(gif, &ext); | ||||
@@ -289,7 +280,7 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||||
img->multi.cap * sizeof(img_frame_t)); | img->multi.cap * sizeof(img_frame_t)); | ||||
} | } | ||||
img->multi.frames[img->multi.cnt].im = im; | img->multi.frames[img->multi.cnt].im = im; | ||||
img->multi.frames[img->multi.cnt].delay = delay ? delay : GIF_DELAY; | img->multi.frames[img->multi.cnt].delay = delay > 0 ? delay : DEF_GIF_DELAY; | ||||
img->multi.length += img->multi.frames[img->multi.cnt].delay; | img->multi.length += img->multi.frames[img->multi.cnt].delay; | ||||
img->multi.cnt++; | img->multi.cnt++; | ||||
} | } | ||||
@@ -308,12 +299,10 @@ bool img_load_gif(img_t *img, const fileinfo_t *file) | |||||
imlib_context_set_image(img->im); | imlib_context_set_image(img->im); | ||||
imlib_free_image(); | imlib_free_image(); | ||||
img->im = img->multi.frames[0].im; | img->im = img->multi.frames[0].im; | ||||
img->multi.animate = GIF_AUTOPLAY; | |||||
} else if (img->multi.cnt == 1) { | } else if (img->multi.cnt == 1) { | ||||
imlib_context_set_image(img->multi.frames[0].im); | imlib_context_set_image(img->multi.frames[0].im); | ||||
imlib_free_image(); | imlib_free_image(); | ||||
img->multi.cnt = 0; | img->multi.cnt = 0; | ||||
img->multi.animate = false; | |||||
} | } | ||||
imlib_context_set_image(img->im); | imlib_context_set_image(img->im); | ||||
@@ -841,21 +830,15 @@ bool img_frame_animate(img_t *img, bool restart) | |||||
return false; | return false; | ||||
if (img->multi.sel + 1 >= img->multi.cnt) { | if (img->multi.sel + 1 >= img->multi.cnt) { | ||||
if (restart || GIF_LOOP == 1) { | img_frame_goto(img, 0); | ||||
img_frame_goto(img, 0); | img->dirty = true; | ||||
} else if (GIF_LOOP == -1 && img->multi.repeat != 0) { | return true; | ||||
if (img->multi.repeat > 0) | |||||
img->multi.repeat--; | |||||
img_frame_goto(img, 0); | |||||
} else { | |||||
img->multi.animate = false; | |||||
return false; | |||||
} | |||||
} else if (!restart) { | } else if (!restart) { | ||||
img_frame_goto(img, img->multi.sel + 1); | img_frame_goto(img, img->multi.sel + 1); | ||||
img->dirty = true; | |||||
return true; | |||||
} else { | |||||
return false; | |||||
} | } | ||||
img->multi.animate = true; | |||||
img->dirty = true; | |||||
return true; | |||||
} | } | ||||
@@ -36,7 +36,6 @@ typedef struct { | |||||
int sel; | int sel; | ||||
bool animate; | bool animate; | ||||
int length; | int length; | ||||
int repeat; | |||||
} multi_img_t; | } multi_img_t; | ||||
typedef struct { | typedef struct { | ||||
@@ -51,7 +50,6 @@ typedef struct { | |||||
scalemode_t scalemode; | scalemode_t scalemode; | ||||
float zoom; | float zoom; | ||||
bool re; | |||||
bool checkpan; | bool checkpan; | ||||
bool dirty; | bool dirty; | ||||
bool aa; | bool aa; | ||||
@@ -33,7 +33,7 @@ const options_t *options = (const options_t*) &_options; | |||||
void print_usage(void) | void print_usage(void) | ||||
{ | { | ||||
printf("usage: sxiv [-bcfhioqrtvZ] [-G GAMMA] [-g GEOMETRY] [-n NUM] " | printf("usage: sxiv [-abcfhioqrtvZ] [-G GAMMA] [-g GEOMETRY] [-n NUM] " | ||||
"[-N NAME] [-S DELAY] [-s MODE] [-z ZOOM] FILES...\n"); | "[-N NAME] [-S DELAY] [-s MODE] [-z ZOOM] FILES...\n"); | ||||
} | } | ||||
@@ -55,6 +55,7 @@ void parse_options(int argc, char **argv) | |||||
_options.scalemode = SCALE_DOWN; | _options.scalemode = SCALE_DOWN; | ||||
_options.zoom = 1.0; | _options.zoom = 1.0; | ||||
_options.animate = false; | |||||
_options.gamma = 0; | _options.gamma = 0; | ||||
_options.slideshow = 0; | _options.slideshow = 0; | ||||
@@ -67,11 +68,14 @@ void parse_options(int argc, char **argv) | |||||
_options.thumb_mode = false; | _options.thumb_mode = false; | ||||
_options.clean_cache = false; | _options.clean_cache = false; | ||||
while ((opt = getopt(argc, argv, "bcfG:g:hin:N:oqrS:s:tvZz:")) != -1) { | while ((opt = getopt(argc, argv, "abcfG:g:hin:N:oqrS:s:tvZz:")) != -1) { | ||||
switch (opt) { | switch (opt) { | ||||
case '?': | case '?': | ||||
print_usage(); | print_usage(); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
case 'a': | |||||
_options.animate = true; | |||||
break; | |||||
case 'b': | case 'b': | ||||
_options.hide_bar = true; | _options.hide_bar = true; | ||||
break; | break; | ||||
@@ -34,6 +34,7 @@ typedef struct { | |||||
/* image: */ | /* image: */ | ||||
scalemode_t scalemode; | scalemode_t scalemode; | ||||
float zoom; | float zoom; | ||||
bool animate; | |||||
int gamma; | int gamma; | ||||
int slideshow; | int slideshow; | ||||
@@ -3,7 +3,7 @@ | |||||
sxiv \- Simple X Image Viewer | sxiv \- Simple X Image Viewer | ||||
.SH SYNOPSIS | .SH SYNOPSIS | ||||
.B sxiv | .B sxiv | ||||
.RB [ \-bcfhioqrtvZ ] | .RB [ \-abcfhioqrtvZ ] | ||||
.RB [ \-G | .RB [ \-G | ||||
.IR GAMMA ] | .IR GAMMA ] | ||||
.RB [ \-g | .RB [ \-g | ||||
@@ -31,6 +31,9 @@ Please note, that the fullscreen mode requires an EWMH/NetWM compliant window | |||||
manager. | manager. | ||||
.SH OPTIONS | .SH OPTIONS | ||||
.TP | .TP | ||||
.B \-a | |||||
Play animations of multi-frame images. | |||||
.TP | |||||
.B \-b | .B \-b | ||||
Do not show info bar on bottom of window. | Do not show info bar on bottom of window. | ||||
.TP | .TP | ||||
@@ -208,7 +211,7 @@ Go to the next frame of a multi-frame image. | |||||
Go to the previous frame of a multi-frame image. | Go to the previous frame of a multi-frame image. | ||||
.TP | .TP | ||||
.B Ctrl-Space | .B Ctrl-Space | ||||
Play/pause animation of a multi-frame image. | Play/stop animations of multi-frame images. | ||||
.SS Panning | .SS Panning | ||||
.TP | .TP | ||||
.BR h ", " Left | .BR h ", " Left | ||||