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
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								commands.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								commands.c
									
									
									
									
									
								
							@@ -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].
 | 
				
			||||||
 * */
 | 
					 * */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								image.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								image.c
									
									
									
									
									
								
							@@ -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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								image.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								image.h
									
									
									
									
									
								
							@@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								sxiv.1
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								sxiv.1
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user