/*-
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1