| @@ -22,10 +22,14 @@ |
| 22 | 22 | | #include <stdlib.h> |
| 23 | 23 | | #include <stdio.h> |
| 24 | 24 | | #include <string.h> |
| 25 | + | #include <fcntl.h> |
| 25 | 26 | | #include <unistd.h> |
| 27 | + | #include <errno.h> |
| 28 | + | #include <signal.h> |
| 26 | 29 | | #include <sys/select.h> |
| 27 | 30 | | #include <sys/stat.h> |
| 28 | 31 | | #include <sys/time.h> |
| 32 | + | #include <sys/wait.h> |
| 29 | 33 | | #include <X11/keysym.h> |
| 30 | 34 | | |
| 31 | 35 | | #include "types.h" |
| @@ -38,8 +42,6 @@ |
| 38 | 42 | | #include "config.h" |
| 39 | 43 | | |
| 40 | 44 | | enum { |
| 41 | | − | BAR_L_LEN = 512, |
| 42 | | − | BAR_R_LEN = 64, |
| 43 | 45 | | FILENAME_CNT = 1024, |
| 44 | 46 | | TITLE_LEN = 256 |
| 45 | 47 | | }; |
| @@ -70,12 +72,11 @@ int prefix; |
| 70 | 72 | | bool resized = false; |
| 71 | 73 | | |
| 72 | 74 | | const char * const INFO_SCRIPT = ".sxiv/exec/image-info"; |
| 73 | | − | char *info_script; |
| 74 | | − | |
| 75 | 75 | | struct { |
| 76 | | − | char l[BAR_L_LEN]; |
| 77 | | − | char r[BAR_R_LEN]; |
| 78 | | − | } bar; |
| 76 | + | char *script; |
| 77 | + | int fd; |
| 78 | + | unsigned int i, lastsep; |
| 79 | + | } info; |
| 79 | 80 | | |
| 80 | 81 | | timeout_t timeouts[] = { |
| 81 | 82 | | { { 0, 0 }, false, redraw }, |
| @@ -212,35 +213,66 @@ bool check_timeouts(struct timeval *t) |
| 212 | 213 | | return tmin > 0; |
| 213 | 214 | | } |
| 214 | 215 | | |
| 216 | + | void open_info(void) |
| 217 | + | { |
| 218 | + | static pid_t pid; |
| 219 | + | int pfd[2]; |
| 220 | + | |
| 221 | + | win.bar.l[0] = '\0'; |
| 222 | + | |
| 223 | + | if (info.fd != -1) { |
| 224 | + | close(info.fd); |
| 225 | + | kill(pid, SIGTERM); |
| 226 | + | while (waitpid(-1, NULL, WNOHANG) > 0); |
| 227 | + | info.fd = -1; |
| 228 | + | } |
| 229 | + | if (info.script == NULL || pipe(pfd) < 0) |
| 230 | + | return; |
| 231 | + | |
| 232 | + | pid = fork(); |
| 233 | + | if (pid > 0) { |
| 234 | + | close(pfd[1]); |
| 235 | + | fcntl(pfd[0], F_SETFL, O_NONBLOCK); |
| 236 | + | info.fd = pfd[0]; |
| 237 | + | info.i = info.lastsep = 0; |
| 238 | + | } else if (pid == 0) { |
| 239 | + | close(pfd[0]); |
| 240 | + | dup2(pfd[1], 1); |
| 241 | + | execl(info.script, info.script, files[fileidx].name, NULL); |
| 242 | + | } |
| 243 | + | } |
| 244 | + | |
| 215 | 245 | | void read_info(void) |
| 216 | 246 | | { |
| 217 | | − | char cmd[4096]; |
| 218 | | − | FILE *outp; |
| 219 | | − | int c, i = 0, n = sizeof(bar.l) - 1; |
| 220 | | − | bool lastsep = false; |
| 221 | | − | |
| 222 | | − | if (info_script != NULL) { |
| 223 | | − | snprintf(cmd, sizeof(cmd), "%s \"%s\"", info_script, files[fileidx].name); |
| 224 | | − | outp = popen(cmd, "r"); |
| 225 | | − | if (outp == NULL) |
| 247 | + | ssize_t i, n; |
| 248 | + | char buf[BAR_L_LEN]; |
| 249 | + | |
| 250 | + | while (true) { |
| 251 | + | n = read(info.fd, buf, sizeof(buf)); |
| 252 | + | if (n < 0 && errno == EAGAIN) |
| 253 | + | return; |
| 254 | + | else if (n == 0) |
| 226 | 255 | | goto end; |
| 227 | | − | while (i < n && (c = fgetc(outp)) != EOF) { |
| 228 | | − | if (c == '\n') { |
| 229 | | − | if (!lastsep) { |
| 230 | | − | bar.l[i++] = ' '; |
| 231 | | − | lastsep = true; |
| 256 | + | for (i = 0; i < n; i++) { |
| 257 | + | if (buf[i] == '\n') { |
| 258 | + | if (info.lastsep == 0) { |
| 259 | + | win.bar.l[info.i++] = ' '; |
| 260 | + | info.lastsep = 1; |
| 232 | 261 | | } |
| 233 | 262 | | } else { |
| 234 | | − | bar.l[i++] = c; |
| 235 | | − | lastsep = false; |
| 263 | + | win.bar.l[info.i++] = buf[i]; |
| 264 | + | info.lastsep = 0; |
| 236 | 265 | | } |
| 266 | + | if (info.i + 1 == sizeof(win.bar.l)) |
| 267 | + | goto end; |
| 237 | 268 | | } |
| 238 | | − | pclose(outp); |
| 239 | 269 | | } |
| 240 | 270 | | end: |
| 241 | | − | if (lastsep) |
| 242 | | − | i--; |
| 243 | | − | bar.l[i] = '\0'; |
| 271 | + | info.i -= info.lastsep; |
| 272 | + | win.bar.l[info.i] = '\0'; |
| 273 | + | win_update_bar(&win); |
| 274 | + | info.fd = -1; |
| 275 | + | while (waitpid(-1, NULL, WNOHANG) > 0); |
| 244 | 276 | | } |
| 245 | 277 | | |
| 246 | 278 | | void load_image(int new) |
| @@ -261,7 +293,7 @@ void load_image(int new) |
| 261 | 293 | | alternate = fileidx; |
| 262 | 294 | | fileidx = new; |
| 263 | 295 | | |
| 264 | | − | read_info(); |
| 296 | + | open_info(); |
| 265 | 297 | | |
| 266 | 298 | | if (img.multi.cnt > 0 && img.multi.animate) |
| 267 | 299 | | set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); |
| @@ -271,9 +303,10 @@ void load_image(int new) |
| 271 | 303 | | |
| 272 | 304 | | void update_info(void) |
| 273 | 305 | | { |
| 274 | | − | unsigned int i, fn, fw, n, len = sizeof(bar.r); |
| 275 | 306 | | int sel; |
| 276 | | − | char *t = bar.r, title[TITLE_LEN]; |
| 307 | + | unsigned int i, fn, fw, n; |
| 308 | + | unsigned int llen = sizeof(win.bar.l), rlen = sizeof(win.bar.r); |
| 309 | + | char *lt = win.bar.l, *rt = win.bar.r, title[TITLE_LEN]; |
| 277 | 310 | | bool ow_info; |
| 278 | 311 | | |
| 279 | 312 | | for (fw = 0, i = filecnt; i > 0; fw++, i /= 10); |
| @@ -283,39 +316,37 @@ void update_info(void) |
| 283 | 316 | | win_set_title(&win, "sxiv"); |
| 284 | 317 | | |
| 285 | 318 | | if (tns.cnt == filecnt) { |
| 286 | | − | n = snprintf(t, len, "%0*d/%d", fw, sel + 1, filecnt); |
| 319 | + | n = snprintf(rt, rlen, "%0*d/%d", fw, sel + 1, filecnt); |
| 287 | 320 | | ow_info = true; |
| 288 | 321 | | } else { |
| 289 | | − | snprintf(bar.l, sizeof(bar.l), "Loading... %0*d/%d", |
| 290 | | − | fw, tns.cnt, filecnt); |
| 291 | | − | bar.r[0] = '\0'; |
| 322 | + | snprintf(lt, llen, "Loading... %0*d/%d", fw, tns.cnt, filecnt); |
| 323 | + | rt[0] = '\0'; |
| 292 | 324 | | ow_info = false; |
| 293 | 325 | | } |
| 294 | 326 | | } else { |
| 295 | 327 | | snprintf(title, sizeof(title), "sxiv - %s", files[sel].name); |
| 296 | 328 | | win_set_title(&win, title); |
| 297 | 329 | | |
| 298 | | − | n = snprintf(t, len, "%3d%% ", (int) (img.zoom * 100.0)); |
| 330 | + | n = snprintf(rt, rlen, "%3d%% ", (int) (img.zoom * 100.0)); |
| 299 | 331 | | if (img.multi.cnt > 0) { |
| 300 | 332 | | for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); |
| 301 | | − | n += snprintf(t + n, len - n, "(%0*d/%d) ", |
| 333 | + | n += snprintf(rt + n, rlen - n, "(%0*d/%d) ", |
| 302 | 334 | | fn, img.multi.sel + 1, img.multi.cnt); |
| 303 | 335 | | } |
| 304 | | − | n += snprintf(t + n, len - n, "%0*d/%d", fw, sel + 1, filecnt); |
| 305 | | − | ow_info = bar.l[0] == '\0'; |
| 336 | + | n += snprintf(rt + n, rlen - n, "%0*d/%d", fw, sel + 1, filecnt); |
| 337 | + | ow_info = info.script == NULL; |
| 306 | 338 | | } |
| 307 | 339 | | if (ow_info) { |
| 308 | 340 | | fn = strlen(files[sel].name); |
| 309 | | − | if (fn < sizeof(bar.l) && |
| 341 | + | if (fn < llen && |
| 310 | 342 | | win_textwidth(files[sel].name, fn, true) + |
| 311 | | − | win_textwidth(bar.r, n, true) < win.w) |
| 343 | + | win_textwidth(rt, n, true) < win.w) |
| 312 | 344 | | { |
| 313 | | − | strncpy(bar.l, files[sel].name, sizeof(bar.l)); |
| 345 | + | strncpy(lt, files[sel].name, llen); |
| 314 | 346 | | } else { |
| 315 | | − | strncpy(bar.l, files[sel].base, sizeof(bar.l)); |
| 347 | + | strncpy(lt, files[sel].base, llen); |
| 316 | 348 | | } |
| 317 | 349 | | } |
| 318 | | − | win_set_bar_info(&win, bar.l, bar.r); |
| 319 | 350 | | } |
| 320 | 351 | | |
| 321 | 352 | | void redraw(void) |
| @@ -458,8 +489,8 @@ void run(void) |
| 458 | 489 | | int xfd; |
| 459 | 490 | | fd_set fds; |
| 460 | 491 | | struct timeval timeout; |
| 492 | + | bool discard, to_set; |
| 461 | 493 | | XEvent ev, nextev; |
| 462 | | − | bool discard; |
| 463 | 494 | | |
| 464 | 495 | | redraw(); |
| 465 | 496 | | |
| @@ -482,12 +513,20 @@ void run(void) |
| 482 | 513 | | check_timeouts(NULL); |
| 483 | 514 | | } |
| 484 | 515 | | |
| 485 | | − | while (XPending(win.env.dpy) == 0 && check_timeouts(&timeout)) { |
| 486 | | − | /* wait for timeouts */ |
| 516 | + | while (XPending(win.env.dpy) == 0 |
| 517 | + | && ((to_set = check_timeouts(&timeout)) || info.fd != -1)) |
| 518 | + | { |
| 519 | + | /* check for timeouts & input */ |
| 487 | 520 | | xfd = ConnectionNumber(win.env.dpy); |
| 488 | 521 | | FD_ZERO(&fds); |
| 489 | 522 | | FD_SET(xfd, &fds); |
| 490 | | − | select(xfd + 1, &fds, 0, 0, &timeout); |
| 523 | + | if (info.fd != -1) { |
| 524 | + | FD_SET(info.fd, &fds); |
| 525 | + | xfd = MAX(xfd, info.fd); |
| 526 | + | } |
| 527 | + | select(xfd + 1, &fds, 0, 0, to_set ? &timeout : NULL); |
| 528 | + | if (FD_ISSET(info.fd, &fds)) |
| 529 | + | read_info(); |
| 491 | 530 | | } |
| 492 | 531 | | |
| 493 | 532 | | do { |
| @@ -641,13 +680,14 @@ int main(int argc, char **argv) |
| 641 | 680 | | warn("could not locate home directory"); |
| 642 | 681 | | } else { |
| 643 | 682 | | len = strlen(homedir) + strlen(INFO_SCRIPT) + 2; |
| 644 | | − | info_script = (char*) s_malloc(len); |
| 645 | | − | snprintf(info_script, len, "%s/%s", homedir, INFO_SCRIPT); |
| 646 | | − | if (access(info_script, X_OK) != 0) { |
| 647 | | − | free(info_script); |
| 648 | | − | info_script = NULL; |
| 683 | + | info.script = (char*) s_malloc(len); |
| 684 | + | snprintf(info.script, len, "%s/%s", homedir, INFO_SCRIPT); |
| 685 | + | if (access(info.script, X_OK) != 0) { |
| 686 | + | free(info.script); |
| 687 | + | info.script = NULL; |
| 649 | 688 | | } |
| 650 | 689 | | } |
| 690 | + | info.fd = -1; |
| 651 | 691 | | |
| 652 | 692 | | if (options->thumb_mode) { |
| 653 | 693 | | mode = MODE_THUMB; |