aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Hawthorn <john.hawthorn@gmail.com>2010-01-04 10:09:04 -0800
committerJohn Hawthorn <john.hawthorn@gmail.com>2010-01-04 10:09:04 -0800
commitbdfc9445506d72d3eec7c3902449efaf13cf0d98 (patch)
tree2c75e72e332c11a3fa290c08355ea850f5612f9c
parentd6bffd293a1443d90c22c24ea162d4ebd6004b00 (diff)
downloadmirror-meh-bdfc9445506d72d3eec7c3902449efaf13cf0d98.tar.gz
mirror-meh-bdfc9445506d72d3eec7c3902449efaf13cf0d98.tar.bz2
mirror-meh-bdfc9445506d72d3eec7c3902449efaf13cf0d98.zip
major cleanup. xlib methods have been abstracted away as a generic
backend. Represent image states as flags.
-rw-r--r--src/bmp.c2
-rw-r--r--src/gif.c2
-rw-r--r--src/jpeg.c6
-rw-r--r--src/main.c236
-rw-r--r--src/meh.h52
-rw-r--r--src/netpbm.c2
-rw-r--r--src/png.c2
-rw-r--r--src/scale.c2
-rw-r--r--src/xlib.c162
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 <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;
}
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 <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;
}
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 <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;
+ }
+ }
+ }
+}