wine/objects/color.c
Alexandre Julliard a69b88b2f2 Release 980315
Sun Mar 15 03:46:50 1998  Dimitrie O. Paun  <dimi@mail.cs.toronto.edu>

	* [*/*]
	Fixed some dprintf_ such that there is one and only one
	new line for each dprintf and that new line occurs at the end.
	Transformed some fprintfs into proper debug statements.
	Removed much redundancy from most of the debug statements. The
	redundancy appeared because now the component and function
	name is output automatically. Most debug statements also used to
	output the name of the function.
	All these changes prepared the source to switch completely to
	the new debugging interface.
	For more info, refer to ./documentation/debug-msg

Sat Mar 14 19:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [misc/shell.c] [if1632/kernel.spec]
	Changed parameters of FUNC004() to fix a crash.
	Not sure if this fix is correct (doc wanted).

	* [windows/user.c] [if1632/user.spec] [include/user.h]
	Implemented UserSeeUserDo.

	* [msdos/int21.c] [include/msdos.h]
	Added "GET LIST OF LISTS" (INT 21/52h).

Sat Mar 14 15:48:02 1998  Douglas Ridgway <ridgway@gmcl.com>

	* [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c]
	Beginnings of enhanced metafile support.

Fri Mar 13 20:53:09 1998  John Richardson <jrichard@zko.dec.com>

	* [win32/console.c]
	Restart interrupted console writes.

Fri Mar 13 18:59:24 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Updated documentation for API manpages.

	* [windows/dce.c]
	ReleaseDC16: Fixed cast.

	* [include/windows.h] [memory/virtual.c]
	VirtualQuery{Ex} should return DWORD instead of BOOL32.

Fri Mar 13 13:03:06 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [README][documentation/status/]
	README updated, added lzexpand,version and multimedia
	status notes to new documentation/status directory.

	* [ole/*.c][if1632/typelib.spec]
	Added typelib stubs, several small additions and fixes.

	* [loader/pe_image.c]
	Fixed a small bug (fixup_imports got passed the wrong hModule in a
	remapcase).

	* [loader/signal.c][if1632/signal.c][misc/winsock_dns.c]
	  [loader/module.c]
	Fixed some recursive debugger crashes (caused by invalid FS).

	* [misc/registry.c]
	Two bugs fixed.

Fri Mar 13 04:55:01 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [include/winnt.h] [include/winnls.h]
	Moved LANG_xxx flags to winnls.h

	* [include/winnls.h]
	Added flags for GetDateFormat(); fixed validity of
	LOCALE_SYSTEM_DEFAULT.

	* [include/windows.h] 
	Added GetTimeFormat() prototypes.

	* [ole/ole2nls.c]
	Implemented ASCII date- and time-functions,  using an
	optimized common core;  added stubs for Unicode versions;  
	started work on a Unicode core.

	* [AUTHORS]
	Added my name.

Mon Mar  9 20:10:15 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [relay32/comctl32.spec] [include/imagelist.h]
	  [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in]
	First attempt at implementing ImageLists.

Sun Mar  8 20:19:49 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/dos_fs.c] [configure.in]
	Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and
	SystemTimeToFileTime right.
	Use timegm() where available.

	* [misc/lstr.c]
	Fix an off by one error in FormatMessage and handle the case 
	when args = NULL (used by programs to get the length of the 
	string).

	* [win32/console.c]
	Actual display a per-process Title string, better working
	attempt for WriteConsole32W and ReadConsole32W.

Fri Mar  6 20:33:45 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [include/config.h.in][configure.in][multimedia/audio.c]
	  [multimedia/dsound.c]
	Added check for FreeBSD sound system.

Sun Mar  1 17:40:10 1998  Jason Schonberg <schon@mti.sgi.com>

	* [controls/edit.c] [include/ole.h] [include/shlobj.h]
	Removed final commas in enum types.

Mon Feb 23 07:52:18 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [multimedia/time.c]
	Workaround to avoid infinite recursion inside timeGetTime.

	* [multimedia/audio.c]
	WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the
	SOUND_DEV can be opened, or if it's busy.
1998-03-15 20:29:56 +00:00

1087 lines
32 KiB
C

/*
* Color functions
*
* Copyright 1993 Alexandre Julliard
* Copyright 1996 Alex Korobka
*/
#include <stdlib.h>
#include "ts_xlib.h"
#include <stdio.h>
#include <string.h>
#include "windows.h"
#include "options.h"
#include "gdi.h"
#include "color.h"
#include "debug.h"
#include "xmalloc.h"
/* Palette indexed mode:
* logical palette -> mapping -> pixel
*
*
* Windows needs contiguous color space ( from 0 to n ) but
* it is possible only with the private colormap. Otherwise we
* have to map DC palette indices to real pixel values. With
* private colormaps it boils down to the identity mapping. The
* other special case is when we have a fixed color visual with
* the screendepth > 8 - we abandon palette mappings altogether
* because pixel values can be calculated without X server
* assistance.
*
* Windows palette manager is described in the
* http://premium.microsoft.com/msdn/library/techart/f30/f34/f40/d4d/sa942.htm
*/
typedef struct
{
Colormap colorMap;
UINT16 size;
UINT16 flags;
INT32 monoPlane; /* bit plane different for white and black pixels */
INT32 (*mapColor)( DC*, COLORREF );
} CSPACE;
static CSPACE cSpace = {0, 0, 0};
static int COLOR_Redshift = 0; /* to handle abortive COLOR_VIRTUAL visuals */
static int COLOR_Redmax = 0;
static int COLOR_Greenshift = 0;
static int COLOR_Greenmax = 0;
static int COLOR_Blueshift = 0;
static int COLOR_Bluemax = 0;
static int COLOR_Graymax = 0;
/* System color space.
*
* First 10 and last 10 colors in COLOR_sysPalette are
* "guarded". RealizePalette changes only the rest of colorcells. For
* currently inactive window it changes only DC palette mappings.
*/
#define NB_COLORCUBE_START_INDEX 63
Visual* visual = NULL;
static PALETTEENTRY* COLOR_sysPal = NULL; /* current system palette */
static int COLOR_gapStart = 256;
static int COLOR_gapEnd = -1;
static int COLOR_gapFilled = 0;
static int COLOR_max = 256;
/* First free dynamic color cell, 0 = full palette, -1 = fixed palette */
static int COLOR_firstFree = 0;
static unsigned char COLOR_freeList[256];
/* Maps entry in the system palette to X pixel value */
int* COLOR_PaletteToPixel = NULL;
/* Maps pixel to the entry in the system palette */
int* COLOR_PixelToPalette = NULL;
static const PALETTEENTRY __sysPalTemplate[NB_RESERVED_COLORS] =
{
/* first 10 entries in the system palette */
/* red green blue flags */
{ 0x00, 0x00, 0x00, PC_SYS_USED },
{ 0x80, 0x00, 0x00, PC_SYS_USED },
{ 0x00, 0x80, 0x00, PC_SYS_USED },
{ 0x80, 0x80, 0x00, PC_SYS_USED },
{ 0x00, 0x00, 0x80, PC_SYS_USED },
{ 0x80, 0x00, 0x80, PC_SYS_USED },
{ 0x00, 0x80, 0x80, PC_SYS_USED },
{ 0xc0, 0xc0, 0xc0, PC_SYS_USED },
{ 0xc0, 0xdc, 0xc0, PC_SYS_USED },
{ 0xa6, 0xca, 0xf0, PC_SYS_USED },
/* ... c_min/2 dynamic colorcells */
/* ... gap (for sparse palettes) */
/* ... c_min/2 dynamic colorcells */
{ 0xff, 0xfb, 0xf0, PC_SYS_USED },
{ 0xa0, 0xa0, 0xa4, PC_SYS_USED },
{ 0x80, 0x80, 0x80, PC_SYS_USED },
{ 0xff, 0x00, 0x00, PC_SYS_USED },
{ 0x00, 0xff, 0x00, PC_SYS_USED },
{ 0xff, 0xff, 0x00, PC_SYS_USED },
{ 0x00, 0x00, 0xff, PC_SYS_USED },
{ 0xff, 0x00, 0xff, PC_SYS_USED },
{ 0x00, 0xff, 0xff, PC_SYS_USED },
{ 0xff, 0xff, 0xff, PC_SYS_USED } /* last 10 */
};
/* Map an EGA index (0..15) to a pixel value in the system color space. */
int COLOR_mapEGAPixel[16];
/***********************************************************************
* Misc auxiliary functions
*/
Colormap COLOR_GetColormap(void)
{
return cSpace.colorMap;
}
BOOL32 COLOR_GetMonoPlane(INT32* plane)
{
*plane = cSpace.monoPlane;
return (cSpace.flags & COLOR_WHITESET) ? TRUE : FALSE;
}
UINT16 COLOR_GetSystemPaletteSize(void)
{
return (cSpace.flags & COLOR_PRIVATE) ? cSpace.size : 256;
}
UINT16 COLOR_GetSystemPaletteFlags(void)
{
return cSpace.flags;
}
const PALETTEENTRY* COLOR_GetSystemPaletteTemplate(void)
{
return __sysPalTemplate;
}
COLORREF COLOR_GetSystemPaletteEntry(UINT32 i)
{
return *(COLORREF*)(COLOR_sysPal + i) & 0x00ffffff;
}
void COLOR_FormatSystemPalette(void)
{
/* Build free list so we'd have an easy way to find
* out if there are any available colorcells.
*/
int i, j = COLOR_firstFree = NB_RESERVED_COLORS/2;
COLOR_sysPal[j].peFlags = 0;
for( i = NB_RESERVED_COLORS/2 + 1 ; i < 256 - NB_RESERVED_COLORS/2 ; i++ )
if( i < COLOR_gapStart || i > COLOR_gapEnd )
{
COLOR_sysPal[i].peFlags = 0; /* unused tag */
COLOR_freeList[j] = i; /* next */
j = i;
}
COLOR_freeList[j] = 0;
}
BOOL32 COLOR_CheckSysColor(COLORREF c)
{
int i;
for( i = 0; i < NB_RESERVED_COLORS; i++ )
if( c == (*(COLORREF*)(__sysPalTemplate + i) & 0x00ffffff) )
return 0;
return 1;
}
/***********************************************************************
* Colormap Initialization
*/
static void COLOR_FillDefaultColors(void)
{
/* initialize unused entries to what Windows uses as a color
* cube - based on Greg Kreider's code.
*/
int i = 0, idx = 0;
int red, no_r, inc_r;
int green, no_g, inc_g;
int blue, no_b, inc_b;
if (cSpace.size <= NB_RESERVED_COLORS)
return;
while (i*i*i < (cSpace.size - NB_RESERVED_COLORS)) i++;
no_r = no_g = no_b = --i;
if ((no_r * (no_g+1) * no_b) < (cSpace.size - NB_RESERVED_COLORS)) no_g++;
if ((no_r * no_g * (no_b+1)) < (cSpace.size - NB_RESERVED_COLORS)) no_b++;
inc_r = (255 - NB_COLORCUBE_START_INDEX)/no_r;
inc_g = (255 - NB_COLORCUBE_START_INDEX)/no_g;
inc_b = (255 - NB_COLORCUBE_START_INDEX)/no_b;
idx = COLOR_firstFree;
if( idx != -1 )
for (blue = NB_COLORCUBE_START_INDEX; blue < 256 && idx; blue += inc_b )
for (green = NB_COLORCUBE_START_INDEX; green < 256 && idx; green += inc_g )
for (red = NB_COLORCUBE_START_INDEX; red < 256 && idx; red += inc_r )
{
/* weird but true */
if( red == NB_COLORCUBE_START_INDEX && green == red && blue == green ) continue;
COLOR_sysPal[idx].peRed = red;
COLOR_sysPal[idx].peGreen = green;
COLOR_sysPal[idx].peBlue = blue;
/* set X color */
if( cSpace.flags & COLOR_VIRTUAL )
{
if (COLOR_Redmax != 255) no_r = (red * COLOR_Redmax) / 255;
if (COLOR_Greenmax != 255) no_g = (green * COLOR_Greenmax) / 255;
if (COLOR_Bluemax != 255) no_b = (blue * COLOR_Bluemax) / 255;
COLOR_PaletteToPixel[idx] = (no_r << COLOR_Redshift) | (no_g << COLOR_Greenshift) | (no_b << COLOR_Blueshift);
}
else if( !(cSpace.flags & COLOR_FIXED) )
{
XColor color = { color.pixel = (COLOR_PaletteToPixel)? COLOR_PaletteToPixel[idx] : idx ,
COLOR_sysPal[idx].peRed << 8,
COLOR_sysPal[idx].peGreen << 8,
COLOR_sysPal[idx].peGreen << 8,
(DoRed | DoGreen | DoBlue) };
TSXStoreColor(display, cSpace.colorMap, &color);
}
idx = COLOR_freeList[idx];
}
/* try to fill some entries in the "gap" with
* what's already in the colormap - they will be
* mappable to but not changeable. */
if( COLOR_gapStart < COLOR_gapEnd && COLOR_PixelToPalette )
{
XColor xc;
int r, g, b, max;
max = COLOR_max - (256 - (COLOR_gapEnd - COLOR_gapStart));
for ( i = 0, idx = COLOR_gapStart; i < 256 && idx <= COLOR_gapEnd; i++ )
if( COLOR_PixelToPalette[i] == 0 )
{
xc.pixel = i;
TSXQueryColor(display, cSpace.colorMap, &xc);
r = xc.red>>8; g = xc.green>>8; b = xc.blue>>8;
if( xc.pixel < 256 && COLOR_CheckSysColor(RGB(r, g, b)) &&
TSXAllocColor(display, cSpace.colorMap, &xc) )
{
COLOR_PixelToPalette[xc.pixel] = idx;
COLOR_PaletteToPixel[idx] = xc.pixel;
*(COLORREF*)(COLOR_sysPal + idx) = RGB(r, g, b);
COLOR_sysPal[idx++].peFlags |= PC_SYS_USED;
if( --max <= 0 ) break;
}
}
COLOR_gapFilled = idx - COLOR_gapStart;
}
}
/***********************************************************************
* COLOR_BuildPrivateMap/COLOR_BuildSharedMap
*
* Allocate colorcells and initialize mapping tables.
*/
static BOOL32 COLOR_BuildPrivateMap(CSPACE* cs)
{
/* Private colormap - identity mapping */
XColor color;
int i;
COLOR_sysPal = (PALETTEENTRY*)xmalloc(sizeof(PALETTEENTRY)*cs->size);
TRACE(palette,"\tbuilding private map - %i palette entries\n", cs->size);
/* Allocate system palette colors */
for( i=0; i < cs->size; i++ )
{
if( i < NB_RESERVED_COLORS/2 )
{
color.red = __sysPalTemplate[i].peRed * 65535 / 255;
color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
color.blue = __sysPalTemplate[i].peBlue * 65535 / 255;
COLOR_sysPal[i] = __sysPalTemplate[i];
}
else if( i >= cs->size - NB_RESERVED_COLORS/2 )
{
int j = NB_RESERVED_COLORS + i - cs->size;
color.red = __sysPalTemplate[j].peRed * 65535 / 255;
color.green = __sysPalTemplate[j].peGreen * 65535 / 255;
color.blue = __sysPalTemplate[j].peBlue * 65535 / 255;
COLOR_sysPal[i] = __sysPalTemplate[j];
}
color.flags = DoRed | DoGreen | DoBlue;
color.pixel = i;
TSXStoreColor(display, cs->colorMap, &color);
/* Set EGA mapping if color is from the first or last eight */
if (i < 8)
COLOR_mapEGAPixel[i] = color.pixel;
else if (i >= cs->size - 8 )
COLOR_mapEGAPixel[i - (cs->size - 16)] = color.pixel;
}
COLOR_PixelToPalette = COLOR_PaletteToPixel = NULL;
COLOR_gapStart = 256; COLOR_gapEnd = -1;
COLOR_firstFree = (cs->size > NB_RESERVED_COLORS)?NB_RESERVED_COLORS/2 : -1;
return FALSE;
}
static BOOL32 COLOR_BuildSharedMap(CSPACE* cs)
{
XColor color;
unsigned long sysPixel[NB_RESERVED_COLORS];
unsigned long* pixDynMapping = NULL;
unsigned long plane_masks[1];
int i, j, warn = 0;
int diff, r, g, b, max = 256, bp = 0, wp = 1;
int step = 1;
/* read "AllocSystemColors" from wine.conf */
COLOR_max = PROFILE_GetWineIniInt( "options", "AllocSystemColors", 256);
if (COLOR_max > 256) COLOR_max = 256;
else if (COLOR_max < 20) COLOR_max = 20;
TRACE(palette,"%d colors configured.\n", COLOR_max);
TRACE(palette,"\tbuilding shared map - %i palette entries\n", cs->size);
/* Be nice and allocate system colors as read-only */
for( i = 0; i < NB_RESERVED_COLORS; i++ )
{
color.red = __sysPalTemplate[i].peRed * 65535 / 255;
color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
color.blue = __sysPalTemplate[i].peBlue * 65535 / 255;
color.flags = DoRed | DoGreen | DoBlue;
if (!TSXAllocColor( display, cSpace.colorMap, &color ))
{
XColor best, c;
if( !warn++ )
{
WARN(palette, "Not enough colors for the full system palette.\n");
bp = BlackPixel(display, DefaultScreen(display));
wp = WhitePixel(display, DefaultScreen(display));
max = (0xffffffff)>>(32 - screenDepth);
if( max > 256 )
{
step = max/256;
max = 256;
}
}
/* reinit color (XAllocColor() may change it)
* and map to the best shared colorcell */
color.red = __sysPalTemplate[i].peRed * 65535 / 255;
color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
color.blue = __sysPalTemplate[i].peBlue * 65535 / 255;
best.pixel = best.red = best.green = best.blue = 0;
for( c.pixel = 0, diff = 0x7fffffff; c.pixel < max; c.pixel += step )
{
TSXQueryColor(display, cSpace.colorMap, &c);
r = (c.red - color.red)>>8;
g = (c.green - color.green)>>8;
b = (c.blue - color.blue)>>8;
r = r*r + g*g + b*b;
if( r < diff ) { best = c; diff = r; }
}
if( TSXAllocColor(display, cSpace.colorMap, &best) )
color.pixel = best.pixel;
else color.pixel = (i < NB_RESERVED_COLORS/2)? bp : wp;
}
sysPixel[i] = color.pixel;
TRACE(palette,"\tsyscolor(%lx) -> pixel %i\n",
*(COLORREF*)(__sysPalTemplate+i), (int)color.pixel);
/* Set EGA mapping if color in the first or last eight */
if (i < 8)
COLOR_mapEGAPixel[i] = color.pixel;
else if (i >= NB_RESERVED_COLORS - 8 )
COLOR_mapEGAPixel[i - (NB_RESERVED_COLORS-16)] = color.pixel;
}
/* now allocate changeable set */
if( !(cSpace.flags & COLOR_FIXED) )
{
int c_min = 0, c_max = cs->size, c_val;
TRACE(palette,"\tdynamic colormap... \n");
/* comment this out if you want to debug palette init */
TSXGrabServer(display);
/* let's become the first client that actually follows
* X guidelines and does binary search...
*/
pixDynMapping = (unsigned long*)xmalloc(sizeof(long)*cs->size);
while( c_max - c_min > 0 )
{
c_val = (c_max + c_min)/2 + (c_max + c_min)%2;
if( !TSXAllocColorCells(display, cs->colorMap, False,
plane_masks, 0, pixDynMapping, c_val) )
c_max = c_val - 1;
else
{
TSXFreeColors(display, cs->colorMap, pixDynMapping, c_val, 0);
c_min = c_val;
}
}
if( c_min > COLOR_max - NB_RESERVED_COLORS)
c_min = COLOR_max - NB_RESERVED_COLORS;
c_min = (c_min/2) + (c_min/2); /* need even set for split palette */
if( c_min > 0 )
if( !TSXAllocColorCells(display, cs->colorMap, False,
plane_masks, 0, pixDynMapping, c_min) )
{
fprintf(stderr,"Inexplicable failure during colorcell allocation.\n");
c_min = 0;
}
cs->size = c_min + NB_RESERVED_COLORS;
TSXUngrabServer(display);
TRACE(palette,"adjusted size %i colorcells\n", cs->size);
}
else if( cSpace.flags & COLOR_VIRTUAL )
{
/* virtual colorspace - ToPhysical takes care of
* color translations but we have to allocate full palette
* to maintain compatibility
*/
cs->size = 256;
TRACE(palette,"\tvirtual colorspace - screendepth %i\n", screenDepth);
}
else cs->size = NB_RESERVED_COLORS; /* system palette only - however we can alloc a bunch
* of colors and map to them */
TRACE(palette,"Shared system palette uses %i colors.\n", cs->size);
/* set gap to account for pixel shortage. It has to be right in the center
* of the system palette because otherwise raster ops get screwed. */
if( cs->size >= 256 )
{ COLOR_gapStart = 256; COLOR_gapEnd = -1; }
else
{ COLOR_gapStart = cs->size/2; COLOR_gapEnd = 255 - cs->size/2; }
COLOR_firstFree = ( cs->size > NB_RESERVED_COLORS &&
(cs->flags & COLOR_VIRTUAL || !(cs->flags & COLOR_FIXED)) )
? NB_RESERVED_COLORS/2 : -1;
COLOR_sysPal = (PALETTEENTRY*)xmalloc(sizeof(PALETTEENTRY)*256);
/* setup system palette entry <-> pixel mappings and fill in 20 fixed entries */
if( screenDepth <= 8 )
{
COLOR_PixelToPalette = (int*)xmalloc(sizeof(int)*256);
memset( COLOR_PixelToPalette, 0, 256*sizeof(int) );
}
/* for hicolor visuals PaletteToPixel mapping is used to skip
* RGB->pixel calculation in COLOR_ToPhysical().
*/
COLOR_PaletteToPixel = (int*)xmalloc(sizeof(int)*256);
for( i = j = 0; i < 256; i++ )
{
if( i >= COLOR_gapStart && i <= COLOR_gapEnd )
{
COLOR_PaletteToPixel[i] = 0;
COLOR_sysPal[i].peFlags = 0; /* mark as unused */
continue;
}
if( i < NB_RESERVED_COLORS/2 )
{
COLOR_PaletteToPixel[i] = sysPixel[i];
COLOR_sysPal[i] = __sysPalTemplate[i];
}
else if( i >= 256 - NB_RESERVED_COLORS/2 )
{
COLOR_PaletteToPixel[i] = sysPixel[(i + NB_RESERVED_COLORS) - 256];
COLOR_sysPal[i] = __sysPalTemplate[(i + NB_RESERVED_COLORS) - 256];
}
else if( pixDynMapping )
COLOR_PaletteToPixel[i] = pixDynMapping[j++];
else
COLOR_PaletteToPixel[i] = i;
TRACE(palette,"\tindex %i -> pixel %i\n", i, COLOR_PaletteToPixel[i]);
if( COLOR_PixelToPalette )
COLOR_PixelToPalette[COLOR_PaletteToPixel[i]] = i;
}
if( pixDynMapping ) free(pixDynMapping);
return TRUE;
}
/***********************************************************************
* COLOR_Computeshifts
*
* Calculate conversion parameters for direct mapped visuals
*/
static void COLOR_Computeshifts(unsigned long maskbits, int *shift, int *max)
{
int i;
if (maskbits==0)
{
*shift=0;
*max=0;
return;
}
for(i=0;!(maskbits&1);i++)
maskbits >>= 1;
*shift = i;
*max = maskbits;
}
/***********************************************************************
* COLOR_Init
*
* Initialize color management.
*/
BOOL32 COLOR_Init(void)
{
int mask, white, black;
visual = DefaultVisual( display, DefaultScreen(display) );
TRACE(palette,"initializing palette manager...\n");
white = WhitePixelOfScreen( screen );
black = BlackPixelOfScreen( screen );
cSpace.monoPlane = 1;
for( mask = 1; !((white & mask)^(black & mask)); mask <<= 1 )
cSpace.monoPlane++;
cSpace.flags = (white & mask) ? COLOR_WHITESET : 0;
cSpace.size = visual->map_entries;
switch(visual->class)
{
case DirectColor:
cSpace.flags |= COLOR_VIRTUAL;
case GrayScale:
case PseudoColor:
if (Options.usePrivateMap)
{
XSetWindowAttributes win_attr;
cSpace.colorMap = TSXCreateColormap( display, rootWindow,
visual, AllocAll );
if (cSpace.colorMap)
{
cSpace.flags |= (COLOR_PRIVATE | COLOR_WHITESET);
cSpace.monoPlane = 1;
for( white = cSpace.size - 1; !(white & 1); white >>= 1 )
cSpace.monoPlane++;
if( rootWindow != DefaultRootWindow(display) )
{
win_attr.colormap = cSpace.colorMap;
TSXChangeWindowAttributes( display, rootWindow,
CWColormap, &win_attr );
}
break;
}
}
cSpace.colorMap = DefaultColormapOfScreen( screen );
break;
case StaticGray:
cSpace.colorMap = DefaultColormapOfScreen( screen );
cSpace.flags |= COLOR_FIXED;
COLOR_Graymax = (1<<screenDepth)-1;
break;
case TrueColor:
cSpace.flags |= COLOR_VIRTUAL;
case StaticColor: {
int *depths,nrofdepths;
/* FIXME: hack to detect XFree32 XF_VGA16 ... We just have
* depths 1 and 4
*/
depths=TSXListDepths(display,DefaultScreen(display),&nrofdepths);
if ((nrofdepths==2) && ((depths[0]==4) || depths[1]==4)) {
cSpace.monoPlane = 1;
for( white = cSpace.size - 1; !(white & 1); white >>= 1 )
cSpace.monoPlane++;
cSpace.flags = (white & mask) ? COLOR_WHITESET : 0;
cSpace.colorMap = DefaultColormapOfScreen( screen );
TSXFree(depths);
break;
}
TSXFree(depths);
cSpace.colorMap = DefaultColormapOfScreen( screen );
cSpace.flags |= COLOR_FIXED;
COLOR_Computeshifts(visual->red_mask, &COLOR_Redshift, &COLOR_Redmax);
COLOR_Computeshifts(visual->green_mask, &COLOR_Greenshift, &COLOR_Greenmax);
COLOR_Computeshifts(visual->blue_mask, &COLOR_Blueshift, &COLOR_Bluemax);
break;
}
}
TRACE(palette," visual class %i (%i)\n",
visual->class, cSpace.monoPlane);
memset(COLOR_freeList, 0, 256*sizeof(unsigned char));
if (cSpace.flags & COLOR_PRIVATE)
COLOR_BuildPrivateMap( &cSpace );
else
COLOR_BuildSharedMap( &cSpace );
/* Build free list */
if( COLOR_firstFree != -1 )
COLOR_FormatSystemPalette();
COLOR_FillDefaultColors();
return TRUE;
}
/***********************************************************************
* COLOR_Cleanup
*
* Free external colors we grabbed in the FillDefaultPalette()
*/
void COLOR_Cleanup(void)
{
if( COLOR_gapFilled )
TSXFreeColors(display, cSpace.colorMap,
(unsigned long*)(COLOR_PaletteToPixel + COLOR_gapStart),
COLOR_gapFilled, 0);
}
/***********************************************************************
* COLOR_IsSolid
*
* Check whether 'color' can be represented with a solid color.
*/
BOOL32 COLOR_IsSolid( COLORREF color )
{
int i;
const PALETTEENTRY *pEntry = COLOR_sysPal;
if (color & 0xff000000) return TRUE; /* indexed color */
if (!color || (color == 0xffffff)) return TRUE; /* black or white */
for (i = 0; i < 256 ; i++, pEntry++)
{
if( i < COLOR_gapStart || i > COLOR_gapEnd )
if ((GetRValue(color) == pEntry->peRed) &&
(GetGValue(color) == pEntry->peGreen) &&
(GetBValue(color) == pEntry->peBlue)) return TRUE;
}
return FALSE;
}
/***********************************************************************
* COLOR_PaletteLookupPixel
*/
int COLOR_PaletteLookupPixel( PALETTEENTRY* palPalEntry, int size,
int* mapping, COLORREF col, BOOL32 skipReserved )
{
int i, best = 0, diff = 0x7fffffff;
int r,g,b;
for( i = 0; i < size && diff ; i++ )
{
if( !(palPalEntry[i].peFlags & PC_SYS_USED) ||
(skipReserved && palPalEntry[i].peFlags & PC_SYS_RESERVED) )
continue;
r = palPalEntry[i].peRed - GetRValue(col);
g = palPalEntry[i].peGreen - GetGValue(col);
b = palPalEntry[i].peBlue - GetBValue(col);
r = r*r + g*g + b*b;
if( r < diff ) { best = i; diff = r; }
}
return (mapping) ? mapping[best] : best;
}
/***********************************************************************
* COLOR_LookupSystemPixel
*/
int COLOR_LookupSystemPixel(COLORREF col)
{
int i, best = 0, diff = 0x7fffffff;
int size = COLOR_GetSystemPaletteSize();
int r,g,b;
for( i = 0; i < size && diff ; i++ )
{
if( i == NB_RESERVED_COLORS/2 )
{
int newi = size - NB_RESERVED_COLORS/2;
if (newi>i) i=newi;
}
r = COLOR_sysPal[i].peRed - GetRValue(col);
g = COLOR_sysPal[i].peGreen - GetGValue(col);
b = COLOR_sysPal[i].peBlue - GetBValue(col);
r = r*r + g*g + b*b;
if( r < diff ) { best = i; diff = r; }
}
return (COLOR_PaletteToPixel)? COLOR_PaletteToPixel[best] : best;
}
/***********************************************************************
* COLOR_PaletteLookupExactIndex
*/
int COLOR_PaletteLookupExactIndex( PALETTEENTRY* palPalEntry, int size,
COLORREF col )
{
int i;
BYTE r = GetRValue(col), g = GetGValue(col), b = GetBValue(col);
for( i = 0; i < size; i++ )
{
if( palPalEntry[i].peFlags & PC_SYS_USED ) /* skips gap */
if( palPalEntry[i].peRed == r &&
palPalEntry[i].peGreen == g &&
palPalEntry[i].peBlue == b )
return i;
}
return -1;
}
/***********************************************************************
* COLOR_LookupNearestColor
*/
COLORREF COLOR_LookupNearestColor( PALETTEENTRY* palPalEntry, int size, COLORREF color )
{
unsigned char spec_type = color >> 24;
int i;
/* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
if( spec_type == 2 ) /* PALETTERGB */
color = *(COLORREF*)
(palPalEntry + COLOR_PaletteLookupPixel(palPalEntry,size,NULL,color,FALSE));
else if( spec_type == 1 ) /* PALETTEINDEX */
if( (i = color & 0x0000ffff) >= size )
{
fprintf(stderr, "\tRGB(%lx) : idx %d is out of bounds, assuming NULL\n", color, i);
color = *(COLORREF*)palPalEntry;
}
else color = *(COLORREF*)(palPalEntry + i);
color &= 0x00ffffff;
return (0x00ffffff & *(COLORREF*)
(COLOR_sysPal + COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL, color, FALSE)));
}
/***********************************************************************
* COLOR_ToLogical
*
* Return RGB color for given X pixel.
*/
COLORREF COLOR_ToLogical(int pixel)
{
XColor color;
/* truecolor visual */
if (screenDepth >= 24) return pixel;
/* check for hicolor visuals first */
if ( cSpace.flags & COLOR_FIXED && !COLOR_Graymax )
{
color.red = (pixel >> COLOR_Redshift) & COLOR_Redmax;
color.green = (pixel >> COLOR_Greenshift) & COLOR_Greenmax;
color.blue = (pixel >> COLOR_Blueshift) & COLOR_Bluemax;
return RGB((color.red * 255)/COLOR_Redmax,
(color.green * 255)/COLOR_Greenmax,
(color.blue * 255)/COLOR_Bluemax);
}
/* check if we can bypass X */
if ((screenDepth <= 8) && (pixel < 256) &&
!(cSpace.flags & (COLOR_VIRTUAL | COLOR_FIXED)) )
return ( *(COLORREF*)(COLOR_sysPal +
((COLOR_PixelToPalette)?COLOR_PixelToPalette[pixel]:pixel)) ) & 0x00ffffff;
color.pixel = pixel;
TSXQueryColor(display, cSpace.colorMap, &color);
return RGB(color.red >> 8, color.green >> 8, color.blue >> 8);
}
/***********************************************************************
* COLOR_ToPhysical
*
* Return the physical color closest to 'color'.
*/
int COLOR_ToPhysical( DC *dc, COLORREF color )
{
WORD index = 0;
HPALETTE16 hPal = (dc)? dc->w.hPalette: STOCK_DEFAULT_PALETTE;
unsigned char spec_type = color >> 24;
PALETTEOBJ* palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hPal, PALETTE_MAGIC );
if ( cSpace.flags & COLOR_FIXED )
{
/* there is no colormap limitation; we are going to have to compute
* the pixel value from the visual information stored earlier
*/
unsigned long red, green, blue;
unsigned idx = 0;
switch(spec_type)
{
case 2: /* PALETTERGB - not sure if we really need to search palette */
idx = COLOR_PaletteLookupPixel( palPtr->logpalette.palPalEntry,
palPtr->logpalette.palNumEntries,
NULL, color, FALSE);
if( palPtr->mapping )
{
GDI_HEAP_UNLOCK( hPal );
return palPtr->mapping[idx];
}
color = *(COLORREF*)(palPtr->logpalette.palPalEntry + idx);
break;
case 1: /* PALETTEINDEX */
if( (idx = color & 0xffff) >= palPtr->logpalette.palNumEntries)
{
fprintf(stderr, "\tRGB(%lx) : idx %d is out of bounds, assuming black\n", color, idx);
GDI_HEAP_UNLOCK( hPal );
return 0;
}
if( palPtr->mapping )
{
GDI_HEAP_UNLOCK( hPal );
return palPtr->mapping[idx];
}
color = *(COLORREF*)(palPtr->logpalette.palPalEntry + idx);
break;
default:
color &= 0xffffff;
/* fall through to RGB */
case 0: /* RGB */
if( dc && (dc->w.bitsPerPixel == 1) )
{
GDI_HEAP_UNLOCK( hPal );
return (((color >> 16) & 0xff) +
((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0;
}
}
red = GetRValue(color); green = GetGValue(color); blue = GetBValue(color);
if (COLOR_Graymax)
{
/* grayscale only; return scaled value */
GDI_HEAP_UNLOCK( hPal );
return ( (red * 30 + green * 69 + blue * 11) * COLOR_Graymax) / 25500;
}
else
{
/* scale each individually and construct the TrueColor pixel value */
if (COLOR_Redmax != 255) red = (red * COLOR_Redmax) / 255;
if (COLOR_Greenmax != 255) green = (green * COLOR_Greenmax) / 255;
if (COLOR_Bluemax != 255) blue = (blue * COLOR_Bluemax) / 255;
GDI_HEAP_UNLOCK( hPal );
return (red << COLOR_Redshift) | (green << COLOR_Greenshift) | (blue << COLOR_Blueshift);
}
}
else
{
/* palPtr can be NULL when DC is being destroyed */
if( !palPtr ) return 0;
else if( !palPtr->mapping )
WARN(palette, "\tpalette %04x is not realized\n", dc->w.hPalette);
switch(spec_type) /* we have to peruse DC and system palette */
{
default:
color &= 0xffffff;
/* fall through to RGB */
case 0: /* RGB */
if( dc && (dc->w.bitsPerPixel == 1) )
{
GDI_HEAP_UNLOCK( hPal );
return (((color >> 16) & 0xff) +
((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0;
}
index = COLOR_PaletteLookupPixel( COLOR_sysPal, 256,
COLOR_PaletteToPixel, color, FALSE);
/* TRACE(palette,"\tRGB(%lx) -> pixel %i\n", color, index);
*/
break;
case 1: /* PALETTEINDEX */
index = color & 0xffff;
if( index >= palPtr->logpalette.palNumEntries )
fprintf(stderr, "\tRGB(%lx) : index %i is out of bounds\n", color, index);
else if( palPtr->mapping ) index = palPtr->mapping[index];
/* TRACE(palette,"\tPALETTEINDEX(%04x) -> pixel %i\n", (WORD)color, index);
*/
break;
case 2: /* PALETTERGB */
index = COLOR_PaletteLookupPixel( palPtr->logpalette.palPalEntry,
palPtr->logpalette.palNumEntries,
palPtr->mapping, color, FALSE);
/* TRACE(palette,"\tPALETTERGB(%lx) -> pixel %i\n", color, index);
*/
break;
}
}
GDI_HEAP_UNLOCK( hPal );
return index;
}
/***********************************************************************
* COLOR_SetMapping
*
* Set the color-mapping table for selected palette.
* Return number of entries which mapping has changed.
*/
int COLOR_SetMapping( PALETTEOBJ* palPtr, UINT32 uStart, UINT32 uNum, BOOL32 mapOnly )
{
char flag;
int prevMapping = (palPtr->mapping) ? 1 : 0;
int index, iRemapped = 0;
/* reset dynamic system palette entries */
if( !mapOnly && COLOR_firstFree != -1)
COLOR_FormatSystemPalette();
/* initialize palette mapping table */
palPtr->mapping = (int*)xrealloc(palPtr->mapping, sizeof(int)*
palPtr->logpalette.palNumEntries);
for( uNum += uStart; uStart < uNum; uStart++ )
{
index = -1;
flag = PC_SYS_USED;
switch( palPtr->logpalette.palPalEntry[uStart].peFlags & 0x07 )
{
case PC_EXPLICIT: /* palette entries are indices into system palette */
index = *(WORD*)(palPtr->logpalette.palPalEntry + uStart);
if( index > 255 || (index >= COLOR_gapStart && index <= COLOR_gapEnd) )
{
fprintf(stderr,"PC_EXPLICIT: idx %d out of system palette, assuming black.\n", index);
index = 0;
}
break;
case PC_RESERVED: /* forbid future mappings to this entry */
flag |= PC_SYS_RESERVED;
/* fall through */
default: /* try to collapse identical colors */
index = COLOR_PaletteLookupExactIndex(COLOR_sysPal, 256,
*(COLORREF*)(palPtr->logpalette.palPalEntry + uStart));
/* fall through */
case PC_NOCOLLAPSE:
if( index < 0 )
{
if( COLOR_firstFree > 0 && !(cSpace.flags & COLOR_FIXED) )
{
XColor color;
index = COLOR_firstFree; /* ought to be available */
COLOR_firstFree = COLOR_freeList[index];
color.pixel = (COLOR_PaletteToPixel) ? COLOR_PaletteToPixel[index] : index;
color.red = palPtr->logpalette.palPalEntry[uStart].peRed << 8;
color.green = palPtr->logpalette.palPalEntry[uStart].peGreen << 8;
color.blue = palPtr->logpalette.palPalEntry[uStart].peBlue << 8;
color.flags = DoRed | DoGreen | DoBlue;
TSXStoreColor(display, cSpace.colorMap, &color);
COLOR_sysPal[index] = palPtr->logpalette.palPalEntry[uStart];
COLOR_sysPal[index].peFlags = flag;
COLOR_freeList[index] = 0;
if( COLOR_PaletteToPixel ) index = COLOR_PaletteToPixel[index];
break;
}
else if ( cSpace.flags & COLOR_VIRTUAL )
{
index = COLOR_ToPhysical( NULL, 0x00ffffff &
*(COLORREF*)(palPtr->logpalette.palPalEntry + uStart));
break;
}
/* we have to map to existing entry in the system palette */
index = COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL,
*(COLORREF*)(palPtr->logpalette.palPalEntry + uStart), TRUE);
}
palPtr->logpalette.palPalEntry[uStart].peFlags |= PC_SYS_USED;
if( COLOR_PaletteToPixel ) index = COLOR_PaletteToPixel[index];
break;
}
if( !prevMapping || palPtr->mapping[uStart] != index ) iRemapped++;
palPtr->mapping[uStart] = index;
TRACE(palette,"\tentry %i (%lx) -> pixel %i\n", uStart,
*(COLORREF*)(palPtr->logpalette.palPalEntry + uStart), index);
}
return iRemapped;
}