Skip to content

Commit

Permalink
Support Windows DPI Awareness from at least Vista.
Browse files Browse the repository at this point in the history
There are three different DPI Awareness modes that have been added to
Windows, starting in Windows Vista. This is an attempt to gracefully
support DPI scaling since Vista. There is still some missing
documentation in the code, but it appears to work well.
  • Loading branch information
Hoikas authored and colincornaby committed Jun 17, 2023
1 parent 6795e67 commit 9c05355
Show file tree
Hide file tree
Showing 14 changed files with 641 additions and 37 deletions.
5 changes: 5 additions & 0 deletions Sources/Plasma/Apps/plClient/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,13 @@ set(plClient_TEXT
)

if(WIN32)
list(APPEND plClient_HEADERS
win32/plWinDpi.h
)

list(APPEND plClient_SOURCES
win32/plClient_Win.cpp
win32/plWinDpi.cpp
win32/winmain.cpp
)

Expand Down
68 changes: 59 additions & 9 deletions Sources/Plasma/Apps/plClient/plClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com

#include "plClient.h"

#ifdef HS_BUILD_FOR_WIN32
# include "win32/plWinDpi.h"
#endif

#include "pnDispatch/plDispatch.h"
#include "pnDispatch/plDispatchLogBase.h"
#include "pnKeyedObject/plFixedKey.h"
Expand Down Expand Up @@ -92,6 +96,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plInputCore/plInputManager.h"
#include "plMessage/plAgeLoadedMsg.h"
#include "plMessage/plAnimCmdMsg.h"
#include "plMessage/plDisplayScaleChangedMsg.h"
#include "plMessage/plInputEventMsg.h"
#include "plMessage/plLinkToAgeMsg.h"
#include "plMessage/plMovieMsg.h"
Expand Down Expand Up @@ -382,6 +387,7 @@ void plClient::InitInputs()
plgDispatch::Dispatch()->RegisterForExactType(plIMouseYEventMsg::Index(), fInputManager->GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plIMouseBEventMsg::Index(), fInputManager->GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), fInputManager->GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plDisplayScaleChangedMsg::Index(), fInputManager->GetKey());
plInputDevice* pKeyboard = new plKeyboardDevice();
fInputManager->AddInputDevice(pKeyboard);

Expand Down Expand Up @@ -710,6 +716,44 @@ bool plClient::MsgReceive(plMessage* msg)
}
return true;
}

plDisplayScaleChangedMsg* pDSChangedMsg = plDisplayScaleChangedMsg::ConvertNoRef(msg);
if (pDSChangedMsg) {
fPipeline->SetBackingScale(pDSChangedMsg->GetScale());
if (pDSChangedMsg->GetSuggestedLocation().has_value()) {
int width = pDSChangedMsg->GetSuggestedLocation()->fRight - pDSChangedMsg->GetSuggestedLocation()->fLeft;
int height = pDSChangedMsg->GetSuggestedLocation()->fBottom - pDSChangedMsg->GetSuggestedLocation()->fTop;
IResizeWindow(width, height);
if (fPipeline) {
// NOTE: Trying to resize the pipeline while it spans multiple
// monitors seems to crash on D3D9.
fPipeline->ResetDisplayDevice(
width,
height,
fPipeline->ColorDepth(),
!fPipeline->IsFullScreen(),
// FIXME... There doesn't seem to be a way to get the current AA value?
fPipeline->GetMaxAntiAlias(width, height, fPipeline->ColorDepth()),
fPipeline->GetMaxAnisotropicSamples(),
// FIXME... There doesn't seem to be a way tog et the current VSync value?
true
);
}
#ifdef HS_BUILD_FOR_WIN32
SetWindowPos(
fWindowHndl,
nullptr,
pDSChangedMsg->GetSuggestedLocation()->fLeft,
pDSChangedMsg->GetSuggestedLocation()->fTop,
width,
height,
SWP_NOZORDER | SWP_NOACTIVATE
);
#endif
}
return true;
}

plRenderRequestMsg* rendReq = plRenderRequestMsg::ConvertNoRef(msg);
if( rendReq )
{
Expand Down Expand Up @@ -1414,6 +1458,8 @@ bool plClient::StartInit()
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), pLMod->GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey());

plgDispatch::Dispatch()->RegisterForExactType(plDisplayScaleChangedMsg::Index(), GetKey());

plSynchedObject::PushSynchDisabled(false); // enable dirty tracking
return true;
}
Expand Down Expand Up @@ -1870,6 +1916,16 @@ void plClient::IAddRenderRequest(plRenderRequest* req)
}
}

void plClient::IResizeWindow(int Width, int Height)
{
if (plMouseDevice::Instance())
plMouseDevice::Instance()->SetDisplayResolution((float)Width, (float)Height);

float aspectratio = (float)Width / (float)Height;
if (pfGameGUIMgr::GetInstance())
pfGameGUIMgr::GetInstance()->SetAspectRatio(aspectratio);
}

void plClient::ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool VSync)
{
if(!fPipeline) return;
Expand All @@ -1885,13 +1941,7 @@ void plClient::ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Wi

void plClient::ResizeDisplayDevice(int Width, int Height, bool Windowed)
{

if (plMouseDevice::Instance())
plMouseDevice::Instance()->SetDisplayResolution((float)Width, (float)Height);

float aspectratio = (float)Width / (float)Height;
if (pfGameGUIMgr::GetInstance())
pfGameGUIMgr::GetInstance()->SetAspectRatio( aspectratio );
IResizeWindow(Width, Height);

// Direct3D no longer uses exclusive fullscreen mode, ergo, we must resize the display
if (!Windowed)
Expand Down Expand Up @@ -1949,8 +1999,8 @@ void plClient::IDetectAudioVideoSettings()
#ifdef HS_BUILD_FOR_WIN32
if(!plPipeline::fDefaultPipeParams.Windowed)
{
plPipeline::fDefaultPipeParams.Width = GetSystemMetrics(SM_CXSCREEN);
plPipeline::fDefaultPipeParams.Height = GetSystemMetrics(SM_CYSCREEN);
plPipeline::fDefaultPipeParams.Width = plWinDpi::Instance().GetSystemMetrics(SM_CXSCREEN, fWindowHndl);
plPipeline::fDefaultPipeParams.Height = plWinDpi::Instance().GetSystemMetrics(SM_CYSCREEN, fWindowHndl);
}
else
#endif
Expand Down
2 changes: 2 additions & 0 deletions Sources/Plasma/Apps/plClient/plClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ class plClient : public hsKeyedObject
void IChangeResolution(int width, int height);
void IUpdateProgressIndicator(plOperationProgress* progress);

void IResizeWindow(int width, int height);

public:

plClient();
Expand Down
25 changes: 16 additions & 9 deletions Sources/Plasma/Apps/plClient/win32/plClient_Win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include <shellapi.h>

#include "plClient.h"
#include "win32/plWinDpi.h"

#include "pnFactory/plFactory.h"
#include "pnNetCommon/plNetApp.h"
Expand All @@ -72,17 +73,23 @@ void plClient::IResizeNativeDisplayDevice(int width, int height, bool windowed)
SetWindowLongPtr(fWindowHndl, GWL_EXSTYLE, winExStyle);

uint32_t flags = SWP_NOCOPYBITS | SWP_SHOWWINDOW | SWP_FRAMECHANGED;
uint32_t outsideWidth, outsideHeight;

// The window rect will be (left, top, width, height)
RECT winRect{ 0, 0, width, height };
if (windowed) {
RECT winRect = { 0, 0, width, height };
AdjustWindowRectEx(&winRect, winStyle, false, winExStyle);
outsideWidth = winRect.right - winRect.left;
outsideHeight = winRect.bottom - winRect.top;
} else {
outsideWidth = width;
outsideHeight = height;
if (GetClientRect(fWindowHndl, &winRect) != FALSE) {
MapWindowPoints(fWindowHndl, nullptr, reinterpret_cast<LPPOINT>(&winRect), 2);
winRect.right = winRect.left + width;
winRect.bottom = winRect.top + height;
}

UINT dpi = plWinDpi::Instance().GetDpi(fWindowHndl);
plWinDpi::Instance().AdjustWindowRectEx(&winRect, winStyle, false, winExStyle, dpi);

winRect.right = winRect.right - winRect.left;
winRect.bottom = winRect.bottom - winRect.top;
}
SetWindowPos(fWindowHndl, HWND_NOTOPMOST, 0, 0, outsideWidth, outsideHeight, flags);
SetWindowPos(fWindowHndl, HWND_NOTOPMOST, winRect.left, winRect.top, winRect.right, winRect.bottom, flags);
}

void plClient::IChangeResolution(int width, int height)
Expand Down
Loading

0 comments on commit 9c05355

Please sign in to comment.