The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
 *imgWinPmap.c --
 *
 *	Implement the Windows specific function calls for the pixmap
 *	image type.
 *
 * Copyright (c) 1996, Expert Interface Technologies
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 */

#include <windows.h>
#include "tkInt.h"
#include "tkWinInt.h"
#include <stdlib.h>
#include <imgPmap.h>
#include "imgInt.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>

typedef struct PixmapData {
    HDC bitmapDC;               /* Bitmap used on Windows platforms */
    HDC maskDC;                 /* Mask used on Windows platforms */
    HBITMAP bitmap, bitmapOld;
    HBITMAP maskBm, maskBmOld;
} PixmapData;

static void		CopyTransparent _ANSI_ARGS_((Display* display,
			    HDC srcDC, Drawable dest,
			    int src_x, int src_y, int width,
			    int height, int dest_x, int dest_y,
			    HDC maskDC));


/*----------------------------------------------------------------------
 * ImgInitPixmapInstance --
 *
 *	Initializes the platform-specific data of a pixmap instance
 *
 *----------------------------------------------------------------------
 */

void
ImgInitPixmapInstance(masterPtr, instancePtr)
    PixmapMaster *masterPtr;	/* Pointer to master for image. */
    PixmapInstance *instancePtr;/* The pixmap instance. */
{
    PixmapData * dataPtr;

    dataPtr = (PixmapData *)ckalloc(sizeof(PixmapData));
    dataPtr->maskDC = NULL;
    dataPtr->bitmapDC = NULL;

    instancePtr->clientData = (ClientData)dataPtr;
}


/*----------------------------------------------------------------------
 * ImgXpmAllocTmpBuffer --
 *
 *	Allocate a temporary space to draw the image.
 *
 *----------------------------------------------------------------------
 */
void
ImgXpmAllocTmpBuffer(masterPtr, instancePtr, imagePtr, maskPtr)
    PixmapMaster * masterPtr;
    PixmapInstance * instancePtr;
    XImage ** imagePtr;
    XImage ** maskPtr;
{
    XImage * image = NULL, * mask = NULL;
    Display *display = Tk_Display(instancePtr->tkwin);
    int depth;

    depth = Tk_Depth(instancePtr->tkwin);

    instancePtr->pixmap = Tk_GetPixmap(display,
	Tk_WindowId(instancePtr->tkwin),
	masterPtr->size[0], masterPtr->size[1], depth);

    mask = (XImage*)ckalloc(sizeof(XImage));

    mask->width = masterPtr->size[0];
    mask->height = masterPtr->size[1];
    mask->bytes_per_line = (mask->width+7)/8;

    mask->data =
      (char *)ckalloc(mask->bytes_per_line  * masterPtr->size[1]);

    *imagePtr = image;
    *maskPtr = mask;
}


void
ImgXpmFreeTmpBuffer(masterPtr, instancePtr, image, mask)
    PixmapMaster * masterPtr;
    PixmapInstance * instancePtr;
    XImage * image;
    XImage * mask;
{
    if (image) {
	ckfree((char*)image->data);
	image->data = NULL;
	XDestroyImage(image);
    }
    if (mask) {
	ckfree((char*)mask->data);
	mask->data = NULL;
	ckfree((char*)mask);
    }
}


/*----------------------------------------------------------------------
 * ImgXpmSetPixel --
 *
 *	Sets the pixel at the given (x,y) coordinate to be the given
 *	color.
 *----------------------------------------------------------------------
 */
void
ImgXpmSetPixel(instancePtr, image, mask, x, y, colorPtr, isTranspPtr)
    PixmapInstance * instancePtr;
    XImage * image;
    XImage * mask;
    int x;
    int y;
    XColor * colorPtr;
    int * isTranspPtr;
{
    char * p;
    int n;
    GC gc;
    XGCValues gcValues;
    Display *display = Tk_Display(instancePtr->tkwin);

    if (colorPtr != NULL) {
	gcValues.foreground = colorPtr->pixel;
	gc = Tk_GetGC(instancePtr->tkwin, GCForeground, &gcValues);
	XDrawRectangle(display, instancePtr->pixmap, gc, x, y, 1, 1);
	Tk_FreeGC(display, gc);
    }

    p = mask->data;
    p+= y*(mask->bytes_per_line);
    p+= x/8;
    n = x%8;

    if (colorPtr != NULL) {
	*p |=  (1 << (7-n));
    } else {
	*p &= ~(1 << (7-n));
	*isTranspPtr = 1;
    }
}

/*----------------------------------------------------------------------
 * ImgXpmRealizePixmap --
 *
 *	On Unix: 	Create the pixmap from the buffer.
 *	On Windows:	Free the mask if there are no transparent pixels.
 *----------------------------------------------------------------------
 */
void
ImgXpmRealizePixmap(masterPtr, instancePtr, image, mask, isTransp)
    PixmapMaster * masterPtr;
    PixmapInstance * instancePtr;
    XImage * image;
    XImage * mask;
{
    Display *display = Tk_Display(instancePtr->tkwin);
    PixmapData *dataPtr = (PixmapData*)instancePtr->clientData;
    HDC dc, bitmapDC;
    TkWinDCState dcState;
    HBITMAP bitmap, bitmapOld;
    int w, h;

    w = masterPtr->size[0];
    h = masterPtr->size[1];

    dc = TkWinGetDrawableDC(display, instancePtr->pixmap, &dcState);
    bitmapDC = CreateCompatibleDC(dc);

    bitmap = CreateCompatibleBitmap(dc, w, h);
    bitmapOld = SelectObject(bitmapDC, bitmap);

    BitBlt(bitmapDC, 0, 0, w, h, dc, 0, 0, SRCCOPY);

    if (isTransp) {
	HDC maskDC;
	HBITMAP maskBm, maskBmOld;

	/*
	 * There are transparent pixels. We need a mask.
	 */
	maskDC = CreateCompatibleDC(dc);
	maskBm = CreateBitmap(w, h, 1, 1, (CONST VOID*)mask->data);
	maskBmOld = SelectObject(maskDC, maskBm);

	BitBlt(bitmapDC, 0, 0, w, h, maskDC, 0, 0, SRCAND);
	BitBlt(maskDC,   0, 0, w, h, maskDC, 0, 0, NOTSRCCOPY);

	TkWinReleaseDrawableDC(instancePtr->pixmap, dc, &dcState);
	dataPtr->maskDC = maskDC;
	dataPtr->maskBm = maskBm;
	dataPtr->maskBmOld = maskBmOld;
    } else {
	dataPtr->maskDC = NULL;
    }
    dataPtr->bitmapDC = bitmapDC;
    dataPtr->bitmap = bitmap;
    dataPtr->bitmapOld = bitmapOld;
}

void
ImgXpmFreeInstanceData(instancePtr, delete)
    PixmapInstance *instancePtr;	/* Pixmap instance. */
    int delete;				/* Should the instance data structure
					 * be deleted as well? */
{
    PixmapData *dataPtr = (PixmapData*)instancePtr->clientData;

    if (dataPtr->maskDC != NULL) {
	DeleteObject(SelectObject(dataPtr->maskDC,
	    dataPtr->maskBmOld));
	DeleteDC(dataPtr->maskDC);
	dataPtr->maskDC = NULL;
    }
    if (dataPtr->bitmapDC != NULL) {
	DeleteObject(SelectObject(dataPtr->bitmapDC,
	    dataPtr->bitmapOld));
	DeleteDC(dataPtr->bitmapDC);
	dataPtr->bitmapDC = NULL;
    }
    if (delete) {
	ckfree((char*)dataPtr);
	instancePtr->clientData = NULL;
    }
}

void
ImgpXpmDisplay(clientData, display, drawable, imageX, imageY, width,
	height, drawableX, drawableY)
    ClientData clientData;	/* Pointer to PixmapInstance structure for
				 * for instance to be displayed. */
    Display *display;		/* Display on which to draw image. */
    Drawable drawable;		/* Pixmap or window in which to draw image. */
    int imageX, imageY;		/* Upper-left corner of region within image
				 * to draw. */
    int width, height;		/* Dimensions of region within image to draw.*/
    int drawableX, drawableY;	/* Coordinates within drawable that
				 * correspond to imageX and imageY. */
{
    PixmapInstance *instancePtr = (PixmapInstance *) clientData;
    PixmapData *dataPtr = (PixmapData*)instancePtr->clientData;

    CopyTransparent(display, dataPtr->bitmapDC, drawable,
	imageX, imageY, width, height,
	drawableX, drawableY, dataPtr->maskDC);
}

static void
CopyTransparent(display, srcDC, dest, src_x, src_y, width, height, dest_x,
        dest_y,	maskDC)
    Display* display;
    HDC srcDC;
    Drawable dest;
    int src_x;
    int src_y;
    int width;
    int height;
    int dest_x;
    int dest_y;
    HDC maskDC;
{
    HDC destDC;
    TkWinDCState destState;

    destDC = TkWinGetDrawableDC(display, dest, &destState);

    if (maskDC) {
	BitBlt(destDC, dest_x, dest_y, width, height, maskDC, src_x, src_y,
	    SRCAND);
	BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
	    SRCPAINT);
    } else {
	BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
	    SRCCOPY);
    }

    TkWinReleaseDrawableDC(dest, destDC, &destState);
}