Spawn and read from info script without blocking
This commit is contained in:
		
							parent
							
								
									9ee34477f8
								
							
						
					
					
						commit
						f3298400e6
					
				
							
								
								
									
										142
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								main.c
									
									
									
									
									
								
							| @ -22,10 +22,14 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <fcntl.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <signal.h> | ||||||
| #include <sys/select.h> | #include <sys/select.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
|  | #include <sys/wait.h> | ||||||
| #include <X11/keysym.h> | #include <X11/keysym.h> | ||||||
| 
 | 
 | ||||||
| #include "types.h" | #include "types.h" | ||||||
| @ -38,8 +42,6 @@ | |||||||
| #include "config.h" | #include "config.h" | ||||||
| 
 | 
 | ||||||
| enum { | enum { | ||||||
| 	BAR_L_LEN    = 512, |  | ||||||
| 	BAR_R_LEN    = 64, |  | ||||||
| 	FILENAME_CNT = 1024, | 	FILENAME_CNT = 1024, | ||||||
| 	TITLE_LEN    = 256 | 	TITLE_LEN    = 256 | ||||||
| }; | }; | ||||||
| @ -70,12 +72,11 @@ int prefix; | |||||||
| bool resized = false; | bool resized = false; | ||||||
| 
 | 
 | ||||||
| const char * const INFO_SCRIPT = ".sxiv/exec/image-info"; | const char * const INFO_SCRIPT = ".sxiv/exec/image-info"; | ||||||
| char *info_script; |  | ||||||
| 
 |  | ||||||
| struct { | struct { | ||||||
| 	char l[BAR_L_LEN]; |   char *script; | ||||||
| 	char r[BAR_R_LEN]; |   int fd; | ||||||
| } bar; |   unsigned int i, lastsep; | ||||||
|  | } info; | ||||||
| 
 | 
 | ||||||
| timeout_t timeouts[] = { | timeout_t timeouts[] = { | ||||||
| 	{ { 0, 0 }, false, redraw }, | 	{ { 0, 0 }, false, redraw }, | ||||||
| @ -212,35 +213,66 @@ bool check_timeouts(struct timeval *t) | |||||||
| 	return tmin > 0; | 	return tmin > 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void open_info(void) | ||||||
|  | { | ||||||
|  | 	static pid_t pid; | ||||||
|  | 	int pfd[2]; | ||||||
|  | 
 | ||||||
|  | 	win.bar.l[0] = '\0'; | ||||||
|  | 
 | ||||||
|  | 	if (info.fd != -1) { | ||||||
|  | 		close(info.fd); | ||||||
|  | 		kill(pid, SIGTERM); | ||||||
|  | 		while (waitpid(-1, NULL, WNOHANG) > 0); | ||||||
|  | 		info.fd = -1; | ||||||
|  | 	} | ||||||
|  | 	if (info.script == NULL || pipe(pfd) < 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	pid = fork(); | ||||||
|  | 	if (pid > 0) { | ||||||
|  | 		close(pfd[1]); | ||||||
|  | 		fcntl(pfd[0], F_SETFL, O_NONBLOCK); | ||||||
|  | 		info.fd = pfd[0]; | ||||||
|  | 		info.i = info.lastsep = 0; | ||||||
|  | 	} else if (pid == 0) { | ||||||
|  | 		close(pfd[0]); | ||||||
|  | 		dup2(pfd[1], 1); | ||||||
|  | 		execl(info.script, info.script, files[fileidx].name, NULL); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void read_info(void) | void read_info(void) | ||||||
| { | { | ||||||
| 	char cmd[4096]; | 	ssize_t i, n; | ||||||
| 	FILE *outp; | 	char buf[BAR_L_LEN]; | ||||||
| 	int c, i = 0, n = sizeof(bar.l) - 1; |  | ||||||
| 	bool lastsep = false; |  | ||||||
| 
 | 
 | ||||||
| 	if (info_script != NULL) { | 	while (true) { | ||||||
| 		snprintf(cmd, sizeof(cmd), "%s \"%s\"", info_script, files[fileidx].name); | 		n = read(info.fd, buf, sizeof(buf)); | ||||||
| 		outp = popen(cmd, "r"); | 		if (n < 0 && errno == EAGAIN) | ||||||
| 		if (outp == NULL) | 			return; | ||||||
|  | 		else if (n == 0) | ||||||
| 			goto end; | 			goto end; | ||||||
| 		while (i < n && (c = fgetc(outp)) != EOF) { | 		for (i = 0; i < n; i++) { | ||||||
| 			if (c == '\n') { | 			if (buf[i] == '\n') { | ||||||
| 				if (!lastsep) { | 				if (info.lastsep == 0) { | ||||||
| 					bar.l[i++] = ' '; | 					win.bar.l[info.i++] = ' '; | ||||||
| 					lastsep = true; | 					info.lastsep = 1; | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				bar.l[i++] = c; | 				win.bar.l[info.i++] = buf[i]; | ||||||
| 				lastsep = false; | 				info.lastsep = 0; | ||||||
| 			} | 			} | ||||||
|  | 			if (info.i + 1 == sizeof(win.bar.l)) | ||||||
|  | 				goto end; | ||||||
| 		} | 		} | ||||||
| 		pclose(outp); |  | ||||||
| 	} | 	} | ||||||
| end: | end: | ||||||
| 	if (lastsep) | 	info.i -= info.lastsep; | ||||||
| 		i--; | 	win.bar.l[info.i] = '\0'; | ||||||
| 	bar.l[i] = '\0'; | 	win_update_bar(&win); | ||||||
|  | 	info.fd = -1; | ||||||
|  | 	while (waitpid(-1, NULL, WNOHANG) > 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void load_image(int new) | void load_image(int new) | ||||||
| @ -261,7 +293,7 @@ void load_image(int new) | |||||||
| 	alternate = fileidx; | 	alternate = fileidx; | ||||||
| 	fileidx = new; | 	fileidx = new; | ||||||
| 
 | 
 | ||||||
| 	read_info(); | 	open_info(); | ||||||
| 
 | 
 | ||||||
| 	if (img.multi.cnt > 0 && img.multi.animate) | 	if (img.multi.cnt > 0 && img.multi.animate) | ||||||
| 		set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); | 		set_timeout(animate, img.multi.frames[img.multi.sel].delay, true); | ||||||
| @ -271,9 +303,10 @@ void load_image(int new) | |||||||
| 
 | 
 | ||||||
| void update_info(void) | void update_info(void) | ||||||
| { | { | ||||||
| 	unsigned int i, fn, fw, n, len = sizeof(bar.r); |  | ||||||
| 	int sel; | 	int sel; | ||||||
| 	char *t = bar.r, title[TITLE_LEN]; | 	unsigned int i, fn, fw, n; | ||||||
|  | 	unsigned int llen = sizeof(win.bar.l), rlen = sizeof(win.bar.r); | ||||||
|  | 	char *lt = win.bar.l, *rt = win.bar.r, title[TITLE_LEN]; | ||||||
| 	bool ow_info; | 	bool ow_info; | ||||||
| 
 | 
 | ||||||
| 	for (fw = 0, i = filecnt; i > 0; fw++, i /= 10); | 	for (fw = 0, i = filecnt; i > 0; fw++, i /= 10); | ||||||
| @ -283,39 +316,37 @@ void update_info(void) | |||||||
| 		win_set_title(&win, "sxiv"); | 		win_set_title(&win, "sxiv"); | ||||||
| 
 | 
 | ||||||
| 		if (tns.cnt == filecnt) { | 		if (tns.cnt == filecnt) { | ||||||
| 			n = snprintf(t, len, "%0*d/%d", fw, sel + 1, filecnt); | 			n = snprintf(rt, rlen, "%0*d/%d", fw, sel + 1, filecnt); | ||||||
| 			ow_info = true; | 			ow_info = true; | ||||||
| 		} else { | 		} else { | ||||||
| 			snprintf(bar.l, sizeof(bar.l), "Loading... %0*d/%d", | 			snprintf(lt, llen, "Loading... %0*d/%d", fw, tns.cnt, filecnt); | ||||||
| 			         fw, tns.cnt, filecnt); | 			rt[0] = '\0'; | ||||||
| 			bar.r[0] = '\0'; |  | ||||||
| 			ow_info = false; | 			ow_info = false; | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		snprintf(title, sizeof(title), "sxiv - %s", files[sel].name); | 		snprintf(title, sizeof(title), "sxiv - %s", files[sel].name); | ||||||
| 		win_set_title(&win, title); | 		win_set_title(&win, title); | ||||||
| 
 | 
 | ||||||
| 		n = snprintf(t, len, "%3d%% ", (int) (img.zoom * 100.0)); | 		n = snprintf(rt, rlen, "%3d%% ", (int) (img.zoom * 100.0)); | ||||||
| 		if (img.multi.cnt > 0) { | 		if (img.multi.cnt > 0) { | ||||||
| 			for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); | 			for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); | ||||||
| 			n += snprintf(t + n, len - n, "(%0*d/%d) ", | 			n += snprintf(rt + n, rlen - n, "(%0*d/%d) ", | ||||||
| 			              fn, img.multi.sel + 1, img.multi.cnt); | 			              fn, img.multi.sel + 1, img.multi.cnt); | ||||||
| 		} | 		} | ||||||
| 		n += snprintf(t + n, len - n, "%0*d/%d", fw, sel + 1, filecnt); | 		n += snprintf(rt + n, rlen - n, "%0*d/%d", fw, sel + 1, filecnt); | ||||||
| 		ow_info = bar.l[0] == '\0'; | 		ow_info = info.script == NULL; | ||||||
| 	} | 	} | ||||||
| 	if (ow_info) { | 	if (ow_info) { | ||||||
| 		fn = strlen(files[sel].name); | 		fn = strlen(files[sel].name); | ||||||
| 		if (fn < sizeof(bar.l) && | 		if (fn < llen && | ||||||
| 		    win_textwidth(files[sel].name, fn, true) + | 		    win_textwidth(files[sel].name, fn, true) + | ||||||
| 		    win_textwidth(bar.r, n, true) < win.w) | 		    win_textwidth(rt, n, true) < win.w) | ||||||
| 		{ | 		{ | ||||||
| 			strncpy(bar.l, files[sel].name, sizeof(bar.l)); | 			strncpy(lt, files[sel].name, llen); | ||||||
| 		} else { | 		} else { | ||||||
| 			strncpy(bar.l, files[sel].base, sizeof(bar.l)); | 			strncpy(lt, files[sel].base, llen); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	win_set_bar_info(&win, bar.l, bar.r); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void redraw(void) | void redraw(void) | ||||||
| @ -458,8 +489,8 @@ void run(void) | |||||||
| 	int xfd; | 	int xfd; | ||||||
| 	fd_set fds; | 	fd_set fds; | ||||||
| 	struct timeval timeout; | 	struct timeval timeout; | ||||||
|  | 	bool discard, to_set; | ||||||
| 	XEvent ev, nextev; | 	XEvent ev, nextev; | ||||||
| 	bool discard; |  | ||||||
| 
 | 
 | ||||||
| 	redraw(); | 	redraw(); | ||||||
| 
 | 
 | ||||||
| @ -482,12 +513,20 @@ void run(void) | |||||||
| 				check_timeouts(NULL); | 				check_timeouts(NULL); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		while (XPending(win.env.dpy) == 0 && check_timeouts(&timeout)) { | 		while (XPending(win.env.dpy) == 0 | ||||||
| 			/* wait for timeouts */ | 		       && ((to_set = check_timeouts(&timeout)) || info.fd != -1)) | ||||||
|  | 		{ | ||||||
|  | 			/* check for timeouts & input */ | ||||||
| 			xfd = ConnectionNumber(win.env.dpy); | 			xfd = ConnectionNumber(win.env.dpy); | ||||||
| 			FD_ZERO(&fds); | 			FD_ZERO(&fds); | ||||||
| 			FD_SET(xfd, &fds); | 			FD_SET(xfd, &fds); | ||||||
| 			select(xfd + 1, &fds, 0, 0, &timeout); | 			if (info.fd != -1) { | ||||||
|  | 				FD_SET(info.fd, &fds); | ||||||
|  | 				xfd = MAX(xfd, info.fd); | ||||||
|  | 			} | ||||||
|  | 			select(xfd + 1, &fds, 0, 0, to_set ? &timeout : NULL); | ||||||
|  | 			if (FD_ISSET(info.fd, &fds)) | ||||||
|  | 				read_info(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		do { | 		do { | ||||||
| @ -641,13 +680,14 @@ int main(int argc, char **argv) | |||||||
| 		warn("could not locate home directory"); | 		warn("could not locate home directory"); | ||||||
| 	} else { | 	} else { | ||||||
| 		len = strlen(homedir) + strlen(INFO_SCRIPT) + 2; | 		len = strlen(homedir) + strlen(INFO_SCRIPT) + 2; | ||||||
| 		info_script = (char*) s_malloc(len); | 		info.script = (char*) s_malloc(len); | ||||||
| 		snprintf(info_script, len, "%s/%s", homedir, INFO_SCRIPT); | 		snprintf(info.script, len, "%s/%s", homedir, INFO_SCRIPT); | ||||||
| 		if (access(info_script, X_OK) != 0) { | 		if (access(info.script, X_OK) != 0) { | ||||||
| 			free(info_script); | 			free(info.script); | ||||||
| 			info_script = NULL; | 			info.script = NULL; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	info.fd = -1; | ||||||
| 
 | 
 | ||||||
| 	if (options->thumb_mode) { | 	if (options->thumb_mode) { | ||||||
| 		mode = MODE_THUMB; | 		mode = MODE_THUMB; | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								window.c
									
									
									
									
									
								
							| @ -414,9 +414,7 @@ void win_draw_bar(win_t *win) | |||||||
| 	XSetForeground(e->dpy, gc, win->bar.fgcol); | 	XSetForeground(e->dpy, gc, win->bar.fgcol); | ||||||
| 	XSetBackground(e->dpy, gc, win->bar.bgcol); | 	XSetBackground(e->dpy, gc, win->bar.bgcol); | ||||||
| 
 | 
 | ||||||
| 	if (win->bar.r != NULL) { | 	if ((len = strlen(win->bar.r)) > 0) { | ||||||
| 		len = strlen(win->bar.r); |  | ||||||
| 		if (len > 0) { |  | ||||||
| 		if ((tw = win_textwidth(win->bar.r, len, true)) > w) | 		if ((tw = win_textwidth(win->bar.r, len, true)) > w) | ||||||
| 			return; | 			return; | ||||||
| 		x = win->w - tw + H_TEXT_PAD; | 		x = win->w - tw + H_TEXT_PAD; | ||||||
| @ -426,9 +424,8 @@ void win_draw_bar(win_t *win) | |||||||
| 		else | 		else | ||||||
| 			XDrawString(e->dpy, win->pm, gc, x, y, win->bar.r, len); | 			XDrawString(e->dpy, win->pm, gc, x, y, win->bar.r, len); | ||||||
| 	} | 	} | ||||||
| 	} | 	if ((len = strlen(win->bar.l)) > 0) { | ||||||
| 	if (win->bar.l != NULL) { | 		olen = len; | ||||||
| 		olen = len = strlen(win->bar.l); |  | ||||||
| 		while (len > 0 && (tw = win_textwidth(win->bar.l, len, true)) > w) | 		while (len > 0 && (tw = win_textwidth(win->bar.l, len, true)) > w) | ||||||
| 			len--; | 			len--; | ||||||
| 		if (len > 0) { | 		if (len > 0) { | ||||||
| @ -480,6 +477,18 @@ void win_draw_rect(win_t *win, Pixmap pm, int x, int y, int w, int h, | |||||||
| 		XDrawRectangle(win->env.dpy, pm, gc, x, y, w, h); | 		XDrawRectangle(win->env.dpy, pm, gc, x, y, w, h); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void win_update_bar(win_t *win) | ||||||
|  | { | ||||||
|  | 	if (win == NULL || win->xwin == None || win->pm == None) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (win->bar.h > 0) { | ||||||
|  | 		win_draw_bar(win); | ||||||
|  | 		XCopyArea(win->env.dpy, win->pm, win->xwin, gc, | ||||||
|  | 		          0, win->h, win->w, win->bar.h, 0, win->h); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int win_textwidth(const char *text, unsigned int len, bool with_padding) | int win_textwidth(const char *text, unsigned int len, bool with_padding) | ||||||
| { | { | ||||||
| 	XRectangle r; | 	XRectangle r; | ||||||
| @ -514,14 +523,6 @@ void win_set_title(win_t *win, const char *title) | |||||||
| 	                PropModeReplace, (unsigned char *) title, strlen(title)); | 	                PropModeReplace, (unsigned char *) title, strlen(title)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void win_set_bar_info(win_t *win, char *linfo, char *rinfo) |  | ||||||
| { |  | ||||||
| 	if (win != NULL) { |  | ||||||
| 		win->bar.l = linfo; |  | ||||||
| 		win->bar.r = rinfo; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void win_set_cursor(win_t *win, cursor_t cursor) | void win_set_cursor(win_t *win, cursor_t cursor) | ||||||
| { | { | ||||||
| 	if (win == NULL || win->xwin == None) | 	if (win == NULL || win->xwin == None) | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								window.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								window.h
									
									
									
									
									
								
							| @ -24,6 +24,11 @@ | |||||||
| 
 | 
 | ||||||
| #include "types.h" | #include "types.h" | ||||||
| 
 | 
 | ||||||
|  | enum { | ||||||
|  | 	BAR_L_LEN = 512, | ||||||
|  | 	BAR_R_LEN = 64 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| 	Display *dpy; | 	Display *dpy; | ||||||
| 	int scr; | 	int scr; | ||||||
| @ -55,8 +60,8 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| 	struct { | 	struct { | ||||||
| 		unsigned int h; | 		unsigned int h; | ||||||
| 		char *l; | 		char l[BAR_L_LEN]; | ||||||
| 		char *r; | 		char r[BAR_R_LEN]; | ||||||
| 		unsigned long bgcol; | 		unsigned long bgcol; | ||||||
| 		unsigned long fgcol; | 		unsigned long fgcol; | ||||||
| 	} bar; | 	} bar; | ||||||
| @ -80,10 +85,11 @@ void win_draw(win_t*); | |||||||
| void win_draw_rect(win_t*, Pixmap, int, int, int, int, bool, int, | void win_draw_rect(win_t*, Pixmap, int, int, int, int, bool, int, | ||||||
|                    unsigned long); |                    unsigned long); | ||||||
| 
 | 
 | ||||||
|  | void win_update_bar(win_t*); | ||||||
|  | 
 | ||||||
| int win_textwidth(const char*, unsigned int, bool); | int win_textwidth(const char*, unsigned int, bool); | ||||||
| 
 | 
 | ||||||
| void win_set_title(win_t*, const char*); | void win_set_title(win_t*, const char*); | ||||||
| void win_set_bar_info(win_t*, char*, char*); |  | ||||||
| void win_set_cursor(win_t*, cursor_t); | void win_set_cursor(win_t*, cursor_t); | ||||||
| 
 | 
 | ||||||
| #endif /* WINDOW_H */ | #endif /* WINDOW_H */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bert Münnich
						Bert Münnich