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

Added FullscreenMode setting

This commit is contained in:
narzoul 2022-04-08 16:13:31 +02:00
parent fb9f28456e
commit 55eab96f78
22 changed files with 327 additions and 96 deletions

View File

@ -11,6 +11,7 @@ namespace Config
Settings::DisplayRefreshRate displayRefreshRate;
Settings::DisplayResolution displayResolution;
Settings::ForceD3D9On12 forceD3D9On12;
Settings::FullscreenMode fullscreenMode;
Settings::RenderColorDepth renderColorDepth;
Settings::ResolutionScale resolutionScale;
Settings::SpriteDetection spriteDetection;

View File

@ -9,6 +9,7 @@
#include <Config/Settings/DisplayRefreshRate.h>
#include <Config/Settings/DisplayResolution.h>
#include <Config/Settings/ForceD3D9On12.h>
#include <Config/Settings/FullscreenMode.h>
#include <Config/Settings/RenderColorDepth.h>
#include <Config/Settings/ResolutionScale.h>
#include <Config/Settings/SpriteDetection.h>
@ -32,6 +33,7 @@ namespace Config
extern Settings::DisplayRefreshRate displayRefreshRate;
extern Settings::DisplayResolution displayResolution;
extern Settings::ForceD3D9On12 forceD3D9On12;
extern Settings::FullscreenMode fullscreenMode;
extern Settings::RenderColorDepth renderColorDepth;
extern Settings::ResolutionScale resolutionScale;
extern Settings::SpriteDetection spriteDetection;

View File

@ -0,0 +1,21 @@
#pragma once
#include <Config/MappedSetting.h>
namespace Config
{
namespace Settings
{
class FullscreenMode : public MappedSetting<UINT>
{
public:
static const UINT BORDERLESS = 0;
static const UINT EXCLUSIVE = 1;
FullscreenMode()
: MappedSetting("FullscreenMode", "borderless", { {"borderless", BORDERLESS}, {"exclusive", EXCLUSIVE} })
{
}
};
}
}

View File

@ -1,6 +1,10 @@
#include <functional>
#include <set>
#include <Windows.h>
#include <winternl.h>
#include <d3dkmthk.h>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <D3dDdi/Adapter.h>
@ -9,6 +13,7 @@
#include <D3dDdi/Hooks.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <D3dDdi/Log/KernelModeThunksLog.h>
#include <Dll/Dll.h>
std::ostream& operator<<(std::ostream& os, const D3DDDIARG_OPENADAPTER& data)
@ -28,26 +33,36 @@ namespace
typedef HRESULT(APIENTRY* PFND3D9ON12_OPENADAPTER)(
D3DDDIARG_OPENADAPTER* pOpenAdapter, LUID* pLUID, D3D9ON12_CREATE_DEVICE_ARGS* pArgs);
typedef HRESULT(APIENTRY* PFND3D9ON12_KMTPRESENT)(
HANDLE hDevice, D3DKMT_PRESENT* pKMTArgs);
struct D3D9ON12_PRIVATE_DDI_TABLE
{
PFND3D9ON12_OPENADAPTER pfnOpenAdapter;
FARPROC pfnGetSharedGDIHandle;
FARPROC pfnCreateSharedNTHandle;
FARPROC pfnGetDeviceState;
PFND3D9ON12_KMTPRESENT pfnKMTPresent;
};
void APIENTRY getPrivateDdiTable(D3D9ON12_PRIVATE_DDI_TABLE* pPrivateDDITable);
HRESULT APIENTRY kmtPresent(HANDLE hDevice, D3DKMT_PRESENT* pKMTArgs);
HRESULT APIENTRY openAdapter(D3DDDIARG_OPENADAPTER* pOpenData);
HRESULT APIENTRY openAdapterPrivate(D3DDDIARG_OPENADAPTER* pOpenData, LUID* pLUID, D3D9ON12_CREATE_DEVICE_ARGS* pArgs);
decltype(&getPrivateDdiTable) g_origGetPrivateDdiTable = nullptr;
PFND3DDDI_OPENADAPTER g_origOpenAdapter = nullptr;
PFND3D9ON12_OPENADAPTER g_origOpenAdapterPrivate = nullptr;
PFND3D9ON12_KMTPRESENT g_origKmtPresent = nullptr;
void APIENTRY getPrivateDdiTable(D3D9ON12_PRIVATE_DDI_TABLE* pPrivateDDITable)
{
LOG_FUNC("GetPrivateDDITable", pPrivateDDITable);
g_origGetPrivateDdiTable(pPrivateDDITable);
g_origOpenAdapterPrivate = pPrivateDDITable->pfnOpenAdapter;
g_origKmtPresent = pPrivateDDITable->pfnKMTPresent;
pPrivateDDITable->pfnOpenAdapter = &openAdapterPrivate;
pPrivateDDITable->pfnKMTPresent = &kmtPresent;
}
FARPROC WINAPI getProcAddress(HMODULE hModule, LPCSTR lpProcName)
@ -84,6 +99,13 @@ namespace
return LOG_RESULT(CALL_ORIG_FUNC(GetProcAddress)(hModule, lpProcName));
}
HRESULT APIENTRY kmtPresent(HANDLE hDevice, D3DKMT_PRESENT* pKMTArgs)
{
LOG_FUNC("KMTPresent", hDevice, pKMTArgs);
D3dDdi::KernelModeThunks::fixPresent(*pKMTArgs);
return LOG_RESULT(g_origKmtPresent(hDevice, pKMTArgs));
}
HRESULT openAdapterCommon(D3DDDIARG_OPENADAPTER* pOpenData, std::function<HRESULT()> origOpenAdapter)
{
D3dDdi::ScopedCriticalSection lock;

View File

@ -18,6 +18,7 @@
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/Palette.h>
#include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
namespace
@ -28,6 +29,8 @@ namespace
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
Compat::SrwLock g_adapterInfoSrwLock;
std::string g_lastDDrawDeviceName;
decltype(&D3DKMTSubmitPresentBltToHwQueue) g_origSubmitPresentBltToHwQueue = nullptr;
decltype(&D3DKMTSubmitPresentToHwQueue) g_origSubmitPresentToHwQueue = nullptr;
long long g_qpcLastVsync = 0;
UINT g_vsyncCounter = 0;
@ -199,6 +202,13 @@ namespace
}
}
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
{
LOG_FUNC("D3DKMTPresent", pData);
D3dDdi::KernelModeThunks::fixPresent(*pData);
return LOG_RESULT(D3DKMTPresent(pData));
}
NTSTATUS APIENTRY queryAdapterInfo(const D3DKMT_QUERYADAPTERINFO* pData)
{
LOG_FUNC("D3DKMTQueryAdapterInfo", pData);
@ -251,6 +261,20 @@ namespace
return LOG_RESULT(result);
}
NTSTATUS APIENTRY submitPresentToHwQueue(D3DKMT_SUBMITPRESENTTOHWQUEUE* pData)
{
LOG_FUNC("D3DKMTSubmitPresentToHwQueue", pData);
D3dDdi::KernelModeThunks::fixPresent(pData->PrivatePresentData);
return LOG_RESULT(g_origSubmitPresentToHwQueue(pData));
}
NTSTATUS APIENTRY submitPresentBltToHwQueue(const D3DKMT_SUBMITPRESENTBLTTOHWQUEUE* pData)
{
LOG_FUNC("D3DKMTSubmitPresentBltToHwQueue", pData);
D3dDdi::KernelModeThunks::fixPresent(const_cast<D3DKMT_PRESENT&>(pData->PrivatePresentData));
return LOG_RESULT(g_origSubmitPresentBltToHwQueue(pData));
}
void updateGdiAdapterInfo()
{
static auto lastDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
@ -331,6 +355,27 @@ namespace D3dDdi
{
namespace KernelModeThunks
{
void fixPresent(D3DKMT_PRESENT& data)
{
static RECT rect = {};
if (DDraw::RealPrimarySurface::isFullscreen())
{
HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow();
if (devicePresentationWindow && devicePresentationWindow == data.hWindow)
{
rect = DDraw::RealPrimarySurface::getMonitorRect();
OffsetRect(&rect, -rect.left, -rect.top);
data.SrcRect = rect;
data.DstRect.right = data.DstRect.left + rect.right;
data.DstRect.bottom = data.DstRect.top + rect.bottom;
if (1 == data.SubRectCnt)
{
data.pSrcSubRects = &rect;
}
}
}
}
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd)
{
DDraw::ScopedThreadLock lock;
@ -359,12 +404,19 @@ namespace D3dDdi
void installHooks()
{
g_origSubmitPresentBltToHwQueue = reinterpret_cast<decltype(&D3DKMTSubmitPresentBltToHwQueue)>(
GetProcAddress(GetModuleHandle("gdi32"), "D3DKMTSubmitPresentBltToHwQueue"));
g_origSubmitPresentToHwQueue = reinterpret_cast<decltype(&D3DKMTSubmitPresentToHwQueue)>(
GetProcAddress(GetModuleHandle("gdi32"), "D3DKMTSubmitPresentToHwQueue"));
Compat::hookIatFunction(Dll::g_origDDrawModule, "CreateDCA", ddrawCreateDcA);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCloseAdapter", closeAdapter);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCreateDCFromMemory", createDcFromMemory);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTPresent", present);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetGammaRamp", setGammaRamp);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSubmitPresentToHwQueue", submitPresentToHwQueue);
Dll::createThread(&vsyncThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
}

View File

@ -1,5 +1,9 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <d3dkmthk.h>
#include <ddraw.h>
#include <Common/CompatRef.h>
@ -16,6 +20,7 @@ namespace D3dDdi
MONITORINFOEXW monitorInfo;
};
void fixPresent(D3DKMT_PRESENT& data);
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd);
AdapterInfo getLastOpenAdapterInfo();
long long getQpcLastVsync();

View File

@ -163,3 +163,18 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER1& da
<< data.Version0
<< Compat::hex(data.Flags.Value);
}
std::ostream& operator<<(std::ostream& os, const D3DKMT_SUBMITPRESENTTOHWQUEUE& data)
{
return Compat::LogStruct(os)
<< Compat::array(data.hHwQueues, data.PrivatePresentData.BroadcastContextCount + 1)
<< data.PrivatePresentData;
}
std::ostream& operator<<(std::ostream& os, const D3DKMT_SUBMITPRESENTBLTTOHWQUEUE& data)
{
return Compat::LogStruct(os)
<< Compat::hex(data.hHwQueue)
<< Compat::hex(data.HwQueueProgressFenceId)
<< data.PrivatePresentData;
}

View File

@ -23,3 +23,5 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_SETGAMMARAMP& data);
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data);
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER& data);
std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER1& data);
std::ostream& operator<<(std::ostream& os, const D3DKMT_SUBMITPRESENTTOHWQUEUE& data);
std::ostream& operator<<(std::ostream& os, const D3DKMT_SUBMITPRESENTBLTTOHWQUEUE& data);

View File

@ -126,7 +126,7 @@ namespace D3dDdi
throw HResultException(E_FAIL);
}
if (m_origData.Flags.Primary)
if (m_origData.Flags.MatchGdiPrimary)
{
g_presentationRect = calculatePresentationRect();
auto& si = m_origData.pSurfList[0];
@ -175,7 +175,7 @@ namespace D3dDdi
Resource::~Resource()
{
if (m_origData.Flags.Primary)
if (m_origData.Flags.MatchGdiPrimary)
{
Gdi::VirtualScreen::setFullscreenMode(false);
Gdi::Cursor::setEmulated(false);
@ -215,7 +215,7 @@ namespace D3dDdi
if (srcResource)
{
if (m_fixedData.Flags.Primary)
if (m_fixedData.Flags.MatchGdiPrimary)
{
return presentationBlt(data, srcResource);
}
@ -486,7 +486,7 @@ namespace D3dDdi
void Resource::fixResourceData()
{
if (m_fixedData.Flags.Primary)
if (m_fixedData.Flags.MatchGdiPrimary)
{
RECT r = DDraw::RealPrimarySurface::getMonitorRect();
if (!IsRectEmpty(&r))
@ -538,7 +538,7 @@ namespace D3dDdi
D3DDDIFORMAT Resource::getFormatConfig()
{
if (m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Primary && D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool &&
if (m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.MatchGdiPrimary && D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool &&
(D3DDDIFMT_X8R8G8B8 == m_fixedData.Format || D3DDDIFMT_R5G6B5 == m_fixedData.Format))
{
switch (Config::renderColorDepth.get())
@ -552,7 +552,7 @@ namespace D3dDdi
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> Resource::getMultisampleConfig()
{
if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.Primary ||
if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.MatchGdiPrimary ||
m_fixedData.Flags.ZBuffer) &&
D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool)
{
@ -570,7 +570,7 @@ namespace D3dDdi
SIZE Resource::getScaledSize()
{
SIZE size = { static_cast<LONG>(m_fixedData.pSurfList[0].Width), static_cast<LONG>(m_fixedData.pSurfList[0].Height) };
if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.Primary ||
if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.MatchGdiPrimary ||
m_fixedData.Flags.ZBuffer) &&
D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool)
{

View File

@ -15,9 +15,9 @@ namespace DDraw
void suppressEmulatedDirectDraw(GUID*& guid);
template <typename TDirectDraw>
HWND getDeviceWindow(TDirectDraw& dd)
HWND* getDeviceWindowPtr(TDirectDraw& dd)
{
return reinterpret_cast<HWND**>(&dd)[1][8];
return &reinterpret_cast<HWND**>(&dd)[1][8];
}
template <typename Vtable>

View File

@ -45,6 +45,9 @@ namespace
std::atomic<long long> g_qpcLastUpdate = 0;
UINT g_flipEndVsyncCount = 0;
UINT g_presentEndVsyncCount = 0;
HWND g_devicePresentationWindow = nullptr;
HWND g_deviceWindow = nullptr;
HWND* g_deviceWindowPtr = nullptr;
CompatPtr<IDirectDrawSurface7> getBackBuffer();
CompatPtr<IDirectDrawSurface7> getLastSurface();
@ -128,6 +131,11 @@ namespace
g_isFullscreen = false;
g_waitingForPrimaryUnlock = false;
g_surfaceDesc = {};
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
g_devicePresentationWindow = nullptr;
g_deviceWindow = nullptr;
g_deviceWindowPtr = nullptr;
g_monitorRect = {};
}
@ -200,9 +208,11 @@ namespace
g_isUpdatePending = false;
g_waitingForPrimaryUnlock = false;
if (g_isFullscreen)
if (g_isFullscreen && g_devicePresentationWindow)
{
*g_deviceWindowPtr = g_devicePresentationWindow;
g_frontBuffer->Flip(g_frontBuffer, getBackBuffer(), DDFLIP_WAIT);
*g_deviceWindowPtr = g_deviceWindow;
}
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + max(flipInterval, 1);
}
@ -296,7 +306,13 @@ namespace DDraw
g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach();
g_frontBuffer->SetPrivateData(g_frontBuffer, IID_IReleaseNotifier,
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
g_deviceWindowPtr = DDraw::DirectDraw::getDeviceWindowPtr(dd.get());
g_deviceWindow = g_deviceWindowPtr ? *g_deviceWindowPtr : nullptr;
g_devicePresentationWindow = Gdi::Window::getPresentationWindow(g_deviceWindow);
onRestore();
updateDevicePresentationWindowPos();
return DD_OK;
}
@ -354,6 +370,11 @@ namespace DDraw
}
}
HWND RealPrimarySurface::getDevicePresentationWindow()
{
return g_devicePresentationWindow;
}
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
{
DDraw::ScopedThreadLock lock;
@ -376,6 +397,15 @@ namespace DDraw
return g_frontBuffer;
}
HWND RealPrimarySurface::getTopmost()
{
if (g_isFullscreen && g_devicePresentationWindow)
{
return g_devicePresentationWindow;
}
return HWND_TOPMOST;
}
void RealPrimarySurface::init()
{
Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
@ -438,6 +468,28 @@ namespace DDraw
}
}
void RealPrimarySurface::updateDevicePresentationWindowPos()
{
if (!g_devicePresentationWindow)
{
return;
}
Gdi::GuiThread::execute([&]()
{
if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow))
{
CALL_ORIG_FUNC(SetWindowPos)(g_devicePresentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW);
}
else
{
Gdi::Window::updatePresentationWindowPos(g_devicePresentationWindow, g_deviceWindow);
}
});
}
bool RealPrimarySurface::waitForFlip(Surface* surface)
{
auto primary(DDraw::PrimarySurface::getPrimary());

View File

@ -17,9 +17,11 @@ namespace DDraw
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static void flush();
static HWND getDevicePresentationWindow();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static RECT getMonitorRect();
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
static HWND getTopmost();
static void init();
static bool isFullscreen();
static bool isLost();
@ -28,6 +30,7 @@ namespace DDraw
static void scheduleUpdate();
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
static void update();
static void updateDevicePresentationWindowPos();
static bool waitForFlip(Surface* surface);
};
}

View File

@ -80,7 +80,7 @@ namespace DDraw
}
g_origCaps = origCaps;
g_deviceWindow = DDraw::DirectDraw::getDeviceWindow(dd.get());
g_deviceWindow = *DDraw::DirectDraw::getDeviceWindowPtr(dd.get());
if (desc.ddpfPixelFormat.dwRGBBitCount <= 8)
{

View File

@ -226,6 +226,7 @@
<ClInclude Include="Config\Settings\DisplayRefreshRate.h" />
<ClInclude Include="Config\Settings\DisplayResolution.h" />
<ClInclude Include="Config\Settings\ForceD3D9On12.h" />
<ClInclude Include="Config\Settings\FullscreenMode.h" />
<ClInclude Include="Config\Settings\RenderColorDepth.h" />
<ClInclude Include="Config\Settings\ResolutionScale.h" />
<ClInclude Include="Config\Settings\SpriteDetection.h" />

View File

@ -540,6 +540,9 @@
<ClInclude Include="Config\Settings\ForceD3D9On12.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\FullscreenMode.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">

View File

@ -239,8 +239,11 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Time::init();
Win32::Thread::applyConfig();
const DWORD disableMaxWindowedMode = 12;
CALL_ORIG_PROC(SetAppCompatData)(disableMaxWindowedMode, 0);
if (Config::Settings::FullscreenMode::EXCLUSIVE == Config::fullscreenMode.get())
{
const DWORD disableMaxWindowedMode = 12;
CALL_ORIG_PROC(SetAppCompatData)(disableMaxWindowedMode, 0);
}
Compat::Log() << "DDrawCompat loaded successfully";
}

View File

@ -9,6 +9,7 @@
#include <Gdi/TitleBar.h>
#include <Gdi/User32WndProcs.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h>
std::ostream& operator<<(std::ostream& os, const MENUITEMINFOW& val)
@ -249,6 +250,21 @@ namespace
}
return FALSE;
}
case WM_SETREDRAW:
{
if (Gdi::Window::isTopLevelWindow(hwnd))
{
BOOL isVisible = IsWindowVisible(hwnd);
auto result = origDefWindowProc(hwnd, msg, wParam, lParam);
if (isVisible != IsWindowVisible(hwnd))
{
Gdi::Window::updateAll();
}
return result;
}
break;
}
}
return defPaintProc(hwnd, msg, wParam, lParam, origDefWindowProc);

View File

@ -38,7 +38,6 @@ namespace
std::map<HWND, WindowProc> g_windowProc;
WindowProc getWindowProc(HWND hwnd);
bool isTopLevelWindow(HWND hwnd);
bool isUser32ScrollBar(HWND hwnd);
void onDestroyWindow(HWND hwnd);
void onGetMinMaxInfo(MINMAXINFO& mmi);
@ -72,7 +71,7 @@ namespace
break;
case WM_SYNCPAINT:
if (isTopLevelWindow(hwnd))
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::onSyncPaint(hwnd);
return 0;
@ -124,7 +123,7 @@ namespace
break;
case WM_STYLECHANGED:
if (isTopLevelWindow(hwnd))
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::onStyleChanged(hwnd, wParam);
}
@ -181,11 +180,6 @@ namespace
return g_windowProc[hwnd];
}
bool isTopLevelWindow(HWND hwnd)
{
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
}
bool isUser32ScrollBar(HWND hwnd)
{
WNDCLASS wc = {};
@ -207,7 +201,7 @@ namespace
void onDestroyWindow(HWND hwnd)
{
if (isTopLevelWindow(hwnd))
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::updateAll();
return;
@ -272,7 +266,7 @@ namespace
notifyFunc();
}
if (isTopLevelWindow(hwnd))
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::updateAll();
}
@ -286,7 +280,7 @@ namespace
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp)
{
if (isTopLevelWindow(hwnd))
if (Gdi::Window::isTopLevelWindow(hwnd))
{
wp.flags |= SWP_NOREDRAW;
}
@ -499,7 +493,7 @@ namespace Gdi
setWindowProc(hwnd, ddcWindowProcA, ddcWindowProcW);
}
if (!isTopLevelWindow(hwnd))
if (!Gdi::Window::isTopLevelWindow(hwnd))
{
return;
}

View File

@ -355,36 +355,15 @@ namespace
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
}
WINDOWPOS wp = {};
wp.flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING;
if (isVisible)
const HWND devicePresentationWindow = DDraw::RealPrimarySurface::getDevicePresentationWindow();
if (DDraw::RealPrimarySurface::isFullscreen() && devicePresentationWindow == it->second.presentationWindow)
{
wp.hwndInsertAfter = GetWindow(hwnd, GW_HWNDPREV);
if (!wp.hwndInsertAfter)
{
wp.hwndInsertAfter = (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP;
}
else if (wp.hwndInsertAfter == it->second.presentationWindow)
{
wp.flags |= SWP_NOZORDER;
}
wp.x = it->second.windowRect.left;
wp.y = it->second.windowRect.top;
wp.cx = it->second.windowRect.right - it->second.windowRect.left;
wp.cy = it->second.windowRect.bottom - it->second.windowRect.top;
wp.flags |= SWP_SHOWWINDOW;
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
}
else
{
wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
}
Gdi::GuiThread::execute([&]()
{
CALL_ORIG_FUNC(SetWindowPos)(it->second.presentationWindow,
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
});
}
}
return TRUE;
@ -395,6 +374,56 @@ namespace Gdi
{
namespace Window
{
HWND getPresentationWindow(HWND hwnd)
{
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(hwnd);
return it != g_windows.end() ? it->second.presentationWindow : nullptr;
}
std::vector<LayeredWindow> getVisibleLayeredWindows()
{
std::vector<LayeredWindow> layeredWindows;
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{
auto& window = **it;
if (window.isLayered && !window.visibleRegion.isEmpty())
{
layeredWindows.push_back({ window.hwnd, window.windowRect, window.visibleRegion });
}
}
RECT wr = {};
auto configWindow = GuiThread::getConfigWindow();
if (configWindow && configWindow->isVisible())
{
GetWindowRect(configWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(configWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion });
auto capture = Input::getCaptureWindow();
if (capture && capture != configWindow)
{
GetWindowRect(capture->getWindow(), &wr);
layeredWindows.push_back({ capture->getWindow(), wr, nullptr });
}
}
HWND cursorWindow = Input::getCursorWindow();
if (cursorWindow)
{
GetWindowRect(cursorWindow, &wr);
layeredWindows.push_back({ cursorWindow, wr, nullptr });
}
return layeredWindows;
}
bool isTopLevelWindow(HWND hwnd)
{
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
}
void onStyleChanged(HWND hwnd, WPARAM wParam)
{
if (GWL_EXSTYLE == wParam)
@ -516,44 +545,6 @@ namespace Gdi
}
}
std::vector<LayeredWindow> getVisibleLayeredWindows()
{
std::vector<LayeredWindow> layeredWindows;
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{
auto& window = **it;
if (window.isLayered && !window.visibleRegion.isEmpty())
{
layeredWindows.push_back({ window.hwnd, window.windowRect, window.visibleRegion });
}
}
RECT wr = {};
auto configWindow = GuiThread::getConfigWindow();
if (configWindow && configWindow->isVisible())
{
GetWindowRect(configWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(configWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion });
auto capture = Input::getCaptureWindow();
if (capture && capture != configWindow)
{
GetWindowRect(capture->getWindow(), &wr);
layeredWindows.push_back({ capture->getWindow(), wr, nullptr });
}
}
HWND cursorWindow = Input::getCursorWindow();
if (cursorWindow)
{
GetWindowRect(cursorWindow, &wr);
layeredWindows.push_back({ cursorWindow, wr, nullptr });
}
return layeredWindows;
}
void updateAll()
{
LOG_FUNC("Window::updateAll");
@ -603,5 +594,44 @@ namespace Gdi
SendNotifyMessage(hwnd, WM_SYNCPAINT, 0, 0);
}
}
void updatePresentationWindowPos(HWND presentationWindow, HWND owner)
{
const bool isOwnerVisible = IsWindowVisible(owner) && !IsIconic(owner);
WINDOWPOS wp = {};
wp.flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING;
if (isOwnerVisible)
{
wp.hwndInsertAfter = GetWindow(owner, GW_HWNDPREV);
if (!wp.hwndInsertAfter)
{
wp.hwndInsertAfter = (GetWindowLong(owner, GWL_EXSTYLE) & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP;
}
else if (wp.hwndInsertAfter == presentationWindow)
{
wp.flags |= SWP_NOZORDER;
}
RECT wr = {};
GetWindowRect(owner, &wr);
wp.x = wr.left;
wp.y = wr.top;
wp.cx = wr.right - wr.left;
wp.cy = wr.bottom - wr.top;
wp.flags |= SWP_SHOWWINDOW;
}
else
{
wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
}
Gdi::GuiThread::execute([&]()
{
CALL_ORIG_FUNC(SetWindowPos)(presentationWindow,
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
});
}
}
}

View File

@ -17,12 +17,15 @@ namespace Gdi
Gdi::Region region;
};
HWND getPresentationWindow(HWND hwnd);
std::vector<LayeredWindow> getVisibleLayeredWindows();
bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);
void updateAll();
void updatePresentationWindowPos(HWND presentationWindow, HWND owner);
}
}

View File

@ -285,8 +285,9 @@ namespace Input
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY);
g_cursorPos = { (g_monitorRect.left + g_monitorRect.right) / 2, (g_monitorRect.top + g_monitorRect.bottom) / 2 };
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y,
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, DDraw::RealPrimarySurface::getTopmost(),
g_cursorPos.x, g_cursorPos.y, g_bmpArrowSize.cx, g_bmpArrowSize.cy,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
g_capture->onMouseMove(getRelativeCursorPos());
resetMouseHook();
@ -305,8 +306,9 @@ namespace Input
{
Gdi::GuiThread::execute([]()
{
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y,
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING);
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, DDraw::RealPrimarySurface::getTopmost(),
g_cursorPos.x, g_cursorPos.y, g_bmpArrowSize.cx, g_bmpArrowSize.cy,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING);
});
}
}

View File

@ -122,7 +122,6 @@ namespace Overlay
if (m_style & WS_VISIBLE)
{
updatePos();
ShowWindow(m_hwnd, SW_SHOWNA);
Input::setCapture(this);
}
else
@ -214,8 +213,10 @@ namespace Overlay
m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor,
monitorRect.right / m_scaleFactor, monitorRect.bottom / m_scaleFactor });
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, HWND_TOPMOST, m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, SWP_NOACTIVATE);
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, DDraw::RealPrimarySurface::getTopmost(),
m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
if (Input::getCaptureWindow() == this)
{
@ -230,7 +231,10 @@ namespace Overlay
switch (uMsg)
{
case WM_DISPLAYCHANGE:
updatePos();
if (m_style & WS_VISIBLE)
{
updatePos();
}
break;
}