From 1ab496cbf5c76892bfeeb644c75d89a54f477a2d Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 21 Feb 2016 12:03:31 +0100 Subject: [PATCH] Minimize invalidation on window position changes --- DDrawCompat/CompatDirectDrawSurface.cpp | 2 +- DDrawCompat/CompatGdi.cpp | 29 +++++++++++++--- DDrawCompat/CompatGdi.h | 2 +- DDrawCompat/CompatGdiWinProc.cpp | 44 ++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/DDrawCompat/CompatDirectDrawSurface.cpp b/DDrawCompat/CompatDirectDrawSurface.cpp index eef827d..e5673fc 100644 --- a/DDrawCompat/CompatDirectDrawSurface.cpp +++ b/DDrawCompat/CompatDirectDrawSurface.cpp @@ -602,7 +602,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface::Restore(TSurface* T result = RealPrimarySurface::restore(); if (wasLost) { - CompatGdi::invalidate(); + CompatGdi::invalidate(nullptr); } } } diff --git a/DDrawCompat/CompatGdi.cpp b/DDrawCompat/CompatGdi.cpp index 52b2f04..3ce7018 100644 --- a/DDrawCompat/CompatGdi.cpp +++ b/DDrawCompat/CompatGdi.cpp @@ -58,14 +58,33 @@ namespace return nullptr; } - BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM /*lParam*/) + BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam) { + if (!IsWindowVisible(hwnd)) + { + return TRUE; + } + DWORD processId = 0; GetWindowThreadProcessId(hwnd, &processId); - if (processId == GetCurrentProcessId()) + if (processId != GetCurrentProcessId()) + { + return TRUE; + } + + if (lParam) + { + POINT origin = {}; + ClientToScreen(hwnd, &origin); + RECT rect = *reinterpret_cast(lParam); + OffsetRect(&rect, -origin.x, -origin.y); + RedrawWindow(hwnd, &rect, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + else { RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); } + return TRUE; } @@ -237,9 +256,9 @@ namespace CompatGdi } } - void invalidate() + void invalidate(const RECT* rect) { - EnumWindows(&invalidateWindow, 0); + EnumWindows(&invalidateWindow, reinterpret_cast(rect)); } void updatePalette() @@ -257,7 +276,7 @@ namespace CompatGdi if (0 != memcmp(usedPaletteEntries, g_usedPaletteEntries, sizeof(usedPaletteEntries))) { - invalidate(); + invalidate(nullptr); } } } diff --git a/DDrawCompat/CompatGdi.h b/DDrawCompat/CompatGdi.h index fd70667..32b53e0 100644 --- a/DDrawCompat/CompatGdi.h +++ b/DDrawCompat/CompatGdi.h @@ -45,6 +45,6 @@ namespace CompatGdi } void installHooks(); - void invalidate(); + void invalidate(const RECT* rect); void updatePalette(); }; diff --git a/DDrawCompat/CompatGdiWinProc.cpp b/DDrawCompat/CompatGdiWinProc.cpp index f6d2ae0..634b55b 100644 --- a/DDrawCompat/CompatGdiWinProc.cpp +++ b/DDrawCompat/CompatGdiWinProc.cpp @@ -1,5 +1,7 @@ #define WIN32_LEAN_AND_MEAN +#include + #include #include @@ -12,9 +14,13 @@ namespace { + std::unordered_map g_prevWindowRect; + void disableDwmAttributes(HWND hwnd); void eraseBackground(HWND hwnd, HDC dc); void ncPaint(HWND hwnd); + void onWindowPosChanged(HWND hwnd); + void removeDropShadow(HWND hwnd); void updateScrolledWindow(HWND hwnd); LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) @@ -25,6 +31,12 @@ namespace if (WM_CREATE == ret->message) { disableDwmAttributes(ret->hwnd); + removeDropShadow(ret->hwnd); + } + else if (WM_DESTROY == ret->message) + { + CompatGdi::GdiScopedThreadLock lock; + g_prevWindowRect.erase(ret->hwnd); } else if (WM_ERASEBKGND == ret->message) { @@ -42,7 +54,7 @@ namespace } else if (WM_WINDOWPOSCHANGED == ret->message) { - CompatGdi::invalidate(); + onWindowPosChanged(ret->hwnd); } else if (WM_VSCROLL == ret->message || WM_HSCROLL == ret->message) { @@ -201,6 +213,36 @@ namespace } } + void onWindowPosChanged(HWND hwnd) + { + CompatGdi::GdiScopedThreadLock lock; + + const auto it = g_prevWindowRect.find(hwnd); + if (it != g_prevWindowRect.end()) + { + CompatGdi::invalidate(&it->second); + } + + if (IsWindowVisible(hwnd)) + { + GetWindowRect(hwnd, it != g_prevWindowRect.end() ? &it->second : &g_prevWindowRect[hwnd]); + RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + else if (it != g_prevWindowRect.end()) + { + g_prevWindowRect.erase(it); + } + } + + void removeDropShadow(HWND hwnd) + { + const auto style = GetClassLongPtr(hwnd, GCL_STYLE); + if (style & CS_DROPSHADOW) + { + SetClassLongPtr(hwnd, GCL_STYLE, style ^ CS_DROPSHADOW); + } + } + void updateScrolledWindow(HWND hwnd) { RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE);