diff --git a/commands.c b/commands.c index 8a1c06a..4c9553e 100644 --- a/commands.c +++ b/commands.c @@ -35,6 +35,7 @@ void load_image(int); void redraw(); void reset_cursor(); void animate(); +void slideshow(); void set_timeout(timeout_f, int, int); void reset_timeout(timeout_f); @@ -57,6 +58,10 @@ int it_switch_mode(arg_t a) { tns_init(&tns, filecnt); img_close(&img, 0); reset_timeout(reset_cursor); + if (img.slideshow) { + img.slideshow = 0; + reset_timeout(slideshow); + } tns.sel = fileidx; tns.dirty = 1; mode = MODE_THUMB; @@ -168,12 +173,11 @@ int i_toggle_animation(arg_t a) { if (img.multi.animate) { reset_timeout(animate); img.multi.animate = 0; - return 0; } else { delay = img_frame_animate(&img, 1); set_timeout(animate, delay, 1); - return 1; } + return 1; } int it_move(arg_t a) { @@ -318,6 +322,46 @@ int i_rotate(arg_t a) { return 0; } +int i_toggle_slideshow(arg_t a) { + if (mode == MODE_IMAGE) { + if (img.slideshow) { + img.slideshow = 0; + reset_timeout(slideshow); + return 1; + } else if (fileidx + 1 < filecnt) { + img.slideshow = 1; + set_timeout(slideshow, img.ss_delay, 1); + return 1; + } + } + return 0; +} + +int i_adjust_slideshow(arg_t a) { + long d = (long) a; + int i, delays[] = { 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600 }; + + if (mode != MODE_IMAGE || !img.slideshow) + return 0; + + if (d < 0) { + for (i = ARRLEN(delays) - 2; i >= 0; i--) { + if (img.ss_delay > delays[i] * 1000) { + img.ss_delay = delays[i] * 1000; + return 1; + } + } + } else { + for (i = 1; i < ARRLEN(delays); i++) { + if (img.ss_delay < delays[i] * 1000) { + img.ss_delay = delays[i] * 1000; + return 1; + } + } + } + return 0; +} + int i_toggle_antialias(arg_t a) { if (mode == MODE_IMAGE) { img_toggle_antialias(&img); @@ -365,14 +409,14 @@ int it_shell_cmd(arg_t a) { n = mode == MODE_IMAGE ? fileidx : tns.sel; if (setenv("SXIV_IMG", files[n].path, 1) < 0) { - warn("could not change env.-variable: SXIV_IMG. command line was: %s", + warn("could not set env.-variable: SXIV_IMG. command line was: %s", cmdline); return 0; } if ((pid = fork()) == 0) { execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); - warn("could not exec: /bin/sh"); + warn("could not exec: /bin/sh. command line was: %s", cmdline); exit(1); } else if (pid < 0) { warn("could not fork. command line was: %s", cmdline); diff --git a/commands.h b/commands.h index 580ea82..e038246 100644 --- a/commands.h +++ b/commands.h @@ -57,6 +57,8 @@ int i_zoom(arg_t); int i_fit_to_win(arg_t); int i_fit_to_img(arg_t); int i_rotate(arg_t); +int i_toggle_slideshow(arg_t); +int i_adjust_slideshow(arg_t); int i_toggle_antialias(arg_t); int it_toggle_alpha(arg_t); int it_open_with(arg_t); diff --git a/config.def.h b/config.def.h index d5a9463..50cecb8 100644 --- a/config.def.h +++ b/config.def.h @@ -29,6 +29,9 @@ static const float zoom_levels[] = { 100.0, 150.0, 200.0, 400.0, 800.0 }; +/* default slideshow delay (in sec, overwritten via -S option): */ +enum { SLIDESHOW_DELAY = 5 }; + /* default settings for multi-frame gif images: */ enum { GIF_DELAY = 100, /* delay time (in ms) */ @@ -104,6 +107,11 @@ static const keymap_t keys[] = { { False, XK_less, i_rotate, (arg_t) DIR_LEFT }, { False, XK_greater, i_rotate, (arg_t) DIR_RIGHT }, + { False, XK_s, i_toggle_slideshow, (arg_t) None }, + { True, XK_plus, i_adjust_slideshow, (arg_t) +1 }, + { True, XK_equal, i_adjust_slideshow, (arg_t) +1 }, + { True, XK_minus, i_adjust_slideshow, (arg_t) -1 }, + { False, XK_a, i_toggle_antialias, (arg_t) None }, { False, XK_A, it_toggle_alpha, (arg_t) None }, diff --git a/image.c b/image.c index 20c4ff3..7402835 100644 --- a/image.c +++ b/image.c @@ -56,6 +56,8 @@ void img_init(img_t *img, win_t *win) { img->zoom = MIN(img->zoom, zoom_max); img->aa = options->aa; img->alpha = 1; + img->slideshow = 0; + img->ss_delay = SLIDESHOW_DELAY * 1000; } if (win) { @@ -651,7 +653,7 @@ int img_frame_animate(img_t *img, int restart) { return 0; if (img->multi.sel + 1 >= img->multi.cnt) { - if (restart || GIF_LOOP) { + if (restart || (GIF_LOOP && !img->slideshow)) { img_frame_goto(img, 0); } else { img->multi.animate = 0; @@ -660,7 +662,6 @@ int img_frame_animate(img_t *img, int restart) { } else if (!restart) { img_frame_goto(img, img->multi.sel + 1); } - img->multi.animate = 1; return img->multi.frames[img->multi.sel].delay; diff --git a/image.h b/image.h index 558e3c2..ddbdb9d 100644 --- a/image.h +++ b/image.h @@ -49,6 +49,9 @@ typedef struct { unsigned char aa; unsigned char alpha; + unsigned char slideshow; + int ss_delay; /* in ms */ + int x; int y; int w; diff --git a/main.c b/main.c index ebb6e7d..c96a030 100644 --- a/main.c +++ b/main.c @@ -53,6 +53,7 @@ typedef struct { void redraw(); void reset_cursor(); void animate(); +void slideshow(); appmode_t mode; img_t img; @@ -68,7 +69,8 @@ char win_title[TITLE_LEN]; timeout_t timeouts[] = { { { 0, 0 }, False, redraw }, { { 0, 0 }, False, reset_cursor }, - { { 0, 0 }, False, animate } + { { 0, 0 }, False, animate }, + { { 0, 0 }, False, slideshow }, }; void cleanup() { @@ -216,8 +218,10 @@ void load_image(int new) { void update_title() { int n; - float size; - const char *unit; + char sshow_info[16]; + char frame_info[16]; + float size, time; + const char *size_unit, *time_unit; if (mode == MODE_THUMB) { n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] %s", @@ -225,18 +229,27 @@ void update_title() { tns.cnt ? files[tns.sel].name : ""); } else { size = filesize; - size_readable(&size, &unit); + size_readable(&size, &size_unit); + + if (img.slideshow) { + time = img.ss_delay / 1000.0; + time_readable(&time, &time_unit); + snprintf(sshow_info, sizeof(sshow_info), "*%d%s* ", + (int) time, time_unit); + } else { + sshow_info[0] = '\0'; + } if (img.multi.cnt) - n = snprintf(win_title, TITLE_LEN, - "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) {%d/%d} %s", - fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w, - img.h, size, unit, img.multi.sel + 1, img.multi.cnt, - files[fileidx].name); + snprintf(frame_info, sizeof(frame_info), "{%d/%d} ", + img.multi.sel + 1, img.multi.cnt); else - n = snprintf(win_title, TITLE_LEN, - "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) %s", - fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w, - img.h, size, unit, files[fileidx].name); + frame_info[0] = '\0'; + + n = snprintf(win_title, TITLE_LEN, + "sxiv: [%d/%d] <%dx%d:%d%%> (%.2f%s) %s%s%s", + fileidx + 1, filecnt, img.w, img.h, + (int) (img.zoom * 100.0), size, size_unit, + sshow_info, frame_info, files[fileidx].name); } if (n >= TITLE_LEN) { @@ -248,10 +261,17 @@ void update_title() { } void redraw() { - if (mode == MODE_IMAGE) + if (mode == MODE_IMAGE) { img_render(&img, &win); - else + if (img.slideshow && !img.multi.animate) { + if (fileidx + 1 < filecnt) + set_timeout(slideshow, img.ss_delay, 1); + else + img.slideshow = 0; + } + } else { tns_render(&tns, &win); + } update_title(); reset_timeout(redraw); reset_cursor(); @@ -282,9 +302,19 @@ void animate() { int delay; delay = img_frame_animate(&img, 0); - if (delay) { + redraw(); + if (delay) set_timeout(animate, delay, 1); - redraw(); +} + +void slideshow() { + if (mode == MODE_IMAGE && !img.multi.animate) { + if (fileidx + 1 < filecnt) { + load_image(fileidx + 1); + redraw(); + } else { + img.slideshow = 0; + } } } diff --git a/options.c b/options.c index 8532be1..1e4a56c 100644 --- a/options.c +++ b/options.c @@ -54,23 +54,22 @@ void print_version() { } void parse_options(int argc, char **argv) { - float z; - int n, opt; + int opt, t; + _options.recursive = 0; _options.startnum = 0; _options.scalemode = SCALE_MODE; _options.zoom = 1.0; _options.aa = 1; - _options.thumbnails = 0; _options.fixed = 0; _options.fullscreen = 0; _options.geometry = NULL; _options.quiet = 0; + _options.thumbnails = 0; _options.clean_cache = 0; - _options.recursive = 0; while ((opt = getopt(argc, argv, "cdFfg:hn:pqrstvZz:")) != -1) { switch (opt) { @@ -96,12 +95,12 @@ void parse_options(int argc, char **argv) { print_usage(); exit(0); case 'n': - if (!sscanf(optarg, "%d", &n) || n < 1) { + if (!sscanf(optarg, "%d", &t) || t < 1) { fprintf(stderr, "sxiv: invalid argument for option -n: %s\n", optarg); exit(1); } else { - _options.startnum = n - 1; + _options.startnum = t - 1; } break; case 'p': @@ -128,12 +127,12 @@ void parse_options(int argc, char **argv) { break; case 'z': _options.scalemode = SCALE_ZOOM; - if (!sscanf(optarg, "%f", &z) || z < 0) { + if (!sscanf(optarg, "%d", &t) || t <= 0) { fprintf(stderr, "sxiv: invalid argument for option -z: %s\n", optarg); exit(1); } - _options.zoom = z / 100.0; + _options.zoom = (float) t / 100.0; break; } } diff --git a/options.h b/options.h index d32d37a..67ad926 100644 --- a/options.h +++ b/options.h @@ -23,23 +23,27 @@ #include "types.h" typedef struct { + /* file list: */ char **filenames; unsigned char from_stdin; + unsigned char recursive; int filecnt; int startnum; + /* image: */ scalemode_t scalemode; float zoom; unsigned char aa; - unsigned char thumbnails; + /* window: */ unsigned char fixed; unsigned char fullscreen; char *geometry; + /* misc flags: */ unsigned char quiet; + unsigned char thumbnails; unsigned char clean_cache; - unsigned char recursive; } options_t; extern const options_t *options; diff --git a/util.c b/util.c index bc7c2e1..99166f8 100644 --- a/util.c +++ b/util.c @@ -127,8 +127,17 @@ void size_readable(float *size, const char **unit) { const char *units[] = { "", "K", "M", "G" }; int i; - for (i = 0; i < ARRLEN(units) && *size > 1024; i++) - *size /= 1024; + for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++) + *size /= 1024.0; + *unit = units[MIN(i, ARRLEN(units) - 1)]; +} + +void time_readable(float *time, const char **unit) { + const char *units[] = { "s", "m", "h" }; + int i; + + for (i = 0; i < ARRLEN(units) && *time >= 60.0; i++) + *time /= 60.0; *unit = units[MIN(i, ARRLEN(units) - 1)]; } diff --git a/util.h b/util.h index cc4da88..8155613 100644 --- a/util.h +++ b/util.h @@ -65,6 +65,7 @@ void die(const char*, ...); ssize_t get_line(char**, size_t*, FILE*); void size_readable(float*, const char**); +void time_readable(float*, const char**); char* absolute_path(const char*);