| @@ -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,12 @@ 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 | + | bool open; |
| 80 | + | } info; |
| 79 | 81 | | |
| 80 | 82 | | timeout_t timeouts[] = { |
| 81 | 83 | | { { 0, 0 }, false, redraw }, |
| @@ -212,35 +214,69 @@ bool check_timeouts(struct timeval *t) |
| 212 | 214 | | return tmin > 0; |
| 213 | 215 | | } |
| 214 | 216 | | |
| 217 | + | void open_info(void) |
| 218 | + | { |
| 219 | + | static pid_t pid; |
| 220 | + | int pfd[2]; |
| 221 | + | |
| 222 | + | if (info.script == NULL || info.open || win.bar.h == 0) |
| 223 | + | return; |
| 224 | + | if (info.fd != -1) { |
| 225 | + | close(info.fd); |
| 226 | + | kill(pid, SIGTERM); |
| 227 | + | info.fd = -1; |
| 228 | + | } |
| 229 | + | win.bar.l[0] = '\0'; |
| 230 | + | |
| 231 | + | if (pipe(pfd) < 0) |
| 232 | + | return; |
| 233 | + | pid = fork(); |
| 234 | + | if (pid > 0) { |
| 235 | + | close(pfd[1]); |
| 236 | + | fcntl(pfd[0], F_SETFL, O_NONBLOCK); |
| 237 | + | info.fd = pfd[0]; |
| 238 | + | info.i = info.lastsep = 0; |
| 239 | + | info.open = true; |
| 240 | + | } else if (pid == 0) { |
| 241 | + | close(pfd[0]); |
| 242 | + | dup2(pfd[1], 1); |
| 243 | + | execl(info.script, info.script, files[fileidx].name, NULL); |
| 244 | + | warn("could not exec: %s", info.script); |
| 245 | + | exit(EXIT_FAILURE); |
| 246 | + | } |
| 247 | + | } |
| 248 | + | |
| 215 | 249 | | void read_info(void) |
| 216 | 250 | | { |
| 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) |
| 251 | + | ssize_t i, n; |
| 252 | + | char buf[BAR_L_LEN]; |
| 253 | + | |
| 254 | + | while (true) { |
| 255 | + | n = read(info.fd, buf, sizeof(buf)); |
| 256 | + | if (n < 0 && errno == EAGAIN) |
| 257 | + | return; |
| 258 | + | else if (n == 0) |
| 226 | 259 | | goto end; |
| 227 | | − | while (i < n && (c = fgetc(outp)) != EOF) { |
| 228 | | − | if (c == '\n') { |
| 229 | | − | if (!lastsep) { |
| 230 | | − | bar.l[i++] = ' '; |
| 231 | | − | lastsep = true; |
| 260 | + | for (i = 0; i < n; i++) { |
| 261 | + | if (buf[i] == '\n') { |
| 262 | + | if (info.lastsep == 0) { |
| 263 | + | win.bar.l[info.i++] = ' '; |
| 264 | + | info.lastsep = 1; |
| 232 | 265 | | } |
| 233 | 266 | | } else { |
| 234 | | − | bar.l[i++] = c; |
| 235 | | − | lastsep = false; |
| 267 | + | win.bar.l[info.i++] = buf[i]; |
| 268 | + | info.lastsep = 0; |
| 236 | 269 | | } |
| 270 | + | if (info.i + 1 == sizeof(win.bar.l)) |
| 271 | + | goto end; |
| 237 | 272 | | } |
| 238 | | − | pclose(outp); |
| 239 | 273 | | } |
| 240 | 274 | | end: |
| 241 | | − | if (lastsep) |
| 242 | | − | i--; |
| 243 | | − | bar.l[i] = '\0'; |
| 275 | + | info.i -= info.lastsep; |
| 276 | + | win.bar.l[info.i] = '\0'; |
| 277 | + | win_update_bar(&win); |
| 278 | + | info.fd = -1; |
| 279 | + | while (waitpid(-1, NULL, WNOHANG) > 0); |
| 244 | 280 | | } |
| 245 | 281 | | |
| 246 | 282 | | void load_image(int new) |
| @@ -261,7 +297,8 @@ void load_image(int new) |
| 261 | 297 | | alternate = fileidx; |
| 262 | 298 | | fileidx = new; |
| 263 | 299 | | |
| 264 | | − | read_info(); |
| 300 | + | info.open = false; |
| 301 | + | open_info(); |
| 265 | 302 | | |
| 266 | 303 | | if (img.multi.cnt > 0 && img.multi.animate) |
| 267 | 304 | | set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); |
| @@ -271,51 +308,56 @@ void load_image(int new) |
| 271 | 308 | | |
| 272 | 309 | | void update_info(void) |
| 273 | 310 | | { |
| 274 | | − | unsigned int i, fn, fw, n, len = sizeof(bar.r); |
| 275 | 311 | | int sel; |
| 276 | | − | char *t = bar.r, title[TITLE_LEN]; |
| 312 | + | unsigned int i, fn, fw, n; |
| 313 | + | unsigned int llen = sizeof(win.bar.l), rlen = sizeof(win.bar.r); |
| 314 | + | char *lt = win.bar.l, *rt = win.bar.r, title[TITLE_LEN]; |
| 277 | 315 | | bool ow_info; |
| 278 | 316 | | |
| 279 | 317 | | for (fw = 0, i = filecnt; i > 0; fw++, i /= 10); |
| 280 | 318 | | sel = mode == MODE_IMAGE ? fileidx : tns.sel; |
| 281 | 319 | | |
| 320 | + | /* update window title */ |
| 282 | 321 | | if (mode == MODE_THUMB) { |
| 283 | 322 | | win_set_title(&win, "sxiv"); |
| 323 | + | } else { |
| 324 | + | snprintf(title, sizeof(title), "sxiv - %s", files[sel].name); |
| 325 | + | win_set_title(&win, title); |
| 326 | + | } |
| 284 | 327 | | |
| 328 | + | /* update bar contents */ |
| 329 | + | if (win.bar.h == 0) |
| 330 | + | return; |
| 331 | + | if (mode == MODE_THUMB) { |
| 285 | 332 | | if (tns.cnt == filecnt) { |
| 286 | | − | n = snprintf(t, len, "%0*d/%d", fw, sel + 1, filecnt); |
| 333 | + | n = snprintf(rt, rlen, "%0*d/%d", fw, sel + 1, filecnt); |
| 287 | 334 | | ow_info = true; |
| 288 | 335 | | } else { |
| 289 | | − | snprintf(bar.l, sizeof(bar.l), "Loading... %0*d/%d", |
| 290 | | − | fw, tns.cnt, filecnt); |
| 291 | | − | bar.r[0] = '\0'; |
| 336 | + | snprintf(lt, llen, "Loading... %0*d/%d", fw, tns.cnt, filecnt); |
| 337 | + | rt[0] = '\0'; |
| 292 | 338 | | ow_info = false; |
| 293 | 339 | | } |
| 294 | 340 | | } else { |
| 295 | | − | snprintf(title, sizeof(title), "sxiv - %s", files[sel].name); |
| 296 | | − | win_set_title(&win, title); |
| 297 | | − | |
| 298 | | − | n = snprintf(t, len, "%3d%% ", (int) (img.zoom * 100.0)); |
| 341 | + | n = snprintf(rt, rlen, "%3d%% | ", (int) (img.zoom * 100.0)); |
| 299 | 342 | | if (img.multi.cnt > 0) { |
| 300 | 343 | | for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); |
| 301 | | − | n += snprintf(t + n, len - n, "(%0*d/%d) ", |
| 344 | + | n += snprintf(rt + n, rlen - n, "%0*d/%d | ", |
| 302 | 345 | | fn, img.multi.sel + 1, img.multi.cnt); |
| 303 | 346 | | } |
| 304 | | − | n += snprintf(t + n, len - n, "%0*d/%d", fw, sel + 1, filecnt); |
| 305 | | − | ow_info = bar.l[0] == '\0'; |
| 347 | + | n += snprintf(rt + n, rlen - n, "%0*d/%d", fw, sel + 1, filecnt); |
| 348 | + | ow_info = info.script == NULL; |
| 306 | 349 | | } |
| 307 | 350 | | if (ow_info) { |
| 308 | 351 | | fn = strlen(files[sel].name); |
| 309 | | − | if (fn < sizeof(bar.l) && |
| 352 | + | if (fn < llen && |
| 310 | 353 | | win_textwidth(files[sel].name, fn, true) + |
| 311 | | − | win_textwidth(bar.r, n, true) < win.w) |
| 354 | + | win_textwidth(rt, n, true) < win.w) |
| 312 | 355 | | { |
| 313 | | − | strncpy(bar.l, files[sel].name, sizeof(bar.l)); |
| 356 | + | strncpy(lt, files[sel].name, llen); |
| 314 | 357 | | } else { |
| 315 | | − | strncpy(bar.l, files[sel].base, sizeof(bar.l)); |
| 358 | + | strncpy(lt, files[sel].base, llen); |
| 316 | 359 | | } |
| 317 | 360 | | } |
| 318 | | − | win_set_bar_info(&win, bar.l, bar.r); |
| 319 | 361 | | } |
| 320 | 362 | | |
| 321 | 363 | | void redraw(void) |
| @@ -458,8 +500,8 @@ void run(void) |
| 458 | 500 | | int xfd; |
| 459 | 501 | | fd_set fds; |
| 460 | 502 | | struct timeval timeout; |
| 503 | + | bool discard, to_set; |
| 461 | 504 | | XEvent ev, nextev; |
| 462 | | − | bool discard; |
| 463 | 505 | | |
| 464 | 506 | | redraw(); |
| 465 | 507 | | |
| @@ -482,12 +524,20 @@ void run(void) |
| 482 | 524 | | check_timeouts(NULL); |
| 483 | 525 | | } |
| 484 | 526 | | |
| 485 | | − | while (XPending(win.env.dpy) == 0 && check_timeouts(&timeout)) { |
| 486 | | − | /* wait for timeouts */ |
| 527 | + | while (XPending(win.env.dpy) == 0 |
| 528 | + | && ((to_set = check_timeouts(&timeout)) || info.fd != -1)) |
| 529 | + | { |
| 530 | + | /* check for timeouts & input */ |
| 487 | 531 | | xfd = ConnectionNumber(win.env.dpy); |
| 488 | 532 | | FD_ZERO(&fds); |
| 489 | 533 | | FD_SET(xfd, &fds); |
| 490 | | − | select(xfd + 1, &fds, 0, 0, &timeout); |
| 534 | + | if (info.fd != -1) { |
| 535 | + | FD_SET(info.fd, &fds); |
| 536 | + | xfd = MAX(xfd, info.fd); |
| 537 | + | } |
| 538 | + | select(xfd + 1, &fds, 0, 0, to_set ? &timeout : NULL); |
| 539 | + | if (FD_ISSET(info.fd, &fds)) |
| 540 | + | read_info(); |
| 491 | 541 | | } |
| 492 | 542 | | |
| 493 | 543 | | do { |
| @@ -641,13 +691,14 @@ int main(int argc, char **argv) |
| 641 | 691 | | warn("could not locate home directory"); |
| 642 | 692 | | } else { |
| 643 | 693 | | 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; |
| 694 | + | info.script = (char*) s_malloc(len); |
| 695 | + | snprintf(info.script, len, "%s/%s", homedir, INFO_SCRIPT); |
| 696 | + | if (access(info.script, X_OK) != 0) { |
| 697 | + | free(info.script); |
| 698 | + | info.script = NULL; |
| 649 | 699 | | } |
| 650 | 700 | | } |
| 701 | + | info.fd = -1; |
| 651 | 702 | | |
| 652 | 703 | | if (options->thumb_mode) { |
| 653 | 704 | | mode = MODE_THUMB; |