/*
 * tkWinPixmap.c --
 *
 *	This file contains the Xlib emulation functions pertaining to creating
 *	and destroying pixmaps.
 *
 * Copyright (c) 1995 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tkWinPixmap.c,v 1.7.4.1 2009/04/30 13:48:00 dkf Exp $
 */

#include "tkWinInt.h"

/*
 *----------------------------------------------------------------------
 *
 * Tk_GetPixmap --
 *
 *	Creates an in memory drawing surface.
 *
 * Results:
 *	Returns a handle to a new pixmap.
 *
 * Side effects:
 *	Allocates a new Win32 bitmap.
 *
 *----------------------------------------------------------------------
 */

Pixmap
Tk_GetPixmap(
    Display *display,
    Drawable d,
    int width,
    int height,
    int depth)
{
    TkWinDrawable *newTwdPtr, *twdPtr;
    int planes;
    Screen *screen;

    display->request++;

    newTwdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable));
    newTwdPtr->type = TWD_BITMAP;
    newTwdPtr->bitmap.depth = depth;
    twdPtr = (TkWinDrawable *) d;
    if (twdPtr->type != TWD_BITMAP) {
	if (twdPtr->window.winPtr == NULL) {
	    newTwdPtr->bitmap.colormap = DefaultColormap(display,
		    DefaultScreen(display));
	} else {
	    newTwdPtr->bitmap.colormap = twdPtr->window.winPtr->atts.colormap;
	}
    } else {
	newTwdPtr->bitmap.colormap = twdPtr->bitmap.colormap;
    }
    screen = &display->screens[0];
    planes = 1;
    if (depth == screen->root_depth) {
	planes = (int) screen->ext_data;
	depth /= planes;
    }
    newTwdPtr->bitmap.handle =
	    CreateBitmap(width, height, (DWORD) planes, (DWORD) depth, NULL);

    /*
     * CreateBitmap tries to use memory on the graphics card. If it fails,
     * call CreateDIBSection which uses real memory; slower, but at least
     * still works. [Bug 2080533]
     */

    if (newTwdPtr->bitmap.handle == NULL) {
	static int repeatError = 0;
	unsigned char *bits = NULL;
	BITMAPINFO bitmapInfo;
	HDC dc;

	memset(&bitmapInfo, 0, sizeof(bitmapInfo));
	bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader);
	bitmapInfo.bmiHeader.biWidth = width;
	bitmapInfo.bmiHeader.biHeight = height;
	bitmapInfo.bmiHeader.biPlanes = planes;
	bitmapInfo.bmiHeader.biBitCount = depth;
	bitmapInfo.bmiHeader.biCompression = BI_RGB;
	bitmapInfo.bmiHeader.biSizeImage = 0;
	dc = GetDC(NULL);
	newTwdPtr->bitmap.handle = CreateDIBSection(dc, &bitmapInfo,
		DIB_RGB_COLORS, (void **) &bits, 0, 0);
	ReleaseDC(NULL, dc);

	/*
	 * Oh no! Things are still going wrong. Pop up a warning message here
	 * (because things will probably crash soon) which will encourage
	 * people to report this as a bug...
	 */

	if (newTwdPtr->bitmap.handle == NULL && !repeatError) {
	    LPVOID lpMsgBuf;

	    repeatError = 1;
	    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
		    FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
		    NULL, GetLastError(),
		    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		    (LPTSTR) &lpMsgBuf, 0, NULL)) {
		MessageBox(NULL, (LPCTSTR) lpMsgBuf,
			"Tk_GetPixmap: Error from CreateDIBSection",
			MB_OK | MB_ICONINFORMATION);
		LocalFree(lpMsgBuf);
	    }
	}
    }

    if (newTwdPtr->bitmap.handle == NULL) {
	ckfree((char *) newTwdPtr);
	return None;
    }

    return (Pixmap) newTwdPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_FreePixmap --
 *
 *	Release the resources associated with a pixmap.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Deletes the bitmap created by Tk_GetPixmap.
 *
 *----------------------------------------------------------------------
 */

void
Tk_FreePixmap(
    Display *display,
    Pixmap pixmap)
{
    TkWinDrawable *twdPtr = (TkWinDrawable *) pixmap;

    display->request++;
    if (twdPtr != NULL) {
	DeleteObject(twdPtr->bitmap.handle);
	ckfree((char *) twdPtr);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkSetPixmapColormap --
 *
 *	The following function is a hack used by the photo widget to
 *	explicitly set the colormap slot of a Pixmap.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

void
TkSetPixmapColormap(
    Pixmap pixmap,
    Colormap colormap)
{
    TkWinDrawable *twdPtr = (TkWinDrawable *)pixmap;
    twdPtr->bitmap.colormap = colormap;
}

/*
 *----------------------------------------------------------------------
 *
 * XGetGeometry --
 *
 *	Retrieve the geometry of the given drawable. Note that this is a
 *	degenerate implementation that only returns the size of a pixmap or
 *	window.
 *
 * Results:
 *	Returns 0.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
XGetGeometry(
    Display *display,
    Drawable d,
    Window *root_return,
    int *x_return,
    int *y_return,
    unsigned int *width_return,
    unsigned int *height_return,
    unsigned int *border_width_return,
    unsigned int *depth_return)
{
    TkWinDrawable *twdPtr = (TkWinDrawable *)d;

    if (twdPtr->type == TWD_BITMAP) {
	HDC dc;
	BITMAPINFO info;

	if (twdPtr->bitmap.handle == NULL) {
	    Tcl_Panic("XGetGeometry: invalid pixmap");
	}
	dc = GetDC(NULL);
	info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	info.bmiHeader.biBitCount = 0;
	if (!GetDIBits(dc, twdPtr->bitmap.handle, 0, 0, NULL, &info,
		DIB_RGB_COLORS)) {
	    Tcl_Panic("XGetGeometry: unable to get bitmap size");
	}
	ReleaseDC(NULL, dc);

	*width_return = info.bmiHeader.biWidth;
	*height_return = info.bmiHeader.biHeight;
    } else if (twdPtr->type == TWD_WINDOW) {
	RECT rect;

	if (twdPtr->window.handle == NULL) {
	    Tcl_Panic("XGetGeometry: invalid window");
	}
	GetClientRect(twdPtr->window.handle, &rect);
	*width_return = rect.right - rect.left;
	*height_return = rect.bottom - rect.top;
    } else {
	Tcl_Panic("XGetGeometry: invalid window");
    }
    return 1;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
