From aeb0e2557cdf6173d1b4aab583f37480f98ea220 Mon Sep 17 00:00:00 2001 From: DrChat Date: Thu, 3 Aug 2017 19:03:26 -0500 Subject: [PATCH] UI: Very basic dynamic DPI support --- premake5.lua | 1 + src/xenia/ui/window.cc | 2 ++ src/xenia/ui/window.h | 14 ++++++-- src/xenia/ui/window_win.cc | 67 +++++++++++++++++++++++++++++++------- src/xenia/ui/window_win.h | 2 ++ 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/premake5.lua b/premake5.lua index 8626ec7fb..593f0503d 100644 --- a/premake5.lua +++ b/premake5.lua @@ -145,6 +145,7 @@ filter("platforms:Windows") "glu32", "opengl32", "comctl32", + "shcore", "shlwapi", }) diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc index 91f4a8f67..cf300a4b5 100644 --- a/src/xenia/ui/window.cc +++ b/src/xenia/ui/window.cc @@ -154,6 +154,8 @@ void Window::Layout() { void Window::Invalidate() {} +void Window::OnDpiChanged(UIEvent* e) {} + void Window::OnResize(UIEvent* e) { ForEachListener([e](auto listener) { listener->OnResize(e); }); } diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h index 107078be1..1fd53fe10 100644 --- a/src/xenia/ui/window.h +++ b/src/xenia/ui/window.h @@ -62,6 +62,9 @@ class Window { virtual bool is_bordered() const { return false; } virtual void set_bordered(bool enabled) {} + virtual int get_dpi() const { return 96; } + virtual float get_dpi_scale() const { return get_dpi() / 96.f; } + bool has_focus() const { return has_focus_; } virtual void set_focus(bool value) { has_focus_ = value; } @@ -70,9 +73,15 @@ class Window { int32_t width() const { return width_; } int32_t height() const { return height_; } - virtual void Resize(int32_t width, int32_t height) = 0; + virtual void Resize(int32_t width, int32_t height) { + width_ = width; + height_ = height; + } virtual void Resize(int32_t left, int32_t top, int32_t right, - int32_t bottom) = 0; + int32_t bottom) { + width_ = right - left; + height_ = bottom - top; + } GraphicsContext* context() const { return context_.get(); } ImGuiDrawer* imgui_drawer() const { return imgui_drawer_.get(); } @@ -126,6 +135,7 @@ class Window { virtual void OnClose(); virtual void OnDestroy(); + virtual void OnDpiChanged(UIEvent* e); virtual void OnResize(UIEvent* e); virtual void OnLayout(UIEvent* e); virtual void OnPaint(UIEvent* e); diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index ba1ff0556..97cf76e5c 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -7,6 +7,7 @@ ****************************************************************************** */ +#include #include #include "xenia/base/assert.h" @@ -48,6 +49,16 @@ bool Win32Window::OnCreate() { static bool has_registered_class = false; if (!has_registered_class) { + // Tell Windows that we're DPI aware. + auto spda = (HRESULT(*)(PROCESS_DPI_AWARENESS value))GetProcAddress( + GetModuleHandle(L"shcore.dll"), "SetProcessDpiAwareness"); + if (spda) { + auto res = spda(PROCESS_PER_MONITOR_DPI_AWARE); + if (res != S_OK) { + XELOGE("Failed to set process DPI awareness. (code = 0x%.8X)", res); + } + } + WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; @@ -207,22 +218,22 @@ void Win32Window::ToggleFullscreen(bool fullscreen) { return; } - fullscreen_ = fullscreen; - DWORD style = GetWindowLong(hwnd_, GWL_STYLE); if (fullscreen) { - // Kill our borders and resize to take up entire primary monitor. // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx MONITORINFO mi = {sizeof(mi)}; if (GetWindowPlacement(hwnd_, &windowed_pos_) && GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTOPRIMARY), &mi)) { + // Remove the menubar and borders. SetWindowLong(hwnd_, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); ::SetMenu(hwnd_, NULL); - // Call into parent class to get around menu resizing code. - Resize(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, - mi.rcMonitor.bottom); + // Resize the window to fullscreen. + auto& rc = mi.rcMonitor; + AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), false); + MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + TRUE); } } else { // Reinstate borders, resize to 1280x720 @@ -234,6 +245,8 @@ void Win32Window::ToggleFullscreen(bool fullscreen) { ::SetMenu(hwnd_, main_menu->handle()); } } + + fullscreen_ = fullscreen; } bool Win32Window::is_bordered() const { @@ -255,6 +268,15 @@ void Win32Window::set_bordered(bool enabled) { } } +int Win32Window::get_dpi() const { + HMONITOR monitor = MonitorFromWindow(hwnd_, MONITOR_DEFAULTTOPRIMARY); + + // According to msdn, x and y are identical... + UINT dpi_x, dpi_y; + GetDpiForMonitor(monitor, MDT_DEFAULT, &dpi_x, &dpi_y); + return dpi_x; +} + void Win32Window::set_cursor_visible(bool value) { if (is_cursor_visible_ == value) { return; @@ -284,6 +306,11 @@ void Win32Window::set_focus(bool value) { } void Win32Window::Resize(int32_t width, int32_t height) { + if (is_fullscreen()) { + // Cannot resize while in fullscreen. + return; + } + RECT rc = {0, 0, width, height}; bool has_menu = !is_fullscreen() && (main_menu_ ? true : false); AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu); @@ -295,15 +322,24 @@ void Win32Window::Resize(int32_t width, int32_t height) { } MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); + + super::Resize(width, height); } void Win32Window::Resize(int32_t left, int32_t top, int32_t right, int32_t bottom) { + if (is_fullscreen()) { + // Cannot resize while in fullscreen. + return; + } + RECT rc = {left, top, right, bottom}; bool has_menu = !is_fullscreen() && (main_menu_ ? true : false); AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu); MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); + + super::Resize(left, top, right, bottom); } void Win32Window::OnResize(UIEvent* e) { @@ -362,7 +398,7 @@ LRESULT CALLBACK Win32Window::WndProcThunk(HWND hWnd, UINT message, LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - if (hWnd != hwnd_) { + if (hwnd_ != nullptr && hWnd != hwnd_) { return DefWindowProc(hWnd, message, wParam, lParam); } @@ -396,8 +432,14 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, DragFinish(hDrop); } break; - case WM_NCCREATE: - break; + case WM_NCCREATE: { + // Tell Windows to automatically scale non-client areas on different DPIs. + auto en = (BOOL(*)(HWND hwnd))GetProcAddress( + GetModuleHandle(L"user32.dll"), "EnableNonClientDpiScaling"); + if (en) { + en(hWnd); + } + } break; case WM_CREATE: break; case WM_DESTROY: @@ -418,8 +460,7 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, case WM_SIZE: { auto e = UIEvent(this); OnResize(&e); - break; - } + } break; case WM_PAINT: { ValidateRect(hwnd_, nullptr); @@ -436,6 +477,10 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, return 0; // Ignored because of custom paint. case WM_DISPLAYCHANGE: break; + case WM_DPICHANGED: { + auto e = UIEvent(this); + OnDpiChanged(&e); + } break; case WM_ACTIVATEAPP: case WM_SHOWWINDOW: { diff --git a/src/xenia/ui/window_win.h b/src/xenia/ui/window_win.h index eae68b2ce..530aa3e7e 100644 --- a/src/xenia/ui/window_win.h +++ b/src/xenia/ui/window_win.h @@ -40,6 +40,8 @@ class Win32Window : public Window { bool is_bordered() const override; void set_bordered(bool enabled) override; + int get_dpi() const override; + void set_cursor_visible(bool value) override; void set_focus(bool value) override;