/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = PALMAN                                         */
/*                                                                    */
/*   Description     = Display Device Driver functions                */
/*                     Palette manager functions                      */
/*                                                                    */
/*   Function        = DeviceAnimatePalette                           */
/*                     DeviceSetPaletteEntries                        */
/*                     DeviceCreatePalette                            */
/*                     DeviceDeletePalette                            */
/*                     RealizePalette                                 */
/*                     DeviceResizePalette                            */
/*                     QueryHWPaletteInfo                             */
/*                     QueryPaletteRealization                        */
/*                     UpdateColors                                   */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/* Revisions:                                                         */
/*                                                                    */
/* 74705  10/15/93 Change Team  Obey the LCOL_OVERRIDE_DEFAULT_COLORS */
/*                              flag when an exact palette match is   */
/*                              found                                 */
/*                                                                    */
/* 78604 02/09/94                Had to add this less than elegant    */
/*                               code to compliment the the wonderful */
/*                               work done in the                     */
/*                               reducedefaultpalettesize.  The       */
/*                               default palette never goes to 16     */
/*                               colors in a seamless enabled driver, */
/*                               it goes to 20 colors to accomodate 4 */
/*                               colors from windows.  But the        */
/*                               ulDirectDeviceDefaultPaletteSize     */
/*                               variable is still 16, which is a     */
/*                               lie.  However, that value is used    */
/*                               throughout the driver and also       */
/*                               passed to the         driver so we   */
/*                               really can't change its value.  So   */
/*                               unfortuanately we will change the    */
/*                               math a little to compensate.         */
/*                                                                    */
/**********************************************************************/
#define INCL_GRE_PALETTE
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#define INCL_WINSYS
#include <eddinclt.h>

#ifdef PALETTE_MGR
#include <eddccone.h>
#include <eddhcone.h>
#include <eddmcone.h>
#include <eddvcone.h>

#include <edddtypt.h>
#include <eddhtype.h>

#include <eddbextf.h>
#include <eddcextf.h>
#include <eddgextf.h>
#include <eddmextf.h>

#include <eddhmacr.h>

#include <cursor.h>
#include <twozero.h>    /* function prototypes */
#include <memman.h>
#include <seamless.h>

#ifdef SEAMLESS
#endif /* SEAMLESS */

extern DDTType          DDT;
extern PBYTE            pPhunkVirt;
extern USHORT           SizeOfHWPalette;
extern RGB2             FullSizeDeviceDefaultPalette[];
extern RGB2             Reduced128DeviceDefaultPalette[];
extern RGB2             Reduced64DeviceDefaultPalette[];
extern RGB2             Reduced32DeviceDefaultPalette[];
extern RGB2             Reduced16DeviceDefaultPalette[];
extern RGB2             WindowsDefaultSysColors[];
extern PRGB2            DirectDeviceDefaultPalette;
extern ULONG            ulDirectDeviceDefaultPaletteSize;
extern COLORTABLETYPE   DefaultEightBppTable256[];
extern COLORTABLETYPE   DefaultEightBppTable128[];
extern COLORTABLETYPE   DefaultEightBppTable64[];
extern COLORTABLETYPE   DefaultEightBppTable32[];
extern COLORTABLETYPE   DefaultEightBppTable16[];
extern PCOLORTABLE      DefaultDirectLogicalColorTable;
extern COLORTABLETYPE   DirectSpecialColorTable[];
#ifndef   _8514
extern MMReg            ShadowXGARegs;
#else
extern MM8514Reg        Shadow8514Regs;
#endif
extern BitmapHeader     DirectListEntry;
extern SHORT            softDrawInUse;
extern HDC              ColorTableRealized;
extern CURSORDATA       cursor_data;
extern PPFNL            EnginesDispatchTable;

/**********************************************************************/
/* Tables used for AVIO colors.                                       */
/**********************************************************************/
extern RGB2             AVIOColorTable[];
extern ULONG            AVIOXlate256[];
extern ULONG            AVIOXlate128[];
extern ULONG            AVIOXlate64[];
extern ULONG            AVIOXlate32[];
extern ULONG            AVIOXlate16[];
extern PULONG           pAVIOColorXlate;

/**********************************************************************/
/* These are used by eddb_CreatePalMapping to keep track of the       */
/* current source and destination palettes used in the current        */
/* palette-palette mapping.  The palette pointers are PVOIDs because  */
/* they may point to either a DEVPAL (real palette manager palettes)  */
/* or an array of RGBs (a device default palette).                    */
/**********************************************************************/
extern PVOID            CurrentSourcePalette;
extern PVOID            CurrentDestPalette;
extern BOOL             CurrentMappingValid;

#ifdef SEAMLESS
extern SEAMLESSDATA     SeamlessData;
#endif /* SEAMLESS */

/**********************************************************************/
/* This is used by SmoothLoadPaletteEntries so that it can work out   */
/* how to smoothly change the default colors.                         */
/**********************************************************************/
ULONG  ulLastDefaultPaletteSize = 256;

RGB2    RGB2NULL = {0, 0, 0, 0};
RGB2    HWPalette[HW_PAL_SIZE];

USHORT  GlobalPalCount     = 0;
USHORT  usGlobalOptimizeID = 1;
PDEVPAL hForeGroundPal = (PDEVPAL)FullSizeDeviceDefaultPalette;
USHORT  fForeGroundOverwrote = FALSE;

#define NUM_VIS_RECTS 4
RGNRECT GetVisRectsControl;
RECTL   VisRects[NUM_VIS_RECTS];

BYTE    UCMapping[HW_PAL_SIZE];


/**********************************************************************/
/* Declare these here. They are not in any header files because they  */
/* should normally accessed using higher level query functions only.  */
/**********************************************************************/
ULONG NearestDefaultPaletteIndex128(RGB2*);
ULONG NearestDefaultPaletteIndex64(RGB2*);
ULONG NearestDefaultPaletteIndex32(RGB2*);
ULONG NearestDefaultPaletteIndex16(RGB2*);

/**********************************************************************/
/* Declare these function prototypes here because they are forward    */
/* referenced within this module, but are not referenced from any     */
/* other module.                                                      */
/**********************************************************************/
VOID  DRIVERCALL RemoveUsedMarkings(VOID);
VOID  DRIVERCALL StoreAndRemoveUsedMarkings(VOID);
ULONG DRIVERCALL IncreaseDefaultPaletteSize(VOID);


/**********************************************************************/
/*                                                                    */
/* Here is the big idea...                                            */
/*                                                                    */
/* The HW palette is divided into two parts. One part contains the    */
/* device default colors (ie the entries that non-palette manager DCs */
/* will use) and the other part contains palette manager palette      */
/* colors.  At start of day the HW palette is completely assigned to  */
/* the device default colors (there are no palette manager DCs at     */
/* start of day).  When palette manager palettes are created and      */
/* subsequently realized they need to be allocated slots in the HW    */
/* palette - the proportion of the HW palette allocated to the        */
/* default colors is reduced to produce free slots which can be       */
/* allocated to the palette manager palettes.  When less palette      */
/* manager slots are required the number of slots allocated to the    */
/* default colors is increased to improve the appereance of the       */
/* non-palette manager DCs.                                           */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* Here is the big plan...                                            */
/*                                                                    */
/* Non-palette manager DCs will only ever be allowed to use colors in */
/* a device default palette.  There are five sizes of device default  */
/* palette - 256, 128, 64, 32, and 16 entry.  (The 256 entry palette  */
/* is the same as 8514 8bpp palette.  The 16 entry palette is the     */
/* same as VGA palette).  For OD_MEMORY DCs the 256 entry device      */
/* default palette is always used.  For OD_DIRECT DCs the device      */
/* default palette will change to allow allocation of HW palette      */
/* slots to palette manager DCs.  Within the HW palette the direct    */
/* device default palette is always positioned symmetrically in two   */
/* halves at the top and the bottom of the HW palette leaving the     */
/* slots in the centre free for palette manager palettes to use.      */
/* This means that when mixing the device default colors the result   */
/* is always another device default color.  Also the colors within    */
/* the device default palettes are arranged so that the inverse mixes */
/* always give the expected results.                                  */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* The device default palettes are accessed through two pointers      */
/* DirectDeviceDefaultPalette and MemoryDeviceDefaultPalette          */
/* depending on whether an OD_DIRECT or OD_MEMORY DC is in use.  The  */
/* size of the DirectDeviceDefaultPalette is always kept in the       */
/* ulDirectDeviceDefaultPaletteSize variable.                         */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* There are also five default logical color tables corresponding to  */
/* the five different device default palettes.  Each of these color   */
/* tables have the same RGB entries in them, but they have different  */
/* indexes into the HW palette which give the nearest colors          */
/* available when each of the device default palettes is loaded into  */
/* the HW palette.                                                    */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* The default logical color tables are accessed through two pointers */
/* DefaultDirectLogicalColorTable and DefaultMemoryLogicalColorTable  */
/* depending on whether an OD_DIRECT or OD_MEMORY DC is in use.       */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* There are also two copies of the special color table (which hold   */
/* system colors and other special colors) - DirectSpecialColorTable  */
/* and MemorySpecialColorTable, corresponding to OD_DIRECT and        */
/* OD_MEMORY DCs.  Unlike the default logical color tables and the    */
/* device default palettes, these tables are changed by altering      */
/* their entries rather than by pointing to different versions of the */
/* tables.                                                            */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* Both special color tables are changed when the system colors are   */
/* changed in eddc_AlterSysColorTable.  System color changes are      */
/* propogated through the system by XGA_EnterDriver calling           */
/* eddc_PropagateSysColorChanges in the usual way with the exception  */
/* that the default logical color tables are all updated by           */
/* eddc_AlterSysColorTable immediately the system colors are changed  */
/* (for CLR_BACKGROUND and CLR_NEUTRAL).                              */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* The direct device default palette is changed by the two functions  */
/* ReduceDefaultPaletteSize and IncreaseDefaultPaletteSize.  These    */
/* functions change the ulDirectDeviceDefaultPaletteSize,             */
/* DirectDeviceDefaultPalette, and DefaultDirectLogicalColorTable     */
/* variables, and update the entries in the DirectSpecialColorTable.  */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/* To keep the logical color tables upto date in all of the DCs there */
/* is a field in the DC instance data that points to the device       */
/* default palette which was current for that DC when the physical    */
/* indexes into the palette were last calculated for that DC. When    */
/* XGA_EnterDriver is called it checks to see if this is the current  */
/* device default palette for that DC. If it is not then it updates   */
/* the logical color table and the current device default palette     */
/* field.  If the logical color table is one of the defaults then it  */
/* can be updated just by changing it to point to the current default */
/* logical color table. If the logical color table is not one of the  */
/* defaults then each index has to be recalculated using the current  */
/* device default palette using NearestDefaultPhysicalIndex.          */
/*                                                                    */
/**********************************************************************/



/**********************************************************************/
/* DeviceAnimatePalette                                               */
/*                                                                    */
/*  Modify the colors in a palette.  The changes will be reflected    */
/*  immediately for each animated index which has a hardware slot.    */
/*                                                                    */
/*  The only logical colors that can possibly be affected by this     */
/*  call are those already marked as PC_RESERVED in the logical       */
/*  palette, by either DeviceCreatePalette or DeviceSetPaletteEntries.*/
/*                                                                    */
/*  The only physical colors that can be affected are those that have */
/*  been assigned hardware slots by RealizePalette.                   */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc         DC handle                                         */
/*      hdevpal     device palette handle                             */
/*      ulFormat    format - must be LCOLF_CONSECRGB                  */
/*      ulStart     first palette entry to change                     */
/*      cclr        count of palette entries to change                */
/*      pclr        pointer to table of new RGB2 palette entries      */
/*      pdcArg      device DC handle                                  */
/*      FunN      function number and COM flags                       */
/*                                                                    */
/* Returns:                                                           */
/*      count of hardware palette slots changed                       */
/* Error Returns:                                                     */
/*      PAL_ERROR                                                     */
/**********************************************************************/

DDIENTRY DeviceAnimatePalette(HDC     hdc,
                              PDEVPAL hdevpal,
                              ULONG   ulFormat,
                              ULONG   ulStart,
                              ULONG   cclr,
                              PULONG  pclr,
                              PDC     pdcArg,
                              ULONG   FunN )

{
    ULONG       Changed;
    RGB2        rgb;
    ULONG       firstindex;
    ULONG       lastindex;
    ULONG       hwIndex;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

#ifdef FIREWALLS
    /******************************************************************/
    /* this test is firewalled since the 8514 prototype driver claims */
    /* that the engine will have already done the test                */
    /******************************************************************/

    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( PAL_ERROR );
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( PAL_ERROR );
    }
#endif /* FIREWALLS */

#ifdef FIREWALLS
    if (hdevpal != pdc->Palette)
    {
        DebugOutput("Device Animate palette: hdevpals do not agree...\n\r");
        if (!hdevpal)
        {
            DebugOutput("NULL hdevpal - using DC hdevpal...\n\r");
            hdevpal = pdc->Palette;
        }
        haltproc();
    }
#endif /* FIREWALLS */


    /******************************************************************/
    /* We can only animate if we have been passed RGBs in consecutive */
    /* formate, and the palette has been realized since the last      */
    /* palette was realized in the foreground (ie. we can guarantee   */
    /* that the mappings we have within the palette structure are     */
    /* still valid.                                                   */
    /******************************************************************/
    if (   (ulFormat == LCOLF_CONSECRGB)
        && (hdevpal->usLocalOptimizeID == usGlobalOptimizeID) )
    {
        /**************************************************************/
        /* initialize return value                                    */
        /**************************************************************/
        Changed = 0;

        /**************************************************************/
        /* set our range of HW slots changed to initial values        */
        /* (the first HW slot changed will always update these values)*/
        /**************************************************************/
        firstindex = SizeOfHWPalette;
        lastindex  = 0;

        /**************************************************************/
        /* pclr points at an array of RGB2 structures                 */
        /**************************************************************/
        /* Defect 63839 - Remove 256 entry logical palette limit      */
        while ((cclr != 0) && (ulStart < hdevpal->usCountStored))
        {
            /**********************************************************/
            /* only process reserved entries which are not also       */
            /* explicit entries, and which were also previously       */
            /* reserved                                               */
            /**********************************************************/
            if ( ((*(PRGB2)pclr).fcOptions & PC_RESERVED) &&
                !((*(PRGB2)pclr).fcOptions & PC_EXPLICIT) &&
                (hdevpal->entries[ulStart].rgb.fcOptions & PC_RESERVED))
            {
                /******************************************************/
                /* this value satisfies the tests so we are going to  */
                /* update the palette                                 */
                /******************************************************/

                /******************************************************/
                /* get the passed rgb2 value                          */
                /******************************************************/
                rgb = *(PRGB2)pclr;

                /******************************************************/
                /* set our flag to say this index is used             */
                /******************************************************/
                rgb.fcOptions |= PC_USED;
                hdevpal->entries[ulStart].rgb = rgb;

                /******************************************************/
                /* If the h/w palette entry is PC_RESERVED then       */
                /* change the HWPalette entry.                        */
                /******************************************************/
                hwIndex = hdevpal->entries[ulStart].bCurrent;

                if ( HWPalette[hwIndex].fcOptions & PC_RESERVED )
                {
                    /**************************************************/
                    /* this entry has a hardware slot allocated, so   */
                    /* write the new value there                      */
                    /**************************************************/
                    HWPalette[hwIndex] = rgb;

                    /**************************************************/
                    /* update the change count                        */
                    /**************************************************/
                    Changed++;

                    /**************************************************/
                    /* keep the range of HW slots changed up to date  */
                    /**************************************************/
                    if (hwIndex > lastindex)
                    {
                        lastindex = hwIndex;
                    }
                    if (hwIndex < firstindex)
                    {
                        firstindex = hwIndex;
                    }

                } /* ...if HWPalette slot reserved */

                /******************************************************/
                /* mark palette as having changed.                    */
                /******************************************************/
                hdevpal->usFlags |= PAL_CHANGED;

            } /* ... if palette entry reserved */

            /**********************************************************/
            /* move to consider the next entry                        */
            /**********************************************************/
            cclr--;
            ulStart++;
            pclr++;
        }

        /**************************************************************/
        /* now pass any changed entries through to the hardware       */
        /**************************************************************/
        if (Changed)
        {
            /**********************************************************/
            /* Just pass on the range of the HW palette which includes*/
            /* all the slots that we changed                          */
            /**********************************************************/
            #ifndef   _8514
            LoadPaletteEntries(firstindex,
            #else
            Load8514PaletteEntries(firstindex,
            #endif
                               lastindex - firstindex + 1,
                               &HWPalette[firstindex]);

            /**********************************************************/
            /* Pass the information that the h/w palette changed on   */
            /* to the palette mapping caching code                    */
            /**********************************************************/
            HWPaletteChanged();
        }

        /**************************************************************/
        /* If the logical palette changed pass this information on to */
        /* the palette mapping caching code                           */
        /**************************************************************/
        if (hdevpal->usFlags & PAL_CHANGED)
        {
            ChangedPalette(hdevpal);
        }

    } /* ... LCOLF_CONSECRGB */
    else /* error */
    {
        /* Defect 65655 - We must log the error                       */
        LogError(PMERR_PALETTE_BUSY);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( PAL_ERROR );
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    return(Changed);
}

/**********************************************************************/
/* DeviceSetPaletteEntries                                            */
/*                                                                    */
/*   This sets entries in the logical palette structure.  It is an    */
/*   error to try and set entries outside the range of the palette.   */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc         DC handle                                         */
/*      hdevpal     device palette handle                             */
/*      ulFormat    format - must be LCOLF_CONSECRGB                  */
/*      ulStart     first palette entry to change                     */
/*      cclr        count of palette entries to change                */
/*      pclr        pointer to table of new RGB2 palette entries      */
/*      pdc         device DC handle                                  */
/*      FunN      function number and COM flags                       */
/*                                                                    */
/* Returns:                                                           */
/*       TRUE if entries set without error                            */
/* Error Returns:                                                     */
/*       FALSE                                                        */
/**********************************************************************/

DDIENTRY DeviceSetPaletteEntries(HDC     hdc,
                                 PDEVPAL hdevpal,
                                 ULONG   ulFormat,
                                 ULONG   ulStart,
                                 ULONG   cclr,
                                 PULONG  pclr,
                                 PDC     pdcArg,
                                 ULONG   FunN )

{
    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

#ifdef FIREWALLS
    /******************************************************************/
    /* this test is firewalled since the 8514 prototype driver claims */
    /* that the engine will have already done the test                */
    /******************************************************************/

    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(FALSE);
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(FALSE);
    }
#endif /* FIREWALLS */

    /******************************************************************/
    /* it is an error to use this function to increase the size of a  */
    /* palette                                                        */
    /******************************************************************/
    if ((ulStart + cclr - 1) > hdevpal->usMax)
    {
        LogError(PMERR_INV_COLOR_INDEX);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(FALSE);
    }

    /******************************************************************/
    /* the only valid format is LCOLF_CONSECRGB                       */
    /******************************************************************/
    if (ulFormat != LCOLF_CONSECRGB)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(FALSE);
    }

    /******************************************************************/
    /* every thing is hunky-dory so go and do the work                */
    /******************************************************************/
    InnerSetPaletteEntries( hdevpal,
                            ulStart,
                            cclr,
                            pclr);

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    return(TRUE);
}

/**********************************************************************/
/* InnerSetPaletteEntries                                             */
/*                                                                    */
/*   Called from DevSetPaletteEntries, and CreatePalette.             */
/*                                                                    */
/*   This function actually sets the entries in the logical palette.  */
/*   It assumes that all error checking has been done by the calling  */
/*   routine.                                                         */
/*                                                                    */
/**********************************************************************/
VOID DRIVERCALL InnerSetPaletteEntries( PDEVPAL hdevpal,
                                        ULONG   ulStart,
                                        ULONG   cclr,
                                        PULONG  pclr)

{
    RGB2        rgb;

    /* Defect 63839 - Support for > 256 entry logical palettes */
    while (cclr)
    {
        /**************************************************************/
        /* get the passed rgb2 value                                  */
        /**************************************************************/
        rgb = *(PRGB2)pclr++;
        if (!(hdevpal->entries[ulStart].rgb.fcOptions & PC_USED))
        {
            /**********************************************************/
            /* this was not previously used, so it must be new        */
            /**********************************************************/
            rgb.fcOptions |= PC_NEW;
        }
        /**************************************************************/
        /* this entry is now used                                     */
        /**************************************************************/
        rgb.fcOptions |= PC_USED;

        /**************************************************************/
        /* save away the rgb value with adjusted flags                */
        /**************************************************************/
        hdevpal->entries[ulStart].rgb = rgb;
        cclr--;
        ulStart++;
    }

    /******************************************************************/
    /* mark palette as having changed.                                */
    /******************************************************************/
    hdevpal->usFlags |= PAL_CHANGED;
    ChangedPalette(hdevpal);

}

/**********************************************************************/
/* DeviceCreatePalette                                                */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc             DC Handle                                     */
/*      ppalinfo        table of palette data                         */
/*      hdevpal         device palette handle (NULL if new)           */
/*      pdc             device display context handle                 */
/*      FunN          function number                                 */
/*                                                                    */
/* If hdevpal is zero, then ppalinfo points to a paletteinfo          */
/* structure, which must be set into a new palette whose handle is    */
/* returned.  The new palette is then selected into the DC.           */
/*                                                                    */
/* If hdevPal is non-zero, then ppalinfo is ignored: the palette is   */
/* selected into the DC.                                              */
/*                                                                    */
/* STRUCTURE                                                          */
/*                                                                    */
/*  if (hdevpal == 0)                                                 */
/*  {                                                                 */
/*      Get new palette                                               */
/*      Clear palette                                                 */
/*      Set palette entries                                           */
/*  }                                                                 */
/*  call eddc_ResetLogColorTable() to tidy up DC state                */
/*  Select palette into DC                                            */
/*  Increment palette usage count                                     */
/*                                                                    */
/* Returns:                                                           */
/*      hdevpal                                                       */
/* Error Returns:                                                     */
/*      ERROR_NEG                                                     */
/**********************************************************************/

DDIENTRY DeviceCreatePalette(HDC          hdc,
                             PPALETTEINFO ppalinfo,
                             PDEVPAL      hdevpal,
                             PDC          pdcArg,
                             ULONG        FunN)

{
    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

#ifdef FIREWALLS
    /******************************************************************/
    /* this test is firewalled since the 8514 prototype driver claims */
    /* that the engine will have already done the test                */
    /******************************************************************/

    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( ERROR_NEG );
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( ERROR_NEG );
    }
#endif /* FIREWALLS */

    if ( !hdevpal )
    {
        /**************************************************************/
        /* check the data is in the right format                      */
        /**************************************************************/
        if (ppalinfo->ulFormat != LCOLF_CONSECRGB)
        {
            ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
            return( ERROR_NEG );
        }

        /**************************************************************/
        /* Create a new palette and copy in the palinfo.              */
        /**************************************************************/
        hdevpal = GetPaletteMemory(ppalinfo->cclr);

        if ((LONG)hdevpal == ERROR_NEG)
        {
            ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
            return( ERROR_NEG );
        }

        /**************************************************************/
        /* update our global palette count                            */
        /**************************************************************/
        GlobalPalCount++;

        /**************************************************************/
        /* totally clear the palette memory                           */
        /* this initializes usage count to 0, max index to 0          */
        /*   and all entries to RGB 0 (black)                         */
        /**************************************************************/
        memset( hdevpal,
                0,
                (sizeof(DEVPAL) +
                ((ppalinfo->cclr - 1) * sizeof(PALENTRY))) );

        /**************************************************************/
        /* store the user flags for this palette                      */
        /* and indicate palette has changed since it was realized     */
        /**************************************************************/
        hdevpal->usFlags = (USHORT)(ppalinfo->flCmd | PAL_CHANGED);

        /**************************************************************/
        /* Set colors into palette                                    */
        /**************************************************************/
        InnerSetPaletteEntries( hdevpal,
                                0L,           /* start is always zero */
                                ppalinfo->cclr,
                                (PULONG)ppalinfo->argb);

        /**************************************************************/
        /* we have a palette so store its maximum index               */
        /**************************************************************/
        hdevpal->usMax = (USHORT)ppalinfo->cclr - (USHORT)1;

        /* Defect 63839 - Support for > 256 entry logical palettes  */
        hdevpal->usCountStored = (USHORT)ppalinfo->cclr;

        /**************************************************************/
        /* We must make sure that the first realize call is not       */
        /* optimized out by setting the local optimization identifier */
        /* to a different number to the global optimization           */
        /* identifier. (We do not have to use -1, but it is as good   */
        /* as any other value!)                                       */
        /**************************************************************/
        hdevpal->usLocalOptimizeID = usGlobalOptimizeID-(SHORT)1;
    }

    /******************************************************************/
    /* Select palette into the DC.                                    */
    /* First, reset the DC to default color table.                    */
    /******************************************************************/
    eddc_ResetLogColorTable();

    /******************************************************************/
    /* Set the palette handle into our dc.                            */
    /******************************************************************/
    pdc->Palette      = hdevpal;
    pdc->DCIColFormat = LCOLF_PALETTE;

    /******************************************************************/
    /* we will be using this palette so increment the usage count     */
    /******************************************************************/
    hdevpal->cUsage++;

    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return (ULONG)hdevpal;
}

/**********************************************************************/
/* GetPaletteMemory                                                   */
/*                                                                    */
/* Get a block of memory for a palette structure.                     */
/* We may wish to make this routine get enough memory for several     */
/* palettes at once (see the 8514 prototype driver)                   */
/* but for now its as simple as possible                              */
/*                                                                    */
/* Returns:                                                           */
/*      hdevpal                                                       */
/* Error Returns:                                                     */
/*      ERROR_NEG                                                     */
/**********************************************************************/
PDEVPAL DRIVERCALL GetPaletteMemory(ULONG cPalEntries)
{
    PDEVPAL     hdevpal;

    hdevpal = AllocateMemory( (sizeof(DEVPAL) +
                              ((cPalEntries -1) * sizeof(PALENTRY)) ),
                              MT_PALETTE,
                              MO_SHARED );
    if (hdevpal == NULL)
    {
        /**************************************************************/
        /* The allocation failed.                                     */
        /**************************************************************/
        return( (PDEVPAL)ERROR_NEG );
    }

    return( hdevpal );
}


/**********************************************************************/
/* FreePaletteMemory                                                  */
/* free a palette structure                                           */
/*                                                                    */
/* we may want to save the memory for reuse later                     */
/*                                                                    */
/* Returns:                                                           */
/*      n/a                                                           */
/* Error Returns:                                                     */
/*      n/a                                                           */
/**********************************************************************/
VOID DRIVERCALL FreePaletteMemory(PDEVPAL hdevpal)
{
    FreeMemory(hdevpal);
}

/**********************************************************************/
/* DeviceDeletePalette                                                */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc             DC Handle                                     */
/*      hdevpal         device palette handle                         */
/*      pdc             device display context handle                 */
/*      FunN          function number                                 */
/*                                                                    */
/* Delete the passed palette (ie. delete it from the current DC)      */
/*                                                                    */
/* STRUCTURE                                                          */
/*                                                                    */
/*   validate parms                                                   */
/*   reset logical color table                                        */
/*   call InnerDeletePalette                                          */
/*                                                                    */
/* Returns:                                                           */
/*      OK                                                            */
/* Error Returns:                                                     */
/*      ERROR_ZERO                                                    */
/**********************************************************************/

DDIENTRY DeviceDeletePalette(HDC          hdc,
                             PDEVPAL      hdevpal,
                             PDC          pdcArg,
                             ULONG        FunN)

{
    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

#ifdef FIREWALLS
    /******************************************************************/
    /* this test is firewalled since the 8514 prototype driver claims */
    /* that the engine will have already done the test                */
    /******************************************************************/

    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(ERROR_ZERO);
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        haltproc();
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(ERROR_ZERO);
    }
#endif /* FIREWALLS */

    /******************************************************************/
    /* Reset the dc to default color table.                           */
    /******************************************************************/
    eddc_ResetLogColorTable();

    pdc->DCIColFormat = LCOLF_DEFAULT;

#ifdef FIREWALLS
    if (hdevpal != pdc->Palette)
    {
        DebugOutput("Device Delete palette: hdevpals do not agree...\n\r");
        if (!hdevpal)
        {
            DebugOutput("NULL hdevpal - using DC hdevpal...\n\r");
            hdevpal = pdc->Palette;
        }
        haltproc();
    }
#endif /* FIREWALLS */

    /******************************************************************/
    /* actually do the delete palette operation                       */
    /******************************************************************/
    InnerDeletePalette(hdevpal);

    pdc->Palette = NULL;

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    return(OK);
}

/**********************************************************************/
/* InnerDeletePalette                                                 */
/*                                                                    */
/* Inner delete palette decrements the palette usage count, and if    */
/* necessary frees up memory occupied by the palette                  */
/*                                                                    */
/* It is called from DeviceDeletePalette, and also if necessary by    */
/* Firewalled code in DisableDC and RestoreDC.                        */
/*                                                                    */
/* Parameters:                                                        */
/*      hdevpal         device palette handle to delete               */
/*                                                                    */
/* Returns:                                                           */
/*      n/a                                                           */
/* Error Returns:                                                     */
/*      n/a                                                           */
/**********************************************************************/

VOID DRIVERCALL InnerDeletePalette(PDEVPAL hdevpal)
{
    /******************************************************************/
    /* Decrement usage count                                          */
    /******************************************************************/
    if ( !(--hdevpal->cUsage) )
    {
        /**************************************************************/
        /* now zero. Destroy this palette.                            */
        /**************************************************************/
        GlobalPalCount--;

        FreePaletteMemory(hdevpal);

        /**************************************************************/
        /* Check foreground palette                                   */
        /**************************************************************/
        if ( hForeGroundPal == hdevpal )
        {
            hForeGroundPal = NULL;
        }
        /******************************************************************/
        /* Invalidate the palette mapping cache if it uses this palette.  */
        /******************************************************************/
        ChangedPalette(hdevpal);
    }
}

ULONG DRIVERCALL CountFreeSlots(VOID)
{
    ULONG   i;
    ULONG   ulFreeSlots;

    ulFreeSlots = 0;
    for (i = 0; i < HW_PAL_SIZE; i++)
    {
        if (!(HWPalette[i].fcOptions & (PC_USED | PC_DEFAULT)))
        {
            ulFreeSlots++;
        }
    }
    return(ulFreeSlots);
}


VOID SmoothLoadPaletteEntries(VOID)
{
    RECTL   rcl;
    PRGB2   LastDefaultPalette;
    ULONG   i;

    if (   (ulDirectDeviceDefaultPaletteSize == 256)
        || (ulLastDefaultPaletteSize == 256)
        || (ulDirectDeviceDefaultPaletteSize == ulLastDefaultPaletteSize) )
    {
        #ifndef   _8514
        LoadPaletteEntries(0, HW_PAL_SIZE, HWPalette);
        #else
        Load8514PaletteEntries(0, HW_PAL_SIZE, HWPalette);
        #endif
        ulLastDefaultPaletteSize = ulDirectDeviceDefaultPaletteSize;
        return;
    }

    rcl.xLeft = 0;
    rcl.yBottom = 0;
    rcl.xRight = DDT.ScreenWidth - 1;
    rcl.yTop = DDT.ScreenHeight - 1;

    switch (ulLastDefaultPaletteSize)
    {
        case 128:
            LastDefaultPalette = Reduced128DeviceDefaultPalette;
            break;
        case 64:
            LastDefaultPalette = Reduced64DeviceDefaultPalette;
            break;
        case 32:
            LastDefaultPalette = Reduced32DeviceDefaultPalette;
            break;
        case 16:
            LastDefaultPalette = Reduced16DeviceDefaultPalette;
            break;
    }


    for (i=0; i<256; i++)
    {
        UCMapping[i] = (BYTE)i;
    }
    for (i=0; i<ulLastDefaultPaletteSize/2; i++)
    {
        UCMapping[i] = (BYTE)NearestDirectDefaultPhysicalIndex(
                                                 LastDefaultPalette[i]);
        if (UCMapping[i]>128)
        {
            UCMapping[i] = (BYTE)
                    (UCMapping[i]-256+ulDirectDeviceDefaultPaletteSize);
        }
        UCMapping[i] += (BYTE)64;
    }
    for (i=256-ulLastDefaultPaletteSize/2; i<256; i++)
    {
        UCMapping[i] = (BYTE)
              NearestDirectDefaultPhysicalIndex(
                       LastDefaultPalette[i-256+ulLastDefaultPaletteSize]);
        if (UCMapping[i]>128)
        {
            UCMapping[i] = (BYTE)
                    (UCMapping[i]-256+ulDirectDeviceDefaultPaletteSize);
        }
        UCMapping[i] += 64;
    }
    if (ulDirectDeviceDefaultPaletteSize > 64)
    {
        for (i=64; i<128; i++)
        {
            UCMapping[i] = (BYTE)(i - 64);
        }
        for (i=128; i<192; i++)
        {
            UCMapping[i] = (BYTE)(i+64);
        }
    }
    else
    {
        for (i=64; i<64+ulDirectDeviceDefaultPaletteSize; i++)
        {
            UCMapping[i] = (BYTE)(i - 64);
        }

    }

    #ifndef   _8514
    LoadPaletteEntries(64,
    #else
    Load8514PaletteEntries(64,
    #endif
                       ulDirectDeviceDefaultPaletteSize,
                       DirectDeviceDefaultPalette);

    UpdateRectangle(&rcl);

    for (i=0; i<256; i++)
    {
        UCMapping[i] = (BYTE)i;
    }
    if (ulDirectDeviceDefaultPaletteSize > 64)
    {
        for (i=0; i<64; i++)
        {
            UCMapping[i] = (BYTE)(i + 64);
        }
        for (i=192; i<256; i++)
        {
            UCMapping[i] = (BYTE)(i - 64);
        }
    }
    else
    {
        for (i=0; i<ulDirectDeviceDefaultPaletteSize; i++)
        {
            UCMapping[i] = (BYTE)(i + 64);
        }
    }
    for (i=64; i<64+ulDirectDeviceDefaultPaletteSize/2; i++)
    {
        UCMapping[i] = (BYTE)(i - 64);
    }
    for (i=64+ulDirectDeviceDefaultPaletteSize/2;
         i<64+ulDirectDeviceDefaultPaletteSize;
         i++)
    {
        UCMapping[i] = (BYTE)
                   (i - 64 + 256 - ulDirectDeviceDefaultPaletteSize);
    }

    #ifndef _8514
    LoadPaletteEntries(0,
                       ulDirectDeviceDefaultPaletteSize/2,
                       DirectDeviceDefaultPalette);
    LoadPaletteEntries(256-ulDirectDeviceDefaultPaletteSize/2,
                       ulDirectDeviceDefaultPaletteSize/2,
                       &DirectDeviceDefaultPalette[
                           ulDirectDeviceDefaultPaletteSize/2] );

    UpdateRectangle(&rcl);

    LoadPaletteEntries(0, HW_PAL_SIZE, HWPalette);
    #else
    Load8514PaletteEntries(0,
                       ulDirectDeviceDefaultPaletteSize/2,
                       DirectDeviceDefaultPalette);
    Load8514PaletteEntries(256-ulDirectDeviceDefaultPaletteSize/2,
                       ulDirectDeviceDefaultPaletteSize/2,
                       &DirectDeviceDefaultPalette[
                           ulDirectDeviceDefaultPaletteSize/2] );

    UpdateRectangle(&rcl);

    Load8514PaletteEntries(0, HW_PAL_SIZE, HWPalette);
    #endif

    ulLastDefaultPaletteSize = ulDirectDeviceDefaultPaletteSize;

}

/**********************************************************************/
/* RealizePalette                                                     */
/*                                                                    */
/*   Realize palette is the heart of the Palette Manager.             */
/*   It takes a logical palette and assigns it slots in the hardware  */
/*   palette.                                                         */
/*                                                                    */
/*   Realizing a palette only works on a device DC.                   */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc             DC handle                                     */
/*      pflType         specifies foreground or not, and we use it to */
/*                      return whether the default colors have changed*/
/*      pcSlotsChanged  pointer to returned count of h/w slots changed*/
/*      pdc             device DC handle                              */
/*      FunN            function and COM_ bits                        */
/*                                                                    */
/* Returns:                                                           */
/*      number of mappings which changed                              */
/* Error Returns:                                                     */
/*      PAL_ERROR                                                     */
/**********************************************************************/

DDIENTRY RealizePalette(HDC          hdc,
                        PULONG       pflType,
                        PULONG       pcSlotsChanged,
                        PDC          pdcArg,
                        ULONG        FunN)
{
    ULONG         cMappingsChanged;
    ULONG         ulFreeSlots;
    static ULONG  ulFreeSlotsLastTime = 0;
    ULONG         i;


    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);


    /******************************************************************/
    /* Get driver semaphore and perform entry checks.                 */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* initialize return values in case we bail out early             */
    /* return values of zero means nothing in the H/W palette changed */
    /******************************************************************/
    *pcSlotsChanged  = 0;
    cMappingsChanged = 0;

    /******************************************************************/
    /* NB.  we dont firewall the path/area test because the 8514      */
    /* prototype does not (it could be due to the fact that           */
    /* RealizePalette is called by pmwin not the GPI level)           */
    /******************************************************************/
    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( PAL_ERROR );
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return( PAL_ERROR );
    }

    /******************************************************************/
    /* Realize palette only does anything on a device DC.             */
    /* If a logical color table is currently realized it overrides    */
    /* any realize palette calls (RealizeLCT should only happen       */
    /* when the app is maximized and in the foreground, so we have to */
    /* make the assumption that any app that has done this knows      */
    /* what it is doing).                                             */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT &&
        !ColorTableRealized)
    {
        /**************************************************************/
        /* If this DC has a palette associated with it then we must   */
        /* realize it.  If it does not have a palette associated with */
        /* it then we must realize the default palette.  Realizing    */
        /* the default palette only needs to be done if the DC is in  */
        /* the foreground because if we were in the background then   */
        /* we would not be able to write to the slots which had been  */
        /* changed anwyay.  DCs in the background must just assume    */
        /* that the default palette is realized.                      */
        /**************************************************************/
        if (pdc->DCIColFormat == LCOLF_PALETTE)
        {
#ifdef FIREWALLS
            if (pdc->Palette == NULL)
            {
                haltproc();
            }
#endif /* FIREWALLS */
            /**********************************************************/
            /* InnerRealizePalette is responsible for realizing a     */
            /* proper palette manager palette (ie. not the default    */
            /* palette).  It will change the HW slots and markings as */
            /* required.                                              */
            /**********************************************************/
            cMappingsChanged = InnerRealizePalette(pflType,pcSlotsChanged);

            /**********************************************************/
            /* Make sure that the next time we realize the default    */
            /* palette in the foreground we do not increase the size  */
            /* of the default palette if we have just realized in the */
            /* foreground.  (See below).                              */
            /**********************************************************/
            if (*pflType & RP_FOREGROUND)
            {
                ulFreeSlotsLastTime = 0;
            }
        }

        /**************************************************************/
        /* no palette means 'realize' the default palette             */
        /* this only makes sense in the foreground                    */
        /* (in the background we must always assume the default       */
        /* palette is realized)                                       */
        /**************************************************************/
        else if (*pflType & RP_FOREGROUND)
        {
            /**********************************************************/
            /* Only realize the default palette if it was not the     */
            /* last palette realized or there are enough free slots   */
            /* to increase the size of the default palette and there  */
            /* were also enough free slots the time before.  This     */
            /* helps stop us from being premature in the (rare) case  */
            /* of the foreground application using a cached PS,       */
            /* responding to realize messages by repainting, and      */
            /* realizing the default palette within its paint         */
            /* routine!                                               */
            /**********************************************************/
            ulFreeSlots = CountFreeSlots();

            if (  (hForeGroundPal != (PDEVPAL)DirectDeviceDefaultPalette)
               || (ulDirectDeviceDefaultPaletteSize <= ulFreeSlotsLastTime))
            {
                StoreAndRemoveUsedMarkings();

                if (ulDirectDeviceDefaultPaletteSize <= ulFreeSlots)
                {
                    do
                    {
                        ulFreeSlots -= ulDirectDeviceDefaultPaletteSize;
                        *pcSlotsChanged = IncreaseDefaultPaletteSize();
                    } while (ulDirectDeviceDefaultPaletteSize <= ulFreeSlots);
                }
                else
                {
                    *pcSlotsChanged = RealizeDefaultPalette();
                }

                hForeGroundPal = (PDEVPAL)DirectDeviceDefaultPalette;
#ifdef SEAMLESS
                /******************************************************/
                /* Update the seamless palette changed time stamp to  */
                /* indicate         palette mappings could now be     */
                /* invalid.                                           */
                /******************************************************/
                SeamlessData.ulLastPalUpdate++;
#endif

                /******************************************************/
                /* If we had to change some of the HW slots in order  */
                /* to realize the default palette then we must clear  */
                /* all of the PC_USED slot markings ready for other   */
                /* palettes to be re-realized.  (When we return the   */
                /* number of slots changed as non-zero realize        */
                /* messages are sent to all the other windows).       */
                /******************************************************/
                if (*pcSlotsChanged)
                {
                    /* Defect 65655 - Only update usGlobalOptimizeID  */
                    /* if the state of the HW palette has changed     */
                    usGlobalOptimizeID++;
                    RemoveUsedMarkings();
                    *pflType |= RP_DEFAULTSCHANGED;
                }
            }

            /**********************************************************/
            /* Keep a copy of the number of free slots to help us to  */
            /* decide when to increase the default palette size.      */
            /**********************************************************/
            ulFreeSlotsLastTime = ulFreeSlots;
        }

        /**************************************************************/
        /* If we have made some changes to the HW palette...          */
        /**************************************************************/
        if (*pcSlotsChanged)
        {
            /**********************************************************/
            /* Update the values in the real HW palette.              */
            /**********************************************************/
//            SmoothLoadPaletteEntries();
            #ifndef   _8514
            LoadPaletteEntries(0, HW_PAL_SIZE, HWPalette );
            #else
            Load8514PaletteEntries(0, HW_PAL_SIZE, HWPalette);
            #endif

            /**********************************************************/
            /* Invalidate the palette-palette mapping table if        */
            /* necessary.                                             */
            /**********************************************************/
            HWPaletteChanged();
        }

        if (  (pdc->DCIColFormat != LCOLF_PALETTE)
           && (*pflType & RP_FOREGROUND)
           && (*pcSlotsChanged == 0) )
        {
            /**********************************************************/
            /* We were asked to realized the default palette in the   */
            /* forground but did not increase the default palette     */
            /* size.  At this point we do something cunning.  We      */
            /* return that there have been HW slots changed but no    */
            /* mapping changes.  This means that realize messages     */
            /* will be sent to all of the other         but no        */
            /* repainting will be required.  This way we will get     */
            /* realize calls from any palettes still being used.      */
            /* This stops us from trying to increase the default      */
            /* palette size next time round if it is not appropriate. */
            /**********************************************************/
            if (ulDirectDeviceDefaultPaletteSize != 256)
            {
                *pcSlotsChanged = 1;
            }
        }
    }

    /******************************************************************/
    /* Chose the appropriate AVIO color table for this size default   */
    /* palette.                                                       */
    /******************************************************************/
    switch (ulDirectDeviceDefaultPaletteSize)
    {
        case 256:
            pAVIOColorXlate = AVIOXlate256;
            break;
        case 128:
            pAVIOColorXlate = AVIOXlate128;
            break;
        case 64:
            pAVIOColorXlate = AVIOXlate64;
            break;
        case 32:
            pAVIOColorXlate = AVIOXlate32;
            break;
        case 16:
            pAVIOColorXlate = AVIOXlate16;
            break;
    }

    /******************************************************************/
    /* The physical indices in the AVIO table may never have been     */
    /* set up.                                                        */
    /******************************************************************/
    if (pAVIOColorXlate[0] == CLR_NOPHYINDEX)
    {
        for (i=0; i < AVIO_PALETTE_SIZE; i++)
        {
            pAVIOColorXlate[i] =
                   NearestDirectDefaultPhysicalIndex(AVIOColorTable[i]);
        }
    }

    /******************************************************************/
    /* If the mappings have changed then we must indicate this to the */
    /* palette->palette mapping cache code.                           */
    /******************************************************************/
    if (cMappingsChanged)
    {
        ChangedPalette(pdc->Palette);
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    return(cMappingsChanged);
}

/**********************************************************************/
/* RealizeDefaultPalette                                              */
/*                                                                    */
/*   This routine puts the default entries back in the h/w palette,   */
/*   and returns the number of h/w entries changed                    */
/*                                                                    */
/* Returns:                                                           */
/*      number of h/w entries changed                                 */
/**********************************************************************/
ULONG DRIVERCALL RealizeDefaultPalette(VOID)
{
    ULONG       i;
    ULONG       slotchanges;

    slotchanges = 0;

    /******************************************************************/
    /* The size of the default palette is dependent on the number of  */
    /* HW palette slots that have been allocated to be used by real   */
    /* palette mananger palettes.  The size of the default palette is */
    /* always one of 16, 32, 64, 128, or 256 so that mixes of the     */
    /* colors in the default palette can not be changed by changes in */
    /* other palettes.  If the default palette is not 256 entries     */
    /* then it is split between the start and end of the HW palette.  */
    /******************************************************************/
    for (i=0; i < ulDirectDeviceDefaultPaletteSize/2; i++)
    {
        if (!(HWPalette[i].fcOptions & PC_DEFAULT))
        {
            /**************************************************/
            /* this entry is currently not default            */
            /* so reload it and count the change to the h/w   */
            /**************************************************/
            slotchanges++;
            HWPalette[i] = DirectDeviceDefaultPalette[i];
        }
    }
    /**********************************************************/
    /* now the values at the end of the table                 */
    /**********************************************************/
    while (i<ulDirectDeviceDefaultPaletteSize)
    {
        /**************************************************************/
        /* This define is to make the conditional statement and the   */
        /* following assignment more readable.                        */
        /* Note that j depends on i, so changes for each pass of the  */
        /* loop.                                                      */
        /**************************************************************/
#define j (HW_PAL_SIZE-ulDirectDeviceDefaultPaletteSize+i)

        if (!(HWPalette[j].fcOptions & PC_DEFAULT))
        {
            /**************************************************/
            /* this entry is currently not default            */
            /* so reload it and count the change to the h/w   */
            /**************************************************/
            slotchanges++;
            HWPalette[j] = DirectDeviceDefaultPalette[i];
        }
#undef j
        i++;
    }

#ifdef SEAMLESS
    /******************************************************************/
    /* If we are realizing the 16 entry default palette then we must  */
    /* also fudge in the middle 4         system colors.  (See        */
    /* fudgepal.c)                                                    */
    /******************************************************************/
    if (ulDirectDeviceDefaultPaletteSize == 16)
    {
        if (!(HWPalette[8].fcOptions & PC_DEFAULT))
        {
            slotchanges++;
            HWPalette[8] = WindowsDefaultSysColors[8];
        }
        if (!(HWPalette[9].fcOptions & PC_DEFAULT))
        {
            slotchanges++;
            HWPalette[9] = WindowsDefaultSysColors[9];
        }
        if (!(HWPalette[246].fcOptions & PC_DEFAULT))
        {
            slotchanges++;
            HWPalette[246] = WindowsDefaultSysColors[10];
        }
        if (!(HWPalette[247].fcOptions & PC_DEFAULT))
        {
            slotchanges++;
            HWPalette[247] = WindowsDefaultSysColors[11];
        }
    }
#endif

    /******************************************************************/
    /* return the number of h/w slot entries that were changed        */
    /******************************************************************/
    return (slotchanges);
}


/**********************************************************************/
/* ReduceDefaultPaletteSize                                           */
/*                                                                    */
/*   This routine reduces the size of the default palette by a factor */
/*   of two, to a minimum size of 16 entries.                         */
/*                                                                    */
/**********************************************************************/
ULONG DRIVERCALL ReduceDefaultPaletteSize(VOID)
{
    ULONG   i;
    ULONG   ulSlotsChanged;

    /******************************************************************/
    /* Work out how many slots we will now allocate to the device     */
    /* default palette and which palette to use.                      */
    /******************************************************************/
    if (ulDirectDeviceDefaultPaletteSize == 256)
    {
        ulDirectDeviceDefaultPaletteSize = 128;
        DirectDeviceDefaultPalette = Reduced128DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable128;
    }
    else if (ulDirectDeviceDefaultPaletteSize == 128)
    {
        ulDirectDeviceDefaultPaletteSize = 64;
        DirectDeviceDefaultPalette = Reduced64DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable64;
    }
    else if (ulDirectDeviceDefaultPaletteSize == 64)
#ifndef SEAMLESS
    /******************************************************************/
    /* Skip the 32 entry palette when seamless because it does not    */
    /* fit well with         system colors and DCR 1590.              */
    /******************************************************************/
    {
        ulDirectDeviceDefaultPaletteSize = 32;
        DirectDeviceDefaultPalette = Reduced32DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable32;
    }
    else if (ulDirectDeviceDefaultPaletteSize == 32)
#endif /* ndef SEAMLESS */
    {
        ulDirectDeviceDefaultPaletteSize = 16;
        DirectDeviceDefaultPalette = Reduced16DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable16;
    }
    else
    {
        /**************************************************************/
        /* If the size of the default palette is not 32, 64, 128, or  */
        /* 256 then something has gone wrong! The best we can do is   */
        /* just guess and use the smallest possible default palette.  */
        /**************************************************************/
        ulDirectDeviceDefaultPaletteSize = 16;
        DirectDeviceDefaultPalette = Reduced16DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable16;
#ifdef FIREWALLS
        haltproc();
#endif /* FIREWALLS */
    }

    /******************************************************************/
    /* Clear all of the PC_DEFAULT flags in the copy of the HW        */
    /* palette so that RealizeDefaultPalette will overwrite the       */
    /* previous default palette slots with the new values.            */
    /******************************************************************/
    for (i = 0; i < HW_PAL_SIZE; i++)
    {
        HWPalette[i].fcOptions &= ~PC_DEFAULT;
    }

    ulSlotsChanged = RealizeDefaultPalette();

    /******************************************************************/
    /* Now go through the direct device special color table and       */
    /* recalculate all the system and special colors.                 */
    /******************************************************************/
    for (i = 0; i < SPECIAL_COL_TAB_SIZE; i++)
    {
        if (DirectSpecialColorTable[i].PhyIndex != CLR_NOPHYINDEX)
        {
            DirectSpecialColorTable[i].PhyIndex =
                        NearestDirectDefaultPhysicalIndex(
                                DirectSpecialColorTable[i].LogRGB);
        }
    }

    return(ulSlotsChanged);
}

/**********************************************************************/
/* IncreaseDefaultPaletteSize                                         */
/*                                                                    */
/*   This routine reduces the size of the default palette by a factor */
/*   of two, to a minimum size of 16 entries.                         */
/*                                                                    */
/**********************************************************************/
ULONG DRIVERCALL IncreaseDefaultPaletteSize(VOID)
{
    ULONG i;
    ULONG   ulSlotsChanged;

    /******************************************************************/
    /* Work out how many slots we will now allocate to the device     */
    /* default palette and which palette to use.                      */
    /******************************************************************/
    if (ulDirectDeviceDefaultPaletteSize == 128)
    {
        ulDirectDeviceDefaultPaletteSize = 256;
        DirectDeviceDefaultPalette = FullSizeDeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable256;
    }
    else if (ulDirectDeviceDefaultPaletteSize == 64)
    {
        ulDirectDeviceDefaultPaletteSize = 128;
        DirectDeviceDefaultPalette = Reduced128DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable128;
    }

#ifndef SEAMLESS
    /******************************************************************/
    /* Skip the 32 entry palette when seamless because it does not    */
    /* fit well with         system colors and DCR 1590.              */
    /******************************************************************/
    else if (ulDirectDeviceDefaultPaletteSize == 32)
    {
        ulDirectDeviceDefaultPaletteSize = 64;
        DirectDeviceDefaultPalette = Reduced64DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable64;
    }
#endif
    else if (ulDirectDeviceDefaultPaletteSize == 16)
    {
#ifndef SEAMLESS
        ulDirectDeviceDefaultPaletteSize = 32;
        DirectDeviceDefaultPalette = Reduced32DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable32;
#else
        ulDirectDeviceDefaultPaletteSize = 64;
        DirectDeviceDefaultPalette = Reduced64DeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable64;
#endif
    }
    else
    {
        /**************************************************************/
        /* If the size of the default palette is not 16, 32, 64, or   */
        /* 128 then something has gone wrong!  The best we can do is  */
        /* just guess and use the largest possible default palette.   */
        /**************************************************************/
        ulDirectDeviceDefaultPaletteSize = 256;
        DirectDeviceDefaultPalette = FullSizeDeviceDefaultPalette;
        DefaultDirectLogicalColorTable = DefaultEightBppTable256;
#ifdef FIREWALLS
        haltproc();
#endif /* FIREWALLS */
    }

    /******************************************************************/
    /* Clear all of the PC_DEFAULT flags in the copy of the HW palette*/
    /* so that RealizeDefaultPalette will overwrite the previous      */
    /* default palette slots with the new values.                     */
    /******************************************************************/
    for (i = 0; i < HW_PAL_SIZE; i++)
    {
        HWPalette[i].fcOptions &= ~PC_DEFAULT;
    }

    ulSlotsChanged = RealizeDefaultPalette();

    /******************************************************************/
    /* Now go through the direct device special color table and       */
    /* recalculate all the system and special colors.                 */
    /******************************************************************/
    for (i = 0; i < SPECIAL_COL_TAB_SIZE; i++)
    {
        if (DirectSpecialColorTable[i].PhyIndex != CLR_NOPHYINDEX)
        {
            DirectSpecialColorTable[i].PhyIndex =
                        NearestDirectDefaultPhysicalIndex(
                                DirectSpecialColorTable[i].LogRGB);
        }
    }

    return(ulSlotsChanged);
}


/**********************************************************************/
/* RemoveUsedMarkings                                                 */
/*                                                                    */
/*   Marks all h/w palette entries as unused by any palettes.         */
/*                                                                    */
/* Returns:                                                           */
/*      n/a                                                           */
/**********************************************************************/

VOID DRIVERCALL RemoveUsedMarkings(VOID)
{
    ULONG   i;

    for (i=0; i<HW_PAL_SIZE; i++)
    {
        HWPalette[i].fcOptions &= ~PC_USED;
    }
}

/**********************************************************************/
/* StoreAndRemoveUsedMarkings                                         */
/*                                                                    */
/*   Copies PC_USED flags to PC_OLD flags and clears PC_USED flags so */
/*   that HW palette entires appear unused by any palette, but the    */
/*   usages can be restored by a call to RestoreUsedMarkings.         */
/*                                                                    */
/* Returns:                                                           */
/*      n/a                                                           */
/**********************************************************************/

VOID DRIVERCALL StoreAndRemoveUsedMarkings(VOID)
{
    ULONG      i;

    for (i=0; i<HW_PAL_SIZE; i++)
    {
        if (HWPalette[i].fcOptions & PC_USED)
        {
            HWPalette[i].fcOptions |= PC_OLD;
            HWPalette[i].fcOptions &= ~PC_USED;
        }
        else
        {
            HWPalette[i].fcOptions &= ~PC_OLD;
        }
    }
}

/**********************************************************************/
/* RestoreUsedMarkings                                                */
/*                                                                    */
/*   Copies PC_OLD flags to PC_USED flags. This restores the usage    */
/*   status of the HW palette back to what is was when the last call  */
/*   to StoreAndRemoveUsedMarkings.                                   */
/*                                                                    */
/* Returns:                                                           */
/*      n/a                                                           */
/**********************************************************************/

VOID DRIVERCALL RestoreUsedMarkings(VOID)
{
    ULONG      i;

    for (i=0; i<HW_PAL_SIZE; i++)
    {
        if (HWPalette[i].fcOptions & PC_OLD)
        {
            HWPalette[i].fcOptions |= PC_USED;
        }
    }
}

/**********************************************************************/
/* InnerRealizePalette                                                */
/*                                                                    */
/*   InnerRealizePalette is responsible for realizing a proper        */
/*   Palette Manager palette (ie not the device default palette).     */
/*   Validity checks (such as is this a device DC) have already been  */
/*   done.                                                            */
/*                                                                    */
/* Parameters:                                                        */
/*      pflType         specifies foreground or not, and also used to */
/*                      return whether the default colors have changed*/
/*      pcSlotsChanged  pointer to returned count of h/w slots changed*/
/*                                                                    */
/* Returns:                                                           */
/*      number of mappings which changed                              */
/* Error Returns:                                                     */
/*      n/a                                                           */
/**********************************************************************/
ULONG DRIVERCALL InnerRealizePalette(PULONG       pflType,
                                     PULONG       pcSlotsChanged)
{
    ULONG       localflags;
    ULONG       MappingsChanged;
    ULONG       HWSlotsChanged;
    ULONG       DefaultsChanged;
    ULONG       palcount;
    ULONG       entry;
    ULONG       slot;
    BYTE        bNoFreeSlotBefore;
    BYTE        bNoFreeSlotAfter;

    /******************************************************************/
    /* to prevent lots of segment loads to get at the palette flags   */
    /* we bring them in locally                                       */
    /******************************************************************/
    localflags = pdc->Palette->usFlags;

    /******************************************************************/
    /* The flags which we will look at during the realize operation   */
    /* in order to decide exactly what to do are:                     */
    /*                                                                */
    /*  *pflType & RP_FOREGROUND                                      */
    /*      - the palette is being realized in the foreground.        */
    /*                                                                */
    /*  localflags & PAL_CHANGED                                      */
    /*      - the palette needs to be realized (ie the current        */
    /*        mappings are not upto date).                            */
    /*                                                                */
    /*  localflags & PAL_CURRENT_OK                                   */
    /*      - the current mapping is valid (but not necessarily upto  */
    /*        date).                                                  */
    /*                                                                */
    /*  localflags & PAL_PREVIOUS_OK                                  */
    /*      - the previous mapping is valid (but not necessarily upto */
    /*        date).                                                  */
    /*                                                                */
    /*  localflags & LCOL_OVERRIDE_DEFAULT_COLORS                     */
    /*      - the palette can overide the entries in the default      */
    /*      palette.                                                  */
    /*                                                                */
    /******************************************************************/


    /******************************************************************/
    /* Initialize the counts of changed made to zero.                 */
    /******************************************************************/
    MappingsChanged = 0;
    HWSlotsChanged  = 0;
    DefaultsChanged = 0;

    /******************************************************************/
    /* Now we must consider the global and local optimization         */
    /* identifiers.                                                   */
    /*                                                                */
    /* Each time a palette is realized in the foreground the global   */
    /* optimization identifier is incremented.  Each time a palette   */
    /* is realized (whether in the foreground or the background) its  */
    /* local optimization identifier is set to the global             */
    /* optimization identifier.                                       */
    /*                                                                */
    /* There are certain conditions under which we will not realize   */
    /* the palette if its entries have not changed, saving a lot      */
    /* of time:                                                       */
    /*                                                                */
    /* 1) If the palette is being realized in the background, and the */
    /*    local optimization id is the same as the global one.        */
    /*    This indicates that the palette has already been realized   */
    /*    since the last foreground realization, so just leave the    */
    /*    mapping the way it is.                                      */
    /*                                                                */
    /* 2) If the palette is being realized in the foreground, the     */
    /*    local optimization id is the same as the global one, and    */
    /*    the palette is already the foreground one.                  */
    /*                                                                */
    /******************************************************************/
    if (!(localflags & PAL_CHANGED) &&
        pdc->Palette->usLocalOptimizeID == usGlobalOptimizeID)
    {
        /**************************************************************/
        /* The palette is unchanged and the optimization identifiers  */
        /* are equal.                                                 */
        /**************************************************************/
        if (!(*pflType & RP_FOREGROUND) ||
            (pdc->Palette == hForeGroundPal))
        {
            /**********************************************************/
            /* We are realizing in the background, or the palette is  */
            /* already the forground one anyway so there is no need   */
            /* to do any realization.                                 */
            /**********************************************************/
            goto no_need_to_realize;
        }
    }

    /******************************************************************/
    /* looks like we'll have to realize this palette in some form     */
    /******************************************************************/
    if (*pflType & RP_FOREGROUND)
    {
        /**************************************************************/
        /* this is in the forground, so update our global info        */
        /**************************************************************/
        hForeGroundPal = pdc->Palette;
        usGlobalOptimizeID++;
#ifdef SEAMLESS
        /**************************************************************/
        /* Update the seamless palette changed time stamp to indicate */
        /*         palette mappings could now be invalid.             */
        /**************************************************************/
        SeamlessData.ulLastPalUpdate++;
#endif
    }

    /******************************************************************/
    /* store the usGlobalOptimizeID value in the palette              */
    /******************************************************************/
    pdc->Palette->usLocalOptimizeID = usGlobalOptimizeID;

    /******************************************************************/
    /* get the number of logical palette entries to consider          */
    /******************************************************************/
    palcount = pdc->Palette->usCountStored;

    /******************************************************************/
    /* if the current values are valid, copy them to the previous     */
    /* values                                                         */
    /******************************************************************/
    if (localflags & PAL_CURRENT_OK)
    {
        for (entry=0; entry<palcount; entry++)
        {
            pdc->Palette->entries[entry].bPrevious =
                                   pdc->Palette->entries[entry].bCurrent;
        }
    }


    /******************************************************************/
    /* We must now map the palette to the real HW palette...          */
    /*                                                                */
    /*      if palette is being realized in the foreground then       */
    /*         mark all HW palette slots as previously unused         */
    /*         mark all used HW palette slots as previously used      */
    /*         mark all HW palette slots as currently unused          */
    /*      endif                                                     */
    /* set_up_realize_loop:                                           */
    /*      for each entry in palette                                 */
    /*        if entry is marked as explict                           */
    /*          goto next_entry                                       */
    /*        endif                                                   */
    /*        if we have an existing mapping                          */
    /*          if existing mapping gives exact slot                  */
    /*            if reserved/no_collapse/used flags do not clash     */
    /*              use this existing mapping                         */
    /*              goto next_entry                                   */
    /*            endif                                               */
    /*          endif                                                 */
    /*        endif                                                   */
    /*        if entry is not marked as reserved or no_collapse       */
    /*          for each hw slot                                      */
    /*            if entry is exact match                             */
    /*              make mapping to this slot                         */
    /*              goto next_entry                                   */
    /*            endif                                               */
    /*          endfor                                                */
    /*        endif                                                   */
    /* find_free_slot:                                                */
    /*        if current foreground palette is the default            */
    /*          if there were free slots when default realized        */
    /*            make mapping to old free slot                       */
    /*            goto next_entry                                     */
    /*          endif                                                 */
    /*        else if there are free hw slots                         */
    /*          make mapping to free slot                             */
    /*          goto next_entry                                       */
    /*        endif                                                   */
    /*        if size of default palette can be reduced               */
    /*          reduce default palette size                           */
    /*          if realizing in the foreground                        */
    /*            mark all slots unused                               */
    /*            goto set_up_realize_loop                            */
    /*          endif                                                 */
    /*          increment global optimization id                      */
    /*          goto find_free_slot                                   */
    /*        else if in foreground and overide defaults is enabled   */
    /*          overwrite one of the default palette slots            */
    /*        else                                                    */
    /*          make mapping to nearest color slot                    */
    /*        endif                                                   */
    /*        endif                                                   */
    /* next_entry:                                                    */
    /*      endfor                                                    */
    /*      if palette is being realized in the foreground            */
    /*        if no HW palette slots were changed during realization  */
    /*          mark previously used HW slots as currently used       */
    /*        endif                                                   */
    /*      endif                                                     */
    /*                                                                */
    /******************************************************************/
    /******************************************************************/
    /* Note: This function really needs restructuring!!!!             */
    /******************************************************************/


    /******************************************************************/
    /* If the palette is being realized in the foreground...          */
    /******************************************************************/
    if (*pflType & RP_FOREGROUND)
    {
        /**************************************************************/
        /* If the last foreground palette overwrote any of the        */
        /* default palette colors then we need to reinstate them.     */
        /**************************************************************/
        if (fForeGroundOverwrote)
        {
            DefaultsChanged = RealizeDefaultPalette();

            /**********************************************************/
            /* currently none of the default colors are overwritten   */
            /**********************************************************/
            fForeGroundOverwrote = FALSE;
        }

        /**************************************************************/
        /* Clear all the HW palette slot PC_USED markings.  (But      */
        /* remember what they were so we can restore them later if    */
        /* realizing this palette makes no changes that will effect   */
        /* any of the palettes which are already realized).           */
        /**************************************************************/
        StoreAndRemoveUsedMarkings();
    }


set_up_realize_loop:

    /******************************************************************/
    /* Initialize our search range used when we are looking for empty */
    /* slots in the HW palette.                                       */
    /******************************************************************/


    /*
    **            Had to add this less than elegant code to compliment the
    ** the wonderful work done in the reducedefaultpalettesize. The default palette
    ** never goes to 16 colors in a seamless enabled driver, it goes to 20
    ** colors to accomodate 4 colors from windows. But the ulDirectDeviceDefaultPaletteSize
    ** variable is still 16, which is a lie. However, that value is used throughout
    ** the driver and also passed to the         driver so we really can't change
    ** its value. So unfortuanately we will change the math a little to compensate.
    */

#ifdef SEAMLESS
    bNoFreeSlotBefore = (BYTE)((ulDirectDeviceDefaultPaletteSize+4)/2);
    bNoFreeSlotAfter  = (BYTE)((255-(ulDirectDeviceDefaultPaletteSize+4)/2));
#else
    bNoFreeSlotBefore = (BYTE)(ulDirectDeviceDefaultPaletteSize/2);
    bNoFreeSlotAfter  = (BYTE)(255-(ulDirectDeviceDefaultPaletteSize/2));
#endif

    /******************************************************************/
    /* Loop through processing each entry in the logical palette.     */
    /******************************************************************/
    for (entry=0; entry<palcount; entry++)
    {
        /**************************************************************/
        /* If the palette entry is marked as PC_EXPLICIT then it is   */
        /* a direct index into the HW palette and no matching is      */
        /* required.                                                  */
        /**************************************************************/
        if (pdc->Palette->entries[entry].rgb.fcOptions & PC_EXPLICIT)
        {
            /**********************************************************/
            /* we just use the RGB value as the hw slot, but since    */
            /* the index is only one byte we just get the bBlue byte  */
            /**********************************************************/
            slot = pdc->Palette->entries[entry].rgb.bBlue;
            goto got_explicit_slot;
        }

        /**************************************************************/
        /* The palette entry is not marked as PC_EXPLICIT we will try */
        /* to find an existing entry in the palette which matches the */
        /* color we are looking for exactly. If we had a previous     */
        /* mapping for this palette then we will first try looking    */
        /* at the slot that the entry was last mapped to.             */
        /**************************************************************/
        if (localflags & PAL_CURRENT_OK)
        {
            slot = pdc->Palette->entries[entry].bCurrent;
            /**********************************************************/
            /* We can only use the existing mapping if the colors are */
            /* an exact match and if the HW slot is currently not     */
            /* either the HW slot or the palette entry are marked as  */
            /* reserved.                                              */
            /**********************************************************/
            if (   (HWPalette[slot].bRed   ==
                               pdc->Palette->entries[entry].rgb.bRed)
                && (HWPalette[slot].bGreen ==
                               pdc->Palette->entries[entry].rgb.bGreen)
                && (HWPalette[slot].bBlue  ==
                               pdc->Palette->entries[entry].rgb.bBlue))
            {
                /******************************************************/
                /* The colors are an exact match. Now we must check   */
                /* that the flags do not clash.                       */
                /******************************************************/
                if (pdc->Palette->entries[entry].rgb.fcOptions
                    & (PC_RESERVED | PC_NOCOLLAPSE) )
                {
                    /**************************************************/
                    /* We want a reserved or nocollapse slot so we    */
                    /* can only use the slot if it is not currently   */
                    /* being used and it is not part of the default   */
                    /* palette.                                       */
                    /**************************************************/

                    /**************************************************/
                    /* Defect 67450 - The logic was incorrect here.   */
                    /* In reality you could to use this slot as long  */
                    /* both PC_USED and PC_DEFAULT are not TRUE.  The */
                    /* previous code wouldn't use the slot if either  */
                    /* flag was ON.  This regression was inflicted    */
                    /* when some cleanup work was attempted.          */
                    /**************************************************/

                    /**************************************************/
                    /* Defect 68053 - Do not use the slot if it is    */
                    /* reserved for one of the system colors.         */
                    /**************************************************/
                    /**************************************************/
                    /* @74705 But...... also check the override flag  */
                    /* and slam the slot if it is set                 */
                    /**************************************************/
                    if (localflags & LCOL_OVERRIDE_DEFAULT_COLORS ||
                        !(HWPalette[slot].fcOptions & PC_DEFAULT))
                    {
                        /**********************************************/
                        /* MEB 11/20/92                               */
                        /* If we are changing the flags here then we  */
                        /* must consider this a changed h/w slot,     */
                        /* otherwise if we change nothing but flags   */
                        /* and do not indicate that the slots have    */
                        /* changed then no repainting will be done.   */
                        /* This means that other palette manager apps */
                        /* which were previously mapping to these     */
                        /* slots will still be doing so, and as we    */
                        /* may just have made them animating this is  */
                        /* not a good idea!                           */
                        /**********************************************/
                        if ((HWPalette[slot].fcOptions
                                   & (PC_RESERVED | PC_NOCOLLAPSE) ) !=
                            (pdc->Palette->entries[entry].rgb.fcOptions
                                   & (PC_RESERVED | PC_NOCOLLAPSE) ) )
                        {
                            HWSlotsChanged++;
                        }

                        HWPalette[slot].fcOptions =
                            pdc->Palette->entries[entry].rgb.fcOptions;
                        goto got_slot;
                    }
                }
                else
                {
                    /**************************************************/
                    /* We can use the slot so long as it is not both  */
                    /* used and reserved.                             */
                    /**************************************************/
                    if (!(   (HWPalette[slot].fcOptions & PC_USED)
                          && (HWPalette[slot].fcOptions & PC_RESERVED)))
                    {
                        /**********************************************/
                        /* Unnecessary to mark as used, since         */
                        /* got_slot will always do that for us.       */
                        /**********************************************/
                        goto got_slot;
                    }
                }
            }
        }

        /**************************************************************/
        /* The palette entry is not marked as PC_EXPLICIT and the     */
        /* existing mapping did not give a usable exactly matching    */
        /* slot so we will now search the whole of the palette for    */
        /* an exact matching slot. To make the test condition simpler */
        /* we will only do this if we do not mind sharing a HW slot   */
        /* (ie we are not processing a PC_RESERVED or PC_NOCOLLAPSE   */
        /* entry).                                                    */
        /**************************************************************/
        if (!(  pdc->Palette->entries[entry].rgb.fcOptions
              & (PC_RESERVED | PC_NOCOLLAPSE) ))
        {
            /**********************************************************/
            /* Palette entry is not marked RESERVED or NO_COLLAPSE so */
            /* we will try to find an existing entry that matches the */
            /* rgb we want.                                           */
            /**********************************************************/
            slot = ExactHWPaletteMatch(pdc->Palette->entries[entry].rgb);
            if (slot != PAL_ERROR)
            {
                /******************************************************/
                /* We found an exact match!                           */
                /******************************************************/
                goto got_slot;
            }
        }

        /**************************************************************/
        /* We did not manage to find an exact match with an existing  */
        /* slot so now we will look to see if we can find any free    */
        /* slots which we can map onto. If the current foreground     */
        /* palette is the default palette then we only want to look   */
        /* for slots which were free when the default palette was     */
        /* realized.  (This avoids changing the HW palette too much   */
        /* when the default palette has been realized as the          */
        /* foreground and so the background apps should hopefully get */
        /* the slots they had previously and will not have to         */
        /* repaint).  If the current foreground palette is not the    */
        /* default palette then we want to look for any free slot.    */
        /**************************************************************/
find_free_slot:
        if (hForeGroundPal == (PDEVPAL)DirectDeviceDefaultPalette)
        {
            while (bNoFreeSlotBefore <= bNoFreeSlotAfter)
            {
                if ( HWPalette[bNoFreeSlotBefore].fcOptions
                     & (PC_DEFAULT | PC_USED | PC_OLD) )
                {
                    bNoFreeSlotBefore++;
                }
                else
                {
                    slot = bNoFreeSlotBefore;
                    bNoFreeSlotBefore++;
                    HWPalette[slot] = pdc->Palette->entries[entry].rgb;
                    HWSlotsChanged++;

                    /**************************************************/
                    /* This was a free slot, so we can put the full   */
                    /* options flags that we need in here.            */
                    /**************************************************/
                    HWPalette[slot].fcOptions =
                        pdc->Palette->entries[entry].rgb.fcOptions;
                    goto got_slot;
                }
            }
        }
        else
        {
            while (bNoFreeSlotBefore <= bNoFreeSlotAfter)
            {
                if ( HWPalette[bNoFreeSlotBefore].fcOptions
                     & (PC_DEFAULT | PC_USED) )
                {
                    bNoFreeSlotBefore++;
                }
                else
                {
                    slot = bNoFreeSlotBefore;
                    bNoFreeSlotBefore++;
                    HWPalette[slot] = pdc->Palette->entries[entry].rgb;
                    HWSlotsChanged++;

                    /**************************************************/
                    /* This was a free slot, so we can put the full   */
                    /* options flags that we need in here.            */
                    /**************************************************/
                    HWPalette[slot].fcOptions =
                        pdc->Palette->entries[entry].rgb.fcOptions;
                    goto got_slot;
                }
            }
        }

        /**************************************************************/
        /* We did not manage to find an exact match with an existing  */
        /* slot nor an empty slot so now we must consider whether we  */
        /* can reduce the size of the default palette in order to     */
        /* obtain more empty slots.                                   */
        /**************************************************************/
        /**************************************************************/
        /* If we are in the foreground then we will allow the default */
        /* palette to be reduced to a size of only 16 entries. If we  */
        /* are in the background then we will not let the default     */
        /* palette be reduced below a size of 64 entries.             */
        /**************************************************************/
        if (   (   (*pflType & RP_FOREGROUND)
                && (ulDirectDeviceDefaultPaletteSize > 16) )
            || (ulDirectDeviceDefaultPaletteSize > 64) )
        {
            /**********************************************************/
            /* We will reduce the size of the default palette and     */
            /* allocate a new free slot to this entry.  We will call  */
            /* ReduceDefaultPaletteSize to change the size and        */
            /* entries in the default palette.  It will also adjust   */
            /* ulDirectDeviceDefaultPaletteSize to reflect the new    */
            /* allocation of slots available to palette manager       */
            /* palettes.  We return the RP_DEFAULTSCHANGED flag so    */
            /* that PMWIN can send paint messages to all of the       */
            /* desktop.                                               */
            /**********************************************************/
            DefaultsChanged = DefaultsChanged + ReduceDefaultPaletteSize();
            *pflType |= RP_DEFAULTSCHANGED;

#ifdef SEAMLESS                                                                       /*          */
            bNoFreeSlotBefore = (BYTE)((ulDirectDeviceDefaultPaletteSize+4)/2);       /*          */
            bNoFreeSlotAfter  = (BYTE)((255-(ulDirectDeviceDefaultPaletteSize+4)/2)); /*          */
#else                                                                                 /*          */
            bNoFreeSlotBefore = (BYTE)(ulDirectDeviceDefaultPaletteSize/2);
            bNoFreeSlotAfter  = (BYTE)(255-(ulDirectDeviceDefaultPaletteSize/2));
#endif                                                                                /*          */

            /**********************************************************/
            /* Unfortunately we know we have just done a dirty deed!  */
            /* We may have already mapped entries to some of the      */
            /* defaults we just changed (both in this palette and in  */
            /* previously realized palettes).  If we are in the       */
            /* foreground then we can simply start the realize again. */
            /* Otherwise we increment to global optimization id to    */
            /* make sure when that when the desktop is repainted then */
            /* no palette realizations are optimized out.             */
            /**********************************************************/
            if (*pflType & RP_FOREGROUND)
            {
                RemoveUsedMarkings();
                goto set_up_realize_loop;
            }
            usGlobalOptimizeID++;
#ifdef SEAMLESS
            /**************************************************************/
            /* Update the seamless palette changed time stamp to indicate */
            /*         palette mappings could now be invalid.             */
            /**************************************************************/
            SeamlessData.ulLastPalUpdate++;
#endif
            goto find_free_slot;
        }

        /**************************************************************/
        /* We did not manage to find an exact match with an existing  */
        /* slot nor an empty slot and we could not reduce the size of */
        /* the default palette so now we must see if we can overwrite */
        /* one of the entries in the default palette.                 */
        /**************************************************************/
        if (localflags & LCOL_OVERRIDE_DEFAULT_COLORS)
        {
            /**********************************************************/
            /* First search the bottom half of the default palette to */
            /* see if we can find an unused slot.                     */
            /**********************************************************/
#ifdef SEAMLESS                                                                       /*          */
            for (slot = 0; slot < ((ulDirectDeviceDefaultPaletteSize+4)/2); slot++)   /*          */
#else                                                                                 /*          */
            for (slot = 0; slot < (ulDirectDeviceDefaultPaletteSize/2); slot++)
#endif                                                                                /*          */
            {
                if (!(HWPalette[slot].fcOptions & PC_USED))
                {
                    /**************************************************/
                    /* We have found a default slot which is not      */
                    /* being used by any of the palette manager       */
                    /* palettes so we will overwrite it with the      */
                    /* value we want to use.  Any non-palette manager */
                    /* DCs using this slot are just unlucky!          */
                    /**************************************************/
                    HWPalette[slot] = pdc->Palette->entries[entry].rgb;
                    fForeGroundOverwrote = TRUE;
                    HWSlotsChanged++;

                    /**************************************************/
                    /* We forced this to be treated like a free slot, */
                    /* so we can put the full options flags that we   */
                    /* need in here.                                  */
                    /**************************************************/
                    HWPalette[slot].fcOptions =
                        pdc->Palette->entries[entry].rgb.fcOptions;
                    goto got_slot;
                }
            }

            /**********************************************************/
            /* We did not find a free slot in the bottom half of the  */
            /* default palette so now search the top half of the      */
            /* default palette to see if we can find an unused slot.  */
            /**********************************************************/
#ifdef SEAMLESS                                                                       /*          */
            for (slot = HW_PAL_SIZE-((ulDirectDeviceDefaultPaletteSize+4)/2);         /*          */
                 slot < HW_PAL_SIZE;                                                  /*          */
                 slot++ )                                                             /*          */
#else                                                                                 /*          */
            for (slot = HW_PAL_SIZE-(ulDirectDeviceDefaultPaletteSize/2);
                 slot < HW_PAL_SIZE;
                 slot++ )
#endif                                                                                /*          */
            {
                if (!(HWPalette[slot].fcOptions & PC_USED))
                {
                    /**************************************************/
                    /* We have found a default slot which is not      */
                    /* being used by any of the palette manager       */
                    /* palettes so we will overwrite it with the      */
                    /* value we want to use. Any non-palette manager  */
                    /* DCs using this slot are just unlucky!          */
                    /**************************************************/
                    HWPalette[slot] = pdc->Palette->entries[entry].rgb;
                    fForeGroundOverwrote = TRUE;
                    HWSlotsChanged++;

                    /**************************************************/
                    /* We forced this to be treated like a free slot, */
                    /* so we can put the full options flags that we   */
                    /* need in here.                                  */
                    /**************************************************/
                    HWPalette[slot].fcOptions =
                        pdc->Palette->entries[entry].rgb.fcOptions;
                    goto got_slot;
                }
            }
        }

        /**************************************************************/
        /* We did not manage to find an exact match with an existing  */
        /* slot or an empty slot and we could not reduce the size of  */
        /* the default palette or overwrite any of the entries in the */
        /* default palette so we must now try to find the nearest     */
        /* possible color match out of the existing entries in the HW */
        /* palette.                                                   */
        /**************************************************************/

        /**************************************************************/
        /* We only have to do an exact search if we did not do one    */
        /* earlier. ie if the request was for a PC_RESERVED or        */
        /* PC_NOCOLLAPSE slot.                                        */
        /**************************************************************/
        if (pdc->Palette->entries[entry].rgb.fcOptions
            & (PC_RESERVED | PC_NOCOLLAPSE) )
        {
            slot = ExactHWPaletteMatch(pdc->Palette->entries[entry].rgb);
            if (slot == PAL_ERROR)
            {
                slot = ClosestHWPaletteMatch(pdc->Palette->entries[entry].rgb);
            }
        }
        else
        {
            slot = ClosestHWPaletteMatch(pdc->Palette->entries[entry].rgb);
        }

        if (slot == PAL_ERROR)
        {
            /**********************************************************/
            /* All of the HW palette entries are reserved! We will    */
            /* just map to slot zero because it is as good as any     */
            /* other slot since reserved slots are likely to change   */
            /* very quickly (ie. there is no point in looking for a   */
            /* nearest color match).                                  */
            /**********************************************************/
            slot = 0;
        }

        /**************************************************************/
        /* Having had to map to an already used slot, we are unable   */
        /* to force any of our options flags onto the hardware        */
        /* palette.  We will just have to put up with those that are  */
        /* there.  (Note that since we fall through to got_slot, then */
        /* we will mark the slot as used, but we knew it was used     */
        /* anyway !)                                                  */
        /**************************************************************/

got_slot:
        /**************************************************************/
        /* We now have a slot to use in our mapping which points to   */
        /* a slot in the HW palette that conains the rgb we want to   */
        /* map to.  We must set the used flags so that other palettes */
        /* do not try to overwrite this slot.  (The exception is the  */
        /* case of an explicit entry in which case we do not set the  */
        /* used flag because we will always goto got_explicit_slot).  */
        /**************************************************************/
        HWPalette[slot].fcOptions |= PC_USED;

got_explicit_slot:
        /**************************************************************/
        /* Save the slot number as the current mapping.               */
        /**************************************************************/
        pdc->Palette->entries[entry].bCurrent = (BYTE)slot;

        /**************************************************************/
        /* have we changed a mapping here                             */
        /**************************************************************/
        if ((pdc->Palette->entries[entry].rgb.fcOptions & PC_NEW) ||
            (pdc->Palette->entries[entry].bPrevious != (BYTE)slot) )
        {
            pdc->Palette->entries[entry].rgb.fcOptions &= ~PC_NEW;
            MappingsChanged++;
        }

    } /* for each entry in the logical palette */


no_need_to_realize:
    if (*pflType & RP_FOREGROUND)
    {
        /**************************************************************/
        /* At this point if we just realized the foreground palette   */
        /* we want to check if we really did make some changes to the */
        /* HW palette.  (This is not as unlikely as you might at      */
        /* first think - cached DCs palettes are frequently selected  */
        /* in and out so appear as new palettes, even if nothing has  */
        /* really changed).  If we did not make any changes then we   */
        /* optimize things by just returning zero as the number of    */
        /* mappings changed so that realize messages are not be sent  */
        /* to all of the background windows.                          */
        /**************************************************************/
        if ((HWSlotsChanged == 0))
        {
            /**********************************************************/
            /* We have not made any changes to the HW palette.        */
            /* Copy back the old used flags so that we do not loose   */
            /* the old palette mappings - pmwin should not send off   */
            /* realize messages since no slots have changed.          */
            /**********************************************************/
            RestoreUsedMarkings();
        }
    }

    /******************************************************************/
    /* We must now update the palette flags to indicate the new state */
    /* of the palette.                                                */
    /******************************************************************/
    if (localflags & PAL_CURRENT_OK)
    {
        /**************************************************************/
        /* On entry to the routine there was a current mapping so we  */
        /* must now set the flag to indicate that the previous        */
        /* mapping is now valid.                                      */
        /**************************************************************/
        localflags |= PAL_PREVIOUS_OK;
    }

    /******************************************************************/
    /* On exit we always have a valid current mapping and we clear    */
    /* the PAL_CHANGED flag to indicate that the palette does not     */
    /* need realizing.                                                */
    /******************************************************************/
    localflags &= ~PAL_CHANGED;
    localflags |= PAL_CURRENT_OK;

    /******************************************************************/
    /* Put the flags back in their far pointer place.                 */
    /******************************************************************/
    pdc->Palette->usFlags = (USHORT)localflags;

    /******************************************************************/
    /* see to the return values NB.  8514 prototype does not seem to  */
    /* include DefaultsChanged in its return value                    */
    /******************************************************************/
    *pcSlotsChanged = HWSlotsChanged /* + DefaultsChanged */ ;

    return (MappingsChanged);
}

/**********************************************************************/
/* ClosestHWPaletteMatch                                              */
/*                                                                    */
/*   This routine searches the hw palette for the closest matching    */
/*   colour. It does not do a search for an exact match before        */
/*   doing the nearest color search because this routine should only  */
/*   be called if an exact match has not been found by a previous     */
/*   call to ExactHWPaletteMatch.                                     */
/*                                                                    */
/*   We can never match to a PC_RESERVED HW slot. If all entries      */
/*   are PC_RESERVED then we cannot do a closest match and so we      */
/*   return PAL_ERROR.                                                */
/*                                                                    */
/* Parameters:                                                        */
/*      rgb             RGB value to search for                       */
/*                                                                    */
/* Returns:                                                           */
/*      index of closest match                                        */
/*      or PAL_ERROR (-1) if no match found.                          */
/*                                                                    */
/**********************************************************************/

ULONG DRIVERCALL ClosestHWPaletteMatch(RGB2 rgb)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    ULONG   Index;                     /* index of closest match      */

#ifdef FIREWALLS
    /******************************************************************/
    /* We will do a check for an exact match as a firewall.  The      */
    /* convension is that this routine will never be called unless a  */
    /* previous call to ExactHWPaletteMatch failed.                   */
    /******************************************************************/
    if (ExactHWPaletteMatch(rgb) != PAL_ERROR)
    {
        haltproc();
    }
#endif /* FIREWALLS */


    /******************************************************************/
    /* Initialize the minimum differnce we have found so far.         */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;

    /******************************************************************/
    /* We will return PAL_ERROR (-1) if all entries are PC_RESERVED   */
    /* and PC_USED.                                                   */
    /******************************************************************/
    Index = PAL_ERROR;

    for (i = 0; i < HW_PAL_SIZE; i++)
    {
        if (!(HWPalette[i].fcOptions & PC_RESERVED))
        {
            /**********************************************************/
            /* this is not reserved so we'll see how close it is      */
            /**********************************************************/
            /**********************************************************/
            /* find the distance between this palette entry and the   */
            /* required color                                         */
            /**********************************************************/
            Diff = rgb2_diff(rgb, HWPalette[i]);

            /**********************************************************/
            /* If this is closer than our previous closest then reset */
            /* MinDiff and set Index                                  */
            /**********************************************************/
            if (Diff < MinDiff)
            {
                MinDiff   = Diff;
                Index = i;
            }
        }
    }
    return(Index);
}

/**********************************************************************/
/* ExactHWPaletteMatch                                                */
/*                                                                    */
/*   This routine searches the hw palette for an exact matching       */
/*   colour.                                                          */
/*                                                                    */
/*   We can never match to a PC_RESERVED HW slot. If we do not        */
/*   find an exact match that is not PC_RESERVED then we return       */
/*   PAL_ERROR (-1) to indicate that the search for a match failed.   */
/*                                                                    */
/*   We search through the PC_DEFAULT slots first, before serching    */
/*   the rest of the palette (note there is no guarentee that the     */
/*   default entries are still in place so search the defaults        */
/*   backwards since we overwrite entries from low to high indices)   */
/*                                                                    */
/* Parameters:                                                        */
/*      rgb             RGB value to search for                       */
/*                                                                    */
/* Returns:                                                           */
/*      index of closest match                                        */
/*      or PAL_ERROR (-1) if no match found.                          */
/*                                                                    */
/**********************************************************************/
ULONG DRIVERCALL ExactHWPaletteMatch(RGB2 rgb)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   i;                         /* loop variable               */

    /******************************************************************/
    /* First check the top half of the default palette.               */
    /******************************************************************/
    for (i = 256-(ulDirectDeviceDefaultPaletteSize/2);
         i < HW_PAL_SIZE;
         i++)
    {
        if (!(HWPalette[i].fcOptions & PC_RESERVED) &&
            HWPalette[i].bRed   == rgb.bRed   &&
            HWPalette[i].bGreen == rgb.bGreen &&
            HWPalette[i].bBlue  == rgb.bBlue )
        {
            return(i);
        }
    }

    /******************************************************************/
    /* Now check the bottom half of the default palette.              */
    /******************************************************************/
    for (i = 0; i < (ulDirectDeviceDefaultPaletteSize/2); i++)
    {
        if (!(HWPalette[i].fcOptions & PC_RESERVED) &&
            HWPalette[i].bRed   == rgb.bRed   &&
            HWPalette[i].bGreen == rgb.bGreen &&
            HWPalette[i].bBlue  == rgb.bBlue )
        {
            return(i);
        }
    }

    /******************************************************************/
    /* Now check the major block of the palette for an exact match.   */
    /******************************************************************/
    for (i = ulDirectDeviceDefaultPaletteSize/2;
         i < (ULONG)(256-(ulDirectDeviceDefaultPaletteSize/2));
         i++ )
    {
        if (!(HWPalette[i].fcOptions & PC_RESERVED) &&
            HWPalette[i].bRed   == rgb.bRed   &&
            HWPalette[i].bGreen == rgb.bGreen &&
            HWPalette[i].bBlue  == rgb.bBlue )
        {
            return(i);
        }
    }

    /******************************************************************/
    /* An exact match was not found so return PAL_ERROR (-1).         */
    /******************************************************************/
    return(PAL_ERROR);
}


/**********************************************************************/
/* rgb2_diff                                                          */
/*                                                                    */
/*   Routine to find the (square of) the euclidian distance between   */
/*   2 RGB values.                                                    */
/*                                                                    */
/* Parameters:                                                        */
/*      rgb1            RGB value 1                                   */
/*      rgb2            RGB value 2                                   */
/*                                                                    */
/* Returns:                                                           */
/*      (square of) distance betwwen 2 RGB values                     */
/* Error Returns:                                                     */
/*      n/a                                                           */
/**********************************************************************/

ULONG DRIVERCALL rgb2_diff (RGB2 rgb1,
                            RGB2 rgb2)

{
    /******************************************************************/
    /* rgb2_diff calculates a value which is proportional to          */
    /* the difference (in RGB space) between the two supplied colors  */
    /******************************************************************/

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    LONG        RedDiff,GreenDiff,BlueDiff;

    /******************************************************************/
    /* WARNING if you try and optimize this check that the compiler   */
    /* generates the code you think it should                         */
    /* (subtraction of BYTEs gives an unsigned SHORT ? ! )            */
    /******************************************************************/
    #define SQR(X) ((X)*(X))

    RedDiff   = (SHORT)rgb1.bRed   - (SHORT)rgb2.bRed;
    GreenDiff = (SHORT)rgb1.bGreen - (SHORT)rgb2.bGreen;
    BlueDiff  = (SHORT)rgb1.bBlue  - (SHORT)rgb2.bBlue;

    return( SQR(RedDiff)   +
            SQR(GreenDiff) +
            SQR(BlueDiff)   );

    #undef SQR
}

/**********************************************************************/
/* UpdateColors                                                       */
/*                                                                    */
/*   Changes the h/w indices for the visible area of the DC as an     */
/*   alternative to redrawing.  Changes from the previous palette     */
/*   realization to the current one.                                  */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc             DC handle                                     */
/*      pdc             device DC handle                              */
/*      FunN          function and COM_ flags                         */
/*                                                                    */
/* Returns:                                                           */
/*      OK                                                            */
/* Error Returns:                                                     */
/*      ERROR_ZERO                                                    */
/**********************************************************************/

DDIENTRY UpdateColors(HDC          hdc,
                      PDC          pdcArg,
                      ULONG        FunN)

{
    ULONG       i;
    ULONG       identity;
    ULONG       PalCount;
    BYTE        previous;
    BYTE        current;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);


    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD);

    /******************************************************************/
    /* NB.  we dont firewall the path/area test because the 8514      */
    /* prototype does not                                             */
    /******************************************************************/
    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we raise an error and leave immediately.       */
    /******************************************************************/
    if (FunNTest(COM_AREA))
    {
        /**************************************************************/
        /* We have been called within an area definition              */
        /**************************************************************/
        LogError(PMERR_INV_IN_AREA);
        ExitDriver(pdcArg, FunN, EDF_STANDARD);
        return( ERROR_ZERO );
    }

    if (FunNTest(COM_PATH))
    {
        /**************************************************************/
        /* We have been called within a path definition               */
        /**************************************************************/
        LogError(PMERR_INV_IN_PATH);
        ExitDriver(pdcArg, FunN, EDF_STANDARD);
        return( ERROR_ZERO );
    }

    /******************************************************************/
    /* we only update colors for device DCs                           */
    /* there is no update we can do if the palette does not have      */
    /* a previous realization (NB. the default palette never has a    */
    /* previous realization)                                          */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT &&
        pdc->Palette->usFlags & PAL_PREVIOUS_OK)
    {
        /**************************************************************/
        /* set up an identity mapping                                 */
        /**************************************************************/
        identity = TRUE;
        for (i=0; i<HW_PAL_SIZE; i++)
        {
            UCMapping[i] = (BYTE)i;
        }

        /**************************************************************/
        /* now fill in the mapping as required                        */
        /**************************************************************/
        PalCount = pdc->Palette->usCountStored;
        for (i=0; i<PalCount; i++)
        {
            previous = pdc->Palette->entries[i].bPrevious;
            current  = pdc->Palette->entries[i].bCurrent;
            if (UCMapping[previous] != current)
            {
                UCMapping[previous] = current;
                identity = FALSE;
            }
        }
        if (!identity)
        {
            /**********************************************************/
            /* mapping is not the identity so we must actually update */
            /* the colors                                             */
            /**********************************************************/
            /**********************************************************/
            /* do the appropriate update into all visible regions     */
            /**********************************************************/
            GetVisRectsControl.ircStart = 1;
            GetVisRectsControl.crc = NUM_VIS_RECTS;
#ifdef POST174
            GetVisRectsControl.ulDirection = RECTDIR_LFRT_BOTTOP;
#else /* POST174 */
            GetVisRectsControl.usDirection = RECTDIR_LFRT_BOTTOP;
#endif /* POST174 */

            do /* for each rectangle comprising the visible region    */
            {
                /******************************************************/
                /* Get some vis region Rectangles from the engine     */
                /******************************************************/
                EnginesDispatchTable[NGreGetVisRects & 0xff](
                                          pdc->DCIhdc,
                                          NULL,
                                          &GetVisRectsControl,
                                          VisRects,
                                          NULL,
                                          NGreGetVisRects);

                if (GetVisRectsControl.crcReturned)
                {
                    /**************************************************/
                    /* we were given some rectangles                  */
                    /**************************************************/
                    /**************************************************/
                    /* reset the start rectangle for next iteration   */
                    /**************************************************/
                    GetVisRectsControl.ircStart +=
                                         GetVisRectsControl.crcReturned;

                    for (i=0; i < GetVisRectsControl.crcReturned; i++)
                    {
                        /**********************************************/
                        /* This rectangle is on the screen so it may  */
                        /* be 'contaminated' by any software cursor.  */
                        /* Thus consider excluding it.                */
                        /*                                            */
                        /* The cast gets rid of a warning, and the    */
                        /* subroutine copes even though the rectangle */
                        /* is not Devpoints (ie ints) but LONGs       */
                        /**********************************************/
                        if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
                        {
                           eddm_ExcludeCursor((pDevPoint)&VisRects[i],
                                              COORD_DEVICE);
                        }

                        /**********************************************/
                        /* change the rectangle to hw coords          */
                        /**********************************************/
                        VisRects[i].xLeft  += pdc->DCIOrigin.X;
                        VisRects[i].xRight += pdc->DCIOrigin.X;
                        VisRects[i].yTop    = pdc->DCIConvFactor -
                                              VisRects[i].yTop;
                        VisRects[i].yBottom = pdc->DCIConvFactor -
                                              VisRects[i].yBottom;

                        /**********************************************/
                        /* do the update for this rectangle           */
                        /**********************************************/
                        UpdateRectangle(&VisRects[i]);

                        /**********************************************/
                        /* we no longer need to have a software       */
                        /* cursor excluded                            */
                        /**********************************************/
                        reenable_cursor();
                    }
                }
            } while ( GetVisRectsControl.crcReturned );
        } /* mapping is not the identity */
    } /* DC is direct */

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD);

    return(OK);
}

#ifdef OMIT
/**********************************************************************/
/* this has now been rewritten in assembler                           */
/**********************************************************************/

/**********************************************************************/
/* update rectangle does the update colours for a single passed       */
/* rectangle (the rectangle is already converted to hw coords)        */
/**********************************************************************/
VOID DRIVERCALL UpdateRectangle(PRECTL rectangle)
{
    ULONG       line;
    ULONG       pel;
    LONG        tempDrawMode;

    /******************************************************************/
    /* we dont do any checks on the rectangle                         */
    /* the engine gave us it so we assume that it is ok               */
    /******************************************************************/
    for (line = rectangle->yBottom; line < rectangle->yTop; line++)
    {
        /**************************************************************/
        /* read the line into our buffer                              */
        /**************************************************************/

        /**************************************************************/
        /* set the mixes for a straight copy                          */
        /**************************************************************/
        #ifndef   _8514
        ShadowXGARegs.FgMix = HWMIX_SOURCE ;
        ShadowXGARegs.BgMix = HWMIX_SOURCE ;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;


        /**************************************************************/
        /* set the source bitmap dimensions and format (the screen)   */
        /**************************************************************/
        ShadowXGARegs.PixMapFormatB = DirectListEntry.Info.HWFormat;
        ShadowXGARegs.PixMapWidthB  = DirectListEntry.Info.HWWidth;
        ShadowXGARegs.PixMapHeightB = DirectListEntry.Info.HWHeight;
        ShadowXGARegs.PixMapBaseB   = DirectListEntry.BMPhys;

        /**************************************************************/
        /* set the destination to be the phunk area                   */
        /**************************************************************/
        ShadowXGARegs.PixMapFormatA = DirectListEntry.Info.HWFormat;
        ShadowXGARegs.PixMapWidthA  = DirectListEntry.Info.HWWidth;
        ShadowXGARegs.PixMapHeightA = 0;
        ShadowXGARegs.PixMapBaseA   = pPhunkPhys;

        /**************************************************************/
        /* set the blt coordinates                                    */
        /**************************************************************/
        ShadowXGARegs.DstXAddr =
        ShadowXGARegs.DstYAddr = 0;
        ShadowXGARegs.SrcXAddr = rectangle->xLeft;
        ShadowXGARegs.SrcYAddr = line;

        /**************************************************************/
        /* Now the blt dimensions                                     */
        /**************************************************************/
        ShadowXGARegs.OpDim1 = rectangle->xRight - rectangle->xLeft - 1;
        ShadowXGARegs.OpDim2 = 0;

        /**************************************************************/
        /* Set the pixel op to be the blt that we want.               */
        /**************************************************************/
        ShadowXGARegs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_B |
                              DST_PIX_MAP_A |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB ;
        #else
        Shadow8514Regs.FgMix = HWMIX_SOURCE ;
        Shadow8514Regs.BgMix = HWMIX_SOURCE ;
        Shadow8514Regs.ColCompCond = COLCOMP_ALWAYS;


        /**************************************************************/
        /* set the source bitmap dimensions and format (the screen)   */
        /**************************************************************/
        Shadow8514Regs.PixMapFormatB = DirectListEntry.Info.HWFormat;
        Shadow8514Regs.PixMapWidthB  = DirectListEntry.Info.HWWidth;
        Shadow8514Regs.PixMapHeightB = DirectListEntry.Info.HWHeight;
        Shadow8514Regs.PixMapBaseB   = DirectListEntry.BMPhys;

        /**************************************************************/
        /* set the destination to be the phunk area                   */
        /**************************************************************/
        Shadow8514Regs.PixMapFormatA = DirectListEntry.Info.HWFormat;
        Shadow8514Regs.PixMapWidthA  = DirectListEntry.Info.HWWidth;
        Shadow8514Regs.PixMapHeightA = 0;
        Shadow8514Regs.PixMapBaseA   = pPhunkPhys;

        /**************************************************************/
        /* set the blt coordinates                                    */
        /**************************************************************/
        Shadow8514Regs.DstXAddr =
        Shadow8514Regs.DstYAddr = 0;
        Shadow8514Regs.SrcXAddr = rectangle->xLeft;
        Shadow8514Regs.SrcYAddr = line;

        /**************************************************************/
        /* Now the blt dimensions                                     */
        /**************************************************************/
        Shadow8514Regs.OpDim1 = rectangle->xRight - rectangle->xLeft - 1;
        Shadow8514Regs.OpDim2 = 0;

        /**************************************************************/
        /* Set the pixel op to be the blt that we want.               */
        /**************************************************************/
        Shadow8514Regs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_B |
                              DST_PIX_MAP_A |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB ;
        #endif

        /**************************************************************/
        /* Do the operation. We will need to use the hardware to do   */
        /* this even if we are in softDraw mode. We will restore the  */
        /* drawing mode once the next blt has been done.              */
        /**************************************************************/
        tempDrawMode = softDrawInUse;
        softDrawInUse = FALSE;
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );

        /**************************************************************/
        /* wait for the data to be in the buffer                      */
        /**************************************************************/
        WaitForRealHW;

        for (pel=0;
             pel < rectangle->xRight - rectangle->xLeft - 1;
             pel++)
        {
            pPhunkVirt[pel] = UCMapping[pPhunkVirt[pel]];
        }

        /**************************************************************/
        /* write the buffer out again by reversing the blt            */
        /**************************************************************/
        /**************************************************************/
        /* set the blt coordinates                                    */
        /**************************************************************/
        #ifndef _8514
        ShadowXGARegs.SrcXAddr =
        ShadowXGARegs.SrcYAddr = 0;
        ShadowXGARegs.DstXAddr = rectangle->xLeft;
        ShadowXGARegs.DstYAddr = line;

        /**************************************************************/
        /* Now the blt dimensions                                     */
        /**************************************************************/
        ShadowXGARegs.OpDim1 = rectangle->xRight - rectangle->xLeft - 1;
        ShadowXGARegs.OpDim2 = 0;

        /**************************************************************/
        /* And go for it..                                            */
        /**************************************************************/
        ShadowXGARegs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_A |
                              DST_PIX_MAP_B |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB ;
        #else
        Shadow8514Regs.SrcXAddr =
        Shadow8514Regs.SrcYAddr = 0;
        Shadow8514Regs.DstXAddr = rectangle->xLeft;
        Shadow8514Regs.DstYAddr = line;

        /**************************************************************/
        /* Now the blt dimensions                                     */
        /**************************************************************/
        Shadow8514Regs.OpDim1 = rectangle->xRight - rectangle->xLeft - 1;
        Shadow8514Regs.OpDim2 = 0;

        /**************************************************************/
        /* And go for it..                                            */
        /**************************************************************/
        Shadow8514Regs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_A |
                              DST_PIX_MAP_B |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB ;
        #endif

        /**************************************************************/
        /* Do the operation. We will need to use the hardware to do   */
        /* this even if we are in softDraw mode. Restore the drawing  */
        /* mode once we have done the blt.                            */
        /**************************************************************/
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );
        softDrawInUse = tempDrawMode;


    }
}


#endif /* OMIT */


/**********************************************************************/
/* QueryHWPaletteInfo                                                 */
/*                                                                    */
/* Return the RGB values that are actually in the hardware palette.   */
/* The order of the returned colors is the same as in the hardware,   */
/* so that programs such as the RTG (Random Testcase Generator) can   */
/* predict the results of color mixing, which happens between palette */
/* indices.                                                           */
/*                                                                    */
/**********************************************************************/

DDIENTRY QueryHWPaletteInfo(HDC    hdc,
                            ULONG  ulStart,
                            ULONG  cclr,
                            PULONG pclr,
                            PDC    pdcArg,
                            ULONG  FunN)

{
    ULONG      i;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* if the count is zero then we are being asked for the size of   */
    /* the palette                                                    */
    /* Note: this could be done before an enter driver, but we often  */
    /* use enter driver as a convenient place to put a breakpoint...  */
    /******************************************************************/
    if (cclr == 0)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return (ULONG)SizeOfHWPalette;
    }

    /******************************************************************/
    /* the 8514 prototype returns at once if too many entries are     */
    /* asked for                                                      */
    /******************************************************************/
    if (cclr + ulStart > SizeOfHWPalette)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return 0L;
    }

    /******************************************************************/
    /* now loop to return all the entries                             */
    /* only return the RGB and external options (ie strip internal    */
    /* PC_ flags)                                                     */
    /******************************************************************/
    i = cclr;
    while (i--)
    {
        *pclr++ = URGB(HWPalette[ulStart]) & RGB_PLUS_MASK;
        ulStart++;
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* return the number of entries in the array                      */
    /******************************************************************/
    return(cclr);
}

/**********************************************************************/
/* QueryPaletteRealization                                            */
/*                                                                    */
/* Return the mapping from the logical palette in the DC to the       */
/* hardware palette, as an array of ULONGs.  This function gives the  */
/* RTG the ability to predict the outcome of color mixing operations. */
/*                                                                    */
/* NOTE: the definition of this routine is so similar to              */
/*       QueryHWPalette that it is very strange that the 8514 prototyp*/
/*       implementation of the routines is so different in regards    */
/*       to handling 'strange' input combinations                     */
/*       However the best we can do is assume the 8514 authors know   */
/*       what they are doing...                                       */
/**********************************************************************/

DDIENTRY QueryPaletteRealization(HDC     hdc,
                                 ULONG   ulStart,
                                 ULONG   cclr,
                                 PULONG  pclr,
                                 PDC     pdcArg,
                                 ULONG   FunN)

{
    ULONG      i;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);


    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* if the count is zero then we are being asked for the size of   */
    /* the palette                                                    */
    /*                                                                */
    /* Note that we subtract ulStart merely because thats what        */
    /* the 8514 prototype driver does...                              */
    /******************************************************************/
    if (cclr == 0)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return (ULONG)pdc->Palette->usMax - ulStart;
    }

    /******************************************************************/
    /* unlike QueryHWPalette which returns at once if too many entries*/
    /* are asked for, the 8514 prototype retricts the number of       */
    /* entries to return as would be expected for this routine        */
    /******************************************************************/
    cclr = min(cclr, pdc->Palette->usMax - ulStart + 1);

    /******************************************************************/
    /* now loop to return all the entries                             */
    /******************************************************************/
    i = cclr;
    while (i--)
    {
        *pclr++ = (ULONG)(pdc->Palette->entries[ulStart].bCurrent);
        ulStart++;
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* return the number of entries in the array                      */
    /******************************************************************/
    return(cclr);
}

/**********************************************************************/
/* DeviceResizePalette                                                */
/*                                                                    */
/*   Changes the size of a logical palette.                           */
/*                                                                    */
/*   If reducing the size removed entries are discarded.              */
/*   If increasing the size, new entries are set to black.            */
/*                                                                    */
/* Parameters:                                                        */
/*      hdc             DC handle                                     */
/*      hdevpal         palette handle                                */
/*      ulSize          new palette size                              */
/*      pdc             device DC handle                              */
/*      FunN          function and COM_ flags                         */
/*                                                                    */
/* Returns:                                                           */
/*      OK                                                            */
/* Error Returns:                                                     */
/*      n/a                                                           */
/**********************************************************************/

DDIENTRY DeviceResizePalette(HDC     hdc,
                             PDEVPAL hdevpal,
                             ULONG   ulSize,
                             PDC     pdcArg,
                             ULONG   FunN)

{
    ULONG      oldmax;
    ULONG      ulMax;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* get old size                                                   */
    /******************************************************************/
    oldmax = hdevpal->usMax;

    /******************************************************************/
    /* store the new size                                             */
    /******************************************************************/
    ulMax = ulSize - 1;
    hdevpal->usMax = (USHORT)ulMax;

    /******************************************************************/
    /* if the size changed then flag rerealizalion will be needed     */
    /******************************************************************/
    if (ulMax != oldmax)
    {
        hdevpal->usFlags |= PAL_CHANGED;

        /**************************************************************/
        /* limit the new maximum to the size we actually store        */
        /**************************************************************/
        /* Defect 63839 - Remove 256 entry logical palette limit      */
        ulMax = min(ulMax, hdevpal->usCountStored - 1);

        /**************************************************************/
        /* keep the number stored in the palette structure            */
        /**************************************************************/
        pdc->Palette->usCountStored = (USHORT)(ulMax + 1);

        /**************************************************************/
        /* if the palette has been enlarged then zero any new entries */
        /*  this sets colors to black and all flags clear             */
        /**************************************************************/
        if (oldmax < ulMax)
        {
            memset( &hdevpal->entries[oldmax+1],
                    0,
                    sizeof(PALENTRY) * (ulMax - oldmax));
        }

        /******************************************************************/
        /* Invalidate the palette mapping cache if it uses this palette.  */
        /******************************************************************/
        ChangedPalette(hdevpal);
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    return(OK);
}

/**********************************************************************/
/* NearestPaletteIndex finds the logical index in the logical         */
/* palette which will give the nearest RGB to the supplied RGB value. */
/*                                                                    */
/* The somewhat unexpected parameters are to make these the same as   */
/* eddc_NearestPhysicalColor, so that the bitmap conversion code can  */
/* call either of them indirectly as appropriate.                     */
/**********************************************************************/

ULONG DRIVERCALL NearestPaletteIndex(RGB2 RGBColor)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    ULONG   Index;                     /* index of closest match      */

    /******************************************************************/
    /* First check for exact match                                    */
    /******************************************************************/
    for (i = 0; i < pdc->Palette->usCountStored; i++)
    {
        /**************************************************************/
        /* check the palette for exact matches                        */
        /**************************************************************/
        if (RGBColor.bBlue  == pdc->Palette->entries[i].rgb.bBlue  &&
            RGBColor.bGreen == pdc->Palette->entries[i].rgb.bGreen &&
            RGBColor.bRed   == pdc->Palette->entries[i].rgb.bRed )
        {
            return(i);
        }
    }

    /******************************************************************/
    /* If not found then look for closest                             */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;
    for (i = 0; i < pdc->Palette->usCountStored; i++)
    {
        /**************************************************************/
        /* find the distance between this palette entry and the       */
        /* required color                                             */
        /**************************************************************/
        Diff = rgb2_diff(RGBColor, pdc->Palette->entries[i].rgb);

        /**************************************************************/
        /* If this is closer than our previous closest then reset     */
        /* MinDiff and set Index                                      */
        /**************************************************************/
        if (Diff < MinDiff)
        {
            MinDiff   = Diff;
            Index = i;
        }
    }
    return(Index);
}



/**********************************************************************/
/* This routine should be called whenever the HW palette is changed.  */
/* It invalidates the palette mapping caching if necessary.           */
/**********************************************************************/

VOID DRIVERCALL HWPaletteChanged( VOID )
{
    /******************************************************************/
    /* If either the current source palette or the current destination*/
    /* palette in the mapping is the screen then we must invalidate   */
    /* the current palette mapping.                                   */
    /******************************************************************/
    if ((CurrentSourcePalette == FNULL) || (CurrentDestPalette == FNULL))
    {
        CurrentMappingValid = FALSE;
    }
}


/**********************************************************************/
/* This routine should be called whenever a logical palette changes   */
/* or is realized causing a change to its mapping to the HW palette   */
/* or is deleted.                                                     */
/* It invalidates the palette mapping caching if necessary.           */
/**********************************************************************/

VOID DRIVERCALL ChangedPalette ( PDEVPAL pPalette)
{
    /******************************************************************/
    /* If either the current source palette or the current destination*/
    /* palette in the mapping is the same as the palette just changed */
    /* then we must invalidate the current palette mapping.           */
    /******************************************************************/
    if ((CurrentSourcePalette == pPalette) || (CurrentDestPalette == pPalette))
    {
        CurrentMappingValid = FALSE;
    }
}

/**********************************************************************/
/* This routine should be called whenever a logical color table       */
/* changes.  It invalidates the palette mapping caching if necessary. */
/**********************************************************************/

VOID DRIVERCALL ChangedColorTable ( PCOLORTABLE pColorTable)
{
    /******************************************************************/
    /* If either the current source palette or the current destination*/
    /* in the palette-palette mapping is the same as the color table  */
    /* just changed then we must invalidate the current palette       */
    /* mapping.                                                       */
    /******************************************************************/
    if (   (CurrentSourcePalette == pColorTable)
        || (CurrentDestPalette == pColorTable) )
    {
        CurrentMappingValid = FALSE;
    }
}

#endif /* PALETTE_MGR */
