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

View File

@ -230,5 +230,18 @@ namespace D3dDdi
HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner, setVidPnSourceOwner);
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
{
void installHooks();
void releaseVidPnSources();
}
}

View File

@ -1,116 +1,64 @@
#include "Common/CompatPtr.h"
#include "Common/CompatRef.h"
#include "Common/Log.h"
#define CINTERFACE
#include <ddraw.h>
#include "Common/Hook.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 "Win32/FontSmoothing.h"
extern HWND g_mainWindow;
namespace
{
bool g_isActive = true;
HWND g_fullScreenCooperativeWindow = nullptr;
DWORD g_fullScreenCooperativeFlags = 0;
Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {};
HHOOK g_callWndProcHook = nullptr;
WNDPROC g_origDdWndProc = nullptr;
void handleActivateApp(bool isActivated);
void activateApp(CompatRef<IDirectDraw7> dd)
void activateApp()
{
if (!(g_fullScreenCooperativeFlags & DDSCL_NOWINDOWCHANGES))
{
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);
}
Gdi::enableEmulation();
Win32::FontSmoothing::setSystemSettings(g_fontSmoothingSettings);
}
void deactivateApp(CompatRef<IDirectDraw7> dd)
void deactivateApp()
{
dd->RestoreDisplayMode(&dd);
dd->SetCooperativeLevel(&dd, g_fullScreenCooperativeWindow, DDSCL_NORMAL);
if (!(g_fullScreenCooperativeFlags & DDSCL_NOWINDOWCHANGES))
{
ShowWindow(g_fullScreenCooperativeWindow, SW_SHOWMINNOACTIVE);
}
Gdi::disableEmulation();
g_fontSmoothingSettings = Win32::FontSmoothing::getSystemSettings();
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);
Compat::LogEnter("callWndProc", nCode, wParam, ret);
static bool isDisplayChangeNotificationEnabled = true;
if (HC_ACTION == nCode && WM_ACTIVATEAPP == ret->message)
switch (uMsg)
{
const bool isActivated = TRUE == ret->wParam;
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)
case WM_ACTIVATEAPP:
{
return;
}
g_isActive = isActivated;
if (!isActivated)
{
Gdi::disableEmulation();
}
auto dd(DDraw::getFullScreenDirectDraw());
if (dd)
{
if (isActivated)
isDisplayChangeNotificationEnabled = false;
if (TRUE == wParam)
{
activateApp(*dd);
activateApp();
}
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
{
void installHooks()
void setCooperativeLevel(HWND hwnd, DWORD flags)
{
const DWORD threadId = GetCurrentThreadId();
g_callWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, callWndProc, nullptr, threadId);
}
bool isActive()
{
return g_isActive;
}
void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags)
{
g_fullScreenCooperativeWindow = hwnd;
g_fullScreenCooperativeFlags = flags;
}
void uninstallHooks()
{
UnhookWindowsHookEx(g_callWndProcHook);
static bool isDdWndProcHooked = false;
if ((flags & DDSCL_FULLSCREEN) && !isDdWndProcHooked)
{
g_origDdWndProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
Compat::hookFunction(reinterpret_cast<void*&>(g_origDdWndProc), ddWndProc);
isDdWndProcHooked = true;
}
}
}
}

View File

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

View File

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

View File

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

View File

@ -40,11 +40,16 @@ namespace
targetDevMode.dmDisplayFrequency == currentDevMode.dmDisplayFrequency &&
targetDevMode.dmDisplayFlags == currentDevMode.dmDisplayFlags)
{
HANDLE dwmDxFullScreenTransitionEvent = OpenEventW(
EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT");
SetEvent(dwmDxFullScreenTransitionEvent);
CloseHandle(dwmDxFullScreenTransitionEvent);
return DISP_CHANGE_SUCCESSFUL;
LONG result = origChangeDisplaySettings(
lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
if (SUCCEEDED(result))
{
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);
hookDirectDrawSurface(*dd7);
hookDirectDrawPalette(*dd7);
ActivateAppHandler::installHooks();
}
void uninstallHooks()
{
RealPrimarySurface::removeUpdateThread();
ActivateAppHandler::uninstallHooks();
}
}

View File

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

View File

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

View File

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