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",
"opengl32",
"comctl32",
"shcore",
"shlwapi",
})

View File

@ -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); });
}

View File

@ -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);

View File

@ -7,6 +7,7 @@
******************************************************************************
*/
#include <ShellScalingApi.h>
#include <string>
#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: {

View File

@ -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;