1527 lines
39 KiB
C++
1527 lines
39 KiB
C++
#include "precomp.h"
|
||
|
||
|
||
//
|
||
// PM.CPP
|
||
// Palette Manager
|
||
//
|
||
// Copyright(c) Microsoft 1997-
|
||
//
|
||
|
||
#define MLZ_FILE_ZONE ZONE_CORE
|
||
|
||
//
|
||
//
|
||
// PALETTE MANAGER (PM) OVERVIEW
|
||
//
|
||
// Palette Manager is responsible for sending palette packets. A palette
|
||
// packet:
|
||
//
|
||
// (1) indicates the colors being used on the host machine - and therefore
|
||
// specifies which colors the remote machine should use if it can choose
|
||
// (e.g. by selecting and realizing the given colors into the display
|
||
// hardware). [A palette packet may not contain the exact colors being
|
||
// used on the host if the protocol bpp is different from the host bpp].
|
||
//
|
||
// (2) specifies the colors which correspond to the values in bitmap
|
||
// (screen) data i.e. the values in 4bpp and 8bpp bitmap data are indices
|
||
// into the table of colors sent in the palette packet.
|
||
//
|
||
//
|
||
// (1) affects order replay and (2) affects screen data replay, so a
|
||
// correct palette packet must be sent (by calling
|
||
// PM_MaybeSendPalettePacket) before a batch of updates are sent.
|
||
//
|
||
// Palette Manager also handles incoming palette packets from other parties
|
||
// in the conference and creates corresponding local palettes which the
|
||
// Update Receiver can query and use when processing updates.
|
||
//
|
||
// When a new palette packet is sent (e.g. due to the System Palette
|
||
// changing), all shared areas of the screen will be retransmitted in due
|
||
// course. A receiving Palette Manager therefore does not have to (and
|
||
// should not attempt to) convert any updates/bitmaps that have been
|
||
// received prior to the arrival of the new palette packet.
|
||
//
|
||
//
|
||
|
||
//
|
||
// PM strategy when network packets cannot be allocated.
|
||
//
|
||
// PM_MaybeSendPalettePacket returns a boolean indicating whether it has
|
||
// succesfully sent a palette packet. The USR will only send updates if
|
||
// the corresponding palette packet is successfully sent.
|
||
//
|
||
//
|
||
|
||
|
||
const COLORREF s_apmGreyRGB[PM_GREY_COUNT] =
|
||
{
|
||
PM_GREY1,
|
||
PM_GREY2,
|
||
PM_GREY3,
|
||
PM_GREY4,
|
||
PM_GREY5
|
||
};
|
||
|
||
|
||
|
||
//
|
||
// PM_PartyLeftShare()
|
||
//
|
||
void ASShare::PM_PartyLeftShare(ASPerson * pasPerson)
|
||
{
|
||
DebugEntry(ASShare::PM_PartyLeftShare);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
|
||
{
|
||
// This should be cleared already!
|
||
ASSERT(!pasPerson->pmcColorTable);
|
||
ASSERT(!pasPerson->apmColorTable);
|
||
ASSERT(!pasPerson->pmPalette);
|
||
}
|
||
else
|
||
{
|
||
TRACE_OUT(("PM_PartyLeftShare: Freeing pm data for 2.x node [%d]",
|
||
pasPerson->mcsID));
|
||
PMFreeIncoming(pasPerson);
|
||
}
|
||
|
||
//
|
||
// NOTE: In 2.1, we didn't renegotiate the outgoing cache size when
|
||
// somebody left. So we don't now either (this is all 2.x compat stuff
|
||
// anyway).
|
||
//
|
||
|
||
DebugExitVOID(ASShare::PM_PartyLeftShare);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PM_RecalcCaps()
|
||
//
|
||
// This calculates the PM hosting caps when
|
||
// * we start to host
|
||
// * we're hosting and somebody joins the share
|
||
// * we're hosting and somebody leaves the share
|
||
//
|
||
// This can GO AWAY WHEN 2.x COMPAT IS GONE -- no more min() of cache size
|
||
//
|
||
void ASShare::PM_RecalcCaps(BOOL fJoiner)
|
||
{
|
||
ASPerson * pasT;
|
||
|
||
DebugEntry(ASShare::PM_RecalcCaps);
|
||
|
||
if (!m_pHost || !fJoiner)
|
||
{
|
||
//
|
||
// Nothing to do if we're not hosting. And also, if somebody has
|
||
// left, no recalculation -- 2.x didn't.
|
||
//
|
||
DC_QUIT;
|
||
}
|
||
|
||
ValidatePerson(m_pasLocal);
|
||
|
||
//
|
||
// NOTE:
|
||
// The default size is 6 palettes cached. The result is going to be
|
||
// <= that number. There's no point in recreating the cache, it's
|
||
// so small.
|
||
//
|
||
m_pHost->m_pmNumTxCacheEntries = m_pasLocal->cpcCaps.palette.capsColorTableCacheSize;
|
||
|
||
if (m_scShareVersion < CAPS_VERSION_30)
|
||
{
|
||
TRACE_OUT(("In share with 2.x nodes, must recalc PM caps"));
|
||
|
||
for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
|
||
{
|
||
m_pHost->m_pmNumTxCacheEntries = min(m_pHost->m_pmNumTxCacheEntries,
|
||
pasT->cpcCaps.palette.capsColorTableCacheSize);
|
||
}
|
||
|
||
TRACE_OUT(("Recalced PM caps: Tx Cache size %d",
|
||
m_pHost->m_pmNumTxCacheEntries));
|
||
}
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitVOID(ASShare::PM_Recalccaps);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_HostStarting()
|
||
//
|
||
// Called when we start to host; sets up color palette stuff and creates
|
||
// outgoing palette cache
|
||
//
|
||
BOOL ASHost::PM_HostStarting(void)
|
||
{
|
||
BOOL rc = FALSE;
|
||
TSHR_COLOR localPalColors[PM_NUM_8BPP_PAL_ENTRIES];
|
||
|
||
DebugEntry(ASHost::PM_HostStarting);
|
||
|
||
//
|
||
// Get palette caps. NOTE PM_RecalcCaps must be called AFTER
|
||
// USR_RecalcCaps(), because that updates m_usrSendingBPP.
|
||
//
|
||
if (g_usrPalettized)
|
||
{
|
||
ASSERT(g_usrScreenBPP <= 8);
|
||
|
||
ZeroMemory(localPalColors, sizeof(localPalColors));
|
||
|
||
//
|
||
// Now create the Local Palette.
|
||
//
|
||
if (!m_pShare->PM_CreatePalette(COLORS_FOR_BPP(g_usrScreenBPP),
|
||
localPalColors, &m_pmTxPalette))
|
||
{
|
||
ERROR_OUT(( "Failed to create Local Palette"));
|
||
DC_QUIT;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_pmTxPalette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
|
||
PMGetGrays();
|
||
}
|
||
|
||
//
|
||
// With NM 3.0, why not just create a receive cache the size that
|
||
// the host specifies in his caps?
|
||
//
|
||
// So I did that. For back compat, OUTGOING caches use the min size.
|
||
// When we only have to be compatible with NM 3.0 and up, we won't
|
||
// have to do this min stuff.
|
||
//
|
||
// Note similar code in CM, SSI, and SBC
|
||
//
|
||
|
||
// Figure out how many outgoing entries we can actually use
|
||
m_pShare->PM_RecalcCaps(TRUE);
|
||
|
||
//
|
||
// Create the PM color table cache with a single eviction
|
||
// category.
|
||
//
|
||
if (!CH_CreateCache(&m_pmTxCacheHandle, TSHR_PM_CACHE_ENTRIES,
|
||
1, 0, PMCacheCallback))
|
||
{
|
||
ERROR_OUT(("Could not create PM cache"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitBOOL(ASHost::PM_HostStarting, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PM_HostEnded()
|
||
//
|
||
// We free resources created when we started to host
|
||
//
|
||
void ASHost::PM_HostEnded(void)
|
||
{
|
||
DebugEntry(ASHost::PM_HostEnded);
|
||
|
||
if (m_pmTxPalette)
|
||
{
|
||
m_pShare->PM_DeletePalette(m_pmTxPalette);
|
||
m_pmTxPalette = NULL;
|
||
}
|
||
|
||
if (m_pmTxCacheHandle)
|
||
{
|
||
CH_DestroyCache(m_pmTxCacheHandle);
|
||
m_pmTxCacheHandle = 0;
|
||
m_pmNumTxCacheEntries = 0;
|
||
}
|
||
|
||
DebugExitVOID(ASHost::PM_HostEnded);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PM_ViewStarting()
|
||
//
|
||
// For 3.0 nodes, we create the PM cache each time they start hosting
|
||
// For 2.x nodes, we create the PM cache once and use it until they leave
|
||
// the share.
|
||
//
|
||
BOOL ASShare::PM_ViewStarting(ASPerson * pasPerson)
|
||
{
|
||
BOOL rc = FALSE;
|
||
|
||
DebugEntry(ASShare::PM_ViewStarting);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
if (pasPerson->pmcColorTable != 0)
|
||
{
|
||
ASSERT(pasPerson->apmColorTable != NULL);
|
||
ASSERT(pasPerson->pmPalette != NULL);
|
||
|
||
ASSERT(pasPerson->cpcCaps.general.version < CAPS_VERSION_30);
|
||
|
||
TRACE_OUT(("PM_ViewStarting Reusing pm data for 2.x node [%d]",
|
||
pasPerson->mcsID));
|
||
rc = TRUE;
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// In normal operation, we will receive a palette packet from the host
|
||
// before any updates, which we use to create the correct palette for
|
||
// this host.
|
||
//
|
||
// However, in some back-level calls we may not receive a palette
|
||
// packet before the first updates, so we initialize this host's
|
||
// palette to the default palette to allow us to generate some sort
|
||
// of output.
|
||
//
|
||
pasPerson->pmPalette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
|
||
|
||
//
|
||
// Allocate color table cache memory based on the negotiated options
|
||
// Space needed is (n)x256xRGBQUAD where n is the number of color
|
||
// tables the conference supports.
|
||
//
|
||
pasPerson->pmcColorTable = pasPerson->cpcCaps.palette.capsColorTableCacheSize;
|
||
|
||
if (!pasPerson->pmcColorTable)
|
||
{
|
||
WARNING_OUT(("PM_ViewStarting: person [%d] has no palette cache size",
|
||
pasPerson->cpcCaps.palette.capsColorTableCacheSize));
|
||
rc = TRUE;
|
||
DC_QUIT;
|
||
}
|
||
|
||
pasPerson->apmColorTable = new COLORTABLECACHE[pasPerson->pmcColorTable];
|
||
if (!pasPerson->apmColorTable)
|
||
{
|
||
ERROR_OUT(( "Failed to get memory for PM color table cache"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
ZeroMemory(pasPerson->apmColorTable, pasPerson->pmcColorTable * sizeof(COLORTABLECACHE));
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitBOOL(ASShare::PM_ViewStarting, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PM_ViewEnded()
|
||
//
|
||
void ASShare::PM_ViewEnded(ASPerson * pasPerson)
|
||
{
|
||
DebugEntry(ASShare::PM_ViewEnded);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
//
|
||
// For 3.0 nodes, we can free the palette cache; 3.0 senders clear theirs
|
||
// every time they host.
|
||
// For 2.x nodes, we must keep it around while they are in the share since
|
||
// they use it across sharing/unsharing/sharing again.
|
||
//
|
||
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
|
||
{
|
||
PMFreeIncoming(pasPerson);
|
||
}
|
||
else
|
||
{
|
||
TRACE_OUT(("PM_PartyViewEnded: Keeping pm data for 2.x node [%d]",
|
||
pasPerson->mcsID));
|
||
}
|
||
|
||
DebugExitVOID(ASShare::PM_PartyViewEnded);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PMFreeIncoming()
|
||
//
|
||
void ASShare::PMFreeIncoming(ASPerson * pasPerson)
|
||
{
|
||
DebugEntry(ASShare::PMFreeIncoming);
|
||
|
||
//
|
||
// Free the color table cache
|
||
//
|
||
pasPerson->pmcColorTable = 0;
|
||
if (pasPerson->apmColorTable)
|
||
{
|
||
delete[] pasPerson->apmColorTable;
|
||
pasPerson->apmColorTable = NULL;
|
||
}
|
||
|
||
if (pasPerson->pmPalette != NULL)
|
||
{
|
||
//
|
||
// Free this host's palette. and set it to NULL so that we can tell
|
||
// that this host has left the share.
|
||
//
|
||
PM_DeletePalette(pasPerson->pmPalette);
|
||
pasPerson->pmPalette = NULL;
|
||
}
|
||
|
||
DebugExitVOID(ASShare::PMFreeIncoming);
|
||
}
|
||
|
||
//
|
||
// PM_MaybeSendPalettePacket()
|
||
//
|
||
BOOL ASHost::PM_MaybeSendPalettePacket(void)
|
||
{
|
||
BOOL rc = TRUE;
|
||
|
||
DebugEntry(ASHost::PM_MaybeSendPalettePacket);
|
||
|
||
if (m_pmMustSendPalette)
|
||
{
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
|
||
//
|
||
// Ensure that our palette colors are up to date before we send the
|
||
// palette packet.
|
||
//
|
||
if (g_usrPalettized)
|
||
{
|
||
PMUpdateSystemPaletteColors();
|
||
}
|
||
|
||
PMUpdateTxPaletteColors();
|
||
}
|
||
else if (g_usrPalettized)
|
||
{
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
|
||
//
|
||
// If the System Palette has changed then we may need to send
|
||
// another palette packet.
|
||
//
|
||
if (PMUpdateSystemPaletteColors())
|
||
{
|
||
//
|
||
// The System Palette has changed, but we only need to send
|
||
// another palette packet if the palette colors have changed.
|
||
//
|
||
TRACE_OUT(( "System Palette changed"));
|
||
|
||
if (PMUpdateTxPaletteColors())
|
||
{
|
||
TRACE_OUT(( "Tx Palette changed"));
|
||
m_pmMustSendPalette = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (m_pmMustSendPalette)
|
||
{
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
|
||
TRACE_OUT(( "Send palette packet"));
|
||
|
||
rc = PMSendPalettePacket(m_apmTxPaletteColors, COLORS_FOR_BPP(m_usrSendingBPP));
|
||
|
||
if (rc)
|
||
{
|
||
m_pmMustSendPalette = FALSE;
|
||
}
|
||
}
|
||
|
||
DebugExitBOOL(ASHost::PM_MaybeSendPalettePacket, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_ReceivedPacket
|
||
//
|
||
void ASShare::PM_ReceivedPacket
|
||
(
|
||
ASPerson * pasPerson,
|
||
PS20DATAPACKET pPacket
|
||
)
|
||
{
|
||
PPMPACKET pPMPacket;
|
||
HPALETTE newPalette = NULL;
|
||
|
||
DebugEntry(ASShare::PM_ReceivedPacket);
|
||
|
||
ValidateView(pasPerson);
|
||
|
||
pPMPacket = (PPMPACKET)pPacket;
|
||
|
||
//
|
||
// Create a new palette from the received packet.
|
||
//
|
||
// We cannot just update the current palette colors (using
|
||
// SetPaletteEntries) because Windows does not handle the repainting
|
||
// of other local Palette Manager apps correctly (it does not
|
||
// broadcast the WM_PALETTE.. messages as the palette mapping does
|
||
// not change).
|
||
//
|
||
if (PM_CreatePalette(pPMPacket->numColors, pPMPacket->aColors,
|
||
&newPalette))
|
||
{
|
||
PM_DeletePalette(pasPerson->pmPalette);
|
||
pasPerson->pmPalette = newPalette;
|
||
|
||
TRACE_OUT(( "Created new palette 0x%08x from packet", newPalette));
|
||
}
|
||
else
|
||
{
|
||
WARNING_OUT(( "Failed to create palette. person(%u) numColors(%u)",
|
||
pasPerson, pPMPacket->numColors));
|
||
}
|
||
|
||
|
||
DebugExitVOID(ASShare::PM_ReceivedPacket);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_SyncOutgoing()
|
||
//
|
||
void ASHost::PM_SyncOutgoing(void)
|
||
{
|
||
DebugEntry(ASHost::PM_SyncOutgoing);
|
||
|
||
//
|
||
// Ensure we send a palette to the remote PM next time we are called.
|
||
//
|
||
if (m_usrSendingBPP <= 8)
|
||
{
|
||
m_pmMustSendPalette = TRUE;
|
||
|
||
//
|
||
// The sync discards any as-yet-unsent accumulated orders. Since these
|
||
// orders may include color table cache orders, clear the cache.
|
||
//
|
||
ASSERT(m_pmTxCacheHandle);
|
||
CH_ClearCache(m_pmTxCacheHandle);
|
||
}
|
||
|
||
DebugExitVOID(ASHost::PM_SyncOutgoing);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_CacheTxColorTable
|
||
//
|
||
BOOL ASHost::PM_CacheTxColorTable
|
||
(
|
||
LPUINT pIndex,
|
||
LPBOOL pCacheChanged,
|
||
UINT cColors,
|
||
LPTSHR_RGBQUAD pColors
|
||
)
|
||
{
|
||
BOOL rc = FALSE;
|
||
UINT cacheIndex = 0;
|
||
UINT i = 0;
|
||
PCOLORTABLECACHE pEntry = NULL;
|
||
COLORTABLECACHE newEntry = { 0 };
|
||
|
||
DebugEntry(ASHost::PM_CacheTxColorTable);
|
||
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
ASSERT(m_pmTxCacheHandle);
|
||
|
||
TRACE_OUT(( "Caching table of %u colors", cColors));
|
||
|
||
//
|
||
// Create the data we want to cache. It may be that there is already
|
||
// an entry in the cache for this set of colors, but we still need to
|
||
// create a cache entry in local memory so we can search the cache to
|
||
// find out.
|
||
//
|
||
ZeroMemory(&newEntry, sizeof(COLORTABLECACHE));
|
||
|
||
newEntry.inUse = TRUE;
|
||
newEntry.cColors = cColors;
|
||
memcpy(&newEntry.colors, pColors, cColors * sizeof(TSHR_RGBQUAD));
|
||
|
||
//
|
||
// Check to see if the table is already cached. (No hint or eviction
|
||
// category.)
|
||
//
|
||
if (CH_SearchCache(m_pmTxCacheHandle, (LPBYTE)(&newEntry),
|
||
sizeof(COLORTABLECACHE), 0, &cacheIndex ))
|
||
{
|
||
TRACE_OUT(( "Found existing entry at %u",cacheIndex));
|
||
*pIndex = cacheIndex;
|
||
*pCacheChanged = FALSE;
|
||
rc = TRUE;
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Find a free cache entry
|
||
//
|
||
// We arrange that our transmit cache is always one greater than the
|
||
// negotiated cache size so that we should never fail to find a free
|
||
// array entry. Once we have fully populated our Tx cache we will
|
||
// always find the free entry as the one last given back to us by CH.
|
||
// Note the scan to <= m_pmNumTxCacheEntries is NOT a mistake.
|
||
//
|
||
if (m_pmNextTxCacheEntry != NULL)
|
||
{
|
||
pEntry = m_pmNextTxCacheEntry;
|
||
m_pmNextTxCacheEntry = NULL;
|
||
}
|
||
else
|
||
{
|
||
for (i = 0; i <= m_pmNumTxCacheEntries; i++)
|
||
{
|
||
if (!m_apmTxCache[i].inUse)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We should never run out of free entries, but cope with it
|
||
//
|
||
if (i > m_pmNumTxCacheEntries)
|
||
{
|
||
ERROR_OUT(( "All PM cache entries in use"));
|
||
rc = FALSE;
|
||
DC_QUIT;
|
||
}
|
||
pEntry = m_apmTxCache + i;
|
||
}
|
||
|
||
|
||
//
|
||
// Set up the color table in the free entry we just found
|
||
//
|
||
memcpy(pEntry, &newEntry, sizeof(COLORTABLECACHE));
|
||
|
||
//
|
||
// Add the new entry to the cache
|
||
// We do not use hints or eviction so set to 0
|
||
//
|
||
cacheIndex = CH_CacheData(m_pmTxCacheHandle, (LPBYTE)pEntry,
|
||
sizeof(COLORTABLECACHE), 0 );
|
||
TRACE_OUT(( "Color table 0x%08x cached at index %u", pEntry, cacheIndex));
|
||
*pIndex = cacheIndex;
|
||
*pCacheChanged = TRUE;
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitDWORD(ASHost::PM_CacheTxColorTable, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_CacheRxColorTable
|
||
//
|
||
BOOL ASShare::PM_CacheRxColorTable
|
||
(
|
||
ASPerson * pasPerson,
|
||
UINT index,
|
||
UINT cColors,
|
||
LPTSHR_RGBQUAD pColors
|
||
)
|
||
{
|
||
BOOL rc = FALSE;
|
||
PCOLORTABLECACHE pColorTable;
|
||
|
||
DebugEntry(ASShare::PM_CacheRxColorTable);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
pColorTable = pasPerson->apmColorTable;
|
||
TRACE_OUT(( "Person [%d] color table rx cache 0x%08x cache %u, %u colors",
|
||
pasPerson->mcsID, pColorTable, index, cColors));
|
||
|
||
if (pColorTable == NULL)
|
||
{
|
||
ERROR_OUT(( "Asked to cache when no cache allocated"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// The index must be within the currently negotiated cache limits
|
||
//
|
||
if (index > pasPerson->pmcColorTable)
|
||
{
|
||
ERROR_OUT(( "Invalid color table index %u",index));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Set up the color table entry
|
||
//
|
||
pColorTable[index].inUse = TRUE;
|
||
pColorTable[index].cColors = cColors;
|
||
memcpy(pColorTable[index].colors, pColors, cColors * sizeof(TSHR_RGBQUAD));
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitDWORD(ASShare::PM_CacheRxColorTable, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PMSendPalettePacket
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Sends a palette packet containing the given colors.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// pColorTable - pointer to an array of TSHR_RGBQUAD colors to be sent in the
|
||
// palette packet.
|
||
//
|
||
// numColors - the number of entries in the TSHR_RGBQUAD array
|
||
//
|
||
// RETURNS: TRUE if the palette packet is sent, FALSE otherwise
|
||
//
|
||
//
|
||
BOOL ASHost::PMSendPalettePacket
|
||
(
|
||
LPTSHR_RGBQUAD pColorTable,
|
||
UINT numColors
|
||
)
|
||
{
|
||
PPMPACKET pPMPacket;
|
||
UINT sizePkt;
|
||
UINT i;
|
||
BOOL rc = FALSE;
|
||
#ifdef _DEBUG
|
||
UINT sentSize;
|
||
#endif // _DEBUG
|
||
|
||
DebugEntry(ASHost::PMSendPalettePacket);
|
||
|
||
//
|
||
// Send a palette packet.
|
||
//
|
||
// First calculate the packet size.
|
||
//
|
||
sizePkt = sizeof(PMPACKET) + (numColors - 1) * sizeof(TSHR_COLOR);
|
||
pPMPacket = (PPMPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES, g_s20BroadcastID, sizePkt);
|
||
if (!pPMPacket)
|
||
{
|
||
WARNING_OUT(("Failed to alloc PM packet, size %u", sizePkt));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Fill in the packet contents.
|
||
//
|
||
pPMPacket->header.header.data.dataType = DT_UP;
|
||
pPMPacket->header.updateType = UPD_PALETTE;
|
||
|
||
//
|
||
// Convert the TSHR_RGBQUADs in the color table to TSHR_COLORs as we copy
|
||
// them into the packet.
|
||
//
|
||
pPMPacket->numColors = numColors;
|
||
for (i = 0; i < numColors; i++)
|
||
{
|
||
//
|
||
// Convert each RGBQuad entry in the color table to a DCColor.
|
||
//
|
||
TSHR_RGBQUAD_TO_TSHR_COLOR(pColorTable[i],
|
||
pPMPacket->aColors[i]);
|
||
}
|
||
|
||
//
|
||
// Now send the packet to the remote application.
|
||
//
|
||
if (m_pShare->m_scfViewSelf)
|
||
m_pShare->PM_ReceivedPacket(m_pShare->m_pasLocal, &(pPMPacket->header.header));
|
||
|
||
#ifdef _DEBUG
|
||
sentSize =
|
||
#endif // _DEBUG
|
||
m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES, g_s20BroadcastID,
|
||
&(pPMPacket->header.header), sizePkt);
|
||
|
||
TRACE_OUT(("PM packet size: %08d, sent %08d", sizePkt, sentSize));
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitDWORD(ASHost::PMSendPalettePacket, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// FUNCTION: PMCacheCallback
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Cursor Manager's Cache Manager callback function. Called whenever an
|
||
// entry is removed from the cache to allow us to free up the object.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// hCache - cache handle
|
||
//
|
||
// event - the cache event that has occured
|
||
//
|
||
// iCacheEntry - index of the cache entry that the event is affecting
|
||
//
|
||
// pData - pointer to the cache data associated with the given cache entry
|
||
//
|
||
// cbDataSize - size in bytes of the cached data
|
||
//
|
||
// RETURNS: Nothing
|
||
//
|
||
//
|
||
void PMCacheCallback
|
||
(
|
||
ASHost * pHost,
|
||
PCHCACHE pCache,
|
||
UINT iCacheEntry,
|
||
LPBYTE pData
|
||
)
|
||
{
|
||
DebugEntry(PMCacheCallback);
|
||
|
||
|
||
//
|
||
// Release the cache entry for reuse
|
||
//
|
||
TRACE_OUT(( "Releasing cache entry %d at 0x%08x",
|
||
iCacheEntry, pData));
|
||
pHost->m_pmNextTxCacheEntry = (PCOLORTABLECACHE)pData;
|
||
pHost->m_pmNextTxCacheEntry->inUse = FALSE;
|
||
|
||
//
|
||
// Let SBC know that the cache entry has been released
|
||
//
|
||
pHost->SBC_PMCacheEntryRemoved(iCacheEntry);
|
||
|
||
DebugExitVOID(PMCacheCallback);
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// PM_GetSystemPaletteEntries
|
||
//
|
||
void ASHost::PM_GetSystemPaletteEntries(LPTSHR_RGBQUAD pColors)
|
||
{
|
||
UINT i;
|
||
|
||
DebugEntry(ASHost::PM_GetSystemPaletteEntries);
|
||
|
||
PMUpdateSystemPaletteColors();
|
||
|
||
for (i = 0; i < PM_NUM_8BPP_PAL_ENTRIES; i++)
|
||
{
|
||
pColors[i].rgbRed = m_apmCurrentSystemPaletteEntries[i].peRed;
|
||
pColors[i].rgbGreen = m_apmCurrentSystemPaletteEntries[i].peGreen;
|
||
pColors[i].rgbBlue = m_apmCurrentSystemPaletteEntries[i].peBlue;
|
||
pColors[i].rgbReserved = 0;
|
||
}
|
||
|
||
//
|
||
// This function in its current form always returns TRUE - it is always
|
||
// able to obtain the system colors.
|
||
//
|
||
DebugExitVOID(ASHost::PM_GetSystemPaletteEntries);
|
||
}
|
||
|
||
|
||
//
|
||
// PM_GetLocalPalette()
|
||
//
|
||
HPALETTE ASHost::PM_GetLocalPalette(void)
|
||
{
|
||
//
|
||
// Ensure the palette is up to date
|
||
//
|
||
if (g_usrPalettized)
|
||
{
|
||
PMUpdateSystemPaletteColors();
|
||
}
|
||
|
||
//
|
||
// Return the handle to the Local Palette.
|
||
//
|
||
return(m_pmTxPalette);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PM_GetColorTable
|
||
//
|
||
void ASShare::PM_GetColorTable
|
||
(
|
||
ASPerson * pasPerson,
|
||
UINT index,
|
||
LPUINT pcColors,
|
||
LPTSHR_RGBQUAD pColors
|
||
)
|
||
{
|
||
PCOLORTABLECACHE pColorTable;
|
||
|
||
DebugEntry(ASShare::PM_GetColorTable);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
ASSERT(pasPerson->apmColorTable);
|
||
|
||
pColorTable = &(pasPerson->apmColorTable[index]);
|
||
TRACE_OUT(( "Color table requested for [%d], table ptr 0x%08x index %d",
|
||
pasPerson->mcsID, pColorTable,index));
|
||
|
||
if (!pColorTable->inUse)
|
||
{
|
||
ERROR_OUT(( "Asked for PM cache entry %hu when cache not yet in use",
|
||
index));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Copy the colors into the structure we have been passed
|
||
//
|
||
*pcColors = pColorTable->cColors;
|
||
|
||
memcpy( pColors,
|
||
pColorTable->colors,
|
||
sizeof(TSHR_RGBQUAD) * pColorTable->cColors );
|
||
|
||
TRACE_OUT(( "Returning %u colors",*pcColors));
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitVOID(ASShare::PM_GetColorTable);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// PMADJUSTBUGGEDCOLOR()
|
||
//
|
||
// Macro used to tweak an 8 bit palette entry that the Win95 16 bit
|
||
// driver returns incorrectly
|
||
//
|
||
#define PMADJUSTBUGGEDCOLOR(pColor) \
|
||
if ( ((pColor)->rgbBlue != 0x00) && \
|
||
((pColor)->rgbBlue != 0xFF) ) \
|
||
{ \
|
||
(pColor)->rgbBlue += 0x40; \
|
||
} \
|
||
\
|
||
if ( ((pColor)->rgbGreen != 0x00) && \
|
||
((pColor)->rgbGreen != 0xFF) ) \
|
||
{ \
|
||
(pColor)->rgbGreen += 0x20; \
|
||
} \
|
||
\
|
||
if ( ((pColor)->rgbRed != 0x00) && \
|
||
((pColor)->rgbRed != 0xFF) ) \
|
||
{ \
|
||
(pColor)->rgbRed += 0x20; \
|
||
}
|
||
|
||
//
|
||
// PMGetGrays()
|
||
//
|
||
// Gets display driver specific versions of gray RGBs
|
||
//
|
||
void ASHost::PMGetGrays(void)
|
||
{
|
||
HBITMAP hOldBitmap = NULL;
|
||
BITMAPINFO_ours bitmapInfo;
|
||
BYTE bitmapBuffer[16];
|
||
UINT i;
|
||
|
||
DebugEntry(ASHost::PMGetGrays);
|
||
|
||
//
|
||
// Initialise the bitmapinfo local structure header contents. This
|
||
// structure will be used in the GetDIBits calls.
|
||
//
|
||
m_pShare->USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, 8);
|
||
|
||
bitmapInfo.bmiHeader.biWidth = 16;
|
||
bitmapInfo.bmiHeader.biHeight = 1;
|
||
|
||
//
|
||
// Select the bitmap into the work DC
|
||
//
|
||
hOldBitmap = SelectBitmap(m_usrWorkDC, m_pShare->m_usrBmp16);
|
||
if (hOldBitmap == NULL)
|
||
{
|
||
ERROR_OUT(( "Failed to select bitmap. hp(%08lX) hbmp(%08lX)",
|
||
m_usrWorkDC, m_pShare->m_usrBmp16 ));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Use the real GDI to set each bit to each supplied color.
|
||
//
|
||
for (i = PM_GREY_COUNT; i-- != 0; )
|
||
{
|
||
SetPixel(m_usrWorkDC, i, 0, s_apmGreyRGB[i]);
|
||
}
|
||
|
||
//
|
||
// Because this function is only used for true color scenarios we do
|
||
// not need to select a palette into our compatible DC. We just need
|
||
// to get the bits.
|
||
//
|
||
if (!GetDIBits(m_usrWorkDC, m_pShare->m_usrBmp16, 0, 1, &bitmapBuffer,
|
||
(BITMAPINFO *)&bitmapInfo, DIB_RGB_COLORS ))
|
||
{
|
||
ERROR_OUT(( "GetDIBits failed. hp(%x) hbmp(%x)",
|
||
m_usrWorkDC, m_pShare->m_usrBmp16));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Check if we need to adjust the palette colors for the 16 bit driver
|
||
// bug.
|
||
//
|
||
m_pmBuggedDriver = ((g_usrScreenBPP > 8) &&
|
||
(bitmapInfo.bmiColors[1].rgbRed == 0) &&
|
||
(bitmapInfo.bmiColors[1].rgbGreen == 0) &&
|
||
(bitmapInfo.bmiColors[1].rgbBlue == 0x40));
|
||
|
||
//
|
||
// Extract the RGBs returned by the display driver with the sending bpp
|
||
// DIB.
|
||
//
|
||
for (i = PM_GREY_COUNT; i-- != 0; )
|
||
{
|
||
//
|
||
// Extract the RGB from the color table
|
||
//
|
||
m_apmDDGreyRGB[i] = *((LPTSHR_RGBQUAD)(&bitmapInfo.bmiColors[bitmapBuffer[i]]));
|
||
|
||
//
|
||
// Adjust the palette colors for the 16 bit driver bug, if needed.
|
||
//
|
||
if (m_pmBuggedDriver)
|
||
{
|
||
TRACE_OUT(( "Adjusting for bugged driver"));
|
||
PMADJUSTBUGGEDCOLOR(&m_apmDDGreyRGB[i]);
|
||
}
|
||
}
|
||
|
||
DC_EXIT_POINT:
|
||
//
|
||
// clean up
|
||
//
|
||
if (hOldBitmap != NULL)
|
||
{
|
||
SelectBitmap(m_usrWorkDC, hOldBitmap);
|
||
|
||
}
|
||
|
||
DebugExitVOID(ASHost::PMGetGrays);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// FUNCTION: PMUpdateSystemPaletteColors
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Determines whether the colors in the System Palette have changed since
|
||
// the last time this function was called and if so, updates the supplied
|
||
// palette so that it contains the same colors as the System Palette.
|
||
//
|
||
// The first time that this function is called after PM_Init the System
|
||
// Palette colors will be returned and the function will return TRUE.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// shadowSystemPalette - handle of the palette to be updated with the
|
||
// current System Palette colors
|
||
//
|
||
// RETURNS: TRUE if the System Palette has changed since the last call,
|
||
// FALSE otherwise.
|
||
//
|
||
//
|
||
BOOL ASHost::PMUpdateSystemPaletteColors(void)
|
||
{
|
||
BOOL rc = FALSE;
|
||
PALETTEENTRY systemPaletteEntries[PM_NUM_8BPP_PAL_ENTRIES];
|
||
HDC hdcScreen = NULL;
|
||
UINT cbSystemPaletteEntries;
|
||
int irgb, crgb, crgbFixed;
|
||
|
||
DebugEntry(ASHost::PMUpdateSystemPaletteColors);
|
||
|
||
ASSERT(g_usrPalettized);
|
||
ASSERT(g_usrScreenBPP <= 8);
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
|
||
//
|
||
// Don't bother with all this stuff if the system palette has not
|
||
// changed at all. We track notifications to our UI to detect
|
||
// palette changes.
|
||
//
|
||
if (!g_asSharedMemory->pmPaletteChanged)
|
||
{
|
||
DC_QUIT;
|
||
}
|
||
|
||
hdcScreen = GetDC(NULL);
|
||
if (!hdcScreen)
|
||
{
|
||
WARNING_OUT(( "GetDC failed"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
if (GetSystemPaletteEntries(hdcScreen, 0, COLORS_FOR_BPP(g_usrScreenBPP),
|
||
systemPaletteEntries) != (UINT)COLORS_FOR_BPP(g_usrScreenBPP))
|
||
{
|
||
WARNING_OUT(( "GetSystemPaletteEntries failed"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Now that we have succesfully queried the system palette, we can
|
||
// reset our flag.
|
||
//
|
||
g_asSharedMemory->pmPaletteChanged = FALSE;
|
||
|
||
cbSystemPaletteEntries = COLORS_FOR_BPP(g_usrScreenBPP) * sizeof(PALETTEENTRY);
|
||
|
||
//
|
||
// See if the System Palette has changed from the last time we queried.
|
||
//
|
||
if (!memcmp(systemPaletteEntries, m_apmCurrentSystemPaletteEntries,
|
||
cbSystemPaletteEntries ))
|
||
{
|
||
//
|
||
// The System Palette has not changed
|
||
//
|
||
TRACE_OUT(( "System palette has NOT changed"));
|
||
rc = TRUE;
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Take a copy of the new System Palette.
|
||
//
|
||
memcpy(m_apmCurrentSystemPaletteEntries, systemPaletteEntries, cbSystemPaletteEntries );
|
||
|
||
//
|
||
// Update the current local paleete.
|
||
//
|
||
// NOTE FOR WIN95:
|
||
// We need to add PC_NOCOLLAPSE to non-system palette entries.
|
||
//
|
||
if (g_asWin95)
|
||
{
|
||
if (GetSystemPaletteUse(hdcScreen) == SYSPAL_STATIC)
|
||
crgbFixed = GetDeviceCaps(hdcScreen, NUMRESERVED) / 2;
|
||
else
|
||
crgbFixed = 1;
|
||
|
||
crgb = COLORS_FOR_BPP(g_usrScreenBPP) - crgbFixed;
|
||
|
||
for (irgb = crgbFixed; irgb < crgb; irgb++)
|
||
{
|
||
systemPaletteEntries[irgb].peFlags = PC_NOCOLLAPSE;
|
||
}
|
||
}
|
||
|
||
SetPaletteEntries(m_pmTxPalette, 0, COLORS_FOR_BPP(g_usrScreenBPP),
|
||
systemPaletteEntries );
|
||
|
||
m_pmMustSendPalette = TRUE;
|
||
|
||
//
|
||
// SFR0407: The system palette has changed so re-fetch our set of RGBs
|
||
// which the driver returns on an 8-bit GetDIBits for greys.
|
||
//
|
||
PMGetGrays();
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
if (hdcScreen)
|
||
{
|
||
ReleaseDC(NULL, hdcScreen);
|
||
}
|
||
|
||
DebugExitBOOL(ASHost::PMUpdateSystemPaletteColors, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
//
|
||
// FUNCTION: PMUpdateTxPaletteColors
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Returns the colors that make up the current Tx Palette (the palette that
|
||
// is SENT from the local machine). These are not necessarily the colors
|
||
// in the local machine's palette, because the local machine's bpp and the
|
||
// protocol bpp may be different (e.g. on an 8bpp machine talking at 4bpp
|
||
// the Tx Palette has 16 entries).
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// pColorTable - pointer to an array of RGBQUADs which is filled with the
|
||
// colors that make up the current Tx Palette.
|
||
//
|
||
// RETURNS: TRUE if successful, FALSE otherwise.
|
||
//
|
||
//
|
||
BOOL ASHost::PMUpdateTxPaletteColors(void)
|
||
{
|
||
UINT i;
|
||
UINT j;
|
||
BOOL rc = FALSE;
|
||
HDC hdcMem = NULL;
|
||
HBITMAP hbmpDummy = NULL;
|
||
HPALETTE hpalOld = NULL;
|
||
BITMAPINFO_ours pmBitmapInfo;
|
||
|
||
DebugEntry(ASHost::PMUpdateTxPaletteColors);
|
||
|
||
//
|
||
// Returns the values returned by a GetDIBits call with the
|
||
// m_pmTxPalette selected.
|
||
//
|
||
ASSERT(m_usrSendingBPP <= 8);
|
||
|
||
//
|
||
// If we are at 8bpp locally, and sending at 8bpp, then the TxPalette
|
||
// is simply the system palette.
|
||
//
|
||
if ((g_usrScreenBPP == 8) && (m_usrSendingBPP == 8))
|
||
{
|
||
PM_GetSystemPaletteEntries(pmBitmapInfo.bmiColors);
|
||
}
|
||
else
|
||
{
|
||
hdcMem = CreateCompatibleDC(NULL);
|
||
if (!hdcMem)
|
||
{
|
||
ERROR_OUT(("PMUpdateTxPaletteColors: couldn't create memory DC"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
hpalOld = SelectPalette(hdcMem, m_pmTxPalette, TRUE);
|
||
RealizePalette(hdcMem);
|
||
|
||
#define DUMMY_WIDTH 8
|
||
#define DUMMY_HEIGHT 8
|
||
|
||
hbmpDummy = CreateBitmap(DUMMY_WIDTH, DUMMY_HEIGHT, 1,
|
||
g_usrScreenBPP, NULL);
|
||
if (hbmpDummy == NULL)
|
||
{
|
||
ERROR_OUT(( "Failed to create bitmap"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
|
||
//
|
||
// Set up the structure required by GetDIBits.
|
||
//
|
||
pmBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
pmBitmapInfo.bmiHeader.biWidth = DUMMY_WIDTH;
|
||
pmBitmapInfo.bmiHeader.biHeight = DUMMY_HEIGHT;
|
||
pmBitmapInfo.bmiHeader.biPlanes = 1;
|
||
pmBitmapInfo.bmiHeader.biBitCount = (WORD)m_usrSendingBPP;
|
||
pmBitmapInfo.bmiHeader.biCompression = BI_RGB;
|
||
pmBitmapInfo.bmiHeader.biSizeImage = 0;
|
||
pmBitmapInfo.bmiHeader.biXPelsPerMeter = 10000;
|
||
pmBitmapInfo.bmiHeader.biYPelsPerMeter = 10000;
|
||
pmBitmapInfo.bmiHeader.biClrUsed = 0;
|
||
pmBitmapInfo.bmiHeader.biClrImportant = 0;
|
||
|
||
if (0 == GetDIBits( hdcMem,
|
||
hbmpDummy,
|
||
0,
|
||
DUMMY_HEIGHT,
|
||
NULL,
|
||
(LPBITMAPINFO)&pmBitmapInfo.bmiHeader,
|
||
DIB_RGB_COLORS ))
|
||
{
|
||
WARNING_OUT(( "GetDIBits failed hdc(%x) hbmp(%x)",
|
||
HandleToUlong(hdcMem),
|
||
HandleToUlong(hbmpDummy)));
|
||
DC_QUIT;
|
||
}
|
||
|
||
SelectPalette(hdcMem, hpalOld, TRUE);
|
||
|
||
PM_AdjustColorsForBuggedDisplayDrivers(
|
||
(LPTSHR_RGBQUAD)pmBitmapInfo.bmiColors,
|
||
COLORS_FOR_BPP(m_usrSendingBPP));
|
||
|
||
//
|
||
// This doesn't work for VGA.
|
||
//
|
||
if (g_usrScreenBPP > 4)
|
||
{
|
||
//
|
||
// Check the new color table for any occurrences of the dodgy-grey
|
||
// RGBs which the display driver returns (getDIBits at 8bpp can
|
||
// return RGBs with unequal R, G and B for a supplied RGB with
|
||
// equal components, causing poor quality output).
|
||
//
|
||
for (i = COLORS_FOR_BPP(m_usrSendingBPP); i-- != 0;)
|
||
{
|
||
for ( j = 0; j < PM_GREY_COUNT; j++ )
|
||
{
|
||
if (!memcmp(&pmBitmapInfo.bmiColors[i],
|
||
&m_apmDDGreyRGB[j],
|
||
sizeof(pmBitmapInfo.bmiColors[i])) )
|
||
{
|
||
//
|
||
// Found a dodgy grey in the color table, so replace
|
||
// with a "good" grey, ie one with equal R, G and B.
|
||
//
|
||
pmBitmapInfo.bmiColors[i].rgbRed =
|
||
GetRValue(s_apmGreyRGB[j]);
|
||
pmBitmapInfo.bmiColors[i].rgbGreen =
|
||
GetGValue(s_apmGreyRGB[j]);
|
||
pmBitmapInfo.bmiColors[i].rgbBlue =
|
||
GetBValue(s_apmGreyRGB[j]);
|
||
TRACE_OUT(( "match our grey %#x", s_apmGreyRGB[j]));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the colors have changed then return TRUE and copy the new color
|
||
// table back, else return FALSE.
|
||
//
|
||
if (!memcmp(m_apmTxPaletteColors, pmBitmapInfo.bmiColors,
|
||
COLORS_FOR_BPP(m_usrSendingBPP) * sizeof(RGBQUAD) ))
|
||
{
|
||
rc = FALSE;
|
||
}
|
||
else
|
||
{
|
||
memcpy(m_apmTxPaletteColors, pmBitmapInfo.bmiColors,
|
||
COLORS_FOR_BPP(m_usrSendingBPP) * sizeof(RGBQUAD) );
|
||
|
||
rc = TRUE;
|
||
}
|
||
|
||
DC_EXIT_POINT:
|
||
if (hbmpDummy != NULL)
|
||
{
|
||
DeleteBitmap(hbmpDummy);
|
||
}
|
||
|
||
if (hdcMem != NULL)
|
||
{
|
||
DeleteDC(hdcMem);
|
||
}
|
||
|
||
DebugExitDWORD(ASHost::PMUpdateTxPaletteColors, rc);
|
||
return(rc);
|
||
}
|
||
|
||
//
|
||
// FUNCTION: PMCreatePalette
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Creates a new palette using the given colors.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// cEntries - number of entries in the pNewEntries array
|
||
//
|
||
// pNewEntries - pointer to a TSHR_COLOR array containing the new palette
|
||
// entries
|
||
//
|
||
// phPal - pointer to a HPALETTE variable that receives the new palette
|
||
// handle.
|
||
//
|
||
//
|
||
// RETURNS - TRUE if successful, FALSE otherwise.
|
||
//
|
||
//
|
||
BOOL ASShare::PM_CreatePalette
|
||
(
|
||
UINT cEntries,
|
||
LPTSHR_COLOR pNewEntries,
|
||
HPALETTE * phPal
|
||
)
|
||
{
|
||
UINT i;
|
||
BYTE pmLogPaletteBuffer[sizeof(LOGPALETTE) + (PM_NUM_8BPP_PAL_ENTRIES-1)*sizeof(PALETTEENTRY)];
|
||
LPLOGPALETTE pLogPalette;
|
||
BOOL rc = FALSE;
|
||
|
||
DebugEntry(ASShare::PM_CreatePalette);
|
||
|
||
ASSERT(cEntries <= PM_NUM_8BPP_PAL_ENTRIES);
|
||
|
||
//
|
||
// Set up a palette structure.
|
||
//
|
||
pLogPalette = (LPLOGPALETTE)pmLogPaletteBuffer;
|
||
|
||
// This is a random windows constant
|
||
pLogPalette->palVersion = 0x300;
|
||
pLogPalette->palNumEntries = (WORD)cEntries;
|
||
|
||
//
|
||
// This palette packet contains an array of TSHR_COLOR structures which
|
||
// contains 3 fields (RGB). We have to convert each of these
|
||
// structures to a PALETTEENTRY structure which has the same 3 fields
|
||
// (RGB) plus some flags.
|
||
//
|
||
for (i = 0; i < cEntries; i++)
|
||
{
|
||
TSHR_COLOR_TO_PALETTEENTRY( pNewEntries[i],
|
||
pLogPalette->palPalEntry[i] );
|
||
}
|
||
|
||
//
|
||
// Create the palette.
|
||
//
|
||
*phPal = CreatePalette(pLogPalette);
|
||
|
||
//
|
||
// Return TRUE if the palette was created.
|
||
//
|
||
rc = (*phPal != NULL);
|
||
|
||
DebugExitDWORD(ASShare::PM_CreatePalette, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// FUNCTION: PM_AdjustColorsForBuggedDisplayDrivers
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Adjusts the supplied color table if necessary to take account of display
|
||
// driver bugs.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// pColors - pointer to the color table (an array of RGBQUADs)
|
||
//
|
||
// cColors - number of colors in the supplied color table
|
||
//
|
||
// RETURNS: Nothing.
|
||
//
|
||
//
|
||
// NOTE: There is similar code in NormalizeRGB below (although not similar
|
||
// enough to macro it.) If you change this code you should probably do
|
||
// the same there.)
|
||
//
|
||
void ASHost::PM_AdjustColorsForBuggedDisplayDrivers
|
||
(
|
||
LPTSHR_RGBQUAD pColors,
|
||
UINT cColors
|
||
)
|
||
{
|
||
LPTSHR_RGBQUAD pColor;
|
||
UINT i;
|
||
|
||
DebugEntry(ASHost::PM_AdjustColorsForBuggedDisplayDrivers);
|
||
|
||
//
|
||
// The Win95 16bpp display drivers return wrong colors when querying at
|
||
// 8bpp. The palette depends on the driver itself (5-6-5, 6-5-5, 5-6-5,
|
||
// or 5-5-5). Only when R, G, and B have the same # of bits are we
|
||
// going to end up with an even distribution.
|
||
//
|
||
// Detect this case and try to adjust the colors.
|
||
//
|
||
m_pmBuggedDriver = ((g_usrScreenBPP > 8) &&
|
||
(pColors[1].rgbRed == 0) &&
|
||
(pColors[1].rgbGreen == 0) &&
|
||
(pColors[1].rgbBlue == 0x40));
|
||
|
||
if (m_pmBuggedDriver)
|
||
{
|
||
TRACE_OUT(( "Adjusting for bugged driver"));
|
||
pColor = pColors;
|
||
|
||
for (i = 0; i < cColors; i++)
|
||
{
|
||
PMADJUSTBUGGEDCOLOR(pColor);
|
||
pColor++;
|
||
}
|
||
}
|
||
|
||
DebugExitVOID(ASHost::PM_AdjustColorsForBuggedDisplayDrivers);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// FUNCTION: PM_DeletePalette
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Deletes the given palette, if it is not the default palette.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// palette - palette to be deleted
|
||
//
|
||
// RETURNS: Nothing.
|
||
//
|
||
//
|
||
void ASShare::PM_DeletePalette(HPALETTE palette)
|
||
{
|
||
DebugEntry(ASShare::PM_DeletePalette);
|
||
|
||
if ((palette != NULL) &&
|
||
(palette != (HPALETTE)GetStockObject(DEFAULT_PALETTE)))
|
||
{
|
||
DeletePalette(palette);
|
||
}
|
||
|
||
DebugExitVOID(ASShare::PM_DeletePalette);
|
||
}
|
||
|