#include "X.h"
#define NEED_EVENTS
#include "Xproto.h"
#include "misc.h"
#include "dix.h"
#include "colormapst.h"
#include "os.h"
#include "scrnintstr.h"
#include "resource.h"
#include "windowstr.h"
#ifdef LBX
#include "lbxserve.h"
#endif
extern XID clientErrorValue;
extern int colormapPrivateCount;
static Pixel FindBestPixel(
EntryPtr ,
int ,
xrgb * ,
int
);
static int AllComp(
EntryPtr ,
xrgb *
);
static int RedComp(
EntryPtr ,
xrgb *
);
static int GreenComp(
EntryPtr ,
xrgb *
);
static int BlueComp(
EntryPtr ,
xrgb *
);
static void FreePixels(
register ColormapPtr ,
register int
);
static void CopyFree(
int ,
int ,
ColormapPtr ,
ColormapPtr
);
static void FreeCell(
ColormapPtr ,
Pixel ,
int
);
static void UpdateColors(
ColormapPtr
);
static int AllocDirect(
int ,
ColormapPtr ,
int ,
int ,
int ,
int ,
Bool ,
Pixel * ,
Pixel * ,
Pixel * ,
Pixel *
);
static int AllocPseudo(
int ,
ColormapPtr ,
int ,
int ,
Bool ,
Pixel * ,
Pixel * ,
Pixel **
);
static Bool AllocCP(
ColormapPtr ,
EntryPtr ,
int ,
int ,
Bool ,
Pixel * ,
Pixel *
);
static Bool AllocShared(
ColormapPtr ,
Pixel * ,
int ,
int ,
int ,
int ,
Pixel ,
Pixel ,
Pixel ,
Pixel *
);
static int FreeCo(
ColormapPtr ,
int ,
int ,
int ,
Pixel * ,
Pixel
);
static int TellNoMap(
WindowPtr ,
Colormap *
);
static void FindColorInRootCmap (
ColormapPtr ,
EntryPtr ,
int ,
xrgb* ,
Pixel* ,
int ,
ColorCompareProcPtr
);
#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1)
#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1)
#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1)
#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask)
#define GetNextBitsOrBreak(bits, mask, base) \
if((bits) == (mask)) \
break; \
(bits) += (base); \
while((bits) & ~(mask)) \
(bits) += ((bits) & ~(mask));
#define SERVER_ID 0
typedef struct _colorResource
{
Colormap mid;
int client;
} colorResource;
int
CreateColormap (mid, pScreen, pVisual, ppcmap, alloc, client)
Colormap mid;
ScreenPtr pScreen;
VisualPtr pVisual;
ColormapPtr *ppcmap;
int alloc;
int client;
{
int class, size;
unsigned long sizebytes;
ColormapPtr pmap;
register EntryPtr pent;
int i;
register Pixel *ppix, **pptr;
class = pVisual->class;
if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID))
return (BadMatch);
size = pVisual->ColormapEntries;
sizebytes = (size * sizeof(Entry)) +
(MAXCLIENTS * sizeof(Pixel *)) +
(MAXCLIENTS * sizeof(int));
if ((class | DynamicClass) == DirectColor)
sizebytes *= 3;
sizebytes += sizeof(ColormapRec);
pmap = (ColormapPtr) xalloc(sizebytes);
if (!pmap)
return (BadAlloc);
pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec));
sizebytes = size * sizeof(Entry);
pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes);
pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed +
(MAXCLIENTS * sizeof(Pixel *)));
pmap->mid = mid;
pmap->flags = 0;
if(mid == pScreen->defColormap)
pmap->flags |= IsDefault;
pmap->pScreen = pScreen;
pmap->pVisual = pVisual;
pmap->class = class;
if ((class | DynamicClass) == DirectColor)
size = NUMRED(pVisual);
pmap->freeRed = size;
bzero ((char *) pmap->red, (int)sizebytes);
bzero((char *) pmap->numPixelsRed, MAXCLIENTS * sizeof(int));
for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; )
*pptr = (Pixel *)NULL;
if (alloc == AllocAll)
{
if (class & DynamicClass)
pmap->flags |= AllAllocated;
for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--)
pent->refcnt = AllocPrivate;
pmap->freeRed = 0;
ppix = (Pixel *)xalloc(size * sizeof(Pixel));
if (!ppix)
{
xfree(pmap);
return (BadAlloc);
}
pmap->clientPixelsRed[client] = ppix;
for(i = 0; i < size; i++)
ppix[i] = i;
pmap->numPixelsRed[client] = size;
}
if ((class | DynamicClass) == DirectColor)
{
pmap->freeGreen = NUMGREEN(pVisual);
pmap->green = (EntryPtr)((char *)pmap->numPixelsRed +
(MAXCLIENTS * sizeof(int)));
pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes);
pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen +
(MAXCLIENTS * sizeof(Pixel *)));
pmap->freeBlue = NUMBLUE(pVisual);
pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen +
(MAXCLIENTS * sizeof(int)));
pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes);
pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue +
(MAXCLIENTS * sizeof(Pixel *)));
bzero ((char *) pmap->green, (int)sizebytes);
bzero ((char *) pmap->blue, (int)sizebytes);
memmove((char *) pmap->clientPixelsGreen,
(char *) pmap->clientPixelsRed,
MAXCLIENTS * sizeof(Pixel *));
memmove((char *) pmap->clientPixelsBlue,
(char *) pmap->clientPixelsRed,
MAXCLIENTS * sizeof(Pixel *));
bzero((char *) pmap->numPixelsGreen, MAXCLIENTS * sizeof(int));
bzero((char *) pmap->numPixelsBlue, MAXCLIENTS * sizeof(int));
if (alloc == AllocAll)
{
size = pmap->freeGreen;
for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--)
pent->refcnt = AllocPrivate;
pmap->freeGreen = 0;
ppix = (Pixel *) xalloc(size * sizeof(Pixel));
if (!ppix)
{
xfree(pmap->clientPixelsRed[client]);
xfree(pmap);
return(BadAlloc);
}
pmap->clientPixelsGreen[client] = ppix;
for(i = 0; i < size; i++)
ppix[i] = i;
pmap->numPixelsGreen[client] = size;
size = pmap->freeBlue;
for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--)
pent->refcnt = AllocPrivate;
pmap->freeBlue = 0;
ppix = (Pixel *) xalloc(size * sizeof(Pixel));
if (!ppix)
{
xfree(pmap->clientPixelsGreen[client]);
xfree(pmap->clientPixelsRed[client]);
xfree(pmap);
return(BadAlloc);
}
pmap->clientPixelsBlue[client] = ppix;
for(i = 0; i < size; i++)
ppix[i] = i;
pmap->numPixelsBlue[client] = size;
}
}
if (!AddResource(mid, RT_COLORMAP, (pointer)pmap))
return (BadAlloc);
pmap->flags |= BeingCreated;
if (colormapPrivateCount == 0)
pmap->devPrivates = NULL;
else
{
pmap->devPrivates = (DevUnion *) xalloc (
colormapPrivateCount * sizeof(DevUnion));
if (!pmap->devPrivates)
{
FreeResource (mid, RT_NONE);
return BadAlloc;
}
}
if (!(*pScreen->CreateColormap)(pmap))
{
FreeResource (mid, RT_NONE);
return BadAlloc;
}
pmap->flags &= ~BeingCreated;
*ppcmap = pmap;
return (Success);
}
int
FreeColormap (value, mid)
pointer value;
XID mid;
{
int i;
register EntryPtr pent;
ColormapPtr pmap = (ColormapPtr)value;
if(CLIENT_ID(mid) != SERVER_ID)
{
(*pmap->pScreen->UninstallColormap) (pmap);
WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid);
}
(*pmap->pScreen->DestroyColormap)(pmap);
if(pmap->clientPixelsRed)
{
for(i = 0; i < MAXCLIENTS; i++)
xfree(pmap->clientPixelsRed[i]);
}
if ((pmap->class == PseudoColor) || (pmap->class == GrayScale))
{
for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1];
pent >= pmap->red;
pent--)
{
if(pent->fShared)
{
if (--pent->co.shco.red->refcnt == 0)
xfree(pent->co.shco.red);
if (--pent->co.shco.green->refcnt == 0)
xfree(pent->co.shco.green);
if (--pent->co.shco.blue->refcnt == 0)
xfree(pent->co.shco.blue);
}
}
}
if((pmap->class | DynamicClass) == DirectColor)
{
for(i = 0; i < MAXCLIENTS; i++)
{
xfree(pmap->clientPixelsGreen[i]);
xfree(pmap->clientPixelsBlue[i]);
}
}
if (pmap->devPrivates)
xfree(pmap->devPrivates);
xfree(pmap);
return(Success);
}
static int
TellNoMap (pwin, pmid)
WindowPtr pwin;
Colormap *pmid;
{
xEvent xE;
if (wColormap(pwin) == *pmid)
{
xE.u.u.type = ColormapNotify;
xE.u.colormap.window = pwin->drawable.id;
xE.u.colormap.colormap = None;
xE.u.colormap.new = TRUE;
xE.u.colormap.state = ColormapUninstalled;
#ifdef PANORAMIX
if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum)
#endif
DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
if (pwin->optional) {
pwin->optional->colormap = None;
CheckWindowOptionalNeed (pwin);
}
}
return (WT_WALKCHILDREN);
}
int
TellLostMap (pwin, value)
WindowPtr pwin;
pointer value;
{
Colormap *pmid = (Colormap *)value;
xEvent xE;
#ifdef PANORAMIX
if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
return WT_STOPWALKING;
#endif
if (wColormap(pwin) == *pmid)
{
xE.u.u.type = ColormapNotify;
xE.u.colormap.window = pwin->drawable.id;
xE.u.colormap.colormap = *pmid;
xE.u.colormap.new = FALSE;
xE.u.colormap.state = ColormapUninstalled;
DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
}
return (WT_WALKCHILDREN);
}
int
TellGainedMap (pwin, value)
WindowPtr pwin;
pointer value;
{
Colormap *pmid = (Colormap *)value;
xEvent xE;
#ifdef PANORAMIX
if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
return WT_STOPWALKING;
#endif
if (wColormap (pwin) == *pmid)
{
xE.u.u.type = ColormapNotify;
xE.u.colormap.window = pwin->drawable.id;
xE.u.colormap.colormap = *pmid;
xE.u.colormap.new = FALSE;
xE.u.colormap.state = ColormapInstalled;
DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
}
return (WT_WALKCHILDREN);
}
int
CopyColormapAndFree (mid, pSrc, client)
Colormap mid;
ColormapPtr pSrc;
int client;
{
ColormapPtr pmap = (ColormapPtr) NULL;
int result, alloc, size;
Colormap midSrc;
ScreenPtr pScreen;
VisualPtr pVisual;
pScreen = pSrc->pScreen;
pVisual = pSrc->pVisual;
midSrc = pSrc->mid;
alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ?
AllocAll : AllocNone;
size = pVisual->ColormapEntries;
result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client);
if(result != Success)
return(result);
if(alloc == AllocAll)
{
memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry));
if((pmap->class | DynamicClass) == DirectColor)
{
memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry));
memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry));
}
pSrc->flags &= ~AllAllocated;
FreePixels(pSrc, client);
UpdateColors(pmap);
return(Success);
}
CopyFree(REDMAP, client, pSrc, pmap);
if ((pmap->class | DynamicClass) == DirectColor)
{
CopyFree(GREENMAP, client, pSrc, pmap);
CopyFree(BLUEMAP, client, pSrc, pmap);
}
if (pmap->class & DynamicClass)
UpdateColors(pmap);
return(Success);
}
static void
CopyFree (channel, client, pmapSrc, pmapDst)
int channel, client;
ColormapPtr pmapSrc, pmapDst;
{
int z, npix;
EntryPtr pentSrcFirst, pentDstFirst;
EntryPtr pentSrc, pentDst;
Pixel *ppix;
int nalloc;
switch(channel)
{
default:
case REDMAP:
ppix = (pmapSrc->clientPixelsRed)[client];
npix = (pmapSrc->numPixelsRed)[client];
pentSrcFirst = pmapSrc->red;
pentDstFirst = pmapDst->red;
break;
case GREENMAP:
ppix = (pmapSrc->clientPixelsGreen)[client];
npix = (pmapSrc->numPixelsGreen)[client];
pentSrcFirst = pmapSrc->green;
pentDstFirst = pmapDst->green;
break;
case BLUEMAP:
ppix = (pmapSrc->clientPixelsBlue)[client];
npix = (pmapSrc->numPixelsBlue)[client];
pentSrcFirst = pmapSrc->blue;
pentDstFirst = pmapDst->blue;
break;
}
nalloc = 0;
if (pmapSrc->class & DynamicClass)
{
for(z = npix; --z >= 0; ppix++)
{
pentSrc = pentSrcFirst + *ppix;
pentDst = pentDstFirst + *ppix;
if (pentDst->refcnt > 0)
{
pentDst->refcnt++;
}
else
{
*pentDst = *pentSrc;
nalloc++;
if (pentSrc->refcnt > 0)
pentDst->refcnt = 1;
else
pentSrc->fShared = FALSE;
}
FreeCell(pmapSrc, *ppix, channel);
}
}
switch(channel)
{
case REDMAP:
pmapDst->freeRed -= nalloc;
(pmapDst->clientPixelsRed)[client] =
(pmapSrc->clientPixelsRed)[client];
(pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL;
(pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client];
(pmapSrc->numPixelsRed)[client] = 0;
break;
case GREENMAP:
pmapDst->freeGreen -= nalloc;
(pmapDst->clientPixelsGreen)[client] =
(pmapSrc->clientPixelsGreen)[client];
(pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL;
(pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client];
(pmapSrc->numPixelsGreen)[client] = 0;
break;
case BLUEMAP:
pmapDst->freeBlue -= nalloc;
pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client];
pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL;
pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client];
pmapSrc->numPixelsBlue[client] = 0;
break;
}
}
static void
FreeCell (pmap, i, channel)
ColormapPtr pmap;
Pixel i;
int channel;
{
EntryPtr pent;
int *pCount;
switch (channel)
{
default:
case PSEUDOMAP:
case REDMAP:
pent = (EntryPtr) &pmap->red[i];
pCount = &pmap->freeRed;
break;
case GREENMAP:
pent = (EntryPtr) &pmap->green[i];
pCount = &pmap->freeGreen;
break;
case BLUEMAP:
pent = (EntryPtr) &pmap->blue[i];
pCount = &pmap->freeBlue;
break;
}
if (pent->refcnt > 1)
pent->refcnt--;
else
{
if (pent->fShared)
{
if(--pent->co.shco.red->refcnt == 0)
xfree(pent->co.shco.red);
if(--pent->co.shco.green->refcnt == 0)
xfree(pent->co.shco.green);
if(--pent->co.shco.blue->refcnt == 0)
xfree(pent->co.shco.blue);
pent->fShared = FALSE;
}
pent->refcnt = 0;
*pCount += 1;
}
}
static void
UpdateColors (pmap)
ColormapPtr pmap;
{
xColorItem *defs;
register xColorItem *pdef;
register EntryPtr pent;
register VisualPtr pVisual;
int i, n, size;
pVisual = pmap->pVisual;
size = pVisual->ColormapEntries;
defs = (xColorItem *)ALLOCATE_LOCAL(size * sizeof(xColorItem));
if (!defs)
return;
n = 0;
pdef = defs;
if (pmap->class == DirectColor)
{
for (i = 0; i < size; i++)
{
if (!pmap->red[i].refcnt &&
!pmap->green[i].refcnt &&
!pmap->blue[i].refcnt)
continue;
pdef->pixel = ((Pixel)i << pVisual->offsetRed) |
((Pixel)i << pVisual->offsetGreen) |
((Pixel)i << pVisual->offsetBlue);
pdef->red = pmap->red[i].co.local.red;
pdef->green = pmap->green[i].co.local.green;
pdef->blue = pmap->blue[i].co.local.blue;
pdef->flags = DoRed|DoGreen|DoBlue;
pdef++;
n++;
}
}
else
{
for (i = 0, pent = pmap->red; i < size; i++, pent++)
{
if (!pent->refcnt)
continue;
pdef->pixel = i;
if(pent->fShared)
{
pdef->red = pent->co.shco.red->color;
pdef->green = pent->co.shco.green->color;
pdef->blue = pent->co.shco.blue->color;
}
else
{
pdef->red = pent->co.local.red;
pdef->green = pent->co.local.green;
pdef->blue = pent->co.local.blue;
}
pdef->flags = DoRed|DoGreen|DoBlue;
pdef++;
n++;
}
}
if (n)
(*pmap->pScreen->StoreColors)(pmap, n, defs);
DEALLOCATE_LOCAL(defs);
}
int
AllocColor (pmap, pred, pgreen, pblue, pPix, client)
ColormapPtr pmap;
unsigned short *pred, *pgreen, *pblue;
Pixel *pPix;
int client;
{
Pixel pixR, pixG, pixB;
int entries;
xrgb rgb;
int class;
VisualPtr pVisual;
int npix;
Pixel *ppix;
pVisual = pmap->pVisual;
(*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual);
rgb.red = *pred;
rgb.green = *pgreen;
rgb.blue = *pblue;
class = pmap->class;
entries = pVisual->ColormapEntries;
if(pmap->flags & BeingCreated)
class |= DynamicClass;
switch (class) {
case StaticColor:
case StaticGray:
*pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
*pred = pmap->red[pixR].co.local.red;
*pgreen = pmap->red[pixR].co.local.green;
*pblue = pmap->red[pixR].co.local.blue;
npix = pmap->numPixelsRed[client];
ppix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
(npix + 1) * sizeof(Pixel));
if (!ppix)
return (BadAlloc);
ppix[npix] = pixR;
pmap->clientPixelsRed[client] = ppix;
pmap->numPixelsRed[client]++;
break;
case TrueColor:
pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
*pPix = (pixR << pVisual->offsetRed) |
(pixG << pVisual->offsetGreen) |
(pixB << pVisual->offsetBlue);
*pred = pmap->red[pixR].co.local.red;
*pgreen = pmap->green[pixG].co.local.green;
*pblue = pmap->blue[pixB].co.local.blue;
npix = pmap->numPixelsRed[client];
ppix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
(npix + 1) * sizeof(Pixel));
if (!ppix)
return (BadAlloc);
ppix[npix] = pixR;
pmap->clientPixelsRed[client] = ppix;
npix = pmap->numPixelsGreen[client];
ppix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client],
(npix + 1) * sizeof(Pixel));
if (!ppix)
return (BadAlloc);
ppix[npix] = pixG;
pmap->clientPixelsGreen[client] = ppix;
npix = pmap->numPixelsBlue[client];
ppix = (Pixel *) xrealloc(pmap->clientPixelsBlue[client],
(npix + 1) * sizeof(Pixel));
if (!ppix)
return (BadAlloc);
ppix[npix] = pixB;
pmap->clientPixelsBlue[client] = ppix;
pmap->numPixelsRed[client]++;
pmap->numPixelsGreen[client]++;
pmap->numPixelsBlue[client]++;
break;
case GrayScale:
case PseudoColor:
if (pmap->mid != pmap->pScreen->defColormap &&
pmap->pVisual->vid == pmap->pScreen->rootVisual)
{
ColormapPtr prootmap = (ColormapPtr)
SecurityLookupIDByType (clients[client], pmap->pScreen->defColormap,
RT_COLORMAP, SecurityReadAccess);
if (pmap->class == prootmap->class)
FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
pPix, PSEUDOMAP, AllComp);
}
if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP,
client, AllComp) != Success)
return (BadAlloc);
break;
case DirectColor:
if (pmap->mid != pmap->pScreen->defColormap &&
pmap->pVisual->vid == pmap->pScreen->rootVisual)
{
ColormapPtr prootmap = (ColormapPtr)
SecurityLookupIDByType (clients[client], pmap->pScreen->defColormap,
RT_COLORMAP, SecurityReadAccess);
if (pmap->class == prootmap->class)
{
pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
&pixR, REDMAP, RedComp);
pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb,
&pixG, GREENMAP, GreenComp);
pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb,
&pixB, BLUEMAP, BlueComp);
*pPix = pixR | pixG | pixB;
}
}
pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
client, RedComp) != Success)
return (BadAlloc);
pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
GREENMAP, client, GreenComp) != Success)
{
(void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
return (BadAlloc);
}
pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
client, BlueComp) != Success)
{
(void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0);
(void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
return (BadAlloc);
}
*pPix = pixR | pixG | pixB;
break;
}
if ((pmap->numPixelsRed[client] == 1) &&
(CLIENT_ID(pmap->mid) != client) &&
!(pmap->flags & BeingCreated))
{
colorResource *pcr;
pcr = (colorResource *) xalloc(sizeof(colorResource));
if (!pcr)
{
(void)FreeColors(pmap, client, 1, pPix, (Pixel)0);
return (BadAlloc);
}
pcr->mid = pmap->mid;
pcr->client = client;
if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
return (BadAlloc);
}
return (Success);
}
void
FakeAllocColor (pmap, item)
register ColormapPtr pmap;
register xColorItem *item;
{
Pixel pixR, pixG, pixB;
Pixel temp;
int entries;
xrgb rgb;
int class;
register VisualPtr pVisual;
pVisual = pmap->pVisual;
rgb.red = item->red;
rgb.green = item->green;
rgb.blue = item->blue;
(*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual);
class = pmap->class;
entries = pVisual->ColormapEntries;
switch (class) {
case GrayScale:
case PseudoColor:
item->pixel = 0;
if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP,
-1, AllComp) == Success) {
item->pixel = temp;
break;
}
case StaticColor:
case StaticGray:
item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
break;
case DirectColor:
pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed;
pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
-1, RedComp) != Success)
pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP)
<< pVisual->offsetRed;
if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
GREENMAP, -1, GreenComp) != Success)
pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb,
GREENMAP) << pVisual->offsetGreen;
if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
-1, BlueComp) != Success)
pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP)
<< pVisual->offsetBlue;
item->pixel = pixR | pixG | pixB;
break;
case TrueColor:
pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
item->pixel = (pixR << pVisual->offsetRed) |
(pixG << pVisual->offsetGreen) |
(pixB << pVisual->offsetBlue);
break;
}
}
void
FakeFreeColor(pmap, pixel)
register ColormapPtr pmap;
Pixel pixel;
{
register VisualPtr pVisual;
Pixel pixR, pixG, pixB;
switch (pmap->class) {
case GrayScale:
case PseudoColor:
if (pmap->red[pixel].refcnt == AllocTemporary)
pmap->red[pixel].refcnt = 0;
break;
case DirectColor:
pVisual = pmap->pVisual;
pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed;
pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
if (pmap->red[pixR].refcnt == AllocTemporary)
pmap->red[pixR].refcnt = 0;
if (pmap->green[pixG].refcnt == AllocTemporary)
pmap->green[pixG].refcnt = 0;
if (pmap->blue[pixB].refcnt == AllocTemporary)
pmap->blue[pixB].refcnt = 0;
break;
}
}
typedef unsigned short BigNumUpper;
typedef unsigned long BigNumLower;
#define BIGNUMLOWERBITS 24
#define BIGNUMUPPERBITS 16
#define BIGNUMLOWER (1 << BIGNUMLOWERBITS)
#define BIGNUMUPPER (1 << BIGNUMUPPERBITS)
#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS)
#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1))
typedef struct _bignum {
BigNumUpper upper;
BigNumLower lower;
} BigNumRec, *BigNumPtr;
#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\
((x)->upper == (y)->upper && (x)->lower > (y)->lower))
#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \
((r)->lower = LOWERPART(u)))
#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \
((r)->lower = BIGNUMLOWER-1))
static void
BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r)
{
BigNumLower lower, carry = 0;
lower = x->lower + y->lower;
if (lower >= BIGNUMLOWER) {
lower -= BIGNUMLOWER;
carry = 1;
}
r->lower = lower;
r->upper = x->upper + y->upper + carry;
}
static Pixel
FindBestPixel(pentFirst, size, prgb, channel)
EntryPtr pentFirst;
int size;
xrgb *prgb;
int channel;
{
EntryPtr pent;
Pixel pixel, final;
long dr, dg, db;
unsigned long sq;
BigNumRec minval, sum, temp;
final = 0;
MaxBigNum(&minval);
for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++)
{
dr = dg = db = 0;
switch(channel)
{
case PSEUDOMAP:
dg = (long) pent->co.local.green - prgb->green;
db = (long) pent->co.local.blue - prgb->blue;
case REDMAP:
dr = (long) pent->co.local.red - prgb->red;
break;
case GREENMAP:
dg = (long) pent->co.local.green - prgb->green;
break;
case BLUEMAP:
db = (long) pent->co.local.blue - prgb->blue;
break;
}
sq = dr * dr;
UnsignedToBigNum (sq, &sum);
sq = dg * dg;
UnsignedToBigNum (sq, &temp);
BigNumAdd (&sum, &temp, &sum);
sq = db * db;
UnsignedToBigNum (sq, &temp);
BigNumAdd (&sum, &temp, &sum);
if (BigNumGreater (&minval, &sum))
{
final = pixel;
minval = sum;
}
}
return(final);
}
static void
FindColorInRootCmap (pmap, pentFirst, size, prgb, pPixel, channel, comp)
ColormapPtr pmap;
EntryPtr pentFirst;
int size;
xrgb* prgb;
Pixel* pPixel;
int channel;
ColorCompareProcPtr comp;
{
EntryPtr pent;
Pixel pixel;
int count;
if ((pixel = *pPixel) >= size)
pixel = 0;
for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++)
{
if (pent->refcnt > 0 && (*comp) (pent, prgb))
{
switch (channel)
{
case REDMAP:
pixel <<= pmap->pVisual->offsetRed;
break;
case GREENMAP:
pixel <<= pmap->pVisual->offsetGreen;
break;
case BLUEMAP:
pixel <<= pmap->pVisual->offsetBlue;
break;
default:
break;
}
*pPixel = pixel;
}
}
}
int
FindColor (pmap, pentFirst, size, prgb, pPixel, channel, client, comp)
ColormapPtr pmap;
EntryPtr pentFirst;
int size;
xrgb *prgb;
Pixel *pPixel;
int channel;
int client;
ColorCompareProcPtr comp;
{
EntryPtr pent;
Bool foundFree;
Pixel pixel, Free = 0;
int npix, count, *nump = NULL;
Pixel **pixp = NULL, *ppix;
xColorItem def;
foundFree = FALSE;
if((pixel = *pPixel) >= size)
pixel = 0;
for (pent = pentFirst + pixel, count = size; --count >= 0; )
{
if (pent->refcnt > 0)
{
if ((*comp) (pent, prgb))
{
if (client >= 0)
pent->refcnt++;
*pPixel = pixel;
switch(channel)
{
case REDMAP:
*pPixel <<= pmap->pVisual->offsetRed;
case PSEUDOMAP:
break;
case GREENMAP:
*pPixel <<= pmap->pVisual->offsetGreen;
break;
case BLUEMAP:
*pPixel <<= pmap->pVisual->offsetBlue;
break;
}
goto gotit;
}
}
else if (!foundFree && pent->refcnt == 0)
{
Free = pixel;
foundFree = TRUE;
if(pmap->flags & BeingCreated)
break;
}
pixel++;
if(pixel >= size)
{
pent = pentFirst;
pixel = 0;
}
else
pent++;
}
if (!foundFree)
return (BadAlloc);
pent = pentFirst + Free;
pent->fShared = FALSE;
pent->refcnt = (client >= 0) ? 1 : AllocTemporary;
switch (channel)
{
case PSEUDOMAP:
pent->co.local.red = prgb->red;
pent->co.local.green = prgb->green;
pent->co.local.blue = prgb->blue;
def.red = prgb->red;
def.green = prgb->green;
def.blue = prgb->blue;
def.flags = (DoRed|DoGreen|DoBlue);
if (client >= 0)
pmap->freeRed--;
def.pixel = Free;
break;
case REDMAP:
pent->co.local.red = prgb->red;
def.red = prgb->red;
def.green = pmap->green[0].co.local.green;
def.blue = pmap->blue[0].co.local.blue;
def.flags = DoRed;
if (client >= 0)
pmap->freeRed--;
def.pixel = Free << pmap->pVisual->offsetRed;
break;
case GREENMAP:
pent->co.local.green = prgb->green;
def.red = pmap->red[0].co.local.red;
def.green = prgb->green;
def.blue = pmap->blue[0].co.local.blue;
def.flags = DoGreen;
if (client >= 0)
pmap->freeGreen--;
def.pixel = Free << pmap->pVisual->offsetGreen;
break;
case BLUEMAP:
pent->co.local.blue = prgb->blue;
def.red = pmap->red[0].co.local.red;
def.green = pmap->green[0].co.local.green;
def.blue = prgb->blue;
def.flags = DoBlue;
if (client >= 0)
pmap->freeBlue--;
def.pixel = Free << pmap->pVisual->offsetBlue;
break;
}
(*pmap->pScreen->StoreColors) (pmap, 1, &def);
pixel = Free;
*pPixel = def.pixel;
gotit:
if (pmap->flags & BeingCreated || client == -1)
return(Success);
switch (channel)
{
case PSEUDOMAP:
case REDMAP:
nump = pmap->numPixelsRed;
pixp = pmap->clientPixelsRed;
break;
case GREENMAP:
nump = pmap->numPixelsGreen;
pixp = pmap->clientPixelsGreen;
break;
case BLUEMAP:
nump = pmap->numPixelsBlue;
pixp = pmap->clientPixelsBlue;
break;
}
npix = nump[client];
ppix = (Pixel *) xrealloc (pixp[client], (npix + 1) * sizeof(Pixel));
if (!ppix)
{
pent->refcnt--;
if (!pent->fShared)
switch (channel)
{
case PSEUDOMAP:
case REDMAP:
pmap->freeRed++;
break;
case GREENMAP:
pmap->freeGreen++;
break;
case BLUEMAP:
pmap->freeBlue++;
break;
}
return(BadAlloc);
}
ppix[npix] = pixel;
pixp[client] = ppix;
nump[client]++;
return(Success);
}
static int
AllComp (pent, prgb)
EntryPtr pent;
xrgb *prgb;
{
if((pent->co.local.red == prgb->red) &&
(pent->co.local.green == prgb->green) &&
(pent->co.local.blue == prgb->blue) )
return (1);
return (0);
}
static int
RedComp (pent, prgb)
EntryPtr pent;
xrgb *prgb;
{
if (pent->co.local.red == prgb->red)
return (1);
return (0);
}
static int
GreenComp (pent, prgb)
EntryPtr pent;
xrgb *prgb;
{
if (pent->co.local.green == prgb->green)
return (1);
return (0);
}
static int
BlueComp (pent, prgb)
EntryPtr pent;
xrgb *prgb;
{
if (pent->co.local.blue == prgb->blue)
return (1);
return (0);
}
int
QueryColors (pmap, count, ppixIn, prgbList)
ColormapPtr pmap;
int count;
Pixel *ppixIn;
xrgb *prgbList;
{
Pixel *ppix, pixel;
xrgb *prgb;
VisualPtr pVisual;
EntryPtr pent;
Pixel i;
int errVal = Success;
pVisual = pmap->pVisual;
if ((pmap->class | DynamicClass) == DirectColor)
{
int numred, numgreen, numblue;
Pixel rgbbad;
numred = NUMRED(pVisual);
numgreen = NUMGREEN(pVisual);
numblue = NUMBLUE(pVisual);
rgbbad = ~RGBMASK(pVisual);
for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
{
pixel = *ppix;
if (pixel & rgbbad) {
clientErrorValue = pixel;
errVal = BadValue;
continue;
}
i = (pixel & pVisual->redMask) >> pVisual->offsetRed;
if (i >= numred)
{
clientErrorValue = pixel;
errVal = BadValue;
continue;
}
prgb->red = pmap->red[i].co.local.red;
i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
if (i >= numgreen)
{
clientErrorValue = pixel;
errVal = BadValue;
continue;
}
prgb->green = pmap->green[i].co.local.green;
i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
if (i >= numblue)
{
clientErrorValue = pixel;
errVal = BadValue;
continue;
}
prgb->blue = pmap->blue[i].co.local.blue;
}
}
else
{
for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
{
pixel = *ppix;
if (pixel >= pVisual->ColormapEntries)
{
clientErrorValue = pixel;
errVal = BadValue;
}
else
{
pent = (EntryPtr)&pmap->red[pixel];
if (pent->fShared)
{
prgb->red = pent->co.shco.red->color;
prgb->green = pent->co.shco.green->color;
prgb->blue = pent->co.shco.blue->color;
}
else
{
prgb->red = pent->co.local.red;
prgb->green = pent->co.local.green;
prgb->blue = pent->co.local.blue;
}
}
}
}
return (errVal);
}
static void
FreePixels(pmap, client)
register ColormapPtr pmap;
register int client;
{
register Pixel *ppix, *ppixStart;
register int n;
int class;
#ifdef LBX
Bool grabbed;
Bool zeroRefCount;
Bool anyRefCountReachedZero = 0;
#endif
class = pmap->class;
ppixStart = pmap->clientPixelsRed[client];
if (class & DynamicClass)
{
n = pmap->numPixelsRed[client];
#ifdef LBX
grabbed = LbxCheckCmapGrabbed (pmap);
if (grabbed)
{
LbxBeginFreeCellsEvent (pmap);
LbxSortPixelList (ppixStart, n);
}
#endif
for (ppix = ppixStart; --n >= 0; )
{
FreeCell(pmap, *ppix, REDMAP);
#ifdef LBX
zeroRefCount = pmap->red[*ppix].refcnt == 0;
if (zeroRefCount)
anyRefCountReachedZero = 1;
if (grabbed && zeroRefCount)
LbxAddFreeCellToEvent (pmap, *ppix);
#endif
ppix++;
}
#ifdef LBX
if (grabbed)
LbxEndFreeCellsEvent (pmap);
else if (anyRefCountReachedZero)
{
LbxDisableSmartGrab (pmap);
}
#endif
}
xfree(ppixStart);
pmap->clientPixelsRed[client] = (Pixel *) NULL;
pmap->numPixelsRed[client] = 0;
if ((class | DynamicClass) == DirectColor)
{
ppixStart = pmap->clientPixelsGreen[client];
if (class & DynamicClass)
for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;)
FreeCell(pmap, *ppix++, GREENMAP);
xfree(ppixStart);
pmap->clientPixelsGreen[client] = (Pixel *) NULL;
pmap->numPixelsGreen[client] = 0;
ppixStart = pmap->clientPixelsBlue[client];
if (class & DynamicClass)
for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; )
FreeCell(pmap, *ppix++, BLUEMAP);
xfree(ppixStart);
pmap->clientPixelsBlue[client] = (Pixel *) NULL;
pmap->numPixelsBlue[client] = 0;
}
}
int
FreeClientPixels (value, fakeid)
pointer value;
XID fakeid;
{
ColormapPtr pmap;
colorResource *pcr = (colorResource *)value;
pmap = (ColormapPtr) LookupIDByType(pcr->mid, RT_COLORMAP);
if (pmap)
FreePixels(pmap, pcr->client);
xfree(pcr);
return Success;
}
int
AllocColorCells (client, pmap, colors, planes, contig, ppix, masks)
int client;
ColormapPtr pmap;
int colors, planes;
Bool contig;
Pixel *ppix;
Pixel *masks;
{
Pixel rmask, gmask, bmask, *ppixFirst, r, g, b;
int n, class;
int ok;
int oldcount;
colorResource *pcr = (colorResource *)NULL;
class = pmap->class;
if (!(class & DynamicClass))
return (BadAlloc);
oldcount = pmap->numPixelsRed[client];
if (pmap->class == DirectColor)
oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
if (!oldcount && (CLIENT_ID(pmap->mid) != client))
{
pcr = (colorResource *) xalloc(sizeof(colorResource));
if (!pcr)
return (BadAlloc);
}
if (pmap->class == DirectColor)
{
ok = AllocDirect (client, pmap, colors, planes, planes, planes,
contig, ppix, &rmask, &gmask, &bmask);
if(ok == Success)
{
for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b)
{
while(!(rmask & r))
r += r;
while(!(gmask & g))
g += g;
while(!(bmask & b))
b += b;
*masks++ = r | g | b;
}
}
}
else
{
ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask,
&ppixFirst);
if(ok == Success)
{
for (r = 1, n = planes; --n >= 0; r += r)
{
while(!(rmask & r))
r += r;
*masks++ = r;
}
}
}
if ((ok == Success) && pcr)
{
pcr->mid = pmap->mid;
pcr->client = client;
if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
ok = BadAlloc;
} else if (pcr)
xfree(pcr);
return (ok);
}
int
AllocColorPlanes (client, pmap, colors, r, g, b, contig, pixels,
prmask, pgmask, pbmask)
int client;
ColormapPtr pmap;
int colors, r, g, b;
Bool contig;
Pixel *pixels;
Pixel *prmask, *pgmask, *pbmask;
{
int ok;
Pixel mask, *ppixFirst;
register Pixel shift;
register int i;
int class;
int oldcount;
colorResource *pcr = (colorResource *)NULL;
class = pmap->class;
if (!(class & DynamicClass))
return (BadAlloc);
oldcount = pmap->numPixelsRed[client];
if (class == DirectColor)
oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
if (!oldcount && (CLIENT_ID(pmap->mid) != client))
{
pcr = (colorResource *) xalloc(sizeof(colorResource));
if (!pcr)
return (BadAlloc);
}
if (class == DirectColor)
{
ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels,
prmask, pgmask, pbmask);
}
else
{
ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels,
&mask, &ppixFirst);
if(ok == Success)
{
*prmask = *pgmask = *pbmask = 0;
shift = 1;
for (i = r; --i >= 0; shift += shift)
{
while (!(mask & shift))
shift += shift;
*prmask |= shift;
}
for (i = g; --i >= 0; shift += shift)
{
while (!(mask & shift))
shift += shift;
*pgmask |= shift;
}
for (i = b; --i >= 0; shift += shift)
{
while (!(mask & shift))
shift += shift;
*pbmask |= shift;
}
if (!AllocShared(pmap, pixels, colors, r, g, b,
*prmask, *pgmask, *pbmask, ppixFirst))
{
(void)FreeColors(pmap, client, colors, pixels, mask);
ok = BadAlloc;
}
}
}
if ((ok == Success) && pcr)
{
pcr->mid = pmap->mid;
pcr->client = client;
if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
ok = BadAlloc;
} else if (pcr)
xfree(pcr);
return (ok);
}
static int
AllocDirect (client, pmap, c, r, g, b, contig, pixels, prmask, pgmask, pbmask)
int client;
ColormapPtr pmap;
int c, r, g, b;
Bool contig;
Pixel *pixels;
Pixel *prmask, *pgmask, *pbmask;
{
Pixel *ppixRed, *ppixGreen, *ppixBlue;
Pixel *ppix, *pDst, *p;
int npix, npixR, npixG, npixB;
Bool okR, okG, okB;
Pixel *rpix = 0, *gpix = 0, *bpix = 0;
npixR = c << r;
npixG = c << g;
npixB = c << b;
if ((r >= 32) || (g >= 32) || (b >= 32) ||
(npixR > pmap->freeRed) || (npixR < c) ||
(npixG > pmap->freeGreen) || (npixG < c) ||
(npixB > pmap->freeBlue) || (npixB < c))
return BadAlloc;
for(p = pixels; p < pixels + c; p++)
*p = 0;
ppixRed = (Pixel *)ALLOCATE_LOCAL(npixR * sizeof(Pixel));
ppixGreen = (Pixel *)ALLOCATE_LOCAL(npixG * sizeof(Pixel));
ppixBlue = (Pixel *)ALLOCATE_LOCAL(npixB * sizeof(Pixel));
if (!ppixRed || !ppixGreen || !ppixBlue)
{
if (ppixBlue) DEALLOCATE_LOCAL(ppixBlue);
if (ppixGreen) DEALLOCATE_LOCAL(ppixGreen);
if (ppixRed) DEALLOCATE_LOCAL(ppixRed);
return(BadAlloc);
}
okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask);
okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask);
okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask);
if (okR && okG && okB)
{
rpix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
(pmap->numPixelsRed[client] + (c << r)) *
sizeof(Pixel));
if (rpix)
pmap->clientPixelsRed[client] = rpix;
gpix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client],
(pmap->numPixelsGreen[client] + (c << g)) *
sizeof(Pixel));
if (gpix)
pmap->clientPixelsGreen[client] = gpix;
bpix = (Pixel *) xrealloc(pmap->clientPixelsBlue[client],
(pmap->numPixelsBlue[client] + (c << b)) *
sizeof(Pixel));
if (bpix)
pmap->clientPixelsBlue[client] = bpix;
}
if (!okR || !okG || !okB || !rpix || !gpix || !bpix)
{
if (okR)
for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++)
pmap->red[*ppix].refcnt = 0;
if (okG)
for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++)
pmap->green[*ppix].refcnt = 0;
if (okB)
for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++)
pmap->blue[*ppix].refcnt = 0;
DEALLOCATE_LOCAL(ppixBlue);
DEALLOCATE_LOCAL(ppixGreen);
DEALLOCATE_LOCAL(ppixRed);
return(BadAlloc);
}
*prmask <<= pmap->pVisual->offsetRed;
*pgmask <<= pmap->pVisual->offsetGreen;
*pbmask <<= pmap->pVisual->offsetBlue;
ppix = rpix + pmap->numPixelsRed[client];
for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++)
{
*ppix++ = *p;
if(p < ppixRed + c)
*pDst++ |= *p << pmap->pVisual->offsetRed;
}
pmap->numPixelsRed[client] += npixR;
pmap->freeRed -= npixR;
ppix = gpix + pmap->numPixelsGreen[client];
for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++)
{
*ppix++ = *p;
if(p < ppixGreen + c)
*pDst++ |= *p << pmap->pVisual->offsetGreen;
}
pmap->numPixelsGreen[client] += npixG;
pmap->freeGreen -= npixG;
ppix = bpix + pmap->numPixelsBlue[client];
for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++)
{
*ppix++ = *p;
if(p < ppixBlue + c)
*pDst++ |= *p << pmap->pVisual->offsetBlue;
}
pmap->numPixelsBlue[client] += npixB;
pmap->freeBlue -= npixB;
DEALLOCATE_LOCAL(ppixBlue);
DEALLOCATE_LOCAL(ppixGreen);
DEALLOCATE_LOCAL(ppixRed);
return (Success);
}
static int
AllocPseudo (client, pmap, c, r, contig, pixels, pmask, pppixFirst)
int client;
ColormapPtr pmap;
int c, r;
Bool contig;
Pixel *pixels;
Pixel *pmask;
Pixel **pppixFirst;
{
Pixel *ppix, *p, *pDst, *ppixTemp;
int npix;
Bool ok;
npix = c << r;
if ((r >= 32) || (npix > pmap->freeRed) || (npix < c))
return(BadAlloc);
if(!(ppixTemp = (Pixel *)ALLOCATE_LOCAL(npix * sizeof(Pixel))))
return(BadAlloc);
ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask);
if (ok)
{
ppix = (Pixel *)xrealloc(pmap->clientPixelsRed[client],
(pmap->numPixelsRed[client] + npix) * sizeof(Pixel));
if (!ppix)
{
for (p = ppixTemp; p < ppixTemp + npix; p++)
pmap->red[*p].refcnt = 0;
return (BadAlloc);
}
pmap->clientPixelsRed[client] = ppix;
ppix += pmap->numPixelsRed[client];
*pppixFirst = ppix;
pDst = pixels;
for (p = ppixTemp; p < ppixTemp + npix; p++)
{
*ppix++ = *p;
if(p < ppixTemp + c)
*pDst++ = *p;
}
pmap->numPixelsRed[client] += npix;
pmap->freeRed -= npix;
}
DEALLOCATE_LOCAL(ppixTemp);
return (ok ? Success : BadAlloc);
}
static Bool
AllocCP (pmap, pentFirst, count, planes, contig, pixels, pMask)
ColormapPtr pmap;
EntryPtr pentFirst;
int count, planes;
Bool contig;
Pixel *pixels, *pMask;
{
EntryPtr ent;
Pixel pixel, base, entries, maxp, save;
int dplanes, found;
Pixel *ppix;
Pixel mask;
Pixel finalmask;
dplanes = pmap->pVisual->nplanes;
if (planes == 0)
{
ppix = pixels;
ent = pentFirst;
pixel = 0;
while (--count >= 0)
{
while (ent->refcnt)
{
ent++;
pixel++;
}
ent->refcnt = AllocPrivate;
*ppix++ = pixel;
ent->fShared = FALSE;
}
*pMask = 0;
return (TRUE);
}
else if (planes > dplanes)
{
return (FALSE);
}
ent = pentFirst;
for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1);
--dplanes >= 0;
mask += mask, base += base)
{
ppix = pixels;
found = 0;
pixel = 0;
entries = pmap->pVisual->ColormapEntries - mask;
while (pixel < entries)
{
save = pixel;
maxp = pixel + mask + base;
while (pixel != maxp && ent[pixel].refcnt == 0)
pixel += base;
if (pixel == maxp)
{
*ppix++ = save;
found++;
if (found == count)
{
while (--count >= 0)
{
pixel = pixels[count];
maxp = pixel + mask;
while (1)
{
ent[pixel].refcnt = AllocPrivate;
ent[pixel].fShared = FALSE;
if (pixel == maxp)
break;
pixel += base;
*ppix++ = pixel;
}
}
*pMask = mask;
return (TRUE);
}
}
pixel = save + 1;
if (pixel & mask)
pixel += mask;
}
}
dplanes = pmap->pVisual->nplanes;
if (contig || planes == 1 || dplanes < 3)
return (FALSE);
finalmask =
(((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) +
(((Pixel)1)<<(dplanes-planes-1));
for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++)
{
pixel = (mask >> 1) & 033333333333;
pixel = mask - pixel - ((pixel >> 1) & 033333333333);
if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes)
continue;
ppix = pixels;
found = 0;
entries = pmap->pVisual->ColormapEntries - mask;
base = lowbit (mask);
for (pixel = 0; pixel < entries; pixel++)
{
if (pixel & mask)
continue;
maxp = 0;
while (ent[pixel + maxp].refcnt == 0)
{
GetNextBitsOrBreak(maxp, mask, base);
}
if ((maxp < mask) || (ent[pixel + mask].refcnt != 0))
continue;
*ppix++ = pixel;
found++;
if (found < count)
continue;
while (--count >= 0)
{
pixel = (pixels)[count];
maxp = 0;
while (1)
{
ent[pixel + maxp].refcnt = AllocPrivate;
ent[pixel + maxp].fShared = FALSE;
GetNextBitsOrBreak(maxp, mask, base);
*ppix++ = pixel + maxp;
}
}
*pMask = mask;
return (TRUE);
}
}
return (FALSE);
}
static Bool
AllocShared (pmap, ppix, c, r, g, b, rmask, gmask, bmask, ppixFirst)
ColormapPtr pmap;
Pixel *ppix;
int c, r, g, b;
Pixel rmask, gmask, bmask;
Pixel *ppixFirst;
{
Pixel *pptr, *cptr;
int npix, z, npixClientNew, npixShared;
Pixel basemask, base, bits, common;
SHAREDCOLOR *pshared, **ppshared, **psharedList;
npixClientNew = c << (r + g + b);
npixShared = (c << r) + (c << g) + (c << b);
psharedList = (SHAREDCOLOR **)ALLOCATE_LOCAL(npixShared *
sizeof(SHAREDCOLOR *));
if (!psharedList)
return FALSE;
ppshared = psharedList;
for (z = npixShared; --z >= 0; )
{
if (!(ppshared[z] = (SHAREDCOLOR *)xalloc(sizeof(SHAREDCOLOR))))
{
for (z++ ; z < npixShared; z++)
xfree(ppshared[z]);
return FALSE;
}
}
for(pptr = ppix, npix = c; --npix >= 0; pptr++)
{
basemask = ~(gmask | bmask);
common = *pptr & basemask;
if (rmask)
{
bits = 0;
base = lowbit (rmask);
while(1)
{
pshared = *ppshared++;
pshared->refcnt = 1 << (g + b);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == (common | bits))
{
pmap->red[*cptr].fShared = TRUE;
pmap->red[*cptr].co.shco.red = pshared;
}
}
GetNextBitsOrBreak(bits, rmask, base);
}
}
else
{
pshared = *ppshared++;
pshared->refcnt = 1 << (g + b);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == common)
{
pmap->red[*cptr].fShared = TRUE;
pmap->red[*cptr].co.shco.red = pshared;
}
}
}
basemask = ~(rmask | bmask);
common = *pptr & basemask;
if (gmask)
{
bits = 0;
base = lowbit (gmask);
while(1)
{
pshared = *ppshared++;
pshared->refcnt = 1 << (r + b);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == (common | bits))
{
pmap->red[*cptr].co.shco.green = pshared;
}
}
GetNextBitsOrBreak(bits, gmask, base);
}
}
else
{
pshared = *ppshared++;
pshared->refcnt = 1 << (g + b);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == common)
{
pmap->red[*cptr].co.shco.green = pshared;
}
}
}
basemask = ~(rmask | gmask);
common = *pptr & basemask;
if (bmask)
{
bits = 0;
base = lowbit (bmask);
while(1)
{
pshared = *ppshared++;
pshared->refcnt = 1 << (r + g);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == (common | bits))
{
pmap->red[*cptr].co.shco.blue = pshared;
}
}
GetNextBitsOrBreak(bits, bmask, base);
}
}
else
{
pshared = *ppshared++;
pshared->refcnt = 1 << (g + b);
for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
{
if ((*cptr & basemask) == common)
{
pmap->red[*cptr].co.shco.blue = pshared;
}
}
}
}
DEALLOCATE_LOCAL(psharedList);
return TRUE;
}
int
FreeColors (pmap, client, count, pixels, mask)
ColormapPtr pmap;
int client, count;
Pixel *pixels;
Pixel mask;
{
int rval, result, class;
Pixel rmask;
class = pmap->class;
if (pmap->flags & AllAllocated)
return(BadAccess);
if ((class | DynamicClass) == DirectColor)
{
rmask = mask & RGBMASK(pmap->pVisual);
result = FreeCo(pmap, client, REDMAP, count, pixels,
mask & pmap->pVisual->redMask);
rval = FreeCo(pmap, client, GREENMAP, count, pixels,
mask & pmap->pVisual->greenMask);
if(rval != Success)
result = rval;
rval = FreeCo(pmap, client, BLUEMAP, count, pixels,
mask & pmap->pVisual->blueMask);
if(rval != Success)
result = rval;
}
else
{
rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1);
result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask);
}
if ((mask != rmask) && count)
{
clientErrorValue = *pixels | mask;
result = BadValue;
}
return (result);
}
static int
FreeCo (pmap, client, color, npixIn, ppixIn, mask)
ColormapPtr pmap;
int client;
int color;
int npixIn;
Pixel *ppixIn;
Pixel mask;
{
Pixel *ppixClient, pixTest;
int npixClient, npixNew, npix;
Pixel bits, base, cmask, rgbbad;
Pixel *pptr, *cptr;
int n, zapped;
int errVal = Success;
int offset, numents;
#ifdef LBX
Bool grabbed;
Bool zeroRefCount;
Bool anyRefCountReachedZero = 0;
#endif
if (npixIn == 0)
return (errVal);
bits = 0;
zapped = 0;
base = lowbit (mask);
switch(color)
{
case REDMAP:
cmask = pmap->pVisual->redMask;
rgbbad = ~RGBMASK(pmap->pVisual);
offset = pmap->pVisual->offsetRed;
numents = (cmask >> offset) + 1;
ppixClient = pmap->clientPixelsRed[client];
npixClient = pmap->numPixelsRed[client];
break;
case GREENMAP:
cmask = pmap->pVisual->greenMask;
rgbbad = ~RGBMASK(pmap->pVisual);
offset = pmap->pVisual->offsetGreen;
numents = (cmask >> offset) + 1;
ppixClient = pmap->clientPixelsGreen[client];
npixClient = pmap->numPixelsGreen[client];
break;
case BLUEMAP:
cmask = pmap->pVisual->blueMask;
rgbbad = ~RGBMASK(pmap->pVisual);
offset = pmap->pVisual->offsetBlue;
numents = (cmask >> offset) + 1;
ppixClient = pmap->clientPixelsBlue[client];
npixClient = pmap->numPixelsBlue[client];
break;
default:
case PSEUDOMAP:
cmask = ~((Pixel)0);
rgbbad = 0;
offset = 0;
numents = pmap->pVisual->ColormapEntries;
ppixClient = pmap->clientPixelsRed[client];
npixClient = pmap->numPixelsRed[client];
break;
}
#ifdef LBX
grabbed = LbxCheckCmapGrabbed (pmap);
if (grabbed)
{
LbxBeginFreeCellsEvent (pmap);
LbxSortPixelList (ppixIn, npixIn);
}
#endif
while (1)
{
for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++)
{
pixTest = ((*pptr | bits) & cmask) >> offset;
if ((pixTest >= numents) || (*pptr & rgbbad))
{
clientErrorValue = *pptr | bits;
errVal = BadValue;
continue;
}
for (cptr = ppixClient, npix = npixClient;
--npix >= 0 && *cptr != pixTest;
cptr++) ;
if (npix >= 0)
{
if (pmap->class & DynamicClass)
{
FreeCell(pmap, pixTest, color);
#ifdef LBX
zeroRefCount = pmap->red[pixTest].refcnt == 0;
if (zeroRefCount)
anyRefCountReachedZero = 1;
if (grabbed && zeroRefCount)
LbxAddFreeCellToEvent (pmap, pixTest);
#endif
}
*cptr = ~((Pixel)0);
zapped++;
}
else
errVal = BadAccess;
}
GetNextBitsOrBreak(bits, mask, base);
}
#ifdef LBX
if (grabbed)
LbxEndFreeCellsEvent (pmap);
else if (anyRefCountReachedZero)
{
LbxDisableSmartGrab (pmap);
}
#endif
if (zapped)
{
npixNew = npixClient - zapped;
if (npixNew)
{
pptr = cptr = ppixClient;
for(npix = 0; npix < npixNew; cptr++)
{
if (*cptr != ~((Pixel)0))
{
*pptr++ = *cptr;
npix++;
}
}
pptr = (Pixel *)xrealloc(ppixClient, npixNew * sizeof(Pixel));
if (pptr)
ppixClient = pptr;
npixClient = npixNew;
}
else
{
npixClient = 0;
xfree(ppixClient);
ppixClient = (Pixel *)NULL;
}
switch(color)
{
case PSEUDOMAP:
case REDMAP:
pmap->clientPixelsRed[client] = ppixClient;
pmap->numPixelsRed[client] = npixClient;
break;
case GREENMAP:
pmap->clientPixelsGreen[client] = ppixClient;
pmap->numPixelsGreen[client] = npixClient;
break;
case BLUEMAP:
pmap->clientPixelsBlue[client] = ppixClient;
pmap->numPixelsBlue[client] = npixClient;
break;
}
}
return (errVal);
}
int
StoreColors (pmap, count, defs)
ColormapPtr pmap;
int count;
xColorItem *defs;
{
register Pixel pix;
register xColorItem *pdef;
register EntryPtr pent, pentT, pentLast;
register VisualPtr pVisual;
SHAREDCOLOR *pred, *pgreen, *pblue;
int n, ChgRed, ChgGreen, ChgBlue, idef;
int class, errVal = Success;
int ok;
class = pmap->class;
if(!(class & DynamicClass) && !(pmap->flags & BeingCreated))
{
return(BadAccess);
}
pVisual = pmap->pVisual;
idef = 0;
if((class | DynamicClass) == DirectColor)
{
int numred, numgreen, numblue;
Pixel rgbbad;
numred = NUMRED(pVisual);
numgreen = NUMGREEN(pVisual);
numblue = NUMBLUE(pVisual);
rgbbad = ~RGBMASK(pVisual);
for (pdef = defs, n = 0; n < count; pdef++, n++)
{
ok = TRUE;
(*pmap->pScreen->ResolveColor)
(&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
if (pdef->pixel & rgbbad)
{
errVal = BadValue;
clientErrorValue = pdef->pixel;
continue;
}
pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed;
if (pix >= numred)
{
errVal = BadValue;
ok = FALSE;
}
else if (pmap->red[pix].refcnt != AllocPrivate)
{
errVal = BadAccess;
ok = FALSE;
}
else if (pdef->flags & DoRed)
{
pmap->red[pix].co.local.red = pdef->red;
}
else
{
pdef->red = pmap->red[pix].co.local.red;
}
pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
if (pix >= numgreen)
{
errVal = BadValue;
ok = FALSE;
}
else if (pmap->green[pix].refcnt != AllocPrivate)
{
errVal = BadAccess;
ok = FALSE;
}
else if (pdef->flags & DoGreen)
{
pmap->green[pix].co.local.green = pdef->green;
}
else
{
pdef->green = pmap->green[pix].co.local.green;
}
pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
if (pix >= numblue)
{
errVal = BadValue;
ok = FALSE;
}
else if (pmap->blue[pix].refcnt != AllocPrivate)
{
errVal = BadAccess;
ok = FALSE;
}
else if (pdef->flags & DoBlue)
{
pmap->blue[pix].co.local.blue = pdef->blue;
}
else
{
pdef->blue = pmap->blue[pix].co.local.blue;
}
if(ok)
{
if(idef != n)
defs[idef] = defs[n];
idef++;
} else
clientErrorValue = pdef->pixel;
}
}
else
{
for (pdef = defs, n = 0; n < count; pdef++, n++)
{
ok = TRUE;
if (pdef->pixel >= pVisual->ColormapEntries)
{
clientErrorValue = pdef->pixel;
errVal = BadValue;
ok = FALSE;
}
else if (pmap->red[pdef->pixel].refcnt != AllocPrivate)
{
errVal = BadAccess;
ok = FALSE;
}
if(ok)
{
if(idef != n)
defs[idef] = defs[n];
idef++;
}
else
continue;
(*pmap->pScreen->ResolveColor)
(&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
pent = &pmap->red[pdef->pixel];
if(pdef->flags & DoRed)
{
if(pent->fShared)
{
pent->co.shco.red->color = pdef->red;
if (pent->co.shco.red->refcnt > 1)
ok = FALSE;
}
else
pent->co.local.red = pdef->red;
}
else
{
if(pent->fShared)
pdef->red = pent->co.shco.red->color;
else
pdef->red = pent->co.local.red;
}
if(pdef->flags & DoGreen)
{
if(pent->fShared)
{
pent->co.shco.green->color = pdef->green;
if (pent->co.shco.green->refcnt > 1)
ok = FALSE;
}
else
pent->co.local.green = pdef->green;
}
else
{
if(pent->fShared)
pdef->green = pent->co.shco.green->color;
else
pdef->green = pent->co.local.green;
}
if(pdef->flags & DoBlue)
{
if(pent->fShared)
{
pent->co.shco.blue->color = pdef->blue;
if (pent->co.shco.blue->refcnt > 1)
ok = FALSE;
}
else
pent->co.local.blue = pdef->blue;
}
else
{
if(pent->fShared)
pdef->blue = pent->co.shco.blue->color;
else
pdef->blue = pent->co.local.blue;
}
if(!ok)
{
pred = pent->co.shco.red;
pgreen = pent->co.shco.green;
pblue = pent->co.shco.blue;
ChgRed = pdef->flags & DoRed;
ChgGreen = pdef->flags & DoGreen;
ChgBlue = pdef->flags & DoBlue;
pentLast = pmap->red + pVisual->ColormapEntries;
for(pentT = pmap->red; pentT < pentLast; pentT++)
{
if(pentT->fShared && (pentT != pent))
{
xColorItem defChg;
defChg.flags = 0;
if(ChgRed && pentT->co.shco.red == pred)
{
defChg.flags |= DoRed;
}
if(ChgGreen && pentT->co.shco.green == pgreen)
{
defChg.flags |= DoGreen;
}
if(ChgBlue && pentT->co.shco.blue == pblue)
{
defChg.flags |= DoBlue;
}
if(defChg.flags != 0)
{
defChg.pixel = pentT - pmap->red;
defChg.red = pentT->co.shco.red->color;
defChg.green = pentT->co.shco.green->color;
defChg.blue = pentT->co.shco.blue->color;
(*pmap->pScreen->StoreColors) (pmap, 1, &defChg);
}
}
}
}
}
}
if (idef != 0)
( *pmap->pScreen->StoreColors) (pmap, idef, defs);
return (errVal);
}
int
IsMapInstalled(map, pWin)
Colormap map;
WindowPtr pWin;
{
Colormap *pmaps;
int imap, nummaps, found;
pmaps = (Colormap *) ALLOCATE_LOCAL(
pWin->drawable.pScreen->maxInstalledCmaps * sizeof(Colormap));
if(!pmaps)
return(FALSE);
nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
(pWin->drawable.pScreen, pmaps);
found = FALSE;
for(imap = 0; imap < nummaps; imap++)
{
if(pmaps[imap] == map)
{
found = TRUE;
break;
}
}
DEALLOCATE_LOCAL(pmaps);
return (found);
}