UI: Very basic dynamic DPI support

This commit is contained in:
DrChat 2017-08-03 19:03:26 -05:00
parent d439704aa9
commit aeb0e2557c
5 changed files with 73 additions and 13 deletions

View File

@ -145,6 +145,7 @@ filter("platforms:Windows")
"glu32", "glu32",
"opengl32", "opengl32",
"comctl32", "comctl32",
"shcore",
"shlwapi", "shlwapi",
}) })

View File

@ -154,6 +154,8 @@ void Window::Layout() {
void Window::Invalidate() {} void Window::Invalidate() {}
void Window::OnDpiChanged(UIEvent* e) {}
void Window::OnResize(UIEvent* e) { void Window::OnResize(UIEvent* e) {
ForEachListener([e](auto listener) { listener->OnResize(e); }); ForEachListener([e](auto listener) { listener->OnResize(e); });
} }

View File

@ -62,6 +62,9 @@ class Window {
virtual bool is_bordered() const { return false; } virtual bool is_bordered() const { return false; }
virtual void set_bordered(bool enabled) {} 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_; } bool has_focus() const { return has_focus_; }
virtual void set_focus(bool value) { has_focus_ = value; } virtual void set_focus(bool value) { has_focus_ = value; }
@ -70,9 +73,15 @@ class Window {
int32_t width() const { return width_; } int32_t width() const { return width_; }
int32_t height() const { return height_; } 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, 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(); } GraphicsContext* context() const { return context_.get(); }
ImGuiDrawer* imgui_drawer() const { return imgui_drawer_.get(); } ImGuiDrawer* imgui_drawer() const { return imgui_drawer_.get(); }
@ -126,6 +135,7 @@ class Window {
virtual void OnClose(); virtual void OnClose();
virtual void OnDestroy(); virtual void OnDestroy();
virtual void OnDpiChanged(UIEvent* e);
virtual void OnResize(UIEvent* e); virtual void OnResize(UIEvent* e);
virtual void OnLayout(UIEvent* e); virtual void OnLayout(UIEvent* e);
virtual void OnPaint(UIEvent* e); virtual void OnPaint(UIEvent* e);

View File

@ -7,6 +7,7 @@
****************************************************************************** ******************************************************************************
*/ */
#include <ShellScalingApi.h>
#include <string> #include <string>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
@ -48,6 +49,16 @@ bool Win32Window::OnCreate() {
static bool has_registered_class = false; static bool has_registered_class = false;
if (!has_registered_class) { 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; WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX); wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
@ -207,22 +218,22 @@ void Win32Window::ToggleFullscreen(bool fullscreen) {
return; return;
} }
fullscreen_ = fullscreen;
DWORD style = GetWindowLong(hwnd_, GWL_STYLE); DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
if (fullscreen) { 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 // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
MONITORINFO mi = {sizeof(mi)}; MONITORINFO mi = {sizeof(mi)};
if (GetWindowPlacement(hwnd_, &windowed_pos_) && if (GetWindowPlacement(hwnd_, &windowed_pos_) &&
GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTOPRIMARY), GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTOPRIMARY),
&mi)) { &mi)) {
// Remove the menubar and borders.
SetWindowLong(hwnd_, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); SetWindowLong(hwnd_, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
::SetMenu(hwnd_, NULL); ::SetMenu(hwnd_, NULL);
// Call into parent class to get around menu resizing code. // Resize the window to fullscreen.
Resize(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, auto& rc = mi.rcMonitor;
mi.rcMonitor.bottom); AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), false);
MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
TRUE);
} }
} else { } else {
// Reinstate borders, resize to 1280x720 // Reinstate borders, resize to 1280x720
@ -234,6 +245,8 @@ void Win32Window::ToggleFullscreen(bool fullscreen) {
::SetMenu(hwnd_, main_menu->handle()); ::SetMenu(hwnd_, main_menu->handle());
} }
} }
fullscreen_ = fullscreen;
} }
bool Win32Window::is_bordered() const { 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) { void Win32Window::set_cursor_visible(bool value) {
if (is_cursor_visible_ == value) { if (is_cursor_visible_ == value) {
return; return;
@ -284,6 +306,11 @@ void Win32Window::set_focus(bool value) {
} }
void Win32Window::Resize(int32_t width, int32_t height) { void Win32Window::Resize(int32_t width, int32_t height) {
if (is_fullscreen()) {
// Cannot resize while in fullscreen.
return;
}
RECT rc = {0, 0, width, height}; RECT rc = {0, 0, width, height};
bool has_menu = !is_fullscreen() && (main_menu_ ? true : false); bool has_menu = !is_fullscreen() && (main_menu_ ? true : false);
AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu); 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, MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
TRUE); TRUE);
super::Resize(width, height);
} }
void Win32Window::Resize(int32_t left, int32_t top, int32_t right, void Win32Window::Resize(int32_t left, int32_t top, int32_t right,
int32_t bottom) { int32_t bottom) {
if (is_fullscreen()) {
// Cannot resize while in fullscreen.
return;
}
RECT rc = {left, top, right, bottom}; RECT rc = {left, top, right, bottom};
bool has_menu = !is_fullscreen() && (main_menu_ ? true : false); bool has_menu = !is_fullscreen() && (main_menu_ ? true : false);
AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu); AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu);
MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
TRUE); TRUE);
super::Resize(left, top, right, bottom);
} }
void Win32Window::OnResize(UIEvent* e) { 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, LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) { LPARAM lParam) {
if (hWnd != hwnd_) { if (hwnd_ != nullptr && hWnd != hwnd_) {
return DefWindowProc(hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
} }
@ -396,8 +432,14 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
DragFinish(hDrop); DragFinish(hDrop);
} break; } break;
case WM_NCCREATE: case WM_NCCREATE: {
break; // 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: case WM_CREATE:
break; break;
case WM_DESTROY: case WM_DESTROY:
@ -418,8 +460,7 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
case WM_SIZE: { case WM_SIZE: {
auto e = UIEvent(this); auto e = UIEvent(this);
OnResize(&e); OnResize(&e);
break; } break;
}
case WM_PAINT: { case WM_PAINT: {
ValidateRect(hwnd_, nullptr); ValidateRect(hwnd_, nullptr);
@ -436,6 +477,10 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
return 0; // Ignored because of custom paint. return 0; // Ignored because of custom paint.
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
break; break;
case WM_DPICHANGED: {
auto e = UIEvent(this);
OnDpiChanged(&e);
} break;
case WM_ACTIVATEAPP: case WM_ACTIVATEAPP:
case WM_SHOWWINDOW: { case WM_SHOWWINDOW: {

View File

@ -40,6 +40,8 @@ class Win32Window : public Window {
bool is_bordered() const override; bool is_bordered() const override;
void set_bordered(bool enabled) override; void set_bordered(bool enabled) override;
int get_dpi() const override;
void set_cursor_visible(bool value) override; void set_cursor_visible(bool value) override;
void set_focus(bool value) override; void set_focus(bool value) override;