mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Optimize GDI redraw on window position changes
This commit is contained in:
parent
7cbc65878a
commit
6183aed7da
@ -17,14 +17,11 @@ namespace
|
|||||||
|
|
||||||
void updateWindowClipList(CompatRef<IDirectDrawClipper> clipper, ClipperData& data);
|
void updateWindowClipList(CompatRef<IDirectDrawClipper> clipper, ClipperData& data);
|
||||||
|
|
||||||
void onWindowPosChange(HWND /*hwnd*/, const RECT& oldWindowRect, const RECT& newWindowRect)
|
void onWindowPosChange()
|
||||||
{
|
{
|
||||||
for (auto& clipperData : g_clipperData)
|
for (auto& clipperData : g_clipperData)
|
||||||
{
|
{
|
||||||
if (!IsRectEmpty(&oldWindowRect) || !IsRectEmpty(&newWindowRect))
|
updateWindowClipList(*clipperData.first, clipperData.second);
|
||||||
{
|
|
||||||
updateWindowClipList(*clipperData.first, clipperData.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,9 +221,11 @@
|
|||||||
<ClInclude Include="Gdi\DcCache.h" />
|
<ClInclude Include="Gdi\DcCache.h" />
|
||||||
<ClInclude Include="Gdi\DcFunctions.h" />
|
<ClInclude Include="Gdi\DcFunctions.h" />
|
||||||
<ClInclude Include="Gdi\PaintHandlers.h" />
|
<ClInclude Include="Gdi\PaintHandlers.h" />
|
||||||
|
<ClInclude Include="Gdi\Region.h" />
|
||||||
<ClInclude Include="Gdi\ScrollBar.h" />
|
<ClInclude Include="Gdi\ScrollBar.h" />
|
||||||
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
||||||
<ClInclude Include="Gdi\TitleBar.h" />
|
<ClInclude Include="Gdi\TitleBar.h" />
|
||||||
|
<ClInclude Include="Gdi\Window.h" />
|
||||||
<ClInclude Include="Gdi\WinProc.h" />
|
<ClInclude Include="Gdi\WinProc.h" />
|
||||||
<ClInclude Include="Win32\DisplayMode.h" />
|
<ClInclude Include="Win32\DisplayMode.h" />
|
||||||
<ClInclude Include="Win32\FontSmoothing.h" />
|
<ClInclude Include="Win32\FontSmoothing.h" />
|
||||||
@ -278,9 +280,11 @@
|
|||||||
<ClCompile Include="Gdi\DcCache.cpp" />
|
<ClCompile Include="Gdi\DcCache.cpp" />
|
||||||
<ClCompile Include="Gdi\DcFunctions.cpp" />
|
<ClCompile Include="Gdi\DcFunctions.cpp" />
|
||||||
<ClCompile Include="Gdi\PaintHandlers.cpp" />
|
<ClCompile Include="Gdi\PaintHandlers.cpp" />
|
||||||
|
<ClCompile Include="Gdi\Region.cpp" />
|
||||||
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
||||||
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
||||||
<ClCompile Include="Gdi\TitleBar.cpp" />
|
<ClCompile Include="Gdi\TitleBar.cpp" />
|
||||||
|
<ClCompile Include="Gdi\Window.cpp" />
|
||||||
<ClCompile Include="Gdi\WinProc.cpp" />
|
<ClCompile Include="Gdi\WinProc.cpp" />
|
||||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||||
<ClCompile Include="Win32\FontSmoothing.cpp" />
|
<ClCompile Include="Win32\FontSmoothing.cpp" />
|
||||||
|
@ -315,6 +315,12 @@
|
|||||||
<ClInclude Include="D3dDdi\Device.h">
|
<ClInclude Include="D3dDdi\Device.h">
|
||||||
<Filter>Header Files\D3dDdi</Filter>
|
<Filter>Header Files\D3dDdi</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Gdi\Window.h">
|
||||||
|
<Filter>Header Files\Gdi</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Gdi\Region.h">
|
||||||
|
<Filter>Header Files\Gdi</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Gdi\Gdi.cpp">
|
<ClCompile Include="Gdi\Gdi.cpp">
|
||||||
@ -482,6 +488,12 @@
|
|||||||
<ClCompile Include="D3dDdi\Device.cpp">
|
<ClCompile Include="D3dDdi\Device.cpp">
|
||||||
<Filter>Source Files\D3dDdi</Filter>
|
<Filter>Source Files\D3dDdi</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Gdi\Window.cpp">
|
||||||
|
<Filter>Source Files\Gdi</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Gdi\Region.cpp">
|
||||||
|
<Filter>Source Files\Gdi</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Dll\DDrawCompat.def">
|
<None Include="Dll\DDrawCompat.def">
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcCache.h"
|
#include "Gdi/DcCache.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -95,7 +96,20 @@ namespace
|
|||||||
SelectClipRgn(compatDc, clipRgn);
|
SelectClipRgn(compatDc, clipRgn);
|
||||||
}
|
}
|
||||||
DeleteObject(clipRgn);
|
DeleteObject(clipRgn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateWindow(HWND wnd)
|
||||||
|
{
|
||||||
|
RECT windowRect = {};
|
||||||
|
GetWindowRect(wnd, &windowRect);
|
||||||
|
|
||||||
|
auto& window = Gdi::Window::get(wnd);
|
||||||
|
RECT cachedWindowRect = window.getWindowRect();
|
||||||
|
|
||||||
|
if (!EqualRect(&windowRect, &cachedWindowRect))
|
||||||
|
{
|
||||||
|
Gdi::Window::updateAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +133,13 @@ namespace Gdi
|
|||||||
return it->second.dc;
|
return it->second.dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(origDc);
|
||||||
|
const HWND rootWnd = wnd ? GetAncestor(wnd, GA_ROOT) : nullptr;
|
||||||
|
if (rootWnd && GetDesktopWindow() != rootWnd)
|
||||||
|
{
|
||||||
|
updateWindow(rootWnd);
|
||||||
|
}
|
||||||
|
|
||||||
CompatDc compatDc(Gdi::DcCache::getDc());
|
CompatDc compatDc(Gdi::DcCache::getDc());
|
||||||
if (!compatDc.dc)
|
if (!compatDc.dc)
|
||||||
{
|
{
|
||||||
@ -130,7 +151,7 @@ namespace Gdi
|
|||||||
|
|
||||||
compatDc.savedState = SaveDC(compatDc.dc);
|
compatDc.savedState = SaveDC(compatDc.dc);
|
||||||
copyDcAttributes(compatDc, origDc, origin);
|
copyDcAttributes(compatDc, origDc, origin);
|
||||||
setClippingRegion(compatDc.dc, origDc, CALL_ORIG_FUNC(WindowFromDC)(origDc), origin);
|
setClippingRegion(compatDc.dc, origDc, wnd, origin);
|
||||||
|
|
||||||
compatDc.refCount = 1;
|
compatDc.refCount = 1;
|
||||||
compatDc.origDc = origDc;
|
compatDc.origDc = origDc;
|
||||||
|
@ -242,7 +242,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
HWND hwnd = WindowFromDC(hdc);
|
HWND hwnd = WindowFromDC(hdc);
|
||||||
if (!hwnd || (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
if (!hwnd || hwnd == GetDesktopWindow() || (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -195,24 +195,25 @@ namespace Gdi
|
|||||||
|
|
||||||
void redrawWindow(HWND hwnd, HRGN rgn)
|
void redrawWindow(HWND hwnd, HRGN rgn)
|
||||||
{
|
{
|
||||||
if (!IsWindowVisible(hwnd))
|
if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rgn)
|
|
||||||
{
|
|
||||||
RedrawWindow(hwnd, nullptr, nullptr,
|
|
||||||
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
POINT origin = {};
|
POINT origin = {};
|
||||||
ClientToScreen(hwnd, &origin);
|
if (rgn)
|
||||||
OffsetRgn(rgn, -origin.x, -origin.y);
|
{
|
||||||
RedrawWindow(hwnd, nullptr, rgn,
|
ClientToScreen(hwnd, &origin);
|
||||||
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
OffsetRgn(rgn, -origin.x, -origin.y);
|
||||||
OffsetRgn(rgn, origin.x, origin.y);
|
}
|
||||||
|
|
||||||
|
RedrawWindow(hwnd, nullptr, rgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
||||||
|
RedrawWindow(hwnd, nullptr, rgn, RDW_ERASENOW);
|
||||||
|
|
||||||
|
if (rgn)
|
||||||
|
{
|
||||||
|
OffsetRgn(rgn, origin.x, origin.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unhookWndProc(LPCSTR className, WNDPROC oldWndProc)
|
void unhookWndProc(LPCSTR className, WNDPROC oldWndProc)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
{
|
{
|
||||||
typedef void(*WindowPosChangeNotifyFunc)(HWND, const RECT&, const RECT&);
|
typedef void(*WindowPosChangeNotifyFunc)();
|
||||||
|
|
||||||
bool beginGdiRendering(DWORD lockFlags = 0);
|
bool beginGdiRendering(DWORD lockFlags = 0);
|
||||||
void endGdiRendering();
|
void endGdiRendering();
|
||||||
|
148
DDrawCompat/Gdi/Region.cpp
Normal file
148
DDrawCompat/Gdi/Region.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Gdi/Region.h"
|
||||||
|
#include "Win32/DisplayMode.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
BOOL CALLBACK addMonitorRectToRegion(
|
||||||
|
HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData)
|
||||||
|
{
|
||||||
|
Gdi::Region& virtualScreenRegion = *reinterpret_cast<Gdi::Region*>(dwData);
|
||||||
|
Gdi::Region monitorRegion(*lprcMonitor);
|
||||||
|
virtualScreenRegion |= monitorRegion;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gdi::Region calculateVirtualScreenRegion()
|
||||||
|
{
|
||||||
|
Gdi::Region region;
|
||||||
|
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(®ion));
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gdi::Region combineRegions(const Gdi::Region& rgn1, const Gdi::Region& rgn2, int mode)
|
||||||
|
{
|
||||||
|
Gdi::Region region;
|
||||||
|
CombineRgn(region, rgn1, rgn2, mode);
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Gdi
|
||||||
|
{
|
||||||
|
Region::Region(const RECT& rect)
|
||||||
|
: m_region(CreateRectRgnIndirect(&rect))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Region::~Region()
|
||||||
|
{
|
||||||
|
if (m_region)
|
||||||
|
{
|
||||||
|
DeleteObject(m_region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Region::Region(const Region& other)
|
||||||
|
: Region()
|
||||||
|
{
|
||||||
|
CombineRgn(m_region, other, nullptr, RGN_COPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region::Region(Region&& other)
|
||||||
|
: m_region(other.m_region)
|
||||||
|
{
|
||||||
|
other.m_region = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region& Region::operator=(Region other)
|
||||||
|
{
|
||||||
|
swap(*this, other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Region::isEmpty() const
|
||||||
|
{
|
||||||
|
return sizeof(RGNDATAHEADER) == GetRegionData(m_region, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Region::offset(int x, int y)
|
||||||
|
{
|
||||||
|
OffsetRgn(m_region, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region::operator HRGN() const
|
||||||
|
{
|
||||||
|
return m_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator&(const Region& other) const
|
||||||
|
{
|
||||||
|
return combineRegions(*this, other, RGN_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator|(const Region& other) const
|
||||||
|
{
|
||||||
|
return combineRegions(*this, other, RGN_OR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator-(const Region& other) const
|
||||||
|
{
|
||||||
|
return combineRegions(*this, other, RGN_DIFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator&=(const Region& other)
|
||||||
|
{
|
||||||
|
return combine(other, RGN_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator|=(const Region& other)
|
||||||
|
{
|
||||||
|
return combine(other, RGN_OR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Region::operator-=(const Region& other)
|
||||||
|
{
|
||||||
|
return combine(other, RGN_DIFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(Region& rgn1, Region& rgn2)
|
||||||
|
{
|
||||||
|
std::swap(rgn1.m_region, rgn2.m_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region operator&(const Region& rgn1, const Region& rgn2)
|
||||||
|
{
|
||||||
|
return combineRegions(rgn1, rgn2, RGN_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region operator|(const Region& rgn1, const Region& rgn2)
|
||||||
|
{
|
||||||
|
return combineRegions(rgn1, rgn2, RGN_OR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region operator-(const Region& rgn1, const Region& rgn2)
|
||||||
|
{
|
||||||
|
return combineRegions(rgn1, rgn2, RGN_DIFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region& Region::combine(const Region& other, int mode)
|
||||||
|
{
|
||||||
|
CombineRgn(m_region, m_region, other, mode);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Region& getVirtualScreenRegion()
|
||||||
|
{
|
||||||
|
static Region virtualScreenRegion;
|
||||||
|
static ULONG displaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||||
|
const ULONG currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||||
|
if (currentDisplaySettingsUniqueness != displaySettingsUniqueness)
|
||||||
|
{
|
||||||
|
virtualScreenRegion = calculateVirtualScreenRegion();
|
||||||
|
displaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||||
|
}
|
||||||
|
return virtualScreenRegion;
|
||||||
|
}
|
||||||
|
}
|
40
DDrawCompat/Gdi/Region.h
Normal file
40
DDrawCompat/Gdi/Region.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace Gdi
|
||||||
|
{
|
||||||
|
class Region
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Region(const RECT& rect = RECT{ 0, 0, 0, 0 });
|
||||||
|
~Region();
|
||||||
|
Region(const Region& other);
|
||||||
|
Region(Region&& other);
|
||||||
|
Region& operator=(Region other);
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
|
void offset(int x, int y);
|
||||||
|
|
||||||
|
operator HRGN() const;
|
||||||
|
|
||||||
|
Region operator&(const Region& other) const;
|
||||||
|
Region operator|(const Region& other) const;
|
||||||
|
Region operator-(const Region& other) const;
|
||||||
|
|
||||||
|
Region operator&=(const Region& other);
|
||||||
|
Region operator|=(const Region& other);
|
||||||
|
Region operator-=(const Region& other);
|
||||||
|
|
||||||
|
friend void swap(Region& rgn1, Region& rgn2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Region& combine(const Region& other, int mode);
|
||||||
|
|
||||||
|
HRGN m_region;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Region& getVirtualScreenRegion();
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
@ -13,29 +13,22 @@
|
|||||||
#include "Gdi/ScrollBar.h"
|
#include "Gdi/ScrollBar.h"
|
||||||
#include "Gdi/ScrollFunctions.h"
|
#include "Gdi/ScrollFunctions.h"
|
||||||
#include "Gdi/TitleBar.h"
|
#include "Gdi/TitleBar.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
#include "Gdi/WinProc.h"
|
#include "Gdi/WinProc.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct WindowData
|
|
||||||
{
|
|
||||||
RECT wndRect;
|
|
||||||
std::shared_ptr<HRGN__> sysClipRgn;
|
|
||||||
};
|
|
||||||
|
|
||||||
HHOOK g_callWndRetProcHook = nullptr;
|
HHOOK g_callWndRetProcHook = nullptr;
|
||||||
HWINEVENTHOOK g_objectStateChangeEventHook = nullptr;
|
HWINEVENTHOOK g_objectStateChangeEventHook = nullptr;
|
||||||
std::unordered_map<HWND, WindowData> g_windowData;
|
|
||||||
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
||||||
|
|
||||||
void disableDwmAttributes(HWND hwnd);
|
void disableDwmAttributes(HWND hwnd);
|
||||||
void onActivate(HWND hwnd);
|
void onActivate(HWND hwnd);
|
||||||
|
void onCreateWindow(HWND hwnd);
|
||||||
|
void onDestroyWindow(HWND hwnd);
|
||||||
void onMenuSelect();
|
void onMenuSelect();
|
||||||
void onWindowPosChanged(HWND hwnd);
|
void onWindowPosChanged(HWND hwnd);
|
||||||
void redrawChangedWindowRegion(HWND hwnd, const WindowData& prevData, const WindowData& data);
|
|
||||||
void redrawUncoveredRegion(const WindowData& prevData, const WindowData& data);
|
|
||||||
void removeDropShadow(HWND hwnd);
|
void removeDropShadow(HWND hwnd);
|
||||||
BOOL CALLBACK updateWindowData(HWND hwnd, LPARAM lParam);
|
|
||||||
|
|
||||||
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
@ -46,13 +39,11 @@ namespace
|
|||||||
{
|
{
|
||||||
if (WM_CREATE == ret->message)
|
if (WM_CREATE == ret->message)
|
||||||
{
|
{
|
||||||
disableDwmAttributes(ret->hwnd);
|
onCreateWindow(ret->hwnd);
|
||||||
removeDropShadow(ret->hwnd);
|
|
||||||
}
|
}
|
||||||
else if (WM_DESTROY == ret->message)
|
else if (WM_DESTROY == ret->message)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
onDestroyWindow(ret->hwnd);
|
||||||
g_windowData.erase(ret->hwnd);
|
|
||||||
}
|
}
|
||||||
else if (WM_WINDOWPOSCHANGED == ret->message)
|
else if (WM_WINDOWPOSCHANGED == ret->message)
|
||||||
{
|
{
|
||||||
@ -92,18 +83,15 @@ namespace
|
|||||||
&disableTransitions, sizeof(disableTransitions));
|
&disableTransitions, sizeof(disableTransitions));
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowData getWindowData(HWND hwnd)
|
BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/)
|
||||||
{
|
{
|
||||||
WindowData data;
|
onCreateWindow(hwnd);
|
||||||
if (IsWindowVisible(hwnd) && !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
if (!(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||||
{
|
{
|
||||||
GetWindowRect(hwnd, &data.wndRect);
|
RedrawWindow(hwnd, nullptr, nullptr,
|
||||||
data.sysClipRgn.reset(CreateRectRgnIndirect(&data.wndRect), DeleteObject);
|
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW);
|
||||||
HDC dc = GetWindowDC(hwnd);
|
|
||||||
GetRandomRgn(dc, data.sysClipRgn.get(), SYSRGN);
|
|
||||||
ReleaseDC(hwnd, dc);
|
|
||||||
}
|
}
|
||||||
return data;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK objectStateChangeEvent(
|
void CALLBACK objectStateChangeEvent(
|
||||||
@ -164,6 +152,26 @@ namespace
|
|||||||
DeleteObject(ncRgn);
|
DeleteObject(ncRgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onCreateWindow(HWND hwnd)
|
||||||
|
{
|
||||||
|
if (Gdi::isTopLevelWindow(hwnd))
|
||||||
|
{
|
||||||
|
disableDwmAttributes(hwnd);
|
||||||
|
removeDropShadow(hwnd);
|
||||||
|
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||||
|
Gdi::Window::add(hwnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDestroyWindow(HWND hwnd)
|
||||||
|
{
|
||||||
|
if (Gdi::isTopLevelWindow(hwnd))
|
||||||
|
{
|
||||||
|
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||||
|
Gdi::Window::remove(hwnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onMenuSelect()
|
void onMenuSelect()
|
||||||
{
|
{
|
||||||
HWND menuWindow = FindWindow(reinterpret_cast<LPCSTR>(0x8000), nullptr);
|
HWND menuWindow = FindWindow(reinterpret_cast<LPCSTR>(0x8000), nullptr);
|
||||||
@ -189,67 +197,12 @@ namespace
|
|||||||
|
|
||||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||||
|
|
||||||
WindowData prevData = g_windowData[hwnd];
|
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), updateWindowData, 0);
|
|
||||||
WindowData& data = g_windowData[hwnd];
|
|
||||||
|
|
||||||
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||||
{
|
{
|
||||||
notifyFunc(hwnd, prevData.wndRect, data.wndRect);
|
notifyFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prevData.sysClipRgn && !data.sysClipRgn)
|
Gdi::Window::updateAll();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
redrawUncoveredRegion(prevData, data);
|
|
||||||
redrawChangedWindowRegion(hwnd, prevData, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void redrawChangedWindowRegion(HWND hwnd, const WindowData& prevData, const WindowData& data)
|
|
||||||
{
|
|
||||||
if (!data.sysClipRgn)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prevData.sysClipRgn)
|
|
||||||
{
|
|
||||||
Gdi::redrawWindow(hwnd, data.sysClipRgn.get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EqualRect(&prevData.wndRect, &data.wndRect))
|
|
||||||
{
|
|
||||||
HRGN rgn = CreateRectRgn(0, 0, 0, 0);
|
|
||||||
CombineRgn(rgn, data.sysClipRgn.get(), prevData.sysClipRgn.get(), RGN_DIFF);
|
|
||||||
Gdi::redrawWindow(hwnd, rgn);
|
|
||||||
DeleteObject(rgn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Gdi::redrawWindow(hwnd, data.sysClipRgn.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void redrawUncoveredRegion(const WindowData& prevData, const WindowData& data)
|
|
||||||
{
|
|
||||||
if (!prevData.sysClipRgn)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.sysClipRgn)
|
|
||||||
{
|
|
||||||
Gdi::redraw(prevData.sysClipRgn.get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRGN rgn = CreateRectRgn(0, 0, 0, 0);
|
|
||||||
CombineRgn(rgn, prevData.sysClipRgn.get(), data.sysClipRgn.get(), RGN_DIFF);
|
|
||||||
Gdi::redraw(rgn);
|
|
||||||
DeleteObject(rgn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeDropShadow(HWND hwnd)
|
void removeDropShadow(HWND hwnd)
|
||||||
@ -260,12 +213,6 @@ namespace
|
|||||||
SetClassLongPtr(hwnd, GCL_STYLE, style ^ CS_DROPSHADOW);
|
SetClassLongPtr(hwnd, GCL_STYLE, style ^ CS_DROPSHADOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK updateWindowData(HWND hwnd, LPARAM /*lParam*/)
|
|
||||||
{
|
|
||||||
g_windowData[hwnd] = getWindowData(hwnd);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
@ -278,6 +225,8 @@ namespace Gdi
|
|||||||
g_callWndRetProcHook = SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
|
g_callWndRetProcHook = SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
|
||||||
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
|
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
|
||||||
nullptr, &objectStateChangeEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
nullptr, &objectStateChangeEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
||||||
|
|
||||||
|
EnumThreadWindows(threadId, initTopLevelWindow, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
||||||
|
128
DDrawCompat/Gdi/Window.cpp
Normal file
128
DDrawCompat/Gdi/Window.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
|
|
||||||
|
namespace Gdi
|
||||||
|
{
|
||||||
|
Window::Window(HWND hwnd)
|
||||||
|
: m_hwnd(hwnd)
|
||||||
|
, m_windowRect{ 0, 0, 0, 0 }
|
||||||
|
, m_isUpdating(false)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Window& Window::add(HWND hwnd)
|
||||||
|
{
|
||||||
|
auto it = s_windows.find(hwnd);
|
||||||
|
if (it != s_windows.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_windows.emplace(hwnd, hwnd).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion)
|
||||||
|
{
|
||||||
|
if (IsRectEmpty(&m_windowRect) || m_visibleRegion.isEmpty())
|
||||||
|
{
|
||||||
|
m_invalidatedRegion = Region();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_invalidatedRegion = m_visibleRegion;
|
||||||
|
|
||||||
|
if (m_windowRect.right - m_windowRect.left == oldWindowRect.right - oldWindowRect.left &&
|
||||||
|
m_windowRect.bottom - m_windowRect.top == oldWindowRect.bottom - oldWindowRect.top)
|
||||||
|
{
|
||||||
|
Region preservedRegion(oldVisibleRegion);
|
||||||
|
preservedRegion.offset(m_windowRect.left - oldWindowRect.left, m_windowRect.top - oldWindowRect.top);
|
||||||
|
preservedRegion &= m_visibleRegion;
|
||||||
|
|
||||||
|
if (!preservedRegion.isEmpty())
|
||||||
|
{
|
||||||
|
HDC screenDc = GetDC(nullptr);
|
||||||
|
SelectClipRgn(screenDc, preservedRegion);
|
||||||
|
BitBlt(screenDc, m_windowRect.left, m_windowRect.top,
|
||||||
|
oldWindowRect.right - oldWindowRect.left, oldWindowRect.bottom - oldWindowRect.top,
|
||||||
|
screenDc, oldWindowRect.left, oldWindowRect.top, SRCCOPY);
|
||||||
|
ReleaseDC(nullptr, screenDc);
|
||||||
|
|
||||||
|
m_invalidatedRegion -= preservedRegion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window& Window::get(HWND hwnd)
|
||||||
|
{
|
||||||
|
return add(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region Window::getVisibleRegion() const
|
||||||
|
{
|
||||||
|
return m_visibleRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT Window::getWindowRect() const
|
||||||
|
{
|
||||||
|
return m_windowRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::remove(HWND hwnd)
|
||||||
|
{
|
||||||
|
s_windows.erase(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::update()
|
||||||
|
{
|
||||||
|
if (m_isUpdating)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_isUpdating = true;
|
||||||
|
|
||||||
|
RECT newWindowRect = {};
|
||||||
|
Region newVisibleRegion;
|
||||||
|
|
||||||
|
if (IsWindowVisible(m_hwnd) && !IsIconic(m_hwnd))
|
||||||
|
{
|
||||||
|
GetWindowRect(m_hwnd, &newWindowRect);
|
||||||
|
if (!IsRectEmpty(&newWindowRect))
|
||||||
|
{
|
||||||
|
HDC windowDc = GetWindowDC(m_hwnd);
|
||||||
|
GetRandomRgn(windowDc, newVisibleRegion, SYSRGN);
|
||||||
|
ReleaseDC(m_hwnd, windowDc);
|
||||||
|
newVisibleRegion &= getVirtualScreenRegion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::swap(m_windowRect, newWindowRect);
|
||||||
|
swap(m_visibleRegion, newVisibleRegion);
|
||||||
|
|
||||||
|
calcInvalidatedRegion(newWindowRect, newVisibleRegion);
|
||||||
|
|
||||||
|
m_isUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::updateAll()
|
||||||
|
{
|
||||||
|
for (auto& windowPair : s_windows)
|
||||||
|
{
|
||||||
|
windowPair.second.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& windowPair : s_windows)
|
||||||
|
{
|
||||||
|
if (!windowPair.second.m_invalidatedRegion.isEmpty())
|
||||||
|
{
|
||||||
|
POINT clientOrigin = {};
|
||||||
|
ClientToScreen(windowPair.first, &clientOrigin);
|
||||||
|
windowPair.second.m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y);
|
||||||
|
RedrawWindow(windowPair.first, nullptr, windowPair.second.m_invalidatedRegion,
|
||||||
|
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASENOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<HWND, Window> Window::s_windows;
|
||||||
|
}
|
40
DDrawCompat/Gdi/Window.h
Normal file
40
DDrawCompat/Gdi/Window.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "Gdi/Region.h"
|
||||||
|
|
||||||
|
namespace Gdi
|
||||||
|
{
|
||||||
|
class Window
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Window(HWND hwnd);
|
||||||
|
Window(const Window&) = delete;
|
||||||
|
Window& operator=(const Window&) = delete;
|
||||||
|
|
||||||
|
Region getVisibleRegion() const;
|
||||||
|
RECT getWindowRect() const;
|
||||||
|
|
||||||
|
static Window& add(HWND hwnd);
|
||||||
|
static Window& get(HWND hwnd);
|
||||||
|
static void remove(HWND hwnd);
|
||||||
|
static void updateAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion);
|
||||||
|
void update();
|
||||||
|
|
||||||
|
HWND m_hwnd;
|
||||||
|
RECT m_windowRect;
|
||||||
|
Region m_visibleRegion;
|
||||||
|
Region m_invalidatedRegion;
|
||||||
|
bool m_isUpdating;
|
||||||
|
|
||||||
|
static std::map<HWND, Window> s_windows;
|
||||||
|
};
|
||||||
|
}
|
@ -372,6 +372,13 @@ namespace Win32
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ULONG queryDisplaySettingsUniqueness()
|
||||||
|
{
|
||||||
|
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
||||||
|
GetProcAddress(GetModuleHandle("gdi32"), "GdiEntry13"));
|
||||||
|
return ddQueryDisplaySettingsUniqueness();
|
||||||
|
}
|
||||||
|
|
||||||
void setDDrawBpp(DWORD bpp)
|
void setDDrawBpp(DWORD bpp)
|
||||||
{
|
{
|
||||||
g_ddrawBpp = bpp;
|
g_ddrawBpp = bpp;
|
||||||
|
@ -13,6 +13,7 @@ namespace Win32
|
|||||||
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
||||||
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
||||||
|
|
||||||
|
ULONG queryDisplaySettingsUniqueness();
|
||||||
void setDDrawBpp(DWORD bpp);
|
void setDDrawBpp(DWORD bpp);
|
||||||
|
|
||||||
void disableDwm8And16BitMitigation();
|
void disableDwm8And16BitMitigation();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user