mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed invalidation of resized windows
This commit is contained in:
parent
453dc4d681
commit
a0919dcaa6
@ -68,6 +68,11 @@ namespace Gdi
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Region::clear()
|
||||||
|
{
|
||||||
|
SetRectRgn(m_region, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool Region::isEmpty() const
|
bool Region::isEmpty() const
|
||||||
{
|
{
|
||||||
return sizeof(RGNDATAHEADER) == GetRegionData(m_region, 0, nullptr);
|
return sizeof(RGNDATAHEADER) == GetRegionData(m_region, 0, nullptr);
|
||||||
|
@ -18,6 +18,7 @@ namespace Gdi
|
|||||||
Region(Region&& other);
|
Region(Region&& other);
|
||||||
Region& operator=(Region other);
|
Region& operator=(Region other);
|
||||||
|
|
||||||
|
void clear();
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
void offset(int x, int y);
|
void offset(int x, int y);
|
||||||
HRGN release();
|
HRGN release();
|
||||||
|
@ -27,23 +27,25 @@ namespace
|
|||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
HWND presentationWindow;
|
HWND presentationWindow;
|
||||||
RECT windowRect;
|
RECT windowRect;
|
||||||
|
RECT clientRect;
|
||||||
Gdi::Region windowRegion;
|
Gdi::Region windowRegion;
|
||||||
Gdi::Region visibleRegion;
|
Gdi::Region visibleRegion;
|
||||||
Gdi::Region invalidatedRegion;
|
Gdi::Region invalidatedRegion;
|
||||||
COLORREF colorKey;
|
COLORREF colorKey;
|
||||||
BYTE alpha;
|
BYTE alpha;
|
||||||
bool isLayered;
|
bool isLayered;
|
||||||
bool isRgnChangePending;
|
bool isVisibleRegionChanged;
|
||||||
|
|
||||||
Window(HWND hwnd)
|
Window(HWND hwnd)
|
||||||
: hwnd(hwnd)
|
: hwnd(hwnd)
|
||||||
, presentationWindow(nullptr)
|
, presentationWindow(nullptr)
|
||||||
, windowRect{}
|
, windowRect{}
|
||||||
|
, clientRect{}
|
||||||
, windowRegion(nullptr)
|
, windowRegion(nullptr)
|
||||||
, colorKey(CLR_INVALID)
|
, colorKey(CLR_INVALID)
|
||||||
, alpha(255)
|
, alpha(255)
|
||||||
, isLayered(true)
|
, isLayered(true)
|
||||||
, isRgnChangePending(false)
|
, isVisibleRegionChanged(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -67,15 +69,29 @@ namespace
|
|||||||
BOOL disableTransitions = TRUE;
|
BOOL disableTransitions = TRUE;
|
||||||
DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disableTransitions, sizeof(disableTransitions));
|
DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disableTransitions, sizeof(disableTransitions));
|
||||||
|
|
||||||
const auto style = GetClassLongPtr(hwnd, GCL_STYLE);
|
const auto style = GetClassLong(hwnd, GCL_STYLE);
|
||||||
if (style & CS_DROPSHADOW)
|
if (style & CS_DROPSHADOW)
|
||||||
{
|
{
|
||||||
SetClassLongPtr(hwnd, GCL_STYLE, style & ~CS_DROPSHADOW);
|
CALL_ORIG_FUNC(SetClassLongA)(hwnd, GCL_STYLE, style & ~CS_DROPSHADOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_windows.emplace(hwnd, Window(hwnd)).first;
|
return g_windows.emplace(hwnd, Window(hwnd)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bltWindow(const RECT& dst, const RECT& src, const Gdi::Region& clipRegion)
|
||||||
|
{
|
||||||
|
if (dst.left == src.left && dst.top == src.top || clipRegion.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC screenDc = GetDC(nullptr);
|
||||||
|
SelectClipRgn(screenDc, clipRegion);
|
||||||
|
BitBlt(screenDc, dst.left, dst.top, src.right - src.left, src.bottom - src.top, screenDc, src.left, src.top, SRCCOPY);
|
||||||
|
SelectClipRgn(screenDc, nullptr);
|
||||||
|
CALL_ORIG_FUNC(ReleaseDC)(nullptr, screenDc);
|
||||||
|
}
|
||||||
|
|
||||||
Gdi::Region getWindowRegion(HWND hwnd)
|
Gdi::Region getWindowRegion(HWND hwnd)
|
||||||
{
|
{
|
||||||
Gdi::Region rgn;
|
Gdi::Region rgn;
|
||||||
@ -187,36 +203,81 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePosition(Window& window, const RECT& oldWindowRect, const Gdi::Region& oldVisibleRegion)
|
void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
|
||||||
|
const Gdi::Region& oldVisibleRegion)
|
||||||
{
|
{
|
||||||
Gdi::Region preservedRegion(oldVisibleRegion);
|
const bool isClientOriginChanged =
|
||||||
preservedRegion.offset(window.windowRect.left - oldWindowRect.left, window.windowRect.top - oldWindowRect.top);
|
window.clientRect.left - window.windowRect.left != oldClientRect.left - oldWindowRect.left ||
|
||||||
preservedRegion &= window.visibleRegion;
|
window.clientRect.top - window.windowRect.top != oldClientRect.top - oldWindowRect.top;
|
||||||
|
const bool isClientWidthChanged =
|
||||||
|
window.clientRect.right - window.clientRect.left != oldClientRect.right - oldClientRect.left;
|
||||||
|
const bool isClientHeightChanged =
|
||||||
|
window.clientRect.bottom - window.clientRect.top != oldClientRect.bottom - oldClientRect.top;
|
||||||
|
const bool isClientInvalidated =
|
||||||
|
isClientWidthChanged && (GetClassLong(window.hwnd, GCL_STYLE) & CS_HREDRAW) ||
|
||||||
|
isClientHeightChanged && (GetClassLong(window.hwnd, GCL_STYLE) & CS_VREDRAW);
|
||||||
|
const bool isFrameInvalidated = isClientOriginChanged || isClientWidthChanged || isClientHeightChanged ||
|
||||||
|
window.windowRect.right - window.windowRect.left != oldWindowRect.right - oldWindowRect.left ||
|
||||||
|
window.windowRect.bottom - window.windowRect.top != oldWindowRect.bottom - oldWindowRect.top;
|
||||||
|
|
||||||
POINT clientPos = {};
|
Gdi::Region preservedRegion;
|
||||||
ClientToScreen(window.hwnd, &clientPos);
|
if (!isClientInvalidated || !isFrameInvalidated)
|
||||||
if (!preservedRegion.isEmpty())
|
|
||||||
{
|
{
|
||||||
Gdi::Region updateRegion;
|
preservedRegion = oldVisibleRegion;
|
||||||
GetUpdateRgn(window.hwnd, updateRegion, FALSE);
|
preservedRegion.offset(window.windowRect.left - oldWindowRect.left, window.windowRect.top - oldWindowRect.top);
|
||||||
OffsetRgn(updateRegion, clientPos.x, clientPos.y);
|
preservedRegion &= window.visibleRegion;
|
||||||
preservedRegion -= updateRegion;
|
|
||||||
|
|
||||||
if (!preservedRegion.isEmpty() &&
|
if (isClientInvalidated)
|
||||||
(window.windowRect.left != oldWindowRect.left || window.windowRect.top != oldWindowRect.top))
|
|
||||||
{
|
{
|
||||||
HDC screenDc = GetDC(nullptr);
|
preservedRegion -= window.clientRect;
|
||||||
SelectClipRgn(screenDc, preservedRegion);
|
}
|
||||||
BitBlt(screenDc, window.windowRect.left, window.windowRect.top,
|
else
|
||||||
oldWindowRect.right - oldWindowRect.left, oldWindowRect.bottom - oldWindowRect.top,
|
{
|
||||||
screenDc, oldWindowRect.left, oldWindowRect.top, SRCCOPY);
|
if (isFrameInvalidated)
|
||||||
SelectClipRgn(screenDc, nullptr);
|
{
|
||||||
CALL_ORIG_FUNC(ReleaseDC)(nullptr, screenDc);
|
preservedRegion &= window.clientRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClientWidthChanged)
|
||||||
|
{
|
||||||
|
RECT r = window.clientRect;
|
||||||
|
r.left += oldClientRect.right - oldClientRect.left;
|
||||||
|
if (r.left < r.right)
|
||||||
|
{
|
||||||
|
preservedRegion -= r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isClientHeightChanged)
|
||||||
|
{
|
||||||
|
RECT r = window.clientRect;
|
||||||
|
r.top += oldClientRect.bottom - oldClientRect.top;
|
||||||
|
if (r.top < r.bottom)
|
||||||
|
{
|
||||||
|
preservedRegion -= r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gdi::Region updateRegion;
|
||||||
|
GetUpdateRgn(window.hwnd, updateRegion, FALSE);
|
||||||
|
updateRegion.offset(window.clientRect.left, window.clientRect.top);
|
||||||
|
preservedRegion -= updateRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFrameInvalidated)
|
||||||
|
{
|
||||||
|
bltWindow(window.windowRect, oldWindowRect, preservedRegion);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bltWindow(window.clientRect, oldClientRect, preservedRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.invalidatedRegion = window.visibleRegion - preservedRegion;
|
window.invalidatedRegion = window.visibleRegion - preservedRegion;
|
||||||
OffsetRgn(window.invalidatedRegion, -clientPos.x, -clientPos.y);
|
if (!window.invalidatedRegion.isEmpty())
|
||||||
|
{
|
||||||
|
window.invalidatedRegion.offset(-window.clientRect.left, -window.clientRect.top);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK updateWindow(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK updateWindow(HWND hwnd, LPARAM lParam)
|
||||||
@ -246,7 +307,7 @@ namespace
|
|||||||
if (isLayered != it->second.isLayered)
|
if (isLayered != it->second.isLayered)
|
||||||
{
|
{
|
||||||
it->second.isLayered = isLayered;
|
it->second.isLayered = isLayered;
|
||||||
it->second.isRgnChangePending = isVisible;
|
it->second.isVisibleRegionChanged = isVisible;
|
||||||
if (!isLayered)
|
if (!isLayered)
|
||||||
{
|
{
|
||||||
it->second.presentationWindow = reinterpret_cast<HWND>(
|
it->second.presentationWindow = reinterpret_cast<HWND>(
|
||||||
@ -268,22 +329,23 @@ namespace
|
|||||||
setPresentationWindowRgn = true;
|
setPresentationWindowRgn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT windowRect = {};
|
WINDOWINFO wi = {};
|
||||||
Gdi::Region visibleRegion;
|
Gdi::Region visibleRegion;
|
||||||
|
|
||||||
if (isVisible)
|
if (isVisible)
|
||||||
{
|
{
|
||||||
GetWindowRect(hwnd, &windowRect);
|
wi.cbSize = sizeof(wi);
|
||||||
if (!IsRectEmpty(&windowRect))
|
GetWindowInfo(hwnd, &wi);
|
||||||
|
if (!IsRectEmpty(&wi.rcWindow))
|
||||||
{
|
{
|
||||||
if (it->second.windowRegion)
|
if (it->second.windowRegion)
|
||||||
{
|
{
|
||||||
visibleRegion = it->second.windowRegion;
|
visibleRegion = it->second.windowRegion;
|
||||||
OffsetRgn(visibleRegion, windowRect.left, windowRect.top);
|
visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
visibleRegion = windowRect;
|
visibleRegion = wi.rcWindow;
|
||||||
}
|
}
|
||||||
visibleRegion &= context.virtualScreenRegion;
|
visibleRegion &= context.virtualScreenRegion;
|
||||||
visibleRegion -= context.obscuredRegion;
|
visibleRegion -= context.obscuredRegion;
|
||||||
@ -295,22 +357,24 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(it->second.windowRect, windowRect);
|
std::swap(it->second.windowRect, wi.rcWindow);
|
||||||
|
std::swap(it->second.clientRect, wi.rcClient);
|
||||||
swap(it->second.visibleRegion, visibleRegion);
|
swap(it->second.visibleRegion, visibleRegion);
|
||||||
|
|
||||||
if (!isLayered)
|
if (!isLayered)
|
||||||
{
|
{
|
||||||
if (!it->second.visibleRegion.isEmpty())
|
if (!it->second.visibleRegion.isEmpty())
|
||||||
{
|
{
|
||||||
updatePosition(it->second, windowRect, visibleRegion);
|
updatePosition(it->second, wi.rcWindow, wi.rcClient, visibleRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVisible && !it->second.isRgnChangePending)
|
if (isVisible && !it->second.isVisibleRegionChanged)
|
||||||
{
|
{
|
||||||
OffsetRgn(visibleRegion, it->second.windowRect.left - windowRect.left, it->second.windowRect.top - windowRect.top);
|
visibleRegion.offset(it->second.windowRect.left - wi.rcWindow.left, it->second.windowRect.top - wi.rcWindow.top);
|
||||||
|
|
||||||
if (it->second.visibleRegion != visibleRegion)
|
if (it->second.visibleRegion != visibleRegion)
|
||||||
{
|
{
|
||||||
it->second.isRgnChangePending = true;
|
it->second.isVisibleRegionChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,9 +483,9 @@ namespace Gdi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->second.isRgnChangePending)
|
if (it->second.isVisibleRegionChanged)
|
||||||
{
|
{
|
||||||
it->second.isRgnChangePending = false;
|
it->second.isVisibleRegionChanged = false;
|
||||||
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
|
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
|
||||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(CALL_ORIG_FUNC(DefWindowProcA)));
|
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(CALL_ORIG_FUNC(DefWindowProcA)));
|
||||||
if (it->second.isLayered)
|
if (it->second.isLayered)
|
||||||
@ -431,7 +495,7 @@ namespace Gdi
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Gdi::Region rgn(it->second.visibleRegion);
|
Gdi::Region rgn(it->second.visibleRegion);
|
||||||
OffsetRgn(rgn, -it->second.windowRect.left, -it->second.windowRect.top);
|
rgn.offset(-it->second.windowRect.left, -it->second.windowRect.top);
|
||||||
rgn |= REGION_OVERRIDE_MARKER_RECT;
|
rgn |= REGION_OVERRIDE_MARKER_RECT;
|
||||||
SetWindowRgn(hwnd, rgn, FALSE);
|
SetWindowRgn(hwnd, rgn, FALSE);
|
||||||
}
|
}
|
||||||
@ -604,7 +668,7 @@ namespace Gdi
|
|||||||
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
|
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
|
||||||
{
|
{
|
||||||
auto& window = **it;
|
auto& window = **it;
|
||||||
if (window.isRgnChangePending || !window.invalidatedRegion.isEmpty())
|
if (window.isVisibleRegionChanged || !window.invalidatedRegion.isEmpty())
|
||||||
{
|
{
|
||||||
invalidatedWindows.push_back(window.hwnd);
|
invalidatedWindows.push_back(window.hwnd);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user