1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48
49#ifdef HAVE_DIX_CONFIG_H
50#include <dix-config.h>
51#endif
52
53#include <X11/X.h>
54#include <X11/Xproto.h>
55#include <stdio.h>
56#include <string.h>
57#include <strings.h>
58#include "misc.h"
59#include "dix.h"
60#include "dixstruct.h"
61#include "colormapst.h"
62#include "os.h"
63#include "scrnintstr.h"
64#include "resource.h"
65#include "windowstr.h"
66#include "privates.h"
67#include "xace.h"
68
69static Pixel FindBestPixel(
70    EntryPtr /*pentFirst*/,
71    int /*size*/,
72    xrgb * /*prgb*/,
73    int /*channel*/
74);
75
76static int AllComp(
77    EntryPtr /*pent*/,
78    xrgb * /*prgb*/
79);
80
81static int RedComp(
82    EntryPtr /*pent*/,
83    xrgb * /*prgb*/
84);
85
86static int GreenComp(
87    EntryPtr /*pent*/,
88    xrgb * /*prgb*/
89);
90
91static int BlueComp(
92    EntryPtr /*pent*/,
93    xrgb * /*prgb*/
94);
95
96static void FreePixels(
97    ColormapPtr /*pmap*/,
98    int /*client*/
99);
100
101static void CopyFree(
102    int /*channel*/,
103    int /*client*/,
104    ColormapPtr /*pmapSrc*/,
105    ColormapPtr /*pmapDst*/
106);
107
108static void FreeCell(
109    ColormapPtr /*pmap*/,
110    Pixel /*i*/,
111    int /*channel*/
112);
113
114static void UpdateColors(
115    ColormapPtr /*pmap*/
116);
117
118static int AllocDirect(
119    int /*client*/,
120    ColormapPtr /*pmap*/,
121    int /*c*/,
122    int /*r*/,
123    int /*g*/,
124    int /*b*/,
125    Bool /*contig*/,
126    Pixel * /*pixels*/,
127    Pixel * /*prmask*/,
128    Pixel * /*pgmask*/,
129    Pixel * /*pbmask*/
130);
131
132static int AllocPseudo(
133    int /*client*/,
134    ColormapPtr /*pmap*/,
135    int /*c*/,
136    int /*r*/,
137    Bool /*contig*/,
138    Pixel * /*pixels*/,
139    Pixel * /*pmask*/,
140    Pixel ** /*pppixFirst*/
141);
142
143static Bool AllocCP(
144    ColormapPtr /*pmap*/,
145    EntryPtr /*pentFirst*/,
146    int /*count*/,
147    int /*planes*/,
148    Bool /*contig*/,
149    Pixel * /*pixels*/,
150    Pixel * /*pMask*/
151);
152
153static Bool AllocShared(
154    ColormapPtr /*pmap*/,
155    Pixel * /*ppix*/,
156    int /*c*/,
157    int /*r*/,
158    int /*g*/,
159    int /*b*/,
160    Pixel /*rmask*/,
161    Pixel /*gmask*/,
162    Pixel /*bmask*/,
163    Pixel * /*ppixFirst*/
164);
165
166static int FreeCo(
167    ColormapPtr /*pmap*/,
168    int /*client*/,
169    int /*color*/,
170    int /*npixIn*/,
171    Pixel * /*ppixIn*/,
172    Pixel /*mask*/
173);
174
175static int   TellNoMap(
176    WindowPtr	/*pwin*/,
177    Colormap 	* /*pmid*/
178);
179
180static void FindColorInRootCmap (
181    ColormapPtr	/* pmap */,
182    EntryPtr	/* pentFirst */,
183    int		/* size */,
184    xrgb*	/* prgb */,
185    Pixel*	/* pPixel */,
186    int		/* channel */,
187    ColorCompareProcPtr /* comp */
188);
189
190#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1)
191#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1)
192#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1)
193#if COMPOSITE
194#define ALPHAMASK(vis)	((vis)->nplanes < 32 ? 0 : \
195			 (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask))
196#else
197#define ALPHAMASK(vis)	0
198#endif
199
200#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis))
201
202/* GetNextBitsOrBreak(bits, mask, base)  --
203 * (Suggestion: First read the macro, then read this explanation.
204 *
205 * Either generate the next value to OR in to a pixel or break out of this
206 * while loop
207 *
208 * This macro is used when we're trying to generate all 2^n combinations of
209 * bits in mask.  What we're doing here is counting in binary, except that
210 * the bits we use to count may not be contiguous.  This macro will be
211 * called 2^n times, returning a different value in bits each time. Then
212 * it will cause us to break out of a surrounding loop. (It will always be
213 * called from within a while loop.)
214 * On call: mask is the value we want to find all the combinations for
215 * base has 1 bit set where the least significant bit of mask is set
216 *
217 * For example,if mask is 01010, base should be 0010 and we count like this:
218 * 00010 (see this isn't so hard),
219 *     then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so
220 *      we add that to bits getting (0100 + 0100) =
221 * 01000 for our next value.
222 *      then we add 0010 to get
223 * 01010 and we're done (easy as 1, 2, 3)
224 */
225#define GetNextBitsOrBreak(bits, mask, base)	\
226	    if((bits) == (mask)) 		\
227		break;		 		\
228	    (bits) += (base);		 	\
229	    while((bits) & ~(mask))		\
230		(bits) += ((bits) & ~(mask));
231/* ID of server as client */
232#define SERVER_ID	0
233
234typedef struct _colorResource
235{
236	Colormap	mid;
237	int		client;
238} colorResource;
239
240/* Invariants:
241 * refcnt == 0 means entry is empty
242 * refcnt > 0 means entry is useable by many clients, so it can't be changed
243 * refcnt == AllocPrivate means entry owned by one client only
244 * fShared should only be set if refcnt == AllocPrivate, and only in red map
245 */
246
247
248/**
249 * Create and initialize the color map
250 *
251 * \param mid    resource to use for this colormap
252 * \param alloc  1 iff all entries are allocated writable
253 */
254int
255CreateColormap (Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
256                ColormapPtr *ppcmap, int alloc, int client)
257{
258    int		class, size;
259    unsigned long sizebytes;
260    ColormapPtr	pmap;
261    EntryPtr	pent;
262    int		i;
263    Pixel	*ppix, **pptr;
264
265    class = pVisual->class;
266    if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID))
267	return BadMatch;
268
269    size = pVisual->ColormapEntries;
270    sizebytes = (size * sizeof(Entry)) +
271		(MAXCLIENTS * sizeof(Pixel *)) +
272		(MAXCLIENTS * sizeof(int));
273    if ((class | DynamicClass) == DirectColor)
274	sizebytes *= 3;
275    sizebytes += sizeof(ColormapRec);
276    if (mid == pScreen->defColormap) {
277	pmap = malloc(sizebytes);
278	if (!pmap)
279	    return BadAlloc;
280	if (!dixAllocatePrivates(&pmap->devPrivates, PRIVATE_COLORMAP)) {
281	    free (pmap);
282	    return BadAlloc;
283	}
284    } else {
285	pmap = _dixAllocateObjectWithPrivates(sizebytes, sizebytes,
286					      offsetof(ColormapRec, devPrivates), PRIVATE_COLORMAP);
287	if (!pmap)
288	    return BadAlloc;
289    }
290#if defined(_XSERVER64)
291    pmap->pad0 = 0;
292    pmap->pad1 = 0;
293#if (X_BYTE_ORDER == X_LITTLE_ENDIAN)
294    pmap->pad2 = 0;
295#endif
296#endif
297    pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec));
298    sizebytes = size * sizeof(Entry);
299    pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes);
300    pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed +
301				 (MAXCLIENTS * sizeof(Pixel *)));
302    pmap->mid = mid;
303    pmap->flags = 0; 	/* start out with all flags clear */
304    if(mid == pScreen->defColormap)
305	pmap->flags |= IsDefault;
306    pmap->pScreen = pScreen;
307    pmap->pVisual = pVisual;
308    pmap->class = class;
309    if ((class | DynamicClass) == DirectColor)
310	size = NUMRED(pVisual);
311    pmap->freeRed = size;
312    memset((char *) pmap->red, 0, (int)sizebytes);
313    memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int));
314    for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; )
315	*pptr = (Pixel *)NULL;
316    if (alloc == AllocAll)
317    {
318	if (class & DynamicClass)
319	    pmap->flags |= AllAllocated;
320	for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--)
321	    pent->refcnt = AllocPrivate;
322	pmap->freeRed = 0;
323	ppix = malloc(size * sizeof(Pixel));
324	if (!ppix)
325	{
326	    free(pmap);
327	    return BadAlloc;
328	}
329	pmap->clientPixelsRed[client] = ppix;
330	for(i = 0; i < size; i++)
331	    ppix[i] = i;
332	pmap->numPixelsRed[client] = size;
333    }
334
335    if ((class | DynamicClass) == DirectColor)
336    {
337	pmap->freeGreen = NUMGREEN(pVisual);
338	pmap->green = (EntryPtr)((char *)pmap->numPixelsRed +
339				 (MAXCLIENTS * sizeof(int)));
340	pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes);
341	pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen +
342				       (MAXCLIENTS * sizeof(Pixel *)));
343	pmap->freeBlue = NUMBLUE(pVisual);
344	pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen +
345				(MAXCLIENTS * sizeof(int)));
346	pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes);
347	pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue +
348				      (MAXCLIENTS * sizeof(Pixel *)));
349
350	memset((char *) pmap->green, 0, (int)sizebytes);
351	memset((char *) pmap->blue, 0, (int)sizebytes);
352
353	memmove((char *) pmap->clientPixelsGreen,
354		(char *) pmap->clientPixelsRed,
355	      MAXCLIENTS * sizeof(Pixel *));
356	memmove((char *) pmap->clientPixelsBlue,
357		(char *) pmap->clientPixelsRed,
358	      MAXCLIENTS * sizeof(Pixel *));
359	memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int));
360	memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int));
361
362	/* If every cell is allocated, mark its refcnt */
363	if (alloc == AllocAll)
364	{
365	    size = pmap->freeGreen;
366	    for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--)
367		pent->refcnt = AllocPrivate;
368	    pmap->freeGreen = 0;
369	    ppix = malloc(size * sizeof(Pixel));
370	    if (!ppix)
371	    {
372		free(pmap->clientPixelsRed[client]);
373		free(pmap);
374		return BadAlloc;
375	    }
376	    pmap->clientPixelsGreen[client] = ppix;
377	    for(i = 0; i < size; i++)
378		ppix[i] = i;
379	    pmap->numPixelsGreen[client] = size;
380
381	    size = pmap->freeBlue;
382	    for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--)
383		pent->refcnt = AllocPrivate;
384	    pmap->freeBlue = 0;
385	    ppix = malloc(size * sizeof(Pixel));
386	    if (!ppix)
387	    {
388		free(pmap->clientPixelsGreen[client]);
389		free(pmap->clientPixelsRed[client]);
390		free(pmap);
391		return BadAlloc;
392	    }
393	    pmap->clientPixelsBlue[client] = ppix;
394	    for(i = 0; i < size; i++)
395		ppix[i] = i;
396	    pmap->numPixelsBlue[client] = size;
397	}
398    }
399    pmap->flags |= BeingCreated;
400
401    if (!AddResource(mid, RT_COLORMAP, (pointer)pmap))
402	return BadAlloc;
403
404    /*
405     * Security creation/labeling check
406     */
407    i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP,
408		 pmap, RT_NONE, NULL, DixCreateAccess);
409    if (i != Success) {
410	FreeResource(mid, RT_NONE);
411	return i;
412    }
413
414    /* If the device wants a chance to initialize the colormap in any way,
415     * this is it.  In specific, if this is a Static colormap, this is the
416     * time to fill in the colormap's values */
417    if (!(*pScreen->CreateColormap)(pmap))
418    {
419	FreeResource (mid, RT_NONE);
420	return BadAlloc;
421    }
422    pmap->flags &= ~BeingCreated;
423    *ppcmap = pmap;
424    return Success;
425}
426
427/**
428 *
429 * \param value  must conform to DeleteType
430 */
431int
432FreeColormap (pointer value, XID mid)
433{
434    int	i;
435    EntryPtr pent;
436    ColormapPtr	pmap = (ColormapPtr)value;
437
438    if(CLIENT_ID(mid) != SERVER_ID)
439    {
440        (*pmap->pScreen->UninstallColormap) (pmap);
441        WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid);
442    }
443
444    /* This is the device's chance to undo anything it needs to, especially
445     * to free any storage it allocated */
446    (*pmap->pScreen->DestroyColormap)(pmap);
447
448    if(pmap->clientPixelsRed)
449    {
450	for(i = 0; i < MAXCLIENTS; i++)
451	    free(pmap->clientPixelsRed[i]);
452    }
453
454    if ((pmap->class == PseudoColor) || (pmap->class == GrayScale))
455    {
456	for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1];
457	    pent >= pmap->red;
458	    pent--)
459	{
460	    if(pent->fShared)
461	    {
462		if (--pent->co.shco.red->refcnt == 0)
463		    free(pent->co.shco.red);
464		if (--pent->co.shco.green->refcnt == 0)
465		    free(pent->co.shco.green);
466		if (--pent->co.shco.blue->refcnt == 0)
467		    free(pent->co.shco.blue);
468	    }
469	}
470    }
471    if((pmap->class | DynamicClass) == DirectColor)
472    {
473        for(i = 0; i < MAXCLIENTS; i++)
474	{
475            free(pmap->clientPixelsGreen[i]);
476            free(pmap->clientPixelsBlue[i]);
477        }
478    }
479
480    if (pmap->flags & IsDefault) {
481	dixFreePrivates(pmap->devPrivates, PRIVATE_COLORMAP);
482	free(pmap);
483    } else
484	dixFreeObjectWithPrivates(pmap, PRIVATE_COLORMAP);
485    return Success;
486}
487
488/* Tell window that pmid has disappeared */
489static int
490TellNoMap (WindowPtr pwin, Colormap *pmid)
491{
492    xEvent 	xE;
493
494    if (wColormap(pwin) == *pmid)
495    {
496	/* This should be call to DeliverEvent */
497	xE.u.u.type = ColormapNotify;
498	xE.u.colormap.window = pwin->drawable.id;
499	xE.u.colormap.colormap = None;
500	xE.u.colormap.new = TRUE;
501	xE.u.colormap.state = ColormapUninstalled;
502#ifdef PANORAMIX
503        if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum)
504#endif
505	   DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
506	if (pwin->optional) {
507	    pwin->optional->colormap = None;
508	    CheckWindowOptionalNeed (pwin);
509	}
510    }
511
512    return WT_WALKCHILDREN;
513}
514
515/* Tell window that pmid got uninstalled */
516int
517TellLostMap (WindowPtr pwin, pointer value)
518{
519    Colormap 	*pmid = (Colormap *)value;
520    xEvent 	xE;
521
522#ifdef PANORAMIX
523    if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
524	return WT_STOPWALKING;
525#endif
526    if (wColormap(pwin) == *pmid)
527    {
528	/* This should be call to DeliverEvent */
529	xE.u.u.type = ColormapNotify;
530	xE.u.colormap.window = pwin->drawable.id;
531	xE.u.colormap.colormap = *pmid;
532	xE.u.colormap.new = FALSE;
533	xE.u.colormap.state = ColormapUninstalled;
534	DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
535    }
536
537    return WT_WALKCHILDREN;
538}
539
540/* Tell window that pmid got installed */
541int
542TellGainedMap (WindowPtr pwin, pointer value)
543{
544    Colormap 	*pmid = (Colormap *)value;
545    xEvent 	xE;
546
547#ifdef PANORAMIX
548    if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
549	return WT_STOPWALKING;
550#endif
551    if (wColormap (pwin) == *pmid)
552    {
553	/* This should be call to DeliverEvent */
554	xE.u.u.type = ColormapNotify;
555	xE.u.colormap.window = pwin->drawable.id;
556	xE.u.colormap.colormap = *pmid;
557	xE.u.colormap.new = FALSE;
558	xE.u.colormap.state = ColormapInstalled;
559	DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
560    }
561
562    return WT_WALKCHILDREN;
563}
564
565
566int
567CopyColormapAndFree (Colormap mid, ColormapPtr pSrc, int client)
568{
569    ColormapPtr	pmap = (ColormapPtr) NULL;
570    int		result, alloc, size;
571    Colormap	midSrc;
572    ScreenPtr	pScreen;
573    VisualPtr	pVisual;
574
575    pScreen = pSrc->pScreen;
576    pVisual = pSrc->pVisual;
577    midSrc = pSrc->mid;
578    alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ?
579            AllocAll : AllocNone;
580    size = pVisual->ColormapEntries;
581
582    /* If the create returns non-0, it failed */
583    result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client);
584    if(result != Success)
585        return result;
586    if(alloc == AllocAll)
587    {
588	memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry));
589	if((pmap->class | DynamicClass) == DirectColor)
590	{
591	    memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry));
592	    memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry));
593	}
594	pSrc->flags &= ~AllAllocated;
595	FreePixels(pSrc, client);
596	UpdateColors(pmap);
597	return Success;
598    }
599
600    CopyFree(REDMAP, client, pSrc, pmap);
601    if ((pmap->class | DynamicClass) == DirectColor)
602    {
603	CopyFree(GREENMAP, client, pSrc, pmap);
604	CopyFree(BLUEMAP, client, pSrc, pmap);
605    }
606    if (pmap->class & DynamicClass)
607	UpdateColors(pmap);
608    /* XXX should worry about removing any RT_CMAPENTRY resource */
609    return Success;
610}
611
612/* Helper routine for freeing large numbers of cells from a map */
613static void
614CopyFree (int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst)
615{
616    int		z, npix;
617    EntryPtr	pentSrcFirst, pentDstFirst;
618    EntryPtr	pentSrc, pentDst;
619    Pixel	*ppix;
620    int		nalloc;
621
622    switch(channel)
623    {
624      default:	/* so compiler can see that everything gets initialized */
625      case REDMAP:
626	ppix = (pmapSrc->clientPixelsRed)[client];
627	npix = (pmapSrc->numPixelsRed)[client];
628	pentSrcFirst = pmapSrc->red;
629	pentDstFirst = pmapDst->red;
630	break;
631      case GREENMAP:
632	ppix = (pmapSrc->clientPixelsGreen)[client];
633	npix = (pmapSrc->numPixelsGreen)[client];
634	pentSrcFirst = pmapSrc->green;
635	pentDstFirst = pmapDst->green;
636	break;
637      case BLUEMAP:
638	ppix = (pmapSrc->clientPixelsBlue)[client];
639	npix = (pmapSrc->numPixelsBlue)[client];
640	pentSrcFirst = pmapSrc->blue;
641	pentDstFirst = pmapDst->blue;
642	break;
643    }
644    nalloc = 0;
645    if (pmapSrc->class & DynamicClass)
646    {
647	for(z = npix; --z >= 0; ppix++)
648	{
649	    /* Copy entries */
650	    pentSrc = pentSrcFirst + *ppix;
651	    pentDst = pentDstFirst + *ppix;
652	    if (pentDst->refcnt > 0)
653	    {
654		pentDst->refcnt++;
655	    }
656	    else
657	    {
658		*pentDst = *pentSrc;
659		nalloc++;
660		if (pentSrc->refcnt > 0)
661		    pentDst->refcnt = 1;
662		else
663		    pentSrc->fShared = FALSE;
664	    }
665	    FreeCell(pmapSrc, *ppix, channel);
666	}
667    }
668
669    /* Note that FreeCell has already fixed pmapSrc->free{Color} */
670    switch(channel)
671    {
672      case REDMAP:
673        pmapDst->freeRed -= nalloc;
674        (pmapDst->clientPixelsRed)[client] =
675	    (pmapSrc->clientPixelsRed)[client];
676        (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL;
677        (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client];
678        (pmapSrc->numPixelsRed)[client] = 0;
679	break;
680      case GREENMAP:
681        pmapDst->freeGreen -= nalloc;
682        (pmapDst->clientPixelsGreen)[client] =
683	    (pmapSrc->clientPixelsGreen)[client];
684        (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL;
685        (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client];
686        (pmapSrc->numPixelsGreen)[client] = 0;
687	break;
688      case BLUEMAP:
689        pmapDst->freeBlue -= nalloc;
690        pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client];
691        pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL;
692        pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client];
693        pmapSrc->numPixelsBlue[client] = 0;
694	break;
695    }
696}
697
698/* Free the ith entry in a color map.  Must handle freeing of
699 * colors allocated through AllocColorPlanes */
700static void
701FreeCell (ColormapPtr pmap, Pixel i, int channel)
702{
703    EntryPtr pent;
704    int	*pCount;
705
706
707    switch (channel)
708    {
709      default:	/* so compiler can see that everything gets initialized */
710      case PSEUDOMAP:
711      case REDMAP:
712          pent = (EntryPtr) &pmap->red[i];
713	  pCount = &pmap->freeRed;
714	  break;
715      case GREENMAP:
716          pent = (EntryPtr) &pmap->green[i];
717	  pCount = &pmap->freeGreen;
718	  break;
719      case BLUEMAP:
720          pent = (EntryPtr) &pmap->blue[i];
721	  pCount = &pmap->freeBlue;
722	  break;
723    }
724    /* If it's not privately allocated and it's not time to free it, just
725     * decrement the count */
726    if (pent->refcnt > 1)
727	pent->refcnt--;
728    else
729    {
730        /* If the color type is shared, find the sharedcolor. If decremented
731         * refcnt is 0, free the shared cell. */
732        if (pent->fShared)
733	{
734	    if(--pent->co.shco.red->refcnt == 0)
735		free(pent->co.shco.red);
736	    if(--pent->co.shco.green->refcnt == 0)
737		free(pent->co.shco.green);
738	    if(--pent->co.shco.blue->refcnt == 0)
739		free(pent->co.shco.blue);
740	    pent->fShared = FALSE;
741	}
742	pent->refcnt = 0;
743	*pCount += 1;
744    }
745}
746
747static void
748UpdateColors (ColormapPtr pmap)
749{
750    xColorItem		*defs;
751    xColorItem *pdef;
752    EntryPtr 	pent;
753    VisualPtr	pVisual;
754    int			i, n, size;
755
756    pVisual = pmap->pVisual;
757    size = pVisual->ColormapEntries;
758    defs = malloc(size * sizeof(xColorItem));
759    if (!defs)
760	return;
761    n = 0;
762    pdef = defs;
763    if (pmap->class == DirectColor)
764    {
765        for (i = 0; i < size; i++)
766	{
767	    if (!pmap->red[i].refcnt &&
768		!pmap->green[i].refcnt &&
769		!pmap->blue[i].refcnt)
770		continue;
771	    pdef->pixel = ((Pixel)i << pVisual->offsetRed) |
772			  ((Pixel)i << pVisual->offsetGreen) |
773			  ((Pixel)i << pVisual->offsetBlue);
774	    pdef->red = pmap->red[i].co.local.red;
775	    pdef->green = pmap->green[i].co.local.green;
776	    pdef->blue = pmap->blue[i].co.local.blue;
777	    pdef->flags = DoRed|DoGreen|DoBlue;
778	    pdef++;
779	    n++;
780	}
781    }
782    else
783    {
784        for (i = 0, pent = pmap->red; i < size; i++, pent++)
785	{
786	    if (!pent->refcnt)
787		continue;
788	    pdef->pixel = i;
789	    if(pent->fShared)
790	    {
791		pdef->red = pent->co.shco.red->color;
792		pdef->green = pent->co.shco.green->color;
793		pdef->blue = pent->co.shco.blue->color;
794	    }
795	    else
796	    {
797		pdef->red = pent->co.local.red;
798		pdef->green = pent->co.local.green;
799		pdef->blue = pent->co.local.blue;
800	    }
801	    pdef->flags = DoRed|DoGreen|DoBlue;
802	    pdef++;
803	    n++;
804	}
805    }
806    if (n)
807	(*pmap->pScreen->StoreColors)(pmap, n, defs);
808    free(defs);
809}
810
811/* Get a read-only color from a ColorMap (probably slow for large maps)
812 * Returns by changing the value in pred, pgreen, pblue and pPix
813 */
814int
815AllocColor (ColormapPtr pmap,
816            unsigned short *pred, unsigned short *pgreen, unsigned short *pblue,
817            Pixel *pPix, int client)
818{
819    Pixel	pixR, pixG, pixB;
820    int		entries;
821    xrgb	rgb;
822    int		class;
823    VisualPtr	pVisual;
824    int		npix;
825    Pixel	*ppix;
826
827    pVisual = pmap->pVisual;
828    (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual);
829    rgb.red = *pred;
830    rgb.green = *pgreen;
831    rgb.blue = *pblue;
832    class = pmap->class;
833    entries = pVisual->ColormapEntries;
834
835    /* If the colormap is being created, then we want to be able to change
836     * the colormap, even if it's a static type. Otherwise, we'd never be
837     * able to initialize static colormaps
838     */
839    if(pmap->flags & BeingCreated)
840	class |= DynamicClass;
841
842    /* If this is one of the static storage classes, and we're not initializing
843     * it, the best we can do is to find the closest color entry to the
844     * requested one and return that.
845     */
846    switch (class) {
847    case StaticColor:
848    case StaticGray:
849	/* Look up all three components in the same pmap */
850	*pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
851	*pred = pmap->red[pixR].co.local.red;
852	*pgreen = pmap->red[pixR].co.local.green;
853	*pblue = pmap->red[pixR].co.local.blue;
854	npix = pmap->numPixelsRed[client];
855	ppix = (Pixel *) realloc(pmap->clientPixelsRed[client],
856				  (npix + 1) * sizeof(Pixel));
857	if (!ppix)
858	    return BadAlloc;
859	ppix[npix] = pixR;
860	pmap->clientPixelsRed[client] = ppix;
861	pmap->numPixelsRed[client]++;
862	break;
863
864    case TrueColor:
865	/* Look up each component in its own map, then OR them together */
866	pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
867	pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
868	pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
869	*pPix = (pixR << pVisual->offsetRed) |
870		(pixG << pVisual->offsetGreen) |
871		(pixB << pVisual->offsetBlue) |
872		ALPHAMASK(pVisual);
873
874	*pred = pmap->red[pixR].co.local.red;
875	*pgreen = pmap->green[pixG].co.local.green;
876	*pblue = pmap->blue[pixB].co.local.blue;
877	npix = pmap->numPixelsRed[client];
878	ppix = (Pixel *) realloc(pmap->clientPixelsRed[client],
879				  (npix + 1) * sizeof(Pixel));
880	if (!ppix)
881	    return BadAlloc;
882	ppix[npix] = pixR;
883	pmap->clientPixelsRed[client] = ppix;
884	npix = pmap->numPixelsGreen[client];
885	ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client],
886				  (npix + 1) * sizeof(Pixel));
887	if (!ppix)
888	    return BadAlloc;
889	ppix[npix] = pixG;
890	pmap->clientPixelsGreen[client] = ppix;
891	npix = pmap->numPixelsBlue[client];
892	ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client],
893				  (npix + 1) * sizeof(Pixel));
894	if (!ppix)
895	    return BadAlloc;
896	ppix[npix] = pixB;
897	pmap->clientPixelsBlue[client] = ppix;
898	pmap->numPixelsRed[client]++;
899	pmap->numPixelsGreen[client]++;
900	pmap->numPixelsBlue[client]++;
901	break;
902
903    case GrayScale:
904    case PseudoColor:
905	if (pmap->mid != pmap->pScreen->defColormap &&
906	    pmap->pVisual->vid == pmap->pScreen->rootVisual)
907	{
908	    ColormapPtr prootmap;
909	    dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap,
910				    RT_COLORMAP, clients[client], DixReadAccess);
911
912	    if (pmap->class == prootmap->class)
913		FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
914			pPix, PSEUDOMAP, AllComp);
915	}
916	if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP,
917		      client, AllComp) != Success)
918	    return BadAlloc;
919        break;
920
921    case DirectColor:
922	if (pmap->mid != pmap->pScreen->defColormap &&
923	    pmap->pVisual->vid == pmap->pScreen->rootVisual)
924	{
925	    ColormapPtr prootmap;
926	    dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap,
927				    RT_COLORMAP, clients[client], DixReadAccess);
928
929	    if (pmap->class == prootmap->class)
930	    {
931		pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
932		FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
933			&pixR, REDMAP, RedComp);
934		pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
935		FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb,
936			&pixG, GREENMAP, GreenComp);
937		pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
938		FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb,
939			&pixB, BLUEMAP, BlueComp);
940		*pPix = pixR | pixG | pixB;
941	    }
942	}
943
944	pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
945	if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
946		      client, RedComp) != Success)
947	    return BadAlloc;
948	pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
949	if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
950		      GREENMAP, client, GreenComp) != Success)
951	{
952	    (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
953	    return BadAlloc;
954	}
955	pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
956	if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
957		      client, BlueComp) != Success)
958	{
959	    (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0);
960	    (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
961	    return BadAlloc;
962	}
963	*pPix = pixR | pixG | pixB | ALPHAMASK(pVisual);
964
965	break;
966    }
967
968    /* if this is the client's first pixel in this colormap, tell the
969     * resource manager that the client has pixels in this colormap which
970     * should be freed when the client dies */
971    if ((pmap->numPixelsRed[client] == 1) &&
972	(CLIENT_ID(pmap->mid) != client) &&
973	!(pmap->flags & BeingCreated))
974    {
975	colorResource	*pcr;
976
977	pcr = malloc(sizeof(colorResource));
978	if (!pcr)
979	{
980	    (void)FreeColors(pmap, client, 1, pPix, (Pixel)0);
981	    return BadAlloc;
982	}
983	pcr->mid = pmap->mid;
984	pcr->client = client;
985	if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
986	    return BadAlloc;
987    }
988    return Success;
989}
990
991/*
992 * FakeAllocColor -- fake an AllocColor request by
993 * returning a free pixel if availible, otherwise returning
994 * the closest matching pixel.  This is used by the mi
995 * software sprite code to recolor cursors.  A nice side-effect
996 * is that this routine will never return failure.
997 */
998
999void
1000FakeAllocColor (ColormapPtr pmap, xColorItem *item)
1001{
1002    Pixel pixR, pixG, pixB;
1003    Pixel temp;
1004    int	entries;
1005    xrgb rgb;
1006    int	class;
1007    VisualPtr pVisual;
1008
1009    pVisual = pmap->pVisual;
1010    rgb.red = item->red;
1011    rgb.green = item->green;
1012    rgb.blue = item->blue;
1013    (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual);
1014    class = pmap->class;
1015    entries = pVisual->ColormapEntries;
1016
1017    switch (class) {
1018    case GrayScale:
1019    case PseudoColor:
1020	temp = 0;
1021	item->pixel = 0;
1022	if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP,
1023		      -1, AllComp) == Success) {
1024	    item->pixel = temp;
1025	    break;
1026	}
1027	/* fall through ... */
1028    case StaticColor:
1029    case StaticGray:
1030	item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
1031	break;
1032
1033    case DirectColor:
1034	/* Look up each component in its own map, then OR them together */
1035	pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed;
1036	pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1037	pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1038	if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
1039		      -1, RedComp) != Success)
1040	    pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP)
1041			<< pVisual->offsetRed;
1042	if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
1043		      GREENMAP, -1, GreenComp) != Success)
1044	    pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb,
1045				 GREENMAP) << pVisual->offsetGreen;
1046	if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
1047		      -1, BlueComp) != Success)
1048	    pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP)
1049			<< pVisual->offsetBlue;
1050	item->pixel = pixR | pixG | pixB;
1051	break;
1052
1053    case TrueColor:
1054	/* Look up each component in its own map, then OR them together */
1055	pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
1056	pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
1057	pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
1058	item->pixel = (pixR << pVisual->offsetRed) |
1059		      (pixG << pVisual->offsetGreen) |
1060		      (pixB << pVisual->offsetBlue);
1061	break;
1062    }
1063}
1064
1065/* free a pixel value obtained from FakeAllocColor */
1066void
1067FakeFreeColor(ColormapPtr pmap, Pixel pixel)
1068{
1069    VisualPtr pVisual;
1070    Pixel pixR, pixG, pixB;
1071
1072    switch (pmap->class) {
1073    case GrayScale:
1074    case PseudoColor:
1075	if (pmap->red[pixel].refcnt == AllocTemporary)
1076	    pmap->red[pixel].refcnt = 0;
1077	break;
1078    case DirectColor:
1079	pVisual = pmap->pVisual;
1080	pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed;
1081	pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1082	pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1083	if (pmap->red[pixR].refcnt == AllocTemporary)
1084	    pmap->red[pixR].refcnt = 0;
1085	if (pmap->green[pixG].refcnt == AllocTemporary)
1086	    pmap->green[pixG].refcnt = 0;
1087	if (pmap->blue[pixB].refcnt == AllocTemporary)
1088	    pmap->blue[pixB].refcnt = 0;
1089	break;
1090    }
1091}
1092
1093typedef unsigned short	BigNumUpper;
1094typedef unsigned long	BigNumLower;
1095
1096#define BIGNUMLOWERBITS	24
1097#define BIGNUMUPPERBITS	16
1098#define BIGNUMLOWER (1 << BIGNUMLOWERBITS)
1099#define BIGNUMUPPER (1 << BIGNUMUPPERBITS)
1100#define UPPERPART(i)	((i) >> BIGNUMLOWERBITS)
1101#define LOWERPART(i)	((i) & (BIGNUMLOWER - 1))
1102
1103typedef struct _bignum {
1104    BigNumUpper	upper;
1105    BigNumLower	lower;
1106} BigNumRec, *BigNumPtr;
1107
1108#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\
1109			    ((x)->upper == (y)->upper && (x)->lower > (y)->lower))
1110
1111#define UnsignedToBigNum(u,r)	(((r)->upper = UPPERPART(u)), \
1112				 ((r)->lower = LOWERPART(u)))
1113
1114#define MaxBigNum(r)		(((r)->upper = BIGNUMUPPER-1), \
1115				 ((r)->lower = BIGNUMLOWER-1))
1116
1117static void
1118BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r)
1119{
1120    BigNumLower	lower, carry = 0;
1121
1122    lower = x->lower + y->lower;
1123    if (lower >= BIGNUMLOWER) {
1124	lower -= BIGNUMLOWER;
1125	carry = 1;
1126    }
1127    r->lower = lower;
1128    r->upper = x->upper + y->upper + carry;
1129}
1130
1131static Pixel
1132FindBestPixel(EntryPtr pentFirst, int size, xrgb *prgb, int channel)
1133{
1134    EntryPtr	pent;
1135    Pixel	pixel, final;
1136    long	dr, dg, db;
1137    unsigned long   sq;
1138    BigNumRec	minval, sum, temp;
1139
1140    final = 0;
1141    MaxBigNum(&minval);
1142    /* look for the minimal difference */
1143    for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++)
1144    {
1145	dr = dg = db = 0;
1146	switch(channel)
1147	{
1148	  case PSEUDOMAP:
1149	      dg = (long) pent->co.local.green - prgb->green;
1150	      db = (long) pent->co.local.blue - prgb->blue;
1151	  case REDMAP:
1152	      dr = (long) pent->co.local.red - prgb->red;
1153	      break;
1154	  case GREENMAP:
1155	      dg = (long) pent->co.local.green - prgb->green;
1156	      break;
1157	  case BLUEMAP:
1158	      db = (long) pent->co.local.blue - prgb->blue;
1159	      break;
1160	}
1161	sq = dr * dr;
1162	UnsignedToBigNum (sq, &sum);
1163	sq = dg * dg;
1164	UnsignedToBigNum (sq, &temp);
1165	BigNumAdd (&sum, &temp, &sum);
1166	sq = db * db;
1167	UnsignedToBigNum (sq, &temp);
1168	BigNumAdd (&sum, &temp, &sum);
1169	if (BigNumGreater (&minval, &sum))
1170	{
1171	    final = pixel;
1172	    minval = sum;
1173	}
1174    }
1175    return final;
1176}
1177
1178static void
1179FindColorInRootCmap (ColormapPtr pmap, EntryPtr pentFirst, int size,
1180                     xrgb *prgb, Pixel *pPixel, int channel,
1181                     ColorCompareProcPtr comp)
1182{
1183    EntryPtr    pent;
1184    Pixel	pixel;
1185    int         count;
1186
1187    if ((pixel = *pPixel) >= size)
1188	pixel = 0;
1189    for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++)
1190    {
1191	if (pent->refcnt > 0 && (*comp) (pent, prgb))
1192	{
1193	    switch (channel)
1194	    {
1195	    case REDMAP:
1196		pixel <<= pmap->pVisual->offsetRed;
1197		break;
1198	    case GREENMAP:
1199		pixel <<= pmap->pVisual->offsetGreen;
1200		break;
1201	    case BLUEMAP:
1202		pixel <<= pmap->pVisual->offsetBlue;
1203		break;
1204	    default: /* PSEUDOMAP */
1205		break;
1206	    }
1207	    *pPixel = pixel;
1208	}
1209    }
1210}
1211
1212/* Tries to find a color in pmap that exactly matches the one requested in prgb
1213 * if it can't it allocates one.
1214 * Starts looking at pentFirst + *pPixel, so if you want a specific pixel,
1215 * load *pPixel with that value, otherwise set it to 0
1216 */
1217int
1218FindColor (ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb *prgb,
1219           Pixel *pPixel, int channel, int client,
1220           ColorCompareProcPtr comp)
1221{
1222    EntryPtr	pent;
1223    Bool	foundFree;
1224    Pixel	pixel, Free = 0;
1225    int		npix, count, *nump = NULL;
1226    Pixel	**pixp = NULL, *ppix;
1227    xColorItem	def;
1228
1229    foundFree = FALSE;
1230
1231    if((pixel = *pPixel) >= size)
1232	pixel = 0;
1233    /* see if there is a match, and also look for a free entry */
1234    for (pent = pentFirst + pixel, count = size; --count >= 0; )
1235    {
1236        if (pent->refcnt > 0)
1237	{
1238    	    if ((*comp) (pent, prgb))
1239	    {
1240		if (client >= 0)
1241		    pent->refcnt++;
1242		*pPixel = pixel;
1243		switch(channel)
1244		{
1245		  case REDMAP:
1246		    *pPixel <<= pmap->pVisual->offsetRed;
1247		  case PSEUDOMAP:
1248		    break;
1249		  case GREENMAP:
1250		    *pPixel <<= pmap->pVisual->offsetGreen;
1251		    break;
1252		  case BLUEMAP:
1253		    *pPixel <<= pmap->pVisual->offsetBlue;
1254		    break;
1255		}
1256		goto gotit;
1257    	    }
1258        }
1259	else if (!foundFree && pent->refcnt == 0)
1260	{
1261	    Free = pixel;
1262	    foundFree = TRUE;
1263	    /* If we're initializing the colormap, then we are looking for
1264	     * the first free cell we can find, not to minimize the number
1265	     * of entries we use.  So don't look any further. */
1266	    if(pmap->flags & BeingCreated)
1267		break;
1268	}
1269	pixel++;
1270	if(pixel >= size)
1271	{
1272	    pent = pentFirst;
1273	    pixel = 0;
1274	}
1275	else
1276	    pent++;
1277    }
1278
1279    /* If we got here, we didn't find a match.  If we also didn't find
1280     * a free entry, we're out of luck.  Otherwise, we'll usurp a free
1281     * entry and fill it in */
1282    if (!foundFree)
1283	return BadAlloc;
1284    pent = pentFirst + Free;
1285    pent->fShared = FALSE;
1286    pent->refcnt = (client >= 0) ? 1 : AllocTemporary;
1287
1288    switch (channel)
1289    {
1290      case PSEUDOMAP:
1291        pent->co.local.red = prgb->red;
1292        pent->co.local.green = prgb->green;
1293        pent->co.local.blue = prgb->blue;
1294        def.red = prgb->red;
1295	def.green = prgb->green;
1296	def.blue = prgb->blue;
1297	def.flags = (DoRed|DoGreen|DoBlue);
1298	if (client >= 0)
1299	    pmap->freeRed--;
1300	def.pixel = Free;
1301	break;
1302
1303      case REDMAP:
1304        pent->co.local.red = prgb->red;
1305        def.red = prgb->red;
1306	def.green = pmap->green[0].co.local.green;
1307	def.blue = pmap->blue[0].co.local.blue;
1308	def.flags = DoRed;
1309	if (client >= 0)
1310	    pmap->freeRed--;
1311	def.pixel = Free << pmap->pVisual->offsetRed;
1312	break;
1313
1314      case GREENMAP:
1315	pent->co.local.green = prgb->green;
1316	def.red = pmap->red[0].co.local.red;
1317        def.green = prgb->green;
1318	def.blue = pmap->blue[0].co.local.blue;
1319	def.flags = DoGreen;
1320	if (client >= 0)
1321	    pmap->freeGreen--;
1322	def.pixel = Free << pmap->pVisual->offsetGreen;
1323	break;
1324
1325      case BLUEMAP:
1326	pent->co.local.blue = prgb->blue;
1327	def.red = pmap->red[0].co.local.red;
1328	def.green = pmap->green[0].co.local.green;
1329	def.blue = prgb->blue;
1330	def.flags = DoBlue;
1331	if (client >= 0)
1332	    pmap->freeBlue--;
1333	def.pixel = Free << pmap->pVisual->offsetBlue;
1334	break;
1335    }
1336    (*pmap->pScreen->StoreColors) (pmap, 1, &def);
1337    pixel = Free;
1338    *pPixel = def.pixel;
1339
1340gotit:
1341    if (pmap->flags & BeingCreated || client == -1)
1342	return Success;
1343    /* Now remember the pixel, for freeing later */
1344    switch (channel)
1345    {
1346      case PSEUDOMAP:
1347      case REDMAP:
1348	nump = pmap->numPixelsRed;
1349	pixp = pmap->clientPixelsRed;
1350	break;
1351
1352      case GREENMAP:
1353	nump = pmap->numPixelsGreen;
1354	pixp = pmap->clientPixelsGreen;
1355	break;
1356
1357      case BLUEMAP:
1358	nump = pmap->numPixelsBlue;
1359	pixp = pmap->clientPixelsBlue;
1360	break;
1361    }
1362    npix = nump[client];
1363    ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel));
1364    if (!ppix)
1365    {
1366	pent->refcnt--;
1367	if (!pent->fShared)
1368	    switch (channel)
1369	    {
1370	      case PSEUDOMAP:
1371	      case REDMAP:
1372		pmap->freeRed++;
1373		break;
1374	      case GREENMAP:
1375		pmap->freeGreen++;
1376		break;
1377	      case BLUEMAP:
1378		pmap->freeBlue++;
1379		break;
1380	    }
1381	return BadAlloc;
1382    }
1383    ppix[npix] = pixel;
1384    pixp[client] = ppix;
1385    nump[client]++;
1386
1387    return Success;
1388}
1389
1390/* Comparison functions -- passed to FindColor to determine if an
1391 * entry is already the color we're looking for or not */
1392static int
1393AllComp (EntryPtr pent, xrgb *prgb)
1394{
1395    if((pent->co.local.red == prgb->red) &&
1396       (pent->co.local.green == prgb->green) &&
1397       (pent->co.local.blue == prgb->blue) )
1398       return 1;
1399    return 0;
1400}
1401
1402static int
1403RedComp (EntryPtr pent, xrgb *prgb)
1404{
1405    if (pent->co.local.red == prgb->red)
1406	return 1;
1407    return 0;
1408}
1409
1410static int
1411GreenComp (EntryPtr pent, xrgb *prgb)
1412{
1413    if (pent->co.local.green == prgb->green)
1414	return 1;
1415    return 0;
1416}
1417
1418static int
1419BlueComp (EntryPtr pent, xrgb *prgb)
1420{
1421    if (pent->co.local.blue == prgb->blue)
1422	return 1;
1423    return 0;
1424}
1425
1426
1427/* Read the color value of a cell */
1428
1429int
1430QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client)
1431{
1432    Pixel	*ppix, pixel;
1433    xrgb	*prgb;
1434    VisualPtr	pVisual;
1435    EntryPtr	pent;
1436    Pixel	i;
1437    int		errVal = Success;
1438
1439    pVisual = pmap->pVisual;
1440    if ((pmap->class | DynamicClass) == DirectColor)
1441    {
1442	int numred, numgreen, numblue;
1443	Pixel rgbbad;
1444
1445	numred = NUMRED(pVisual);
1446	numgreen = NUMGREEN(pVisual);
1447	numblue = NUMBLUE(pVisual);
1448	rgbbad = ~RGBMASK(pVisual);
1449	for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
1450	{
1451	    pixel = *ppix;
1452	    if (pixel & rgbbad) {
1453		client->errorValue = pixel;
1454		errVal =  BadValue;
1455		continue;
1456	    }
1457	    i  = (pixel & pVisual->redMask) >> pVisual->offsetRed;
1458	    if (i >= numred)
1459	    {
1460		client->errorValue = pixel;
1461		errVal =  BadValue;
1462		continue;
1463	    }
1464	    prgb->red = pmap->red[i].co.local.red;
1465	    i  = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1466	    if (i >= numgreen)
1467	    {
1468		client->errorValue = pixel;
1469		errVal =  BadValue;
1470		continue;
1471	    }
1472	    prgb->green = pmap->green[i].co.local.green;
1473	    i  = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1474	    if (i >= numblue)
1475	    {
1476		client->errorValue = pixel;
1477		errVal =  BadValue;
1478		continue;
1479	    }
1480	    prgb->blue = pmap->blue[i].co.local.blue;
1481	}
1482    }
1483    else
1484    {
1485	for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
1486	{
1487	    pixel = *ppix;
1488	    if (pixel >= pVisual->ColormapEntries)
1489	    {
1490		client->errorValue = pixel;
1491		errVal = BadValue;
1492	    }
1493	    else
1494	    {
1495		pent = (EntryPtr)&pmap->red[pixel];
1496		if (pent->fShared)
1497		{
1498		    prgb->red = pent->co.shco.red->color;
1499		    prgb->green = pent->co.shco.green->color;
1500		    prgb->blue = pent->co.shco.blue->color;
1501		}
1502		else
1503		{
1504		    prgb->red = pent->co.local.red;
1505		    prgb->green = pent->co.local.green;
1506		    prgb->blue = pent->co.local.blue;
1507		}
1508	    }
1509	}
1510    }
1511    return errVal;
1512}
1513
1514static void
1515FreePixels(ColormapPtr pmap, int client)
1516{
1517    Pixel *ppix, *ppixStart;
1518    int n;
1519    int	class;
1520
1521    class = pmap->class;
1522    ppixStart = pmap->clientPixelsRed[client];
1523    if (class & DynamicClass)
1524    {
1525	n = pmap->numPixelsRed[client];
1526	for (ppix = ppixStart; --n >= 0; )
1527	{
1528	    FreeCell(pmap, *ppix, REDMAP);
1529	    ppix++;
1530	}
1531    }
1532
1533    free(ppixStart);
1534    pmap->clientPixelsRed[client] = (Pixel *) NULL;
1535    pmap->numPixelsRed[client] = 0;
1536    if ((class | DynamicClass) == DirectColor)
1537    {
1538        ppixStart = pmap->clientPixelsGreen[client];
1539	if (class & DynamicClass)
1540	    for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;)
1541		FreeCell(pmap, *ppix++, GREENMAP);
1542	free(ppixStart);
1543	pmap->clientPixelsGreen[client] = (Pixel *) NULL;
1544	pmap->numPixelsGreen[client] = 0;
1545
1546        ppixStart = pmap->clientPixelsBlue[client];
1547	if (class & DynamicClass)
1548	    for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; )
1549		FreeCell(pmap, *ppix++, BLUEMAP);
1550	free(ppixStart);
1551	pmap->clientPixelsBlue[client] = (Pixel *) NULL;
1552	pmap->numPixelsBlue[client] = 0;
1553    }
1554}
1555
1556/**
1557 * Frees all of a client's colors and cells.
1558 *
1559 *  \param value  must conform to DeleteType
1560 *  \unused fakeid
1561 */
1562int
1563FreeClientPixels (pointer value, XID fakeid)
1564{
1565    pointer pmap;
1566    colorResource *pcr = value;
1567    int rc;
1568
1569    rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient,
1570				 DixRemoveAccess);
1571    if (rc == Success)
1572	FreePixels((ColormapPtr)pmap, pcr->client);
1573    free(pcr);
1574    return Success;
1575}
1576
1577int
1578AllocColorCells (int client, ColormapPtr pmap, int colors, int planes,
1579                 Bool contig, Pixel *ppix, Pixel *masks)
1580{
1581    Pixel	rmask, gmask, bmask, *ppixFirst, r, g, b;
1582    int		n, class;
1583    int		ok;
1584    int		oldcount;
1585    colorResource *pcr = (colorResource *)NULL;
1586
1587    class = pmap->class;
1588    if (!(class & DynamicClass))
1589	return BadAlloc; /* Shouldn't try on this type */
1590    oldcount = pmap->numPixelsRed[client];
1591    if (pmap->class == DirectColor)
1592	oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
1593    if (!oldcount && (CLIENT_ID(pmap->mid) != client))
1594    {
1595	pcr = malloc(sizeof(colorResource));
1596	if (!pcr)
1597	    return BadAlloc;
1598    }
1599
1600    if (pmap->class == DirectColor)
1601    {
1602        ok = AllocDirect (client, pmap, colors, planes, planes, planes,
1603			  contig, ppix, &rmask, &gmask, &bmask);
1604	if(ok == Success)
1605	{
1606	    for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b)
1607	    {
1608		while(!(rmask & r))
1609		    r += r;
1610		while(!(gmask & g))
1611		    g += g;
1612		while(!(bmask & b))
1613		    b += b;
1614		*masks++ = r | g | b;
1615	    }
1616	}
1617    }
1618    else
1619    {
1620        ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask,
1621			  &ppixFirst);
1622	if(ok == Success)
1623	{
1624	    for (r = 1, n = planes; --n >= 0; r += r)
1625	    {
1626		while(!(rmask & r))
1627		    r += r;
1628		*masks++ = r;
1629	    }
1630	}
1631    }
1632
1633    /* if this is the client's first pixels in this colormap, tell the
1634     * resource manager that the client has pixels in this colormap which
1635     * should be freed when the client dies */
1636    if ((ok == Success) && pcr)
1637    {
1638	pcr->mid = pmap->mid;
1639	pcr->client = client;
1640	if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
1641	    ok = BadAlloc;
1642    } else free(pcr);
1643
1644    return ok;
1645}
1646
1647
1648int
1649AllocColorPlanes (int client, ColormapPtr pmap, int colors,
1650                  int r, int g, int b, Bool contig, Pixel *pixels,
1651                  Pixel *prmask, Pixel *pgmask, Pixel *pbmask)
1652{
1653    int		ok;
1654    Pixel	mask, *ppixFirst;
1655    Pixel shift;
1656    int i;
1657    int		class;
1658    int		oldcount;
1659    colorResource *pcr = (colorResource *)NULL;
1660
1661    class = pmap->class;
1662    if (!(class & DynamicClass))
1663	return BadAlloc; /* Shouldn't try on this type */
1664    oldcount = pmap->numPixelsRed[client];
1665    if (class == DirectColor)
1666	oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
1667    if (!oldcount && (CLIENT_ID(pmap->mid) != client))
1668    {
1669	pcr = malloc(sizeof(colorResource));
1670	if (!pcr)
1671	    return BadAlloc;
1672    }
1673
1674    if (class == DirectColor)
1675    {
1676        ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels,
1677			  prmask, pgmask, pbmask);
1678    }
1679    else
1680    {
1681	/* Allocate the proper pixels */
1682	/* XXX This is sort of bad, because of contig is set, we force all
1683	 * r + g + b bits to be contiguous.  Should only force contiguity
1684	 * per mask
1685	 */
1686        ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels,
1687			  &mask, &ppixFirst);
1688
1689	if(ok == Success)
1690	{
1691	    /* now split that mask into three */
1692	    *prmask = *pgmask = *pbmask = 0;
1693	    shift = 1;
1694	    for (i = r; --i >= 0; shift += shift)
1695	    {
1696		while (!(mask & shift))
1697		    shift += shift;
1698		*prmask |= shift;
1699	    }
1700	    for (i = g; --i >= 0; shift += shift)
1701	    {
1702		while (!(mask & shift))
1703		    shift += shift;
1704		*pgmask |= shift;
1705	    }
1706	    for (i = b; --i >= 0; shift += shift)
1707	    {
1708		while (!(mask & shift))
1709		    shift += shift;
1710		*pbmask |= shift;
1711	    }
1712
1713	    /* set up the shared color cells */
1714	    if (!AllocShared(pmap, pixels, colors, r, g, b,
1715			     *prmask, *pgmask, *pbmask, ppixFirst))
1716	    {
1717		(void)FreeColors(pmap, client, colors, pixels, mask);
1718		ok = BadAlloc;
1719	    }
1720	}
1721    }
1722
1723    /* if this is the client's first pixels in this colormap, tell the
1724     * resource manager that the client has pixels in this colormap which
1725     * should be freed when the client dies */
1726    if ((ok == Success) && pcr)
1727    {
1728	pcr->mid = pmap->mid;
1729	pcr->client = client;
1730	if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
1731	    ok = BadAlloc;
1732    } else free(pcr);
1733
1734    return ok;
1735}
1736
1737static int
1738AllocDirect (int client, ColormapPtr pmap, int c, int r, int g, int b, Bool contig,
1739             Pixel *pixels, Pixel *prmask, Pixel *pgmask, Pixel *pbmask)
1740{
1741    Pixel	*ppixRed, *ppixGreen, *ppixBlue;
1742    Pixel	*ppix, *pDst, *p;
1743    int		npix, npixR, npixG, npixB;
1744    Bool	okR, okG, okB;
1745    Pixel	*rpix = 0, *gpix = 0, *bpix = 0;
1746
1747    npixR = c << r;
1748    npixG = c << g;
1749    npixB = c << b;
1750    if ((r >= 32) || (g >= 32) || (b >= 32) ||
1751	(npixR > pmap->freeRed) || (npixR < c) ||
1752	(npixG > pmap->freeGreen) || (npixG < c) ||
1753	(npixB > pmap->freeBlue) || (npixB < c))
1754	return BadAlloc;
1755
1756    /* start out with empty pixels */
1757    for(p = pixels; p < pixels + c; p++)
1758	*p = 0;
1759
1760    ppixRed = malloc(npixR * sizeof(Pixel));
1761    ppixGreen = malloc(npixG * sizeof(Pixel));
1762    ppixBlue = malloc(npixB * sizeof(Pixel));
1763    if (!ppixRed || !ppixGreen || !ppixBlue)
1764    {
1765	free(ppixBlue);
1766	free(ppixGreen);
1767	free(ppixRed);
1768	return BadAlloc;
1769    }
1770
1771    okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask);
1772    okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask);
1773    okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask);
1774
1775    if (okR && okG && okB)
1776    {
1777	rpix = (Pixel *) realloc(pmap->clientPixelsRed[client],
1778				  (pmap->numPixelsRed[client] + (c << r)) *
1779				  sizeof(Pixel));
1780	if (rpix)
1781	    pmap->clientPixelsRed[client] = rpix;
1782	gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client],
1783				  (pmap->numPixelsGreen[client] + (c << g)) *
1784				  sizeof(Pixel));
1785	if (gpix)
1786	    pmap->clientPixelsGreen[client] = gpix;
1787	bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client],
1788				  (pmap->numPixelsBlue[client] + (c << b)) *
1789				  sizeof(Pixel));
1790	if (bpix)
1791	    pmap->clientPixelsBlue[client] = bpix;
1792    }
1793
1794    if (!okR || !okG || !okB || !rpix || !gpix || !bpix)
1795    {
1796	if (okR)
1797	    for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++)
1798		pmap->red[*ppix].refcnt = 0;
1799	if (okG)
1800	    for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++)
1801		pmap->green[*ppix].refcnt = 0;
1802	if (okB)
1803	    for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++)
1804		pmap->blue[*ppix].refcnt = 0;
1805	free(ppixBlue);
1806	free(ppixGreen);
1807	free(ppixRed);
1808	return BadAlloc;
1809    }
1810
1811    *prmask <<= pmap->pVisual->offsetRed;
1812    *pgmask <<= pmap->pVisual->offsetGreen;
1813    *pbmask <<= pmap->pVisual->offsetBlue;
1814
1815    ppix = rpix + pmap->numPixelsRed[client];
1816    for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++)
1817    {
1818	*ppix++ = *p;
1819	if(p < ppixRed + c)
1820	    *pDst++ |= *p << pmap->pVisual->offsetRed;
1821    }
1822    pmap->numPixelsRed[client] += npixR;
1823    pmap->freeRed -= npixR;
1824
1825    ppix = gpix + pmap->numPixelsGreen[client];
1826    for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++)
1827    {
1828	*ppix++ = *p;
1829	if(p < ppixGreen + c)
1830	    *pDst++ |= *p << pmap->pVisual->offsetGreen;
1831    }
1832    pmap->numPixelsGreen[client] += npixG;
1833    pmap->freeGreen -= npixG;
1834
1835    ppix = bpix + pmap->numPixelsBlue[client];
1836    for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++)
1837    {
1838	*ppix++ = *p;
1839	if(p < ppixBlue + c)
1840	    *pDst++ |= *p << pmap->pVisual->offsetBlue;
1841    }
1842    pmap->numPixelsBlue[client] += npixB;
1843    pmap->freeBlue -= npixB;
1844
1845
1846    for (pDst = pixels; pDst < pixels + c; pDst++)
1847	*pDst |= ALPHAMASK(pmap->pVisual);
1848
1849    free(ppixBlue);
1850    free(ppixGreen);
1851    free(ppixRed);
1852
1853    return Success;
1854}
1855
1856static int
1857AllocPseudo (int client, ColormapPtr pmap, int c, int r, Bool contig,
1858             Pixel *pixels, Pixel *pmask, Pixel **pppixFirst)
1859{
1860    Pixel	*ppix, *p, *pDst, *ppixTemp;
1861    int		npix;
1862    Bool	ok;
1863
1864    npix = c << r;
1865    if ((r >= 32) || (npix > pmap->freeRed) || (npix < c))
1866	return BadAlloc;
1867    if(!(ppixTemp = malloc(npix * sizeof(Pixel))))
1868	return BadAlloc;
1869    ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask);
1870
1871    if (ok)
1872    {
1873
1874	/* all the allocated pixels are added to the client pixel list,
1875	 * but only the unique ones are returned to the client */
1876	ppix = (Pixel *)realloc(pmap->clientPixelsRed[client],
1877			 (pmap->numPixelsRed[client] + npix) * sizeof(Pixel));
1878	if (!ppix)
1879	{
1880	    for (p = ppixTemp; p < ppixTemp + npix; p++)
1881		pmap->red[*p].refcnt = 0;
1882	    free(ppixTemp);
1883	    return BadAlloc;
1884	}
1885	pmap->clientPixelsRed[client] = ppix;
1886	ppix += pmap->numPixelsRed[client];
1887	*pppixFirst = ppix;
1888	pDst = pixels;
1889	for (p = ppixTemp; p < ppixTemp + npix; p++)
1890	{
1891	    *ppix++ = *p;
1892	    if(p < ppixTemp + c)
1893	        *pDst++ = *p;
1894	}
1895	pmap->numPixelsRed[client] += npix;
1896	pmap->freeRed -= npix;
1897    }
1898    free(ppixTemp);
1899    return ok ? Success : BadAlloc;
1900}
1901
1902/* Allocates count << planes pixels from colormap pmap for client. If
1903 * contig, then the plane mask is made of consecutive bits.  Returns
1904 * all count << pixels in the array pixels. The first count of those
1905 * pixels are the unique pixels.  *pMask has the mask to Or with the
1906 * unique pixels to get the rest of them.
1907 *
1908 * Returns True iff all pixels could be allocated
1909 * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE
1910 * (see AllocShared for why we care)
1911 */
1912static Bool
1913AllocCP (ColormapPtr pmap, EntryPtr pentFirst, int count, int planes,
1914         Bool contig, Pixel *pixels, Pixel *pMask)
1915{
1916    EntryPtr	ent;
1917    Pixel	pixel, base, entries, maxp, save;
1918    int		dplanes, found;
1919    Pixel	*ppix;
1920    Pixel	mask;
1921    Pixel	finalmask;
1922
1923    dplanes = pmap->pVisual->nplanes;
1924
1925    /* Easy case.  Allocate pixels only */
1926    if (planes == 0)
1927    {
1928        /* allocate writable entries */
1929	ppix = pixels;
1930        ent = pentFirst;
1931        pixel = 0;
1932        while (--count >= 0)
1933	{
1934            /* Just find count unallocated cells */
1935    	    while (ent->refcnt)
1936	    {
1937    	        ent++;
1938    	        pixel++;
1939    	    }
1940    	    ent->refcnt = AllocPrivate;
1941    	    *ppix++ = pixel;
1942	    ent->fShared = FALSE;
1943        }
1944        *pMask = 0;
1945        return TRUE;
1946    }
1947    else if (planes > dplanes)
1948    {
1949	return FALSE;
1950    }
1951
1952    /* General case count pixels * 2 ^ planes cells to be allocated */
1953
1954    /* make room for new pixels */
1955    ent = pentFirst;
1956
1957    /* first try for contiguous planes, since it's fastest */
1958    for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1);
1959         --dplanes >= 0;
1960         mask += mask, base += base)
1961    {
1962        ppix = pixels;
1963        found = 0;
1964        pixel = 0;
1965        entries = pmap->pVisual->ColormapEntries - mask;
1966        while (pixel < entries)
1967	{
1968    	    save = pixel;
1969    	    maxp = pixel + mask + base;
1970    	    /* check if all are free */
1971    	    while (pixel != maxp && ent[pixel].refcnt == 0)
1972    	        pixel += base;
1973	    if (pixel == maxp)
1974		{
1975		    /* this one works */
1976		    *ppix++ = save;
1977		    found++;
1978		    if (found == count)
1979		    {
1980			/* found enough, allocate them all */
1981			while (--count >= 0)
1982			{
1983			    pixel = pixels[count];
1984			    maxp = pixel + mask;
1985			    while (1)
1986			    {
1987				ent[pixel].refcnt = AllocPrivate;
1988				ent[pixel].fShared = FALSE;
1989				if (pixel == maxp)
1990				    break;
1991				pixel += base;
1992				*ppix++ = pixel;
1993			    }
1994			}
1995			*pMask = mask;
1996			return TRUE;
1997		    }
1998		}
1999    	    pixel = save + 1;
2000    	    if (pixel & mask)
2001    	        pixel += mask;
2002        }
2003    }
2004
2005    dplanes = pmap->pVisual->nplanes;
2006    if (contig || planes == 1 || dplanes < 3)
2007	return FALSE;
2008
2009    /* this will be very slow for large maps, need a better algorithm */
2010
2011    /*
2012       we can generate the smallest and largest numbers that fits in dplanes
2013       bits and contain exactly planes bits set as follows. First, we need to
2014       check that it is possible to generate such a mask at all.
2015       (Non-contiguous masks need one more bit than contiguous masks). Then
2016       the smallest such mask consists of the rightmost planes-1 bits set, then
2017       a zero, then a one in position planes + 1. The formula is
2018         (3 << (planes-1)) -1
2019       The largest such masks consists of the leftmost planes-1 bits set, then
2020       a zero, then a one bit in position dplanes-planes-1. If dplanes is
2021       smaller than 32 (the number of bits in a word) then the formula is:
2022         (1<<dplanes) - (1<<(dplanes-planes+1) + (1<<dplanes-planes-1)
2023       If dplanes = 32, then we can't calculate (1<<dplanes) and we have
2024       to use:
2025         ( (1<<(planes-1)) - 1) << (dplanes-planes+1) + (1<<(dplanes-planes-1))
2026
2027	  << Thank you, Loretta>>>
2028
2029    */
2030
2031    finalmask =
2032        (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) +
2033	  (((Pixel)1)<<(dplanes-planes-1));
2034    for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++)
2035    {
2036        /* next 3 magic statements count number of ones (HAKMEM #169) */
2037        pixel = (mask >> 1) & 033333333333;
2038        pixel = mask - pixel - ((pixel >> 1) & 033333333333);
2039        if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes)
2040    	    continue;
2041        ppix = pixels;
2042        found = 0;
2043        entries = pmap->pVisual->ColormapEntries - mask;
2044        base = lowbit (mask);
2045        for (pixel = 0; pixel < entries; pixel++)
2046	{
2047	    if (pixel & mask)
2048	        continue;
2049	    maxp = 0;
2050	    /* check if all are free */
2051	    while (ent[pixel + maxp].refcnt == 0)
2052	    {
2053		GetNextBitsOrBreak(maxp, mask, base);
2054	    }
2055	    if ((maxp < mask) || (ent[pixel + mask].refcnt != 0))
2056		continue;
2057	    /* this one works */
2058	    *ppix++ = pixel;
2059	    found++;
2060	    if (found < count)
2061		continue;
2062	    /* found enough, allocate them all */
2063	    while (--count >= 0)
2064	    {
2065		pixel = (pixels)[count];
2066		maxp = 0;
2067		while (1)
2068		{
2069		    ent[pixel + maxp].refcnt = AllocPrivate;
2070		    ent[pixel + maxp].fShared = FALSE;
2071		    GetNextBitsOrBreak(maxp, mask, base);
2072		    *ppix++ = pixel + maxp;
2073		}
2074	    }
2075
2076	    *pMask = mask;
2077	    return TRUE;
2078	}
2079    }
2080    return FALSE;
2081}
2082
2083/**
2084 *
2085 *  \param ppixFirst  First of the client's new pixels
2086 */
2087static Bool
2088AllocShared (ColormapPtr pmap, Pixel *ppix, int c, int r, int g, int b,
2089             Pixel rmask, Pixel gmask, Pixel bmask, Pixel *ppixFirst)
2090{
2091    Pixel	*pptr, *cptr;
2092    int		npix, z, npixClientNew, npixShared;
2093    Pixel	basemask, base, bits, common;
2094    SHAREDCOLOR *pshared, **ppshared, **psharedList;
2095
2096    npixClientNew = c << (r + g + b);
2097    npixShared = (c << r) + (c << g) + (c << b);
2098    psharedList = malloc(npixShared * sizeof(SHAREDCOLOR *));
2099    if (!psharedList)
2100	return FALSE;
2101    ppshared = psharedList;
2102    for (z = npixShared; --z >= 0; )
2103    {
2104	if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR))))
2105	{
2106	    for (z++ ; z < npixShared; z++)
2107		free(ppshared[z]);
2108	    free(psharedList);
2109	    return FALSE;
2110	}
2111    }
2112    for(pptr = ppix, npix = c; --npix >= 0; pptr++)
2113    {
2114	basemask = ~(gmask | bmask);
2115	common = *pptr & basemask;
2116	if (rmask)
2117	{
2118	    bits = 0;
2119	    base = lowbit (rmask);
2120	    while(1)
2121	    {
2122		pshared = *ppshared++;
2123		pshared->refcnt = 1 << (g + b);
2124		for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2125		{
2126		    if ((*cptr & basemask) == (common | bits))
2127		    {
2128			pmap->red[*cptr].fShared = TRUE;
2129			pmap->red[*cptr].co.shco.red = pshared;
2130		    }
2131		}
2132		GetNextBitsOrBreak(bits, rmask, base);
2133	    }
2134	}
2135	else
2136	{
2137	    pshared = *ppshared++;
2138	    pshared->refcnt = 1 << (g + b);
2139	    for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2140	    {
2141		if ((*cptr & basemask) == common)
2142		{
2143		    pmap->red[*cptr].fShared = TRUE;
2144		    pmap->red[*cptr].co.shco.red = pshared;
2145		}
2146	    }
2147	}
2148	basemask = ~(rmask | bmask);
2149	common = *pptr & basemask;
2150	if (gmask)
2151	{
2152	    bits = 0;
2153	    base = lowbit (gmask);
2154	    while(1)
2155	    {
2156		pshared = *ppshared++;
2157		pshared->refcnt = 1 << (r + b);
2158		for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2159		{
2160		    if ((*cptr & basemask) == (common | bits))
2161		    {
2162			pmap->red[*cptr].co.shco.green = pshared;
2163		    }
2164		}
2165		GetNextBitsOrBreak(bits, gmask, base);
2166	    }
2167	}
2168	else
2169	{
2170	    pshared = *ppshared++;
2171	    pshared->refcnt = 1 << (g + b);
2172	    for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2173	    {
2174		if ((*cptr & basemask) == common)
2175		{
2176		    pmap->red[*cptr].co.shco.green = pshared;
2177		}
2178	    }
2179	}
2180	basemask = ~(rmask | gmask);
2181	common = *pptr & basemask;
2182	if (bmask)
2183	{
2184	    bits = 0;
2185	    base = lowbit (bmask);
2186	    while(1)
2187	    {
2188		pshared = *ppshared++;
2189		pshared->refcnt = 1 << (r + g);
2190		for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2191		{
2192		    if ((*cptr & basemask) == (common | bits))
2193		    {
2194			pmap->red[*cptr].co.shco.blue = pshared;
2195		    }
2196		}
2197		GetNextBitsOrBreak(bits, bmask, base);
2198	    }
2199	}
2200	else
2201	{
2202	    pshared = *ppshared++;
2203	    pshared->refcnt = 1 << (g + b);
2204	    for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2205	    {
2206		if ((*cptr & basemask) == common)
2207		{
2208		    pmap->red[*cptr].co.shco.blue = pshared;
2209		}
2210	    }
2211	}
2212    }
2213    free(psharedList);
2214    return TRUE;
2215}
2216
2217
2218/** FreeColors
2219 * Free colors and/or cells (probably slow for large numbers)
2220 */
2221int
2222FreeColors (ColormapPtr pmap, int client, int count, Pixel *pixels, Pixel mask)
2223{
2224    int		rval, result, class;
2225    Pixel	rmask;
2226
2227    class = pmap->class;
2228    if (pmap->flags & AllAllocated)
2229	return BadAccess;
2230    if ((class | DynamicClass) == DirectColor)
2231    {
2232	rmask = mask & RGBMASK(pmap->pVisual);
2233        result = FreeCo(pmap, client, REDMAP, count, pixels,
2234			mask & pmap->pVisual->redMask);
2235	/* If any of the three calls fails, we must report that, if more
2236	 * than one fails, it's ok that we report the last one */
2237        rval = FreeCo(pmap, client, GREENMAP, count, pixels,
2238		      mask & pmap->pVisual->greenMask);
2239	if(rval != Success)
2240	    result = rval;
2241	rval = FreeCo(pmap, client, BLUEMAP, count, pixels,
2242		      mask & pmap->pVisual->blueMask);
2243	if(rval != Success)
2244	    result = rval;
2245    }
2246    else
2247    {
2248	rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1);
2249        result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask);
2250    }
2251    if ((mask != rmask) && count)
2252    {
2253	clients[client]->errorValue = *pixels | mask;
2254	result = BadValue;
2255    }
2256    /* XXX should worry about removing any RT_CMAPENTRY resource */
2257    return result;
2258}
2259
2260/**
2261 * Helper for FreeColors -- frees all combinations of *newpixels and mask bits
2262 * which the client has allocated in channel colormap cells of pmap.
2263 * doesn't change newpixels if it doesn't need to
2264 *
2265 *  \param pmap   which colormap head
2266 *  \param color  which sub-map, eg, RED, BLUE, PSEUDO
2267 *  \param npixIn number of pixels passed in
2268 *  \param ppixIn number of base pixels
2269 *  \param mask   mask client gave us
2270 */
2271static int
2272FreeCo (ColormapPtr pmap, int client, int color, int npixIn, Pixel *ppixIn, Pixel mask)
2273{
2274    Pixel	*ppixClient, pixTest;
2275    int		npixClient, npixNew, npix;
2276    Pixel	bits, base, cmask, rgbbad;
2277    Pixel	*pptr, *cptr;
2278    int 	n, zapped;
2279    int		errVal = Success;
2280    int		offset, numents;
2281
2282    if (npixIn == 0)
2283        return errVal;
2284    bits = 0;
2285    zapped = 0;
2286    base = lowbit (mask);
2287
2288    switch(color)
2289    {
2290      case REDMAP:
2291	cmask = pmap->pVisual->redMask;
2292	rgbbad = ~RGBMASK(pmap->pVisual);
2293	offset = pmap->pVisual->offsetRed;
2294	numents = (cmask >> offset) + 1;
2295	ppixClient = pmap->clientPixelsRed[client];
2296	npixClient = pmap->numPixelsRed[client];
2297	break;
2298      case GREENMAP:
2299	cmask = pmap->pVisual->greenMask;
2300	rgbbad = ~RGBMASK(pmap->pVisual);
2301	offset = pmap->pVisual->offsetGreen;
2302	numents = (cmask >> offset) + 1;
2303	ppixClient = pmap->clientPixelsGreen[client];
2304	npixClient = pmap->numPixelsGreen[client];
2305	break;
2306      case BLUEMAP:
2307	cmask = pmap->pVisual->blueMask;
2308	rgbbad = ~RGBMASK(pmap->pVisual);
2309	offset = pmap->pVisual->offsetBlue;
2310	numents = (cmask >> offset) + 1;
2311	ppixClient = pmap->clientPixelsBlue[client];
2312	npixClient = pmap->numPixelsBlue[client];
2313	break;
2314      default:	/* so compiler can see that everything gets initialized */
2315      case PSEUDOMAP:
2316	cmask = ~((Pixel)0);
2317	rgbbad = 0;
2318	offset = 0;
2319	numents = pmap->pVisual->ColormapEntries;
2320	ppixClient = pmap->clientPixelsRed[client];
2321	npixClient = pmap->numPixelsRed[client];
2322	break;
2323    }
2324
2325
2326    /* zap all pixels which match */
2327    while (1)
2328    {
2329        /* go through pixel list */
2330        for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++)
2331	{
2332	    pixTest = ((*pptr | bits) & cmask) >> offset;
2333	    if ((pixTest >= numents) || (*pptr & rgbbad))
2334	    {
2335		clients[client]->errorValue = *pptr | bits;
2336		errVal = BadValue;
2337		continue;
2338	    }
2339
2340	    /* find match in client list */
2341	    for (cptr = ppixClient, npix = npixClient;
2342	         --npix >= 0 && *cptr != pixTest;
2343		 cptr++) ;
2344
2345	    if (npix >= 0)
2346	    {
2347		if (pmap->class & DynamicClass)
2348		{
2349		    FreeCell(pmap, pixTest, color);
2350		}
2351		*cptr = ~((Pixel)0);
2352		zapped++;
2353	    }
2354	    else
2355		errVal = BadAccess;
2356	}
2357        /* generate next bits value */
2358	GetNextBitsOrBreak(bits, mask, base);
2359    }
2360
2361    /* delete freed pixels from client pixel list */
2362    if (zapped)
2363    {
2364        npixNew = npixClient - zapped;
2365        if (npixNew)
2366	{
2367	    /* Since the list can only get smaller, we can do a copy in
2368	     * place and then realloc to a smaller size */
2369    	    pptr = cptr = ppixClient;
2370
2371	    /* If we have all the new pixels, we don't have to examine the
2372	     * rest of the old ones */
2373	    for(npix = 0; npix < npixNew; cptr++)
2374	    {
2375    	        if (*cptr != ~((Pixel)0))
2376		{
2377    		    *pptr++ = *cptr;
2378		    npix++;
2379    	        }
2380    	    }
2381	    pptr = (Pixel *)realloc(ppixClient, npixNew * sizeof(Pixel));
2382	    if (pptr)
2383		ppixClient = pptr;
2384	    npixClient = npixNew;
2385        }
2386	else
2387	{
2388	    npixClient = 0;
2389	    free(ppixClient);
2390    	    ppixClient = (Pixel *)NULL;
2391	}
2392	switch(color)
2393	{
2394	  case PSEUDOMAP:
2395	  case REDMAP:
2396	    pmap->clientPixelsRed[client] = ppixClient;
2397	    pmap->numPixelsRed[client] = npixClient;
2398	    break;
2399	  case GREENMAP:
2400	    pmap->clientPixelsGreen[client] = ppixClient;
2401	    pmap->numPixelsGreen[client] = npixClient;
2402	    break;
2403	  case BLUEMAP:
2404	    pmap->clientPixelsBlue[client] = ppixClient;
2405	    pmap->numPixelsBlue[client] = npixClient;
2406	    break;
2407	}
2408    }
2409    return errVal;
2410}
2411
2412
2413
2414/* Redefine color values */
2415int
2416StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client)
2417{
2418    Pixel 	pix;
2419    xColorItem *pdef;
2420    EntryPtr 	pent, pentT, pentLast;
2421    VisualPtr	pVisual;
2422    SHAREDCOLOR		*pred, *pgreen, *pblue;
2423    int			n, ChgRed, ChgGreen, ChgBlue, idef;
2424    int			class, errVal = Success;
2425    int			ok;
2426
2427
2428    class = pmap->class;
2429    if(!(class & DynamicClass) && !(pmap->flags & BeingCreated))
2430    {
2431	return BadAccess;
2432    }
2433    pVisual = pmap->pVisual;
2434
2435    idef = 0;
2436    if((class | DynamicClass) == DirectColor)
2437    {
2438	int numred, numgreen, numblue;
2439	Pixel rgbbad;
2440
2441	numred = NUMRED(pVisual);
2442	numgreen = NUMGREEN(pVisual);
2443	numblue = NUMBLUE(pVisual);
2444	rgbbad = ~RGBMASK(pVisual);
2445        for (pdef = defs, n = 0; n < count; pdef++, n++)
2446	{
2447	    ok = TRUE;
2448            (*pmap->pScreen->ResolveColor)
2449	        (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
2450
2451	    if (pdef->pixel & rgbbad)
2452	    {
2453		errVal = BadValue;
2454		client->errorValue = pdef->pixel;
2455		continue;
2456	    }
2457	    pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed;
2458	    if (pix >= numred)
2459	    {
2460		errVal = BadValue;
2461		ok = FALSE;
2462	    }
2463	    else if (pmap->red[pix].refcnt != AllocPrivate)
2464	    {
2465		errVal = BadAccess;
2466		ok = FALSE;
2467	    }
2468	    else if (pdef->flags & DoRed)
2469	    {
2470		pmap->red[pix].co.local.red = pdef->red;
2471	    }
2472	    else
2473	    {
2474		pdef->red = pmap->red[pix].co.local.red;
2475	    }
2476
2477	    pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
2478	    if (pix >= numgreen)
2479	    {
2480		errVal = BadValue;
2481		ok = FALSE;
2482	    }
2483	    else if (pmap->green[pix].refcnt != AllocPrivate)
2484	    {
2485		errVal = BadAccess;
2486		ok = FALSE;
2487	    }
2488	    else if (pdef->flags & DoGreen)
2489	    {
2490		pmap->green[pix].co.local.green = pdef->green;
2491	    }
2492	    else
2493	    {
2494		pdef->green = pmap->green[pix].co.local.green;
2495	    }
2496
2497	    pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
2498	    if (pix >= numblue)
2499	    {
2500		errVal = BadValue;
2501		ok = FALSE;
2502	    }
2503	    else if (pmap->blue[pix].refcnt != AllocPrivate)
2504	    {
2505		errVal = BadAccess;
2506		ok = FALSE;
2507	    }
2508	    else if (pdef->flags & DoBlue)
2509	    {
2510		pmap->blue[pix].co.local.blue = pdef->blue;
2511	    }
2512	    else
2513	    {
2514		pdef->blue = pmap->blue[pix].co.local.blue;
2515	    }
2516	    /* If this is an o.k. entry, then it gets added to the list
2517	     * to be sent to the hardware.  If not, skip it.  Once we've
2518	     * skipped one, we have to copy all the others.
2519	     */
2520	    if(ok)
2521	    {
2522		if(idef != n)
2523		    defs[idef] = defs[n];
2524		idef++;
2525	    } else
2526		client->errorValue = pdef->pixel;
2527	}
2528    }
2529    else
2530    {
2531        for (pdef = defs, n = 0; n < count; pdef++, n++)
2532	{
2533
2534	    ok = TRUE;
2535	    if (pdef->pixel >= pVisual->ColormapEntries)
2536	    {
2537		client->errorValue = pdef->pixel;
2538	        errVal = BadValue;
2539		ok = FALSE;
2540	    }
2541	    else if (pmap->red[pdef->pixel].refcnt != AllocPrivate)
2542	    {
2543		errVal = BadAccess;
2544		ok = FALSE;
2545	    }
2546
2547	    /* If this is an o.k. entry, then it gets added to the list
2548	     * to be sent to the hardware.  If not, skip it.  Once we've
2549	     * skipped one, we have to copy all the others.
2550	     */
2551	    if(ok)
2552	    {
2553		if(idef != n)
2554		    defs[idef] = defs[n];
2555		idef++;
2556	    }
2557	    else
2558		continue;
2559
2560            (*pmap->pScreen->ResolveColor)
2561	        (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
2562
2563	    pent = &pmap->red[pdef->pixel];
2564
2565	    if(pdef->flags & DoRed)
2566	    {
2567		if(pent->fShared)
2568		{
2569		    pent->co.shco.red->color = pdef->red;
2570		    if (pent->co.shco.red->refcnt > 1)
2571			ok = FALSE;
2572		}
2573		else
2574		    pent->co.local.red = pdef->red;
2575	    }
2576	    else
2577	    {
2578		if(pent->fShared)
2579		    pdef->red = pent->co.shco.red->color;
2580		else
2581		    pdef->red = pent->co.local.red;
2582	    }
2583	    if(pdef->flags & DoGreen)
2584	    {
2585		if(pent->fShared)
2586		{
2587		    pent->co.shco.green->color = pdef->green;
2588		    if (pent->co.shco.green->refcnt > 1)
2589			ok = FALSE;
2590		}
2591		else
2592		    pent->co.local.green = pdef->green;
2593	    }
2594	    else
2595	    {
2596		if(pent->fShared)
2597		    pdef->green = pent->co.shco.green->color;
2598		else
2599		    pdef->green = pent->co.local.green;
2600	    }
2601	    if(pdef->flags & DoBlue)
2602	    {
2603		if(pent->fShared)
2604		{
2605		    pent->co.shco.blue->color = pdef->blue;
2606		    if (pent->co.shco.blue->refcnt > 1)
2607			ok = FALSE;
2608		}
2609		else
2610		    pent->co.local.blue = pdef->blue;
2611	    }
2612	    else
2613	    {
2614		if(pent->fShared)
2615		    pdef->blue = pent->co.shco.blue->color;
2616		else
2617		    pdef->blue = pent->co.local.blue;
2618	    }
2619
2620	    if(!ok)
2621	    {
2622                /* have to run through the colormap and change anybody who
2623		 * shares this value */
2624	        pred = pent->co.shco.red;
2625	        pgreen = pent->co.shco.green;
2626	        pblue = pent->co.shco.blue;
2627	        ChgRed = pdef->flags & DoRed;
2628	        ChgGreen = pdef->flags & DoGreen;
2629	        ChgBlue = pdef->flags & DoBlue;
2630	        pentLast = pmap->red + pVisual->ColormapEntries;
2631
2632	        for(pentT = pmap->red; pentT < pentLast; pentT++)
2633		{
2634		    if(pentT->fShared && (pentT != pent))
2635		    {
2636			xColorItem	defChg;
2637
2638			/* There are, alas, devices in this world too dumb
2639			 * to read their own hardware colormaps.  Sick, but
2640			 * true.  So we're going to be really nice and load
2641			 * the xColorItem with the proper value for all the
2642			 * fields.  We will only set the flags for those
2643			 * fields that actually change.  Smart devices can
2644			 * arrange to change only those fields.  Dumb devices
2645			 * can rest assured that we have provided for them,
2646			 * and can change all three fields */
2647
2648			defChg.flags = 0;
2649			if(ChgRed && pentT->co.shco.red == pred)
2650			{
2651			    defChg.flags |= DoRed;
2652			}
2653			if(ChgGreen && pentT->co.shco.green == pgreen)
2654			{
2655			    defChg.flags |= DoGreen;
2656			}
2657			if(ChgBlue && pentT->co.shco.blue == pblue)
2658			{
2659			    defChg.flags |= DoBlue;
2660			}
2661			if(defChg.flags != 0)
2662			{
2663			    defChg.pixel = pentT - pmap->red;
2664			    defChg.red = pentT->co.shco.red->color;
2665			    defChg.green = pentT->co.shco.green->color;
2666			    defChg.blue = pentT->co.shco.blue->color;
2667			    (*pmap->pScreen->StoreColors) (pmap, 1, &defChg);
2668			}
2669		    }
2670		}
2671
2672	    }
2673	}
2674    }
2675    /* Note that we use idef, the count of acceptable entries, and not
2676     * count, the count of proposed entries */
2677    if (idef != 0)
2678	( *pmap->pScreen->StoreColors) (pmap, idef, defs);
2679    return errVal;
2680}
2681
2682int
2683IsMapInstalled(Colormap map, WindowPtr pWin)
2684{
2685    Colormap	*pmaps;
2686    int		imap, nummaps, found;
2687
2688    pmaps = malloc(pWin->drawable.pScreen->maxInstalledCmaps*sizeof(Colormap));
2689    if(!pmaps)
2690	return FALSE;
2691    nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
2692        (pWin->drawable.pScreen, pmaps);
2693    found = FALSE;
2694    for(imap = 0; imap < nummaps; imap++)
2695    {
2696	if(pmaps[imap] == map)
2697	{
2698	    found = TRUE;
2699	    break;
2700	}
2701    }
2702    free(pmaps);
2703    return found;
2704}
2705
2706struct colormap_lookup_data {
2707    ScreenPtr pScreen;
2708    VisualPtr visuals;
2709};
2710
2711static void _colormap_find_resource(pointer value, XID id,
2712				    pointer cdata)
2713{
2714    struct colormap_lookup_data *cmap_data = cdata;
2715    VisualPtr visuals = cmap_data->visuals;
2716    ScreenPtr pScreen = cmap_data->pScreen;
2717    ColormapPtr cmap = value;
2718    int j;
2719
2720    if (pScreen != cmap->pScreen)
2721	return;
2722
2723    j = cmap->pVisual - pScreen->visuals;
2724    cmap->pVisual = &visuals[j];
2725}
2726
2727/* something has realloced the visuals, instead of breaking
2728   ABI fix it up here - glx and compsite did this wrong */
2729Bool
2730ResizeVisualArray(ScreenPtr pScreen, int new_visual_count,
2731		  DepthPtr depth)
2732{
2733    struct colormap_lookup_data cdata;
2734    int numVisuals;
2735    VisualPtr visuals;
2736    XID *vids, vid;
2737    int first_new_vid, first_new_visual, i;
2738
2739    first_new_vid = depth->numVids;
2740    first_new_visual = pScreen->numVisuals;
2741
2742    vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID));
2743    if (!vids)
2744        return FALSE;
2745
2746    /* its realloced now no going back if we fail the next one */
2747    depth->vids = vids;
2748
2749    numVisuals = pScreen->numVisuals + new_visual_count;
2750    visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec));
2751    if (!visuals) {
2752	return FALSE;
2753    }
2754
2755    cdata.visuals = visuals;
2756    cdata.pScreen = pScreen;
2757    FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata);
2758
2759    pScreen->visuals = visuals;
2760
2761    for (i = 0; i < new_visual_count; i++) {
2762	vid = FakeClientID(0);
2763	pScreen->visuals[first_new_visual + i].vid = vid;
2764	vids[first_new_vid + i] = vid;
2765    }
2766
2767    depth->numVids += new_visual_count;
2768    pScreen->numVisuals += new_visual_count;
2769
2770    return TRUE;
2771}
2772