Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1471 lines
37 KiB

  1. #include "precomp.h"
  2. //
  3. // PM.CPP
  4. // Palette Manager
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. //
  11. // PALETTE MANAGER (PM) OVERVIEW
  12. //
  13. // Palette Manager is responsible for sending palette packets. A palette
  14. // packet:
  15. //
  16. // (1) indicates the colors being used on the host machine - and therefore
  17. // specifies which colors the remote machine should use if it can choose
  18. // (e.g. by selecting and realizing the given colors into the display
  19. // hardware). [A palette packet may not contain the exact colors being
  20. // used on the host if the protocol bpp is different from the host bpp].
  21. //
  22. // (2) specifies the colors which correspond to the values in bitmap
  23. // (screen) data i.e. the values in 4bpp and 8bpp bitmap data are indices
  24. // into the table of colors sent in the palette packet.
  25. //
  26. //
  27. // (1) affects order replay and (2) affects screen data replay, so a
  28. // correct palette packet must be sent (by calling
  29. // PM_MaybeSendPalettePacket) before a batch of updates are sent.
  30. //
  31. // Palette Manager also handles incoming palette packets from other parties
  32. // in the conference and creates corresponding local palettes which the
  33. // Update Receiver can query and use when processing updates.
  34. //
  35. // When a new palette packet is sent (e.g. due to the System Palette
  36. // changing), all shared areas of the screen will be retransmitted in due
  37. // course. A receiving Palette Manager therefore does not have to (and
  38. // should not attempt to) convert any updates/bitmaps that have been
  39. // received prior to the arrival of the new palette packet.
  40. //
  41. //
  42. //
  43. // PM strategy when network packets cannot be allocated.
  44. //
  45. // PM_MaybeSendPalettePacket returns a boolean indicating whether it has
  46. // succesfully sent a palette packet. The USR will only send updates if
  47. // the corresponding palette packet is successfully sent.
  48. //
  49. //
  50. const COLORREF s_apmGreyRGB[PM_GREY_COUNT] =
  51. {
  52. PM_GREY1,
  53. PM_GREY2,
  54. PM_GREY3,
  55. PM_GREY4,
  56. PM_GREY5
  57. };
  58. //
  59. // PM_PartyLeftShare()
  60. //
  61. void ASShare::PM_PartyLeftShare(ASPerson * pasPerson)
  62. {
  63. DebugEntry(ASShare::PM_PartyLeftShare);
  64. ValidatePerson(pasPerson);
  65. // This should be cleared already!
  66. ASSERT(!pasPerson->pmcColorTable);
  67. ASSERT(!pasPerson->apmColorTable);
  68. ASSERT(!pasPerson->pmPalette);
  69. DebugExitVOID(ASShare::PM_PartyLeftShare);
  70. }
  71. //
  72. // PM_RecalcCaps()
  73. //
  74. // This calculates the PM hosting caps when
  75. // * we start to host
  76. // * we're hosting and somebody joins the share
  77. // * we're hosting and somebody leaves the share
  78. //
  79. // This can GO AWAY WHEN 2.x COMPAT IS GONE -- no more min() of cache size
  80. //
  81. void ASShare::PM_RecalcCaps(BOOL fJoiner)
  82. {
  83. ASPerson * pasT;
  84. DebugEntry(ASShare::PM_RecalcCaps);
  85. if (!m_pHost || !fJoiner)
  86. {
  87. //
  88. // Nothing to do if we're not hosting. And also, if somebody has
  89. // left, no recalculation -- 2.x didn't.
  90. //
  91. DC_QUIT;
  92. }
  93. ValidatePerson(m_pasLocal);
  94. //
  95. // NOTE:
  96. // The default size is 6 palettes cached. The result is going to be
  97. // <= that number. There's no point in recreating the cache, it's
  98. // so small.
  99. //
  100. m_pHost->m_pmNumTxCacheEntries = m_pasLocal->cpcCaps.palette.capsColorTableCacheSize;
  101. DC_EXIT_POINT:
  102. DebugExitVOID(ASShare::PM_Recalccaps);
  103. }
  104. //
  105. // PM_HostStarting()
  106. //
  107. // Called when we start to host; sets up color palette stuff and creates
  108. // outgoing palette cache
  109. //
  110. BOOL ASHost::PM_HostStarting(void)
  111. {
  112. BOOL rc = FALSE;
  113. TSHR_COLOR localPalColors[PM_NUM_8BPP_PAL_ENTRIES];
  114. DebugEntry(ASHost::PM_HostStarting);
  115. //
  116. // Get palette caps. NOTE PM_RecalcCaps must be called AFTER
  117. // USR_RecalcCaps(), because that updates m_usrSendingBPP.
  118. //
  119. if (g_usrPalettized)
  120. {
  121. ASSERT(g_usrScreenBPP <= 8);
  122. ZeroMemory(localPalColors, sizeof(localPalColors));
  123. //
  124. // Now create the Local Palette.
  125. //
  126. if (!m_pShare->PM_CreatePalette(COLORS_FOR_BPP(g_usrScreenBPP),
  127. localPalColors, &m_pmTxPalette))
  128. {
  129. ERROR_OUT(( "Failed to create Local Palette"));
  130. DC_QUIT;
  131. }
  132. }
  133. else
  134. {
  135. m_pmTxPalette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
  136. PMGetGrays();
  137. }
  138. //
  139. // With NM 3.0, why not just create a receive cache the size that
  140. // the host specifies in his caps?
  141. //
  142. // So I did that. For back compat, OUTGOING caches use the min size.
  143. // When we only have to be compatible with NM 3.0 and up, we won't
  144. // have to do this min stuff.
  145. //
  146. // Note similar code in CM, SSI, and SBC
  147. //
  148. // Figure out how many outgoing entries we can actually use
  149. m_pShare->PM_RecalcCaps(TRUE);
  150. //
  151. // Create the PM color table cache with a single eviction
  152. // category.
  153. //
  154. if (!CH_CreateCache(&m_pmTxCacheHandle, TSHR_PM_CACHE_ENTRIES,
  155. 1, 0, PMCacheCallback))
  156. {
  157. ERROR_OUT(("Could not create PM cache"));
  158. DC_QUIT;
  159. }
  160. rc = TRUE;
  161. DC_EXIT_POINT:
  162. DebugExitBOOL(ASHost::PM_HostStarting, rc);
  163. return(rc);
  164. }
  165. //
  166. // PM_HostEnded()
  167. //
  168. // We free resources created when we started to host
  169. //
  170. void ASHost::PM_HostEnded(void)
  171. {
  172. DebugEntry(ASHost::PM_HostEnded);
  173. if (m_pmTxPalette)
  174. {
  175. m_pShare->PM_DeletePalette(m_pmTxPalette);
  176. m_pmTxPalette = NULL;
  177. }
  178. if (m_pmTxCacheHandle)
  179. {
  180. CH_DestroyCache(m_pmTxCacheHandle);
  181. m_pmTxCacheHandle = 0;
  182. m_pmNumTxCacheEntries = 0;
  183. }
  184. DebugExitVOID(ASHost::PM_HostEnded);
  185. }
  186. //
  187. // PM_ViewStarting()
  188. //
  189. // For 3.0 nodes, we create the PM cache each time they start hosting
  190. // For 2.x nodes, we create the PM cache once and use it until they leave
  191. // the share.
  192. //
  193. BOOL ASShare::PM_ViewStarting(ASPerson * pasPerson)
  194. {
  195. BOOL rc = FALSE;
  196. DebugEntry(ASShare::PM_ViewStarting);
  197. ValidatePerson(pasPerson);
  198. //
  199. // In normal operation, we will receive a palette packet from the host
  200. // before any updates, which we use to create the correct palette for
  201. // this host.
  202. //
  203. // However, in some back-level calls we may not receive a palette
  204. // packet before the first updates, so we initialize this host's
  205. // palette to the default palette to allow us to generate some sort
  206. // of output.
  207. //
  208. pasPerson->pmPalette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
  209. //
  210. // Allocate color table cache memory based on the negotiated options
  211. // Space needed is (n)x256xRGBQUAD where n is the number of color
  212. // tables the conference supports.
  213. //
  214. pasPerson->pmcColorTable = pasPerson->cpcCaps.palette.capsColorTableCacheSize;
  215. if (!pasPerson->pmcColorTable)
  216. {
  217. WARNING_OUT(("PM_ViewStarting: person [%d] has no palette cache size",
  218. pasPerson->cpcCaps.palette.capsColorTableCacheSize));
  219. rc = TRUE;
  220. DC_QUIT;
  221. }
  222. pasPerson->apmColorTable = new COLORTABLECACHE[pasPerson->pmcColorTable];
  223. if (!pasPerson->apmColorTable)
  224. {
  225. ERROR_OUT(( "Failed to get memory for PM color table cache"));
  226. DC_QUIT;
  227. }
  228. ZeroMemory(pasPerson->apmColorTable, pasPerson->pmcColorTable * sizeof(COLORTABLECACHE));
  229. rc = TRUE;
  230. DC_EXIT_POINT:
  231. DebugExitBOOL(ASShare::PM_ViewStarting, rc);
  232. return(rc);
  233. }
  234. //
  235. // PM_ViewEnded()
  236. //
  237. void ASShare::PM_ViewEnded(ASPerson * pasPerson)
  238. {
  239. DebugEntry(ASShare::PM_ViewEnded);
  240. ValidatePerson(pasPerson);
  241. PMFreeIncoming(pasPerson);
  242. DebugExitVOID(ASShare::PM_PartyViewEnded);
  243. }
  244. //
  245. // PMFreeIncoming()
  246. //
  247. void ASShare::PMFreeIncoming(ASPerson * pasPerson)
  248. {
  249. DebugEntry(ASShare::PMFreeIncoming);
  250. //
  251. // Free the color table cache
  252. //
  253. pasPerson->pmcColorTable = 0;
  254. if (pasPerson->apmColorTable)
  255. {
  256. delete[] pasPerson->apmColorTable;
  257. pasPerson->apmColorTable = NULL;
  258. }
  259. if (pasPerson->pmPalette != NULL)
  260. {
  261. //
  262. // Free this host's palette. and set it to NULL so that we can tell
  263. // that this host has left the share.
  264. //
  265. PM_DeletePalette(pasPerson->pmPalette);
  266. pasPerson->pmPalette = NULL;
  267. }
  268. DebugExitVOID(ASShare::PMFreeIncoming);
  269. }
  270. //
  271. // PM_MaybeSendPalettePacket()
  272. //
  273. BOOL ASHost::PM_MaybeSendPalettePacket(void)
  274. {
  275. BOOL rc = TRUE;
  276. DebugEntry(ASHost::PM_MaybeSendPalettePacket);
  277. if (m_pmMustSendPalette)
  278. {
  279. ASSERT(m_usrSendingBPP <= 8);
  280. //
  281. // Ensure that our palette colors are up to date before we send the
  282. // palette packet.
  283. //
  284. if (g_usrPalettized)
  285. {
  286. PMUpdateSystemPaletteColors();
  287. }
  288. PMUpdateTxPaletteColors();
  289. }
  290. else if (g_usrPalettized)
  291. {
  292. ASSERT(m_usrSendingBPP <= 8);
  293. //
  294. // If the System Palette has changed then we may need to send
  295. // another palette packet.
  296. //
  297. if (PMUpdateSystemPaletteColors())
  298. {
  299. //
  300. // The System Palette has changed, but we only need to send
  301. // another palette packet if the palette colors have changed.
  302. //
  303. TRACE_OUT(( "System Palette changed"));
  304. if (PMUpdateTxPaletteColors())
  305. {
  306. TRACE_OUT(( "Tx Palette changed"));
  307. m_pmMustSendPalette = TRUE;
  308. }
  309. }
  310. }
  311. if (m_pmMustSendPalette)
  312. {
  313. ASSERT(m_usrSendingBPP <= 8);
  314. TRACE_OUT(( "Send palette packet"));
  315. rc = PMSendPalettePacket(m_apmTxPaletteColors, COLORS_FOR_BPP(m_usrSendingBPP));
  316. if (rc)
  317. {
  318. m_pmMustSendPalette = FALSE;
  319. }
  320. }
  321. DebugExitBOOL(ASHost::PM_MaybeSendPalettePacket, rc);
  322. return(rc);
  323. }
  324. //
  325. // PM_ReceivedPacket
  326. //
  327. void ASShare::PM_ReceivedPacket
  328. (
  329. ASPerson * pasPerson,
  330. PS20DATAPACKET pPacket
  331. )
  332. {
  333. PPMPACKET pPMPacket;
  334. HPALETTE newPalette = NULL;
  335. DebugEntry(ASShare::PM_ReceivedPacket);
  336. ValidateView(pasPerson);
  337. pPMPacket = (PPMPACKET)pPacket;
  338. //
  339. // Create a new palette from the received packet.
  340. //
  341. // We cannot just update the current palette colors (using
  342. // SetPaletteEntries) because Windows does not handle the repainting
  343. // of other local Palette Manager apps correctly (it does not
  344. // broadcast the WM_PALETTE.. messages as the palette mapping does
  345. // not change).
  346. //
  347. if (PM_CreatePalette(pPMPacket->numColors, pPMPacket->aColors,
  348. &newPalette))
  349. {
  350. PM_DeletePalette(pasPerson->pmPalette);
  351. pasPerson->pmPalette = newPalette;
  352. TRACE_OUT(( "Created new palette 0x%08x from packet", newPalette));
  353. }
  354. else
  355. {
  356. WARNING_OUT(( "Failed to create palette. person(%u) numColors(%u)",
  357. pasPerson, pPMPacket->numColors));
  358. }
  359. DebugExitVOID(ASShare::PM_ReceivedPacket);
  360. }
  361. //
  362. // PM_SyncOutgoing()
  363. //
  364. void ASHost::PM_SyncOutgoing(void)
  365. {
  366. DebugEntry(ASHost::PM_SyncOutgoing);
  367. //
  368. // Ensure we send a palette to the remote PM next time we are called.
  369. //
  370. if (m_usrSendingBPP <= 8)
  371. {
  372. m_pmMustSendPalette = TRUE;
  373. //
  374. // The sync discards any as-yet-unsent accumulated orders. Since these
  375. // orders may include color table cache orders, clear the cache.
  376. //
  377. ASSERT(m_pmTxCacheHandle);
  378. CH_ClearCache(m_pmTxCacheHandle);
  379. }
  380. DebugExitVOID(ASHost::PM_SyncOutgoing);
  381. }
  382. //
  383. // PM_CacheTxColorTable
  384. //
  385. BOOL ASHost::PM_CacheTxColorTable
  386. (
  387. LPUINT pIndex,
  388. LPBOOL pCacheChanged,
  389. UINT cColors,
  390. LPTSHR_RGBQUAD pColors
  391. )
  392. {
  393. BOOL rc = FALSE;
  394. UINT cacheIndex = 0;
  395. UINT i = 0;
  396. PCOLORTABLECACHE pEntry = NULL;
  397. COLORTABLECACHE newEntry = { 0 };
  398. DebugEntry(ASHost::PM_CacheTxColorTable);
  399. ASSERT(m_usrSendingBPP <= 8);
  400. ASSERT(m_pmTxCacheHandle);
  401. TRACE_OUT(( "Caching table of %u colors", cColors));
  402. //
  403. // Create the data we want to cache. It may be that there is already
  404. // an entry in the cache for this set of colors, but we still need to
  405. // create a cache entry in local memory so we can search the cache to
  406. // find out.
  407. //
  408. ZeroMemory(&newEntry, sizeof(COLORTABLECACHE));
  409. newEntry.inUse = TRUE;
  410. newEntry.cColors = cColors;
  411. memcpy(&newEntry.colors, pColors, cColors * sizeof(TSHR_RGBQUAD));
  412. //
  413. // Check to see if the table is already cached. (No hint or eviction
  414. // category.)
  415. //
  416. if (CH_SearchCache(m_pmTxCacheHandle, (LPBYTE)(&newEntry),
  417. sizeof(COLORTABLECACHE), 0, &cacheIndex ))
  418. {
  419. TRACE_OUT(( "Found existing entry at %u",cacheIndex));
  420. *pIndex = cacheIndex;
  421. *pCacheChanged = FALSE;
  422. rc = TRUE;
  423. DC_QUIT;
  424. }
  425. //
  426. // Find a free cache entry
  427. //
  428. // We arrange that our transmit cache is always one greater than the
  429. // negotiated cache size so that we should never fail to find a free
  430. // array entry. Once we have fully populated our Tx cache we will
  431. // always find the free entry as the one last given back to us by CH.
  432. // Note the scan to <= m_pmNumTxCacheEntries is NOT a mistake.
  433. //
  434. if (m_pmNextTxCacheEntry != NULL)
  435. {
  436. pEntry = m_pmNextTxCacheEntry;
  437. m_pmNextTxCacheEntry = NULL;
  438. }
  439. else
  440. {
  441. for (i = 0; i <= m_pmNumTxCacheEntries; i++)
  442. {
  443. if (!m_apmTxCache[i].inUse)
  444. {
  445. break;
  446. }
  447. }
  448. //
  449. // We should never run out of free entries, but cope with it
  450. //
  451. if (i > m_pmNumTxCacheEntries)
  452. {
  453. ERROR_OUT(( "All PM cache entries in use"));
  454. rc = FALSE;
  455. DC_QUIT;
  456. }
  457. pEntry = m_apmTxCache + i;
  458. }
  459. //
  460. // Set up the color table in the free entry we just found
  461. //
  462. memcpy(pEntry, &newEntry, sizeof(COLORTABLECACHE));
  463. //
  464. // Add the new entry to the cache
  465. // We do not use hints or eviction so set to 0
  466. //
  467. cacheIndex = CH_CacheData(m_pmTxCacheHandle, (LPBYTE)pEntry,
  468. sizeof(COLORTABLECACHE), 0 );
  469. TRACE_OUT(( "Color table 0x%08x cached at index %u", pEntry, cacheIndex));
  470. *pIndex = cacheIndex;
  471. *pCacheChanged = TRUE;
  472. rc = TRUE;
  473. DC_EXIT_POINT:
  474. DebugExitDWORD(ASHost::PM_CacheTxColorTable, rc);
  475. return(rc);
  476. }
  477. //
  478. // PM_CacheRxColorTable
  479. //
  480. BOOL ASShare::PM_CacheRxColorTable
  481. (
  482. ASPerson * pasPerson,
  483. UINT index,
  484. UINT cColors,
  485. LPTSHR_RGBQUAD pColors
  486. )
  487. {
  488. BOOL rc = FALSE;
  489. PCOLORTABLECACHE pColorTable;
  490. DebugEntry(ASShare::PM_CacheRxColorTable);
  491. ValidatePerson(pasPerson);
  492. pColorTable = pasPerson->apmColorTable;
  493. TRACE_OUT(( "Person [%d] color table rx cache 0x%08x cache %u, %u colors",
  494. pasPerson->mcsID, pColorTable, index, cColors));
  495. if (pColorTable == NULL)
  496. {
  497. ERROR_OUT(( "Asked to cache when no cache allocated"));
  498. DC_QUIT;
  499. }
  500. //
  501. // The index must be within the currently negotiated cache limits
  502. //
  503. if (index > pasPerson->pmcColorTable)
  504. {
  505. ERROR_OUT(( "Invalid color table index %u",index));
  506. DC_QUIT;
  507. }
  508. //
  509. // Set up the color table entry
  510. //
  511. pColorTable[index].inUse = TRUE;
  512. pColorTable[index].cColors = cColors;
  513. memcpy(pColorTable[index].colors, pColors, cColors * sizeof(TSHR_RGBQUAD));
  514. rc = TRUE;
  515. DC_EXIT_POINT:
  516. DebugExitDWORD(ASShare::PM_CacheRxColorTable, rc);
  517. return(rc);
  518. }
  519. //
  520. // PMSendPalettePacket
  521. //
  522. // DESCRIPTION:
  523. //
  524. // Sends a palette packet containing the given colors.
  525. //
  526. // PARAMETERS:
  527. //
  528. // pColorTable - pointer to an array of TSHR_RGBQUAD colors to be sent in the
  529. // palette packet.
  530. //
  531. // numColors - the number of entries in the TSHR_RGBQUAD array
  532. //
  533. // RETURNS: TRUE if the palette packet is sent, FALSE otherwise
  534. //
  535. //
  536. BOOL ASHost::PMSendPalettePacket
  537. (
  538. LPTSHR_RGBQUAD pColorTable,
  539. UINT numColors
  540. )
  541. {
  542. PPMPACKET pPMPacket;
  543. UINT sizePkt;
  544. UINT i;
  545. BOOL rc = FALSE;
  546. #ifdef _DEBUG
  547. UINT sentSize;
  548. #endif // _DEBUG
  549. DebugEntry(ASHost::PMSendPalettePacket);
  550. //
  551. // Send a palette packet.
  552. //
  553. // First calculate the packet size.
  554. //
  555. sizePkt = sizeof(PMPACKET) + (numColors - 1) * sizeof(TSHR_COLOR);
  556. pPMPacket = (PPMPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES, g_s20BroadcastID, sizePkt);
  557. if (!pPMPacket)
  558. {
  559. WARNING_OUT(("Failed to alloc PM packet, size %u", sizePkt));
  560. DC_QUIT;
  561. }
  562. //
  563. // Fill in the packet contents.
  564. //
  565. pPMPacket->header.header.data.dataType = DT_UP;
  566. pPMPacket->header.updateType = UPD_PALETTE;
  567. //
  568. // Convert the TSHR_RGBQUADs in the color table to TSHR_COLORs as we copy
  569. // them into the packet.
  570. //
  571. pPMPacket->numColors = numColors;
  572. for (i = 0; i < numColors; i++)
  573. {
  574. //
  575. // Convert each RGBQuad entry in the color table to a DCColor.
  576. //
  577. TSHR_RGBQUAD_TO_TSHR_COLOR(pColorTable[i],
  578. pPMPacket->aColors[i]);
  579. }
  580. //
  581. // Now send the packet to the remote application.
  582. //
  583. if (m_pShare->m_scfViewSelf)
  584. m_pShare->PM_ReceivedPacket(m_pShare->m_pasLocal, &(pPMPacket->header.header));
  585. #ifdef _DEBUG
  586. sentSize =
  587. #endif // _DEBUG
  588. m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES, g_s20BroadcastID,
  589. &(pPMPacket->header.header), sizePkt);
  590. TRACE_OUT(("PM packet size: %08d, sent %08d", sizePkt, sentSize));
  591. rc = TRUE;
  592. DC_EXIT_POINT:
  593. DebugExitDWORD(ASHost::PMSendPalettePacket, rc);
  594. return(rc);
  595. }
  596. //
  597. // FUNCTION: PMCacheCallback
  598. //
  599. // DESCRIPTION:
  600. //
  601. // Cursor Manager's Cache Manager callback function. Called whenever an
  602. // entry is removed from the cache to allow us to free up the object.
  603. //
  604. // PARAMETERS:
  605. //
  606. // hCache - cache handle
  607. //
  608. // event - the cache event that has occured
  609. //
  610. // iCacheEntry - index of the cache entry that the event is affecting
  611. //
  612. // pData - pointer to the cache data associated with the given cache entry
  613. //
  614. // cbDataSize - size in bytes of the cached data
  615. //
  616. // RETURNS: Nothing
  617. //
  618. //
  619. void PMCacheCallback
  620. (
  621. ASHost * pHost,
  622. PCHCACHE pCache,
  623. UINT iCacheEntry,
  624. LPBYTE pData
  625. )
  626. {
  627. DebugEntry(PMCacheCallback);
  628. //
  629. // Release the cache entry for reuse
  630. //
  631. TRACE_OUT(( "Releasing cache entry %d at 0x%08x",
  632. iCacheEntry, pData));
  633. pHost->m_pmNextTxCacheEntry = (PCOLORTABLECACHE)pData;
  634. pHost->m_pmNextTxCacheEntry->inUse = FALSE;
  635. //
  636. // Let SBC know that the cache entry has been released
  637. //
  638. pHost->SBC_PMCacheEntryRemoved(iCacheEntry);
  639. DebugExitVOID(PMCacheCallback);
  640. }
  641. //
  642. // PM_GetSystemPaletteEntries
  643. //
  644. void ASHost::PM_GetSystemPaletteEntries(LPTSHR_RGBQUAD pColors)
  645. {
  646. UINT i;
  647. DebugEntry(ASHost::PM_GetSystemPaletteEntries);
  648. PMUpdateSystemPaletteColors();
  649. for (i = 0; i < PM_NUM_8BPP_PAL_ENTRIES; i++)
  650. {
  651. pColors[i].rgbRed = m_apmCurrentSystemPaletteEntries[i].peRed;
  652. pColors[i].rgbGreen = m_apmCurrentSystemPaletteEntries[i].peGreen;
  653. pColors[i].rgbBlue = m_apmCurrentSystemPaletteEntries[i].peBlue;
  654. pColors[i].rgbReserved = 0;
  655. }
  656. //
  657. // This function in its current form always returns TRUE - it is always
  658. // able to obtain the system colors.
  659. //
  660. DebugExitVOID(ASHost::PM_GetSystemPaletteEntries);
  661. }
  662. //
  663. // PM_GetLocalPalette()
  664. //
  665. HPALETTE ASHost::PM_GetLocalPalette(void)
  666. {
  667. //
  668. // Ensure the palette is up to date
  669. //
  670. if (g_usrPalettized)
  671. {
  672. PMUpdateSystemPaletteColors();
  673. }
  674. //
  675. // Return the handle to the Local Palette.
  676. //
  677. return(m_pmTxPalette);
  678. }
  679. //
  680. // PM_GetColorTable
  681. //
  682. void ASShare::PM_GetColorTable
  683. (
  684. ASPerson * pasPerson,
  685. UINT index,
  686. LPUINT pcColors,
  687. LPTSHR_RGBQUAD pColors
  688. )
  689. {
  690. PCOLORTABLECACHE pColorTable;
  691. DebugEntry(ASShare::PM_GetColorTable);
  692. ValidatePerson(pasPerson);
  693. ASSERT(pasPerson->apmColorTable);
  694. pColorTable = &(pasPerson->apmColorTable[index]);
  695. TRACE_OUT(( "Color table requested for [%d], table ptr 0x%08x index %d",
  696. pasPerson->mcsID, pColorTable,index));
  697. if (!pColorTable->inUse)
  698. {
  699. ERROR_OUT(( "Asked for PM cache entry %hu when cache not yet in use",
  700. index));
  701. DC_QUIT;
  702. }
  703. //
  704. // Copy the colors into the structure we have been passed
  705. //
  706. *pcColors = pColorTable->cColors;
  707. memcpy( pColors,
  708. pColorTable->colors,
  709. sizeof(TSHR_RGBQUAD) * pColorTable->cColors );
  710. TRACE_OUT(( "Returning %u colors",*pcColors));
  711. DC_EXIT_POINT:
  712. DebugExitVOID(ASShare::PM_GetColorTable);
  713. }
  714. //
  715. // PMADJUSTBUGGEDCOLOR()
  716. //
  717. // Macro used to tweak an 8 bit palette entry that the Win95 16 bit
  718. // driver returns incorrectly
  719. //
  720. #define PMADJUSTBUGGEDCOLOR(pColor) \
  721. if ( ((pColor)->rgbBlue != 0x00) && \
  722. ((pColor)->rgbBlue != 0xFF) ) \
  723. { \
  724. (pColor)->rgbBlue += 0x40; \
  725. } \
  726. \
  727. if ( ((pColor)->rgbGreen != 0x00) && \
  728. ((pColor)->rgbGreen != 0xFF) ) \
  729. { \
  730. (pColor)->rgbGreen += 0x20; \
  731. } \
  732. \
  733. if ( ((pColor)->rgbRed != 0x00) && \
  734. ((pColor)->rgbRed != 0xFF) ) \
  735. { \
  736. (pColor)->rgbRed += 0x20; \
  737. }
  738. //
  739. // PMGetGrays()
  740. //
  741. // Gets display driver specific versions of gray RGBs
  742. //
  743. void ASHost::PMGetGrays(void)
  744. {
  745. HBITMAP hOldBitmap = NULL;
  746. BITMAPINFO_ours bitmapInfo;
  747. BYTE bitmapBuffer[16];
  748. UINT i;
  749. DebugEntry(ASHost::PMGetGrays);
  750. //
  751. // Initialise the bitmapinfo local structure header contents. This
  752. // structure will be used in the GetDIBits calls.
  753. //
  754. m_pShare->USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, 8);
  755. bitmapInfo.bmiHeader.biWidth = 16;
  756. bitmapInfo.bmiHeader.biHeight = 1;
  757. //
  758. // Select the bitmap into the work DC
  759. //
  760. hOldBitmap = SelectBitmap(m_usrWorkDC, m_pShare->m_usrBmp16);
  761. if (hOldBitmap == NULL)
  762. {
  763. ERROR_OUT(( "Failed to select bitmap. hp(%08lX) hbmp(%08lX)",
  764. m_usrWorkDC, m_pShare->m_usrBmp16 ));
  765. DC_QUIT;
  766. }
  767. //
  768. // Use the real GDI to set each bit to each supplied color.
  769. //
  770. for (i = PM_GREY_COUNT; i-- != 0; )
  771. {
  772. SetPixel(m_usrWorkDC, i, 0, s_apmGreyRGB[i]);
  773. }
  774. //
  775. // Because this function is only used for true color scenarios we do
  776. // not need to select a palette into our compatible DC. We just need
  777. // to get the bits.
  778. //
  779. if (!GetDIBits(m_usrWorkDC, m_pShare->m_usrBmp16, 0, 1, &bitmapBuffer,
  780. (BITMAPINFO *)&bitmapInfo, DIB_RGB_COLORS ))
  781. {
  782. ERROR_OUT(( "GetDIBits failed. hp(%x) hbmp(%x)",
  783. m_usrWorkDC, m_pShare->m_usrBmp16));
  784. DC_QUIT;
  785. }
  786. //
  787. // Check if we need to adjust the palette colors for the 16 bit driver
  788. // bug.
  789. //
  790. m_pmBuggedDriver = ((g_usrScreenBPP > 8) &&
  791. (bitmapInfo.bmiColors[1].rgbRed == 0) &&
  792. (bitmapInfo.bmiColors[1].rgbGreen == 0) &&
  793. (bitmapInfo.bmiColors[1].rgbBlue == 0x40));
  794. //
  795. // Extract the RGBs returned by the display driver with the sending bpp
  796. // DIB.
  797. //
  798. for (i = PM_GREY_COUNT; i-- != 0; )
  799. {
  800. //
  801. // Extract the RGB from the color table
  802. //
  803. m_apmDDGreyRGB[i] = *((LPTSHR_RGBQUAD)(&bitmapInfo.bmiColors[bitmapBuffer[i]]));
  804. //
  805. // Adjust the palette colors for the 16 bit driver bug, if needed.
  806. //
  807. if (m_pmBuggedDriver)
  808. {
  809. TRACE_OUT(( "Adjusting for bugged driver"));
  810. PMADJUSTBUGGEDCOLOR(&m_apmDDGreyRGB[i]);
  811. }
  812. }
  813. DC_EXIT_POINT:
  814. //
  815. // clean up
  816. //
  817. if (hOldBitmap != NULL)
  818. {
  819. SelectBitmap(m_usrWorkDC, hOldBitmap);
  820. }
  821. DebugExitVOID(ASHost::PMGetGrays);
  822. }
  823. //
  824. // FUNCTION: PMUpdateSystemPaletteColors
  825. //
  826. // DESCRIPTION:
  827. //
  828. // Determines whether the colors in the System Palette have changed since
  829. // the last time this function was called and if so, updates the supplied
  830. // palette so that it contains the same colors as the System Palette.
  831. //
  832. // The first time that this function is called after PM_Init the System
  833. // Palette colors will be returned and the function will return TRUE.
  834. //
  835. // PARAMETERS:
  836. //
  837. // shadowSystemPalette - handle of the palette to be updated with the
  838. // current System Palette colors
  839. //
  840. // RETURNS: TRUE if the System Palette has changed since the last call,
  841. // FALSE otherwise.
  842. //
  843. //
  844. BOOL ASHost::PMUpdateSystemPaletteColors(void)
  845. {
  846. BOOL rc = FALSE;
  847. PALETTEENTRY systemPaletteEntries[PM_NUM_8BPP_PAL_ENTRIES];
  848. HDC hdcScreen = NULL;
  849. UINT cbSystemPaletteEntries;
  850. int irgb, crgb, crgbFixed;
  851. DebugEntry(ASHost::PMUpdateSystemPaletteColors);
  852. ASSERT(g_usrPalettized);
  853. ASSERT(g_usrScreenBPP <= 8);
  854. ASSERT(m_usrSendingBPP <= 8);
  855. //
  856. // Don't bother with all this stuff if the system palette has not
  857. // changed at all. We track notifications to our UI to detect
  858. // palette changes.
  859. //
  860. if (!g_asSharedMemory->pmPaletteChanged)
  861. {
  862. DC_QUIT;
  863. }
  864. hdcScreen = GetDC(NULL);
  865. if (!hdcScreen)
  866. {
  867. WARNING_OUT(( "GetDC failed"));
  868. DC_QUIT;
  869. }
  870. if (GetSystemPaletteEntries(hdcScreen, 0, COLORS_FOR_BPP(g_usrScreenBPP),
  871. systemPaletteEntries) != (UINT)COLORS_FOR_BPP(g_usrScreenBPP))
  872. {
  873. WARNING_OUT(( "GetSystemPaletteEntries failed"));
  874. DC_QUIT;
  875. }
  876. //
  877. // Now that we have succesfully queried the system palette, we can
  878. // reset our flag.
  879. //
  880. g_asSharedMemory->pmPaletteChanged = FALSE;
  881. cbSystemPaletteEntries = COLORS_FOR_BPP(g_usrScreenBPP) * sizeof(PALETTEENTRY);
  882. //
  883. // See if the System Palette has changed from the last time we queried.
  884. //
  885. if (!memcmp(systemPaletteEntries, m_apmCurrentSystemPaletteEntries,
  886. cbSystemPaletteEntries ))
  887. {
  888. //
  889. // The System Palette has not changed
  890. //
  891. TRACE_OUT(( "System palette has NOT changed"));
  892. rc = TRUE;
  893. DC_QUIT;
  894. }
  895. //
  896. // Take a copy of the new System Palette.
  897. //
  898. memcpy(m_apmCurrentSystemPaletteEntries, systemPaletteEntries, cbSystemPaletteEntries );
  899. //
  900. // Update the current local paleete.
  901. //
  902. // NOTE FOR WIN95:
  903. // We need to add PC_NOCOLLAPSE to non-system palette entries.
  904. //
  905. if (g_asWin95)
  906. {
  907. if (GetSystemPaletteUse(hdcScreen) == SYSPAL_STATIC)
  908. crgbFixed = GetDeviceCaps(hdcScreen, NUMRESERVED) / 2;
  909. else
  910. crgbFixed = 1;
  911. crgb = COLORS_FOR_BPP(g_usrScreenBPP) - crgbFixed;
  912. for (irgb = crgbFixed; irgb < crgb; irgb++)
  913. {
  914. systemPaletteEntries[irgb].peFlags = PC_NOCOLLAPSE;
  915. }
  916. }
  917. SetPaletteEntries(m_pmTxPalette, 0, COLORS_FOR_BPP(g_usrScreenBPP),
  918. systemPaletteEntries );
  919. m_pmMustSendPalette = TRUE;
  920. //
  921. // SFR0407: The system palette has changed so re-fetch our set of RGBs
  922. // which the driver returns on an 8-bit GetDIBits for greys.
  923. //
  924. PMGetGrays();
  925. rc = TRUE;
  926. DC_EXIT_POINT:
  927. if (hdcScreen)
  928. {
  929. ReleaseDC(NULL, hdcScreen);
  930. }
  931. DebugExitBOOL(ASHost::PMUpdateSystemPaletteColors, rc);
  932. return(rc);
  933. }
  934. //
  935. // FUNCTION: PMUpdateTxPaletteColors
  936. //
  937. // DESCRIPTION:
  938. //
  939. // Returns the colors that make up the current Tx Palette (the palette that
  940. // is SENT from the local machine). These are not necessarily the colors
  941. // in the local machine's palette, because the local machine's bpp and the
  942. // protocol bpp may be different (e.g. on an 8bpp machine talking at 4bpp
  943. // the Tx Palette has 16 entries).
  944. //
  945. // PARAMETERS:
  946. //
  947. // pColorTable - pointer to an array of RGBQUADs which is filled with the
  948. // colors that make up the current Tx Palette.
  949. //
  950. // RETURNS: TRUE if successful, FALSE otherwise.
  951. //
  952. //
  953. BOOL ASHost::PMUpdateTxPaletteColors(void)
  954. {
  955. UINT i;
  956. UINT j;
  957. BOOL rc = FALSE;
  958. HDC hdcMem = NULL;
  959. HBITMAP hbmpDummy = NULL;
  960. HPALETTE hpalOld = NULL;
  961. BITMAPINFO_ours pmBitmapInfo;
  962. DebugEntry(ASHost::PMUpdateTxPaletteColors);
  963. //
  964. // Returns the values returned by a GetDIBits call with the
  965. // m_pmTxPalette selected.
  966. //
  967. ASSERT(m_usrSendingBPP <= 8);
  968. //
  969. // If we are at 8bpp locally, and sending at 8bpp, then the TxPalette
  970. // is simply the system palette.
  971. //
  972. if ((g_usrScreenBPP == 8) && (m_usrSendingBPP == 8))
  973. {
  974. PM_GetSystemPaletteEntries(pmBitmapInfo.bmiColors);
  975. }
  976. else
  977. {
  978. hdcMem = CreateCompatibleDC(NULL);
  979. if (!hdcMem)
  980. {
  981. ERROR_OUT(("PMUpdateTxPaletteColors: couldn't create memory DC"));
  982. DC_QUIT;
  983. }
  984. hpalOld = SelectPalette(hdcMem, m_pmTxPalette, TRUE);
  985. RealizePalette(hdcMem);
  986. #define DUMMY_WIDTH 8
  987. #define DUMMY_HEIGHT 8
  988. hbmpDummy = CreateBitmap(DUMMY_WIDTH, DUMMY_HEIGHT, 1,
  989. g_usrScreenBPP, NULL);
  990. if (hbmpDummy == NULL)
  991. {
  992. ERROR_OUT(( "Failed to create bitmap"));
  993. DC_QUIT;
  994. }
  995. //
  996. // Set up the structure required by GetDIBits.
  997. //
  998. pmBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  999. pmBitmapInfo.bmiHeader.biWidth = DUMMY_WIDTH;
  1000. pmBitmapInfo.bmiHeader.biHeight = DUMMY_HEIGHT;
  1001. pmBitmapInfo.bmiHeader.biPlanes = 1;
  1002. pmBitmapInfo.bmiHeader.biBitCount = (WORD)m_usrSendingBPP;
  1003. pmBitmapInfo.bmiHeader.biCompression = BI_RGB;
  1004. pmBitmapInfo.bmiHeader.biSizeImage = 0;
  1005. pmBitmapInfo.bmiHeader.biXPelsPerMeter = 10000;
  1006. pmBitmapInfo.bmiHeader.biYPelsPerMeter = 10000;
  1007. pmBitmapInfo.bmiHeader.biClrUsed = 0;
  1008. pmBitmapInfo.bmiHeader.biClrImportant = 0;
  1009. if (0 == GetDIBits( hdcMem,
  1010. hbmpDummy,
  1011. 0,
  1012. DUMMY_HEIGHT,
  1013. NULL,
  1014. (LPBITMAPINFO)&pmBitmapInfo.bmiHeader,
  1015. DIB_RGB_COLORS ))
  1016. {
  1017. WARNING_OUT(( "GetDIBits failed hdc(%x) hbmp(%x)",
  1018. HandleToUlong(hdcMem),
  1019. HandleToUlong(hbmpDummy)));
  1020. DC_QUIT;
  1021. }
  1022. SelectPalette(hdcMem, hpalOld, TRUE);
  1023. PM_AdjustColorsForBuggedDisplayDrivers(
  1024. (LPTSHR_RGBQUAD)pmBitmapInfo.bmiColors,
  1025. COLORS_FOR_BPP(m_usrSendingBPP));
  1026. //
  1027. // This doesn't work for VGA.
  1028. //
  1029. if (g_usrScreenBPP > 4)
  1030. {
  1031. //
  1032. // Check the new color table for any occurrences of the dodgy-grey
  1033. // RGBs which the display driver returns (getDIBits at 8bpp can
  1034. // return RGBs with unequal R, G and B for a supplied RGB with
  1035. // equal components, causing poor quality output).
  1036. //
  1037. for (i = COLORS_FOR_BPP(m_usrSendingBPP); i-- != 0;)
  1038. {
  1039. for ( j = 0; j < PM_GREY_COUNT; j++ )
  1040. {
  1041. if (!memcmp(&pmBitmapInfo.bmiColors[i],
  1042. &m_apmDDGreyRGB[j],
  1043. sizeof(pmBitmapInfo.bmiColors[i])) )
  1044. {
  1045. //
  1046. // Found a dodgy grey in the color table, so replace
  1047. // with a "good" grey, ie one with equal R, G and B.
  1048. //
  1049. pmBitmapInfo.bmiColors[i].rgbRed =
  1050. GetRValue(s_apmGreyRGB[j]);
  1051. pmBitmapInfo.bmiColors[i].rgbGreen =
  1052. GetGValue(s_apmGreyRGB[j]);
  1053. pmBitmapInfo.bmiColors[i].rgbBlue =
  1054. GetBValue(s_apmGreyRGB[j]);
  1055. TRACE_OUT(( "match our grey %#x", s_apmGreyRGB[j]));
  1056. break;
  1057. }
  1058. }
  1059. }
  1060. }
  1061. }
  1062. //
  1063. // If the colors have changed then return TRUE and copy the new color
  1064. // table back, else return FALSE.
  1065. //
  1066. if (!memcmp(m_apmTxPaletteColors, pmBitmapInfo.bmiColors,
  1067. COLORS_FOR_BPP(m_usrSendingBPP) * sizeof(RGBQUAD) ))
  1068. {
  1069. rc = FALSE;
  1070. }
  1071. else
  1072. {
  1073. memcpy(m_apmTxPaletteColors, pmBitmapInfo.bmiColors,
  1074. COLORS_FOR_BPP(m_usrSendingBPP) * sizeof(RGBQUAD) );
  1075. rc = TRUE;
  1076. }
  1077. DC_EXIT_POINT:
  1078. if (hbmpDummy != NULL)
  1079. {
  1080. DeleteBitmap(hbmpDummy);
  1081. }
  1082. if (hdcMem != NULL)
  1083. {
  1084. DeleteDC(hdcMem);
  1085. }
  1086. DebugExitDWORD(ASHost::PMUpdateTxPaletteColors, rc);
  1087. return(rc);
  1088. }
  1089. //
  1090. // FUNCTION: PMCreatePalette
  1091. //
  1092. // DESCRIPTION:
  1093. //
  1094. // Creates a new palette using the given colors.
  1095. //
  1096. // PARAMETERS:
  1097. //
  1098. // cEntries - number of entries in the pNewEntries array
  1099. //
  1100. // pNewEntries - pointer to a TSHR_COLOR array containing the new palette
  1101. // entries
  1102. //
  1103. // phPal - pointer to a HPALETTE variable that receives the new palette
  1104. // handle.
  1105. //
  1106. //
  1107. // RETURNS - TRUE if successful, FALSE otherwise.
  1108. //
  1109. //
  1110. BOOL ASShare::PM_CreatePalette
  1111. (
  1112. UINT cEntries,
  1113. LPTSHR_COLOR pNewEntries,
  1114. HPALETTE * phPal
  1115. )
  1116. {
  1117. UINT i;
  1118. BYTE pmLogPaletteBuffer[sizeof(LOGPALETTE) + (PM_NUM_8BPP_PAL_ENTRIES-1)*sizeof(PALETTEENTRY)];
  1119. LPLOGPALETTE pLogPalette;
  1120. BOOL rc = FALSE;
  1121. DebugEntry(ASShare::PM_CreatePalette);
  1122. ASSERT(cEntries <= PM_NUM_8BPP_PAL_ENTRIES);
  1123. //
  1124. // Set up a palette structure.
  1125. //
  1126. pLogPalette = (LPLOGPALETTE)pmLogPaletteBuffer;
  1127. // This is a random windows constant
  1128. pLogPalette->palVersion = 0x300;
  1129. pLogPalette->palNumEntries = (WORD)cEntries;
  1130. //
  1131. // This palette packet contains an array of TSHR_COLOR structures which
  1132. // contains 3 fields (RGB). We have to convert each of these
  1133. // structures to a PALETTEENTRY structure which has the same 3 fields
  1134. // (RGB) plus some flags.
  1135. //
  1136. for (i = 0; i < cEntries; i++)
  1137. {
  1138. TSHR_COLOR_TO_PALETTEENTRY( pNewEntries[i],
  1139. pLogPalette->palPalEntry[i] );
  1140. }
  1141. //
  1142. // Create the palette.
  1143. //
  1144. *phPal = CreatePalette(pLogPalette);
  1145. //
  1146. // Return TRUE if the palette was created.
  1147. //
  1148. rc = (*phPal != NULL);
  1149. DebugExitDWORD(ASShare::PM_CreatePalette, rc);
  1150. return(rc);
  1151. }
  1152. //
  1153. // FUNCTION: PM_AdjustColorsForBuggedDisplayDrivers
  1154. //
  1155. // DESCRIPTION:
  1156. //
  1157. // Adjusts the supplied color table if necessary to take account of display
  1158. // driver bugs.
  1159. //
  1160. // PARAMETERS:
  1161. //
  1162. // pColors - pointer to the color table (an array of RGBQUADs)
  1163. //
  1164. // cColors - number of colors in the supplied color table
  1165. //
  1166. // RETURNS: Nothing.
  1167. //
  1168. //
  1169. // NOTE: There is similar code in NormalizeRGB below (although not similar
  1170. // enough to macro it.) If you change this code you should probably do
  1171. // the same there.)
  1172. //
  1173. void ASHost::PM_AdjustColorsForBuggedDisplayDrivers
  1174. (
  1175. LPTSHR_RGBQUAD pColors,
  1176. UINT cColors
  1177. )
  1178. {
  1179. LPTSHR_RGBQUAD pColor;
  1180. UINT i;
  1181. DebugEntry(ASHost::PM_AdjustColorsForBuggedDisplayDrivers);
  1182. //
  1183. // The Win95 16bpp display drivers return wrong colors when querying at
  1184. // 8bpp. The palette depends on the driver itself (5-6-5, 6-5-5, 5-6-5,
  1185. // or 5-5-5). Only when R, G, and B have the same # of bits are we
  1186. // going to end up with an even distribution.
  1187. //
  1188. // Detect this case and try to adjust the colors.
  1189. //
  1190. m_pmBuggedDriver = ((g_usrScreenBPP > 8) &&
  1191. (pColors[1].rgbRed == 0) &&
  1192. (pColors[1].rgbGreen == 0) &&
  1193. (pColors[1].rgbBlue == 0x40));
  1194. if (m_pmBuggedDriver)
  1195. {
  1196. TRACE_OUT(( "Adjusting for bugged driver"));
  1197. pColor = pColors;
  1198. for (i = 0; i < cColors; i++)
  1199. {
  1200. PMADJUSTBUGGEDCOLOR(pColor);
  1201. pColor++;
  1202. }
  1203. }
  1204. DebugExitVOID(ASHost::PM_AdjustColorsForBuggedDisplayDrivers);
  1205. }
  1206. //
  1207. // FUNCTION: PM_DeletePalette
  1208. //
  1209. // DESCRIPTION:
  1210. //
  1211. // Deletes the given palette, if it is not the default palette.
  1212. //
  1213. // PARAMETERS:
  1214. //
  1215. // palette - palette to be deleted
  1216. //
  1217. // RETURNS: Nothing.
  1218. //
  1219. //
  1220. void ASShare::PM_DeletePalette(HPALETTE palette)
  1221. {
  1222. DebugEntry(ASShare::PM_DeletePalette);
  1223. if ((palette != NULL) &&
  1224. (palette != (HPALETTE)GetStockObject(DEFAULT_PALETTE)))
  1225. {
  1226. DeletePalette(palette);
  1227. }
  1228. DebugExitVOID(ASShare::PM_DeletePalette);
  1229. }
  1230.