From bdfc9445506d72d3eec7c3902449efaf13cf0d98 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 4 Jan 2010 10:09:04 -0800 Subject: major cleanup. xlib methods have been abstracted away as a generic backend. Represent image states as flags. --- src/bmp.c | 2 +- src/gif.c | 2 +- src/jpeg.c | 6 +- src/main.c | 236 +++++++++++++++++++++++------------------------------------ src/meh.h | 52 +++++++------ src/netpbm.c | 2 +- src/png.c | 2 +- src/scale.c | 2 +- src/xlib.c | 162 +++++++++++++++++++++++++++++++++------- 9 files changed, 266 insertions(+), 200 deletions(-) diff --git a/src/bmp.c b/src/bmp.c index 01a4970..6751a53 100644 --- a/src/bmp.c +++ b/src/bmp.c @@ -172,7 +172,7 @@ int bmp_read(struct image *img){ free(row); - img->state = LOADED; + img->state |= LOADED | SLOWLOADED; return 0; } diff --git a/src/gif.c b/src/gif.c index ef6c312..7c55209 100644 --- a/src/gif.c +++ b/src/gif.c @@ -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; } diff --git a/src/jpeg.c b/src/jpeg.c index d10cede..90ff880 100644 --- a/src/jpeg.c +++ b/src/jpeg.c @@ -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; } diff --git a/src/main.c b/src/main.c index 3bf667a..2204393 100644 --- a/src/main.c +++ b/src/main.c @@ -8,18 +8,12 @@ #include #include -#include -#include -#include - #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; } diff --git a/src/meh.h b/src/meh.h index b8522d9..ca737f8 100644 --- a/src/meh.h +++ b/src/meh.h @@ -1,8 +1,8 @@ +#ifndef MEH_H +#define MEH_H MEH_H #include -#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; } diff --git a/src/png.c b/src/png.c index 9e9077d..290f51d 100644 --- a/src/png.c +++ b/src/png.c @@ -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)]; diff --git a/src/xlib.c b/src/xlib.c index a407f15..06f63f8 100644 --- a/src/xlib.c +++ b/src/xlib.c @@ -1,9 +1,4 @@ -#include -#include -#include -#include - #include #include #include @@ -11,18 +6,30 @@ #include #include +#include +#include +#include +#include + #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; + } + } + } +} -- cgit v1.2.3