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

Fixed various alt-tabbing issues

This commit is contained in:
narzoul 2016-12-13 22:27:01 +01:00
parent d898961a7e
commit 5b5863b028
12 changed files with 93 additions and 160 deletions

View File

@ -3,6 +3,7 @@
#include "D3dDdi/DeviceFuncs.h" #include "D3dDdi/DeviceFuncs.h"
#include "D3dDdi/LockResource.h" #include "D3dDdi/LockResource.h"
#include "D3dDdi/KernelModeThunks.h"
namespace namespace
{ {
@ -11,6 +12,7 @@ namespace
HANDLE device; HANDLE device;
HANDLE resource; HANDLE resource;
Resource() : device(nullptr), resource(nullptr) {}
Resource(HANDLE device, HANDLE resource) : device(device), resource(resource) {} Resource(HANDLE device, HANDLE resource) : device(device), resource(resource) {}
bool operator<(const Resource& rhs) const bool operator<(const Resource& rhs) const
@ -41,6 +43,7 @@ namespace
std::map<Resource, D3dDdi::LockResource> g_lockResources; std::map<Resource, D3dDdi::LockResource> g_lockResources;
std::map<HANDLE, D3dDdi::LockResource::SubResource*> g_renderTargets; std::map<HANDLE, D3dDdi::LockResource::SubResource*> g_renderTargets;
Resource g_sharedPrimary;
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
ResourceReplacer::ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex) ResourceReplacer::ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex)
@ -208,6 +211,13 @@ namespace
HRESULT APIENTRY destroyResource(HANDLE hDevice, HANDLE hResource) HRESULT APIENTRY destroyResource(HANDLE hDevice, HANDLE hResource)
{ {
const bool isSharedPrimary =
hDevice == g_sharedPrimary.device && hResource == g_sharedPrimary.resource;
if (isSharedPrimary)
{
D3dDdi::KernelModeThunks::releaseVidPnSources();
}
HRESULT result = getOrigVtable(hDevice).pfnDestroyResource(hDevice, hResource); HRESULT result = getOrigVtable(hDevice).pfnDestroyResource(hDevice, hResource);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
@ -224,6 +234,11 @@ namespace
getOrigVtable(hDevice).pfnDestroyResource(hDevice, it->second.getHandle()); getOrigVtable(hDevice).pfnDestroyResource(hDevice, it->second.getHandle());
g_lockResources.erase(it); g_lockResources.erase(it);
} }
if (isSharedPrimary)
{
g_sharedPrimary = {};
}
} }
return result; return result;
} }
@ -251,6 +266,16 @@ namespace
return getOrigVtable(hDevice).pfnLock(hDevice, pData); return getOrigVtable(hDevice).pfnLock(hDevice, pData);
} }
HRESULT APIENTRY openResource(HANDLE hDevice, D3DDDIARG_OPENRESOURCE* pResource)
{
HRESULT result = getOrigVtable(hDevice).pfnOpenResource(hDevice, pResource);
if (SUCCEEDED(result) && pResource->Flags.Fullscreen)
{
g_sharedPrimary = Resource(hDevice, pResource->hResource);
}
return result;
}
HRESULT APIENTRY present(HANDLE hDevice, const D3DDDIARG_PRESENT* pData) HRESULT APIENTRY present(HANDLE hDevice, const D3DDDIARG_PRESENT* pData)
{ {
auto it = g_lockResources.find(Resource(hDevice, pData->hSrcResource)); auto it = g_lockResources.find(Resource(hDevice, pData->hSrcResource));
@ -334,6 +359,7 @@ namespace D3dDdi
vtable.pfnDrawRectPatch = &RENDER_FUNC(pfnDrawRectPatch); vtable.pfnDrawRectPatch = &RENDER_FUNC(pfnDrawRectPatch);
vtable.pfnDrawTriPatch = &RENDER_FUNC(pfnDrawTriPatch); vtable.pfnDrawTriPatch = &RENDER_FUNC(pfnDrawTriPatch);
vtable.pfnLock = &lock; vtable.pfnLock = &lock;
vtable.pfnOpenResource = &openResource;
vtable.pfnPresent = &present; vtable.pfnPresent = &present;
vtable.pfnPresent1 = &present1; vtable.pfnPresent1 = &present1;
vtable.pfnSetRenderTarget = &setRenderTarget; vtable.pfnSetRenderTarget = &setRenderTarget;

View File

@ -230,5 +230,18 @@ namespace D3dDdi
HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner, setVidPnSourceOwner); HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner, setVidPnSourceOwner);
HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner1, setVidPnSourceOwner1); HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner1, setVidPnSourceOwner1);
} }
void releaseVidPnSources()
{
for (auto it : g_devices)
{
if (D3DDDI_ID_UNINITIALIZED != it.second.vidPnSourceId)
{
D3DKMT_SETVIDPNSOURCEOWNER vidPnSourceOwner = {};
vidPnSourceOwner.hDevice = it.first;
D3DKMTSetVidPnSourceOwner(&vidPnSourceOwner);
}
}
}
} }
} }

View File

@ -7,5 +7,6 @@ namespace D3dDdi
namespace KernelModeThunks namespace KernelModeThunks
{ {
void installHooks(); void installHooks();
void releaseVidPnSources();
} }
} }

View File

@ -1,116 +1,64 @@
#include "Common/CompatPtr.h" #define CINTERFACE
#include "Common/CompatRef.h"
#include "Common/Log.h" #include <ddraw.h>
#include "Common/Hook.h"
#include "DDraw/ActivateAppHandler.h" #include "DDraw/ActivateAppHandler.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/DisplayMode.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "Gdi/Gdi.h" #include "Gdi/Gdi.h"
#include "Win32/FontSmoothing.h" #include "Win32/FontSmoothing.h"
extern HWND g_mainWindow;
namespace namespace
{ {
bool g_isActive = true;
HWND g_fullScreenCooperativeWindow = nullptr;
DWORD g_fullScreenCooperativeFlags = 0;
Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {}; Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {};
HHOOK g_callWndProcHook = nullptr; WNDPROC g_origDdWndProc = nullptr;
void handleActivateApp(bool isActivated); void activateApp()
void activateApp(CompatRef<IDirectDraw7> dd)
{ {
if (!(g_fullScreenCooperativeFlags & DDSCL_NOWINDOWCHANGES)) Gdi::enableEmulation();
{
ShowWindow(g_fullScreenCooperativeWindow, SW_RESTORE);
HWND lastActivePopup = GetLastActivePopup(g_fullScreenCooperativeWindow);
if (lastActivePopup && lastActivePopup != g_fullScreenCooperativeWindow)
{
BringWindowToTop(lastActivePopup);
}
}
dd->SetCooperativeLevel(&dd, g_fullScreenCooperativeWindow, g_fullScreenCooperativeFlags);
auto dm = DDraw::DisplayMode::getDisplayMode(dd);
dd->SetDisplayMode(&dd, dm.dwWidth, dm.dwHeight, 32, dm.dwRefreshRate, 0);
auto primary(DDraw::PrimarySurface::getPrimary());
if (primary && SUCCEEDED(primary->Restore(primary)))
{
DDraw::SurfaceImpl<IDirectDrawSurface7>::fixSurfacePtrs(*primary);
Gdi::invalidate(nullptr);
}
Win32::FontSmoothing::setSystemSettings(g_fontSmoothingSettings); Win32::FontSmoothing::setSystemSettings(g_fontSmoothingSettings);
} }
void deactivateApp(CompatRef<IDirectDraw7> dd) void deactivateApp()
{ {
dd->RestoreDisplayMode(&dd); Gdi::disableEmulation();
dd->SetCooperativeLevel(&dd, g_fullScreenCooperativeWindow, DDSCL_NORMAL);
if (!(g_fullScreenCooperativeFlags & DDSCL_NOWINDOWCHANGES))
{
ShowWindow(g_fullScreenCooperativeWindow, SW_SHOWMINNOACTIVE);
}
g_fontSmoothingSettings = Win32::FontSmoothing::getSystemSettings(); g_fontSmoothingSettings = Win32::FontSmoothing::getSystemSettings();
Win32::FontSmoothing::setSystemSettings(Win32::FontSmoothing::g_origSystemSettings); Win32::FontSmoothing::setSystemSettings(Win32::FontSmoothing::g_origSystemSettings);
} }
LRESULT CALLBACK callWndProc(int nCode, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK ddWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
auto ret = reinterpret_cast<CWPSTRUCT*>(lParam); static bool isDisplayChangeNotificationEnabled = true;
Compat::LogEnter("callWndProc", nCode, wParam, ret);
if (HC_ACTION == nCode && WM_ACTIVATEAPP == ret->message) switch (uMsg)
{ {
const bool isActivated = TRUE == ret->wParam; case WM_ACTIVATEAPP:
handleActivateApp(isActivated);
}
LRESULT result = CallNextHookEx(nullptr, nCode, wParam, lParam);
Compat::LogLeave("callWndProc", nCode, wParam, ret) << result;
return result;
}
void handleActivateApp(bool isActivated)
{
Compat::LogEnter("handleActivateApp", isActivated);
if (isActivated == g_isActive)
{ {
return; isDisplayChangeNotificationEnabled = false;
} if (TRUE == wParam)
g_isActive = isActivated;
if (!isActivated)
{
Gdi::disableEmulation();
}
auto dd(DDraw::getFullScreenDirectDraw());
if (dd)
{
if (isActivated)
{ {
activateApp(*dd); activateApp();
} }
else else
{ {
deactivateApp(*dd); deactivateApp();
} }
LRESULT result = g_origDdWndProc(hwnd, uMsg, wParam, lParam);
isDisplayChangeNotificationEnabled = true;
return result;
} }
if (isActivated) case WM_DISPLAYCHANGE:
{ {
Gdi::enableEmulation(); // Fix for alt-tabbing in Commandos 2
if (!isDisplayChangeNotificationEnabled)
{
return 0;
}
break;
}
} }
Compat::LogLeave("handleActivateApp", isActivated); return g_origDdWndProc(hwnd, uMsg, wParam, lParam);
} }
} }
@ -118,26 +66,15 @@ namespace DDraw
{ {
namespace ActivateAppHandler namespace ActivateAppHandler
{ {
void installHooks() void setCooperativeLevel(HWND hwnd, DWORD flags)
{ {
const DWORD threadId = GetCurrentThreadId(); static bool isDdWndProcHooked = false;
g_callWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, callWndProc, nullptr, threadId); if ((flags & DDSCL_FULLSCREEN) && !isDdWndProcHooked)
} {
g_origDdWndProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
bool isActive() Compat::hookFunction(reinterpret_cast<void*&>(g_origDdWndProc), ddWndProc);
{ isDdWndProcHooked = true;
return g_isActive; }
}
void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags)
{
g_fullScreenCooperativeWindow = hwnd;
g_fullScreenCooperativeFlags = flags;
}
void uninstallHooks()
{
UnhookWindowsHookEx(g_callWndProcHook);
} }
} }
} }

View File

@ -8,9 +8,6 @@ namespace DDraw
{ {
namespace ActivateAppHandler namespace ActivateAppHandler
{ {
void installHooks(); void setCooperativeLevel(HWND hwnd, DWORD flags);
bool isActive();
void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags);
void uninstallHooks();
} }
} }

View File

@ -1,17 +1,12 @@
#include "Common/CompatPtr.h" #include "Common/CompatPtr.h"
#include "Common/CompatRef.h"
#include "DDraw/ActivateAppHandler.h" #include "DDraw/ActivateAppHandler.h"
#include "DDraw/DirectDraw.h" #include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/DisplayMode.h" #include "DDraw/DisplayMode.h"
#include "DDraw/Surfaces/TagSurface.h" #include "DDraw/Surfaces/TagSurface.h"
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/Surface.h"
namespace DDraw namespace DDraw
{ {
TagSurface* g_fullScreenTagSurface = nullptr;
template <typename TDirectDraw> template <typename TDirectDraw>
void* getDdObject(TDirectDraw& dd) void* getDdObject(TDirectDraw& dd)
{ {
@ -23,19 +18,6 @@ namespace DDraw
template void* getDdObject(IDirectDraw4&); template void* getDdObject(IDirectDraw4&);
template void* getDdObject(IDirectDraw7&); template void* getDdObject(IDirectDraw7&);
CompatPtr<IDirectDraw7> getFullScreenDirectDraw()
{
return g_fullScreenTagSurface ? g_fullScreenTagSurface->getDirectDraw() : nullptr;
}
void onRelease(TagSurface& dd)
{
if (&dd == g_fullScreenTagSurface)
{
g_fullScreenTagSurface = nullptr;
}
}
template <typename TDirectDraw> template <typename TDirectDraw>
void DirectDraw<TDirectDraw>::setCompatVtable(Vtable<TDirectDraw>& vtable) void DirectDraw<TDirectDraw>::setCompatVtable(Vtable<TDirectDraw>& vtable)
{ {
@ -130,11 +112,6 @@ namespace DDraw
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::SetCooperativeLevel( HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::SetCooperativeLevel(
TDirectDraw* This, HWND hWnd, DWORD dwFlags) TDirectDraw* This, HWND hWnd, DWORD dwFlags)
{ {
if ((dwFlags & DDSCL_FULLSCREEN) && !ActivateAppHandler::isActive())
{
return DDERR_EXCLUSIVEMODEALREADYSET;
}
HRESULT result = s_origVtable.SetCooperativeLevel(This, hWnd, dwFlags); HRESULT result = s_origVtable.SetCooperativeLevel(This, hWnd, dwFlags);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
@ -147,18 +124,7 @@ namespace DDraw
tagSurface = TagSurface::get(ddObject); tagSurface = TagSurface::get(ddObject);
} }
if (tagSurface) ActivateAppHandler::setCooperativeLevel(hWnd, dwFlags);
{
if (dwFlags & DDSCL_FULLSCREEN)
{
g_fullScreenTagSurface = tagSurface;
ActivateAppHandler::setFullScreenCooperativeLevel(hWnd, dwFlags);
}
else if ((dwFlags & DDSCL_NORMAL) && tagSurface == g_fullScreenTagSurface)
{
g_fullScreenTagSurface = nullptr;
}
}
} }
return result; return result;
} }

View File

@ -1,20 +1,14 @@
#pragma once #pragma once
#include "Common/CompatPtr.h"
#include "Common/CompatVtable.h" #include "Common/CompatVtable.h"
#include "DDraw/Visitors/DirectDrawVtblVisitor.h" #include "DDraw/Visitors/DirectDrawVtblVisitor.h"
#include "DDraw/Types.h" #include "DDraw/Types.h"
namespace DDraw namespace DDraw
{ {
class TagSurface;
template <typename TDirectDraw> template <typename TDirectDraw>
void* getDdObject(TDirectDraw& dd); void* getDdObject(TDirectDraw& dd);
CompatPtr<IDirectDraw7> getFullScreenDirectDraw();
void onRelease(TagSurface& dd);
template <typename TDirectDraw> template <typename TDirectDraw>
class DirectDraw: public CompatVtable<Vtable<TDirectDraw>> class DirectDraw: public CompatVtable<Vtable<TDirectDraw>>
{ {

View File

@ -40,11 +40,16 @@ namespace
targetDevMode.dmDisplayFrequency == currentDevMode.dmDisplayFrequency && targetDevMode.dmDisplayFrequency == currentDevMode.dmDisplayFrequency &&
targetDevMode.dmDisplayFlags == currentDevMode.dmDisplayFlags) targetDevMode.dmDisplayFlags == currentDevMode.dmDisplayFlags)
{ {
HANDLE dwmDxFullScreenTransitionEvent = OpenEventW( LONG result = origChangeDisplaySettings(
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT"); lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
SetEvent(dwmDxFullScreenTransitionEvent); if (SUCCEEDED(result))
CloseHandle(dwmDxFullScreenTransitionEvent); {
return DISP_CHANGE_SUCCESSFUL; HANDLE dwmDxFullScreenTransitionEvent = OpenEventW(
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
SetEvent(dwmDxFullScreenTransitionEvent);
CloseHandle(dwmDxFullScreenTransitionEvent);
}
return result;
} }
} }

View File

@ -108,13 +108,10 @@ namespace DDraw
hookDirectDraw(*dd7); hookDirectDraw(*dd7);
hookDirectDrawSurface(*dd7); hookDirectDrawSurface(*dd7);
hookDirectDrawPalette(*dd7); hookDirectDrawPalette(*dd7);
ActivateAppHandler::installHooks();
} }
void uninstallHooks() void uninstallHooks()
{ {
RealPrimarySurface::removeUpdateThread(); RealPrimarySurface::removeUpdateThread();
ActivateAppHandler::uninstallHooks();
} }
} }

View File

@ -129,7 +129,7 @@ namespace
timeBeginPeriod(1); timeBeginPeriod(1);
g_frontBuffer = surface.detach(); g_frontBuffer = surface.detach();
g_backBuffer = backBuffer.detach(); g_backBuffer = backBuffer;
g_surfaceDesc = desc; g_surfaceDesc = desc;
g_isFullScreen = isFlippable; g_isFullScreen = isFlippable;
@ -149,7 +149,7 @@ namespace
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
timeEndPeriod(1); timeEndPeriod(1);
g_frontBuffer = nullptr; g_frontBuffer = nullptr;
g_backBuffer.release(); g_backBuffer = nullptr;
g_clipper = nullptr; g_clipper = nullptr;
g_isFullScreen = false; g_isFullScreen = false;
DDraw::PaletteConverter::release(); DDraw::PaletteConverter::release();

View File

@ -145,6 +145,7 @@ namespace DDraw
while (SUCCEEDED(result) && next.get() != g_gdiSurface.get() && next.get() != primary) while (SUCCEEDED(result) && next.get() != g_gdiSurface.get() && next.get() != primary)
{ {
current = next; current = next;
next.reset();
result = current->GetAttachedSurface(current, &caps, &next.getRef()); result = current->GetAttachedSurface(current, &caps, &next.getRef());
} }

View File

@ -3,7 +3,6 @@
#include "DDraw/DirectDraw.h" #include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h" #include "DDraw/Repository.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "DDraw/Surfaces/TagSurface.h" #include "DDraw/Surfaces/TagSurface.h"
namespace namespace
@ -15,9 +14,6 @@ namespace DDraw
{ {
TagSurface::~TagSurface() TagSurface::~TagSurface()
{ {
std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(),
[=](auto& i) { return i.second == this; })->second;
onRelease(*this);
Repository::onRelease(m_ddObject); Repository::onRelease(m_ddObject);
g_tagSurfaces.erase(std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(), g_tagSurfaces.erase(std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(),
[=](auto& i) { return i.second == this; })); [=](auto& i) { return i.second == this; }));