From 6e15cb7da7a8f2c85d2afaaadce5c1b1705fb189 Mon Sep 17 00:00:00 2001 From: narzoul Date: Wed, 27 Jan 2021 09:37:47 +0100 Subject: [PATCH] Use only static colors when default palette is selected Fixes changing window border/caption colors (issue #86). --- DDrawCompat/Gdi/Dc.cpp | 10 +-- DDrawCompat/Gdi/DcCache.cpp | 66 ++++++-------------- DDrawCompat/Gdi/DcCache.h | 5 +- DDrawCompat/Gdi/DcFunctions.cpp | 10 ++- DDrawCompat/Gdi/User32WndProcs.cpp | 3 +- DDrawCompat/Gdi/VirtualScreen.cpp | 97 ++++++++++++++++++++---------- DDrawCompat/Gdi/VirtualScreen.h | 6 +- DDrawCompat/Gdi/Window.cpp | 3 +- 8 files changed, 107 insertions(+), 93 deletions(-) diff --git a/DDrawCompat/Gdi/Dc.cpp b/DDrawCompat/Gdi/Dc.cpp index a29988e..f2f43bf 100644 --- a/DDrawCompat/Gdi/Dc.cpp +++ b/DDrawCompat/Gdi/Dc.cpp @@ -26,6 +26,7 @@ namespace HGDIOBJ savedBrush; HGDIOBJ savedPen; HPALETTE savedPalette; + bool useDefaultPalette; }; typedef std::unordered_map CompatDcMap; @@ -151,7 +152,7 @@ namespace Gdi for (auto& origDcToCompatDc : g_origDcToCompatDc) { restoreDc(origDcToCompatDc.second); - Gdi::DcCache::deleteDc(origDcToCompatDc.second.dc); + Gdi::VirtualScreen::deleteDc(origDcToCompatDc.second.dc); } g_origDcToCompatDc.clear(); } @@ -166,7 +167,7 @@ namespace Gdi if (threadId == it->second.threadId) { restoreDc(it->second); - Gdi::DcCache::deleteDc(it->second.dc); + Gdi::VirtualScreen::deleteDc(it->second.dc); it = g_origDcToCompatDc.erase(it); } else @@ -195,7 +196,8 @@ namespace Gdi } CompatDc compatDc; - compatDc.dc = Gdi::DcCache::getDc(); + compatDc.useDefaultPalette = GetStockObject(DEFAULT_PALETTE) == GetCurrentObject(origDc, OBJ_PAL); + compatDc.dc = Gdi::DcCache::getDc(compatDc.useDefaultPalette); if (!compatDc.dc) { return nullptr; @@ -251,7 +253,7 @@ namespace Gdi if (0 == compatDc.refCount) { restoreDc(compatDc); - Gdi::DcCache::releaseDc(compatDc.dc); + Gdi::DcCache::releaseDc(compatDc.dc, compatDc.useDefaultPalette); g_origDcToCompatDc.erase(origDc); } } diff --git a/DDrawCompat/Gdi/DcCache.cpp b/DDrawCompat/Gdi/DcCache.cpp index a6edc3b..5273c28 100644 --- a/DDrawCompat/Gdi/DcCache.cpp +++ b/DDrawCompat/Gdi/DcCache.cpp @@ -1,87 +1,61 @@ -#include #include #include #include -#include "Common/ScopedCriticalSection.h" -#include "Gdi/DcCache.h" -#include "Gdi/VirtualScreen.h" +#include +#include +#include namespace { + struct Cache + { + std::vector> cache; + std::vector> defPalCache; + }; + Compat::CriticalSection g_cs; - std::map> g_threadIdToDcCache; + std::map g_threadIdToDcCache; } namespace Gdi { namespace DcCache { - void deleteDc(HDC cachedDc) - { - Compat::ScopedCriticalSection lock(g_cs); - for (auto& threadIdToDcCache : g_threadIdToDcCache) - { - auto& dcCache = threadIdToDcCache.second; - auto it = std::find(dcCache.begin(), dcCache.end(), cachedDc); - if (it != dcCache.end()) - { - Gdi::VirtualScreen::deleteDc(*it); - dcCache.erase(it); - return; - } - } - } - void dllProcessDetach() { Compat::ScopedCriticalSection lock(g_cs); - for (auto& threadIdToDcCache : g_threadIdToDcCache) - { - for (HDC dc : threadIdToDcCache.second) - { - Gdi::VirtualScreen::deleteDc(dc); - } - } g_threadIdToDcCache.clear(); } void dllThreadDetach() { Compat::ScopedCriticalSection lock(g_cs); - auto it = g_threadIdToDcCache.find(GetCurrentThreadId()); - if (it == g_threadIdToDcCache.end()) - { - return; - } - - for (HDC dc : it->second) - { - Gdi::VirtualScreen::deleteDc(dc); - } - - g_threadIdToDcCache.erase(it); + g_threadIdToDcCache.erase(GetCurrentThreadId()); } - HDC getDc() + HDC getDc(bool useDefaultPalette) { Compat::ScopedCriticalSection lock(g_cs); - std::vector& dcCache = g_threadIdToDcCache[GetCurrentThreadId()]; + auto& cache = g_threadIdToDcCache[GetCurrentThreadId()]; + auto& dcCache = useDefaultPalette ? cache.defPalCache : cache.cache; if (dcCache.empty()) { - return Gdi::VirtualScreen::createDc(); + return Gdi::VirtualScreen::createDc(useDefaultPalette); } - HDC dc = dcCache.back(); + HDC dc = dcCache.back().release(); dcCache.pop_back(); return dc; } - void releaseDc(HDC cachedDc) + void releaseDc(HDC cachedDc, bool useDefaultPalette) { Compat::ScopedCriticalSection lock(g_cs); - g_threadIdToDcCache[GetCurrentThreadId()].push_back(cachedDc); + auto& cache = g_threadIdToDcCache[GetCurrentThreadId()]; + auto& dcCache = useDefaultPalette ? cache.defPalCache : cache.cache; + dcCache.emplace_back(cachedDc, Gdi::VirtualScreen::deleteDc); } } } diff --git a/DDrawCompat/Gdi/DcCache.h b/DDrawCompat/Gdi/DcCache.h index aacf699..6406c48 100644 --- a/DDrawCompat/Gdi/DcCache.h +++ b/DDrawCompat/Gdi/DcCache.h @@ -6,10 +6,9 @@ namespace Gdi { namespace DcCache { - void deleteDc(HDC cachedDc); void dllProcessDetach(); void dllThreadDetach(); - HDC getDc(); - void releaseDc(HDC cachedDc); + HDC getDc(bool useDefaultPalette); + void releaseDc(HDC cachedDc, bool useDefaultPalette); } } diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index b974e45..50c880a 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -214,7 +214,8 @@ namespace LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy); if (g_redirectToDib && Gdi::isDisplayDc(hdc)) { - return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy)); + const bool useDefaultPalette = false; + return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy, useDefaultPalette)); } return LOG_RESULT(CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy)); } @@ -226,7 +227,9 @@ namespace const DWORD CBM_CREATDIB = 2; if (g_redirectToDib && !(fdwInit & CBM_CREATDIB) && lpbmih && Gdi::isDisplayDc(hdc)) { - HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib(lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight); + const bool useDefaultPalette = false; + HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib( + lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, useDefaultPalette); if (bitmap && lpbInit && lpbmi) { SetDIBits(hdc, bitmap, 0, std::abs(lpbmi->bmiHeader.biHeight), lpbInit, lpbmi, fuUsage); @@ -241,7 +244,8 @@ namespace LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight); if (g_redirectToDib && Gdi::isDisplayDc(hdc)) { - return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight)); + const bool useDefaultPalette = false; + return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight, useDefaultPalette)); } return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight)); } diff --git a/DDrawCompat/Gdi/User32WndProcs.cpp b/DDrawCompat/Gdi/User32WndProcs.cpp index e48fc39..4d9f2b9 100644 --- a/DDrawCompat/Gdi/User32WndProcs.cpp +++ b/DDrawCompat/Gdi/User32WndProcs.cpp @@ -308,7 +308,8 @@ namespace RECT r = {}; GetClientRect(hwnd, &r); HDC dc = CreateCompatibleDC(nullptr); - HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom); + const bool useDefaultPalette = true; + HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom, useDefaultPalette); HGDIOBJ origBitmap = SelectObject(dc, dib); CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast(dc), 0); LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast(dc), lParam); diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 36b6028..82319ff 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -1,20 +1,25 @@ -#include +#include -#include "Config/Config.h" -#include "Common/ScopedCriticalSection.h" -#include "D3dDdi/Device.h" -#include "D3dDdi/ScopedCriticalSection.h" -#include "DDraw/DirectDraw.h" -#include "DDraw/RealPrimarySurface.h" -#include "DDraw/ScopedThreadLock.h" -#include "DDraw/Surfaces/PrimarySurface.h" -#include "Gdi/Gdi.h" -#include "Gdi/Region.h" -#include "Gdi/VirtualScreen.h" -#include "Win32/DisplayMode.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace { + struct VirtualScreenDc + { + bool useDefaultPalette; + }; + Compat::CriticalSection g_cs; Gdi::Region g_region; RECT g_bounds = {}; @@ -26,8 +31,9 @@ namespace void* g_surfaceView = nullptr; HGDIOBJ g_stockBitmap = nullptr; + RGBQUAD g_defaultPalette[256] = {}; RGBQUAD g_systemPalette[256] = {}; - std::set g_dcs; + std::map g_dcs; BOOL CALLBACK addMonitorRectToRegion( HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData) @@ -38,7 +44,16 @@ namespace return TRUE; } - HBITMAP createDibSection(LONG width, LONG height, HANDLE section) + RGBQUAD convertToRgbQuad(PALETTEENTRY entry) + { + RGBQUAD quad = {}; + quad.rgbRed = entry.peRed; + quad.rgbGreen = entry.peGreen; + quad.rgbBlue = entry.peBlue; + return quad; + } + + HBITMAP createDibSection(LONG width, LONG height, HANDLE section, bool useDefaultPalette) { struct BITMAPINFO256 : public BITMAPINFO { @@ -55,7 +70,14 @@ namespace if (8 == g_bpp) { - memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette)); + if (useDefaultPalette) + { + memcpy(bmi.bmiColors, g_defaultPalette, sizeof(g_defaultPalette)); + } + else + { + memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette)); + } } else { @@ -74,10 +96,10 @@ namespace Gdi { namespace VirtualScreen { - HDC createDc() + HDC createDc(bool useDefaultPalette) { Compat::ScopedCriticalSection lock(g_cs); - std::unique_ptr dib(createDib(), DeleteObject); + std::unique_ptr dib(createDib(useDefaultPalette), DeleteObject); if (!dib) { return nullptr; @@ -98,24 +120,24 @@ namespace Gdi dib.release(); g_stockBitmap = stockBitmap; - g_dcs.insert(dc.get()); + g_dcs[dc.get()] = { useDefaultPalette }; return dc.release(); } - HBITMAP createDib() + HBITMAP createDib(bool useDefaultPalette) { Compat::ScopedCriticalSection lock(g_cs); if (!g_surfaceFileMapping) { return nullptr; } - return createDibSection(g_width, -g_height, g_surfaceFileMapping); + return createDibSection(g_width, -g_height, g_surfaceFileMapping, useDefaultPalette); } - HBITMAP createOffScreenDib(LONG width, LONG height) + HBITMAP createOffScreenDib(LONG width, LONG height, bool useDefaultPalette) { Compat::ScopedCriticalSection lock(g_cs); - return createDibSection(width, height, nullptr); + return createDibSection(width, height, nullptr, useDefaultPalette); } CompatPtr createSurface(const RECT& rect) @@ -190,6 +212,16 @@ namespace Gdi void init() { + PALETTEENTRY entries[20] = {}; + HPALETTE defaultPalette = reinterpret_cast(GetStockObject(DEFAULT_PALETTE)); + GetPaletteEntries(defaultPalette, 0, 20, entries); + + for (int i = 0; i < 10; ++i) + { + g_defaultPalette[i] = convertToRgbQuad(entries[i]); + g_defaultPalette[246 + i] = convertToRgbQuad(entries[10 + i]); + } + update(); } @@ -223,9 +255,9 @@ namespace Gdi if (g_surfaceFileMapping) { - for (HDC dc : g_dcs) + for (auto& dc : g_dcs) { - DeleteObject(SelectObject(dc, g_stockBitmap)); + DeleteObject(SelectObject(dc.first, g_stockBitmap)); } UnmapViewOfFile(g_surfaceView); CloseHandle(g_surfaceFileMapping); @@ -235,9 +267,9 @@ namespace Gdi g_pitch * g_height + 8, nullptr); g_surfaceView = MapViewOfFile(g_surfaceFileMapping, FILE_MAP_WRITE, 0, 0, 0); - for (HDC dc : g_dcs) + for (auto& dc : g_dcs) { - SelectObject(dc, createDib()); + SelectObject(dc.first, createDib(dc.second.useDefaultPalette)); } } @@ -252,17 +284,18 @@ namespace Gdi RGBQUAD systemPalette[256] = {}; for (int i = 0; i < 256; ++i) { - systemPalette[i].rgbRed = palette[i].peRed; - systemPalette[i].rgbGreen = palette[i].peGreen; - systemPalette[i].rgbBlue = palette[i].peBlue; + systemPalette[i] = convertToRgbQuad(palette[i]); } if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette))) { memcpy(g_systemPalette, systemPalette, sizeof(systemPalette)); - for (HDC dc : g_dcs) + for (auto& dc : g_dcs) { - SetDIBColorTable(dc, 0, 256, systemPalette); + if (!dc.second.useDefaultPalette) + { + SetDIBColorTable(dc.first, 0, 256, systemPalette); + } } } diff --git a/DDrawCompat/Gdi/VirtualScreen.h b/DDrawCompat/Gdi/VirtualScreen.h index 150f402..4dfd381 100644 --- a/DDrawCompat/Gdi/VirtualScreen.h +++ b/DDrawCompat/Gdi/VirtualScreen.h @@ -10,9 +10,9 @@ namespace Gdi namespace VirtualScreen { - HDC createDc(); - HBITMAP createDib(); - HBITMAP createOffScreenDib(LONG width, LONG height); + HDC createDc(bool useDefaultPalette); + HBITMAP createDib(bool useDefaultPalette); + HBITMAP createOffScreenDib(LONG width, LONG height, bool useDefaultPalette); CompatPtr createSurface(const RECT& rect); void deleteDc(HDC dc); diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index f5e654f..6ec8b56 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -429,7 +429,8 @@ namespace Gdi if (!virtualScreenDc) { - virtualScreenDc.reset(Gdi::VirtualScreen::createDc()); + const bool useDefaultPalette = false; + virtualScreenDc.reset(Gdi::VirtualScreen::createDc(useDefaultPalette)); if (!virtualScreenDc) { return;