aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/bmp.c24
-rw-r--r--src/gif.c6
-rw-r--r--src/jpeg.c4
-rw-r--r--src/main.c199
-rw-r--r--src/meh.h19
-rw-r--r--src/png.c10
-rw-r--r--src/xlib.c182
8 files changed, 269 insertions, 177 deletions
diff --git a/Makefile b/Makefile
index 4622ca5..6d9243d 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ SRCFILES := $(wildcard src/*.c)
OBJFILES := $(SRCFILES:%.c=%.o)
DEPFILES := $(OBJFILES:%.o=%.d)
CLEANFILES := $(CLEANFILES) $(DEPFILES) $(OBJFILES) meh
-LIBS := -lX11 -ljpeg -lpng -lgif
+LIBS := -lX11 -lXext -ljpeg -lpng -lgif
meh: $(OBJFILES)
$(CC) -o $@ $(OBJFILES) $(LIBS)
diff --git a/src/bmp.c b/src/bmp.c
index 6d0daa2..4024521 100644
--- a/src/bmp.c
+++ b/src/bmp.c
@@ -55,13 +55,13 @@ struct image *bmp_open(FILE *f){
if(headersize == 12){ /* OS/2 v1 */
b->ncolors = 0;
fseek(f, 18, SEEK_SET);
- b->img.width = getshort(f);
- b->img.height = getshort(f);
+ b->img.bufwidth = getshort(f);
+ b->img.bufheight = getshort(f);
b->compression = 0;
}else{
fseek(f, 18, SEEK_SET);
- b->img.width = getlong(f);
- b->img.height = getlong(f);
+ b->img.bufwidth = getlong(f);
+ b->img.bufheight = getlong(f);
fseek(f, 28, SEEK_SET);
b->bpp = getshort(f);
@@ -83,7 +83,7 @@ struct image *bmp_open(FILE *f){
}
if(b->bpp >= 16){
- b->rowwidth = b->img.width * b->bpp / 8;
+ b->rowwidth = b->img.bufwidth * b->bpp / 8;
b->colours = NULL;
}else{
int i;
@@ -96,7 +96,7 @@ struct image *bmp_open(FILE *f){
if(headersize != 12)
getc(f);
}
- b->rowwidth = (b->img.width * b->bpp + 7) / 8;
+ b->rowwidth = (b->img.bufwidth * b->bpp + 7) / 8;
}
if(b->rowwidth & 3){
b->rowwidth += 4 - (b->rowwidth & 3);
@@ -116,7 +116,7 @@ static int readrow(struct image *img, unsigned char *row, unsigned char *buf){
struct bmp_t *b = (struct bmp_t *)img;
unsigned int x, i = 0;
if(b->bpp == 24 || b->bpp == 32){
- for(x = 0; x < img->width * 3; x+=3){
+ for(x = 0; x < img->bufwidth * 3; x+=3){
buf[x + 2] = row[i++];
buf[x + 1] = row[i++];
buf[x + 0] = row[i++];
@@ -124,7 +124,7 @@ static int readrow(struct image *img, unsigned char *row, unsigned char *buf){
i++;
}
}else if(b->bpp == 16){
- for(x = 0; x < img->width * 3; x+=3){
+ for(x = 0; x < img->bufwidth * 3; x+=3){
unsigned short c;
c = row[i++];
c |= row[i++] << 8;
@@ -134,7 +134,7 @@ static int readrow(struct image *img, unsigned char *row, unsigned char *buf){
int mask;
int pixelsperbit = 8 / b->bpp;
mask = ~((~0) << b->bpp);
- for(x = 0; x < img->width; x++){
+ for(x = 0; x < img->bufwidth; x++){
unsigned char c = ((row[i / pixelsperbit]) >> ((8 - ((i+1) % pixelsperbit) * b->bpp)) % 8) & mask;
*buf++ = b->colours[c].r;
*buf++ = b->colours[c].g;
@@ -156,11 +156,11 @@ int bmp_read(struct image *img){
FILE *f = b->f;
row = malloc(b->rowwidth);
- dy = img->width * 3;
- i = img->height * dy;
+ dy = img->bufwidth * 3;
+ i = img->bufheight * dy;
fseek(f, b->bitmapoffset, SEEK_SET);
- for(y = img->height; y; y--){
+ for(y = img->bufheight; y; y--){
i -= dy;
if(fread(row, 1, b->rowwidth, f) != b->rowwidth || readrow(img, row, &img->buf[i])){
free(row);
diff --git a/src/gif.c b/src/gif.c
index ae15418..8da6554 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -42,8 +42,8 @@ static struct image *gif_open(FILE *f){
g->f = f;
g->gif = gif;
- g->img.width = gif->SWidth;
- g->img.height = gif->SHeight;
+ g->img.bufwidth = gif->SWidth;
+ g->img.bufheight = gif->SHeight;
return (struct image *)g;
}
@@ -70,7 +70,7 @@ static int gif_read(struct image *img){
return 1;
}
- for(i = 0; i < img->width * img->height; i++){
+ for(i = 0; i < img->bufwidth * img->bufheight; i++){
unsigned char idx = s->RasterBits[i];
img->buf[j++] = colormap[idx].Red;
img->buf[j++] = colormap[idx].Green;
diff --git a/src/jpeg.c b/src/jpeg.c
index 797bdb4..5745541 100644
--- a/src/jpeg.c
+++ b/src/jpeg.c
@@ -53,8 +53,8 @@ static struct image *jpeg_open(FILE *f){
jpeg_calc_output_dimensions(&j->cinfo);
- j->img.width = j->cinfo.output_width;
- j->img.height = j->cinfo.output_height;
+ j->img.bufwidth = j->cinfo.output_width;
+ j->img.bufheight = j->cinfo.output_height;
return (struct image *)j;
}
diff --git a/src/main.c b/src/main.c
index a8d043b..99fedbb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -41,38 +41,51 @@ void usage(){
exit(EXIT_FAILURE);
}
-struct image *imgopen(FILE *f){
+struct image *newimage(FILE *f){
struct image *img = NULL;
struct imageformat **fmt = formats;
for(fmt = formats; *fmt; fmt++){
if((img = (*fmt)->open(f))){
img->fmt = *fmt;
+ img->ximg = NULL;
+ img->redraw = 1;
+ img->state = NONE;
return img;
}
}
return NULL;
}
+struct image *imgopen(FILE *f){
+ return newimage(f);
+}
+
static int imageslen;
static int imageidx;
static char **images;
-static char *filename = NULL;
+//static char *filename = NULL;
static int width = 0, height = 0;
static struct image *img = NULL;
-static XImage *ximg = NULL;
-static int redraw = 0;
+
+void freeimage(struct image *img){
+ if(img){
+ if(img->ximg)
+ freeXImg(img->ximg);
+ if(img->buf)
+ free(img->buf);
+ free(img);
+ }
+}
void nextimage(){
if(++imageidx == imageslen)
imageidx = 0;
- filename = images[imageidx];
}
void previmage(){
if(--imageidx < 0)
imageidx = imageslen - 1;
- filename = images[imageidx];
}
static void (*direction)() = nextimage;
@@ -85,7 +98,7 @@ void handlekeypress(XEvent *event){
exit(0);
break;
case XK_Return:
- puts(filename);
+ // puts(filename);
fflush(stdout);
break;
case XK_t:
@@ -95,17 +108,12 @@ void handlekeypress(XEvent *event){
direction = key == XK_t ? nextimage : previmage;
direction();
/* Pass through */
+ freeimage(img);
+ img = NULL;
+ break;
case XK_r:
- if(img){
- if(img->buf)
- free(img->buf);
- free(img);
- }
- if(ximg)
- XDestroyImage(ximg);
- ximg = NULL;
+ freeimage(img);
img = NULL;
- redraw = 1;
break;
}
}
@@ -116,18 +124,30 @@ void handleevent(XEvent *event){
if(width != event->xconfigure.width || height != event->xconfigure.height){
width = event->xconfigure.width;
height = event->xconfigure.height;
- redraw = 1;
- if(ximg)
- XDestroyImage(ximg);
- ximg = NULL;
+ if(img){
+ if(img->ximg)
+ XDestroyImage(img->ximg);
+ img->ximg = NULL;
+ img->redraw = 1;
+ if(img->state == LINEARDRAWN)
+ img->state = LINEAR;
+ else if(img->state == BILINEARDRAWN)
+ img->state = BILINEAR;
+ }
/* Some window managers need reminding */
if(img)
- setaspect(img->width, img->height);
+ setaspect(img->bufwidth, img->bufheight);
}
break;
case Expose:
- redraw = 1;
+ if(img){
+ img->redraw = 1;
+ if(img->state == LINEARDRAWN)
+ img->state = LINEAR;
+ else if(img->state == BILINEARDRAWN)
+ img->state = BILINEAR;
+ }
break;
case KeyPress:
handlekeypress(event);
@@ -135,51 +155,58 @@ void handleevent(XEvent *event){
}
}
-void doredraw(){
- if(!img){
- if(!filename)
- return;
- const char *firstimg = filename;
- while(!img){
- FILE *f;
- if((f = fopen(filename, "rb"))){
- if((img = imgopen(f)))
- break;
- else
- fprintf(stderr, "Invalid format '%s'\n", filename);
- }else{
- fprintf(stderr, "Cannot open '%s'\n", filename);
+struct image *imageopen2(){
+ char *filename = images[imageidx];
+ struct image *i;
+ FILE *f;
+ if((f = fopen(filename, "rb"))){
+ if((i = imgopen(f)))
+ return i;
+ else
+ fprintf(stderr, "Invalid format '%s'\n", filename);
+ }else{
+ fprintf(stderr, "Cannot open '%s'\n", filename);
+ }
+ return NULL;
+}
+
+int doredraw(struct image **i){
+ if(!*i){
+ int firstimg = imageidx;
+ while(!*i){
+ if((*i = imageopen2(images[imageidx]))){
+ break;
}
if(mode == MODE_CTL)
- return;
+ return 0;
direction();
- if(filename == firstimg){
+ if(imageidx == firstimg){
fprintf(stderr, "No valid images to view\n");
exit(EXIT_FAILURE);
}
}
- setaspect(img->width, img->height);
+ setaspect((*i)->bufwidth, (*i)->bufheight);
- img->buf = malloc(3 * img->width * img->height);
- if(img->fmt->read(img)){
+ (*i)->buf = malloc(3 * (*i)->bufwidth * (*i)->bufheight);
+ if((*i)->fmt->read(*i)){
fprintf(stderr, "read error!\n");
}
- img->fmt->close(img);
-
- /* Allow for some events to be read, read is slow */
- /*while(XPending(display)){
- XEvent event;
- XNextEvent(display, &event);
- handleevent(&event);
- }*/
+ (*i)->fmt->close(*i);
+ return 1;
+ }else if(width && height){
+ if(!(*i)->ximg){
+ (*i)->ximg = getimage(*i, width, height);
+ return 1;
+ }else if((*i)->redraw){ /* TODO */
+ drawimage((*i)->ximg, width, height);
+ (*i)->redraw = 0;
+ return 1;
+ }
}
- if(!ximg)
- ximg = getimage(img, width, height);
- drawimage(ximg, width, height);
+ return 0;
}
-
void run(){
int xfd;
xfd = ConnectionNumber(display);
@@ -187,8 +214,6 @@ void run(){
struct timeval tv0 = {0, 0};
struct timeval *tv = &tv0;
- char buf[512];
- int bufidx = 0;
for(;;){
FD_ZERO(&fds);
FD_SET(xfd, &fds);
@@ -200,48 +225,26 @@ void run(){
}
if(FD_ISSET(0, &fds)){
assert(mode == MODE_CTL);
- int n = read(0, buf, 512 - bufidx);
- if(n == -1){
- perror("read failed");
- }else if(n == 0){
- fprintf(stderr, "done reading\n");
- exit(0);
- }
- char *p;
- p = &buf[bufidx];
- bufidx+=n;
- for(; n > 0; p++, n--){
- if(*p == '\n' || *p == '\0'){
- n--;
- *p = '\0';
- strcpy(filename, buf);
- for(;n && (*p == '\0' || *p == '\n'); p++, n--);
- bufidx = n;
- if(n)
- memmove(buf, p, n);
- if(img){
- if(img->buf)
- free(img->buf);
- free(img);
- }
- if(ximg)
- XDestroyImage(ximg);
- ximg = NULL;
- img = NULL;
- redraw = 1;
- tv = &tv0;
- }
- }
+ exit(1);
}
- if(!XPending(display) && ret == 0 && redraw){
- doredraw();
- tv = NULL;
- }
- while(XPending(display)){
- tv = &tv0;
- XEvent event;
- XNextEvent(display, &event);
- handleevent(&event);
+ if(XPending(display)){
+ do{
+ tv = &tv0;
+ XEvent event;
+ XNextEvent(display, &event);
+ handleevent(&event);
+ }while(XPending(display));
+ }else if(ret == 0){
+ if(!img || img->state != BILINEARDRAWN){
+ doredraw(&img);
+ }
+ /*else if(!nextimg || !nextimg->ximg || !nextimg->redraw){
+ doredraw(&nextimg);
+ }else if(!previmg || !previmg->ximg || !previmg->redraw){
+ doredraw(&previmg);
+ }else{
+ tv = &tv0;
+ }*/
}
}
}
@@ -254,8 +257,7 @@ int main(int argc, char *argv[]){
if(argc != 2)
usage();
mode = MODE_CTL;
- filename = malloc(512);
- filename[0] = '\0';
+ exit(EXIT_FAILURE);
}else if(!strcmp(argv[1], "-list")){
if(argc != 2)
usage();
@@ -267,7 +269,6 @@ int main(int argc, char *argv[]){
images = &argv[1];
imageslen = argc-1;
imageidx = 0;
- filename = argv[1];
}
xinit();
run();
diff --git a/src/meh.h b/src/meh.h
index 521e4a9..d7f160e 100644
--- a/src/meh.h
+++ b/src/meh.h
@@ -1,6 +1,8 @@
#include <stdio.h>
+#include "X11/Xlib.h"
+
struct image;
struct imageformat{
@@ -9,14 +11,25 @@ struct imageformat{
void (*close)(struct image *);
};
+typedef enum{
+ NONE,
+ IMG,
+ ALLOC,
+ LINEAR,
+ LINEARDRAWN,
+ BILINEAR,
+ BILINEARDRAWN,
+} drawstate;
+
struct image{
unsigned char *buf;
- unsigned int width, height;
+ unsigned int bufwidth, bufheight;
struct imageformat *fmt;
+ int redraw;
+ drawstate state;
+ XImage *ximg;
};
-#include "X11/Xlib.h"
-
XImage *ximage(struct image *img, unsigned int width, unsigned int height);
void setaspect(unsigned int w, unsigned int h);
void xinit();
diff --git a/src/png.c b/src/png.c
index fa6e9f7..6f567b1 100644
--- a/src/png.c
+++ b/src/png.c
@@ -54,8 +54,8 @@ struct image *png_open(FILE *f){
png_read_info(p->png_ptr, p->info_ptr);
- p->img.width = png_get_image_width(p->png_ptr, p->info_ptr);
- p->img.height = png_get_image_height(p->png_ptr, p->info_ptr);
+ p->img.bufwidth = png_get_image_width(p->png_ptr, p->info_ptr);
+ p->img.bufheight = png_get_image_height(p->png_ptr, p->info_ptr);
return (struct image *)p;
}
@@ -91,9 +91,9 @@ int png_read(struct image *img){
png_read_update_info(p->png_ptr, p->info_ptr);
}
- row_pointers = (png_bytepp)malloc(img->height * sizeof(png_bytep));
- for(y = 0; y < img->height; y++)
- row_pointers[y] = img->buf + y * img->width * 3;
+ row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep));
+ for(y = 0; y < img->bufheight; y++)
+ row_pointers[y] = img->buf + y * img->bufwidth * 3;
png_read_image(p->png_ptr, row_pointers);
free(row_pointers);
diff --git a/src/xlib.c b/src/xlib.c
index d36a931..511e740 100644
--- a/src/xlib.c
+++ b/src/xlib.c
@@ -7,6 +7,9 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
#include "meh.h"
@@ -16,80 +19,139 @@ int screen;
Window window;
GC gc;
-static unsigned int getshift(unsigned int mask){
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
- return __builtin_ctz(mask);
-#else
- int i = 0;
- while((mask & 1) == 0){
- i++;
- mask >>= 1;
+int xshm = 0;
+
+#define GETVAL(x, c) (ibuf[(x) * 3 + (c)])
+#define GETLVAL(x, y, u, v, c) (( \
+ (GETVAL((x), (c)) * (1023^(u)) + GETVAL((x)+1, (c)) * (u)) * (1023^(v)) + \
+ (GETVAL((x)+img->bufwidth, (c)) * (1023^(u)) + GETVAL((x)+img->bufwidth+1, (c)) * (u)) * (v)) >> 20)
+
+void scale(struct image *img, XImage *ximg){
+ int x, y;
+ unsigned char * __restrict__ ibuf;
+ char* __restrict__ newBuf = ximg->data;
+ unsigned int jdy = ximg->bytes_per_line / 4 - ximg->width;
+ unsigned int dx = (img->bufwidth << 10) / ximg->width;
+
+ struct timeval t0;
+ struct timeval t1;
+ gettimeofday(&t0, NULL);
+
+ for(y = 0; y < ximg->height; y++){
+ unsigned int bufy = (y << 10) * img->bufheight / ximg->height;
+ unsigned int v_ratio = (bufy & 1023);
+ unsigned int bufx = img->bufwidth / ximg->width;
+ unsigned char *ibuf = &img->buf[y * img->bufheight / ximg->height * img->bufwidth * 3];
+ for(x = ximg->width; x; x--){
+ unsigned int u_ratio = (bufx & 1023);
+
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 2);
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 1);
+ *newBuf++ = GETLVAL(bufx >> 10, bufy >> 10, u_ratio, v_ratio, 0);
+ newBuf++;
+
+ bufx += dx;
+ }
+ newBuf += jdy;
}
- return i;
-#endif
+
+ gettimeofday(&t1, NULL);
+ printf("%i ms\n", ((t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec) / 1000);
}
+
+void linearscale(struct image *img, XImage *ximg){
+ unsigned int i;
+ int x, y;
+ unsigned int dx;
+ unsigned char * __restrict__ ibuf;
+ char* __restrict__ newBuf = ximg->data;
+ unsigned int jdy = ximg->bytes_per_line / 4 - ximg->width;
+ dx = (img->bufwidth << 10) / ximg->width;
+
+ struct timeval t0;
+ struct timeval t1;
+ gettimeofday(&t0, NULL);
+
+ for(y = 0; y < ximg->height; y++){
+ i = 0;
+ ibuf = &img->buf[y * img->bufheight / ximg->height * img->bufwidth * 3];
+ for(x = 0; x < ximg->width; x++){
+ *newBuf++ = (ibuf[(i >> 10)*3+2]);
+ *newBuf++ = (ibuf[(i >> 10)*3+1]);
+ *newBuf++ = (ibuf[(i >> 10)*3]);
+ newBuf++;
+
+ i += dx;
+ }
+ newBuf += jdy;
+ }
+
+ gettimeofday(&t1, NULL);
+ printf("%i ms\n", ((t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec) / 1000);
+}
+
+XShmSegmentInfo *shminfo;
XImage *ximage(struct image *img, unsigned int width, unsigned int height) {
int depth;
XImage *ximg = NULL;
Visual *vis;
- unsigned int rshift, gshift, bshift;
- unsigned int i;
- unsigned int x,y;
- unsigned int j = 0;
depth = DefaultDepth(display, screen);
vis = DefaultVisual(display, screen);
- rshift = getshift(vis->red_mask);
- gshift = getshift(vis->green_mask);
- bshift = getshift(vis->blue_mask);
-
- if (depth >= 24) {
- unsigned char *ibuf;
- unsigned int dx;
- size_t numNewBufBytes = ((sizeof(u_int32_t)) * (width) * (height));
- u_int32_t *newBuf = malloc(numNewBufBytes);
-
- dx = 1024 * img->width / width;
- for(y = 0; y < height; y++){
- i = 0;
- ibuf = &img->buf[y * img->height / height * img->width * 3];
- for(x = 0; x < width; x++){
- unsigned int r, g, b;
- r = (ibuf[(i >> 10)*3] << rshift) & vis->red_mask;
- g = (ibuf[(i >> 10)*3+1] << gshift) & vis->green_mask;
- b = (ibuf[(i >> 10)*3+2] << bshift) & vis->blue_mask;
-
- newBuf[j++] = r | g | b;
- i += dx;
+ if(depth >= 24){
+ if(xshm){
+ shminfo = malloc(sizeof(XShmSegmentInfo));
+ if(!(ximg = XShmCreateImage(display,
+ CopyFromParent, depth,
+ ZPixmap,
+ NULL,
+ shminfo,
+ width, height
+ ))){
+ }
+ if((shminfo->shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT|0777)) == -1){
+ fprintf(stderr, "XShm problems\n");
+ exit(1);
+ }
+ if((shminfo->shmaddr = ximg->data = shmat(shminfo->shmid, 0, 0)) == (void *)-1){
+ fprintf(stderr, "XShm problems\n");
+ exit(1);
+ }
+ shminfo->readOnly = False;
+ if(!XShmAttach(display, shminfo)){
+ fprintf(stderr, "XShm problems, falling back to to XImage\n");
+ xshm = 0;
}
}
-
- ximg = XCreateImage (display,
- CopyFromParent, depth,
- ZPixmap, 0,
- (char *) newBuf,
- width, height,
- 32, 0
- );
+ if(!xshm){
+ ximg = XCreateImage(display,
+ CopyFromParent, depth,
+ ZPixmap, 0,
+ NULL,
+ width, height,
+ 32, 0
+ );
+ ximg->data = malloc(ximg->bytes_per_line * ximg->height + /*HACK*/(ximg->bytes_per_line+1));
+ XInitImage(ximg);
+ }
+ scale(img, ximg);
}else{
/* TODO other depths */
- fprintf(stderr, "This program does not support display depths less than 24.\n");
+ fprintf(stderr, "This program does not yet support display depths <24.\n");
exit(1);
return NULL;
}
- XInitImage(ximg);
-
return ximg;
}
XImage *getimage(struct image *img, unsigned int width, unsigned int height){
- if(width * img->height > height * img->width){
- return ximage(img, img->width * height / img->height, height);
+ if(width * img->bufheight > height * img->bufwidth){
+ return ximage(img, img->bufwidth * height / img->bufheight, height);
}else{
- return ximage(img, width, img->height * width / img->width);
+ return ximage(img, width, img->bufheight * width / img->bufwidth);
}
}
@@ -103,7 +165,7 @@ void drawimage(XImage *ximg, unsigned int width, unsigned int height){
if(xoffset){
rects[0].width = rects[1].width = xoffset;
rects[0].height = rects[1].height = height;
- rects[1].x = width-xoffset;
+ rects[1].x = width - xoffset;
rects[1].y = 0;
}else if(yoffset){
rects[0].width = rects[1].width = width;
@@ -113,10 +175,26 @@ void drawimage(XImage *ximg, unsigned int width, unsigned int height){
}
XFillRectangles(display, window, gc, rects, 2);
}
- XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height);
+ if(xshm){
+ XShmPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height, False);
+ }else{
+ XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->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 setaspect(unsigned int w, unsigned int h){
XSizeHints *hints = XAllocSizeHints();