diff options
Diffstat (limited to 'src/xlib.c')
| -rw-r--r-- | src/xlib.c | 162 | 
1 files changed, 134 insertions, 28 deletions
@@ -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; +			} +		} +	} +}  | 
