diff options
| -rw-r--r-- | src/bmp.c | 2 | ||||
| -rw-r--r-- | src/gif.c | 2 | ||||
| -rw-r--r-- | src/jpeg.c | 6 | ||||
| -rw-r--r-- | src/main.c | 236 | ||||
| -rw-r--r-- | src/meh.h | 52 | ||||
| -rw-r--r-- | src/netpbm.c | 2 | ||||
| -rw-r--r-- | src/png.c | 2 | ||||
| -rw-r--r-- | src/scale.c | 2 | ||||
| -rw-r--r-- | src/xlib.c | 162 | 
9 files changed, 266 insertions, 200 deletions
| @@ -172,7 +172,7 @@ int bmp_read(struct image *img){  	free(row); -	img->state = LOADED; +	img->state |= LOADED | SLOWLOADED;  	return 0;  } @@ -79,7 +79,7 @@ static int gif_read(struct image *img){  		img->buf[j++] = colormap[idx].Blue;  	} -	img->state = LOADED; +	img->state |= LOADED | SLOWLOADED;  	return 0;  } @@ -70,7 +70,7 @@ void jpeg_prep(struct image *img){  	j->cinfo.do_block_smoothing = 0;  	j->cinfo.quantize_colors = 0;  	j->cinfo.dct_method = JDCT_FASTEST; -	j->cinfo.scale_denom = img->state < FASTLOADED ? 8 : 1; /* TODO: This should be changed done only for large jpegs */ +	j->cinfo.scale_denom = (img->state & LOADED) ? 1 : 8; /* TODO: This should be changed done only for large jpegs */  	jpeg_calc_output_dimensions(&j->cinfo); @@ -138,7 +138,9 @@ static int jpeg_read(struct image *img){  	}  	jpeg_finish_decompress(&j->cinfo); -	img->state = j->cinfo.scale_denom == 1 ? LOADED : FASTLOADED; +	img->state |= LOADED; +	if(j->cinfo.scale_denom == 1) +		img->state |= SLOWLOADED;  	return 0;  } @@ -8,18 +8,12 @@  #include <string.h>  #include <sys/time.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/keysym.h> -  #include "meh.h"  #define MODE_NORM 0  #define MODE_LIST 1  #define MODE_CTL 2 -static int mode; - -extern Display *display; +int mode;  /* Supported Formats */  struct imageformat *formats[] = { @@ -46,8 +40,8 @@ struct image *newimage(FILE *f){  	struct imageformat **fmt = formats;  	for(fmt = formats; *fmt; fmt++){  		if((img = (*fmt)->open(f))){ -			img->ximg = NULL;  			img->state = NONE; +			img->backend = NULL;  			return img;  		}  	} @@ -65,13 +59,12 @@ static int imageslen;  static int imageidx;  static char **images; -static int width = 0, height = 0; -static struct image *curimg = NULL; +int width = 0, height = 0; +struct image *curimg = NULL;  void freeimage(struct image *img){  	if(img){ -		if(img->ximg) -			freeXImg(img->ximg); +		backend_free(img);  		if(img->buf)  			free(img->buf);  		free(img); @@ -81,85 +74,51 @@ void freeimage(struct image *img){  void nextimage(){  	if(++imageidx == imageslen)  		imageidx = 0; +	freeimage(curimg); +	curimg = NULL;  }  void previmage(){  	if(--imageidx < 0)  		imageidx = imageslen - 1; +	freeimage(curimg); +	curimg = NULL;  }  static void (*direction)() = nextimage; -void handlekeypress(XEvent *event){ -	KeySym key = XLookupKeysym(&event->xkey, 0); -	switch(key){ -		case XK_Escape: -		case XK_q: -			exit(0); -			break; -		case XK_Return: -			puts(images[imageidx]); -			fflush(stdout); -			break; -		case XK_j: -		case XK_k: -			if(mode == MODE_CTL) -				return; -			direction = key == XK_j ? nextimage : previmage; -			direction(); -			/* Pass through */ -		case XK_r: -			freeimage(curimg); -			curimg = NULL; -			break; +void key_reload(){ +	freeimage(curimg); +	curimg = NULL; +} +void key_next(){ +	if(mode != MODE_CTL){ +		direction = nextimage; +		direction();  	}  } - -void handleevent(XEvent *event){ -	switch(event->type){ -		case ConfigureNotify: -			if(width != event->xconfigure.width || height != event->xconfigure.height){ -				width = event->xconfigure.width; -				height = event->xconfigure.height; -				if(curimg){ -					if(curimg->ximg) -						XDestroyImage(curimg->ximg); -					curimg->ximg = NULL; -					if(curimg->state >= LOADED) -						curimg->state = LOADED; -					else if(curimg->state >= FASTLOADED) -						curimg->state = FASTLOADED; -				} - -				/* Some window managers need reminding */ -				if(curimg) -					setaspect(curimg->bufwidth, curimg->bufheight); -			} -			break; -		case Expose: -			if(curimg){ -				if(curimg->state >= SCALED) -					curimg->state = SCALED; -				else if(curimg->state >= LOADED) -					curimg->state = LOADED; -				else if(curimg->state >= FASTSCALED) -					curimg->state = FASTSCALED; -			} -			break; -		case KeyPress: -			if(mode == MODE_CTL) -				break; -			handlekeypress(event); -			break; +void key_prev(){ +	if(mode != MODE_CTL){ +		direction = previmage; +		direction();  	}  } +void key_quit(){ +	exit(EXIT_SUCCESS); +} + +void key_action(){ +	puts(images[imageidx]); +	fflush(stdout); +}  struct image *imageopen2(char *filename){  	struct image *i;  	FILE *f;  	if((f = fopen(filename, "rb"))){ -		if((i = imgopen(f))) +		if((i = imgopen(f))){  			return i; +		}  		else  			fprintf(stderr, "Invalid format '%s'\n", filename);  	}else{ @@ -168,14 +127,14 @@ struct image *imageopen2(char *filename){  	return NULL;  } -void doredraw(struct image **i){ +static int doredraw(struct image **i){  	if(!*i){  		if(mode == MODE_CTL){  			if(images[0] == NULL) -				return; +				return 0;  			if(!(*i = imageopen2(images[0]))){  				images[0] = NULL; -				return; +				return 0;  			}  		}else{  			int firstimg = imageidx; @@ -193,13 +152,14 @@ void doredraw(struct image **i){  		(*i)->buf = NULL;  		(*i)->state = NONE; +		return 1;  	}else{ -		imgstate dstate = (*i)->state + 1; -		if(dstate == LOADED || dstate == FASTLOADED){ +		imgstate state = (*i)->state; +		if(!(state & LOADED) || ((state & (SLOWLOADED | DRAWN)) == (DRAWN)) ){  			if((*i)->fmt->prep){  				(*i)->fmt->prep(*i);  			} -			setaspect((*i)->bufwidth, (*i)->bufheight); +			backend_setaspect((*i)->bufwidth, (*i)->bufheight);  			if((*i)->buf)  				free((*i)->buf); @@ -211,80 +171,35 @@ void doredraw(struct image **i){  			}  			TDEBUG_END("read"); -			if((*i)->state == LOADED){ +			if(((*i)->state & LOADED) && ((*i)->state & SLOWLOADED)){  				/* We are done with the format's methods */  				(*i)->fmt->close(*i);  			} +			(*i)->state &= LOADED | SLOWLOADED; +  			/* state should be set by format */ -			assert((*i)->state == LOADED || (*i)->state == FASTLOADED); +			assert((*i)->state & LOADED); +			return 1;  		}else if(width && height){ -			if(dstate == SCALED || dstate == FASTSCALED2 || dstate == FASTSCALED){ -				(*i)->ximg = getimage(*i, width, height, dstate != SCALED); -				(*i)->state = dstate; -				dstate++; /* Always draw after rendering */ -			} -		} -		if(dstate == DRAWN || dstate == FASTDRAWN || dstate == FASTDRAWN2){ -			assert((*i)->ximg); -			drawimage((*i)->ximg, width, height); -			(*i)->state = dstate; -		} -	} -} +			if((state & LOADED) && !(state & SCALED)){ +				backend_prepare(*i, width, height, !!(state & SCALED)); +				(*i)->state &= LOADED | SLOWLOADED | SCALED | SLOWSCALED; -void run(){ -	int xfd; -	xfd = ConnectionNumber(display); -	fd_set fds; -	struct timeval tv0 = {0, 0}; -	struct timeval *tv = &tv0; -	int maxfd = xfd > ctlfd ? xfd : ctlfd; - -	for(;;){ -		FD_ZERO(&fds); -		FD_SET(xfd, &fds); -		if(mode == MODE_CTL) -			FD_SET(ctlfd, &fds); /* STDIN */ -		int ret = select(maxfd+1, &fds, NULL, NULL, tv); -		if(ret == -1){ -			perror("select failed\n"); -		} -		if(FD_ISSET(ctlfd, &fds)){ -			assert(mode == MODE_CTL); -			size_t slen = 0; -			ssize_t read; -			if(images[0]){ -				free(images[0]); -			} -			freeimage(curimg); -			curimg = NULL; -			images[0] = NULL; -			if((read = getline(images, &slen, stdin)) == -1){ -				exit(EXIT_SUCCESS); +				/* state should be set by backend */ +				assert((*i)->state & SCALED); + +				/* state should not be drawn so that we will draw later (also assures correct return value) */ +				assert(!((*i)->state & DRAWN));  			} -			images[0][read-1] = '\0'; -			tv = &tv0;  		} -		if(XPending(display)){ -			tv = &tv0; -			XEvent event; -			do{ -				XNextEvent(display, &event); -				handleevent(&event); -			}while(XPending(display)); -		}else if(ret == 0){ -			if(mode == MODE_CTL && images[0] == NULL){ -				tv = NULL; -			}else if(!curimg || curimg->state != DRAWN){ -				doredraw(&curimg); -			//}else if(!nextimg || nextimg->state != DRAWN){ -			}else{ -				/* If we get here  everything has been drawn in full or we need more input to continue */ -				tv = NULL; -			} +		if(((*i)->state & SCALED) && !(state & DRAWN)){ +			backend_draw(*i, width, height); +			(*i)->state |= DRAWN; +			return 1;  		}  	} +	return 0;  }  void readlist(FILE *f){ @@ -313,6 +228,41 @@ void readlist(FILE *f){  	}  } +int setup_fds(fd_set *fds){ +	FD_ZERO(fds); +	if(mode == MODE_CTL) +		FD_SET(ctlfd, fds); /* STDIN */ +	return ctlfd; +} + +int process_fds(fd_set *fds){ +	if(FD_ISSET(ctlfd, fds)){ +		assert(mode == MODE_CTL); +		size_t slen = 0; +		ssize_t read; +		if(images[0]){ +			free(images[0]); +		} +		freeimage(curimg); +		curimg = NULL; +		images[0] = NULL; +		if((read = getline(images, &slen, stdin)) == -1){ +			exit(EXIT_SUCCESS); +		} +		images[0][read-1] = '\0'; +		return 1; +	} +	return 0; +} + +int process_idle(){ +	if(mode == MODE_CTL && images[0] == NULL){ +		return 0; +	}else{ +		return doredraw(&curimg); +	} +} +  int main(int argc, char *argv[]){  	if(argc < 2)  		usage(); @@ -346,8 +296,8 @@ int main(int argc, char *argv[]){  		imageslen = argc-1;  		imageidx = 0;  	} -	xinit(); -	run(); +	backend_init(); +	backend_run();  	return 0;  } @@ -1,8 +1,8 @@ +#ifndef MEH_H +#define MEH_H MEH_H  #include <stdio.h> -#include "X11/Xlib.h" -  struct image;  struct imageformat{ @@ -13,16 +13,12 @@ struct imageformat{  };  typedef enum{ -	NONE, -	FASTLOADED, -	FASTSCALED, -	FASTDRAWN, -	LOADED, -	FASTSCALED2, -	FASTDRAWN2, -	SCALED, -	DRAWN, -	ERROR +	NONE = 0, +	LOADED = 1, +	SLOWLOADED = 2, +	SCALED = 4, +	SLOWSCALED = 8, +	DRAWN = 16  } imgstate;  struct image{ @@ -30,20 +26,29 @@ struct image{  	unsigned int bufwidth, bufheight;  	struct imageformat *fmt;  	imgstate state; -	XImage *ximg; +	void *backend;  }; -/* scale */ -void scale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf); -void nearestscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf); +/* backend */ +void backend_init(); +void backend_free(struct image *img); +void backend_setaspect(unsigned int w, unsigned int h); +void backend_prepare(struct image *img, unsigned int width, unsigned int height, int fast); +void backend_draw(struct image *img, unsigned int width, unsigned int height); +void backend_run(); + +/* key actions for backend */ +void key_reload(); +void key_next(); +void key_prev(); +void key_quit(); +void key_action(); -/* XLib */ -void setaspect(unsigned int w, unsigned int h); -void xinit(); -void drawimage(XImage *ximg, unsigned int width, unsigned int height); -XImage *getimage(struct image *img, unsigned int width, unsigned int height, int fast); -void freeXImg(XImage *ximg); +/* callbacks from backend */ +int setup_fds(fd_set *fds); +int process_fds(fd_set *fds); +int process_idle();  #ifdef TDEBUG  #define TDEBUG_START \ @@ -66,5 +71,8 @@ extern struct imageformat bmp;  extern struct imageformat netpbm;  extern struct imageformat imagemagick; +extern int width, height; +extern struct image *curimg; +#endif diff --git a/src/netpbm.c b/src/netpbm.c index 951bfd9..f30dbbc 100644 --- a/src/netpbm.c +++ b/src/netpbm.c @@ -139,7 +139,7 @@ int netpbm_read(struct image *img){  		}  	} -	img->state = LOADED; +	img->state |= LOADED | SLOWLOADED;  	return 0;  } @@ -100,7 +100,7 @@ int png_read(struct image *img){  	png_read_image(p->png_ptr, row_pointers);  	free(row_pointers); -	img->state = LOADED; +	img->state |= LOADED | SLOWLOADED;  	return 0;  } diff --git a/src/scale.c b/src/scale.c index 92db4a8..eb9e689 100644 --- a/src/scale.c +++ b/src/scale.c @@ -65,7 +65,7 @@ static void superscale(struct image *img, unsigned int width, unsigned int heigh  	}  	unsigned int y0; -	int * __restrict__ dest; +	unsigned int * __restrict__ dest;  	for(y = 0; y < img->bufheight;){  		unsigned int ydiv = divy[y * height / img->bufheight];  		char * __restrict__ ydest = &newBuf[bytesperline * (y * height / img->bufheight)]; @@ -1,9 +1,4 @@ -#include <assert.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -  #include <X11/Xlib.h>  #include <X11/Xutil.h>  #include <X11/keysym.h> @@ -11,18 +6,30 @@  #include <sys/ipc.h>  #include <sys/shm.h> +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +  #include "meh.h" +#include "scale.h" + +struct data_t{ +	XImage *ximg; +};  /* Globals */  Display *display; -int screen; -Window window; -GC gc; +static int screen; +static Window window; +static GC gc; + +static int xfd; -int xshm = 0; +static int xshm = 0; -XShmSegmentInfo *shminfo; -XImage *ximage(struct image *img, unsigned int width, unsigned int height, int fast){ +static XShmSegmentInfo *shminfo; +static XImage *ximage(struct image *img, unsigned int width, unsigned int height, int fast){  	int depth;  	XImage *ximg = NULL;  	Visual *vis; @@ -79,15 +86,25 @@ XImage *ximage(struct image *img, unsigned int width, unsigned int height, int f  	return ximg;  } -XImage *getimage(struct image *img, unsigned int width, unsigned int height, int fast){ +void backend_prepare(struct image *img, unsigned int width, unsigned int height, int fast){ +	struct data_t *data = img->backend = malloc(sizeof (struct data_t));  	if(width * img->bufheight > height * img->bufwidth){ -		return ximage(img, img->bufwidth * height / img->bufheight, height, fast); +		data->ximg = ximage(img, img->bufwidth * height / img->bufheight, height, fast);  	}else{ -		return ximage(img, width, img->bufheight * width / img->bufwidth, fast); +		data->ximg = ximage(img, width, img->bufheight * width / img->bufwidth, fast);  	} + +	img->state |= SCALED; +	if(!fast) +		img->state |= SLOWSCALED;  } -void drawimage(XImage *ximg, unsigned int width, unsigned int height){ +void backend_draw(struct image *img, unsigned int width, unsigned int height){ +	assert(((struct data_t *)img->backend)); +	assert(((struct data_t *)img->backend)->ximg); + +	XImage *ximg = ((struct data_t *)img->backend)->ximg; +  	XRectangle rects[2];  	int yoffset, xoffset;  	xoffset = (width - ximg->width) / 2; @@ -117,20 +134,27 @@ void drawimage(XImage *ximg, unsigned int width, unsigned int height){  	XFlush(display);  } -void freeXImg(XImage *ximg){ -	if(xshm){ -		XShmDetach(display, shminfo); -		XDestroyImage(ximg); -		shmdt(shminfo->shmaddr); -		shmctl(shminfo->shmid, IPC_RMID, 0); -		free(shminfo); -	}else{ -		XDestroyImage(ximg); +void backend_free(struct image *img){ +	assert(img); +	if(img->backend){ +		XImage *ximg = ((struct data_t *)img->backend)->ximg; +		if(ximg){ +			if(xshm){ +				XShmDetach(display, shminfo); +				XDestroyImage(ximg); +				shmdt(shminfo->shmaddr); +				shmctl(shminfo->shmid, IPC_RMID, 0); +				free(shminfo); +			}else{ +				XDestroyImage(ximg); +			} +		} +		img->backend = NULL;  	}  } -void setaspect(unsigned int w, unsigned int h){ +void backend_setaspect(unsigned int w, unsigned int h){  	XSizeHints *hints = XAllocSizeHints();  	//hints->flags = PAspect;  	hints->flags = 0; @@ -142,19 +166,20 @@ void setaspect(unsigned int w, unsigned int h){  }  /* Alt-F4 silent. Keeps people happy */ -int xquit(Display *d){ +static int xquit(Display *d){  	(void)d;  	exit(EXIT_SUCCESS);  	return 0;  } -void xinit(){ +void backend_init(){  	display = XOpenDisplay (NULL); +	xfd = ConnectionNumber(display);  	assert(display);  	screen = DefaultScreen(display);  	window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 640, 480, 0, DefaultDepth(display, screen), InputOutput, CopyFromParent, 0, NULL); -	setaspect(1, 1); +	backend_setaspect(1, 1);  	gc = XCreateGC(display, window, 0, NULL);  	XMapRaised(display, window); @@ -164,5 +189,86 @@ void xinit(){  	XFlush(display);  } +void handlekeypress(XEvent *event){ +	KeySym key = XLookupKeysym(&event->xkey, 0); +	switch(key){ +		case XK_Escape: +		case XK_q: +			key_quit(); +			break; +		case XK_Return: +			key_action(); +			break; +		case XK_j: +			key_next(); +			break; +		case XK_k: +			key_prev(); +			break; +		case XK_r: +			key_reload(); +			break; +	} +} + + +void handleevent(XEvent *event){ +	switch(event->type){ +		case ConfigureNotify: +			if(width != event->xconfigure.width || height != event->xconfigure.height){ +				width = event->xconfigure.width; +				height = event->xconfigure.height; +				if(curimg){ +					backend_free(curimg); +					curimg->state &= ~(DRAWN | SCALED | SLOWSCALED); + +					/* Some window managers need reminding */ +					backend_setaspect(curimg->bufwidth, curimg->bufheight); +				} +			} +			break; +		case Expose: +			if(curimg){ +				curimg->state &= ~DRAWN; +			} +			break; +		case KeyPress: +			handlekeypress(event); +			break; +	} +} + +void backend_run(){ +	fd_set fds; +	struct timeval tv0 = {0, 0}; +	struct timeval *tv = &tv0; + +	for(;;){ +		int maxfd = setup_fds(&fds); +		FD_SET(xfd, &fds); +		if(xfd > maxfd) +			maxfd = xfd; +		int ret = select(maxfd+1, &fds, NULL, NULL, tv); +		if(ret == -1){ +			perror("select failed\n"); +		} +		if(process_fds(&fds)){ +			tv = &tv0; +		} +		if(XPending(display)){ +			tv = &tv0; +			XEvent event; +			do{ +				XNextEvent(display, &event); +				handleevent(&event); +			}while(XPending(display)); +		}else if(ret == 0){ +			if(!process_idle()){ +				/* If we get here everything has been drawn in full or we need more input to continue */ +				tv = NULL; +			} +		} +	} +} | 
