Skip to content

Commit

Permalink
Added Win32 support for per-monitor DPI and scaling (#11171)
Browse files Browse the repository at this point in the history
[win32]  added support for per-monitor DPI and scaling
  • Loading branch information
stammen authored and MartijnKaijser committed Dec 14, 2016
1 parent 59a5c42 commit a11603a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 31 deletions.
40 changes: 21 additions & 19 deletions xbmc/platform/win32/app.manifest
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <!-- Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <!-- Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!-- Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!-- Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
    </application>
  </compatibility>
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
<ms_compatibility:compatibility xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" xmlns="urn:schemas-microsoft-com:compatibility.v1">
<ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3" xmlns="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"></ms_asmv3:supportedOS>
<ms_asmv3:supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"></ms_asmv3:supportedOS>
<ms_asmv3:supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"></ms_asmv3:supportedOS>
<ms_asmv3:supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"></ms_asmv3:supportedOS>
<ms_asmv3:supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"></ms_asmv3:supportedOS>
</ms_asmv3:application>
</ms_compatibility:compatibility>
</assembly>
29 changes: 26 additions & 3 deletions xbmc/windowing/windows/WinEventsWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,16 @@ LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
ZeroMemory(&newEvent, sizeof(newEvent));
static HDEVNOTIFY hDeviceNotify;

if (uMsg == WM_NCCREATE)
{
// if available, enable DPI scaling of non-client portion of window (title bar, etc.)
if (g_Windowing.PtrEnableNonClientDpiScaling != NULL)
{
g_Windowing.PtrEnableNonClientDpiScaling(hWnd);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

if (uMsg == WM_CREATE)
{
g_hWnd = hWnd;
Expand Down Expand Up @@ -668,6 +678,19 @@ LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
m_pEventFunc(newEvent);
}
return(0);
case WM_DPICHANGED:
// This message tells the program that most of its window is on a
// monitor with a new DPI. The wParam contains the new DPI, and the
// lParam contains a rect which defines the window rectangle scaled
// the new DPI.
if (g_application.GetRenderGUI() && !g_Windowing.IsAlteringWindow())
{
// get the suggested size of the window on the new display with a different DPI
unsigned short dpi = LOWORD(wParam);
RECT resizeRect = *((RECT*)lParam);
g_Windowing.DPIChanged(dpi, resizeRect);
}
return(0);
case WM_DISPLAYCHANGE:
CLog::Log(LOGDEBUG, __FUNCTION__": display change event");
if (g_application.GetRenderGUI() && !g_Windowing.IsAlteringWindow() && GET_X_LPARAM(lParam) > 0 && GET_Y_LPARAM(lParam) > 0)
Expand All @@ -684,9 +707,9 @@ LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
newEvent.type = XBMC_VIDEORESIZE;
newEvent.resize.w = GET_X_LPARAM(lParam);
newEvent.resize.h = GET_Y_LPARAM(lParam);
}
m_pEventFunc(newEvent);
}
}
m_pEventFunc(newEvent);
}
return(0);
case WM_SIZE:
newEvent.type = XBMC_VIDEORESIZE;
Expand Down
71 changes: 62 additions & 9 deletions xbmc/windowing/windows/WinSystemWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ CWinSystemWin32::CWinSystemWin32()
PtrCloseGestureInfoHandle = NULL;
PtrSetGestureConfig = NULL;
PtrGetGestureInfo = NULL;
PtrEnableNonClientDpiScaling = NULL;
m_ValidWindowedPosition = false;
m_IsAlteringWindow = false;
}
Expand Down Expand Up @@ -87,6 +88,18 @@ bool CWinSystemWin32::CreateNewWindow(const std::string& name, bool fullScreen,
if(m_hInstance == NULL)
CLog::Log(LOGDEBUG, "%s : GetModuleHandle failed with %d", __FUNCTION__, GetLastError());

// Load Win32 procs if available
HMODULE hUser32 = GetModuleHandleA("user32");
if (hUser32)
{
PtrGetGestureInfo = (pGetGestureInfo)GetProcAddress(hUser32, "GetGestureInfo");
PtrSetGestureConfig = (pSetGestureConfig)GetProcAddress(hUser32, "SetGestureConfig");
PtrCloseGestureInfoHandle = (pCloseGestureInfoHandle)GetProcAddress(hUser32, "CloseGestureInfoHandle");

// if available, enable automatic DPI scaling of the non-client area portions of the window.
PtrEnableNonClientDpiScaling = (pEnableNonClientDpiScaling)GetProcAddress(hUser32, "EnableNonClientDpiScaling");
}

m_nWidth = res.iWidth;
m_nHeight = res.iHeight;
m_bFullScreen = fullScreen;
Expand Down Expand Up @@ -128,14 +141,7 @@ bool CWinSystemWin32::CreateNewWindow(const std::string& name, bool fullScreen,

SetProp(hWnd, MICROSOFT_TABLETPENSERVICE_PROPERTY, reinterpret_cast<HANDLE>(dwHwndTabletProperty));

// setup our touch pointers
HMODULE hUser32 = GetModuleHandleA( "user32" );
if (hUser32)
{
PtrGetGestureInfo = (pGetGestureInfo) GetProcAddress( hUser32, "GetGestureInfo" );
PtrSetGestureConfig = (pSetGestureConfig) GetProcAddress( hUser32, "SetGestureConfig" );
PtrCloseGestureInfoHandle = (pCloseGestureInfoHandle) GetProcAddress( hUser32, "CloseGestureInfoHandle" );
}


m_hWnd = hWnd;
m_hDC = GetDC(m_hWnd);
Expand Down Expand Up @@ -330,6 +336,52 @@ bool CWinSystemWin32::SetFullScreenEx(bool fullScreen, RESOLUTION_INFO& res, boo
return true;
}

bool CWinSystemWin32::DPIChanged(WORD dpi, RECT windowRect)
{
(void)dpi;
RECT resizeRect = windowRect;
HMONITOR hMon = MonitorFromRect(&resizeRect, MONITOR_DEFAULTTONULL);
if (hMon == NULL)
{
hMon = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY);
}

if (hMon)
{
MONITORINFOEX monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hMon, &monitorInfo);
RECT wr = monitorInfo.rcWork;
long wrWidth = wr.right - wr.left;
long wrHeight = wr.bottom - wr.top;
long resizeWidth = resizeRect.right - resizeRect.left;
long resizeHeight = resizeRect.bottom - resizeRect.top;

if (resizeWidth > wrWidth)
{
resizeRect.right = resizeRect.left + wrWidth;
}

// make sure suggested windows size is not taller or wider than working area of new monitor (considers the toolbar)
if (resizeHeight > wrHeight)
{
resizeRect.bottom = resizeRect.top + wrHeight;
}
}

// resize the window to the suggested size. Will generate a WM_SIZE event
SetWindowPos(m_hWnd,
NULL,
resizeRect.left,
resizeRect.top,
resizeRect.right - resizeRect.left,
resizeRect.bottom - resizeRect.top,
SWP_NOZORDER | SWP_NOACTIVATE);

return true;
}


void CWinSystemWin32::RestoreDesktopResolution(int screen)
{
int resIdx = RES_DESKTOP;
Expand Down Expand Up @@ -434,6 +486,7 @@ bool CWinSystemWin32::ResizeInternal(bool forceRefresh)
rc.top = m_nTop = newScreenRect.top + ((newScreenRect.bottom - newScreenRect.top) / 2) - (m_nHeight / 2);
rc.right = m_nLeft + m_nWidth;
rc.bottom = m_nTop + m_nHeight;
m_ValidWindowedPosition = true;
}

AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, false );
Expand All @@ -458,7 +511,7 @@ bool CWinSystemWin32::ResizeInternal(bool forceRefresh)

// The SWP_DRAWFRAME is here because, perversely, without it win7 draws a
// white frame plus titlebar around the xbmc splash
SetWindowPos(m_hWnd, windowAfter, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW|SWP_DRAWFRAME);
SetWindowPos(m_hWnd, windowAfter, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_DRAWFRAME);

//! @todo Probably only need this if switching screens
ValidateRect(NULL, NULL);
Expand Down
3 changes: 3 additions & 0 deletions xbmc/windowing/windows/WinSystemWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,17 @@ class CWinSystemWin32 : public CWinSystemBase
// CWinSystemWin32
HWND GetHwnd() { return m_hWnd; }
bool IsAlteringWindow() { return m_IsAlteringWindow; }
bool DPIChanged(WORD dpi, RECT windowRect);

// touchscreen support
typedef BOOL (WINAPI *pGetGestureInfo)(HGESTUREINFO, PGESTUREINFO);
typedef BOOL (WINAPI *pSetGestureConfig)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
typedef BOOL (WINAPI *pCloseGestureInfoHandle)(HGESTUREINFO);
typedef BOOL(WINAPI *pEnableNonClientDpiScaling)(HWND);
pGetGestureInfo PtrGetGestureInfo;
pSetGestureConfig PtrSetGestureConfig;
pCloseGestureInfoHandle PtrCloseGestureInfoHandle;
pEnableNonClientDpiScaling PtrEnableNonClientDpiScaling;

protected:
bool ChangeResolution(const RESOLUTION_INFO& res, bool forceChange = false);
Expand Down

0 comments on commit a11603a

Please sign in to comment.