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

Fixed scroll bar control painting and thumb tracking

This commit is contained in:
narzoul 2021-02-13 12:03:00 +01:00
parent 27ae9affb8
commit 205f517845
23 changed files with 493 additions and 496 deletions

View File

@ -187,18 +187,6 @@ namespace D3dDdi
{ {
} }
void Resource::beginGdiAccess(bool isReadOnly)
{
if (m_lockResource)
{
if (!m_lockData[0].isSysMemUpToDate)
{
copyToSysMem(0);
}
m_lockData[0].isVidMemUpToDate &= isReadOnly;
}
}
HRESULT Resource::blt(D3DDDIARG_BLT data) HRESULT Resource::blt(D3DDDIARG_BLT data)
{ {
if (!isValidRect(data.DstSubResourceIndex, data.DstRect)) if (!isValidRect(data.DstSubResourceIndex, data.DstRect))
@ -471,14 +459,6 @@ namespace D3dDdi
#endif #endif
} }
void Resource::endGdiAccess(bool isReadOnly)
{
if (m_lockResource && !isReadOnly && m_lockData[0].isSysMemUpToDate)
{
m_lockData[0].isVidMemUpToDate = false;
}
}
void* Resource::getLockPtr(UINT subResourceIndex) void* Resource::getLockPtr(UINT subResourceIndex)
{ {
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data; return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
@ -517,6 +497,21 @@ namespace D3dDdi
return m_device.getOrigVtable().pfnLock(m_device, &data); return m_device.getOrigVtable().pfnLock(m_device, &data);
} }
void Resource::prepareForGdiRendering(bool isReadOnly)
{
if (!m_lockResource)
{
return;
}
if (!m_lockData[0].isSysMemUpToDate)
{
copyToSysMem(0);
}
m_lockData[0].isVidMemUpToDate &= isReadOnly;
m_lockData[0].qpcLastForcedLock = Time::queryPerformanceCounter();
}
void Resource::prepareForRendering(UINT subResourceIndex, bool isReadOnly) void Resource::prepareForRendering(UINT subResourceIndex, bool isReadOnly)
{ {
if (m_lockResource && 0 == m_lockData[subResourceIndex].lockCount) if (m_lockResource && 0 == m_lockData[subResourceIndex].lockCount)

View File

@ -26,12 +26,11 @@ namespace D3dDdi
operator HANDLE() const { return m_handle; } operator HANDLE() const { return m_handle; }
void beginGdiAccess(bool isReadOnly);
HRESULT blt(D3DDDIARG_BLT data); HRESULT blt(D3DDDIARG_BLT data);
HRESULT colorFill(D3DDDIARG_COLORFILL data); HRESULT colorFill(D3DDDIARG_COLORFILL data);
void endGdiAccess(bool isReadOnly);
void* getLockPtr(UINT subResourceIndex); void* getLockPtr(UINT subResourceIndex);
HRESULT lock(D3DDDIARG_LOCK& data); HRESULT lock(D3DDDIARG_LOCK& data);
void prepareForGdiRendering(bool isReadOnly);
void prepareForRendering(UINT subResourceIndex, bool isReadOnly); void prepareForRendering(UINT subResourceIndex, bool isReadOnly);
void setAsGdiResource(bool isGdiResource); void setAsGdiResource(bool isGdiResource);
HRESULT unlock(const D3DDDIARG_UNLOCK& data); HRESULT unlock(const D3DDDIARG_UNLOCK& data);

View File

@ -1,11 +1,10 @@
#include <cstring> #include <cstring>
#include <deque> #include <deque>
#include "Common/Time.h" #include <Common/Time.h>
#include "Config/Config.h" #include <Config/Config.h>
#include "DDraw/DirectDrawPalette.h" #include <DDraw/DirectDrawPalette.h>
#include "DDraw/Surfaces/PrimarySurface.h" #include <DDraw/Surfaces/PrimarySurface.h>
#include "Gdi/AccessGuard.h"
namespace DDraw namespace DDraw
{ {

View File

@ -15,7 +15,6 @@
#include <DDraw/ScopedThreadLock.h> #include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h> #include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Types.h> #include <DDraw/Types.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/Caret.h> #include <Gdi/Caret.h>
#include <Gdi/Gdi.h> #include <Gdi/Gdi.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>

View File

@ -213,7 +213,7 @@
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" /> <ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" /> <ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
<ClInclude Include="Dll\Dll.h" /> <ClInclude Include="Dll\Dll.h" />
<ClInclude Include="Gdi\AccessGuard.h" /> <ClInclude Include="Gdi\CompatDc.h" />
<ClInclude Include="Gdi\Font.h" /> <ClInclude Include="Gdi\Font.h" />
<ClInclude Include="Gdi\Gdi.h" /> <ClInclude Include="Gdi\Gdi.h" />
<ClInclude Include="Gdi\Caret.h" /> <ClInclude Include="Gdi\Caret.h" />
@ -287,7 +287,7 @@
<ClCompile Include="Direct3d\Log.cpp" /> <ClCompile Include="Direct3d\Log.cpp" />
<ClCompile Include="Dll\DllMain.cpp" /> <ClCompile Include="Dll\DllMain.cpp" />
<ClCompile Include="Dll\Dll.cpp" /> <ClCompile Include="Dll\Dll.cpp" />
<ClCompile Include="Gdi\AccessGuard.cpp" /> <ClCompile Include="Gdi\CompatDc.cpp" />
<ClCompile Include="Gdi\Font.cpp" /> <ClCompile Include="Gdi\Font.cpp" />
<ClCompile Include="Gdi\Gdi.cpp" /> <ClCompile Include="Gdi\Gdi.cpp" />
<ClCompile Include="Gdi\Caret.cpp" /> <ClCompile Include="Gdi\Caret.cpp" />

View File

@ -297,9 +297,6 @@
<ClInclude Include="Gdi\VirtualScreen.h"> <ClInclude Include="Gdi\VirtualScreen.h">
<Filter>Header Files\Gdi</Filter> <Filter>Header Files\Gdi</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Gdi\AccessGuard.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\Palette.h"> <ClInclude Include="Gdi\Palette.h">
<Filter>Header Files\Gdi</Filter> <Filter>Header Files\Gdi</Filter>
</ClInclude> </ClInclude>
@ -402,6 +399,9 @@
<ClInclude Include="Gdi\Metrics.h"> <ClInclude Include="Gdi\Metrics.h">
<Filter>Header Files\Gdi</Filter> <Filter>Header Files\Gdi</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Gdi\CompatDc.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp"> <ClCompile Include="Gdi\Gdi.cpp">
@ -545,9 +545,6 @@
<ClCompile Include="Gdi\VirtualScreen.cpp"> <ClCompile Include="Gdi\VirtualScreen.cpp">
<Filter>Source Files\Gdi</Filter> <Filter>Source Files\Gdi</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Gdi\AccessGuard.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\Palette.cpp"> <ClCompile Include="Gdi\Palette.cpp">
<Filter>Source Files\Gdi</Filter> <Filter>Source Files\Gdi</Filter>
</ClCompile> </ClCompile>
@ -620,5 +617,8 @@
<ClCompile Include="Gdi\Metrics.cpp"> <ClCompile Include="Gdi\Metrics.cpp">
<Filter>Source Files\Gdi</Filter> <Filter>Source Files\Gdi</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Gdi\CompatDc.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,41 +0,0 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/Resource.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/AccessGuard.h"
namespace Gdi
{
AccessGuard::AccessGuard(Access access, bool condition)
: m_access(access)
, m_condition(condition)
{
if (m_condition)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->beginGdiAccess(ACCESS_READ == m_access);
}
}
}
AccessGuard::~AccessGuard()
{
if (m_condition)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->endGdiAccess(ACCESS_READ == m_access);
}
if (ACCESS_WRITE == m_access &&
(!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
}
}
}

View File

@ -1,21 +0,0 @@
#pragma once
namespace Gdi
{
enum Access
{
ACCESS_READ,
ACCESS_WRITE
};
class AccessGuard
{
public:
AccessGuard(Access access, bool condition = true);
~AccessGuard();
private:
Access m_access;
bool m_condition;
};
}

View File

@ -0,0 +1,44 @@
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Dc.h>
namespace Gdi
{
CompatDc::CompatDc(HDC dc, bool isReadOnly)
: m_origDc(dc)
, m_compatDc(Gdi::Dc::getDc(dc))
, m_isReadOnly(isReadOnly)
{
if (m_compatDc)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->prepareForGdiRendering(isReadOnly);
}
}
else
{
m_compatDc = m_origDc;
}
}
CompatDc::~CompatDc()
{
if (m_compatDc != m_origDc)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (!m_isReadOnly && (!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
Gdi::Dc::releaseDc(m_origDc);
}
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Windows.h>
namespace Gdi
{
class CompatDc
{
public:
CompatDc(HDC dc, bool isReadOnly = false);
CompatDc(const CompatDc&) = delete;
CompatDc(CompatDc&& other) = delete;
CompatDc& operator=(const CompatDc&) = delete;
CompatDc& operator=(CompatDc&&) = delete;
~CompatDc();
operator HDC() const
{
return m_compatDc;
}
private:
HDC m_origDc;
HDC m_compatDc;
bool m_isReadOnly;
};
}

View File

@ -22,10 +22,6 @@ namespace
HDC origDc; HDC origDc;
DWORD threadId; DWORD threadId;
int savedState; int savedState;
HGDIOBJ savedFont;
HGDIOBJ savedBrush;
HGDIOBJ savedPen;
HPALETTE savedPalette;
bool useDefaultPalette; bool useDefaultPalette;
}; };
@ -38,11 +34,10 @@ namespace
void copyDcAttributes(CompatDc& compatDc, HDC origDc, const POINT& origin) void copyDcAttributes(CompatDc& compatDc, HDC origDc, const POINT& origin)
{ {
SelectObject(compatDc.dc, compatDc.savedFont = GetCurrentObject(origDc, OBJ_FONT)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
SelectObject(compatDc.dc, compatDc.savedBrush = GetCurrentObject(origDc, OBJ_BRUSH)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
SelectObject(compatDc.dc, compatDc.savedPen = GetCurrentObject(origDc, OBJ_PEN)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
CALL_ORIG_FUNC(SelectPalette)( CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
compatDc.dc, compatDc.savedPalette = static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
const int graphicsMode = GetGraphicsMode(origDc); const int graphicsMode = GetGraphicsMode(origDc);
SetGraphicsMode(compatDc.dc, graphicsMode); SetGraphicsMode(compatDc.dc, graphicsMode);
@ -98,20 +93,10 @@ namespace
void restoreDc(const CompatDc& compatDc) void restoreDc(const CompatDc& compatDc)
{ {
if (0 != compatDc.savedState) // Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one
{ HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP);
// Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one RestoreDC(compatDc.dc, compatDc.savedState);
HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP); SelectObject(compatDc.dc, bitmap);
RestoreDC(compatDc.dc, compatDc.savedState);
SelectObject(compatDc.dc, bitmap);
}
else
{
SelectObject(compatDc.dc, compatDc.savedFont);
SelectObject(compatDc.dc, compatDc.savedBrush);
SelectObject(compatDc.dc, compatDc.savedPen);
CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, compatDc.savedPalette, FALSE);
}
} }
void setClippingRegion(const CompatDc& compatDc, HWND hwnd, const POINT& origin, const RECT& virtualScreenBounds) void setClippingRegion(const CompatDc& compatDc, HWND hwnd, const POINT& origin, const RECT& virtualScreenBounds)
@ -135,10 +120,7 @@ namespace
ExtSelectClipRgn(compatDc.dc, clipRgn, RGN_AND); ExtSelectClipRgn(compatDc.dc, clipRgn, RGN_AND);
} }
if (0 != compatDc.savedState) SetMetaRgn(compatDc.dc);
{
SetMetaRgn(compatDc.dc);
}
} }
} }
@ -177,7 +159,7 @@ namespace Gdi
} }
} }
HDC getDc(HDC origDc, bool useMetaRgn) HDC getDc(HDC origDc)
{ {
if (!isDisplayDc(origDc)) if (!isDisplayDc(origDc))
{ {
@ -222,7 +204,7 @@ namespace Gdi
compatDc.refCount = 1; compatDc.refCount = 1;
compatDc.origDc = origDc; compatDc.origDc = origDc;
compatDc.threadId = GetCurrentThreadId(); compatDc.threadId = GetCurrentThreadId();
compatDc.savedState = useMetaRgn ? SaveDC(compatDc.dc) : 0; compatDc.savedState = SaveDC(compatDc.dc);
copyDcAttributes(compatDc, origDc, origin); copyDcAttributes(compatDc, origDc, origin);
setClippingRegion(compatDc, hwnd, origin, virtualScreenBounds); setClippingRegion(compatDc, hwnd, origin, virtualScreenBounds);

View File

@ -8,7 +8,7 @@ namespace Gdi
{ {
void dllProcessDetach(); void dllProcessDetach();
void dllThreadDetach(); void dllThreadDetach();
HDC getDc(HDC origDc, bool useMetaRgn = true); HDC getDc(HDC origDc);
HDC getOrigDc(HDC dc); HDC getOrigDc(HDC dc);
void releaseDc(HDC origDc); void releaseDc(HDC origDc);
} }

View File

@ -2,7 +2,7 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Gdi/AccessGuard.h> #include <Gdi/CompatDc.h>
#include <Gdi/Dc.h> #include <Gdi/Dc.h>
#include <Gdi/DcFunctions.h> #include <Gdi/DcFunctions.h>
#include <Gdi/Font.h> #include <Gdi/Font.h>
@ -14,39 +14,6 @@
namespace namespace
{ {
class CompatDc
{
public:
CompatDc(HDC dc) : m_origDc(dc), m_compatDc(Gdi::Dc::getDc(dc, false))
{
}
CompatDc(const CompatDc&) = delete;
CompatDc(CompatDc&& other) : m_origDc(nullptr), m_compatDc(nullptr)
{
std::swap(m_origDc, other.m_origDc);
std::swap(m_compatDc, other.m_compatDc);
}
~CompatDc()
{
if (m_compatDc)
{
Gdi::Dc::releaseDc(m_origDc);
}
}
operator HDC() const
{
return m_compatDc ? m_compatDc : m_origDc;
}
private:
HDC m_origDc;
HDC m_compatDc;
};
std::unordered_map<void*, const char*> g_funcNames; std::unordered_map<void*, const char*> g_funcNames;
thread_local bool g_redirectToDib = true; thread_local bool g_redirectToDib = true;
@ -123,9 +90,9 @@ namespace
return t; return t;
} }
CompatDc replaceDc(HDC dc) Gdi::CompatDc replaceDc(HDC dc)
{ {
return CompatDc(dc); return Gdi::CompatDc(dc);
} }
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params> template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
@ -137,9 +104,7 @@ namespace
if (hasDisplayDcArg(hdc, params...)) if (hasDisplayDcArg(hdc, params...))
{ {
D3dDdi::ScopedCriticalSection lock; Gdi::CompatDc compatDc(hdc, isReadOnly<OrigFuncPtr, origFunc>());
Gdi::AccessGuard accessGuard(isReadOnly<OrigFuncPtr, origFunc>() ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
CompatDc compatDc(hdc);
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(compatDc, replaceDc(params)...); Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(compatDc, replaceDc(params)...);
if (isPositionUpdated<OrigFuncPtr, origFunc>() && result) if (isPositionUpdated<OrigFuncPtr, origFunc>() && result)
{ {
@ -181,9 +146,7 @@ namespace
} }
else else
{ {
D3dDdi::ScopedCriticalSection lock; Gdi::CompatDc compatDc(hdc);
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CompatDc compatDc(hdc);
BOOL result = CALL_ORIG_FUNC(ExtTextOutW)(compatDc, x, y, options, lprect, lpString, c, lpDx); BOOL result = CALL_ORIG_FUNC(ExtTextOutW)(compatDc, x, y, options, lprect, lpString, c, lpDx);
if (result) if (result)
{ {
@ -255,9 +218,7 @@ namespace
LOG_FUNC("DrawCaption", hwnd, hdc, lprect, flags); LOG_FUNC("DrawCaption", hwnd, hdc, lprect, flags);
if (Gdi::isDisplayDc(hdc)) if (Gdi::isDisplayDc(hdc))
{ {
D3dDdi::ScopedCriticalSection lock; return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, Gdi::CompatDc(hdc), lprect, flags));
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, replaceDc(hdc), lprect, flags));
} }
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, hdc, lprect, flags)); return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, hdc, lprect, flags));
} }

View File

@ -1,177 +1,285 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Gdi/Gdi.h>
#include <Gdi/ScrollBar.h> #include <Gdi/ScrollBar.h>
namespace namespace
{ {
enum ScrollBarInfoIndex enum ScrollBarInfoIndex
{ {
SBII_SCROLLBAR = 0, SBII_SELF = 0,
SBII_TOP_RIGHT_ARROW = 1, SBII_TOP_ARROW = 1,
SBII_PAGEUP_PAGERIGHT_REGION = 2, SBII_PAGEUP_REGION = 2,
SBII_THUMB = 3, SBII_THUMB = 3,
SBII_PAGEDOWN_PAGELEFT_REGION = 4, SBII_PAGEDOWN_REGION = 4,
SBII_BOTTOM_LEFT_ARROW = 5 SBII_BOTTOM_ARROW = 5
}; };
bool isVertical(HWND hwnd, int bar)
{
if (SB_CTL == bar)
{
return CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE) & SBS_VERT;
}
return SB_VERT == bar;
}
thread_local Gdi::ScrollBar* g_trackedScrollBar = nullptr;
} }
namespace Gdi namespace Gdi
{ {
ScrollBar::ScrollBar(HWND hwnd, HDC compatDc) : ScrollBar::ScrollBar(HWND hwnd, int bar)
m_hwnd(hwnd), m_compatDc(compatDc), m_windowRect(), : m_hwnd(hwnd)
m_isLeftMouseButtonDown(false), m_cursorPos(), , m_bar(bar)
m_horizontalSbi(), m_verticalSbi() , m_windowRect{}
, m_sbi{}
, m_isVertical(isVertical(hwnd, bar))
, m_arrowSize(CALL_ORIG_FUNC(GetSystemMetrics)(m_isVertical ? SM_CYVSCROLL : SM_CXHSCROLL))
, m_left(m_isVertical ? &RECT::left : &RECT::top)
, m_top(m_isVertical ? &RECT::top : &RECT::left)
, m_right(m_isVertical ? &RECT::right : &RECT::bottom)
, m_bottom(m_isVertical ? &RECT::bottom : &RECT::right)
, m_trackedChildId(-1)
, m_trackedThumbOffset(0)
{ {
const LONG windowStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE); LONG objectId = OBJID_CLIENT;
if (SB_HORZ == bar)
m_horizontalSbi.isVisible = 0 != (windowStyle & WS_HSCROLL); {
m_verticalSbi.isVisible = 0 != (windowStyle & WS_VSCROLL); objectId = OBJID_HSCROLL;
}
else if (SB_VERT == bar)
{
objectId = OBJID_VSCROLL;
}
m_sbi.cbSize = sizeof(m_sbi);
GetScrollBarInfo(hwnd, objectId, &m_sbi);
GetWindowRect(hwnd, &m_windowRect); GetWindowRect(hwnd, &m_windowRect);
OffsetRect(&m_sbi.rcScrollBar, -m_windowRect.left, -m_windowRect.top);
if (m_horizontalSbi.isVisible || m_verticalSbi.isVisible) if (g_trackedScrollBar &&
hwnd == g_trackedScrollBar->m_hwnd &&
bar == g_trackedScrollBar->m_bar &&
GetKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0)
{ {
m_isLeftMouseButtonDown = DWORD pos = GetMessagePos();
hwnd == GetCapture() && POINTS pt = *reinterpret_cast<POINTS*>(&pos);
GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0 && POINT p = { pt.x - m_windowRect.left, pt.y - m_windowRect.top };
GetCursorPos(&m_cursorPos);
if (m_isLeftMouseButtonDown) if (SBII_THUMB == g_trackedScrollBar->m_trackedChildId)
{ {
m_cursorPos.x -= m_windowRect.left; RECT trackRect = m_sbi.rcScrollBar;
m_cursorPos.y -= m_windowRect.top; if (m_isVertical)
{
InflateRect(&trackRect, 8 * (trackRect.right - trackRect.left), 2 * m_arrowSize);
}
else
{
InflateRect(&trackRect, 2 * m_arrowSize, 8 * (trackRect.bottom - trackRect.top));
}
if (PtInRect(&trackRect, p))
{
const LONG thumbSize = m_sbi.xyThumbBottom - m_sbi.xyThumbTop;
const LONG minThumbPos = m_arrowSize;
const LONG maxThumbPos = m_sbi.rcScrollBar.*m_bottom - m_sbi.rcScrollBar.*m_top - thumbSize - m_arrowSize;
LONG thumbPos = (m_isVertical ? p.y : p.x) - m_sbi.rcScrollBar.*m_top -
g_trackedScrollBar->m_trackedThumbOffset;
if (thumbPos < minThumbPos)
{
thumbPos = minThumbPos;
}
if (thumbPos > maxThumbPos)
{
thumbPos = maxThumbPos;
}
m_sbi.xyThumbTop = thumbPos;
m_sbi.xyThumbBottom = thumbPos + thumbSize;
}
} }
else
if (m_horizontalSbi.isVisible)
{ {
m_horizontalSbi = getScrollBarInfo(OBJID_HSCROLL); RECT rect = getChildRect(g_trackedScrollBar->m_trackedChildId);
} if (PtInRect(&rect, p))
{
if (m_verticalSbi.isVisible) m_sbi.rgstate[g_trackedScrollBar->m_trackedChildId] |= STATE_SYSTEM_PRESSED;
{ }
m_verticalSbi = getScrollBarInfo(OBJID_VSCROLL);
} }
} }
} }
void ScrollBar::drawAll() const ScrollBar::~ScrollBar()
{ {
drawHorizArrows(); if (this == g_trackedScrollBar)
drawVertArrows();
}
void ScrollBar::drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const
{
UINT stateFlags = 0;
if (sbci.state & STATE_SYSTEM_UNAVAILABLE)
{ {
stateFlags |= DFCS_INACTIVE; g_trackedScrollBar = nullptr;
}
else if (sbci.state & STATE_SYSTEM_PRESSED)
{
stateFlags |= DFCS_PUSHED;
}
RECT rect = sbci.rect;
CALL_ORIG_FUNC(DrawFrameControl)(m_compatDc, &rect, DFC_SCROLL, dfcState | stateFlags);
}
void ScrollBar::drawHorizArrows() const
{
if (m_horizontalSbi.isVisible)
{
drawArrow(m_horizontalSbi.topLeftArrow, DFCS_SCROLLLEFT);
drawArrow(m_horizontalSbi.bottomRightArrow, DFCS_SCROLLRIGHT);
} }
} }
void ScrollBar::drawVertArrows() const void ScrollBar::drawAll(HDC dc, HBRUSH brush)
{ {
if (m_verticalSbi.isVisible) if (isVisible())
{ {
drawArrow(m_verticalSbi.topLeftArrow, DFCS_SCROLLUP); drawArrow(dc, SBII_TOP_ARROW);
drawArrow(m_verticalSbi.bottomRightArrow, DFCS_SCROLLDOWN); drawPageRegion(dc, brush, SBII_PAGEUP_REGION);
drawThumb(dc, brush);
drawPageRegion(dc, brush, SBII_PAGEDOWN_REGION);
drawArrow(dc, SBII_BOTTOM_ARROW);
} }
} }
void ScrollBar::excludeFromClipRegion(const RECT& rect) const void ScrollBar::drawArrow(HDC dc, LONG childId)
{ {
ExcludeClipRect(m_compatDc, rect.left, rect.top, rect.right, rect.bottom); UINT state = 0;
} if (SBII_TOP_ARROW == childId)
void ScrollBar::excludeFromClipRegion(const ScrollBarInfo& sbi) const
{
if (sbi.isVisible)
{ {
excludeFromClipRegion(sbi.topLeftArrow.rect); state = m_isVertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT;
excludeFromClipRegion(sbi.bottomRightArrow.rect);
}
}
void ScrollBar::excludeFromClipRegion() const
{
excludeFromClipRegion(m_horizontalSbi);
excludeFromClipRegion(m_verticalSbi);
}
ScrollBar::ScrollBarInfo ScrollBar::getScrollBarInfo(LONG objId) const
{
ScrollBarInfo scrollBarInfo = {};
SCROLLBARINFO sbi = {};
sbi.cbSize = sizeof(sbi);
scrollBarInfo.isVisible = GetScrollBarInfo(m_hwnd, objId, &sbi) &&
!(sbi.rgstate[SBII_SCROLLBAR] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN));
if (!scrollBarInfo.isVisible)
{
return scrollBarInfo;
}
OffsetRect(&sbi.rcScrollBar, -m_windowRect.left, -m_windowRect.top);
scrollBarInfo.topLeftArrow.rect = sbi.rcScrollBar;
scrollBarInfo.bottomRightArrow.rect = sbi.rcScrollBar;
scrollBarInfo.shaftRect = sbi.rcScrollBar;
if (OBJID_HSCROLL == objId)
{
const int w = GetSystemMetrics(SM_CXHSCROLL);
scrollBarInfo.topLeftArrow.rect.right = scrollBarInfo.topLeftArrow.rect.left + w;
scrollBarInfo.topLeftArrow.state = sbi.rgstate[SBII_BOTTOM_LEFT_ARROW];
scrollBarInfo.bottomRightArrow.rect.left = scrollBarInfo.bottomRightArrow.rect.right - w;
scrollBarInfo.bottomRightArrow.state = sbi.rgstate[SBII_TOP_RIGHT_ARROW];
InflateRect(&scrollBarInfo.shaftRect, -w, 0);
} }
else else
{ {
const int h = GetSystemMetrics(SM_CYVSCROLL); state = m_isVertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT;
scrollBarInfo.topLeftArrow.rect.bottom = scrollBarInfo.topLeftArrow.rect.top + h;
scrollBarInfo.topLeftArrow.state = sbi.rgstate[SBII_TOP_RIGHT_ARROW];
scrollBarInfo.bottomRightArrow.rect.top = scrollBarInfo.bottomRightArrow.rect.bottom - h;
scrollBarInfo.bottomRightArrow.state = sbi.rgstate[SBII_BOTTOM_LEFT_ARROW];
InflateRect(&scrollBarInfo.shaftRect, 0, -h);
} }
if (m_isLeftMouseButtonDown) if (m_sbi.rgstate[childId] & STATE_SYSTEM_UNAVAILABLE)
{ {
setPressedState(scrollBarInfo.topLeftArrow); state |= DFCS_INACTIVE;
setPressedState(scrollBarInfo.bottomRightArrow); }
else if (m_sbi.rgstate[childId] & STATE_SYSTEM_PRESSED)
{
state |= DFCS_PUSHED;
} }
return scrollBarInfo; RECT rect = getChildRect(childId);
DrawFrameControl(dc, &rect, DFC_SCROLL, state);
} }
void ScrollBar::setPressedState(ScrollBarChildInfo& sbci) const void ScrollBar::drawPageRegion(HDC dc, HBRUSH brush, LONG childId)
{ {
if (!(sbci.state & STATE_SYSTEM_UNAVAILABLE) && PtInRect(&sbci.rect, m_cursorPos)) RECT rect = getChildRect(childId);
if (IsRectEmpty(&rect))
{ {
sbci.state |= STATE_SYSTEM_PRESSED; return;
}
FillRect(dc, &rect, brush);
if (SB_CTL == m_bar)
{
const UINT edges = m_isVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM);
DrawEdge(dc, &rect, BDR_SUNKEN, edges | BF_FLAT);
}
if (m_sbi.rgstate[childId] & STATE_SYSTEM_PRESSED)
{
InvertRect(dc, &rect);
}
}
void ScrollBar::drawThumb(HDC dc, HBRUSH brush)
{
if (m_sbi.rgstate[SBII_SELF] & STATE_SYSTEM_UNAVAILABLE)
{
drawPageRegion(dc, brush, SBII_THUMB);
}
else
{
RECT rect = m_sbi.rcScrollBar;
rect.*m_top += m_sbi.xyThumbTop;
rect.*m_bottom = m_sbi.rcScrollBar.*m_top + m_sbi.xyThumbBottom;
DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
}
}
RECT ScrollBar::getChildRect(LONG childId)
{
RECT r = m_sbi.rcScrollBar;
switch (childId)
{
case SBII_TOP_ARROW:
r.*m_bottom = r.*m_top + m_arrowSize;
break;
case SBII_PAGEUP_REGION:
r.*m_bottom = r.*m_top + m_sbi.xyThumbTop;
r.*m_top += m_arrowSize;
break;
case SBII_THUMB:
r.*m_bottom = r.*m_top + m_sbi.xyThumbBottom;
r.*m_top += m_sbi.xyThumbTop;
break;
case SBII_PAGEDOWN_REGION:
r.*m_top += m_sbi.xyThumbBottom;
r.*m_bottom -= m_arrowSize;
break;
case SBII_BOTTOM_ARROW:
r.*m_top = r.*m_bottom - m_arrowSize;
break;
}
return r;
}
LONG ScrollBar::hitTest(POINT p)
{
if (m_sbi.rgstate[SBII_SELF] & STATE_SYSTEM_UNAVAILABLE)
{
return -1;
}
for (UINT i = SBII_TOP_ARROW; i <= SBII_BOTTOM_ARROW; ++i)
{
RECT r = getChildRect(i);
if (PtInRect(&r, p))
{
return (m_sbi.rgstate[i] & STATE_SYSTEM_UNAVAILABLE) ? -1 : i;
}
}
return -1;
}
bool ScrollBar::isVisible()
{
return !(m_sbi.rgstate[SBII_SELF] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN));
}
void ScrollBar::onCtlColorScrollBar(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT result)
{
HWND hwndSb = reinterpret_cast<HWND>(lParam);
HBRUSH brush = reinterpret_cast<HBRUSH>(result);
HDC dc = reinterpret_cast<HDC>(wParam);
if (hwnd == hwndSb)
{
ScrollBar(hwnd, SB_HORZ).drawAll(dc, brush);
ScrollBar(hwnd, SB_VERT).drawAll(dc, brush);
}
else
{
ScrollBar(hwndSb, SB_CTL).drawAll(dc, brush);
}
}
void ScrollBar::onLButtonDown(LPARAM lParam)
{
POINTS pt = *reinterpret_cast<POINTS*>(&lParam);
POINT p = { pt.x, pt.y };
if (SB_CTL != m_bar)
{
p.x -= m_windowRect.left;
p.y -= m_windowRect.top;
}
m_trackedChildId = hitTest(p);
if (-1 != m_trackedChildId)
{
g_trackedScrollBar = this;
if (SBII_THUMB == m_trackedChildId)
{
RECT rect = getChildRect(SBII_THUMB);
m_trackedThumbOffset = m_isVertical ? (p.y - rect.top) : (p.x - rect.left);
}
} }
} }
} }

View File

@ -7,42 +7,33 @@ namespace Gdi
class ScrollBar class ScrollBar
{ {
public: public:
struct ScrollBarChildInfo ScrollBar(HWND hwnd, int bar);
{ ~ScrollBar();
RECT rect;
LONG state;
};
struct ScrollBarInfo void onLButtonDown(LPARAM lParam);
{
ScrollBarChildInfo topLeftArrow;
ScrollBarChildInfo bottomRightArrow;
RECT shaftRect;
bool isVisible;
};
ScrollBar(HWND hwnd, HDC compatDc); static void onCtlColorScrollBar(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT result);
void drawAll() const;
void drawHorizArrows() const;
void drawVertArrows() const;
void excludeFromClipRegion() const;
const ScrollBarInfo& getHorizontalScrollBarInfo() const { return m_horizontalSbi; }
const ScrollBarInfo& getVerticalScrollBarInfo() const { return m_verticalSbi; }
private: private:
void drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const; void drawAll(HDC dc, HBRUSH brush);
void excludeFromClipRegion(const RECT& rect) const; void drawArrow(HDC dc, LONG childId);
void excludeFromClipRegion(const ScrollBarInfo& sbi) const; void drawPageRegion(HDC dc, HBRUSH brush, LONG childId);
ScrollBarInfo getScrollBarInfo(LONG objId) const; void drawThumb(HDC dc, HBRUSH brush);
void setPressedState(ScrollBarChildInfo& sbci) const; RECT getChildRect(LONG childId);
LONG hitTest(POINT p);
bool isVisible();
HWND m_hwnd; HWND m_hwnd;
HDC m_compatDc; int m_bar;
RECT m_windowRect; RECT m_windowRect;
bool m_isLeftMouseButtonDown; SCROLLBARINFO m_sbi;
POINT m_cursorPos; bool m_isVertical;
ScrollBarInfo m_horizontalSbi; int m_arrowSize;
ScrollBarInfo m_verticalSbi; LONG RECT::* m_left;
LONG RECT::* m_top;
LONG RECT::* m_right;
LONG RECT::* m_bottom;
LONG m_trackedChildId;
LONG m_trackedThumbOffset;
}; };
} }

View File

@ -1,10 +1,8 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/Dc.h> #include <Gdi/Dc.h>
#include <Gdi/Gdi.h> #include <Gdi/Gdi.h>
#include <Gdi/Region.h> #include <Gdi/Region.h>
#include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h> #include <Gdi/ScrollFunctions.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
@ -48,31 +46,6 @@ namespace
return LOG_RESULT(result); return LOG_RESULT(result);
} }
int WINAPI setScrollInfo(HWND hwnd, int nBar, LPCSCROLLINFO lpsi, BOOL redraw)
{
LOG_FUNC("SetScrollInfo", hwnd, nBar, lpsi, redraw);
int result = CALL_ORIG_FUNC(SetScrollInfo)(hwnd, nBar, lpsi, redraw);
if (redraw && (SB_HORZ == nBar || SB_VERT == nBar))
{
Gdi::ScrollBar sb(hwnd, nullptr);
const auto& sbi = SB_HORZ == nBar ? sb.getHorizontalScrollBarInfo() : sb.getVerticalScrollBarInfo();
if (sbi.isVisible)
{
HDC windowDc = GetWindowDC(hwnd);
SelectClipRgn(windowDc, Gdi::Region(sbi.shaftRect));
HDC compatDc = Gdi::Dc::getDc(windowDc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CALL_ORIG_FUNC(DefWindowProcA)(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
Gdi::Dc::releaseDc(windowDc);
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
}
}
return LOG_RESULT(result);
}
} }
namespace Gdi namespace Gdi
@ -83,7 +56,6 @@ namespace Gdi
{ {
HOOK_FUNCTION(user32, ScrollWindow, scrollWindow); HOOK_FUNCTION(user32, ScrollWindow, scrollWindow);
HOOK_FUNCTION(user32, ScrollWindowEx, scrollWindowEx); HOOK_FUNCTION(user32, ScrollWindowEx, scrollWindowEx);
HOOK_FUNCTION(user32, SetScrollInfo, setScrollInfo);
} }
} }
} }

View File

@ -1,8 +1,6 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Gdi/Gdi.h>
#include <Gdi/Region.h> #include <Gdi/Region.h>
#include <Gdi/TitleBar.h> #include <Gdi/TitleBar.h>
#include <Gdi/VirtualScreen.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
namespace namespace
@ -19,9 +17,8 @@ namespace
namespace Gdi namespace Gdi
{ {
TitleBar::TitleBar(HWND hwnd, HDC compatDc) TitleBar::TitleBar(HWND hwnd)
: m_hwnd(hwnd) : m_hwnd(hwnd)
, m_compatDc(compatDc)
, m_buttonWidth(0) , m_buttonWidth(0)
, m_buttonHeight(0) , m_buttonHeight(0)
, m_tbi{} , m_tbi{}
@ -75,26 +72,26 @@ namespace Gdi
} }
} }
void TitleBar::drawAll() const void TitleBar::drawAll(HDC dc) const
{ {
drawCaption(); drawCaption(dc);
drawButtons(); drawButtons(dc);
} }
void TitleBar::drawButtons() const void TitleBar::drawButtons(HDC dc) const
{ {
if (!m_hasTitleBar) if (!m_hasTitleBar)
{ {
return; return;
} }
drawButton(TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN); drawButton(dc, TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN);
drawButton(TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX); drawButton(dc, TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
drawButton(TBII_HELP_BUTTON, DFCS_CAPTIONHELP); drawButton(dc, TBII_HELP_BUTTON, DFCS_CAPTIONHELP);
drawButton(TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE); drawButton(dc, TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE);
} }
void TitleBar::drawCaption() const void TitleBar::drawCaption(HDC dc) const
{ {
if (!m_hasTitleBar) if (!m_hasTitleBar)
{ {
@ -111,20 +108,15 @@ namespace Gdi
flags |= DC_GRADIENT; flags |= DC_GRADIENT;
} }
RECT virtualScreenBounds = VirtualScreen::getBounds(); SelectClipRgn(dc, Region(m_tbi.rcTitleBar));
RECT clipRect = m_tbi.rcTitleBar; DrawCaption(m_hwnd, dc, &m_tbi.rcTitleBar, flags);
OffsetRect(&clipRect, m_windowRect.left - virtualScreenBounds.left, m_windowRect.top - virtualScreenBounds.top); SelectClipRgn(dc, nullptr);
Region clipRgn(clipRect);
SelectClipRgn(m_compatDc, clipRgn);
CALL_ORIG_FUNC(DrawCaption)(m_hwnd, m_compatDc, &m_tbi.rcTitleBar, flags);
SelectClipRgn(m_compatDc, nullptr);
if (m_hasIcon) if (m_hasIcon)
{ {
RECT r = m_tbi.rcTitleBar; RECT r = m_tbi.rcTitleBar;
r.right = r.left + r.bottom - r.top; r.right = r.left + r.bottom - r.top;
CALL_ORIG_FUNC(FillRect)(m_compatDc, &r, FillRect(dc, &r, GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
HICON icon = reinterpret_cast<HICON>(SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 96)); HICON icon = reinterpret_cast<HICON>(SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 96));
if (!icon) if (!icon)
@ -135,11 +127,11 @@ namespace Gdi
int height = GetSystemMetrics(SM_CYSMICON); int height = GetSystemMetrics(SM_CYSMICON);
int x = r.left + (r.right - r.left - width) / 2 + 2; int x = r.left + (r.right - r.left - width) / 2 + 2;
int y = r.top + (r.bottom - r.top - height) / 2; int y = r.top + (r.bottom - r.top - height) / 2;
CALL_ORIG_FUNC(DrawIconEx)(m_compatDc, x, y, icon, width, height, 0, nullptr, DI_NORMAL); DrawIconEx(dc, x, y, icon, width, height, 0, nullptr, DI_NORMAL);
} }
} }
void TitleBar::drawButton(std::size_t tbiIndex, UINT dfcState) const void TitleBar::drawButton(HDC dc, std::size_t tbiIndex, UINT dfcState) const
{ {
if (!isVisible(tbiIndex)) if (!isVisible(tbiIndex))
{ {
@ -157,16 +149,7 @@ namespace Gdi
} }
RECT rect = m_tbi.rgrect[tbiIndex]; RECT rect = m_tbi.rgrect[tbiIndex];
CALL_ORIG_FUNC(DrawFrameControl)(m_compatDc, &rect, DFC_CAPTION, dfcState | stateFlags); DrawFrameControl(dc, &rect, DFC_CAPTION, dfcState | stateFlags);
}
void TitleBar::excludeFromClipRegion() const
{
if (m_hasTitleBar)
{
const RECT& r = m_tbi.rcTitleBar;
ExcludeClipRect(m_compatDc, r.left, r.top, r.right, r.bottom);
}
} }
bool TitleBar::isVisible(std::size_t tbiIndex) const bool TitleBar::isVisible(std::size_t tbiIndex) const

View File

@ -9,19 +9,17 @@ namespace Gdi
class TitleBar class TitleBar
{ {
public: public:
TitleBar(HWND hwnd, HDC compatDc); TitleBar(HWND hwnd);
void drawAll() const; void drawAll(HDC dc) const;
void drawButtons() const; void drawButtons(HDC dc) const;
void drawCaption() const; void drawCaption(HDC dc) const;
void excludeFromClipRegion() const;
private: private:
void drawButton(std::size_t tbiIndex, UINT dfcState) const; void drawButton(HDC dc, std::size_t tbiIndex, UINT dfcState) const;
bool isVisible(std::size_t tbiIndex) const; bool isVisible(std::size_t tbiIndex) const;
HWND m_hwnd; HWND m_hwnd;
HDC m_compatDc;
int m_buttonWidth; int m_buttonWidth;
int m_buttonHeight; int m_buttonHeight;
TITLEBARINFOEX m_tbi; TITLEBARINFOEX m_tbi;

View File

@ -1,7 +1,6 @@
#include <vector> #include <vector>
#include <Gdi/AccessGuard.h> #include <Gdi/CompatDc.h>
#include <Gdi/Dc.h>
#include <Gdi/ScrollBar.h> #include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h> #include <Gdi/ScrollFunctions.h>
#include <Gdi/TitleBar.h> #include <Gdi/TitleBar.h>
@ -134,6 +133,15 @@ namespace
{ {
switch (msg) switch (msg)
{ {
case WM_CTLCOLORSCROLLBAR:
if (reinterpret_cast<HWND>(lParam) == hwnd)
{
LRESULT result = origDefWindowProc(hwnd, msg, wParam, lParam);
Gdi::ScrollBar::onCtlColorScrollBar(hwnd, wParam, lParam, result);
return result;
}
break;
case WM_NCACTIVATE: case WM_NCACTIVATE:
return onNcActivate(hwnd, wParam, lParam); return onNcActivate(hwnd, wParam, lParam);
@ -151,12 +159,13 @@ namespace
case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDOWN:
{ {
LRESULT result = origDefWindowProc(hwnd, msg, wParam, lParam);
if (wParam == HTHSCROLL || wParam == HTVSCROLL) if (wParam == HTHSCROLL || wParam == HTVSCROLL)
{ {
onNcPaint(hwnd, origDefWindowProc); Gdi::ScrollBar sb(hwnd, wParam == HTHSCROLL ? SB_HORZ : SB_VERT);
sb.onLButtonDown(lParam);
return origDefWindowProc(hwnd, msg, wParam, lParam);
} }
return result; return origDefWindowProc(hwnd, msg, wParam, lParam);
} }
} }
@ -347,20 +356,8 @@ namespace
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc) LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
{ {
if (hwnd) return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND,
{ reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), 0);
LRESULT result = 0;
HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
Gdi::Dc::releaseDc(dc);
return result;
}
}
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
} }
LRESULT onNcActivate(HWND hwnd, WPARAM /*wParam*/, LPARAM lParam) LRESULT onNcActivate(HWND hwnd, WPARAM /*wParam*/, LPARAM lParam)
@ -375,73 +372,29 @@ namespace
LRESULT onNcPaint(HWND hwnd, WNDPROC origWndProc) LRESULT onNcPaint(HWND hwnd, WNDPROC origWndProc)
{ {
D3dDdi::ScopedCriticalSection lock;
HDC windowDc = GetWindowDC(hwnd); HDC windowDc = GetWindowDC(hwnd);
HDC compatDc = Gdi::Dc::getDc(windowDc); CallWindowProc(origWndProc, hwnd, WM_PRINT,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(windowDc))), PRF_NONCLIENT);
if (compatDc) Gdi::TitleBar(hwnd).drawAll(windowDc);
{ ReleaseDC(hwnd, windowDc);
D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
Gdi::TitleBar titleBar(hwnd, compatDc);
titleBar.drawAll();
titleBar.excludeFromClipRegion();
Gdi::ScrollBar scrollBar(hwnd, compatDc);
scrollBar.drawAll();
scrollBar.excludeFromClipRegion();
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
Gdi::Dc::releaseDc(windowDc);
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
return 0; return 0;
} }
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc) LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
{ {
if (!hwnd)
{
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
}
PAINTSTRUCT paint = {}; PAINTSTRUCT paint = {};
HDC dc = BeginPaint(hwnd, &paint); HDC dc = BeginPaint(hwnd, &paint);
HDC compatDc = Gdi::Dc::getDc(dc); CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), PRF_CLIENT);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
Gdi::Dc::releaseDc(dc);
}
else
{
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(dc), PRF_CLIENT);
}
EndPaint(hwnd, &paint); EndPaint(hwnd, &paint);
return 0; return 0;
} }
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc) LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc)
{ {
LRESULT result = 0; return CallWindowProc(origWndProc, hwnd, msg,
HDC compatDc = Gdi::Dc::getDc(dc); reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), flags);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
Gdi::Dc::releaseDc(dc);
}
else
{
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
}
return result;
} }
LRESULT onSetText(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) LRESULT onSetText(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
@ -459,6 +412,13 @@ namespace
{ {
switch (msg) switch (msg)
{ {
case WM_LBUTTONDOWN:
{
Gdi::ScrollBar sb(hwnd, SB_CTL);
sb.onLButtonDown(lParam);
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
case WM_PAINT: case WM_PAINT:
return onPaint(hwnd, origWndProc); return onPaint(hwnd, origWndProc);
@ -468,10 +428,9 @@ namespace
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE)); SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
} }
return TRUE; return TRUE;
default:
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
} }
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
} }
BOOL WINAPI setMenuItemInfoW(HMENU hmenu, UINT item, BOOL fByPositon, LPCMENUITEMINFOW lpmii) BOOL WINAPI setMenuItemInfoW(HMENU hmenu, UINT item, BOOL fByPositon, LPCMENUITEMINFOW lpmii)

View File

@ -7,7 +7,7 @@
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/ScopedSrwLock.h> #include <Common/ScopedSrwLock.h>
#include <Dll/Dll.h> #include <Dll/Dll.h>
#include <Gdi/AccessGuard.h> #include <Gdi/CompatDc.h>
#include <Gdi/Dc.h> #include <Gdi/Dc.h>
#include <Gdi/PresentationWindow.h> #include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollBar.h> #include <Gdi/ScrollBar.h>
@ -34,6 +34,7 @@ namespace
WindowProc getWindowProc(HWND hwnd); WindowProc getWindowProc(HWND hwnd);
bool isTopLevelWindow(HWND hwnd); bool isTopLevelWindow(HWND hwnd);
bool isUser32ScrollBar(HWND hwnd);
void onCreateWindow(HWND hwnd); void onCreateWindow(HWND hwnd);
void onDestroyWindow(HWND hwnd); void onDestroyWindow(HWND hwnd);
void onWindowPosChanged(HWND hwnd); void onWindowPosChanged(HWND hwnd);
@ -64,6 +65,14 @@ namespace
switch (uMsg) switch (uMsg)
{ {
case WM_CTLCOLORSCROLLBAR:
if (reinterpret_cast<HWND>(lParam) != hwnd &&
isUser32ScrollBar(reinterpret_cast<HWND>(lParam)))
{
Gdi::ScrollBar::onCtlColorScrollBar(hwnd, wParam, lParam, result);
}
break;
case WM_NCDESTROY: case WM_NCDESTROY:
onDestroyWindow(hwnd); onDestroyWindow(hwnd);
break; break;
@ -153,6 +162,25 @@ namespace
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT); return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
} }
bool isUser32ScrollBar(HWND hwnd)
{
WNDCLASS wc = {};
static const ATOM sbAtom = static_cast<ATOM>(GetClassInfo(nullptr, "ScrollBar", &wc));
if (sbAtom != GetClassLong(hwnd, GCW_ATOM))
{
return false;
}
auto it = g_windowProc.find(hwnd);
if (it == g_windowProc.end())
{
return false;
}
return GetModuleHandle("comctl32") != Compat::getModuleHandleFromAddress(
IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA);
}
void CALLBACK objectCreateEvent( void CALLBACK objectCreateEvent(
HWINEVENTHOOK /*hWinEventHook*/, HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/, DWORD /*event*/,
@ -177,33 +205,38 @@ namespace
DWORD /*dwEventThread*/, DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/) DWORD /*dwmsEventTime*/)
{ {
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject) switch (idObject)
{ {
if (!hwnd) case OBJID_TITLEBAR:
{ {
return; HDC dc = GetWindowDC(hwnd);
} Gdi::TitleBar(hwnd).drawButtons(dc);
ReleaseDC(hwnd, dc);
break;
}
HDC windowDc = GetWindowDC(hwnd); case OBJID_CLIENT:
HDC compatDc = Gdi::Dc::getDc(windowDc); if (!isUser32ScrollBar(hwnd))
if (compatDc)
{ {
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE); break;
if (OBJID_TITLEBAR == idObject)
{
Gdi::TitleBar(hwnd, compatDc).drawButtons();
}
else if (OBJID_HSCROLL == idObject)
{
Gdi::ScrollBar(hwnd, compatDc).drawHorizArrows();
}
else if (OBJID_VSCROLL == idObject)
{
Gdi::ScrollBar(hwnd, compatDc).drawVertArrows();
}
Gdi::Dc::releaseDc(windowDc);
} }
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc); case OBJID_HSCROLL:
case OBJID_VSCROLL:
{
HDC dc = GetWindowDC(hwnd);
if (OBJID_CLIENT == idObject)
{
SendMessage(GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
else
{
DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
ReleaseDC(hwnd, dc);
break;
}
} }
} }
@ -421,6 +454,7 @@ namespace Gdi
HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow); HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow);
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect); HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
CoInitialize(nullptr);
g_objectCreateEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, g_objectCreateEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
Dll::g_currentModule, &objectCreateEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); Dll::g_currentModule, &objectCreateEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE, g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,

View File

@ -83,7 +83,7 @@ namespace
SelectClipRgn(screenDc, clipRegion); SelectClipRgn(screenDc, clipRegion);
BitBlt(screenDc, dst.left, dst.top, src.right - src.left, src.bottom - src.top, screenDc, src.left, src.top, SRCCOPY); BitBlt(screenDc, dst.left, dst.top, src.right - src.left, src.bottom - src.top, screenDc, src.left, src.top, SRCCOPY);
SelectClipRgn(screenDc, nullptr); SelectClipRgn(screenDc, nullptr);
CALL_ORIG_FUNC(ReleaseDC)(nullptr, screenDc); ReleaseDC(nullptr, screenDc);
return true; return true;
} }

View File

@ -346,6 +346,13 @@ std::ostream& operator<<(std::ostream& os, const POINT& p)
<< p.y; << p.y;
} }
std::ostream& operator<<(std::ostream& os, const POINTS& p)
{
return Compat::LogStruct(os)
<< p.x
<< p.y;
}
std::ostream& operator<<(std::ostream& os, const RECT& rect) std::ostream& operator<<(std::ostream& os, const RECT& rect)
{ {
return Compat::LogStruct(os) return Compat::LogStruct(os)

View File

@ -33,6 +33,7 @@ std::ostream& operator<<(std::ostream& os, const MSG& msg);
std::ostream& operator<<(std::ostream& os, const NCCALCSIZE_PARAMS& nccs); std::ostream& operator<<(std::ostream& os, const NCCALCSIZE_PARAMS& nccs);
std::ostream& operator<<(std::ostream& os, const NMHDR& nm); std::ostream& operator<<(std::ostream& os, const NMHDR& nm);
std::ostream& operator<<(std::ostream& os, const POINT& p); std::ostream& operator<<(std::ostream& os, const POINT& p);
std::ostream& operator<<(std::ostream& os, const POINTS& p);
std::ostream& operator<<(std::ostream& os, const RECT& rect); std::ostream& operator<<(std::ostream& os, const RECT& rect);
std::ostream& operator<<(std::ostream& os, const SIZE& size); std::ostream& operator<<(std::ostream& os, const SIZE& size);
std::ostream& operator<<(std::ostream& os, const STYLESTRUCT& ss); std::ostream& operator<<(std::ostream& os, const STYLESTRUCT& ss);