Krolyxon
Commit f329840

Branches

Refs →

nsxivf329840

Spawn and read from info script without blocking

Author
Bert Münnich
Date
2013-02-11 23:05 +0100
Committer
Bert Münnich · 2013-03-19 21:13 +0100
Parent
9ee3447
Commit
f3298400e6704844aeb1d3e0951e84b4236d2302

+131 −84

3 files changed

  1. M main.c +92 −52
  2. M window.c +30 −29
  3. M window.h +9 −3
M main.c View
@@ -22,10 +22,14 @@
2222 #include <stdlib.h>
2323 #include <stdio.h>
2424 #include <string.h>
25+#include <fcntl.h>
2526 #include <unistd.h>
27+#include <errno.h>
28+#include <signal.h>
2629 #include <sys/select.h>
2730 #include <sys/stat.h>
2831 #include <sys/time.h>
32+#include <sys/wait.h>
2933 #include <X11/keysym.h>
3034
3135 #include "types.h"
@@ -38,8 +42,6 @@
3842 #include "config.h"
3943
4044 enum {
41− BAR_L_LEN = 512,
42− BAR_R_LEN = 64,
4345 FILENAME_CNT = 1024,
4446 TITLE_LEN = 256
4547 };
@@ -70,12 +72,11 @@ int prefix;
7072 bool resized = false;
7173
7274 const char * const INFO_SCRIPT = ".sxiv/exec/image-info";
73−char *info_script;
74−
7575 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;
7980
8081 timeout_t timeouts[] = {
8182 { { 0, 0 }, false, redraw },
@@ -212,35 +213,66 @@ bool check_timeouts(struct timeval *t)
212213 return tmin > 0;
213214 }
214215
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+
215245 void read_info(void)
216246 {
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)
226255 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;
232261 }
233262 } else {
234− bar.l[i++] = c;
235− lastsep = false;
263+ win.bar.l[info.i++] = buf[i];
264+ info.lastsep = 0;
236265 }
266+ if (info.i + 1 == sizeof(win.bar.l))
267+ goto end;
237268 }
238− pclose(outp);
239269 }
240270 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);
244276 }
245277
246278 void load_image(int new)
@@ -261,7 +293,7 @@ void load_image(int new)
261293 alternate = fileidx;
262294 fileidx = new;
263295
264− read_info();
296+ open_info();
265297
266298 if (img.multi.cnt > 0 && img.multi.animate)
267299 set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
@@ -271,9 +303,10 @@ void load_image(int new)
271303
272304 void update_info(void)
273305 {
274− unsigned int i, fn, fw, n, len = sizeof(bar.r);
275306 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];
277310 bool ow_info;
278311
279312 for (fw = 0, i = filecnt; i > 0; fw++, i /= 10);
@@ -283,39 +316,37 @@ void update_info(void)
283316 win_set_title(&win, "sxiv");
284317
285318 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);
287320 ow_info = true;
288321 } 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';
292324 ow_info = false;
293325 }
294326 } else {
295327 snprintf(title, sizeof(title), "sxiv - %s", files[sel].name);
296328 win_set_title(&win, title);
297329
298− n = snprintf(t, len, "%3d%% ", (int) (img.zoom * 100.0));
330+ n = snprintf(rt, rlen, "%3d%% ", (int) (img.zoom * 100.0));
299331 if (img.multi.cnt > 0) {
300332 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) ",
302334 fn, img.multi.sel + 1, img.multi.cnt);
303335 }
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;
306338 }
307339 if (ow_info) {
308340 fn = strlen(files[sel].name);
309− if (fn < sizeof(bar.l) &&
341+ if (fn < llen &&
310342 win_textwidth(files[sel].name, fn, true) +
311− win_textwidth(bar.r, n, true) < win.w)
343+ win_textwidth(rt, n, true) < win.w)
312344 {
313− strncpy(bar.l, files[sel].name, sizeof(bar.l));
345+ strncpy(lt, files[sel].name, llen);
314346 } else {
315− strncpy(bar.l, files[sel].base, sizeof(bar.l));
347+ strncpy(lt, files[sel].base, llen);
316348 }
317349 }
318− win_set_bar_info(&win, bar.l, bar.r);
319350 }
320351
321352 void redraw(void)
@@ -458,8 +489,8 @@ void run(void)
458489 int xfd;
459490 fd_set fds;
460491 struct timeval timeout;
492+ bool discard, to_set;
461493 XEvent ev, nextev;
462− bool discard;
463494
464495 redraw();
465496
@@ -482,12 +513,20 @@ void run(void)
482513 check_timeouts(NULL);
483514 }
484515
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 */
487520 xfd = ConnectionNumber(win.env.dpy);
488521 FD_ZERO(&fds);
489522 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();
491530 }
492531
493532 do {
@@ -641,13 +680,14 @@ int main(int argc, char **argv)
641680 warn("could not locate home directory");
642681 } else {
643682 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;
649688 }
650689 }
690+ info.fd = -1;
651691
652692 if (options->thumb_mode) {
653693 mode = MODE_THUMB;
M window.c View
@@ -414,31 +414,28 @@ void win_draw_bar(win_t *win)
414414 XSetForeground(e->dpy, gc, win->bar.fgcol);
415415 XSetBackground(e->dpy, gc, win->bar.bgcol);
416416
417− if (win->bar.r != NULL) {
418− len = strlen(win->bar.r);
419− if (len > 0) {
420− if ((tw = win_textwidth(win->bar.r, len, true)) > w)
421− return;
422− x = win->w - tw + H_TEXT_PAD;
423− w -= tw;
424− if (font.set)
425− XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->bar.r, len);
426− else
427− XDrawString(e->dpy, win->pm, gc, x, y, win->bar.r, len);
428− }
417+ if ((len = strlen(win->bar.r)) > 0) {
418+ if ((tw = win_textwidth(win->bar.r, len, true)) > w)
419+ return;
420+ x = win->w - tw + H_TEXT_PAD;
421+ w -= tw;
422+ if (font.set)
423+ XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->bar.r, len);
424+ else
425+ XDrawString(e->dpy, win->pm, gc, x, y, win->bar.r, len);
429426 }
430− if (win->bar.l != NULL) {
431− olen = len = strlen(win->bar.l);
427+ if ((len = strlen(win->bar.l)) > 0) {
428+ olen = len;
432429 while (len > 0 && (tw = win_textwidth(win->bar.l, len, true)) > w)
433430 len--;
434431 if (len > 0) {
435− if (len != olen) {
436− w = strlen(dots);
437− if (len <= w)
438− return;
439− memcpy(rest, win->bar.l + len - w, w);
440− memcpy(win->bar.l + len - w, dots, w);
441− }
432+ if (len != olen) {
433+ w = strlen(dots);
434+ if (len <= w)
435+ return;
436+ memcpy(rest, win->bar.l + len - w, w);
437+ memcpy(win->bar.l + len - w, dots, w);
438+ }
442439 x = H_TEXT_PAD;
443440 if (font.set)
444441 XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->bar.l, len);
@@ -480,6 +477,18 @@ void win_draw_rect(win_t *win, Pixmap pm, int x, int y, int w, int h,
480477 XDrawRectangle(win->env.dpy, pm, gc, x, y, w, h);
481478 }
482479
480+void win_update_bar(win_t *win)
481+{
482+ if (win == NULL || win->xwin == None || win->pm == None)
483+ return;
484+
485+ if (win->bar.h > 0) {
486+ win_draw_bar(win);
487+ XCopyArea(win->env.dpy, win->pm, win->xwin, gc,
488+ 0, win->h, win->w, win->bar.h, 0, win->h);
489+ }
490+}
491+
483492 int win_textwidth(const char *text, unsigned int len, bool with_padding)
484493 {
485494 XRectangle r;
@@ -514,14 +523,6 @@ void win_set_title(win_t *win, const char *title)
514523 PropModeReplace, (unsigned char *) title, strlen(title));
515524 }
516525
517−void win_set_bar_info(win_t *win, char *linfo, char *rinfo)
518−{
519− if (win != NULL) {
520− win->bar.l = linfo;
521− win->bar.r = rinfo;
522− }
523−}
524−
525526 void win_set_cursor(win_t *win, cursor_t cursor)
526527 {
527528 if (win == NULL || win->xwin == None)
M window.h View
@@ -24,6 +24,11 @@
2424
2525 #include "types.h"
2626
27+enum {
28+ BAR_L_LEN = 512,
29+ BAR_R_LEN = 64
30+};
31+
2732 typedef struct {
2833 Display *dpy;
2934 int scr;
@@ -55,8 +60,8 @@ typedef struct {
5560
5661 struct {
5762 unsigned int h;
58− char *l;
59− char *r;
63+ char l[BAR_L_LEN];
64+ char r[BAR_R_LEN];
6065 unsigned long bgcol;
6166 unsigned long fgcol;
6267 } bar;
@@ -80,10 +85,11 @@ void win_draw(win_t*);
8085 void win_draw_rect(win_t*, Pixmap, int, int, int, int, bool, int,
8186 unsigned long);
8287
88+void win_update_bar(win_t*);
89+
8390 int win_textwidth(const char*, unsigned int, bool);
8491
8592 void win_set_title(win_t*, const char*);
86−void win_set_bar_info(win_t*, char*, char*);
8793 void win_set_cursor(win_t*, cursor_t);
8894
8995 #endif /* WINDOW_H */