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 onWindowPosChange(HWND /*hwnd*/, const RECT& oldWindowRect, const RECT& newWindowRect)
|
||||
void onWindowPosChange()
|
||||
{
|
||||
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\DcFunctions.h" />
|
||||
<ClInclude Include="Gdi\PaintHandlers.h" />
|
||||
<ClInclude Include="Gdi\Region.h" />
|
||||
<ClInclude Include="Gdi\ScrollBar.h" />
|
||||
<ClInclude Include="Gdi\ScrollFunctions.h" />
|
||||
<ClInclude Include="Gdi\TitleBar.h" />
|
||||
<ClInclude Include="Gdi\Window.h" />
|
||||
<ClInclude Include="Gdi\WinProc.h" />
|
||||
<ClInclude Include="Win32\DisplayMode.h" />
|
||||
<ClInclude Include="Win32\FontSmoothing.h" />
|
||||
@ -278,9 +280,11 @@
|
||||
<ClCompile Include="Gdi\DcCache.cpp" />
|
||||
<ClCompile Include="Gdi\DcFunctions.cpp" />
|
||||
<ClCompile Include="Gdi\PaintHandlers.cpp" />
|
||||
<ClCompile Include="Gdi\Region.cpp" />
|
||||
<ClCompile Include="Gdi\ScrollBar.cpp" />
|
||||
<ClCompile Include="Gdi\ScrollFunctions.cpp" />
|
||||
<ClCompile Include="Gdi\TitleBar.cpp" />
|
||||
<ClCompile Include="Gdi\Window.cpp" />
|
||||
<ClCompile Include="Gdi\WinProc.cpp" />
|
||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||
<ClCompile Include="Win32\FontSmoothing.cpp" />
|
||||
|
@ -315,6 +315,12 @@
|
||||
<ClInclude Include="D3dDdi\Device.h">
|
||||
<Filter>Header Files\D3dDdi</Filter>
|
||||
</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>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -482,6 +488,12 @@
|
||||
<ClCompile Include="D3dDdi\Device.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</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>
|
||||
<None Include="Dll\DDrawCompat.def">
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Gdi/Dc.h"
|
||||
#include "Gdi/DcCache.h"
|
||||
#include "Gdi/Gdi.h"
|
||||
#include "Gdi/Window.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -95,7 +96,20 @@ namespace
|
||||
SelectClipRgn(compatDc, 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;
|
||||
}
|
||||
|
||||
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());
|
||||
if (!compatDc.dc)
|
||||
{
|
||||
@ -130,7 +151,7 @@ namespace Gdi
|
||||
|
||||
compatDc.savedState = SaveDC(compatDc.dc);
|
||||
copyDcAttributes(compatDc, origDc, origin);
|
||||
setClippingRegion(compatDc.dc, origDc, CALL_ORIG_FUNC(WindowFromDC)(origDc), origin);
|
||||
setClippingRegion(compatDc.dc, origDc, wnd, origin);
|
||||
|
||||
compatDc.refCount = 1;
|
||||
compatDc.origDc = origDc;
|
||||
|
@ -242,7 +242,7 @@ namespace
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -195,24 +195,25 @@ namespace Gdi
|
||||
|
||||
void redrawWindow(HWND hwnd, HRGN rgn)
|
||||
{
|
||||
if (!IsWindowVisible(hwnd))
|
||||
if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rgn)
|
||||
{
|
||||
RedrawWindow(hwnd, nullptr, nullptr,
|
||||
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
return;
|
||||
}
|
||||
|
||||
POINT origin = {};
|
||||
ClientToScreen(hwnd, &origin);
|
||||
OffsetRgn(rgn, -origin.x, -origin.y);
|
||||
RedrawWindow(hwnd, nullptr, rgn,
|
||||
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
OffsetRgn(rgn, origin.x, origin.y);
|
||||
if (rgn)
|
||||
{
|
||||
ClientToScreen(hwnd, &origin);
|
||||
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)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
typedef void(*WindowPosChangeNotifyFunc)(HWND, const RECT&, const RECT&);
|
||||
typedef void(*WindowPosChangeNotifyFunc)();
|
||||
|
||||
bool beginGdiRendering(DWORD lockFlags = 0);
|
||||
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
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dwmapi.h>
|
||||
#include <Windows.h>
|
||||
@ -13,29 +13,22 @@
|
||||
#include "Gdi/ScrollBar.h"
|
||||
#include "Gdi/ScrollFunctions.h"
|
||||
#include "Gdi/TitleBar.h"
|
||||
#include "Gdi/Window.h"
|
||||
#include "Gdi/WinProc.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct WindowData
|
||||
{
|
||||
RECT wndRect;
|
||||
std::shared_ptr<HRGN__> sysClipRgn;
|
||||
};
|
||||
|
||||
HHOOK g_callWndRetProcHook = nullptr;
|
||||
HWINEVENTHOOK g_objectStateChangeEventHook = nullptr;
|
||||
std::unordered_map<HWND, WindowData> g_windowData;
|
||||
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
||||
|
||||
void disableDwmAttributes(HWND hwnd);
|
||||
void onActivate(HWND hwnd);
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void onDestroyWindow(HWND hwnd);
|
||||
void onMenuSelect();
|
||||
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);
|
||||
BOOL CALLBACK updateWindowData(HWND hwnd, LPARAM lParam);
|
||||
|
||||
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
@ -46,13 +39,11 @@ namespace
|
||||
{
|
||||
if (WM_CREATE == ret->message)
|
||||
{
|
||||
disableDwmAttributes(ret->hwnd);
|
||||
removeDropShadow(ret->hwnd);
|
||||
onCreateWindow(ret->hwnd);
|
||||
}
|
||||
else if (WM_DESTROY == ret->message)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(Gdi::g_gdiCriticalSection);
|
||||
g_windowData.erase(ret->hwnd);
|
||||
onDestroyWindow(ret->hwnd);
|
||||
}
|
||||
else if (WM_WINDOWPOSCHANGED == ret->message)
|
||||
{
|
||||
@ -92,18 +83,15 @@ namespace
|
||||
&disableTransitions, sizeof(disableTransitions));
|
||||
}
|
||||
|
||||
WindowData getWindowData(HWND hwnd)
|
||||
BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/)
|
||||
{
|
||||
WindowData data;
|
||||
if (IsWindowVisible(hwnd) && !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||
onCreateWindow(hwnd);
|
||||
if (!(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
|
||||
{
|
||||
GetWindowRect(hwnd, &data.wndRect);
|
||||
data.sysClipRgn.reset(CreateRectRgnIndirect(&data.wndRect), DeleteObject);
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
GetRandomRgn(dc, data.sysClipRgn.get(), SYSRGN);
|
||||
ReleaseDC(hwnd, dc);
|
||||
RedrawWindow(hwnd, nullptr, nullptr,
|
||||
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW);
|
||||
}
|
||||
return data;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CALLBACK objectStateChangeEvent(
|
||||
@ -164,6 +152,26 @@ namespace
|
||||
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()
|
||||
{
|
||||
HWND menuWindow = FindWindow(reinterpret_cast<LPCSTR>(0x8000), nullptr);
|
||||
@ -189,67 +197,12 @@ namespace
|
||||
|
||||
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)
|
||||
{
|
||||
notifyFunc(hwnd, prevData.wndRect, data.wndRect);
|
||||
notifyFunc();
|
||||
}
|
||||
|
||||
if (!prevData.sysClipRgn && !data.sysClipRgn)
|
||||
{
|
||||
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);
|
||||
Gdi::Window::updateAll();
|
||||
}
|
||||
|
||||
void removeDropShadow(HWND hwnd)
|
||||
@ -260,12 +213,6 @@ namespace
|
||||
SetClassLongPtr(hwnd, GCL_STYLE, style ^ CS_DROPSHADOW);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CALLBACK updateWindowData(HWND hwnd, LPARAM /*lParam*/)
|
||||
{
|
||||
g_windowData[hwnd] = getWindowData(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
@ -278,6 +225,8 @@ namespace Gdi
|
||||
g_callWndRetProcHook = SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
|
||||
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
|
||||
nullptr, &objectStateChangeEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
||||
|
||||
EnumThreadWindows(threadId, initTopLevelWindow, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ULONG queryDisplaySettingsUniqueness()
|
||||
{
|
||||
static auto ddQueryDisplaySettingsUniqueness = reinterpret_cast<ULONG(APIENTRY*)()>(
|
||||
GetProcAddress(GetModuleHandle("gdi32"), "GdiEntry13"));
|
||||
return ddQueryDisplaySettingsUniqueness();
|
||||
}
|
||||
|
||||
void setDDrawBpp(DWORD bpp)
|
||||
{
|
||||
g_ddrawBpp = bpp;
|
||||
|
@ -13,6 +13,7 @@ namespace Win32
|
||||
const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage);
|
||||
HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight);
|
||||
|
||||
ULONG queryDisplaySettingsUniqueness();
|
||||
void setDDrawBpp(DWORD bpp);
|
||||
|
||||
void disableDwm8And16BitMitigation();
|
||||
|
Loading…
x
Reference in New Issue
Block a user