1 /***********************************************************
3 Copyright (c) 1987 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 ******************************************************************/
49 /* $XConsortium: colormap.c /main/71 1996/06/17 11:01:33 mor $ */
50 /* $XFree86: xc/programs/Xserver/dix/colormap.c,v 3.1 1996/12/23 06:29:34 dawes Exp $ */
57 #include "colormapst.h"
59 #include "scrnintstr.h"
61 #include "windowstr.h"
63 extern XID clientErrorValue;
65 static Pixel FindBestPixel(
66 #if NeedFunctionPrototypes
67 EntryPtr /*pentFirst*/,
75 #if NeedFunctionPrototypes
82 #if NeedFunctionPrototypes
89 #if NeedFunctionPrototypes
96 #if NeedFunctionPrototypes
102 static void FreePixels(
103 #if NeedFunctionPrototypes
104 register ColormapPtr /*pmap*/,
105 register int /*client*/
109 static void CopyFree(
110 #if NeedFunctionPrototypes
113 ColormapPtr /*pmapSrc*/,
114 ColormapPtr /*pmapDst*/
118 static void FreeCell(
119 #if NeedFunctionPrototypes
120 ColormapPtr /*pmap*/,
126 static void UpdateColors(
127 #if NeedFunctionPrototypes
132 static int AllocDirect(
133 #if NeedFunctionPrototypes
135 ColormapPtr /*pmap*/,
148 static int AllocPseudo(
149 #if NeedFunctionPrototypes
151 ColormapPtr /*pmap*/,
157 Pixel ** /*pppixFirst*/
162 #if NeedFunctionPrototypes
163 ColormapPtr /*pmap*/,
164 EntryPtr /*pentFirst*/,
173 static Bool AllocShared(
174 #if NeedFunctionPrototypes
175 ColormapPtr /*pmap*/,
184 Pixel * /*ppixFirst*/
189 #if NeedFunctionPrototypes
190 ColormapPtr /*pmap*/,
199 static int TellNoMap(
200 #if NeedFunctionPrototypes
206 #define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1)
207 #define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1)
208 #define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1)
209 #define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask)
211 /* GetNextBitsOrBreak(bits, mask, base) --
212 * (Suggestion: First read the macro, then read this explanation.
214 * Either generate the next value to OR in to a pixel or break out of this
217 * This macro is used when we're trying to generate all 2^n combinations of
218 * bits in mask. What we're doing here is counting in binary, except that
219 * the bits we use to count may not be contiguous. This macro will be
220 * called 2^n times, returning a different value in bits each time. Then
221 * it will cause us to break out of a surrounding loop. (It will always be
222 * called from within a while loop.)
223 * On call: mask is the value we want to find all the combinations for
224 * base has 1 bit set where the least significant bit of mask is set
226 * For example,if mask is 01010, base should be 0010 and we count like this:
227 * 00010 (see this isn't so hard),
228 * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so
229 * we add that to bits getting (0100 + 0100) =
230 * 01000 for our next value.
231 * then we add 0010 to get
232 * 01010 and we're done (easy as 1, 2, 3)
234 #define GetNextBitsOrBreak(bits, mask, base) \
235 if((bits) == (mask)) \
238 while((bits) & ~(mask)) \
239 (bits) += ((bits) & ~(mask));
240 /* ID of server as client */
243 typedef struct _colorResource
250 * refcnt == 0 means entry is empty
251 * refcnt > 0 means entry is useable by many clients, so it can't be changed
252 * refcnt == AllocPrivate means entry owned by one client only
253 * fShared should only be set if refcnt == AllocPrivate, and only in red map
257 /* Create and initialize the color map */
259 CreateColormap (mid, pScreen, pVisual, ppcmap, alloc, client)
260 Colormap mid; /* resource to use for this colormap */
264 int alloc; /* 1 iff all entries are allocated writeable */
268 unsigned long sizebytes;
270 register EntryPtr pent;
272 register Pixel *ppix, **pptr;
273 extern int colormapPrivateCount;
275 class = pVisual->class;
276 if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID))
279 size = pVisual->ColormapEntries;
280 sizebytes = (size * sizeof(Entry)) +
281 (MAXCLIENTS * sizeof(Pixel *)) +
282 (MAXCLIENTS * sizeof(int));
283 if ((class | DynamicClass) == DirectColor)
285 sizebytes += sizeof(ColormapRec);
286 pmap = (ColormapPtr) xalloc(sizebytes);
289 pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec));
290 sizebytes = size * sizeof(Entry);
291 pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes);
292 pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed +
293 (MAXCLIENTS * sizeof(Pixel *)));
295 pmap->flags = 0; /* start out with all flags clear */
296 if(mid == pScreen->defColormap)
297 pmap->flags |= IsDefault;
298 pmap->pScreen = pScreen;
299 pmap->pVisual = pVisual;
301 if ((class | DynamicClass) == DirectColor)
302 size = NUMRED(pVisual);
303 pmap->freeRed = size;
304 bzero ((char *) pmap->red, (int)sizebytes);
305 bzero((char *) pmap->numPixelsRed, MAXCLIENTS * sizeof(int));
306 for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; )
307 *pptr = (Pixel *)NULL;
308 if (alloc == AllocAll)
310 if (class & DynamicClass)
311 pmap->flags |= AllAllocated;
312 for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--)
313 pent->refcnt = AllocPrivate;
315 ppix = (Pixel *)xalloc(size * sizeof(Pixel));
321 pmap->clientPixelsRed[client] = ppix;
322 for(i = 0; i < size; i++)
324 pmap->numPixelsRed[client] = size;
327 if ((class | DynamicClass) == DirectColor)
329 pmap->freeGreen = NUMGREEN(pVisual);
330 pmap->green = (EntryPtr)((char *)pmap->numPixelsRed +
331 (MAXCLIENTS * sizeof(int)));
332 pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes);
333 pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen +
334 (MAXCLIENTS * sizeof(Pixel *)));
335 pmap->freeBlue = NUMBLUE(pVisual);
336 pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen +
337 (MAXCLIENTS * sizeof(int)));
338 pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes);
339 pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue +
340 (MAXCLIENTS * sizeof(Pixel *)));
342 bzero ((char *) pmap->green, (int)sizebytes);
343 bzero ((char *) pmap->blue, (int)sizebytes);
345 memmove((char *) pmap->clientPixelsGreen,
346 (char *) pmap->clientPixelsRed,
347 MAXCLIENTS * sizeof(Pixel *));
348 memmove((char *) pmap->clientPixelsBlue,
349 (char *) pmap->clientPixelsRed,
350 MAXCLIENTS * sizeof(Pixel *));
351 bzero((char *) pmap->numPixelsGreen, MAXCLIENTS * sizeof(int));
352 bzero((char *) pmap->numPixelsBlue, MAXCLIENTS * sizeof(int));
354 /* If every cell is allocated, mark its refcnt */
355 if (alloc == AllocAll)
357 size = pmap->freeGreen;
358 for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--)
359 pent->refcnt = AllocPrivate;
361 ppix = (Pixel *) xalloc(size * sizeof(Pixel));
364 xfree(pmap->clientPixelsRed[client]);
368 pmap->clientPixelsGreen[client] = ppix;
369 for(i = 0; i < size; i++)
371 pmap->numPixelsGreen[client] = size;
373 size = pmap->freeBlue;
374 for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--)
375 pent->refcnt = AllocPrivate;
377 ppix = (Pixel *) xalloc(size * sizeof(Pixel));
380 xfree(pmap->clientPixelsGreen[client]);
381 xfree(pmap->clientPixelsRed[client]);
385 pmap->clientPixelsBlue[client] = ppix;
386 for(i = 0; i < size; i++)
388 pmap->numPixelsBlue[client] = size;
391 if (!AddResource(mid, RT_COLORMAP, (pointer)pmap))
393 /* If the device wants a chance to initialize the colormap in any way,
394 * this is it. In specific, if this is a Static colormap, this is the
395 * time to fill in the colormap's values */
396 pmap->flags |= BeingCreated;
400 * Allocate the array of devPrivate's for this colormap.
403 if (colormapPrivateCount == 0)
404 pmap->devPrivates = NULL;
407 pmap->devPrivates = (DevUnion *) xalloc (
408 colormapPrivateCount * sizeof(DevUnion));
410 if (!pmap->devPrivates)
412 FreeResource (mid, RT_NONE);
417 if (!(*pScreen->CreateColormap)(pmap))
419 FreeResource (mid, RT_NONE);
422 pmap->flags &= ~BeingCreated;
428 FreeColormap (value, mid)
429 pointer value; /* must conform to DeleteType */
433 register EntryPtr pent;
434 ColormapPtr pmap = (ColormapPtr)value;
436 if(CLIENT_ID(mid) != SERVER_ID)
438 (*pmap->pScreen->UninstallColormap) (pmap);
439 WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid);
442 /* This is the device's chance to undo anything it needs to, especially
443 * to free any storage it allocated */
444 (*pmap->pScreen->DestroyColormap)(pmap);
446 if(pmap->clientPixelsRed)
448 for(i = 0; i < MAXCLIENTS; i++)
449 xfree(pmap->clientPixelsRed[i]);
452 if ((pmap->class == PseudoColor) || (pmap->class == GrayScale))
454 for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1];
460 if (--pent->co.shco.red->refcnt == 0)
461 xfree(pent->co.shco.red);
462 if (--pent->co.shco.green->refcnt == 0)
463 xfree(pent->co.shco.green);
464 if (--pent->co.shco.blue->refcnt == 0)
465 xfree(pent->co.shco.blue);
469 if((pmap->class | DynamicClass) == DirectColor)
471 for(i = 0; i < MAXCLIENTS; i++)
473 xfree(pmap->clientPixelsGreen[i]);
474 xfree(pmap->clientPixelsBlue[i]);
478 if (pmap->devPrivates)
479 xfree(pmap->devPrivates);
485 /* Tell window that pmid has disappeared */
487 TellNoMap (pwin, pmid)
492 if (wColormap(pwin) == *pmid)
494 /* This should be call to DeliverEvent */
495 xE.u.u.type = ColormapNotify;
496 xE.u.colormap.window = pwin->drawable.id;
497 xE.u.colormap.colormap = None;
498 xE.u.colormap.new = TRUE;
499 xE.u.colormap.state = ColormapUninstalled;
500 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
501 if (pwin->optional) {
502 pwin->optional->colormap = None;
503 CheckWindowOptionalNeed (pwin);
507 return (WT_WALKCHILDREN);
510 /* Tell window that pmid got uninstalled */
512 TellLostMap (pwin, value)
516 Colormap *pmid = (Colormap *)value;
518 if (wColormap(pwin) == *pmid)
520 /* This should be call to DeliverEvent */
521 xE.u.u.type = ColormapNotify;
522 xE.u.colormap.window = pwin->drawable.id;
523 xE.u.colormap.colormap = *pmid;
524 xE.u.colormap.new = FALSE;
525 xE.u.colormap.state = ColormapUninstalled;
526 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
529 return (WT_WALKCHILDREN);
532 /* Tell window that pmid got installed */
534 TellGainedMap (pwin, value)
538 Colormap *pmid = (Colormap *)value;
540 if (wColormap (pwin) == *pmid)
542 /* This should be call to DeliverEvent */
543 xE.u.u.type = ColormapNotify;
544 xE.u.colormap.window = pwin->drawable.id;
545 xE.u.colormap.colormap = *pmid;
546 xE.u.colormap.new = FALSE;
547 xE.u.colormap.state = ColormapInstalled;
548 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
551 return (WT_WALKCHILDREN);
556 CopyColormapAndFree (mid, pSrc, client)
561 ColormapPtr pmap = (ColormapPtr) NULL;
562 int result, alloc, size;
567 pScreen = pSrc->pScreen;
568 pVisual = pSrc->pVisual;
570 alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ?
571 AllocAll : AllocNone;
572 size = pVisual->ColormapEntries;
574 /* If the create returns non-0, it failed */
575 result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client);
576 if(result != Success)
578 if(alloc == AllocAll)
580 memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry));
581 if((pmap->class | DynamicClass) == DirectColor)
583 memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry));
584 memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry));
586 pSrc->flags &= ~AllAllocated;
587 FreePixels(pSrc, client);
592 CopyFree(REDMAP, client, pSrc, pmap);
593 if ((pmap->class | DynamicClass) == DirectColor)
595 CopyFree(GREENMAP, client, pSrc, pmap);
596 CopyFree(BLUEMAP, client, pSrc, pmap);
598 if (pmap->class & DynamicClass)
600 /* XXX should worry about removing any RT_CMAPENTRY resource */
604 /* Helper routine for freeing large numbers of cells from a map */
606 CopyFree (channel, client, pmapSrc, pmapDst)
608 ColormapPtr pmapSrc, pmapDst;
610 int z, npix, oldFree;
611 EntryPtr pentSrcFirst, pentDstFirst;
612 EntryPtr pentSrc, pentDst;
618 default: /* so compiler can see that everything gets initialized */
620 ppix = (pmapSrc->clientPixelsRed)[client];
621 npix = (pmapSrc->numPixelsRed)[client];
622 pentSrcFirst = pmapSrc->red;
623 pentDstFirst = pmapDst->red;
624 oldFree = pmapSrc->freeRed;
627 ppix = (pmapSrc->clientPixelsGreen)[client];
628 npix = (pmapSrc->numPixelsGreen)[client];
629 pentSrcFirst = pmapSrc->green;
630 pentDstFirst = pmapDst->green;
631 oldFree = pmapSrc->freeGreen;
634 ppix = (pmapSrc->clientPixelsBlue)[client];
635 npix = (pmapSrc->numPixelsBlue)[client];
636 pentSrcFirst = pmapSrc->blue;
637 pentDstFirst = pmapDst->blue;
638 oldFree = pmapSrc->freeBlue;
642 if (pmapSrc->class & DynamicClass)
644 for(z = npix; --z >= 0; ppix++)
647 pentSrc = pentSrcFirst + *ppix;
648 pentDst = pentDstFirst + *ppix;
649 if (pentDst->refcnt > 0)
657 if (pentSrc->refcnt > 0)
660 pentSrc->fShared = FALSE;
662 FreeCell(pmapSrc, *ppix, channel);
666 /* Note that FreeCell has already fixed pmapSrc->free{Color} */
670 pmapDst->freeRed -= nalloc;
671 (pmapDst->clientPixelsRed)[client] =
672 (pmapSrc->clientPixelsRed)[client];
673 (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL;
674 (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client];
675 (pmapSrc->numPixelsRed)[client] = 0;
678 pmapDst->freeGreen -= nalloc;
679 (pmapDst->clientPixelsGreen)[client] =
680 (pmapSrc->clientPixelsGreen)[client];
681 (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL;
682 (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client];
683 (pmapSrc->numPixelsGreen)[client] = 0;
686 pmapDst->freeBlue -= nalloc;
687 pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client];
688 pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL;
689 pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client];
690 pmapSrc->numPixelsBlue[client] = 0;
695 /* Free the ith entry in a color map. Must handle freeing of
696 * colors allocated through AllocColorPlanes */
698 FreeCell (pmap, i, channel)
709 default: /* so compiler can see that everything gets initialized */
712 pent = (EntryPtr) &pmap->red[i];
713 pCount = &pmap->freeRed;
716 pent = (EntryPtr) &pmap->green[i];
717 pCount = &pmap->freeGreen;
720 pent = (EntryPtr) &pmap->blue[i];
721 pCount = &pmap->freeBlue;
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)
730 /* If the color type is shared, find the sharedcolor. If decremented
731 * refcnt is 0, free the shared cell. */
734 if(--pent->co.shco.red->refcnt == 0)
735 xfree(pent->co.shco.red);
736 if(--pent->co.shco.green->refcnt == 0)
737 xfree(pent->co.shco.green);
738 if(--pent->co.shco.blue->refcnt == 0)
739 xfree(pent->co.shco.blue);
740 pent->fShared = FALSE;
752 register xColorItem *pdef;
753 register EntryPtr pent;
754 register VisualPtr pVisual;
757 pVisual = pmap->pVisual;
758 size = pVisual->ColormapEntries;
759 defs = (xColorItem *)ALLOCATE_LOCAL(size * sizeof(xColorItem));
764 if (pmap->class == DirectColor)
766 for (i = 0; i < size; i++)
768 if (!pmap->red[i].refcnt &&
769 !pmap->green[i].refcnt &&
770 !pmap->blue[i].refcnt)
772 pdef->pixel = ((Pixel)i << pVisual->offsetRed) |
773 ((Pixel)i << pVisual->offsetGreen) |
774 ((Pixel)i << pVisual->offsetBlue);
775 pdef->red = pmap->red[i].co.local.red;
776 pdef->green = pmap->green[i].co.local.green;
777 pdef->blue = pmap->blue[i].co.local.blue;
778 pdef->flags = DoRed|DoGreen|DoBlue;
785 for (i = 0, pent = pmap->red; i < size; i++, pent++)
792 pdef->red = pent->co.shco.red->color;
793 pdef->green = pent->co.shco.green->color;
794 pdef->blue = pent->co.shco.blue->color;
798 pdef->red = pent->co.local.red;
799 pdef->green = pent->co.local.green;
800 pdef->blue = pent->co.local.blue;
802 pdef->flags = DoRed|DoGreen|DoBlue;
808 (*pmap->pScreen->StoreColors)(pmap, n, defs);
809 DEALLOCATE_LOCAL(defs);
812 /* Get a read-only color from a ColorMap (probably slow for large maps)
813 * Returns by changing the value in pred, pgreen, pblue and pPix
816 AllocColor (pmap, pred, pgreen, pblue, pPix, client)
818 unsigned short *pred, *pgreen, *pblue;
822 Pixel pixR, pixG, pixB;
830 pVisual = pmap->pVisual;
831 (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual);
836 entries = pVisual->ColormapEntries;
838 /* If the colormap is being created, then we want to be able to change
839 * the colormap, even if it's a static type. Otherwise, we'd never be
840 * able to initialize static colormaps
842 if(pmap->flags & BeingCreated)
843 class |= DynamicClass;
845 /* If this is one of the static storage classes, and we're not initializing
846 * it, the best we can do is to find the closest color entry to the
847 * requested one and return that.
852 /* Look up all three components in the same pmap */
853 *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
854 *pred = pmap->red[pixR].co.local.red;
855 *pgreen = pmap->red[pixR].co.local.green;
856 *pblue = pmap->red[pixR].co.local.blue;
857 npix = pmap->numPixelsRed[client];
858 ppix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
859 (npix + 1) * sizeof(Pixel));
863 pmap->clientPixelsRed[client] = ppix;
864 pmap->numPixelsRed[client]++;
868 /* Look up each component in its own map, then OR them together */
869 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
870 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
871 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
872 *pPix = (pixR << pVisual->offsetRed) |
873 (pixG << pVisual->offsetGreen) |
874 (pixB << pVisual->offsetBlue);
875 *pred = pmap->red[pixR].co.local.red;
876 *pgreen = pmap->green[pixG].co.local.green;
877 *pblue = pmap->blue[pixB].co.local.blue;
878 npix = pmap->numPixelsRed[client];
879 ppix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
880 (npix + 1) * sizeof(Pixel));
884 pmap->clientPixelsRed[client] = ppix;
885 npix = pmap->numPixelsGreen[client];
886 ppix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client],
887 (npix + 1) * sizeof(Pixel));
891 pmap->clientPixelsGreen[client] = ppix;
892 npix = pmap->numPixelsBlue[client];
893 ppix = (Pixel *) xrealloc(pmap->clientPixelsBlue[client],
894 (npix + 1) * sizeof(Pixel));
898 pmap->clientPixelsBlue[client] = ppix;
899 pmap->numPixelsRed[client]++;
900 pmap->numPixelsGreen[client]++;
901 pmap->numPixelsBlue[client]++;
906 if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP,
907 client, AllComp) != Success)
912 pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
913 if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
914 client, RedComp) != Success)
916 pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
917 if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
918 GREENMAP, client, GreenComp) != Success)
920 (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
923 pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
924 if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
925 client, BlueComp) != Success)
927 (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0);
928 (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
931 *pPix = pixR | pixG | pixB;
935 /* if this is the client's first pixel in this colormap, tell the
936 * resource manager that the client has pixels in this colormap which
937 * should be freed when the client dies */
938 if ((pmap->numPixelsRed[client] == 1) &&
939 (CLIENT_ID(pmap->mid) != client) &&
940 !(pmap->flags & BeingCreated))
944 pcr = (colorResource *) xalloc(sizeof(colorResource));
947 (void)FreeColors(pmap, client, 1, pPix, (Pixel)0);
950 pcr->mid = pmap->mid;
951 pcr->client = client;
952 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
959 * FakeAllocColor -- fake an AllocColor request by
960 * returning a free pixel if availible, otherwise returning
961 * the closest matching pixel. This is used by the mi
962 * software sprite code to recolor cursors. A nice side-effect
963 * is that this routine will never return failure.
967 FakeAllocColor (pmap, item)
968 register ColormapPtr pmap;
969 register xColorItem *item;
971 Pixel pixR, pixG, pixB;
976 register VisualPtr pVisual;
978 pVisual = pmap->pVisual;
980 rgb.green = item->green;
981 rgb.blue = item->blue;
982 (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual);
984 entries = pVisual->ColormapEntries;
990 if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP,
991 -1, AllComp) == Success) {
995 /* fall through ... */
998 item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
1002 /* Look up each component in its own map, then OR them together */
1003 pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed;
1004 pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1005 pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1006 if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
1007 -1, RedComp) != Success)
1008 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP)
1009 << pVisual->offsetRed;
1010 if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
1011 GREENMAP, -1, GreenComp) != Success)
1012 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb,
1013 GREENMAP) << pVisual->offsetGreen;
1014 if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
1015 -1, BlueComp) != Success)
1016 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP)
1017 << pVisual->offsetBlue;
1018 item->pixel = pixR | pixG | pixB;
1022 /* Look up each component in its own map, then OR them together */
1023 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
1024 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
1025 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
1026 item->pixel = (pixR << pVisual->offsetRed) |
1027 (pixG << pVisual->offsetGreen) |
1028 (pixB << pVisual->offsetBlue);
1033 /* free a pixel value obtained from FakeAllocColor */
1035 FakeFreeColor(pmap, pixel)
1036 register ColormapPtr pmap;
1039 register VisualPtr pVisual;
1040 Pixel pixR, pixG, pixB;
1042 switch (pmap->class) {
1045 if (pmap->red[pixel].refcnt == AllocTemporary)
1046 pmap->red[pixel].refcnt = 0;
1049 pVisual = pmap->pVisual;
1050 pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed;
1051 pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1052 pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1053 if (pmap->red[pixR].refcnt == AllocTemporary)
1054 pmap->red[pixR].refcnt = 0;
1055 if (pmap->green[pixG].refcnt == AllocTemporary)
1056 pmap->green[pixG].refcnt = 0;
1057 if (pmap->blue[pixB].refcnt == AllocTemporary)
1058 pmap->blue[pixB].refcnt = 0;
1063 typedef unsigned short BigNumUpper;
1064 typedef unsigned long BigNumLower;
1066 #define BIGNUMLOWERBITS 24
1067 #define BIGNUMUPPERBITS 16
1068 #define BIGNUMLOWER (1 << BIGNUMLOWERBITS)
1069 #define BIGNUMUPPER (1 << BIGNUMUPPERBITS)
1070 #define UPPERPART(i) ((i) >> BIGNUMLOWERBITS)
1071 #define LOWERPART(i) ((i) & (BIGNUMLOWER - 1))
1073 typedef struct _bignum {
1076 } BigNumRec, *BigNumPtr;
1078 #define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\
1079 ((x)->upper == (y)->upper && (x)->lower > (y)->lower))
1081 #define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \
1082 ((r)->lower = LOWERPART(u)))
1084 #define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \
1085 ((r)->lower = BIGNUMLOWER-1))
1088 #if NeedFunctionPrototypes
1089 BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r)
1095 BigNumLower lower, carry = 0;
1097 lower = x->lower + y->lower;
1098 if (lower >= BIGNUMLOWER) {
1099 lower -= BIGNUMLOWER;
1103 r->upper = x->upper + y->upper + carry;
1107 FindBestPixel(pentFirst, size, prgb, channel)
1117 BigNumRec minval, sum, temp;
1121 /* look for the minimal difference */
1122 for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++)
1128 dg = pent->co.local.green - prgb->green;
1129 db = pent->co.local.blue - prgb->blue;
1131 dr = pent->co.local.red - prgb->red;
1134 dg = pent->co.local.green - prgb->green;
1137 db = pent->co.local.blue - prgb->blue;
1141 UnsignedToBigNum (sq, &sum);
1143 UnsignedToBigNum (sq, &temp);
1144 BigNumAdd (&sum, &temp, &sum);
1146 UnsignedToBigNum (sq, &temp);
1147 BigNumAdd (&sum, &temp, &sum);
1148 if (BigNumGreater (&minval, &sum))
1157 /* Tries to find a color in pmap that exactly matches the one requested in prgb
1158 * if it can't it allocates one.
1159 * Starts looking at pentFirst + *pPixel, so if you want a specific pixel,
1160 * load *pPixel with that value, otherwise set it to 0
1163 FindColor (pmap, pentFirst, size, prgb, pPixel, channel, client, comp)
1171 ColorCompareProcPtr comp;
1176 int npix, count, *nump;
1177 Pixel **pixp, *ppix;
1182 if((pixel = *pPixel) >= size)
1184 /* see if there is a match, and also look for a free entry */
1185 for (pent = pentFirst + pixel, count = size; --count >= 0; )
1187 if (pent->refcnt > 0)
1189 if ((*comp) (pent, prgb))
1197 *pPixel <<= pmap->pVisual->offsetRed;
1201 *pPixel <<= pmap->pVisual->offsetGreen;
1204 *pPixel <<= pmap->pVisual->offsetBlue;
1210 else if (!foundFree && pent->refcnt == 0)
1214 /* If we're initializing the colormap, then we are looking for
1215 * the first free cell we can find, not to minimize the number
1216 * of entries we use. So don't look any further. */
1217 if(pmap->flags & BeingCreated)
1230 /* If we got here, we didn't find a match. If we also didn't find
1231 * a free entry, we're out of luck. Otherwise, we'll usurp a free
1232 * entry and fill it in */
1235 pent = pentFirst + Free;
1236 pent->fShared = FALSE;
1237 pent->refcnt = (client >= 0) ? 1 : AllocTemporary;
1242 pent->co.local.red = prgb->red;
1243 pent->co.local.green = prgb->green;
1244 pent->co.local.blue = prgb->blue;
1245 def.red = prgb->red;
1246 def.green = prgb->green;
1247 def.blue = prgb->blue;
1248 def.flags = (DoRed|DoGreen|DoBlue);
1255 pent->co.local.red = prgb->red;
1256 def.red = prgb->red;
1257 def.green = pmap->green[0].co.local.green;
1258 def.blue = pmap->blue[0].co.local.blue;
1262 def.pixel = Free << pmap->pVisual->offsetRed;
1266 pent->co.local.green = prgb->green;
1267 def.red = pmap->red[0].co.local.red;
1268 def.green = prgb->green;
1269 def.blue = pmap->blue[0].co.local.blue;
1270 def.flags = DoGreen;
1273 def.pixel = Free << pmap->pVisual->offsetGreen;
1277 pent->co.local.blue = prgb->blue;
1278 def.red = pmap->red[0].co.local.red;
1279 def.green = pmap->green[0].co.local.green;
1280 def.blue = prgb->blue;
1284 def.pixel = Free << pmap->pVisual->offsetBlue;
1287 (*pmap->pScreen->StoreColors) (pmap, 1, &def);
1289 *pPixel = def.pixel;
1292 if (pmap->flags & BeingCreated || client == -1)
1294 /* Now remember the pixel, for freeing later */
1299 nump = pmap->numPixelsRed;
1300 pixp = pmap->clientPixelsRed;
1304 nump = pmap->numPixelsGreen;
1305 pixp = pmap->clientPixelsGreen;
1309 nump = pmap->numPixelsBlue;
1310 pixp = pmap->clientPixelsBlue;
1313 npix = nump[client];
1314 ppix = (Pixel *) xrealloc (pixp[client], (npix + 1) * sizeof(Pixel));
1335 pixp[client] = ppix;
1341 /* Comparison functions -- passed to FindColor to determine if an
1342 * entry is already the color we're looking for or not */
1344 AllComp (pent, prgb)
1348 if((pent->co.local.red == prgb->red) &&
1349 (pent->co.local.green == prgb->green) &&
1350 (pent->co.local.blue == prgb->blue) )
1356 RedComp (pent, prgb)
1360 if (pent->co.local.red == prgb->red)
1366 GreenComp (pent, prgb)
1370 if (pent->co.local.green == prgb->green)
1376 BlueComp (pent, prgb)
1380 if (pent->co.local.blue == prgb->blue)
1386 /* Read the color value of a cell */
1389 QueryColors (pmap, count, ppixIn, prgbList)
1400 int errVal = Success;
1402 pVisual = pmap->pVisual;
1403 if ((pmap->class | DynamicClass) == DirectColor)
1405 int numred, numgreen, numblue;
1408 numred = NUMRED(pVisual);
1409 numgreen = NUMGREEN(pVisual);
1410 numblue = NUMBLUE(pVisual);
1411 rgbbad = ~RGBMASK(pVisual);
1412 for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
1415 if (pixel & rgbbad) {
1416 clientErrorValue = pixel;
1420 i = (pixel & pVisual->redMask) >> pVisual->offsetRed;
1423 clientErrorValue = pixel;
1427 prgb->red = pmap->red[i].co.local.red;
1428 i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
1431 clientErrorValue = pixel;
1435 prgb->green = pmap->green[i].co.local.green;
1436 i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
1439 clientErrorValue = pixel;
1443 prgb->blue = pmap->blue[i].co.local.blue;
1448 for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
1451 if (pixel >= pVisual->ColormapEntries)
1453 clientErrorValue = pixel;
1458 pent = (EntryPtr)&pmap->red[pixel];
1461 prgb->red = pent->co.shco.red->color;
1462 prgb->green = pent->co.shco.green->color;
1463 prgb->blue = pent->co.shco.blue->color;
1467 prgb->red = pent->co.local.red;
1468 prgb->green = pent->co.local.green;
1469 prgb->blue = pent->co.local.blue;
1478 FreePixels(pmap, client)
1479 register ColormapPtr pmap;
1480 register int client;
1482 register Pixel *ppix, *ppixStart;
1488 Bool anyRefCountReachedZero = 0;
1491 class = pmap->class;
1492 ppixStart = pmap->clientPixelsRed[client];
1493 if (class & DynamicClass)
1495 n = pmap->numPixelsRed[client];
1497 grabbed = LbxCheckCmapGrabbed (pmap);
1501 * If the colormap is grabbed by a proxy, the server must
1502 * notify the proxy of all cells that are freed (the refcount
1503 * has reached zero on these cells).
1506 LbxBeginFreeCellsEvent (pmap);
1507 LbxSortPixelList (ppixStart, n);
1510 for (ppix = ppixStart; --n >= 0; )
1512 FreeCell(pmap, *ppix, REDMAP);
1515 * Only PSEUDO colormaps are grabbed by LBX proxies.
1516 * Check if the ref count reached zero on this pixel.
1519 zeroRefCount = pmap->red[*ppix].refcnt == 0;
1521 anyRefCountReachedZero = 1;
1523 if (grabbed && zeroRefCount)
1524 LbxAddFreeCellToEvent (pmap, *ppix);
1530 LbxEndFreeCellsEvent (pmap);
1531 else if (anyRefCountReachedZero)
1534 * We only send LbxFreeCell events to a proxy that has the colormap
1535 * grabbed. If the colormap is not grabbed, the proxy that last
1536 * had the colormap grabbed will not be able to do a smart grab
1537 * in the future. A smart grab can only occur if the proxy is kept
1538 * up to date on every alloc/free change in the colormap.
1541 LbxDisableSmartGrab (pmap);
1547 pmap->clientPixelsRed[client] = (Pixel *) NULL;
1548 pmap->numPixelsRed[client] = 0;
1549 if ((class | DynamicClass) == DirectColor)
1551 ppixStart = pmap->clientPixelsGreen[client];
1552 if (class & DynamicClass)
1553 for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;)
1554 FreeCell(pmap, *ppix++, GREENMAP);
1556 pmap->clientPixelsGreen[client] = (Pixel *) NULL;
1557 pmap->numPixelsGreen[client] = 0;
1559 ppixStart = pmap->clientPixelsBlue[client];
1560 if (class & DynamicClass)
1561 for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; )
1562 FreeCell(pmap, *ppix++, BLUEMAP);
1564 pmap->clientPixelsBlue[client] = (Pixel *) NULL;
1565 pmap->numPixelsBlue[client] = 0;
1569 /* Free all of a client's colors and cells */
1572 FreeClientPixels (value, fakeid)
1573 pointer value; /* must conform to DeleteType */
1577 colorResource *pcr = (colorResource *)value;
1579 pmap = (ColormapPtr) LookupIDByType(pcr->mid, RT_COLORMAP);
1581 FreePixels(pmap, pcr->client);
1587 AllocColorCells (client, pmap, colors, planes, contig, ppix, masks)
1595 Pixel rmask, gmask, bmask, *ppixFirst, r, g, b;
1599 colorResource *pcr = (colorResource *)NULL;
1601 class = pmap->class;
1602 if (!(class & DynamicClass))
1603 return (BadAlloc); /* Shouldn't try on this type */
1604 oldcount = pmap->numPixelsRed[client];
1605 if (pmap->class == DirectColor)
1606 oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
1607 if (!oldcount && (CLIENT_ID(pmap->mid) != client))
1609 pcr = (colorResource *) xalloc(sizeof(colorResource));
1614 if (pmap->class == DirectColor)
1616 ok = AllocDirect (client, pmap, colors, planes, planes, planes,
1617 contig, ppix, &rmask, &gmask, &bmask);
1620 for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b)
1628 *masks++ = r | g | b;
1634 ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask,
1638 for (r = 1, n = planes; --n >= 0; r += r)
1647 /* if this is the client's first pixels in this colormap, tell the
1648 * resource manager that the client has pixels in this colormap which
1649 * should be freed when the client dies */
1650 if ((ok == Success) && pcr)
1652 pcr->mid = pmap->mid;
1653 pcr->client = client;
1654 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
1664 AllocColorPlanes (client, pmap, colors, r, g, b, contig, pixels,
1665 prmask, pgmask, pbmask)
1668 int colors, r, g, b;
1671 Pixel *prmask, *pgmask, *pbmask;
1674 Pixel mask, *ppixFirst;
1675 register Pixel shift;
1679 colorResource *pcr = (colorResource *)NULL;
1681 class = pmap->class;
1682 if (!(class & DynamicClass))
1683 return (BadAlloc); /* Shouldn't try on this type */
1684 oldcount = pmap->numPixelsRed[client];
1685 if (class == DirectColor)
1686 oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
1687 if (!oldcount && (CLIENT_ID(pmap->mid) != client))
1689 pcr = (colorResource *) xalloc(sizeof(colorResource));
1694 if (class == DirectColor)
1696 ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels,
1697 prmask, pgmask, pbmask);
1701 /* Allocate the proper pixels */
1702 /* XXX This is sort of bad, because of contig is set, we force all
1703 * r + g + b bits to be contiguous. Should only force contiguity
1706 ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels,
1711 /* now split that mask into three */
1712 *prmask = *pgmask = *pbmask = 0;
1714 for (i = r; --i >= 0; shift += shift)
1716 while (!(mask & shift))
1720 for (i = g; --i >= 0; shift += shift)
1722 while (!(mask & shift))
1726 for (i = b; --i >= 0; shift += shift)
1728 while (!(mask & shift))
1733 /* set up the shared color cells */
1734 if (!AllocShared(pmap, pixels, colors, r, g, b,
1735 *prmask, *pgmask, *pbmask, ppixFirst))
1737 (void)FreeColors(pmap, client, colors, pixels, mask);
1743 /* if this is the client's first pixels in this colormap, tell the
1744 * resource manager that the client has pixels in this colormap which
1745 * should be freed when the client dies */
1746 if ((ok == Success) && pcr)
1748 pcr->mid = pmap->mid;
1749 pcr->client = client;
1750 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
1759 AllocDirect (client, pmap, c, r, g, b, contig, pixels, prmask, pgmask, pbmask)
1765 Pixel *prmask, *pgmask, *pbmask;
1767 Pixel *ppixRed, *ppixGreen, *ppixBlue;
1768 Pixel *ppix, *pDst, *p;
1769 int npix, npixR, npixG, npixB;
1771 Pixel *rpix = 0, *gpix = 0, *bpix = 0;
1776 if ((r >= 32) || (g >= 32) || (b >= 32) ||
1777 (npixR > pmap->freeRed) || (npixR < c) ||
1778 (npixG > pmap->freeGreen) || (npixG < c) ||
1779 (npixB > pmap->freeBlue) || (npixB < c))
1782 /* start out with empty pixels */
1783 for(p = pixels; p < pixels + c; p++)
1786 ppixRed = (Pixel *)ALLOCATE_LOCAL(npixR * sizeof(Pixel));
1787 ppixGreen = (Pixel *)ALLOCATE_LOCAL(npixG * sizeof(Pixel));
1788 ppixBlue = (Pixel *)ALLOCATE_LOCAL(npixB * sizeof(Pixel));
1789 if (!ppixRed || !ppixGreen || !ppixBlue)
1791 if (ppixBlue) DEALLOCATE_LOCAL(ppixBlue);
1792 if (ppixGreen) DEALLOCATE_LOCAL(ppixGreen);
1793 if (ppixRed) DEALLOCATE_LOCAL(ppixRed);
1797 okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask);
1798 okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask);
1799 okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask);
1801 if (okR && okG && okB)
1803 rpix = (Pixel *) xrealloc(pmap->clientPixelsRed[client],
1804 (pmap->numPixelsRed[client] + (c << r)) *
1807 pmap->clientPixelsRed[client] = rpix;
1808 gpix = (Pixel *) xrealloc(pmap->clientPixelsGreen[client],
1809 (pmap->numPixelsGreen[client] + (c << g)) *
1812 pmap->clientPixelsGreen[client] = gpix;
1813 bpix = (Pixel *) xrealloc(pmap->clientPixelsBlue[client],
1814 (pmap->numPixelsBlue[client] + (c << b)) *
1817 pmap->clientPixelsBlue[client] = bpix;
1820 if (!okR || !okG || !okB || !rpix || !gpix || !bpix)
1823 for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++)
1824 pmap->red[*ppix].refcnt = 0;
1826 for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++)
1827 pmap->green[*ppix].refcnt = 0;
1829 for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++)
1830 pmap->blue[*ppix].refcnt = 0;
1831 DEALLOCATE_LOCAL(ppixBlue);
1832 DEALLOCATE_LOCAL(ppixGreen);
1833 DEALLOCATE_LOCAL(ppixRed);
1837 *prmask <<= pmap->pVisual->offsetRed;
1838 *pgmask <<= pmap->pVisual->offsetGreen;
1839 *pbmask <<= pmap->pVisual->offsetBlue;
1841 ppix = rpix + pmap->numPixelsRed[client];
1842 for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++)
1846 *pDst++ |= *p << pmap->pVisual->offsetRed;
1848 pmap->numPixelsRed[client] += npixR;
1849 pmap->freeRed -= npixR;
1851 ppix = gpix + pmap->numPixelsGreen[client];
1852 for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++)
1855 if(p < ppixGreen + c)
1856 *pDst++ |= *p << pmap->pVisual->offsetGreen;
1858 pmap->numPixelsGreen[client] += npixG;
1859 pmap->freeGreen -= npixG;
1861 ppix = bpix + pmap->numPixelsBlue[client];
1862 for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++)
1865 if(p < ppixBlue + c)
1866 *pDst++ |= *p << pmap->pVisual->offsetBlue;
1868 pmap->numPixelsBlue[client] += npixB;
1869 pmap->freeBlue -= npixB;
1871 DEALLOCATE_LOCAL(ppixBlue);
1872 DEALLOCATE_LOCAL(ppixGreen);
1873 DEALLOCATE_LOCAL(ppixRed);
1879 AllocPseudo (client, pmap, c, r, contig, pixels, pmask, pppixFirst)
1888 Pixel *ppix, *p, *pDst, *ppixTemp;
1893 if ((r >= 32) || (npix > pmap->freeRed) || (npix < c))
1895 if(!(ppixTemp = (Pixel *)ALLOCATE_LOCAL(npix * sizeof(Pixel))))
1897 ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask);
1902 /* all the allocated pixels are added to the client pixel list,
1903 * but only the unique ones are returned to the client */
1904 ppix = (Pixel *)xrealloc(pmap->clientPixelsRed[client],
1905 (pmap->numPixelsRed[client] + npix) * sizeof(Pixel));
1908 for (p = ppixTemp; p < ppixTemp + npix; p++)
1909 pmap->red[*p].refcnt = 0;
1912 pmap->clientPixelsRed[client] = ppix;
1913 ppix += pmap->numPixelsRed[client];
1916 for (p = ppixTemp; p < ppixTemp + npix; p++)
1919 if(p < ppixTemp + c)
1922 pmap->numPixelsRed[client] += npix;
1923 pmap->freeRed -= npix;
1925 DEALLOCATE_LOCAL(ppixTemp);
1926 return (ok ? Success : BadAlloc);
1929 /* Allocates count << planes pixels from colormap pmap for client. If
1930 * contig, then the plane mask is made of consecutive bits. Returns
1931 * all count << pixels in the array pixels. The first count of those
1932 * pixels are the unique pixels. *pMask has the mask to Or with the
1933 * unique pixels to get the rest of them.
1935 * Returns True iff all pixels could be allocated
1936 * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE
1937 * (see AllocShared for why we care)
1940 AllocCP (pmap, pentFirst, count, planes, contig, pixels, pMask)
1945 Pixel *pixels, *pMask;
1949 Pixel pixel, base, entries, maxp, save;
1955 dplanes = pmap->pVisual->nplanes;
1957 /* Easy case. Allocate pixels only */
1960 /* allocate writable entries */
1964 while (--count >= 0)
1966 /* Just find count unallocated cells */
1972 ent->refcnt = AllocPrivate;
1974 ent->fShared = FALSE;
1979 else if (planes > dplanes)
1984 /* General case count pixels * 2 ^ planes cells to be allocated */
1986 /* make room for new pixels */
1989 /* first try for contiguous planes, since it's fastest */
1990 for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1);
1992 mask += mask, base += base)
1997 entries = pmap->pVisual->ColormapEntries - mask;
1998 while (pixel < entries)
2001 maxp = pixel + mask + base;
2002 /* check if all are free */
2003 while (pixel != maxp && ent[pixel].refcnt == 0)
2007 /* this one works */
2012 /* found enough, allocate them all */
2013 while (--count >= 0)
2015 pixel = pixels[count];
2016 maxp = pixel + mask;
2019 ent[pixel].refcnt = AllocPrivate;
2020 ent[pixel].fShared = FALSE;
2037 dplanes = pmap->pVisual->nplanes;
2038 if (contig || planes == 1 || dplanes < 3)
2041 /* this will be very slow for large maps, need a better algorithm */
2044 we can generate the smallest and largest numbers that fits in dplanes
2045 bits and contain exactly planes bits set as follows. First, we need to
2046 check that it is possible to generate such a mask at all.
2047 (Non-contiguous masks need one more bit than contiguous masks). Then
2048 the smallest such mask consists of the rightmost planes-1 bits set, then
2049 a zero, then a one in position planes + 1. The formula is
2050 (3 << (planes-1)) -1
2051 The largest such masks consists of the leftmost planes-1 bits set, then
2052 a zero, then a one bit in position dplanes-planes-1. If dplanes is
2053 smaller than 32 (the number of bits in a word) then the formula is:
2054 (1<<dplanes) - (1<<(dplanes-planes+1) + (1<<dplanes-planes-1)
2055 If dplanes = 32, then we can't calculate (1<<dplanes) and we have
2057 ( (1<<(planes-1)) - 1) << (dplanes-planes+1) + (1<<(dplanes-planes-1))
2059 << Thank you, Loretta>>>
2064 (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) +
2065 (((Pixel)1)<<(dplanes-planes-1));
2066 for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++)
2068 /* next 3 magic statements count number of ones (HAKMEM #169) */
2069 pixel = (mask >> 1) & 033333333333;
2070 pixel = mask - pixel - ((pixel >> 1) & 033333333333);
2071 if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes)
2075 entries = pmap->pVisual->ColormapEntries - mask;
2076 base = lowbit (mask);
2077 for (pixel = 0; pixel < entries; pixel++)
2082 /* check if all are free */
2083 while (ent[pixel + maxp].refcnt == 0)
2085 GetNextBitsOrBreak(maxp, mask, base);
2087 if ((maxp < mask) || (ent[pixel + mask].refcnt != 0))
2089 /* this one works */
2094 /* found enough, allocate them all */
2095 while (--count >= 0)
2097 pixel = (pixels)[count];
2101 ent[pixel + maxp].refcnt = AllocPrivate;
2102 ent[pixel + maxp].fShared = FALSE;
2103 GetNextBitsOrBreak(maxp, mask, base);
2104 *ppix++ = pixel + maxp;
2116 AllocShared (pmap, ppix, c, r, g, b, rmask, gmask, bmask, ppixFirst)
2120 Pixel rmask, gmask, bmask;
2121 Pixel *ppixFirst; /* First of the client's new pixels */
2124 int npix, z, npixClientNew, npixShared;
2125 Pixel basemask, base, bits, common;
2126 SHAREDCOLOR *pshared, **ppshared, **psharedList;
2128 npixClientNew = c << (r + g + b);
2129 npixShared = (c << r) + (c << g) + (c << b);
2130 psharedList = (SHAREDCOLOR **)ALLOCATE_LOCAL(npixShared *
2131 sizeof(SHAREDCOLOR *));
2134 ppshared = psharedList;
2135 for (z = npixShared; --z >= 0; )
2137 if (!(ppshared[z] = (SHAREDCOLOR *)xalloc(sizeof(SHAREDCOLOR))))
2139 for (z++ ; z < npixShared; z++)
2144 for(pptr = ppix, npix = c; --npix >= 0; pptr++)
2146 basemask = ~(gmask | bmask);
2147 common = *pptr & basemask;
2151 base = lowbit (rmask);
2154 pshared = *ppshared++;
2155 pshared->refcnt = 1 << (g + b);
2156 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2158 if ((*cptr & basemask) == (common | bits))
2160 pmap->red[*cptr].fShared = TRUE;
2161 pmap->red[*cptr].co.shco.red = pshared;
2164 GetNextBitsOrBreak(bits, rmask, base);
2169 pshared = *ppshared++;
2170 pshared->refcnt = 1 << (g + b);
2171 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2173 if ((*cptr & basemask) == common)
2175 pmap->red[*cptr].fShared = TRUE;
2176 pmap->red[*cptr].co.shco.red = pshared;
2180 basemask = ~(rmask | bmask);
2181 common = *pptr & basemask;
2185 base = lowbit (gmask);
2188 pshared = *ppshared++;
2189 pshared->refcnt = 1 << (r + b);
2190 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2192 if ((*cptr & basemask) == (common | bits))
2194 pmap->red[*cptr].co.shco.green = pshared;
2197 GetNextBitsOrBreak(bits, gmask, base);
2202 pshared = *ppshared++;
2203 pshared->refcnt = 1 << (g + b);
2204 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2206 if ((*cptr & basemask) == common)
2208 pmap->red[*cptr].co.shco.green = pshared;
2212 basemask = ~(rmask | gmask);
2213 common = *pptr & basemask;
2217 base = lowbit (bmask);
2220 pshared = *ppshared++;
2221 pshared->refcnt = 1 << (r + g);
2222 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2224 if ((*cptr & basemask) == (common | bits))
2226 pmap->red[*cptr].co.shco.blue = pshared;
2229 GetNextBitsOrBreak(bits, bmask, base);
2234 pshared = *ppshared++;
2235 pshared->refcnt = 1 << (g + b);
2236 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
2238 if ((*cptr & basemask) == common)
2240 pmap->red[*cptr].co.shco.blue = pshared;
2245 DEALLOCATE_LOCAL(psharedList);
2250 /* Free colors and/or cells (probably slow for large numbers) */
2253 FreeColors (pmap, client, count, pixels, mask)
2259 int rval, result, class;
2262 class = pmap->class;
2263 if (pmap->flags & AllAllocated)
2265 if ((class | DynamicClass) == DirectColor)
2267 rmask = mask & RGBMASK(pmap->pVisual);
2268 result = FreeCo(pmap, client, REDMAP, count, pixels,
2269 mask & pmap->pVisual->redMask);
2270 /* If any of the three calls fails, we must report that, if more
2271 * than one fails, it's ok that we report the last one */
2272 rval = FreeCo(pmap, client, GREENMAP, count, pixels,
2273 mask & pmap->pVisual->greenMask);
2276 rval = FreeCo(pmap, client, BLUEMAP, count, pixels,
2277 mask & pmap->pVisual->blueMask);
2283 rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1);
2284 result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask);
2286 if ((mask != rmask) && count)
2288 clientErrorValue = *pixels | mask;
2291 /* XXX should worry about removing any RT_CMAPENTRY resource */
2295 /* Helper for FreeColors -- frees all combinations of *newpixels and mask bits
2296 * which the client has allocated in channel colormap cells of pmap.
2297 * doesn't change newpixels if it doesn't need to */
2299 FreeCo (pmap, client, color, npixIn, ppixIn, mask)
2300 ColormapPtr pmap; /* which colormap head */
2302 int color; /* which sub-map, eg RED, BLUE, PSEUDO */
2303 int npixIn; /* number of pixels passed in */
2304 Pixel *ppixIn; /* list of base pixels */
2305 Pixel mask; /* mask client gave us */
2308 Pixel *ppixClient, pixTest;
2309 int npixClient, npixNew, npix;
2310 Pixel bits, base, cmask, rgbbad;
2313 int errVal = Success;
2314 int offset, numents;
2318 Bool anyRefCountReachedZero = 0;
2325 base = lowbit (mask);
2330 cmask = pmap->pVisual->redMask;
2331 rgbbad = ~RGBMASK(pmap->pVisual);
2332 offset = pmap->pVisual->offsetRed;
2333 numents = (cmask >> offset) + 1;
2334 ppixClient = pmap->clientPixelsRed[client];
2335 npixClient = pmap->numPixelsRed[client];
2338 cmask = pmap->pVisual->greenMask;
2339 rgbbad = ~RGBMASK(pmap->pVisual);
2340 offset = pmap->pVisual->offsetGreen;
2341 numents = (cmask >> offset) + 1;
2342 ppixClient = pmap->clientPixelsGreen[client];
2343 npixClient = pmap->numPixelsGreen[client];
2346 cmask = pmap->pVisual->blueMask;
2347 rgbbad = ~RGBMASK(pmap->pVisual);
2348 offset = pmap->pVisual->offsetBlue;
2349 numents = (cmask >> offset) + 1;
2350 ppixClient = pmap->clientPixelsBlue[client];
2351 npixClient = pmap->numPixelsBlue[client];
2353 default: /* so compiler can see that everything gets initialized */
2355 cmask = ~((Pixel)0);
2358 numents = pmap->pVisual->ColormapEntries;
2359 ppixClient = pmap->clientPixelsRed[client];
2360 npixClient = pmap->numPixelsRed[client];
2365 grabbed = LbxCheckCmapGrabbed (pmap);
2370 * If the colormap is grabbed by a proxy, the server must
2371 * notify the proxy of all cells that are freed (the refcount
2372 * has reached zero on these cells).
2375 LbxBeginFreeCellsEvent (pmap);
2376 LbxSortPixelList (ppixIn, npixIn);
2380 /* zap all pixels which match */
2383 /* go through pixel list */
2384 for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++)
2386 pixTest = ((*pptr | bits) & cmask) >> offset;
2387 if ((pixTest >= numents) || (*pptr & rgbbad))
2389 clientErrorValue = *pptr | bits;
2394 /* find match in client list */
2395 for (cptr = ppixClient, npix = npixClient;
2396 --npix >= 0 && *cptr != pixTest;
2401 if (pmap->class & DynamicClass)
2403 FreeCell(pmap, pixTest, color);
2406 * Only PSEUDO colormaps are grabbed by LBX proxies.
2407 * Check if the ref count reached zero on this pixel.
2410 zeroRefCount = pmap->red[pixTest].refcnt == 0;
2412 anyRefCountReachedZero = 1;
2414 if (grabbed && zeroRefCount)
2415 LbxAddFreeCellToEvent (pmap, pixTest);
2418 *cptr = ~((Pixel)0);
2424 /* generate next bits value */
2425 GetNextBitsOrBreak(bits, mask, base);
2430 LbxEndFreeCellsEvent (pmap);
2431 else if (anyRefCountReachedZero)
2434 * We only send LbxFreeCell events to a proxy that has the colormap
2435 * grabbed. If the colormap is not grabbed, the proxy that last
2436 * had the colormap grabbed will not be able to do a smart grab
2437 * in the future. A smart grab can only occur if the proxy is kept
2438 * up to date on every alloc/free change in the colormap.
2441 LbxDisableSmartGrab (pmap);
2445 /* delete freed pixels from client pixel list */
2448 npixNew = npixClient - zapped;
2451 /* Since the list can only get smaller, we can do a copy in
2452 * place and then realloc to a smaller size */
2453 pptr = cptr = ppixClient;
2455 /* If we have all the new pixels, we don't have to examine the
2456 * rest of the old ones */
2457 for(npix = 0; npix < npixNew; cptr++)
2459 if (*cptr != ~((Pixel)0))
2465 pptr = (Pixel *)xrealloc(ppixClient, npixNew * sizeof(Pixel));
2468 npixClient = npixNew;
2474 ppixClient = (Pixel *)NULL;
2480 pmap->clientPixelsRed[client] = ppixClient;
2481 pmap->numPixelsRed[client] = npixClient;
2484 pmap->clientPixelsGreen[client] = ppixClient;
2485 pmap->numPixelsGreen[client] = npixClient;
2488 pmap->clientPixelsBlue[client] = ppixClient;
2489 pmap->numPixelsBlue[client] = npixClient;
2498 /* Redefine color values */
2500 StoreColors (pmap, count, defs)
2506 register xColorItem *pdef;
2507 register EntryPtr pent, pentT, pentLast;
2508 register VisualPtr pVisual;
2509 SHAREDCOLOR *pred, *pgreen, *pblue;
2510 int n, ChgRed, ChgGreen, ChgBlue, idef;
2511 int class, errVal = Success;
2515 class = pmap->class;
2516 if(!(class & DynamicClass) && !(pmap->flags & BeingCreated))
2520 pVisual = pmap->pVisual;
2523 if((class | DynamicClass) == DirectColor)
2525 int numred, numgreen, numblue;
2528 numred = NUMRED(pVisual);
2529 numgreen = NUMGREEN(pVisual);
2530 numblue = NUMBLUE(pVisual);
2531 rgbbad = ~RGBMASK(pVisual);
2532 for (pdef = defs, n = 0; n < count; pdef++, n++)
2535 (*pmap->pScreen->ResolveColor)
2536 (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
2538 if (pdef->pixel & rgbbad)
2541 clientErrorValue = pdef->pixel;
2544 pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed;
2550 else if (pmap->red[pix].refcnt != AllocPrivate)
2555 else if (pdef->flags & DoRed)
2557 pmap->red[pix].co.local.red = pdef->red;
2561 pdef->red = pmap->red[pix].co.local.red;
2564 pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
2565 if (pix >= numgreen)
2570 else if (pmap->green[pix].refcnt != AllocPrivate)
2575 else if (pdef->flags & DoGreen)
2577 pmap->green[pix].co.local.green = pdef->green;
2581 pdef->green = pmap->green[pix].co.local.green;
2584 pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
2590 else if (pmap->blue[pix].refcnt != AllocPrivate)
2595 else if (pdef->flags & DoBlue)
2597 pmap->blue[pix].co.local.blue = pdef->blue;
2601 pdef->blue = pmap->blue[pix].co.local.blue;
2603 /* If this is an o.k. entry, then it gets added to the list
2604 * to be sent to the hardware. If not, skip it. Once we've
2605 * skipped one, we have to copy all the others.
2610 defs[idef] = defs[n];
2613 clientErrorValue = pdef->pixel;
2618 for (pdef = defs, n = 0; n < count; pdef++, n++)
2622 if (pdef->pixel >= pVisual->ColormapEntries)
2624 clientErrorValue = pdef->pixel;
2628 else if (pmap->red[pdef->pixel].refcnt != AllocPrivate)
2634 /* If this is an o.k. entry, then it gets added to the list
2635 * to be sent to the hardware. If not, skip it. Once we've
2636 * skipped one, we have to copy all the others.
2641 defs[idef] = defs[n];
2647 (*pmap->pScreen->ResolveColor)
2648 (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
2650 pent = &pmap->red[pdef->pixel];
2652 if(pdef->flags & DoRed)
2656 pent->co.shco.red->color = pdef->red;
2657 if (pent->co.shco.red->refcnt > 1)
2661 pent->co.local.red = pdef->red;
2666 pdef->red = pent->co.shco.red->color;
2668 pdef->red = pent->co.local.red;
2670 if(pdef->flags & DoGreen)
2674 pent->co.shco.green->color = pdef->green;
2675 if (pent->co.shco.green->refcnt > 1)
2679 pent->co.local.green = pdef->green;
2684 pdef->green = pent->co.shco.green->color;
2686 pdef->green = pent->co.local.green;
2688 if(pdef->flags & DoBlue)
2692 pent->co.shco.blue->color = pdef->blue;
2693 if (pent->co.shco.blue->refcnt > 1)
2697 pent->co.local.blue = pdef->blue;
2702 pdef->blue = pent->co.shco.blue->color;
2704 pdef->blue = pent->co.local.blue;
2709 /* have to run through the colormap and change anybody who
2710 * shares this value */
2711 pred = pent->co.shco.red;
2712 pgreen = pent->co.shco.green;
2713 pblue = pent->co.shco.blue;
2714 ChgRed = pdef->flags & DoRed;
2715 ChgGreen = pdef->flags & DoGreen;
2716 ChgBlue = pdef->flags & DoBlue;
2717 pentLast = pmap->red + pVisual->ColormapEntries;
2719 for(pentT = pmap->red; pentT < pentLast; pentT++)
2721 if(pentT->fShared && (pentT != pent))
2725 /* There are, alas, devices in this world too dumb
2726 * to read their own hardware colormaps. Sick, but
2727 * true. So we're going to be really nice and load
2728 * the xColorItem with the proper value for all the
2729 * fields. We will only set the flags for those
2730 * fields that actually change. Smart devices can
2731 * arrange to change only those fields. Dumb devices
2732 * can rest assured that we have provided for them,
2733 * and can change all three fields */
2736 if(ChgRed && pentT->co.shco.red == pred)
2738 defChg.flags |= DoRed;
2740 if(ChgGreen && pentT->co.shco.green == pgreen)
2742 defChg.flags |= DoGreen;
2744 if(ChgBlue && pentT->co.shco.blue == pblue)
2746 defChg.flags |= DoBlue;
2748 if(defChg.flags != 0)
2750 defChg.pixel = pentT - pmap->red;
2751 defChg.red = pentT->co.shco.red->color;
2752 defChg.green = pentT->co.shco.green->color;
2753 defChg.blue = pentT->co.shco.blue->color;
2754 (*pmap->pScreen->StoreColors) (pmap, 1, &defChg);
2762 /* Note that we use idef, the count of acceptable entries, and not
2763 * count, the count of proposed entries */
2765 ( *pmap->pScreen->StoreColors) (pmap, idef, defs);
2770 IsMapInstalled(map, pWin)
2775 int imap, nummaps, found;
2777 pmaps = (Colormap *) ALLOCATE_LOCAL(
2778 pWin->drawable.pScreen->maxInstalledCmaps * sizeof(Colormap));
2781 nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
2782 (pWin->drawable.pScreen, pmaps);
2784 for(imap = 0; imap < nummaps; imap++)
2786 if(pmaps[imap] == map)
2792 DEALLOCATE_LOCAL(pmaps);