nsxiv5105127
Added slideshow support
+136 −35
10 files changed
- M commands.c +48 −4
- M commands.h +2 −0
- M config.def.h +8 −0
- M image.c +3 −2
- M image.h +3 −0
- M main.c +47 −17
- M options.c +7 −8
- M options.h +6 −2
- M util.c +11 −2
- M util.h +1 −0
| @@ -35,6 +35,7 @@ void load_image(int); | |||
| 35 | 35 | void redraw(); | |
| 36 | 36 | void reset_cursor(); | |
| 37 | 37 | void animate(); | |
| 38 | + | void slideshow(); | |
| 38 | 39 | void set_timeout(timeout_f, int, int); | |
| 39 | 40 | void reset_timeout(timeout_f); | |
| 40 | 41 | ||
| @@ -57,6 +58,10 @@ int it_switch_mode(arg_t a) { | |||
| 57 | 58 | tns_init(&tns, filecnt); | |
| 58 | 59 | img_close(&img, 0); | |
| 59 | 60 | reset_timeout(reset_cursor); | |
| 61 | + | if (img.slideshow) { | |
| 62 | + | img.slideshow = 0; | |
| 63 | + | reset_timeout(slideshow); | |
| 64 | + | } | |
| 60 | 65 | tns.sel = fileidx; | |
| 61 | 66 | tns.dirty = 1; | |
| 62 | 67 | mode = MODE_THUMB; | |
| @@ -168,12 +173,11 @@ int i_toggle_animation(arg_t a) { | |||
| 168 | 173 | if (img.multi.animate) { | |
| 169 | 174 | reset_timeout(animate); | |
| 170 | 175 | img.multi.animate = 0; | |
| 171 | − | return 0; | |
| 172 | 176 | } else { | |
| 173 | 177 | delay = img_frame_animate(&img, 1); | |
| 174 | 178 | set_timeout(animate, delay, 1); | |
| 175 | − | return 1; | |
| 176 | 179 | } | |
| 180 | + | return 1; | |
| 177 | 181 | } | |
| 178 | 182 | ||
| 179 | 183 | int it_move(arg_t a) { | |
| @@ -318,6 +322,46 @@ int i_rotate(arg_t a) { | |||
| 318 | 322 | return 0; | |
| 319 | 323 | } | |
| 320 | 324 | ||
| 325 | + | int i_toggle_slideshow(arg_t a) { | |
| 326 | + | if (mode == MODE_IMAGE) { | |
| 327 | + | if (img.slideshow) { | |
| 328 | + | img.slideshow = 0; | |
| 329 | + | reset_timeout(slideshow); | |
| 330 | + | return 1; | |
| 331 | + | } else if (fileidx + 1 < filecnt) { | |
| 332 | + | img.slideshow = 1; | |
| 333 | + | set_timeout(slideshow, img.ss_delay, 1); | |
| 334 | + | return 1; | |
| 335 | + | } | |
| 336 | + | } | |
| 337 | + | return 0; | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | int i_adjust_slideshow(arg_t a) { | |
| 341 | + | long d = (long) a; | |
| 342 | + | int i, delays[] = { 1, 2, 3, 5, 10, 15, 20, 30, 60, 120, 180, 300, 600 }; | |
| 343 | + | ||
| 344 | + | if (mode != MODE_IMAGE || !img.slideshow) | |
| 345 | + | return 0; | |
| 346 | + | ||
| 347 | + | if (d < 0) { | |
| 348 | + | for (i = ARRLEN(delays) - 2; i >= 0; i--) { | |
| 349 | + | if (img.ss_delay > delays[i] * 1000) { | |
| 350 | + | img.ss_delay = delays[i] * 1000; | |
| 351 | + | return 1; | |
| 352 | + | } | |
| 353 | + | } | |
| 354 | + | } else { | |
| 355 | + | for (i = 1; i < ARRLEN(delays); i++) { | |
| 356 | + | if (img.ss_delay < delays[i] * 1000) { | |
| 357 | + | img.ss_delay = delays[i] * 1000; | |
| 358 | + | return 1; | |
| 359 | + | } | |
| 360 | + | } | |
| 361 | + | } | |
| 362 | + | return 0; | |
| 363 | + | } | |
| 364 | + | ||
| 321 | 365 | int i_toggle_antialias(arg_t a) { | |
| 322 | 366 | if (mode == MODE_IMAGE) { | |
| 323 | 367 | img_toggle_antialias(&img); | |
| @@ -365,14 +409,14 @@ int it_shell_cmd(arg_t a) { | |||
| 365 | 409 | n = mode == MODE_IMAGE ? fileidx : tns.sel; | |
| 366 | 410 | ||
| 367 | 411 | if (setenv("SXIV_IMG", files[n].path, 1) < 0) { | |
| 368 | − | warn("could not change env.-variable: SXIV_IMG. command line was: %s", | |
| 412 | + | warn("could not set env.-variable: SXIV_IMG. command line was: %s", | |
| 369 | 413 | cmdline); | |
| 370 | 414 | return 0; | |
| 371 | 415 | } | |
| 372 | 416 | ||
| 373 | 417 | if ((pid = fork()) == 0) { | |
| 374 | 418 | execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); | |
| 375 | − | warn("could not exec: /bin/sh"); | |
| 419 | + | warn("could not exec: /bin/sh. command line was: %s", cmdline); | |
| 376 | 420 | exit(1); | |
| 377 | 421 | } else if (pid < 0) { | |
| 378 | 422 | warn("could not fork. command line was: %s", cmdline); | |
| @@ -57,6 +57,8 @@ int i_zoom(arg_t); | |||
| 57 | 57 | int i_fit_to_win(arg_t); | |
| 58 | 58 | int i_fit_to_img(arg_t); | |
| 59 | 59 | int i_rotate(arg_t); | |
| 60 | + | int i_toggle_slideshow(arg_t); | |
| 61 | + | int i_adjust_slideshow(arg_t); | |
| 60 | 62 | int i_toggle_antialias(arg_t); | |
| 61 | 63 | int it_toggle_alpha(arg_t); | |
| 62 | 64 | int it_open_with(arg_t); | |
| @@ -29,6 +29,9 @@ static const float zoom_levels[] = { | |||
| 29 | 29 | 100.0, 150.0, 200.0, 400.0, 800.0 | |
| 30 | 30 | }; | |
| 31 | 31 | ||
| 32 | + | /* default slideshow delay (in sec, overwritten via -S option): */ | |
| 33 | + | enum { SLIDESHOW_DELAY = 5 }; | |
| 34 | + | ||
| 32 | 35 | /* default settings for multi-frame gif images: */ | |
| 33 | 36 | enum { | |
| 34 | 37 | GIF_DELAY = 100, /* delay time (in ms) */ | |
| @@ -104,6 +107,11 @@ static const keymap_t keys[] = { | |||
| 104 | 107 | { False, XK_less, i_rotate, (arg_t) DIR_LEFT }, | |
| 105 | 108 | { False, XK_greater, i_rotate, (arg_t) DIR_RIGHT }, | |
| 106 | 109 | ||
| 110 | + | { False, XK_s, i_toggle_slideshow, (arg_t) None }, | |
| 111 | + | { True, XK_plus, i_adjust_slideshow, (arg_t) +1 }, | |
| 112 | + | { True, XK_equal, i_adjust_slideshow, (arg_t) +1 }, | |
| 113 | + | { True, XK_minus, i_adjust_slideshow, (arg_t) -1 }, | |
| 114 | + | ||
| 107 | 115 | { False, XK_a, i_toggle_antialias, (arg_t) None }, | |
| 108 | 116 | { False, XK_A, it_toggle_alpha, (arg_t) None }, | |
| 109 | 117 | ||
| @@ -56,6 +56,8 @@ void img_init(img_t *img, win_t *win) { | |||
| 56 | 56 | img->zoom = MIN(img->zoom, zoom_max); | |
| 57 | 57 | img->aa = options->aa; | |
| 58 | 58 | img->alpha = 1; | |
| 59 | + | img->slideshow = 0; | |
| 60 | + | img->ss_delay = SLIDESHOW_DELAY * 1000; | |
| 59 | 61 | } | |
| 60 | 62 | ||
| 61 | 63 | if (win) { | |
| @@ -651,7 +653,7 @@ int img_frame_animate(img_t *img, int restart) { | |||
| 651 | 653 | return 0; | |
| 652 | 654 | ||
| 653 | 655 | if (img->multi.sel + 1 >= img->multi.cnt) { | |
| 654 | − | if (restart || GIF_LOOP) { | |
| 656 | + | if (restart || (GIF_LOOP && !img->slideshow)) { | |
| 655 | 657 | img_frame_goto(img, 0); | |
| 656 | 658 | } else { | |
| 657 | 659 | img->multi.animate = 0; | |
| @@ -660,7 +662,6 @@ int img_frame_animate(img_t *img, int restart) { | |||
| 660 | 662 | } else if (!restart) { | |
| 661 | 663 | img_frame_goto(img, img->multi.sel + 1); | |
| 662 | 664 | } | |
| 663 | − | ||
| 664 | 665 | img->multi.animate = 1; | |
| 665 | 666 | ||
| 666 | 667 | return img->multi.frames[img->multi.sel].delay; | |
| @@ -49,6 +49,9 @@ typedef struct { | |||
| 49 | 49 | unsigned char aa; | |
| 50 | 50 | unsigned char alpha; | |
| 51 | 51 | ||
| 52 | + | unsigned char slideshow; | |
| 53 | + | int ss_delay; /* in ms */ | |
| 54 | + | ||
| 52 | 55 | int x; | |
| 53 | 56 | int y; | |
| 54 | 57 | int w; | |
| @@ -53,6 +53,7 @@ typedef struct { | |||
| 53 | 53 | void redraw(); | |
| 54 | 54 | void reset_cursor(); | |
| 55 | 55 | void animate(); | |
| 56 | + | void slideshow(); | |
| 56 | 57 | ||
| 57 | 58 | appmode_t mode; | |
| 58 | 59 | img_t img; | |
| @@ -68,7 +69,8 @@ char win_title[TITLE_LEN]; | |||
| 68 | 69 | timeout_t timeouts[] = { | |
| 69 | 70 | { { 0, 0 }, False, redraw }, | |
| 70 | 71 | { { 0, 0 }, False, reset_cursor }, | |
| 71 | − | { { 0, 0 }, False, animate } | |
| 72 | + | { { 0, 0 }, False, animate }, | |
| 73 | + | { { 0, 0 }, False, slideshow }, | |
| 72 | 74 | }; | |
| 73 | 75 | ||
| 74 | 76 | void cleanup() { | |
| @@ -216,8 +218,10 @@ void load_image(int new) { | |||
| 216 | 218 | ||
| 217 | 219 | void update_title() { | |
| 218 | 220 | int n; | |
| 219 | − | float size; | |
| 220 | − | const char *unit; | |
| 221 | + | char sshow_info[16]; | |
| 222 | + | char frame_info[16]; | |
| 223 | + | float size, time; | |
| 224 | + | const char *size_unit, *time_unit; | |
| 221 | 225 | ||
| 222 | 226 | if (mode == MODE_THUMB) { | |
| 223 | 227 | n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] %s", | |
| @@ -225,18 +229,27 @@ void update_title() { | |||
| 225 | 229 | tns.cnt ? files[tns.sel].name : ""); | |
| 226 | 230 | } else { | |
| 227 | 231 | size = filesize; | |
| 228 | − | size_readable(&size, &unit); | |
| 232 | + | size_readable(&size, &size_unit); | |
| 233 | + | ||
| 234 | + | if (img.slideshow) { | |
| 235 | + | time = img.ss_delay / 1000.0; | |
| 236 | + | time_readable(&time, &time_unit); | |
| 237 | + | snprintf(sshow_info, sizeof(sshow_info), "*%d%s* ", | |
| 238 | + | (int) time, time_unit); | |
| 239 | + | } else { | |
| 240 | + | sshow_info[0] = '\0'; | |
| 241 | + | } | |
| 229 | 242 | if (img.multi.cnt) | |
| 230 | − | n = snprintf(win_title, TITLE_LEN, | |
| 231 | − | "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) {%d/%d} %s", | |
| 232 | − | fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w, | |
| 233 | − | img.h, size, unit, img.multi.sel + 1, img.multi.cnt, | |
| 234 | − | files[fileidx].name); | |
| 243 | + | snprintf(frame_info, sizeof(frame_info), "{%d/%d} ", | |
| 244 | + | img.multi.sel + 1, img.multi.cnt); | |
| 235 | 245 | else | |
| 236 | − | n = snprintf(win_title, TITLE_LEN, | |
| 237 | − | "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) %s", | |
| 238 | − | fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w, | |
| 239 | − | img.h, size, unit, files[fileidx].name); | |
| 246 | + | frame_info[0] = '\0'; | |
| 247 | + | ||
| 248 | + | n = snprintf(win_title, TITLE_LEN, | |
| 249 | + | "sxiv: [%d/%d] <%dx%d:%d%%> (%.2f%s) %s%s%s", | |
| 250 | + | fileidx + 1, filecnt, img.w, img.h, | |
| 251 | + | (int) (img.zoom * 100.0), size, size_unit, | |
| 252 | + | sshow_info, frame_info, files[fileidx].name); | |
| 240 | 253 | } | |
| 241 | 254 | ||
| 242 | 255 | if (n >= TITLE_LEN) { | |
| @@ -248,10 +261,17 @@ void update_title() { | |||
| 248 | 261 | } | |
| 249 | 262 | ||
| 250 | 263 | void redraw() { | |
| 251 | − | if (mode == MODE_IMAGE) | |
| 264 | + | if (mode == MODE_IMAGE) { | |
| 252 | 265 | img_render(&img, &win); | |
| 253 | − | else | |
| 266 | + | if (img.slideshow && !img.multi.animate) { | |
| 267 | + | if (fileidx + 1 < filecnt) | |
| 268 | + | set_timeout(slideshow, img.ss_delay, 1); | |
| 269 | + | else | |
| 270 | + | img.slideshow = 0; | |
| 271 | + | } | |
| 272 | + | } else { | |
| 254 | 273 | tns_render(&tns, &win); | |
| 274 | + | } | |
| 255 | 275 | update_title(); | |
| 256 | 276 | reset_timeout(redraw); | |
| 257 | 277 | reset_cursor(); | |
| @@ -282,9 +302,19 @@ void animate() { | |||
| 282 | 302 | int delay; | |
| 283 | 303 | ||
| 284 | 304 | delay = img_frame_animate(&img, 0); | |
| 285 | − | if (delay) { | |
| 305 | + | redraw(); | |
| 306 | + | if (delay) | |
| 286 | 307 | set_timeout(animate, delay, 1); | |
| 287 | − | redraw(); | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | void slideshow() { | |
| 311 | + | if (mode == MODE_IMAGE && !img.multi.animate) { | |
| 312 | + | if (fileidx + 1 < filecnt) { | |
| 313 | + | load_image(fileidx + 1); | |
| 314 | + | redraw(); | |
| 315 | + | } else { | |
| 316 | + | img.slideshow = 0; | |
| 317 | + | } | |
| 288 | 318 | } | |
| 289 | 319 | } | |
| 290 | 320 | ||
| @@ -54,23 +54,22 @@ void print_version() { | |||
| 54 | 54 | } | |
| 55 | 55 | ||
| 56 | 56 | void parse_options(int argc, char **argv) { | |
| 57 | − | float z; | |
| 58 | − | int n, opt; | |
| 57 | + | int opt, t; | |
| 59 | 58 | ||
| 59 | + | _options.recursive = 0; | |
| 60 | 60 | _options.startnum = 0; | |
| 61 | 61 | ||
| 62 | 62 | _options.scalemode = SCALE_MODE; | |
| 63 | 63 | _options.zoom = 1.0; | |
| 64 | 64 | _options.aa = 1; | |
| 65 | − | _options.thumbnails = 0; | |
| 66 | 65 | ||
| 67 | 66 | _options.fixed = 0; | |
| 68 | 67 | _options.fullscreen = 0; | |
| 69 | 68 | _options.geometry = NULL; | |
| 70 | 69 | ||
| 71 | 70 | _options.quiet = 0; | |
| 71 | + | _options.thumbnails = 0; | |
| 72 | 72 | _options.clean_cache = 0; | |
| 73 | − | _options.recursive = 0; | |
| 74 | 73 | ||
| 75 | 74 | while ((opt = getopt(argc, argv, "cdFfg:hn:pqrstvZz:")) != -1) { | |
| 76 | 75 | switch (opt) { | |
| @@ -96,12 +95,12 @@ void parse_options(int argc, char **argv) { | |||
| 96 | 95 | print_usage(); | |
| 97 | 96 | exit(0); | |
| 98 | 97 | case 'n': | |
| 99 | − | if (!sscanf(optarg, "%d", &n) || n < 1) { | |
| 98 | + | if (!sscanf(optarg, "%d", &t) || t < 1) { | |
| 100 | 99 | fprintf(stderr, "sxiv: invalid argument for option -n: %s\n", | |
| 101 | 100 | optarg); | |
| 102 | 101 | exit(1); | |
| 103 | 102 | } else { | |
| 104 | − | _options.startnum = n - 1; | |
| 103 | + | _options.startnum = t - 1; | |
| 105 | 104 | } | |
| 106 | 105 | break; | |
| 107 | 106 | case 'p': | |
| @@ -128,12 +127,12 @@ void parse_options(int argc, char **argv) { | |||
| 128 | 127 | break; | |
| 129 | 128 | case 'z': | |
| 130 | 129 | _options.scalemode = SCALE_ZOOM; | |
| 131 | − | if (!sscanf(optarg, "%f", &z) || z < 0) { | |
| 130 | + | if (!sscanf(optarg, "%d", &t) || t <= 0) { | |
| 132 | 131 | fprintf(stderr, "sxiv: invalid argument for option -z: %s\n", | |
| 133 | 132 | optarg); | |
| 134 | 133 | exit(1); | |
| 135 | 134 | } | |
| 136 | − | _options.zoom = z / 100.0; | |
| 135 | + | _options.zoom = (float) t / 100.0; | |
| 137 | 136 | break; | |
| 138 | 137 | } | |
| 139 | 138 | } | |
| @@ -23,23 +23,27 @@ | |||
| 23 | 23 | #include "types.h" | |
| 24 | 24 | ||
| 25 | 25 | typedef struct { | |
| 26 | + | /* file list: */ | |
| 26 | 27 | char **filenames; | |
| 27 | 28 | unsigned char from_stdin; | |
| 29 | + | unsigned char recursive; | |
| 28 | 30 | int filecnt; | |
| 29 | 31 | int startnum; | |
| 30 | 32 | ||
| 33 | + | /* image: */ | |
| 31 | 34 | scalemode_t scalemode; | |
| 32 | 35 | float zoom; | |
| 33 | 36 | unsigned char aa; | |
| 34 | − | unsigned char thumbnails; | |
| 35 | 37 | ||
| 38 | + | /* window: */ | |
| 36 | 39 | unsigned char fixed; | |
| 37 | 40 | unsigned char fullscreen; | |
| 38 | 41 | char *geometry; | |
| 39 | 42 | ||
| 43 | + | /* misc flags: */ | |
| 40 | 44 | unsigned char quiet; | |
| 45 | + | unsigned char thumbnails; | |
| 41 | 46 | unsigned char clean_cache; | |
| 42 | − | unsigned char recursive; | |
| 43 | 47 | } options_t; | |
| 44 | 48 | ||
| 45 | 49 | extern const options_t *options; | |
| @@ -127,8 +127,17 @@ void size_readable(float *size, const char **unit) { | |||
| 127 | 127 | const char *units[] = { "", "K", "M", "G" }; | |
| 128 | 128 | int i; | |
| 129 | 129 | ||
| 130 | − | for (i = 0; i < ARRLEN(units) && *size > 1024; i++) | |
| 131 | − | *size /= 1024; | |
| 130 | + | for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++) | |
| 131 | + | *size /= 1024.0; | |
| 132 | + | *unit = units[MIN(i, ARRLEN(units) - 1)]; | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | void time_readable(float *time, const char **unit) { | |
| 136 | + | const char *units[] = { "s", "m", "h" }; | |
| 137 | + | int i; | |
| 138 | + | ||
| 139 | + | for (i = 0; i < ARRLEN(units) && *time >= 60.0; i++) | |
| 140 | + | *time /= 60.0; | |
| 132 | 141 | *unit = units[MIN(i, ARRLEN(units) - 1)]; | |
| 133 | 142 | } | |
| 134 | 143 | ||
| @@ -65,6 +65,7 @@ void die(const char*, ...); | |||
| 65 | 65 | ssize_t get_line(char**, size_t*, FILE*); | |
| 66 | 66 | ||
| 67 | 67 | void size_readable(float*, const char**); | |
| 68 | + | void time_readable(float*, const char**); | |
| 68 | 69 | ||
| 69 | 70 | char* absolute_path(const char*); | |
| 70 | 71 | ||