/*
	@(#)DrvColors.c	1.40
    	Copyright 1997 Willows Software, Inc. 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.


For more information about the Willows Twin Libraries.

	http://www.willows.com	

To send email to the maintainer of the Willows Twin Libraries.

	mailto:twin@willows.com 

*/

#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#include "windows.h"

#include "compat.h"
#include "Log.h"
#include "GdiObjects.h"
#include "DrvDC.h"
#include "DrvDP.h"
#include "Driver.h"

	/* enable new palette code */
#define	TWIN_PALETTE

#define xx_to_xxxx(x)	((unsigned short) (((x) * 0xffffUL) / 0xffUL))
#define xxxx_to_xx(x)	((unsigned char) (((x) * 0xffUL) / 0xffffUL))

/* exported inside the driver */
#ifdef TWIN_PALETTE
DWORD DrvMakePixel(COLORREF, LPDRIVERDC);
#else
DWORD DrvMakePixel(COLORREF);
#endif
void DrvGetXColor(COLORREF,XColor *);
/* prototype needed for WinCalloc, from kernel.c */
LPVOID WinCalloc( unsigned int units, unsigned int size );
#ifdef TWIN_PALETTE

Display *display;
static BOOL bPaletteDevice;

/* (Color) Device Colormap ************************************************* */

static int DeviceColormapSize = 0;
static Colormap DeviceColormap = (Colormap) 0;
static XColor *DeviceColormapValues = (XColor *) 0;
static unsigned long pixel0;
static unsigned long pixel_mask0, pixel_mask, pixel_masks[32];
static int pixel_numplanes;

static BOOL CreateDeviceColormap(Display *display, int screen,
	int minplanes, int maxplanes)
{
	int i, j;
	unsigned long *pixels, planes[32];

	/* pass 1: allocate colors from default colormap
	 * pass 2: create colormap & allocate colors from new colormap
	 */
	DeviceColormapSize = (XDefaultVisual(display, screen))->map_entries;
	for (i = 0; i < 2; i++)
	{
		/* pass 1: get default colormap
		 * pass 2: create custom colormap
		 */
		if (i == 0)
		{
			LOGSTR((LF_LOG, "CreateDeviceColormap:"
				" (LOG) use default colormap\n"));
			DeviceColormap = XDefaultColormap(display, screen);
		}
		else
		{
			LOGSTR((LF_LOG, "CreateDeviceColormap:"
				" (LOG) create colormap\n"));
			DeviceColormap = XCreateColormap(display,
				XRootWindow(display, screen),
				XDefaultVisual(display, screen),
				AllocNone);
		}
		/* pass 1: save default colormap colors for pass 2
		 * pass 2: initialize with default colormap colors to minimize
		 *	   techni-color(tm) effect
		 */
		if (i == 0)
		{
			DeviceColormapValues = (XColor *)
				WinMalloc(DeviceColormapSize * sizeof(XColor));
			for (j = 0; j < DeviceColormapSize; j++)
			{
				DeviceColormapValues[j].pixel = j;
			}
			XQueryColors(display, DeviceColormap,
				DeviceColormapValues,
				DeviceColormapSize);
		}
		else
		{
			pixels = (unsigned long *) WinMalloc(DeviceColormapSize *
				sizeof(unsigned long));
			if (!XAllocColorCells(display, DeviceColormap, True,
				planes, 0, pixels, DeviceColormapSize))
			{
				LOGSTR((LF_LOG, "CreateDeviceColormap:"
					" (LOG) XAllocColorCells() failed\n"));
			}
			XStoreColors(display, DeviceColormap,
				DeviceColormapValues,
				DeviceColormapSize);
			XFreeColors(display, DeviceColormap, pixels,
				DeviceColormapSize, 0L);
		}
		/* allocate as many color planes as possible */
		if ((minplanes < 1) || (maxplanes < 1))
			break;
		for (j = maxplanes; j >= minplanes; j--)
		{
			if (!XAllocColorCells(display, DeviceColormap, True,
				pixel_masks, j, &pixel0, 1))
			{
				LOGSTR((LF_LOG, "CreateDeviceColormap:"
					" (LOG) unable to alloc %d planes\n",
					j));
				continue;
			}
			pixel_numplanes = j;
			pixel_mask0 = ~0;
			for (pixel_mask = 0, j = 0; j < pixel_numplanes; j++)
			{
				pixel_mask |= pixel_masks[j];
				pixel_mask0 = min(pixel_mask0, pixel_masks[j]);
			}
			break;
		}
		if (j >= minplanes)
			break;
	}
	if (i == 2)
	{
		ERRSTR((LF_ERR, "CreateDeviceColormap:"
			" (ERR) unable to alloc %d to %d planes\n",
			minplanes, maxplanes));
		return (FALSE);
	}

	/* success */
	return (TRUE);

}

/* (Color) Default Palette ************************************************* */

#define DefaultPaletteSize\
	(sizeof(DefaultPalette)/sizeof(DefaultPalette[0]))

#define DefaultPaletteLoStaticUse\
	(DefaultPaletteSize/2)

#define DefaultPaletteHiStaticUse\
	(DefaultPaletteSize - DefaultPaletteLoStaticUse)

#define DefaultPaletteLoNoStaticUse\
	(1)

#define DefaultPaletteHiNoStaticUse\
	(1)

#define DefaultPaletteLoStaticIndex\
	(0)

#define DefaultPaletteHiStaticIndex\
	(DefaultPaletteSize - DefaultPaletteHiStaticUse)

#define DefaultPaletteLoNoStaticIndex\
	(0)

#define DefaultPaletteHiNoStaticIndex\
	(DefaultPaletteSize - DefaultPaletteHiNoStaticUse)

static PALETTEENTRY DefaultPalette[] =
{
	/* first 10 system palette entries */
	{ 0x00, 0x00, 0x00, 0 },		/* black */
	{ 0x80, 0x00, 0x00, 0 },		/* dark red */
	{ 0x00, 0x80, 0x00, 0 },		/* dark green */
	{ 0x80, 0x80, 0x00, 0 },		/* dark yellow */
	{ 0x00, 0x00, 0x80, 0 },		/* dark blue */
	{ 0x80, 0x00, 0x80, 0 },		/* dark magenta */
	{ 0x00, 0x80, 0x80, 0 },		/* dark cyan */
	{ 0xc0, 0xc0, 0xc0, 0 },		/* light gray */
	{ 0xc0, 0xdc, 0xc0, 0 },		/* money green */
	{ 0xa6, 0xca, 0xf0, 0 },		/* sky blue */
	/* last 10 system palette entries */
	{ 0xff, 0xfb, 0xf0, 0 },		/* cream */
	{ 0xa0, 0xa0, 0xa4, 0 },		/* light gray */
	{ 0x80, 0x80, 0x80, 0 },		/* medium gray */
	{ 0xff, 0x00, 0x00, 0 },		/* red */
	{ 0x00, 0xff, 0x00, 0 },		/* green */
	{ 0xff, 0xff, 0x00, 0 },		/* yellow */
	{ 0x00, 0x00, 0xff, 0 },		/* blue */
	{ 0xff, 0x00, 0xff, 0 },		/* magenta */
	{ 0x00, 0xff, 0xff, 0 },		/* cyan */
	{ 0xff, 0xff, 0xff, 0 },		/* white */
};

static DWORD DefaultPaletteMapper[DefaultPaletteSize];

static HPALETTE CreateDefaultPalette()
{
	union
	{
		LOGPALETTE LogPalette;
		PALETTEENTRY pad[sizeof(LOGPALETTE)/sizeof(PALETTEENTRY)
			+ DefaultPaletteSize];
	} u;
	int i;

	/* create logical palette from default palette */
	u.LogPalette.palVersion = 0x0300;
	u.LogPalette.palNumEntries = DefaultPaletteSize;
	for (i = 0; i < DefaultPaletteSize; i++)
		u.LogPalette.palPalEntry[i] = DefaultPalette[i];
	return (CreatePalette(&u.LogPalette));

}

/* (Color) System Palette ************************************************** */

static int SystemPaletteSize = 0;
static int SystemPaletteLoStaticUse = 0;
static int SystemPaletteHiStaticUse = 0;
static int SystemPaletteLoNoStaticUse = 0;
static int SystemPaletteHiNoStaticUse = 0;
static int SystemPaletteLoStaticIndex = 0;
static int SystemPaletteHiStaticIndex = 0;
static int SystemPaletteLoNoStaticIndex = 0;
static int SystemPaletteHiNoStaticIndex = 0;

static LPPALETTEENTRY SystemPalette = (LPPALETTEENTRY) 0;
static LPDWORD SystemPaletteMapper = (LPDWORD) 0;
static LPINT SystemPalettePixelUse = (LPINT) 0;

static BOOL CreateSystemPaletteMapper()
{
	int i;

	/* create system palette mapper once */
	if (SystemPaletteMapper)
		return (TRUE);

	/* create system palette mapper */
	if (!(SystemPaletteMapper = (LPDWORD)
		WinMalloc(SystemPaletteSize * sizeof(DWORD))))
	{
		ERRSTR((LF_ERR, "CreateSystemPaletteMapper:"
			" (ERR) malloc\n"));
		return (FALSE);
	}

	/* initialize system palette mapper */
	for (i = 0; i < SystemPaletteSize; i++)
	{
		SystemPaletteMapper[i] = pixel0 | (i * pixel_mask0);
		LOGSTR((LF_LOG, "CreateSystemPaletteMapper:"
			" (LOG) system palette [%04x] mapped to [%04x]\n",
			i, SystemPaletteMapper[i]));
	}
	return (TRUE);

}

static BOOL CreateSystemPalettePixelUse()
{
	int i;

	/* create system palette pixel use counter once */
	if (SystemPalettePixelUse)
		return (TRUE);

	/* create system palette pixel use counter */
	if (!(SystemPalettePixelUse = (LPINT)
		WinMalloc(SystemPaletteSize * sizeof(INT))))
	{
		ERRSTR((LF_ERR, "CreateSystemPalettePixelUse:"
			" (ERR) malloc\n"));
		return (FALSE);
	}

	/* initialize system palette pixel use counter */
	for (i = 0; i < SystemPaletteSize; i++)
	{
		SystemPalettePixelUse[i] = -1;
		LOGSTR((LF_LOG, "CreateSystemPalettePixelUse:"
			" (LOG) system palette [%04x] pixel use [%d]\n",
			i, SystemPalettePixelUse[i]));
	}
	return (TRUE);

}

static BOOL CreateSystemPalette()
{
	int i, j,
	    SystemPaletteLoIndex0, SystemPaletteLoIndex1,
	    SystemPaletteHiIndex0, SystemPaletteHiIndex1;
	XColor xc;

	/* compute system palette index limits */
	SystemPaletteSize = 1 << pixel_numplanes;
	SystemPaletteLoStaticUse = DefaultPaletteLoStaticUse;
	SystemPaletteHiStaticUse = DefaultPaletteHiStaticUse;
	SystemPaletteLoNoStaticUse = DefaultPaletteLoNoStaticUse;
	SystemPaletteHiNoStaticUse = DefaultPaletteHiNoStaticUse;
	SystemPaletteLoStaticIndex = DefaultPaletteLoStaticIndex;
	SystemPaletteHiStaticIndex = SystemPaletteSize
		- DefaultPaletteHiStaticUse;
	SystemPaletteLoNoStaticIndex = DefaultPaletteLoNoStaticIndex;
	SystemPaletteHiNoStaticIndex = SystemPaletteSize
		- DefaultPaletteHiNoStaticUse;
	LOGSTR((LF_LOG, "CreateSystemPalette:\n"
		" (LOG) SystemPaletteSize            [%04x]\n"
		" (LOG) SystemPaletteLoStaticUse     [%04x]\n"
		" (LOG) SystemPaletteHiStaticUse     [%04x]\n"
		" (LOG) SystemPaletteLoNoStaticUse   [%04x]\n"
		" (LOG) SystemPaletteHiNoStaticUse   [%04x]\n"
		" (LOG) SystemPaletteLoStaticIndex   [%04x]\n"
		" (LOG) SystemPaletteHiStaticIndex   [%04x]\n"
		" (LOG) SystemPaletteLoNoStaticIndex [%04x]\n"
		" (LOG) SystemPaletteHiNoStaticIndex [%04x]\n",
		SystemPaletteSize,
		SystemPaletteLoStaticUse,
		SystemPaletteHiStaticUse,
		SystemPaletteLoNoStaticUse,
		SystemPaletteHiNoStaticUse,
		SystemPaletteLoStaticIndex,
		SystemPaletteHiStaticIndex,
		SystemPaletteLoNoStaticIndex,
		SystemPaletteHiNoStaticIndex));

	/* create system palette */
	if (!(SystemPalette = (LPPALETTEENTRY) WinMalloc(SystemPaletteSize *
		sizeof(PALETTEENTRY))))
	{
		ERRSTR((LF_ERR, "CreateSystemPalette:"

                        " (ERR) malloc system palette\n"));
		return (FALSE);
	}

	/* initialize system palette */
	for (i = 0, j = pixel0; i < SystemPaletteSize; i++, j += pixel_mask0)
	{
		SystemPalette[i].peRed =
			xxxx_to_xx(DeviceColormapValues[j].red);
		SystemPalette[i].peGreen =
			xxxx_to_xx(DeviceColormapValues[j].green);
		SystemPalette[i].peBlue =
			xxxx_to_xx(DeviceColormapValues[j].blue);
		SystemPalette[i].peFlags = 0;
		LOGSTR((LF_LOG, "CreateSystemPalette:"
			" (LOG) system palette [%04x] RGB(%02x,%02x,%02x)\n",
			i,
			SystemPalette[i].peRed,
			SystemPalette[i].peGreen,
			SystemPalette[i].peBlue));
	}

	/* create system palette mapper */
	if (!CreateSystemPaletteMapper())
		return (FALSE);

	/* create system palette pixel use counter */
	if (!CreateSystemPalettePixelUse())
		return (FALSE);

	/* get system palette index limits */
	SystemPaletteLoIndex0 = SystemPaletteLoStaticIndex;
	SystemPaletteLoIndex1 = SystemPaletteLoStaticIndex
		+ SystemPaletteLoStaticUse;
	SystemPaletteHiIndex0 = SystemPaletteHiStaticIndex;
	SystemPaletteHiIndex1 = SystemPaletteHiStaticIndex
		+ SystemPaletteHiStaticUse;

	/* set system palette low static colors */
	for (i = SystemPaletteLoIndex0; i < SystemPaletteLoIndex1; i++)
	{
		/* low static colors cannot use system palette high half */
		if (i >= SystemPaletteSize / 2)
		{
			LOGSTR((LF_LOG, "CreateSystemPalette:"
				" (LOG) system palette [%04x]"
				" unusable low static\n", i));
			continue;
		}
		/* set system palette color */
		SystemPalette[i] =
			DefaultPalette[DefaultPaletteLoStaticIndex + i];
		/* set hardware color */
		xc.pixel = SystemPaletteMapper[i];
		xc.red = xx_to_xxxx(SystemPalette[i].peRed);
		xc.green = xx_to_xxxx(SystemPalette[i].peGreen);
		xc.blue = xx_to_xxxx(SystemPalette[i].peBlue);
		xc.flags = DoRed | DoGreen | DoBlue;
		XStoreColor(display, DeviceColormap, &xc);
		LOGSTR((LF_LOG, "CreateSystemPalette:"
			" (LOG) system palette [%04x]"
			" RGB(%02x,%02x,%02x)\n", i,
			SystemPalette[i].peRed,
			SystemPalette[i].peGreen,
			SystemPalette[i].peBlue));
	}

	/* set system palette unused colors */
	for (i = SystemPaletteLoIndex1; i < SystemPaletteHiIndex0; i++)
	{
		float rainbow;
		BYTE r, g, b;
		/* set system palette color */
		rainbow = i - SystemPaletteLoIndex1 + 1.0;
		rainbow /= SystemPaletteHiIndex0 - SystemPaletteLoIndex1 + 1.0;
		r = (BYTE) (((long)(rainbow * 0x00000100L)) % 0x0100L);
		g = (BYTE) (((long)(rainbow * 0x00010000L)) % 0x0100L);
		b = (BYTE) (((long)(rainbow * 0x01000000L)) % 0x0100L);
		SystemPalette[i].peRed = r;
		SystemPalette[i].peGreen = g;
		SystemPalette[i].peBlue = b;
		/* set hardware color */
		xc.pixel = SystemPaletteMapper[i];
		xc.red = xx_to_xxxx(SystemPalette[i].peRed);
		xc.green = xx_to_xxxx(SystemPalette[i].peGreen);
		xc.blue = xx_to_xxxx(SystemPalette[i].peBlue);
		xc.flags = DoRed | DoGreen | DoBlue;
		XStoreColor(display, DeviceColormap, &xc);
		LOGSTR((LF_LOG, "CreateSystemPalette:"
			" (LOG) system palette [%04x]"
			" RGB(%02x,%02x,%02x)\n", i,
			SystemPalette[i].peRed,
			SystemPalette[i].peGreen,
			SystemPalette[i].peBlue));
	}

	/* set system palette high static colors */
	for (i = SystemPaletteHiIndex0; i < SystemPaletteHiIndex1; i++)
	{
		/* high static colors cannot use system palette low half */
		if (i < SystemPaletteSize / 2)
		{
			LOGSTR((LF_LOG, "CreateSystemPalette:"
				" (LOG) system palette [%04x]"
				" unusable high static\n", i));
			continue;
		}
		/* set system palette color */
		SystemPalette[i] =
			DefaultPalette[DefaultPaletteHiStaticIndex + i
				- SystemPaletteHiIndex0];
		/* set hardware color */
		xc.pixel = SystemPaletteMapper[i];
		xc.red = xx_to_xxxx(SystemPalette[i].peRed);
		xc.green = xx_to_xxxx(SystemPalette[i].peGreen);
		xc.blue = xx_to_xxxx(SystemPalette[i].peBlue);
		xc.flags = DoRed | DoGreen | DoBlue;
		XStoreColor(display, DeviceColormap, &xc);
		LOGSTR((LF_LOG, "CreateSystemPalette:"
			" (LOG) system palette [%04x]"
			" RGB(%02x,%02x,%02x)\n", i,
			SystemPalette[i].peRed,
			SystemPalette[i].peGreen,
			SystemPalette[i].peBlue));
	}

	/* success */
	return (TRUE);

}

static BOOL CreateUnusedSystemPalette(UINT uSystemPaletteUse)
{
	int i,
	    SystemPaletteLoIndex0, SystemPaletteLoIndex1,
	    SystemPaletteHiIndex0, SystemPaletteHiIndex1;

	/* get system palette index limits */
	switch (uSystemPaletteUse)
	{
	case SYSPAL_STATIC:
		SystemPaletteLoIndex0 = SystemPaletteLoStaticIndex;
		SystemPaletteLoIndex1 = SystemPaletteLoStaticIndex
			+ SystemPaletteLoStaticUse;
		SystemPaletteHiIndex0 = SystemPaletteHiStaticIndex;
		SystemPaletteHiIndex1 = SystemPaletteHiStaticIndex
			+ SystemPaletteHiStaticUse;
		break;
	case SYSPAL_NOSTATIC:
		SystemPaletteLoIndex0 = SystemPaletteLoNoStaticIndex;
		SystemPaletteLoIndex1 = SystemPaletteLoNoStaticIndex
			+ SystemPaletteLoNoStaticUse;
		SystemPaletteHiIndex0 = SystemPaletteHiNoStaticIndex;
		SystemPaletteHiIndex1 = SystemPaletteHiNoStaticIndex
			+ SystemPaletteHiNoStaticUse;
		break;
	default:
		ERRSTR((LF_ERR, "CreateUnusedSystemPalette:"
			" (ERR) invalid system palette use [%d]\n",
			uSystemPaletteUse));
		return (FALSE);
	}

	/* create system palette index usage counter */
	if (!SystemPalettePixelUse
	 && !(SystemPalettePixelUse = (LPINT) WinMalloc(SystemPaletteSize *
		sizeof(INT))))
	{
		ERRSTR((LF_ERR, "CreateUnusedSystemPalette:"
			" (ERR) alloc system palette index usage counter\n"));
		return (FALSE);
	}

	/* mark unavailable system palette index */
	for (i = 0; i < SystemPaletteLoIndex0; i++)
	{
		if (i >= SystemPaletteSize / 2)
			continue;
		LOGSTR((LF_LOG, "CreateUnusedSystemPalette:"
			" (LOG) system palette index [%04x]"
			" ... LO UNAVAILABLE\n", i));
		SystemPalettePixelUse[i] = -1;
	}

	/* mark static system palette index */
	for (i = SystemPaletteLoIndex0; i < SystemPaletteLoIndex1; i++)
	{
		if (i >= SystemPaletteSize / 2)
			continue;
		LOGSTR((LF_LOG, "CreateUnusedSystemPalette:"
			" (LOG) system palette index [%04x]"
			" ... LO STATIC USED\n", i));
		SystemPalettePixelUse[i] = 1;
	}

	/* mark unused system palette index */
	for (i = SystemPaletteLoIndex1; i < SystemPaletteHiIndex0; i++)
	{
		LOGSTR((LF_LOG, "CreateUnusedSystemPalette:"
			" (LOG) system palette index [%04x]"
			" ... UNUSED\n", i));
#if 0
		SystemPalettePixelUse[i] = 0;
#else
		/* HACK:  This ought to be zero to mark palette entry as
		 * unused.  Instead, we mark as used so that we can color
		 * match with the rainbow colors which we set up in
		 * CreateSystemPalette().  This hack exists only to make
		 * the splash bitmap look nice and pretty on palette devices.
		 * Alternatively, we could inform the splash screen writer
		 * that LoadBitmap() on a 256-color bitmap will always
		 * create a 16-color bitmap under Windows (even on a 256-color
		 * palette device).
		 */
		SystemPalettePixelUse[i] = 1;
#endif
	}

	/* mark static system palette index */
	for (i = SystemPaletteHiIndex0; i < SystemPaletteHiIndex1; i++)
	{
		if (i < SystemPaletteSize / 2)
			continue;
		LOGSTR((LF_LOG, "CreateUnusedSystemPalette:"
			" (LOG) system palette index [%04x]"
			" ... HI STATIC USED\n", i));
		SystemPalettePixelUse[i] = 1;
	}

	/* mark unavailable system palette index */
	for (i = SystemPaletteHiIndex1; i < SystemPaletteSize; i++)
	{
		if (i < SystemPaletteSize / 2)
			continue;
		LOGSTR((LF_LOG, "CreateUnusedSystemPalette:"
			" (LOG) system palette index [%4x]"
			" ... HI UNAVAILABLE\n", i));
		SystemPalettePixelUse[i] = -1;
	}

	/* success */
	return (TRUE);

}

static UINT UnusedSystemPaletteIndex()
{
	UINT u;

	/* find unused system palette index */
	for (u = 0; u < SystemPaletteSize; u++)
		if (SystemPalettePixelUse[u] == 0)
			break;
	return (u);

}

static UINT NearestSystemPaletteIndex(LPPALETTEENTRY pe)
{
	UINT u, v;
	LONG delta, delta0, r0, g0, b0;
	XColor xc;

	/* match exact color */
	for (u = 0; u < SystemPaletteSize; u++)
	{
		if (SystemPalettePixelUse[u] <= 0)
			continue;
		if (SystemPalette[u].peRed != pe->peRed)
			continue;
		if (SystemPalette[u].peGreen != pe->peGreen)
			continue;
		if (SystemPalette[u].peBlue != pe->peBlue)
			continue;
		SystemPalettePixelUse[u]++;
		return (u);
	}

	/* match unused system palette index */
	if ((u = UnusedSystemPaletteIndex()) < SystemPaletteSize)
	{
		/* set hardware color */
		xc.pixel = SystemPaletteMapper[u];
		xc.red = xx_to_xxxx(pe->peRed);
		xc.green = xx_to_xxxx(pe->peGreen);
		xc.blue = xx_to_xxxx(pe->peBlue);
		xc.flags = DoRed | DoGreen | DoBlue;
		XStoreColor(display, DeviceColormap, &xc);
		/* set system palette color */
		SystemPalette[u] = *pe;
		SystemPalette[u].peFlags = 0;
		SystemPalettePixelUse[u]++;
		return (u);
	}

	/* match nearest color */
	for (u = v = 0, delta = 0x30000L; v < SystemPaletteSize; v++)
	{
		if (SystemPalettePixelUse[v] <= 0)
			continue;
		r0 = ((LONG) SystemPalette[v].peRed) - ((LONG) pe->peRed);
		g0 = ((LONG) SystemPalette[v].peGreen) - ((LONG) pe->peGreen);
		b0 = ((LONG) SystemPalette[v].peBlue) - ((LONG) pe->peBlue);
		delta0 = (r0 * r0) + (g0 * g0) + (b0 * b0);
		if (delta > delta0)
		{
			u = v;
			delta = delta0;
		}
	}
	SystemPalettePixelUse[u]++;
	return (u);

}

static UINT AllocSystemPaletteIndex(LPPALETTEENTRY pe)
{
	UINT u;
	XColor xc;

	/* PC_RESERVED (after AllocSystemPaletteIndex call) */
	if (pe->peFlags == (PC_RESERVED | PC_EXPLICIT))
	{
		u = (pe->peRed & 0x00ff) | ((pe->peGreen << 8) & 0xff00);
		if ((u < SystemPaletteSize)
		 && (SystemPalette[u].peFlags == (PC_RESERVED | PC_EXPLICIT)))
		{
			return (u);
		}
	}

	/* PC_RESERVED (before AllocSystemPaletteIndex call) */
	if (pe->peFlags == PC_RESERVED)
	{
		if ((u = UnusedSystemPaletteIndex()) < SystemPaletteSize)
		{
			LOGSTR((LF_LOG, "AllocSystemPaletteIndex:"
				" (LOG) PC_RESERVED - system palette index"
				" [%4x] RGB(%2x,%2x,%2x)", u,
				pe->peRed, pe->peGreen, pe->peBlue));
			/* set hardware color */
			xc.pixel = SystemPaletteMapper[u];
			xc.red = xx_to_xxxx(pe->peRed);
			xc.green = xx_to_xxxx(pe->peGreen);
			xc.blue = xx_to_xxxx(pe->peBlue);
			xc.flags = DoRed | DoGreen | DoBlue;
			XStoreColor(display, DeviceColormap, &xc);
			/* set system palette color */
			SystemPalette[u] = *pe;
			SystemPalette[u].peFlags |= PC_EXPLICIT;
			SystemPalettePixelUse[u] = -1;
			/* get system palette index */
			pe->peRed = (u & 0xff);
			pe->peGreen = (u & 0xff00) >> 8;
			pe->peFlags |= PC_EXPLICIT;
			return (u);
		}
		LOGSTR((LF_LOG, "AllocSystemPaletteIndex:"
			" (LOG) PC_RESERVED - system palette full\n"));
		return (0);
	}

	/* PC_EXPLICIT */
	if (pe->peFlags == PC_EXPLICIT)
	{
		u = pe->peRed | (pe->peGreen << 8);
		if (u >= SystemPaletteSize)
		{
			ERRSTR((LF_ERR, "AllocSystemPaletteIndex:"
				" (ERR) PC_EXPLICIT - hardware palette index"
				" [%4x] exceeds hardware palette size [%4x]\n",
				u, SystemPaletteSize));
			u = 0;
		}
		return (u);
	}

	/* PC_NOCOLLAPSE */
	if (pe->peFlags == PC_NOCOLLAPSE)
	{
		if ((u = UnusedSystemPaletteIndex()) < SystemPaletteSize)
		{
			/* set hardware color */
			xc.pixel = SystemPaletteMapper[u];
			xc.red = xx_to_xxxx(pe->peRed);
			xc.green = xx_to_xxxx(pe->peGreen);
			xc.blue = xx_to_xxxx(pe->peBlue);
			xc.flags = DoRed | DoGreen | DoBlue;
			XStoreColor(display, DeviceColormap, &xc);
			/* set system palette color */
			SystemPalette[u] = *pe;
			SystemPalette[u].peFlags = 0;
			SystemPalettePixelUse[u]++;
			return (u);
		}
	}

	/* default */
	if ((u = NearestSystemPaletteIndex(pe)) < SystemPaletteSize)
	{
		SystemPalettePixelUse[u]++;
	}
	return (u);

}

static DWORD SystemPalettePixel(COLORREF cr)
{
#ifdef __VMS /* not nice to have a nonvoid function without a return */
return(0);
#endif
}





/* (Color) Non-Palette Device ********************************************** */

static DWORD dwRMask, dwGMask, dwBMask;
static DWORD dwRMapper[256], dwGMapper[256], dwBMapper[256];

/* -------- */

/* standard static system colors */

static PALETTEENTRY peSystemPalette[] =
{
	/* first 10 system palette entries */
	{ 0x00, 0x00, 0x00, 0 },		/* black */
	{ 0x80, 0x00, 0x00, 0 },		/* dark red */
	{ 0x00, 0x80, 0x00, 0 },		/* dark green */
	{ 0x80, 0x80, 0x00, 0 },		/* dark yellow */
	{ 0x00, 0x00, 0x80, 0 },		/* dark blue */
	{ 0x80, 0x00, 0x80, 0 },		/* dark magenta */
	{ 0x00, 0x80, 0x80, 0 },		/* dark cyan */
	{ 0xc0, 0xc0, 0xc0, 0 },		/* light gray */
	{ 0xc0, 0xdc, 0xc0, 0 },		/* money green */
	{ 0xa6, 0xca, 0xf0, 0 },		/* sky blue */
	/* last 10 system palette entries */
	{ 0xff, 0xfb, 0xf0, 0 },		/* cream */
	{ 0xa0, 0xa0, 0xa4, 0 },		/* light gray */
	{ 0x80, 0x80, 0x80, 0 },		/* medium gray */
	{ 0xff, 0x00, 0x00, 0 },		/* red */
	{ 0x00, 0xff, 0x00, 0 },		/* green */
	{ 0xff, 0xff, 0x00, 0 },		/* yellow */
	{ 0x00, 0x00, 0xff, 0 },		/* blue */
	{ 0xff, 0x00, 0xff, 0 },		/* magenta */
	{ 0x00, 0xff, 0xff, 0 },		/* cyan */
	{ 0xff, 0xff, 0xff, 0 },		/* white */
};

/* system palette index to hardware palette index translation table */

static WORD wSystemPaletteIndexTable
	[sizeof(peSystemPalette)/sizeof(peSystemPalette[0])];

static BOOL XIsPaletteDevice(LPDRIVERDC lpDriverDC);

static HPALETTE XAllocSystemPalette(UINT uNumSystemPaletteEntries);

static BOOL XInitSystemPalette(LPDRIVERDC lpDriverDC,
	UINT uNumLoSystemPaletteEntries,
	LPPALETTEENTRY lpLoSystemPaletteEntries,
	UINT uNumHiSystemPaletteEntries,
	LPPALETTEENTRY lpHiSystemPaletteEntries);

DWORD DrvColorsInit(LPARAM,LPARAM,LPVOID);
DWORD DrvColorsTab(void);

static DWORD DrvSystemPaletteUse(LPARAM, LPARAM, LPVOID);
static DWORD DrvGetSystemPalette(LPARAM, LPARAM, LPVOID);
static DWORD DrvSetSystemPalette(LPARAM, LPARAM, LPVOID);
static DWORD DrvAnimatePalette(LPARAM, LPARAM, LPVOID);
static DWORD DrvUpdateColors(LPARAM, LPARAM, LPVOID);
static DWORD DrvColorMakePixel(LPARAM, LPARAM, LPVOID);
static DWORD DrvColorGetColorRef(LPARAM, LPARAM, LPVOID);
static DWORD DrvColorsDoNothing(LPARAM,LPARAM,LPVOID);
static DWORD DrvColorsDoDefault(LPARAM,LPARAM,LPVOID);
#endif	/* TWIN_PALETTE */

static DWORD DrvGetNearestColor(LPARAM, LPARAM, LPVOID);
static DWORD DrvFillRGBTable(LPARAM, LPARAM, LPVOID);
static DWORD DrvInitColors(UINT);
static COLORREF DrvGetColorRef(DWORD);

RGBQUAD RgbColors_128[128] = {
	{ 0x00, 0x00, 0x00, 0 },
	{ 0x00, 0x00, 0x80, 0 },
	{ 0x00, 0x80, 0x00, 0 },
	{ 0x00, 0x80, 0x80, 0 },
	{ 0x80, 0x00, 0x00, 0 },
	{ 0x80, 0x00, 0x80, 0 },
	{ 0x80, 0x80, 0x00, 0 },
	{ 0xc0, 0xc0, 0xc0, 0 },
	{ 0xc0, 0xdc, 0xc0, 0 },
	{ 0xf0, 0xca, 0xa6, 0 },

	{ 0x50, 0x50, 0x50, 0 },
	{ 0x60, 0x60, 0x60, 0 },
	{ 0x70, 0x70, 0x70, 0 },
	{ 0x90, 0x90, 0x90, 0 },
	{ 0xa0, 0xa0, 0xa0, 0 },
	{ 0xb0, 0xb0, 0xb0, 0 },
	{ 0xd0, 0xd0, 0xd0, 0 },
	{ 0xe0, 0xe0, 0xe0, 0 },

	{ 0xc0, 0x00, 0x00, 0 },
	{ 0x00, 0x40, 0x00, 0 },
	{ 0x40, 0x80, 0x00, 0 },
	{ 0xc0, 0x80, 0x00, 0 },
	{ 0xff, 0x80, 0x00, 0 },
	{ 0x00, 0xc0, 0x00, 0 },
	{ 0x40, 0xc0, 0x00, 0 },
	{ 0x80, 0xc0, 0x00, 0 },
	{ 0xc0, 0xc0, 0x00, 0 },
	{ 0xff, 0xc0, 0x00, 0 },
	{ 0x40, 0xff, 0x00, 0 },
	{ 0x80, 0xff, 0x00, 0 },
	{ 0xc0, 0xff, 0x00, 0 },
	{ 0x40, 0x00, 0x40, 0 },
	{ 0x80, 0x00, 0x40, 0 },
	{ 0xc0, 0x00, 0x40, 0 },
	{ 0xff, 0x00, 0x40, 0 },
	{ 0x00, 0x40, 0x40, 0 },
	{ 0x40, 0x40, 0x40, 0 },
	{ 0x80, 0x40, 0x40, 0 },
	{ 0xc0, 0x40, 0x40, 0 },
	{ 0xff, 0x40, 0x40, 0 },
	{ 0x00, 0x80, 0x40, 0 },
	{ 0x40, 0x80, 0x40, 0 },
	{ 0x80, 0x80, 0x40, 0 },
	{ 0xc0, 0x80, 0x40, 0 },
	{ 0xff, 0x80, 0x40, 0 },
	{ 0x00, 0xc0, 0x40, 0 },
	{ 0x40, 0xc0, 0x40, 0 },
	{ 0x80, 0xc0, 0x40, 0 },
	{ 0xc0, 0xc0, 0x40, 0 },
	{ 0xff, 0xc0, 0x40, 0 },
	{ 0xc0, 0xff, 0x40, 0 },
	{ 0xff, 0xff, 0x40, 0 },
	{ 0x40, 0x00, 0x80, 0 },
	{ 0xc0, 0x00, 0x80, 0 },
	{ 0xff, 0x00, 0x80, 0 },
	{ 0x00, 0x40, 0x80, 0 },
	{ 0x40, 0x40, 0x80, 0 },
	{ 0x80, 0x40, 0x80, 0 },
	{ 0xc0, 0x40, 0x80, 0 },
	{ 0xff, 0x40, 0x80, 0 },
	{ 0x40, 0x80, 0x80, 0 },
	{ 0xc0, 0x80, 0x80, 0 },
	{ 0xff, 0x80, 0x80, 0 },
	{ 0x00, 0xc0, 0x80, 0 },
	{ 0x40, 0xc0, 0x80, 0 },
	{ 0x80, 0xc0, 0x80, 0 },
	{ 0xc0, 0xc0, 0x80, 0 },
	{ 0xff, 0xc0, 0x80, 0 },
	{ 0x00, 0xff, 0x80, 0 },
	{ 0x40, 0xff, 0x80, 0 },
	{ 0x80, 0xff, 0x80, 0 },
	{ 0xc0, 0xff, 0x80, 0 },
	{ 0xff, 0xff, 0x80, 0 },
	{ 0x00, 0x00, 0xc0, 0 },
	{ 0x40, 0x00, 0xc0, 0 },
	{ 0x80, 0x00, 0xc0, 0 },
	{ 0xc0, 0x00, 0xc0, 0 },
	{ 0xff, 0x00, 0xc0, 0 },
	{ 0x00, 0x40, 0xc0, 0 },
	{ 0x40, 0x40, 0xc0, 0 },
	{ 0x80, 0x40, 0xc0, 0 },
	{ 0xc0, 0x40, 0xc0, 0 },
	{ 0xff, 0x40, 0xc0, 0 },
	{ 0x00, 0x80, 0xc0, 0 },
	{ 0x40, 0x80, 0xc0, 0 },
	{ 0x80, 0x80, 0xc0, 0 },
	{ 0xc0, 0x80, 0xc0, 0 },
	{ 0xff, 0x80, 0xc0, 0 },
	{ 0x00, 0xc0, 0xc0, 0 },
	{ 0x40, 0xc0, 0xc0, 0 },
	{ 0x80, 0xc0, 0xc0, 0 },
	{ 0xff, 0xc0, 0xc0, 0 },
	{ 0x00, 0xff, 0xc0, 0 },
	{ 0x40, 0xff, 0xc0, 0 },
	{ 0x80, 0xff, 0xc0, 0 },
	{ 0xc0, 0xff, 0xc0, 0 },
	{ 0xff, 0xff, 0xc0, 0 },
	{ 0x40, 0x00, 0xff, 0 },
	{ 0x80, 0x00, 0xff, 0 },
	{ 0xc0, 0x00, 0xff, 0 },
	{ 0x00, 0x40, 0xff, 0 },
	{ 0x40, 0x40, 0xff, 0 },
	{ 0x80, 0x40, 0xff, 0 },
	{ 0xc0, 0x40, 0xff, 0 },
	{ 0xff, 0x40, 0xff, 0 },
	{ 0x00, 0x80, 0xff, 0 },
	{ 0x40, 0x80, 0xff, 0 },
	{ 0x80, 0x80, 0xff, 0 },
	{ 0xc0, 0x80, 0xff, 0 },
	{ 0xff, 0x80, 0xff, 0 },
	{ 0x00, 0xc0, 0xff, 0 },
	{ 0x40, 0xc0, 0xff, 0 },
	{ 0x80, 0xc0, 0xff, 0 },
	{ 0xc0, 0xc0, 0xff, 0 },
	{ 0xff, 0xc0, 0xff, 0 },
	{ 0x40, 0xff, 0xff, 0 },
	{ 0x80, 0xff, 0xff, 0 },
	{ 0xc0, 0xff, 0xff, 0 },

	{ 0xf0, 0xfb, 0xff, 0 },
	{ 0xa4, 0xa0, 0xa0, 0 },
	{ 0x80, 0x80, 0x80, 0 },
	{ 0x00, 0x00, 0xff, 0 },
	{ 0x00, 0xff, 0x00, 0 },
	{ 0x00, 0xff, 0xff, 0 },
	{ 0xff, 0x00, 0x00, 0 },
	{ 0xff, 0x00, 0xff, 0 },
	{ 0xff, 0xff, 0x00, 0 },
	{ 0xff, 0xff, 0xff, 0 }
};

RGBQUAD RgbColors_64[64] = {
	{ 0x00, 0x00, 0x00, 0 },
	{ 0x00, 0x00, 0x80, 0 },
	{ 0x00, 0x80, 0x00, 0 },
	{ 0x00, 0x80, 0x80, 0 },
	{ 0x80, 0x00, 0x00, 0 },
	{ 0x80, 0x00, 0x80, 0 },
	{ 0x80, 0x80, 0x00, 0 },
	{ 0xc0, 0xc0, 0xc0, 0 },
	{ 0xc0, 0xdc, 0xc0, 0 },
	{ 0xf0, 0xca, 0xa6, 0 },

	{ 0x40, 0x40, 0x40, 0 },
	{ 0x80, 0x40, 0x00, 0 },
	{ 0xc0, 0x40, 0x00, 0 },
	{ 0xff, 0x40, 0x00, 0 },
	{ 0x00, 0xc0, 0x00, 0 },
	{ 0x80, 0xc0, 0x00, 0 },
	{ 0xc0, 0xc0, 0x00, 0 },
	{ 0xff, 0xc0, 0x00, 0 },
	{ 0x80, 0x80, 0x40, 0 },
	{ 0xc0, 0x80, 0x40, 0 },
	{ 0xff, 0x80, 0x40, 0 },
	{ 0x00, 0x40, 0x80, 0 },
	{ 0xc0, 0x40, 0x80, 0 },
	{ 0xff, 0x40, 0x80, 0 },
	{ 0x00, 0xc0, 0x80, 0 },
	{ 0x80, 0xc0, 0x80, 0 },
	{ 0xc0, 0xc0, 0x80, 0 },
	{ 0xff, 0xc0, 0x80, 0 },
	{ 0x00, 0xff, 0x80, 0 },
	{ 0x80, 0xff, 0x80, 0 },
	{ 0xc0, 0xff, 0x80, 0 },
	{ 0xff, 0xff, 0x80, 0 },
	{ 0x00, 0x00, 0xc0, 0 },
	{ 0x80, 0x00, 0xc0, 0 },
	{ 0xc0, 0x00, 0xc0, 0 },
	{ 0xff, 0x00, 0xc0, 0 },
	{ 0x00, 0x80, 0xc0, 0 },
	{ 0x80, 0x80, 0xc0, 0 },
	{ 0xc0, 0x80, 0xc0, 0 },
	{ 0xff, 0x80, 0xc0, 0 },
	{ 0x00, 0xff, 0xc0, 0 },
	{ 0x80, 0xff, 0xc0, 0 },
	{ 0xc0, 0xff, 0xc0, 0 },
	{ 0xff, 0xff, 0xc0, 0 },
	{ 0x40, 0x00, 0xff, 0 },
	{ 0x80, 0x00, 0xff, 0 },
	{ 0xc0, 0x00, 0xff, 0 },
	{ 0x00, 0xc0, 0xff, 0 },
	{ 0x80, 0xc0, 0xff, 0 },
	{ 0xc0, 0xc0, 0xff, 0 },
	{ 0xff, 0xc0, 0xff, 0 },
	{ 0x40, 0xff, 0xff, 0 },
	{ 0x80, 0xff, 0xff, 0 },
	{ 0xc0, 0xff, 0xff, 0 },

	{ 0xf0, 0xfb, 0xff, 0 },
	{ 0xa4, 0xa0, 0xa0, 0 },
	{ 0x80, 0x80, 0x80, 0 },
	{ 0x00, 0x00, 0xff, 0 },
	{ 0x00, 0xff, 0x00, 0 },
	{ 0x00, 0xff, 0xff, 0 },
	{ 0xff, 0x00, 0x00, 0 },
	{ 0xff, 0x00, 0xff, 0 },
	{ 0xff, 0xff, 0x00, 0 },
	{ 0xff, 0xff, 0xff, 0 }
};

RGBQUAD RgbColors_32[32] = {
	{ 0x00, 0x00, 0x00, 0 },
	{ 0x00, 0x00, 0x80, 0 },
	{ 0x00, 0x80, 0x00, 0 },
	{ 0x00, 0x80, 0x80, 0 },
	{ 0x80, 0x00, 0x00, 0 },
	{ 0x80, 0x00, 0x80, 0 },
	{ 0x80, 0x80, 0x00, 0 },
	{ 0xc0, 0xc0, 0xc0, 0 },
	{ 0xc0, 0xdc, 0xc0, 0 },
	{ 0xf0, 0xca, 0xa6, 0 },

	{ 0xff, 0x80, 0x00, 0 },
	{ 0x80, 0xff, 0x00, 0 },
	{ 0xff, 0x00, 0x80, 0 },
	{ 0xff, 0x80, 0x80, 0 },
	{ 0x00, 0xff, 0x80, 0 },
	{ 0x80, 0xff, 0x80, 0 },
	{ 0xff, 0xff, 0x80, 0 },
	{ 0x80, 0x00, 0xff, 0 },
	{ 0x00, 0x80, 0xff, 0 },
	{ 0x80, 0x80, 0xff, 0 },
	{ 0xff, 0x80, 0xff, 0 },
	{ 0x80, 0xff, 0xff, 0 },

	{ 0x40, 0x40, 0x40, 0 },
	{ 0xf0, 0xfb, 0xff, 0 },
	{ 0x80, 0x80, 0x80, 0 },
	{ 0x00, 0x00, 0xff, 0 },
	{ 0x00, 0xff, 0x00, 0 },
	{ 0x00, 0xff, 0xff, 0 },
	{ 0xff, 0x00, 0x00, 0 },
	{ 0xff, 0x00, 0xff, 0 },
	{ 0xff, 0xff, 0x00, 0 },
	{ 0xff, 0xff, 0xff, 0 }
};

RGBQUAD RgbColors_16[16] = {
	{ 0x00, 0x00, 0x00, 0 },
	{ 0x00, 0x00, 0x80, 0 },
	{ 0x00, 0x80, 0x00, 0 },
	{ 0x00, 0x80, 0x80, 0 },
	{ 0x80, 0x00, 0x00, 0 },
	{ 0x80, 0x00, 0x80, 0 },
	{ 0x80, 0x80, 0x00, 0 },
	{ 0xc0, 0xc0, 0xc0, 0 },

	{ 0x80, 0x80, 0x80, 0 },
	{ 0x00, 0x00, 0xff, 0 },
	{ 0x00, 0xff, 0x00, 0 },
	{ 0x00, 0xff, 0xff, 0 },
	{ 0xff, 0x00, 0x00, 0 },
	{ 0xff, 0x00, 0xff, 0 },
	{ 0xff, 0xff, 0x00, 0 },
	{ 0xff, 0xff, 0xff, 0 }
};

typedef struct tagXRGB
{
    WORD	red,green,blue,pad;
} XRGB, *LPXRGB;

typedef struct tagCOLORMAPPROPERTY
{
    LONG	nRefCount;
    LONG	nNumColors;
    DWORD 	nBasePixel;
    DWORD 	nPlaneMask;
    XRGB	xrgb[1];
} COLORMAPPROPERTY, *LPCOLORMAPPROPERTY;

#define		LF_COLORS	LF_LOG

#define		COLOR_STEP	0x400

#define		itoc(x)		(((int)(x) * ((int)0xFFFF)) / ((int)0x00FF))
#define		ctoi(x)		(((int)(x) * ((int)0x00FF)) / ((int)0xFFFF))

static XColor	*pixel_table;
static DWORD 	*pixel_mapper;

static DWORD	pixel_white;
static DWORD	pixel_black;

static BOOL	fTrueColor = FALSE;

static TWINDRVSUBPROC DrvColorsEntryTab[] = {
	DrvColorsInit,
	DrvColorsDoNothing, /* GETCAPS */
	DrvColorsDoNothing, /* EVENTS */
	DrvColorsDoDefault, /* PLH_DEFAULTPALETTE */
	DrvSystemPaletteUse,
	DrvGetSystemPalette,
	DrvSetSystemPalette,
	DrvAnimatePalette,
	DrvUpdateColors,
	DrvColorMakePixel,
	DrvGetNearestColor,
	DrvColorGetColorRef,
	DrvFillRGBTable,
	DrvColorsDoDefault, /*PLH_MAKEPALENTRY */
	DrvColorsDoDefault /* PLH_GETPIXELINFO */
};

DWORD
DrvColorsInit(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{
	DWORD dwReturn;

	if (dwParam2)
	{
		dwReturn = DrvInitColors((UINT)dwParam1);
		return dwReturn;
	}
	else
		return 0L; 
}

#ifdef TWIN_PALETTE
static BOOL XIsPaletteDevice(LPDRIVERDC lpDriverDC)
{
	Display *display = lpDriverDC->dp->display;
	int screen = lpDriverDC->dp->screen;
	Visual *visual = XDefaultVisual(display, screen);

	switch (visual->class)
	{
	case StaticGray:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X static palette (StaticGray)"
			" <-> non-palette device under MS-Windows\n"));
		return (FALSE);
	case StaticColor:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X static palette (StaticColor)"
			" <-> non-palette device under MS-Windows\n"));
		return (FALSE);
	case TrueColor:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X triple static palette (TrueColor)"
			" <-> non-palette device under MS-Windows\n"));
		return (FALSE);
	case GrayScale:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X non-static palette (GrayScale)"
			" <-> palette device under MS-Windows\n"));
		return (TRUE);
	case PseudoColor:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X non-static palette (PseudoColor)"
			" <-> palette device under MS-Windows\n"));
		return (TRUE);
	case DirectColor:
		LOGSTR((LF_LOG, "XIsPaletteDevice:"
			" (LOG) X triple non-static palette (DirectColor)"
			" <-> non-palette device under MS-Windows\n"));
		return (FALSE);
	default:
		ERRSTR((LF_ERR, "XIsPaletteDevice:\n"
			" (ERR) unknown X visual class %d\n",
			visual->class));
		return (FALSE);
	}

	return (FALSE);

}

static HPALETTE XAllocSystemPalette(UINT uNumSystemPaletteEntries)
{
	HPALETTE hPalette;
	LPLOGPALETTE lpLogPalette;
	UINT u;

	if (!(lpLogPalette = (LPLOGPALETTE) WinMalloc(sizeof(LOGPALETTE)
		+ uNumSystemPaletteEntries * sizeof(PALETTEENTRY))))
	{
		ERRSTR((LF_ERR, "XAllocSystemPalette:"
			" (ERR) cannot allocate LOGPALETTE\n"));
		return (HPALETTE)NULL;
	}

	lpLogPalette->palVersion = 0x0300;
	lpLogPalette->palNumEntries = uNumSystemPaletteEntries;
	for (u = 0; u < uNumSystemPaletteEntries; u++)
	{
		LOGSTR((LF_LOG, "XAllocSystemPalette:"
			" (LOG) system palette index [%d]\n", u));
		lpLogPalette->palPalEntry[u].peRed = u & 0xff;
		lpLogPalette->palPalEntry[u].peGreen = (u >> 8) & 0xff;
		lpLogPalette->palPalEntry[u].peFlags = PC_EXPLICIT;
	}

	hPalette = CreatePalette(lpLogPalette);

	WinFree(lpLogPalette);

	return (hPalette);

}

static BOOL XInitSystemPalette(LPDRIVERDC lpDriverDC,
	UINT uNumLoSystemPaletteEntries,
	LPPALETTEENTRY lpLoSystemPaletteEntries,
	UINT uNumHiSystemPaletteEntries,
	LPPALETTEENTRY lpHiSystemPaletteEntries)
{
	UINT uNumSystemPaletteEntries, uSystemPaletteIndex, u, v;
	PALETTEENTRY peSystemPaletteEntry;
	unsigned long pixel, pixels[256], planes[1];

return (TRUE);
if (!lpDriverDC)
{
	static DRIVERDC dummy;
	lpDriverDC = &dummy;
	dummy.dp = GETDP();
}

	/* allocate system palette */
	uNumSystemPaletteEntries = XDefaultVisual(lpDriverDC->dp->display,
		lpDriverDC->dp->screen)->map_entries;
	if (!lpDriverDC->dp->uSystemPaletteUseCount)
	{
		if (!(lpDriverDC->dp->uSystemPaletteUseCount = (LPUINT)
			WinCalloc(uNumSystemPaletteEntries + 1, sizeof(UINT))))
		{
			ERRSTR((LF_ERR, "XInitSystemPalette:"
				" (ERR) cannot allocate"
				" uSystemPaletteUseCount\n"));
			return (FALSE);
		}
	}
	if (!lpDriverDC->dp->hSystemPalette)
	{
		if (!(lpDriverDC->dp->hSystemPalette =
			XAllocSystemPalette(uNumSystemPaletteEntries)))
		{
			ERRSTR((LF_ERR, "XInitSystemPalette:"
				" (ERR) cannot allocate hSystemPalette\n"));
			return (FALSE);
		}
	}
	if (!lpDriverDC->dp->hOldSystemPalette)
	{
		if (!(lpDriverDC->dp->hOldSystemPalette =
			XAllocSystemPalette(uNumSystemPaletteEntries)))
		{
			ERRSTR((LF_ERR, "XInitSystemPalette:"
				" (ERR) cannot allocate hOldSystemPalette\n"));
			return (FALSE);
		}
	}

	/* free system palette entries */
	for (u = 0; u < uNumSystemPaletteEntries; u++)
	{
		if ((GetPaletteEntries(lpDriverDC->dp->hSystemPalette,
			u, 1, &peSystemPaletteEntry) != 1)
		 || (SetPaletteEntries(lpDriverDC->dp->hOldSystemPalette,
			u, 1, &peSystemPaletteEntry) != 1))
		{
			ERRSTR((LF_ERR, "XInitSystemPalette:"
				" (ERR) cannot save system palette"
				" for UpdateColors()\n"));
			return (FALSE);
		}
		for (v = 0; v < lpDriverDC->dp->uSystemPaletteUseCount[u]; v++)
		{
			LOGSTR((LF_LOG, "XInitSystemPalette:"
				" (LOG) free system palette entry [%d]\n", u));
			pixel = u;
			XFreeColors(lpDriverDC->dp->display,
				lpDriverDC->dp->SystemPalette,
				&pixel, 1, 0L);
		}
		lpDriverDC->dp->uSystemPaletteUseCount[u] = 0;
	}

	/* allocate low (static) system palette entries */
	for (u = 0; u < uNumLoSystemPaletteEntries; u++)
	{
		if (u > uNumSystemPaletteEntries - uNumHiSystemPaletteEntries)
		{
			LOGSTR((LF_LOG, "XInitSystemPalette:"
				" (LOG) low system palette index [%d]"
				" > num entries [%d] - num hi entries [%d]\n",
				u,
				uNumSystemPaletteEntries,
				uNumHiSystemPaletteEntries));
			continue;
		}
		if ((uSystemPaletteIndex = 
			(DWORD)DrvSetSystemPalette((DWORD)lpDriverDC,
			(DWORD)FALSE, (LPVOID)(lpLoSystemPaletteEntries + u)))
			!= u)
		{
			LOGSTR((LF_LOG, "XInitSystemPalette:"
				" (LOG) low system palette index [%d]"
				" != X colormap index [%d]\n",
				u, uSystemPaletteIndex));
		}
	}

	/* allocate middle (non-static) system palette entries */
	if (uNumLoSystemPaletteEntries + uNumHiSystemPaletteEntries
		< uNumSystemPaletteEntries)
	{
		XAllocColorCells(lpDriverDC->dp->display,
			lpDriverDC->dp->SystemPalette, False,
			planes, 0,
			pixels, uNumSystemPaletteEntries
				- uNumLoSystemPaletteEntries
				- uNumHiSystemPaletteEntries);
	}

	/* allocate high (static) system palette entries */
	for (u = 0; u < uNumHiSystemPaletteEntries; u++)
	{
		if (uNumSystemPaletteEntries - uNumHiSystemPaletteEntries + u
			< uNumLoSystemPaletteEntries)
		{
			LOGSTR((LF_LOG, "XInitSystemPalette:"
				" (LOG) high system palette index [%d]"
				" < num low entries [%d]\n",
				uNumSystemPaletteEntries
					- uNumHiSystemPaletteEntries + u,
				uNumLoSystemPaletteEntries));
			continue;
		}
		if ((uSystemPaletteIndex = 
			(DWORD)DrvSetSystemPalette((DWORD)lpDriverDC,
			(DWORD)FALSE, (LPVOID)(lpHiSystemPaletteEntries + u)))
			!= uNumSystemPaletteEntries
				- uNumHiSystemPaletteEntries + u)
		{
			LOGSTR((LF_LOG, "XInitSystemPalette:"
				" (LOG) high system palette index [%d]"
				" != X colormap index [%d]\n",
				uNumSystemPaletteEntries
					- uNumHiSystemPaletteEntries + u,
				uSystemPaletteIndex));
		}
	}

	/* free middle (non-static) system palette entries */
	if (uNumLoSystemPaletteEntries + uNumHiSystemPaletteEntries
		< uNumSystemPaletteEntries)
	{
		XFreeColors(lpDriverDC->dp->display,
			lpDriverDC->dp->SystemPalette,
			pixels, uNumSystemPaletteEntries
				- uNumLoSystemPaletteEntries
				- uNumHiSystemPaletteEntries, 0);
	}

	/* successful system palette initialization */
	return (TRUE);

}

static DWORD 
DrvSystemPaletteUse(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
	LPDRIVERDC lpDriverDC = (LPDRIVERDC)dwParam1;
	UINT uSystemPaletteUse = (UINT)dwParam2;
	BOOL bSetSystemPaletteUse = (BOOL)lpParams;
	UINT uOldSystemPaletteUse;

	APISTR((LF_API, "DrvSystemPaletteUse: lpDriverDC %p\n"
		" uSystemPaletteUse %d bSetSystemPaletteUse %d\n",
		lpDriverDC, uSystemPaletteUse, bSetSystemPaletteUse));

	/* verify palette device */
	if (!bPaletteDevice)
	{
		ERRSTR((LF_ERR, "DrvSystemPaletteUse:"
			" (ERR) non-palette device\n"));
		SetLastErrorEx(1, 0);
		return (DWORD)(SYSPAL_ERROR);
	}

	/* get system palette use */
	uOldSystemPaletteUse = lpDriverDC->dp->uSystemPaletteUse;

	/* set system palette use */
	if (bSetSystemPaletteUse)
	{
		switch (uSystemPaletteUse)
		{
		case SYSPAL_STATIC:
			LOGSTR((LF_LOG, "DrvSystemPaletteUse:"
				" (LOG) set SYSPAL_STATIC\n"));
			lpDriverDC->dp->uSystemPaletteUse = uSystemPaletteUse;
			break;
		case SYSPAL_NOSTATIC:
			LOGSTR((LF_LOG, "DrvSystemPaletteUse:"
				" (LOG) set SYSPAL_NOSTATIC\n"));
			lpDriverDC->dp->uSystemPaletteUse = uSystemPaletteUse;
			break;
		default:
			ERRSTR((LF_ERR, "DrvSystemPaletteUse:"
				" (ERR) unknown system palette use %d\n",
				uSystemPaletteUse));
			uOldSystemPaletteUse = SYSPAL_ERROR;
			break;
		}
	}

	/* return old system palette use */
	return (DWORD)(uOldSystemPaletteUse);

}

static DWORD 
DrvGetSystemPalette(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
	LPDRIVERDC lpDriverDC = (LPDRIVERDC)dwParam1;
	APISTR((LF_API, "DrvGetSystemPalette: lpDriverDC %p\n", lpDriverDC));

	/* (non-palette) */
	if (!bPaletteDevice)
		return (DWORD)(CreateDefaultPalette());

	/* (palette) */
	return (DWORD)(CreateDefaultPalette());


}








static DWORD 
DrvSetSystemPalette(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
	LPDRIVERDC lpDriverDC = (LPDRIVERDC)dwParam1;	
	BOOL bInitSystemPalette = (BOOL)dwParam2;
	LPPALETTEENTRY lpPaletteEntry = (LPPALETTEENTRY)lpParams;
	APISTR((LF_API, "DrvSetSystemPalette:"
		" lpDriverDC %p bInitSystemPalette %d lpPaletteEntry %p\n",
		lpDriverDC, bInitSystemPalette, lpPaletteEntry));

	/* verify palette device */
	if (!bPaletteDevice)
	{
		static UINT Pixel;
		if (bInitSystemPalette)
		{
		  Pixel = 0;
		}
		else
		{
	          Pixel++;
		}
		return Pixel;
	}

	/* initialize system palette */
	if (bInitSystemPalette
	 && !CreateUnusedSystemPalette(lpDriverDC->dp->uSystemPaletteUse))
	{
		ERRSTR((LF_ERR, "DrvSetSystemPalette: (ERR) init palette\n"));
		return (DWORD)(0);
	}

	/* allocate system palette index */
	return (DWORD)AllocSystemPaletteIndex(lpPaletteEntry);

}

static DWORD
DrvAnimatePalette(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
        UINT uAnimatePaletteIndex = (UINT)dwParam2;
	LPPALETTEENTRY lpAnimatePaletteEntry = (LPPALETTEENTRY)lpParams;
	XColor xc;

	if (uAnimatePaletteIndex >= SystemPaletteSize)
	{
		ERRSTR((LF_ERR, "DrvAnimatePalette:"
			" (ERR) animate palette index [%04x]"
			" >= system palette size [%04x]\n",
			uAnimatePaletteIndex, SystemPaletteSize));
		return (DWORD)(FALSE);
	}

	if (!lpAnimatePaletteEntry)
	{
		ERRSTR((LF_ERR, "DrvAnimatePalette:"
			" (ERR) null animate palette entry\n"));
		return (DWORD)(FALSE);
	}

	if (SystemPalettePixelUse[uAnimatePaletteIndex] != -1)
	{
/*
		ERRSTR((LF_ERR, "DrvAnimatePalette:"
			" (ERR) attempt to animate unreserved index [%04x]\n",
			uAnimatePaletteIndex));
		return (DWORD)(FALSE);
*/
	}

	/* set hardware color */
	xc.pixel = SystemPaletteMapper[uAnimatePaletteIndex];
	xc.red = xx_to_xxxx(lpAnimatePaletteEntry->peRed);
	xc.green = xx_to_xxxx(lpAnimatePaletteEntry->peGreen);
	xc.blue = xx_to_xxxx(lpAnimatePaletteEntry->peBlue);
	xc.flags = DoRed | DoGreen | DoBlue;
	XStoreColor(display, DeviceColormap, &xc);
	return (DWORD)(TRUE);

}

static DWORD
DrvUpdateColors(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
	LPDRIVERDC lpDriverDC = (LPDRIVERDC)dwParam1;	
	APISTR((LF_API, "DrvUpdateColors: lpDriverDC %p\n", lpDriverDC));

	/* verify palette device */
	if (!bPaletteDevice)
	{
		ERRSTR((LF_ERR, "DrvUpdateColors:"
			" (ERR) non-palette device\n"));
		SetLastErrorEx(1, 0);
		return (DWORD)(FALSE);
	}
	return (DWORD)(FALSE);
}

#endif	/* TWIN_PALETTE */

static COLORREF
DrvGetNearestColor(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{
	COLORREF cr = (COLORREF)dwParam1;
	BYTE r, g, b;
	DWORD dwPixel;
	PRIVATEDISPLAY *dp = GETDP();
	XColor xc;

	/* (non-palette device) */
	if (!bPaletteDevice)
	{
		r = GetRValue(cr);
		g = GetGValue(cr);
		b = GetBValue(cr);
		dwPixel = (dwRMapper[r] | dwGMapper[g] | dwBMapper[b]);
		r = 255 * (dwPixel & dwRMask) / dwRMask;
		g = 255 * (dwPixel & dwGMask) / dwGMask;
		b = 255 * (dwPixel & dwBMask) / dwBMask;
		return (RGB(r, g, b));
	}

	/* (palette device) */
	if (bPaletteDevice)
	{
		xc.red = itoc(GetRValue(cr));
		xc.green = itoc(GetGValue(cr));
		xc.blue = itoc(GetBValue(cr));
		if (XAllocColor(dp->display, dp->SystemPalette, &xc))
			XFreeColors(dp->display, dp->SystemPalette,
				&xc.pixel, 1, 0L);
		return RGB(ctoi(xc.red), ctoi(xc.green), ctoi(xc.blue));
	}

}

void
DrvGetXColor(COLORREF cr, XColor *xc)
{
    PRIVATEDISPLAY *dp = GETDP();
    DWORD pixel;

    if (fTrueColor) {
	xc->red   = itoc(GetRValue(cr)); 
	xc->green = itoc(GetGValue(cr)); 
	xc->blue   = itoc(GetBValue(cr)); 
	xc->flags = DoRed|DoGreen|DoBlue;
    }
    else {
#ifdef TWIN_PALETTE
	xc->red = itoc(GetRValue(cr));
	xc->green = itoc(GetGValue(cr));
	xc->blue = itoc(GetBValue(cr));
	if (XAllocColor(dp->display, dp->SystemPalette, xc))
		XFreeColors(dp->display, dp->SystemPalette, &xc->pixel, 1, 0L);
#else
	pixel = DrvMakePixel(cr);	
	pixel &= 0xff;
	*xc = pixel_table[pixel];
#endif
    }
}

/* 
 *	for a given pixel value
 *	lookup its colors and return colorref for it
 *	(note: if its in our table use that entry, otherwise
 *	return the query value...)
 */

#ifdef TWIN_PALETTE

static DWORD
DrvColorGetColorRef(LPARAM dwParam1, LPARAM dwParm2, LPVOID lpParams)
{
	return (DWORD)DrvGetColorRef((DWORD)dwParam1);
}

static COLORREF
DrvGetColorRef(DWORD dwPixel)
{
	BYTE r, g, b;
	XColor xc;

	LOGSTR((LF_LOG, "DrvGetColorRef: (LOG) pixel [%08lx]", dwPixel));

	/* (non-palette device) */
	if (!bPaletteDevice)
	{
		r = 255 * (dwPixel & dwRMask) / dwRMask;
		g = 255 * (dwPixel & dwGMask) / dwGMask;
		b = 255 * (dwPixel & dwBMask) / dwBMask;
	}

	/* (palette device) */
	if (bPaletteDevice)
	{
		xc.pixel = pixel0 | (dwPixel & pixel_mask);
		XQueryColor(display, DeviceColormap, &xc);
		r = xxxx_to_xx(xc.red);
		g = xxxx_to_xx(xc.green);
		b = xxxx_to_xx(xc.blue);
	}

	LOGSTR((LF_LOG, " RGB(%02x,%02x,%02x)\n", r, g, b));
	return (RGB(r, g, b));

}

#else

static COLORREF
DrvGetColorRef(DWORD pixel)
{
    XColor  	xc,*xp;
    DWORD	p;
    COLORREF	rgb;
    PRIVATEDISPLAY *dp;
    int		red,green,blue;

    dp = GETDP();

    if (fTrueColor) {
/*
 *  For 16 bpp data is represented by short values in the following
 *  format: 'RRRrrGGg gggBBBbb'. To extract each color's portion into
 *  a byte value, shift it into the high portion of the byte and then
 *  OR into the remaining bits the high portion of the color again. That
 *  is: Red = 'RRRrrRRR', Green = 'GGggggGG', and Blue = 'BBBbbBBB'.
 *  This method ensures that '11111xxx xxxxxxxx' becomes '11111111'.
 *  The 15 bpp data is treated in the same manner ('0RRRrrGG GggBBBbb').
 */
	if (dp->BitsPixel == 16) {
	    if (dp->Depth == 15) {
		red = ((pixel >> 7) & 0xf8) | (pixel >> 12);
		green = ((pixel >> 2) & 0xf8) | ((pixel >> 7) & 7);
		blue = ((pixel & 0x1f) << 3) | ((pixel >> 2) & 7);
	    } else {
		red = ((pixel >> 8) & 0xf8) | (pixel >> 13);
		green = ((pixel >> 3) & 0xfc) | ((pixel >> 9) & 3);
		blue = ((pixel & 0x1f) << 3) | ((pixel >> 2) & 7);
	    }
	} else if (dp->BitsPixel == 32) {
/* This may not right. Programs seem to work find no matter what's here.
   The problem is that I don't understand exactly what's happening, the 
   16 bpp code is confusing. JJF 2/20/96 */
	    red =  (pixel >> 16) & 0xff;
	    green =  (pixel >> 8) & 0xff;
	    blue = pixel & 0xff;
	} else {
	    ERRSTR((LF_ERR,"Unsupported X server -- %x bits-per-pixel\n",
			dp->BitsPixel));
	    return 0L;
	}
	return RGB(red,green,blue); 
    }

    if (pixel >= dp->pixel_base && pixel < (dp->pixel_base + dp->nNumPixels))
	return pixel_mapper[pixel];
    else {
	xc.pixel = pixel;
#ifdef TWIN_PALETTE
	XQueryColor(dp->display,dp->SystemPalette, &xc);
#else
	XQueryColor(dp->display,dp->color_map, &xc);
#endif
	xp = &xc;

	red = ctoi(xp->red);
	green = ctoi(xp->green);
	blue = ctoi(xp->blue);

	rgb = RGB(red,green,blue);

	return rgb;
    }
}
#endif
 
static DWORD 
DrvFillRGBTable(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
    int nNumColors = (int)dwParam1;
    RGBQUAD *lprgb = (RGBQUAD *)lpParams;
    int i;
    COLORREF cr;

#ifdef TWIN_PALETTE

	if (nNumColors > SystemPaletteSize)
	{
		ERRSTR((LF_ERR, "DrvFillRGBTable:"
			" (ERR) nNumColors [%d] > SystemPaletteSize [%d]\n",
			nNumColors, SystemPaletteSize));
		return (DWORD)(FALSE);
	}

#else

#ifdef LATER
    /* for now it can only be called with nNumColors == 256 */
#else
    if (nNumColors != 256)
	return (DWORD)FALSE;
#endif

#endif	/* !defined(TWIN_PALETTE) */

    for (i = 0; i < nNumColors; i++) {
	cr = DrvGetColorRef((DWORD)i);

	lprgb[i].rgbBlue = GetBValue(cr);
	lprgb[i].rgbGreen = GetGValue(cr);
	lprgb[i].rgbRed = GetRValue(cr);
	lprgb[i].rgbReserved = 0;
    }
    return (DWORD)TRUE;
}

/*
 *	given a colorref, return the pixel that goes with it 
 *	normalize to standard pixel values...
 *	try to match
 *	if none found, but free slot exists, then allocate it
 */

#ifdef TWIN_PALETTE

static WORD DrvGetNearestPaletteIndex(BYTE r, BYTE g, BYTE b,
	WORD wPaletteSize, LPPALETTEENTRY lpPaletteEntryTable)
{
	WORD w, wNearestPaletteIndex;
	long err, err0, r0, g0, b0;

	for (w = wNearestPaletteIndex = 0, err = 0x30000L;
	     w < wPaletteSize;
	     w++)
	{
		r0 = lpPaletteEntryTable[w].peRed;
		g0 = lpPaletteEntryTable[w].peGreen;
		b0 = lpPaletteEntryTable[w].peBlue;
		err0 = (r - r0) * (r - r0)
			+ (g - g0) * (g - g0)
			+ (b - b0) * (b - b0);
		if (err0 == 0)
			return (w);
		if (err0 < err)
		{
			err = err0;
			wNearestPaletteIndex = w;
		}
	}
	return (wNearestPaletteIndex);

}

static DWORD DrvMakePaletteIndexPixel(WORD wPaletteIndex,
	WORD wPaletteSize, LPWORD lpPaletteIndexTable)
{
	if (wPaletteIndex >= wPaletteSize)
	{
		ERRSTR((LF_ERR, "DrvMakePaletteIndexPixel():"
			" (ERR) palette index [%d] >= palette size [d]\n",
			wPaletteIndex, wPaletteSize));
		wPaletteIndex = 0;
	}
	return (lpPaletteIndexTable[wPaletteIndex]);
}

static void DrvGetPaletteIndexRGB(WORD wPaletteIndex,
	WORD wPaletteSize, LPPALETTEENTRY lpPaletteEntryTable,
	BYTE *r, BYTE *g, BYTE *b)
{
	if (wPaletteIndex >= wPaletteSize)
	{
		ERRSTR((LF_ERR, "DrvMakePaletteIndexRGB():"
			" (ERR) palette index [%d] >= palette size [d]\n",
			wPaletteIndex, wPaletteSize));
		wPaletteIndex = 0;
	}
	*r = lpPaletteEntryTable[wPaletteIndex].peRed;
	*g = lpPaletteEntryTable[wPaletteIndex].peGreen;
	*b = lpPaletteEntryTable[wPaletteIndex].peBlue;
}

static DWORD DrvMakeVGAPalettePixel(BYTE r, BYTE g, BYTE b)
{
/*
	return DrvMakePaletteIndexPixel(DrvGetNearestPaletteIndex(r, g, b,
		SystemPaletteSize, SystemPalette),
		SystemPaletteSize, SystemPaletteMapper);
*/
	PALETTEENTRY pe;

	/* make black pixel */
	if ((r == 0) && (g == 0) && (b == 0))
		return (SystemPaletteMapper[0]);

	/* make white pixel */
	if ((r == 255) && (g == 255) && (b == 255))
		return (SystemPaletteMapper[SystemPaletteSize - 1]);

	/* make other pixel */
	pe.peRed = r;
	pe.peGreen = g;
	pe.peBlue = b;
	pe.peFlags = 0;
	return SystemPaletteMapper[DrvGetNearestPaletteIndex(r, g, b,
		SystemPaletteSize, SystemPalette)];

}

static DWORD DrvMakeNonPalettePixel(BYTE r, BYTE g, BYTE b)
{
	LOGSTR((LF_LOG, "DrvMakeNonPalettePixel:"
		" (LOG) RGB(%02x,%02x,%02x)\n",
		r, g, b));
	return (dwRMapper[r] | dwGMapper[g] | dwBMapper[b]);
}

static DWORD 
DrvColorMakePixel(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpParams)
{
	return DrvMakePixel((COLORREF)dwParam1, (LPDRIVERDC)dwParam2);
}

DWORD
DrvMakePixel(COLORREF ColorRef, LPDRIVERDC lpDriverDC)
{
	BYTE r, g, b;
	WORD wPaletteIndex;
	DWORD dwPixel;

	/* convert PALETTERGB() color value to pixel value */
	if ((ColorRef & 0xff000000UL) == 0x02000000UL)
	{
		r = GetRValue(ColorRef);
		g = GetGValue(ColorRef);
		b = GetBValue(ColorRef);
		if (bPaletteDevice)
		{
			/* convert PALETTERGB() to PALETTEINDEX() */
			if (!lpDriverDC || !lpDriverDC->lpPaletteEntryTable)
			{
				/* use system palette */
				wPaletteIndex = DrvGetNearestPaletteIndex
					(r, g, b, SystemPaletteSize,
					SystemPalette);
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTERGB(%02x,%02x,%02x)"
					" ----> PALETTEINDEX(%04x)"
					" [SYSTEM PALETTE]\n",
					r, g, b, wPaletteIndex));
			}
			else
			{
				/* use selected palette */
				wPaletteIndex = DrvGetNearestPaletteIndex
					(r, g, b, lpDriverDC->wPaletteSize,
					lpDriverDC->lpPaletteEntryTable);
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTERGB(%02x,%02x,%02x)"
					" ----> PALETTEINDEX(%04x)"
					" [SELECTED PALETTE]\n",
					r, g, b, wPaletteIndex));
			}
			ColorRef = PALETTEINDEX(wPaletteIndex);
		}
		else
		{
			/* convert PALETTERGB() to RGB() */
			LOGSTR((LF_LOG, "DrvMakePixel:"
				" (LOG) PALETTERGB(%02x,%02x,%02x)"
				" ----> RGB(%02x,%02x,%02x)\n",
				r, g, b, r, g, b));
			ColorRef = RGB(r, g, b);
		}
	}

	/* convert PALETTEINDEX() color value to pixel value */
	if ((ColorRef & 0xff000000UL) == 0x01000000UL)
	{
		wPaletteIndex = (WORD) (ColorRef & 0x0000ffffUL);
		if (bPaletteDevice)
		{
			/* convert PALETTEINDEX() to pixel value */
			if (!lpDriverDC || !lpDriverDC->lpPaletteEntryTable)
			{
				/* use system palette */
/*
				dwPixel = DrvMakePaletteIndexPixel
					(wPaletteIndex, SystemPaletteSize,
					SystemPaletteMapper);
*/
dwPixel = 0;
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTEINDEX(%04x)"
					" ----> pixel %08x"
					" [SYSTEM PALETTE]\n",
					wPaletteIndex, dwPixel));
			}
			else
			{
				/* use selected palette */
				dwPixel = DrvMakePaletteIndexPixel
					(wPaletteIndex,
					lpDriverDC->wPaletteSize,
					lpDriverDC->lpPaletteIndexTable);
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTEINDEX(%04x)"
					" ----> pixel %08x"
					" [SELECTED PALETTE]\n",
					wPaletteIndex, dwPixel));
			}
			/* return pixel value */
			return (dwPixel);
		}
		else
		{
			/* convert PALETTEINDEX() to RGB() */
			if (!lpDriverDC || !lpDriverDC->lpPaletteEntryTable)
			{
				/* use system palette */
				DrvGetPaletteIndexRGB(wPaletteIndex,
					SystemPaletteSize, SystemPalette,
					&r, &g, &b);
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTEINDEX(%04x)"
					" ----> RGB(%02x,%02x,%02x)"
					" [SYSTEM PALETTE]\n",
					wPaletteIndex, r, g, b));
			}
			else
			{
				/* use selected palette */
				DrvGetPaletteIndexRGB(wPaletteIndex,
					lpDriverDC->wPaletteSize,
					lpDriverDC->lpPaletteEntryTable,
					&r, &g, &b);
				LOGSTR((LF_LOG, "DrvMakePixel:"
					" (LOG) PALETTEINDEX(%04x)"
					" ----> RGB(%02x,%02x,%02x)"
					" [SELECTED PALETTE]\n",
					wPaletteIndex, r, g, b));
			}
			ColorRef = RGB(r, g, b);
		}
	}

	/* convert RGB() color value to pixel value */
	if ((ColorRef & 0xff000000UL) == 0x00000000UL)
	{
		r = GetRValue(ColorRef);
		g = GetGValue(ColorRef);
		b = GetBValue(ColorRef);
		if (bPaletteDevice)
		{
			dwPixel = DrvMakeVGAPalettePixel(r, g, b);
			LOGSTR((LF_LOG, "DrvMakePixel:"
				" (LOG) RGB(%02x,%02x,%02x)"
				" ----> pixel %08x"
				" [VGA PALETTE]\n",
				r, g, b, dwPixel));
		}
		else
		{
			dwPixel = DrvMakeNonPalettePixel(r, g, b);
			LOGSTR((LF_LOG, "DrvMakePixel:"
				" (LOG) RGB(%02x,%02x,%02x)"
				" ----> pixel %08x"
				" [NO PALETTE]\n",
				r, g, b, dwPixel));
		}
	}

	/* return pixel value */
	return (dwPixel);

}

#else

#define DELTA 31

static DWORD
DrvColorMakePixel(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{
	return DrvColorMakePixel((COLORREF)dwParam1);
}

DWORD
DrvMakePixel(COLORREF value)
{
    XColor xc;
    PRIVATEDISPLAY   *dp;
    int red,green,blue;
    DWORD cred,cgreen,cblue;
    DWORD pixel;
    LONG dx;
    LONG i,new,delta,min,match;
	
    /* if black or white wanted... return the PIXEL... */
    if(value == RGB(255,255,255))
	return pixel_white;

    if(value == RGB(0,0,0))
	return pixel_black;

    /* convert the COLORREF to RGB values */
    red = GetRValue(value);
    green = GetGValue(value);
    blue =  GetBValue(value);

    dp = GETDP();

    if (fTrueColor) {
	if (dp->BitsPixel == 16) {
	    if (dp->Depth == 15)
		pixel = ((red/8) << 10) | ((green/8) << 5) | (blue/8);
	    else
		pixel = ((red/8) << 11) | ((green/4) << 5) | (blue/8);
	    return (pixel & 0xffff);
	} else if (dp->BitsPixel == 32) { /* JJF 2/20/96 */
	    pixel = (red << 16) | (green << 8) | (blue);
	    return (pixel & 0xffffff);
	} else {
	    ERRSTR((LF_ERR,"Unsupported X server -- %x bits-per-pixel\n",
			dp->BitsPixel));
	    return 0L;
	}
    }

    min    = 255*255*255;
    match  = 0;	
    new    = 0;

    for (i=dp->pixel_base; i<dp->pixel_base+dp->nNumPixels; i++) {
	if (pixel_mapper[i] == value) {
	    match = i;
	    min   = 0;
	    break;
	}
    }

    if (match == 0)
	for (i=dp->pixel_base; i<dp->pixel_base+dp->nNumPixels; i++) {
	    delta = 0;
	    cred = GetRValue(pixel_mapper[i]);
	    cgreen = GetGValue(pixel_mapper[i]);
	    cblue = GetBValue(pixel_mapper[i]);

	    dx = cred - red;
	    delta = dx * dx;
	    dx = cgreen - green;
	    delta += dx * dx;
	    dx = cblue - blue;
	    delta += dx * dx;
			
	    if (delta < min) {
		min = delta;
		match = i;
	    }
	}

    return pixel_table[match].pixel;
}
#endif /* else TWIN_PALETTE */

#ifdef TWIN_PALETTE
static DWORD
DrvInitColors(UINT uiCompatibility)
{
	static BOOL bInitialized = FALSE;
	PRIVATEDISPLAY *dp = GETDP();
	Visual *visual;
	int i;

	/* initialize colors once */
	if (bInitialized)
		return (1L);
	bInitialized = TRUE;

	/* determine whether display is a palette or non-palette device */
	display = dp->display;
	visual = DefaultVisual(dp->display, dp->screen);
	switch (visual->class)
	{
	case StaticGray:
		bPaletteDevice = TRUE;
		break;
	case StaticColor:
		bPaletteDevice = TRUE;
		break;
	case GrayScale:
		bPaletteDevice = TRUE;
		break;
	case PseudoColor:
		bPaletteDevice = TRUE;
		break;
	case TrueColor:
		bPaletteDevice = FALSE;
		break;
	case DirectColor:
		ERRSTR((LF_ERR, "DrvInitColors: DirectColor not supported\n"));
		return (0L);
	default:
		ERRSTR((LF_ERR, "DrvInitColors: unknown visual class %d\n",
			visual->class));
		return (0L);
	}

	/* [NONPALETTE] initialize red/green/blue color component info */
	if (!bPaletteDevice)
	{
		dwRMask = visual->red_mask;
		dwGMask = visual->green_mask;
		dwBMask = visual->blue_mask;
		LOGSTR((LF_LOG, "DrvInitColors:"
			" (LOG) RGB Mask (%08x,%08x,%08x)\n",
			dwRMask, dwGMask, dwBMask));
		for (i = 0; i < 256; i++)
		{
			dwRMapper[i] = (i * dwRMask / 255) & dwRMask;
			dwGMapper[i] = (i * dwGMask / 255) & dwGMask;
			dwBMapper[i] = (i * dwBMask / 255) & dwBMask;
			LOGSTR((LF_LOG, "DrvInitColors:"
				" (LOG) [%02x] RGB Mapper (%08x,%08x,%08x)\n",
				i, dwRMapper[i], dwGMapper[i], dwBMapper[i]));
		}
		dp->pixel_mask = ~0L;
		return (1L);
	}

	/* [PALETTE] initialize palette index info */
	if (!CreateDeviceColormap(dp->display, dp->screen, 5, 8))
		return (0L);
	CreateSystemPalette();
	CreateUnusedSystemPalette(SYSPAL_STATIC);

	/* save colormap for create window code */
	dp->SystemPalette = DeviceColormap;

	/* save pixel mask for bitblt/raster-op code */
	dp->pixel_base = pixel0;
	dp->pixel_mask = pixel_mask;
	dp->nNumPixels = 1 << pixel_numplanes;

	/* success */
	return (1L);

}
#else
static DWORD
DrvInitColors(UINT uiCompatibility)
{
    static BOOL fInitialized = FALSE;
    int	i,nNumColors,nNumPlanes,rc,nDiff;
    BOOL	fReverse = FALSE;
    DWORD	li;
    DWORD	pixel_base,pixel_mask = 0;
    DWORD	pixel_base1,base_save;
    DWORD plane_masks[8];
    PRIVATEDISPLAY   *dp;
    LPCOLORMAPPROPERTY lpcpr;
    LPXRGB lpxrgb;
    DWORD dwSize;
    BYTE pixel_map[256];
    XColor *xc,xcolor;
    int actual_format = 0;
    Atom atmActualType;
    DWORD nitems,bytes_after;
    int nplanes,nindex,ncolors;
    RGBQUAD *RgbColors;
	
    if (fInitialized)
	return 1L;
    else
	fInitialized = TRUE;

    dp = GETDP();

    nNumPlanes = dp->Depth;
    nNumColors = 1 << nNumPlanes;

    switch (nNumPlanes) {
    case 1:		/* monochrome */
	pixel_mapper = (LPDWORD)WinMalloc(2*sizeof(DWORD));
	pixel_table = (XColor *)WinMalloc(2*sizeof(XColor));
	dp->pixel_mask = 1;
	dp->pixel_base = 0;
	dp->nNumPixels = nNumColors;
	pixel_white = WhitePixel(dp->display,dp->screen);
 	pixel_black = BlackPixel(dp->display,dp->screen);
	pixel_mapper[pixel_black] = RGB(0,0,0);
	pixel_mapper[pixel_white] = RGB(255,255,255);
	pixel_table[pixel_black].red = pixel_table[pixel_black].green =
		pixel_table[pixel_black].blue = 0;
	pixel_table[pixel_black].flags = DoRed|DoGreen|DoBlue;
	pixel_table[pixel_black].pad = 0;
	pixel_table[pixel_black].pixel = pixel_black;
	pixel_table[pixel_white].red = pixel_table[pixel_white].green =
		pixel_table[pixel_white].blue = 0xffff;
	pixel_table[pixel_white].flags = DoRed|DoGreen|DoBlue;
	pixel_table[pixel_white].pad = 0;
	pixel_table[pixel_white].pixel = pixel_white;
	return 1L;
	break;

    case 4:		/* 16-color server */
	pixel_mapper = (LPDWORD)WinMalloc(16*sizeof(DWORD));
	pixel_table = (XColor *)WinMalloc(16*sizeof(XColor));
	dp->pixel_mask = 0xf;
	dp->pixel_base = 0;
	dp->nNumPixels = nNumColors;
	pixel_white = WhitePixel(dp->display,dp->screen);
 	pixel_black = BlackPixel(dp->display,dp->screen);
	for (i = 0; i < 16; i++) {
	    xc = &pixel_table[i];
	    xc->pixel = i;
#ifdef TWIN_PALETTE
	    XQueryColor(dp->display,dp->SystemPalette, xc);
#else
	    XQueryColor(dp->display,dp->color_map, xc);
#endif
	    pixel_mapper[i] = RGB(ctoi(xc->red),ctoi(xc->green),ctoi(xc->blue));
	}
	return 1L;
	break;

    default:		/* true color */
	if (nNumPlanes < 8) {
	    ERRSTR((LF_ERR,
		"Unknown number %d of color planes on the server\n",
		nNumPlanes));
	    return 0L;
	}
	fTrueColor = TRUE;
	dp->pixel_mask = -1;
	dp->pixel_base = 0;
	dp->nNumPixels = nNumColors;
	pixel_white = WhitePixel(dp->display,dp->screen);
 	pixel_black = BlackPixel(dp->display,dp->screen);
	return 1L;
	break;

    case 8:		/* 256 colors */
	pixel_mapper = (LPDWORD)WinMalloc(256*sizeof(DWORD));
	pixel_table = (XColor *)WinMalloc(256*sizeof(XColor));

	dp->atmColormapProperty = XInternAtom(dp->display,
			"WILLOWS_COLORMAP",False);
	rc = XGetWindowProperty(dp->display,
		RootWindow(dp->display,dp->screen), 
		dp->atmColormapProperty,
		0,
		sizeof(COLORMAPPROPERTY)/sizeof(LONG),
		False,
		AnyPropertyType,
		&atmActualType,
		&actual_format,
		&nitems,
		&bytes_after,
		(LPBYTE *)&lpcpr);

	if (rc == Success && actual_format == 32) {
	    lpxrgb = &lpcpr->xrgb[0];
	    xcolor.red = lpxrgb->red;
	    xcolor.green = lpxrgb->green;
	    xcolor.blue = lpxrgb->blue;
	    xcolor.flags = DoRed|DoGreen|DoBlue;
	    xcolor.pad = 0;
#ifdef TWIN_PALETTE
	    XAllocColor(dp->display,dp->SystemPalette,&xcolor);
#else
	    XAllocColor(dp->display,dp->color_map,&xcolor);
#endif
	    if (xcolor.pixel == lpcpr->nBasePixel) {
		fReverse = FALSE;
		goto SecondCopy;
	    }
	    else if (xcolor.pixel == (lpcpr->nBasePixel|lpcpr->nPlaneMask)) {
		fReverse = TRUE;
		goto SecondCopy;
	    }
	    else {
#ifdef TWIN_PALETTE
		XFreeColors(dp->display,dp->SystemPalette,
			&xcolor.pixel,1,0);
#else
		XFreeColors(dp->display,dp->color_map,
			&xcolor.pixel,1,0);
#endif
		XFree((LPSTR)lpcpr);
	    }
	    /* fall thru to first copy mode */
	}

FirstCopy:
	    memset(pixel_map,'\0',sizeof(pixel_map));
	    memset(plane_masks,'\0',sizeof(plane_masks));

	    XGrabServer(dp->display);

	    pixel_base = 0;
	    for (i = nNumPlanes; i; i--) {
		nplanes = i;
		rc = XAllocColorCells(dp->display,
			XDefaultColormap(dp->display,dp->screen),
			True,
			plane_masks,
			i,
			&pixel_base,
			1);
		if (rc) {
		    break;
		}
	    }

	    for (i=0; i < nplanes; i++) 
		pixel_mask |= plane_masks[i];

	    nNumColors = 1 << nplanes;
	    switch (nNumColors) {
		case 128:
		    RgbColors = &RgbColors_128[0];
		    break;
		case 64:
		    RgbColors = &RgbColors_64[0];
		    break;
		case 32:
		    RgbColors = &RgbColors_32[0];
		    break;
		case 16:
		    RgbColors = &RgbColors_16[0];
		    break;
		default:
		    ERRSTR((LF_ERR,
			"Do not have color distribution available. (2) \n"));
		    XUngrabServer(dp->display);
		    return 0L;
	    }
	    logstr(LF_LOG,"Allocating %d colors...\n",nNumColors);


	    for (i = 0; i < nNumColors; i++)
		pixel_mapper[pixel_base+i] = RGB(RgbColors[i].rgbRed,
						 RgbColors[i].rgbGreen,
						 RgbColors[i].rgbBlue);


#ifdef	DEBUG
	    xcolor.red = xcolor.green = xcolor.blue = 0;
	    xcolor.flags = DoRed|DoGreen|DoBlue;
	    xcolor.pad = 0;
#endif

	    for (i = nplanes-1; i; i--) {
		rc = XAllocColorCells(dp->display,
#ifdef TWIN_PALETTE
			dp->SystemPalette,
#else
			dp->color_map,
#endif
			True,
			plane_masks,
			i,
			&pixel_base1,
			1);
		if (!rc)
		    break;

		ncolors = 1 << i;

		for (nindex = 0; nindex < ncolors; nindex++) {
#ifdef	DEBUG
		    xcolor.pixel = pixel_base1+nindex;
#ifdef TWIN_PALETTE
		    XStoreColor(dp->display,dp->SystemPalette,&xcolor);
#else
		    XStoreColor(dp->display,dp->color_map,&xcolor);
#endif
#endif
		    pixel_map[pixel_base1+nindex] = 1;
		}
	    }

	    i = 1;
	    while(1) {
		rc = XAllocColorCells(dp->display,
#ifdef TWIN_PALETTE
			dp->SystemPalette,
#else
			dp->color_map,
#endif
			True,
			plane_masks,
			0,
			&pixel_base1,
			1);
		if (!rc)
		    break;
		pixel_map[pixel_base1] = 1;
#ifdef	DEBUG
		xcolor.pixel = pixel_base1;
#ifdef TWIN_PALETTE
		XStoreColor(dp->display,dp->SystemPalette,&xcolor);
#else
		XStoreColor(dp->display,dp->color_map,&xcolor);
#endif
#endif
		if (i) {
		    if (i == 2) {
			nDiff = pixel_base1 - base_save;
			fReverse = (nDiff < 0);
			i = 0;
		    }
		    else if (i == 1) {
			base_save = pixel_base1;
			i = 2;
		    }
		}
	    }

	    XFreeColors(dp->display, 
#ifdef TWIN_PALETTE
		dp->SystemPalette,
#else
		dp->color_map,
#endif
		&pixel_base, 1, pixel_mask);

	    for (nindex = 0; nindex < nNumColors; nindex++) {
		i = (fReverse) ? nNumColors - nindex - 1 : nindex;
		xc = &pixel_table[pixel_base+i];
		xc->red = itoc(RgbColors[i].rgbRed);
		xc->green = itoc(RgbColors[i].rgbGreen);
		xc->blue = itoc(RgbColors[i].rgbBlue);
		xc->flags = DoRed|DoGreen|DoBlue;
		xc->pad = 0;
#ifdef TWIN_PALETTE
		XAllocColor(dp->display,dp->SystemPalette,xc);
#else
		XAllocColor(dp->display,dp->color_map,xc);
#endif
		if (xc->pixel < pixel_base ||
			xc->pixel >= pixel_base+nNumColors) {
		    int nRedDirection,nGreenDirection,nBlueDirection;	    
		    nRedDirection = (xc->red < 0x8000)?1:0;
		    nGreenDirection = (xc->green < 0x8000)?1:0;
		    nBlueDirection = (xc->blue < 0x8000)?1:0;
		    while(1) {
			if (nRedDirection)
			    xc->red += COLOR_STEP;
			else
			    xc->red -= COLOR_STEP;
			if (nGreenDirection)
			    xc->green += COLOR_STEP;
			else
			    xc->green -= COLOR_STEP;
			if (nBlueDirection)
			    xc->blue += COLOR_STEP;
			else
			    xc->blue -= COLOR_STEP;
#ifdef TWIN_PALETTE
			XAllocColor(dp->display,dp->SystemPalette,xc);
#else
			XAllocColor(dp->display,dp->color_map,xc);
#endif
			if (!(xc->pixel < pixel_base ||
				xc->pixel >= pixel_base+nNumColors))
			    break;
		    }
	        }
	    }

	    for (li = 0; li < 256; li++)
		if (pixel_map[li])
#ifdef TWIN_PALETTE
		    XFreeColors(dp->display,dp->SystemPalette,
#else
		    XFreeColors(dp->display,dp->color_map,
#endif
			&li,1,0);

	    pixel_black = pixel_base;
 	    pixel_white = pixel_base | pixel_mask;

	    dwSize = 4*sizeof(LONG)+ nNumColors*sizeof(XRGB);
	    lpcpr = (LPCOLORMAPPROPERTY)WinMalloc(dwSize);

	    lpcpr->nRefCount = 1;
	    lpcpr->nNumColors = nNumColors;
	    lpcpr->nBasePixel = pixel_base;
	    lpcpr->nPlaneMask = pixel_mask;
	    for (i = 0,lpxrgb = &lpcpr->xrgb[0]; i < nNumColors; i++) {
		lpxrgb[i].red = pixel_table[pixel_base+i].red;
		lpxrgb[i].green = pixel_table[pixel_base+i].green;
		lpxrgb[i].blue = pixel_table[pixel_base+i].blue;
		lpxrgb[i].pad = 0;
	    }

	    XChangeProperty(dp->display, RootWindow(dp->display,dp->screen), 
		dp->atmColormapProperty,
		XA_INTEGER,
		32,
		PropModeReplace,
		(LPBYTE)lpcpr,
		dwSize/sizeof(long));

	    WinFree((LPSTR)lpcpr);

	    XUngrabServer(dp->display);

	dp->pixel_mask = pixel_mask;
	dp->pixel_base = pixel_base;
	dp->nNumPixels = nNumColors;

	return 1L;

SecondCopy:
	
	dp->pixel_mask = lpcpr->nPlaneMask;
	dp->pixel_base = pixel_base = lpcpr->nBasePixel;
	dp->nNumPixels = nNumColors = lpcpr->nNumColors;
	pixel_black = pixel_base;
 	pixel_white = pixel_base | dp->pixel_mask;

	XFree((LPSTR)lpcpr);

	dwSize = 4 + (nNumColors*sizeof(XRGB))/sizeof(LONG);

	rc = XGetWindowProperty(dp->display,
		RootWindow(dp->display,dp->screen), 
		dp->atmColormapProperty,
		0,
		dwSize,
		False,
		AnyPropertyType,
		&atmActualType,
		&actual_format,
		&nitems,
		&bytes_after,
		(LPBYTE *)&lpcpr);

	if (rc != Success)
	    goto FirstCopy;
	else {
	    if (actual_format != 32 || nitems != dwSize) {
		XFree((LPSTR)lpcpr);
		goto FirstCopy;
	    }
	}

	lpxrgb = &lpcpr->xrgb[0];

	switch (nNumColors) {
	    case 128:
		RgbColors = &RgbColors_128[0];
		break;
	    case 64:
		RgbColors = &RgbColors_64[0];
		break;
	    case 32:
		RgbColors = &RgbColors_32[0];
		break;
	    case 16:
		RgbColors = &RgbColors_16[0];
		break;
	    default:
		ERRSTR((LF_ERR,"Do not have color distribution available. (1)\n"));
		XUngrabServer(dp->display);
		return 0L;
	}
	ERRSTR((LF_ERR,"Using %d colors...\n",nNumColors));

	for (i = 0; i < nNumColors; i++) {
	    pixel_mapper[pixel_base+i] = RGB(RgbColors[i].rgbRed,
						 RgbColors[i].rgbGreen,
						 RgbColors[i].rgbBlue);
	    xc = &pixel_table[pixel_base+i];
	    xc->red = lpxrgb[i].red;
	    xc->green = lpxrgb[i].green;
	    xc->blue = lpxrgb[i].blue;
	    xc->flags = DoRed|DoGreen|DoBlue;
	    xc->pad = 0;
#ifdef TWIN_PALETTE
	    XAllocColor(dp->display,dp->SystemPalette,xc);
#else
	    XAllocColor(dp->display,dp->color_map,xc);
#endif
	}

	lpcpr->nRefCount++;

	XChangeProperty(dp->display, RootWindow(dp->display,dp->screen), 
		dp->atmColormapProperty,
		XA_INTEGER,
		32,
		PropModeReplace,
		(LPBYTE)lpcpr,
		dwSize);

	XFree((LPSTR)lpcpr);

	return 1L;
	break;
    }
}
#endif /* else TWIN_PALETTE */

DWORD
DrvColorsDoNothing(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{
	return 1L;
}

DWORD
DrvColorsDoDefault(LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{
	return 0L;
}

DWORD
DrvColorsTab(void)
{
#if defined(TWIN_RUNTIME_DRVTAB)
	DrvColorsEntryTab[0] = DrvColorsInit;
	DrvColorsEntryTab[1] = DrvColorsDoNothing;
	DrvColorsEntryTab[2] = DrvColorsDoNothing;
	DrvColorsEntryTab[3] = DrvColorsDoDefault;
	DrvColorsEntryTab[4] = DrvSystemPaletteUse;
	DrvColorsEntryTab[5] = DrvGetSystemPalette;
	DrvColorsEntryTab[6] = DrvSetSystemPalette;
	DrvColorsEntryTab[7] = DrvAnimatePalette;
	DrvColorsEntryTab[8] = DrvUpdateColors;
	DrvColorsEntryTab[9] = DrvColorMakePixel;
	DrvColorsEntryTab[10] = DrvGetNearestColor;
	DrvColorsEntryTab[11] = DrvColorGetColorRef;
	DrvColorsEntryTab[12] = DrvFillRGBTable;
	DrvColorsEntryTab[13] = DrvColorsDoDefault;
	DrvColorsEntryTab[14] = DrvColorsDoDefault;
#endif

	return (DWORD)DrvColorsEntryTab;
}
