diff --git a/xbmc/platform/win32/app.manifest b/xbmc/platform/win32/app.manifest index b11f40223f2e6..13e10b4faf693 100644 --- a/xbmc/platform/win32/app.manifest +++ b/xbmc/platform/win32/app.manifest @@ -1,22 +1,24 @@ -    -      -      -      -      -      -      -      -      -      -      -    -    -      true -    + + + + + + + + + + True/PM + + + + + + + + + + + \ No newline at end of file diff --git a/xbmc/windowing/windows/WinEventsWin32.cpp b/xbmc/windowing/windows/WinEventsWin32.cpp index d5199f40ceb6a..f005ef0c0cc4c 100644 --- a/xbmc/windowing/windows/WinEventsWin32.cpp +++ b/xbmc/windowing/windows/WinEventsWin32.cpp @@ -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; @@ -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) @@ -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; diff --git a/xbmc/windowing/windows/WinSystemWin32.cpp b/xbmc/windowing/windows/WinSystemWin32.cpp index 58431efc5786f..7bfa54c4247b0 100644 --- a/xbmc/windowing/windows/WinSystemWin32.cpp +++ b/xbmc/windowing/windows/WinSystemWin32.cpp @@ -47,6 +47,7 @@ CWinSystemWin32::CWinSystemWin32() PtrCloseGestureInfoHandle = NULL; PtrSetGestureConfig = NULL; PtrGetGestureInfo = NULL; + PtrEnableNonClientDpiScaling = NULL; m_ValidWindowedPosition = false; m_IsAlteringWindow = false; } @@ -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; @@ -128,14 +141,7 @@ bool CWinSystemWin32::CreateNewWindow(const std::string& name, bool fullScreen, SetProp(hWnd, MICROSOFT_TABLETPENSERVICE_PROPERTY, reinterpret_cast(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); @@ -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; @@ -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 ); @@ -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); diff --git a/xbmc/windowing/windows/WinSystemWin32.h b/xbmc/windowing/windows/WinSystemWin32.h index 4de378cb4bd00..f220cefcd0d9e 100644 --- a/xbmc/windowing/windows/WinSystemWin32.h +++ b/xbmc/windowing/windows/WinSystemWin32.h @@ -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);