/*- * Copyright (c) 2001 Jordan DeLong * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "wm.h" /* flag if mitshm is available and usable */ static int image_mitshm = 0; /* determine if we can use MITSHM */ void image_init() { if (options.wantmitshm) { image_mitshm = XShmQueryExtension(display); if (image_mitshm) warnx("using MITSHM for images"); } else image_mitshm = 0; } /* create an ximage, using MITSHM if possible */ static XImage *createximg(screen_t *screen, int width, int height, XShmSegmentInfo **shminfo, int fallback) { XImage *ximage; /* use mitshm if available */ if (!image_mitshm) goto nomitshm; /* create the seginfo and the ximage */ *shminfo = malloc(sizeof(XShmSegmentInfo)); if (!*shminfo) return NULL; ximage = XShmCreateImage(display, DefaultVisual(display, screen->num), DefaultDepth(display, screen->num), ZPixmap, NULL, *shminfo, width, height); if (!ximage) goto free1; /* get a shared memory segment */ (*shminfo)->shmid = shmget(IPC_PRIVATE, ximage->bytes_per_line * ximage->height, IPC_CREAT | 0777); if ((*shminfo)->shmid == -1) goto free2; (*shminfo)->shmaddr = ximage->data = shmat((*shminfo)->shmid, 0, 0); (*shminfo)->readOnly = 0; /* try to attach the server */ if (XShmAttach(display, *shminfo) == 0) goto free3; XSync(display, 0); /* cause the seg to remove when all procs detach */ shmctl((*shminfo)->shmid, IPC_RMID, 0); /* if we get here we succeeded with shm */ return ximage; /* falls through to try a non shm ximage */ free3: shmctl((*shminfo)->shmid, IPC_RMID, 0); shmdt((*shminfo)->shmaddr); free2: XDestroyImage(ximage); free1: free(*shminfo); *shminfo = NULL; warnx("mitshm failed; falling back to normal ximage"); nomitshm: /* only proceed if non-mitshm are ok */ if (!fallback) return NULL; /* if mitshm isn't available, just use normal ximage */ ximage = XCreateImage(display, DefaultVisual(display, screen->num), DefaultDepth(display, screen->num), ZPixmap, 0, NULL, width, height, 8, 0); /* allocate memory for the image data */ ximage->data = malloc(ximage->bytes_per_line * height); if (!ximage->data) { XDestroyImage(ximage); return NULL; } return ximage; } /* create an image of a particular size */ image_t *image_create(screen_t *screen, int width, int height) { image_t *image; /* get memory for the image_t */ image = calloc(1, sizeof(image_t)); if (!image) return NULL; image->screen = screen; /* create the ximage */ image->ximage = createximg(screen, width, height, &image->shminfo, 1); if (!image->ximage) goto free; image->shmimg = image->shminfo != NULL; return image; free: free(image); return NULL; } /* create an image_t out of a pixmap for a particular screen */ image_t *image_frompixmap(pixmap_t *pixmap, screen_t *screen) { image_t *image; /* get memory for the image_t */ image = calloc(1, sizeof(image_t)); if (!image) return NULL; image->screen = screen; /* for shm we need to create the shm image first */ if (image_mitshm) { image->ximage = createximg(screen, pixmap->width, pixmap->height, &image->shminfo, 0); if (!image->ximage) goto nomitshm; image->shmimg = 1; XShmGetImage(display, pixmap->pixmaps[screen->num], image->ximage, 0, 0, AllPlanes); return image; } nomitshm: image->ximage = XGetImage(display, pixmap->pixmaps[screen->num], 0, 0, pixmap->width, pixmap->height, AllPlanes, ZPixmap); return image; } /* destroy an image_t */ void image_destroy(image_t *image) { if (image->shmimg) { XShmDetach(display, image->shminfo); shmdt(image->shminfo->shmaddr); free(image->shminfo); } XDestroyImage(image->ximage); free(image); } /* wrap image putting for abstraction of shm images */ void image_put(image_t *image, Drawable d, GC gc, int src_x, int src_y, int dest_x, int dest_y, int width, int height) { if (image->shmimg) XShmPutImage(display, d, gc, image->ximage, src_x, src_y, dest_x, dest_y, width, height, 0); else XPutImage(display, d, gc, image->ximage, src_x, src_y, dest_x, dest_y, width, height); XFlush(display); } /* make a copy of an image */ image_t *image_clone(image_t *src) { image_t *dest; /* get memory for the new image */ dest = calloc(1, sizeof(image_t)); if (!dest) return NULL; dest->screen = src->screen; /* copy the image */ if (src->shmimg) { dest->ximage = createximg(src->screen, src->ximage->width, src->ximage->height, &dest->shminfo, 0); if (!dest->ximage) goto nomitshm; dest->shmimg = 1; memcpy(dest->ximage->data, src->ximage->data, dest->ximage->bytes_per_line * dest->ximage->width); return dest; } nomitshm: dest->ximage = XSubImage(src->ximage, 0, 0, src->ximage->width, src->ximage->height); return dest; } /* scale an image to the size specified */ image_t *image_scale(image_t *src, int width, int height) { image_t *dest; Pixel pixel; double dx, dy; double srcx, srcy; int x, y; /* can't size to nothing */ assert(width > 0 && height > 0); /* * if the requested size is the current size, * just return a copy of the image. */ if (width == src->ximage->width && height == src->ximage->height) return image_clone(src); /* create the destination image */ dest = image_create(src->screen, width, height); if (!dest) return NULL; /* find the ratio of the old dims to new */ dx = (double) src->ximage->width / (double) width; dy = (double) src->ximage->height / (double) height; /* * perform the scaling; this is probably much slower than * it could be... */ for (y = 0, srcy = 0; y < height; y++, srcy += dy) for (x = 0, srcx = 0; x < width; x++, srcx += dx) { pixel = XGetPixel(src->ximage, (int) srcx, (int) srcy); XPutPixel(dest->ximage, x, y, pixel); } return dest; }