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:
parent
27ae9affb8
commit
205f517845
@ -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)
|
||||
{
|
||||
if (!isValidRect(data.DstSubResourceIndex, data.DstRect))
|
||||
@ -471,14 +459,6 @@ namespace D3dDdi
|
||||
#endif
|
||||
}
|
||||
|
||||
void Resource::endGdiAccess(bool isReadOnly)
|
||||
{
|
||||
if (m_lockResource && !isReadOnly && m_lockData[0].isSysMemUpToDate)
|
||||
{
|
||||
m_lockData[0].isVidMemUpToDate = false;
|
||||
}
|
||||
}
|
||||
|
||||
void* Resource::getLockPtr(UINT subResourceIndex)
|
||||
{
|
||||
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
|
||||
@ -517,6 +497,21 @@ namespace D3dDdi
|
||||
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)
|
||||
{
|
||||
if (m_lockResource && 0 == m_lockData[subResourceIndex].lockCount)
|
||||
|
@ -26,12 +26,11 @@ namespace D3dDdi
|
||||
|
||||
operator HANDLE() const { return m_handle; }
|
||||
|
||||
void beginGdiAccess(bool isReadOnly);
|
||||
HRESULT blt(D3DDDIARG_BLT data);
|
||||
HRESULT colorFill(D3DDDIARG_COLORFILL data);
|
||||
void endGdiAccess(bool isReadOnly);
|
||||
void* getLockPtr(UINT subResourceIndex);
|
||||
HRESULT lock(D3DDDIARG_LOCK& data);
|
||||
void prepareForGdiRendering(bool isReadOnly);
|
||||
void prepareForRendering(UINT subResourceIndex, bool isReadOnly);
|
||||
void setAsGdiResource(bool isGdiResource);
|
||||
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
|
||||
|
@ -1,11 +1,10 @@
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
|
||||
#include "Common/Time.h"
|
||||
#include "Config/Config.h"
|
||||
#include "DDraw/DirectDrawPalette.h"
|
||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||
#include "Gdi/AccessGuard.h"
|
||||
#include <Common/Time.h>
|
||||
#include <Config/Config.h>
|
||||
#include <DDraw/DirectDrawPalette.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
|
||||
namespace DDraw
|
||||
{
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <DDraw/ScopedThreadLock.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Types.h>
|
||||
#include <Gdi/AccessGuard.h>
|
||||
#include <Gdi/Caret.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
|
@ -213,7 +213,7 @@
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
|
||||
<ClInclude Include="Dll\Dll.h" />
|
||||
<ClInclude Include="Gdi\AccessGuard.h" />
|
||||
<ClInclude Include="Gdi\CompatDc.h" />
|
||||
<ClInclude Include="Gdi\Font.h" />
|
||||
<ClInclude Include="Gdi\Gdi.h" />
|
||||
<ClInclude Include="Gdi\Caret.h" />
|
||||
@ -287,7 +287,7 @@
|
||||
<ClCompile Include="Direct3d\Log.cpp" />
|
||||
<ClCompile Include="Dll\DllMain.cpp" />
|
||||
<ClCompile Include="Dll\Dll.cpp" />
|
||||
<ClCompile Include="Gdi\AccessGuard.cpp" />
|
||||
<ClCompile Include="Gdi\CompatDc.cpp" />
|
||||
<ClCompile Include="Gdi\Font.cpp" />
|
||||
<ClCompile Include="Gdi\Gdi.cpp" />
|
||||
<ClCompile Include="Gdi\Caret.cpp" />
|
||||
|
@ -297,9 +297,6 @@
|
||||
<ClInclude Include="Gdi\VirtualScreen.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\AccessGuard.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\Palette.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
@ -402,6 +399,9 @@
|
||||
<ClInclude Include="Gdi\Metrics.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\CompatDc.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -545,9 +545,6 @@
|
||||
<ClCompile Include="Gdi\VirtualScreen.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\AccessGuard.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\Palette.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
@ -620,5 +617,8 @@
|
||||
<ClCompile Include="Gdi\Metrics.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\CompatDc.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
44
DDrawCompat/Gdi/CompatDc.cpp
Normal file
44
DDrawCompat/Gdi/CompatDc.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
27
DDrawCompat/Gdi/CompatDc.h
Normal file
27
DDrawCompat/Gdi/CompatDc.h
Normal 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;
|
||||
};
|
||||
}
|
@ -22,10 +22,6 @@ namespace
|
||||
HDC origDc;
|
||||
DWORD threadId;
|
||||
int savedState;
|
||||
HGDIOBJ savedFont;
|
||||
HGDIOBJ savedBrush;
|
||||
HGDIOBJ savedPen;
|
||||
HPALETTE savedPalette;
|
||||
bool useDefaultPalette;
|
||||
};
|
||||
|
||||
@ -38,11 +34,10 @@ namespace
|
||||
|
||||
void copyDcAttributes(CompatDc& compatDc, HDC origDc, const POINT& origin)
|
||||
{
|
||||
SelectObject(compatDc.dc, compatDc.savedFont = GetCurrentObject(origDc, OBJ_FONT));
|
||||
SelectObject(compatDc.dc, compatDc.savedBrush = GetCurrentObject(origDc, OBJ_BRUSH));
|
||||
SelectObject(compatDc.dc, compatDc.savedPen = GetCurrentObject(origDc, OBJ_PEN));
|
||||
CALL_ORIG_FUNC(SelectPalette)(
|
||||
compatDc.dc, compatDc.savedPalette = static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
|
||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
|
||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
|
||||
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
|
||||
CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
|
||||
|
||||
const int graphicsMode = GetGraphicsMode(origDc);
|
||||
SetGraphicsMode(compatDc.dc, graphicsMode);
|
||||
@ -98,20 +93,10 @@ namespace
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
// Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one
|
||||
HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP);
|
||||
RestoreDC(compatDc.dc, compatDc.savedState);
|
||||
SelectObject(compatDc.dc, bitmap);
|
||||
}
|
||||
|
||||
void setClippingRegion(const CompatDc& compatDc, HWND hwnd, const POINT& origin, const RECT& virtualScreenBounds)
|
||||
@ -135,10 +120,7 @@ namespace
|
||||
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))
|
||||
{
|
||||
@ -222,7 +204,7 @@ namespace Gdi
|
||||
compatDc.refCount = 1;
|
||||
compatDc.origDc = origDc;
|
||||
compatDc.threadId = GetCurrentThreadId();
|
||||
compatDc.savedState = useMetaRgn ? SaveDC(compatDc.dc) : 0;
|
||||
compatDc.savedState = SaveDC(compatDc.dc);
|
||||
copyDcAttributes(compatDc, origDc, origin);
|
||||
setClippingRegion(compatDc, hwnd, origin, virtualScreenBounds);
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace Gdi
|
||||
{
|
||||
void dllProcessDetach();
|
||||
void dllThreadDetach();
|
||||
HDC getDc(HDC origDc, bool useMetaRgn = true);
|
||||
HDC getDc(HDC origDc);
|
||||
HDC getOrigDc(HDC dc);
|
||||
void releaseDc(HDC origDc);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Gdi/AccessGuard.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/DcFunctions.h>
|
||||
#include <Gdi/Font.h>
|
||||
@ -14,39 +14,6 @@
|
||||
|
||||
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;
|
||||
thread_local bool g_redirectToDib = true;
|
||||
|
||||
@ -123,9 +90,9 @@ namespace
|
||||
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>
|
||||
@ -137,9 +104,7 @@ namespace
|
||||
|
||||
if (hasDisplayDcArg(hdc, params...))
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
Gdi::AccessGuard accessGuard(isReadOnly<OrigFuncPtr, origFunc>() ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
|
||||
CompatDc compatDc(hdc);
|
||||
Gdi::CompatDc compatDc(hdc, isReadOnly<OrigFuncPtr, origFunc>());
|
||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(compatDc, replaceDc(params)...);
|
||||
if (isPositionUpdated<OrigFuncPtr, origFunc>() && result)
|
||||
{
|
||||
@ -181,9 +146,7 @@ namespace
|
||||
}
|
||||
else
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
CompatDc compatDc(hdc);
|
||||
Gdi::CompatDc compatDc(hdc);
|
||||
BOOL result = CALL_ORIG_FUNC(ExtTextOutW)(compatDc, x, y, options, lprect, lpString, c, lpDx);
|
||||
if (result)
|
||||
{
|
||||
@ -255,9 +218,7 @@ namespace
|
||||
LOG_FUNC("DrawCaption", hwnd, hdc, lprect, flags);
|
||||
if (Gdi::isDisplayDc(hdc))
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
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, Gdi::CompatDc(hdc), lprect, flags));
|
||||
}
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, hdc, lprect, flags));
|
||||
}
|
||||
|
@ -1,177 +1,285 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
enum ScrollBarInfoIndex
|
||||
{
|
||||
SBII_SCROLLBAR = 0,
|
||||
SBII_TOP_RIGHT_ARROW = 1,
|
||||
SBII_PAGEUP_PAGERIGHT_REGION = 2,
|
||||
SBII_SELF = 0,
|
||||
SBII_TOP_ARROW = 1,
|
||||
SBII_PAGEUP_REGION = 2,
|
||||
SBII_THUMB = 3,
|
||||
SBII_PAGEDOWN_PAGELEFT_REGION = 4,
|
||||
SBII_BOTTOM_LEFT_ARROW = 5
|
||||
SBII_PAGEDOWN_REGION = 4,
|
||||
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
|
||||
{
|
||||
ScrollBar::ScrollBar(HWND hwnd, HDC compatDc) :
|
||||
m_hwnd(hwnd), m_compatDc(compatDc), m_windowRect(),
|
||||
m_isLeftMouseButtonDown(false), m_cursorPos(),
|
||||
m_horizontalSbi(), m_verticalSbi()
|
||||
ScrollBar::ScrollBar(HWND hwnd, int bar)
|
||||
: m_hwnd(hwnd)
|
||||
, m_bar(bar)
|
||||
, 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);
|
||||
|
||||
m_horizontalSbi.isVisible = 0 != (windowStyle & WS_HSCROLL);
|
||||
m_verticalSbi.isVisible = 0 != (windowStyle & WS_VSCROLL);
|
||||
LONG objectId = OBJID_CLIENT;
|
||||
if (SB_HORZ == bar)
|
||||
{
|
||||
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);
|
||||
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 =
|
||||
hwnd == GetCapture() &&
|
||||
GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0 &&
|
||||
GetCursorPos(&m_cursorPos);
|
||||
DWORD pos = GetMessagePos();
|
||||
POINTS pt = *reinterpret_cast<POINTS*>(&pos);
|
||||
POINT p = { pt.x - m_windowRect.left, pt.y - m_windowRect.top };
|
||||
|
||||
if (m_isLeftMouseButtonDown)
|
||||
if (SBII_THUMB == g_trackedScrollBar->m_trackedChildId)
|
||||
{
|
||||
m_cursorPos.x -= m_windowRect.left;
|
||||
m_cursorPos.y -= m_windowRect.top;
|
||||
RECT trackRect = m_sbi.rcScrollBar;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_horizontalSbi.isVisible)
|
||||
else
|
||||
{
|
||||
m_horizontalSbi = getScrollBarInfo(OBJID_HSCROLL);
|
||||
}
|
||||
|
||||
if (m_verticalSbi.isVisible)
|
||||
{
|
||||
m_verticalSbi = getScrollBarInfo(OBJID_VSCROLL);
|
||||
RECT rect = getChildRect(g_trackedScrollBar->m_trackedChildId);
|
||||
if (PtInRect(&rect, p))
|
||||
{
|
||||
m_sbi.rgstate[g_trackedScrollBar->m_trackedChildId] |= STATE_SYSTEM_PRESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBar::drawAll() const
|
||||
ScrollBar::~ScrollBar()
|
||||
{
|
||||
drawHorizArrows();
|
||||
drawVertArrows();
|
||||
}
|
||||
|
||||
void ScrollBar::drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const
|
||||
{
|
||||
UINT stateFlags = 0;
|
||||
if (sbci.state & STATE_SYSTEM_UNAVAILABLE)
|
||||
if (this == g_trackedScrollBar)
|
||||
{
|
||||
stateFlags |= DFCS_INACTIVE;
|
||||
}
|
||||
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);
|
||||
g_trackedScrollBar = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBar::drawVertArrows() const
|
||||
void ScrollBar::drawAll(HDC dc, HBRUSH brush)
|
||||
{
|
||||
if (m_verticalSbi.isVisible)
|
||||
if (isVisible())
|
||||
{
|
||||
drawArrow(m_verticalSbi.topLeftArrow, DFCS_SCROLLUP);
|
||||
drawArrow(m_verticalSbi.bottomRightArrow, DFCS_SCROLLDOWN);
|
||||
drawArrow(dc, SBII_TOP_ARROW);
|
||||
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);
|
||||
}
|
||||
|
||||
void ScrollBar::excludeFromClipRegion(const ScrollBarInfo& sbi) const
|
||||
{
|
||||
if (sbi.isVisible)
|
||||
UINT state = 0;
|
||||
if (SBII_TOP_ARROW == childId)
|
||||
{
|
||||
excludeFromClipRegion(sbi.topLeftArrow.rect);
|
||||
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);
|
||||
state = m_isVertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int h = GetSystemMetrics(SM_CYVSCROLL);
|
||||
|
||||
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);
|
||||
state = m_isVertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT;
|
||||
}
|
||||
|
||||
if (m_isLeftMouseButtonDown)
|
||||
if (m_sbi.rgstate[childId] & STATE_SYSTEM_UNAVAILABLE)
|
||||
{
|
||||
setPressedState(scrollBarInfo.topLeftArrow);
|
||||
setPressedState(scrollBarInfo.bottomRightArrow);
|
||||
state |= DFCS_INACTIVE;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,42 +7,33 @@ namespace Gdi
|
||||
class ScrollBar
|
||||
{
|
||||
public:
|
||||
struct ScrollBarChildInfo
|
||||
{
|
||||
RECT rect;
|
||||
LONG state;
|
||||
};
|
||||
ScrollBar(HWND hwnd, int bar);
|
||||
~ScrollBar();
|
||||
|
||||
struct ScrollBarInfo
|
||||
{
|
||||
ScrollBarChildInfo topLeftArrow;
|
||||
ScrollBarChildInfo bottomRightArrow;
|
||||
RECT shaftRect;
|
||||
bool isVisible;
|
||||
};
|
||||
void onLButtonDown(LPARAM lParam);
|
||||
|
||||
ScrollBar(HWND hwnd, HDC compatDc);
|
||||
|
||||
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; }
|
||||
static void onCtlColorScrollBar(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT result);
|
||||
|
||||
private:
|
||||
void drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const;
|
||||
void excludeFromClipRegion(const RECT& rect) const;
|
||||
void excludeFromClipRegion(const ScrollBarInfo& sbi) const;
|
||||
ScrollBarInfo getScrollBarInfo(LONG objId) const;
|
||||
void setPressedState(ScrollBarChildInfo& sbci) const;
|
||||
void drawAll(HDC dc, HBRUSH brush);
|
||||
void drawArrow(HDC dc, LONG childId);
|
||||
void drawPageRegion(HDC dc, HBRUSH brush, LONG childId);
|
||||
void drawThumb(HDC dc, HBRUSH brush);
|
||||
RECT getChildRect(LONG childId);
|
||||
LONG hitTest(POINT p);
|
||||
bool isVisible();
|
||||
|
||||
HWND m_hwnd;
|
||||
HDC m_compatDc;
|
||||
int m_bar;
|
||||
RECT m_windowRect;
|
||||
bool m_isLeftMouseButtonDown;
|
||||
POINT m_cursorPos;
|
||||
ScrollBarInfo m_horizontalSbi;
|
||||
ScrollBarInfo m_verticalSbi;
|
||||
SCROLLBARINFO m_sbi;
|
||||
bool m_isVertical;
|
||||
int m_arrowSize;
|
||||
LONG RECT::* m_left;
|
||||
LONG RECT::* m_top;
|
||||
LONG RECT::* m_right;
|
||||
LONG RECT::* m_bottom;
|
||||
LONG m_trackedChildId;
|
||||
LONG m_trackedThumbOffset;
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Gdi/AccessGuard.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/Region.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
#include <Gdi/ScrollFunctions.h>
|
||||
#include <Gdi/Window.h>
|
||||
|
||||
@ -48,31 +46,6 @@ namespace
|
||||
|
||||
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
|
||||
@ -83,7 +56,6 @@ namespace Gdi
|
||||
{
|
||||
HOOK_FUNCTION(user32, ScrollWindow, scrollWindow);
|
||||
HOOK_FUNCTION(user32, ScrollWindowEx, scrollWindowEx);
|
||||
HOOK_FUNCTION(user32, SetScrollInfo, setScrollInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/Region.h>
|
||||
#include <Gdi/TitleBar.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
@ -19,9 +17,8 @@ namespace
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
TitleBar::TitleBar(HWND hwnd, HDC compatDc)
|
||||
TitleBar::TitleBar(HWND hwnd)
|
||||
: m_hwnd(hwnd)
|
||||
, m_compatDc(compatDc)
|
||||
, m_buttonWidth(0)
|
||||
, m_buttonHeight(0)
|
||||
, m_tbi{}
|
||||
@ -75,26 +72,26 @@ namespace Gdi
|
||||
}
|
||||
}
|
||||
|
||||
void TitleBar::drawAll() const
|
||||
void TitleBar::drawAll(HDC dc) const
|
||||
{
|
||||
drawCaption();
|
||||
drawButtons();
|
||||
drawCaption(dc);
|
||||
drawButtons(dc);
|
||||
}
|
||||
|
||||
void TitleBar::drawButtons() const
|
||||
void TitleBar::drawButtons(HDC dc) const
|
||||
{
|
||||
if (!m_hasTitleBar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
drawButton(TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN);
|
||||
drawButton(TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
|
||||
drawButton(TBII_HELP_BUTTON, DFCS_CAPTIONHELP);
|
||||
drawButton(TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE);
|
||||
drawButton(dc, TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN);
|
||||
drawButton(dc, TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
|
||||
drawButton(dc, TBII_HELP_BUTTON, DFCS_CAPTIONHELP);
|
||||
drawButton(dc, TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE);
|
||||
}
|
||||
|
||||
void TitleBar::drawCaption() const
|
||||
void TitleBar::drawCaption(HDC dc) const
|
||||
{
|
||||
if (!m_hasTitleBar)
|
||||
{
|
||||
@ -111,20 +108,15 @@ namespace Gdi
|
||||
flags |= DC_GRADIENT;
|
||||
}
|
||||
|
||||
RECT virtualScreenBounds = VirtualScreen::getBounds();
|
||||
RECT clipRect = m_tbi.rcTitleBar;
|
||||
OffsetRect(&clipRect, m_windowRect.left - virtualScreenBounds.left, m_windowRect.top - virtualScreenBounds.top);
|
||||
Region clipRgn(clipRect);
|
||||
SelectClipRgn(m_compatDc, clipRgn);
|
||||
CALL_ORIG_FUNC(DrawCaption)(m_hwnd, m_compatDc, &m_tbi.rcTitleBar, flags);
|
||||
SelectClipRgn(m_compatDc, nullptr);
|
||||
SelectClipRgn(dc, Region(m_tbi.rcTitleBar));
|
||||
DrawCaption(m_hwnd, dc, &m_tbi.rcTitleBar, flags);
|
||||
SelectClipRgn(dc, nullptr);
|
||||
|
||||
if (m_hasIcon)
|
||||
{
|
||||
RECT r = m_tbi.rcTitleBar;
|
||||
r.right = r.left + r.bottom - r.top;
|
||||
CALL_ORIG_FUNC(FillRect)(m_compatDc, &r,
|
||||
GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
|
||||
FillRect(dc, &r, GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
|
||||
|
||||
HICON icon = reinterpret_cast<HICON>(SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 96));
|
||||
if (!icon)
|
||||
@ -135,11 +127,11 @@ namespace Gdi
|
||||
int height = GetSystemMetrics(SM_CYSMICON);
|
||||
int x = r.left + (r.right - r.left - width) / 2 + 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))
|
||||
{
|
||||
@ -157,16 +149,7 @@ namespace Gdi
|
||||
}
|
||||
|
||||
RECT rect = m_tbi.rgrect[tbiIndex];
|
||||
CALL_ORIG_FUNC(DrawFrameControl)(m_compatDc, &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);
|
||||
}
|
||||
DrawFrameControl(dc, &rect, DFC_CAPTION, dfcState | stateFlags);
|
||||
}
|
||||
|
||||
bool TitleBar::isVisible(std::size_t tbiIndex) const
|
||||
|
@ -9,19 +9,17 @@ namespace Gdi
|
||||
class TitleBar
|
||||
{
|
||||
public:
|
||||
TitleBar(HWND hwnd, HDC compatDc);
|
||||
TitleBar(HWND hwnd);
|
||||
|
||||
void drawAll() const;
|
||||
void drawButtons() const;
|
||||
void drawCaption() const;
|
||||
void excludeFromClipRegion() const;
|
||||
void drawAll(HDC dc) const;
|
||||
void drawButtons(HDC dc) const;
|
||||
void drawCaption(HDC dc) const;
|
||||
|
||||
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;
|
||||
|
||||
HWND m_hwnd;
|
||||
HDC m_compatDc;
|
||||
int m_buttonWidth;
|
||||
int m_buttonHeight;
|
||||
TITLEBARINFOEX m_tbi;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <Gdi/AccessGuard.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
#include <Gdi/ScrollFunctions.h>
|
||||
#include <Gdi/TitleBar.h>
|
||||
@ -134,6 +133,15 @@ namespace
|
||||
{
|
||||
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:
|
||||
return onNcActivate(hwnd, wParam, lParam);
|
||||
|
||||
@ -151,12 +159,13 @@ namespace
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
{
|
||||
LRESULT result = origDefWindowProc(hwnd, msg, wParam, lParam);
|
||||
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)
|
||||
{
|
||||
if (hwnd)
|
||||
{
|
||||
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);
|
||||
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND,
|
||||
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), 0);
|
||||
}
|
||||
|
||||
LRESULT onNcActivate(HWND hwnd, WPARAM /*wParam*/, LPARAM lParam)
|
||||
@ -375,73 +372,29 @@ namespace
|
||||
|
||||
LRESULT onNcPaint(HWND hwnd, WNDPROC origWndProc)
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
HDC windowDc = GetWindowDC(hwnd);
|
||||
HDC compatDc = Gdi::Dc::getDc(windowDc);
|
||||
|
||||
if (compatDc)
|
||||
{
|
||||
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);
|
||||
CallWindowProc(origWndProc, hwnd, WM_PRINT,
|
||||
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(windowDc))), PRF_NONCLIENT);
|
||||
Gdi::TitleBar(hwnd).drawAll(windowDc);
|
||||
ReleaseDC(hwnd, windowDc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
|
||||
{
|
||||
if (!hwnd)
|
||||
{
|
||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||
}
|
||||
|
||||
PAINTSTRUCT paint = {};
|
||||
HDC dc = BeginPaint(hwnd, &paint);
|
||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
|
||||
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), PRF_CLIENT);
|
||||
EndPaint(hwnd, &paint);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc)
|
||||
{
|
||||
LRESULT result = 0;
|
||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||
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;
|
||||
return CallWindowProc(origWndProc, hwnd, msg,
|
||||
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), flags);
|
||||
}
|
||||
|
||||
LRESULT onSetText(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||
@ -459,6 +412,13 @@ namespace
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
Gdi::ScrollBar sb(hwnd, SB_CTL);
|
||||
sb.onLButtonDown(lParam);
|
||||
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
return onPaint(hwnd, origWndProc);
|
||||
|
||||
@ -468,10 +428,9 @@ namespace
|
||||
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
||||
}
|
||||
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)
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <Common/Log.h>
|
||||
#include <Common/ScopedSrwLock.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <Gdi/AccessGuard.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
@ -34,6 +34,7 @@ namespace
|
||||
|
||||
WindowProc getWindowProc(HWND hwnd);
|
||||
bool isTopLevelWindow(HWND hwnd);
|
||||
bool isUser32ScrollBar(HWND hwnd);
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void onDestroyWindow(HWND hwnd);
|
||||
void onWindowPosChanged(HWND hwnd);
|
||||
@ -64,6 +65,14 @@ namespace
|
||||
|
||||
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:
|
||||
onDestroyWindow(hwnd);
|
||||
break;
|
||||
@ -153,6 +162,25 @@ namespace
|
||||
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(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
@ -177,33 +205,38 @@ namespace
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject)
|
||||
switch (idObject)
|
||||
{
|
||||
if (!hwnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
case OBJID_TITLEBAR:
|
||||
{
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
Gdi::TitleBar(hwnd).drawButtons(dc);
|
||||
ReleaseDC(hwnd, dc);
|
||||
break;
|
||||
}
|
||||
|
||||
HDC windowDc = GetWindowDC(hwnd);
|
||||
HDC compatDc = Gdi::Dc::getDc(windowDc);
|
||||
if (compatDc)
|
||||
case OBJID_CLIENT:
|
||||
if (!isUser32ScrollBar(hwnd))
|
||||
{
|
||||
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
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, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
|
||||
|
||||
CoInitialize(nullptr);
|
||||
g_objectCreateEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
|
||||
Dll::g_currentModule, &objectCreateEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
|
||||
|
@ -83,7 +83,7 @@ namespace
|
||||
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);
|
||||
ReleaseDC(nullptr, screenDc);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -346,6 +346,13 @@ std::ostream& operator<<(std::ostream& os, const POINT& p)
|
||||
<< 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)
|
||||
{
|
||||
return Compat::LogStruct(os)
|
||||
|
@ -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 NMHDR& nm);
|
||||
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 SIZE& size);
|
||||
std::ostream& operator<<(std::ostream& os, const STYLESTRUCT& ss);
|
||||
|
Loading…
x
Reference in New Issue
Block a user