1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Fixed a race condition for updating invalidated window regions

See issue #306.
This commit is contained in:
narzoul 2024-05-09 13:02:45 +02:00
parent 0f63ebef9f
commit f7ea662c47
3 changed files with 15 additions and 41 deletions

View File

@ -147,7 +147,8 @@ namespace
case WM_SYNCPAINT:
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::onSyncPaint(hwnd);
RECT emptyRect = {};
RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW);
return 0;
}
break;

View File

@ -95,6 +95,7 @@ namespace
Gdi::Region obscuredRegion;
Gdi::Region invalidatedRegion;
Gdi::Region virtualScreenRegion;
std::vector<HWND> invalidatedWindows;
DWORD processId;
};
@ -105,7 +106,6 @@ namespace
RECT windowRect;
RECT clientRect;
Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion;
LayeredWindowContent layeredWindowContent;
bool isMenu;
bool isLayered;
@ -171,7 +171,7 @@ namespace
return g_windows.erase(it);
}
void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
bool updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
const Gdi::Region& oldVisibleRegion, Gdi::Region& invalidatedRegion)
{
LOG_FUNC("Window::updatePosition", window.hwnd, oldWindowRect, oldClientRect,
@ -250,11 +250,15 @@ namespace
}
}
window.invalidatedRegion = window.visibleRegion - preservedRegion;
if (!window.invalidatedRegion.isEmpty())
auto invalidatedWindowRegion = window.visibleRegion - preservedRegion;
if (!invalidatedWindowRegion.isEmpty())
{
window.invalidatedRegion.offset(-window.clientRect.left, -window.clientRect.top);
invalidatedWindowRegion.offset(-window.clientRect.left, -window.clientRect.top);
RedrawWindow(window.hwnd, nullptr, invalidatedWindowRegion,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
return true;
}
return false;
}
BOOL CALLBACK updateWindow(HWND hwnd, LPARAM lParam)
@ -345,9 +349,10 @@ namespace
if (!isLayered)
{
if (!it->second.visibleRegion.isEmpty())
if (!it->second.visibleRegion.isEmpty() &&
updatePosition(it->second, wi.rcWindow, wi.rcClient, visibleRegion, context.invalidatedRegion))
{
updatePosition(it->second, wi.rcWindow, wi.rcClient, visibleRegion, context.invalidatedRegion);
context.invalidatedWindows.push_back(hwnd);
}
if (exStyle & WS_EX_TRANSPARENT)
@ -525,27 +530,6 @@ namespace Gdi
}
}
void onSyncPaint(HWND hwnd)
{
LOG_FUNC("Window::onSyncPaint", hwnd);
{
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(hwnd);
if (it == g_windows.end())
{
return;
}
RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
it->second.invalidatedRegion.clear();
}
RECT emptyRect = {};
RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW);
}
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper)
{
@ -617,7 +601,6 @@ namespace Gdi
UpdateWindowContext context;
context.processId = GetCurrentProcessId();
context.virtualScreenRegion = VirtualScreen::getBounds();
std::vector<HWND> invalidatedWindows;
{
D3dDdi::ScopedCriticalSection lock;
@ -637,18 +620,9 @@ namespace Gdi
}
g_fullscreenWindow = findFullscreenWindow();
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{
auto& window = **it;
if (!window.invalidatedRegion.isEmpty())
{
invalidatedWindows.push_back(window.hwnd);
}
}
}
for (auto hwnd : invalidatedWindows)
for (auto hwnd : context.invalidatedWindows)
{
SendNotifyMessage(hwnd, WM_SYNCPAINT, 0, 0);
}

View File

@ -29,7 +29,6 @@ namespace Gdi
Gdi::Region getWindowRgn(HWND hwnd);
bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);