Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions os/win/winapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ WinAPI::WinAPI()
GET_PROC(m_user32, GetPointerInfo);
GET_PROC(m_user32, GetPointerPenInfo);
GET_PROC(m_user32, SetProcessDpiAwarenessContext);
GET_PROC(m_user32, GetWindowDpiAwarenessContext);
GET_PROC(m_user32, AreDpiAwarenessContextsEqual);
GET_PROC(m_user32, EnableNonClientDpiScaling);
GET_PROC(m_user32, GetDpiForWindow);
GET_PROC(m_user32, GetSystemMetricsForDpi);
GET_PROC(m_user32, AdjustWindowRectExForDpi);
}
if (m_ninput) {
GET_PROC(m_ninput, CreateInteractionContext);
Expand Down
14 changes: 14 additions & 0 deletions os/win/winapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ typedef HRESULT(WINAPI* ProcessPointerFramesInteractionContext_Func)(
const POINTER_INFO* pointerInfo);

typedef BOOL(WINAPI* SetProcessDpiAwarenessContext_Func)(DPI_AWARENESS_CONTEXT value);
typedef DPI_AWARENESS_CONTEXT(WINAPI* GetWindowDpiAwarenessContext_Func)(HWND hwnd);
typedef BOOL(WINAPI* AreDpiAwarenessContextsEqual_Func)(DPI_AWARENESS_CONTEXT dpiContextA, DPI_AWARENESS_CONTEXT dpiContextB);
typedef BOOL(WINAPI* EnableNonClientDpiScaling_Func)(HWND hwnd);
typedef UINT(WINAPI* GetDpiForWindow_Func)(HWND hwnd);
typedef int(WINAPI* GetSystemMetricsForDpi_Func)(int nIndex, UINT dpi);
typedef BOOL(WINAPI* AdjustWindowRectExForDpi_Func)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);

class WinAPI {
public:
Expand All @@ -71,6 +77,14 @@ class WinAPI {
SetPropertyInteractionContext_Func SetPropertyInteractionContext = nullptr;
ProcessPointerFramesInteractionContext_Func ProcessPointerFramesInteractionContext = nullptr;

// Functions introduced on Windows 10 version 1607
GetWindowDpiAwarenessContext_Func GetWindowDpiAwarenessContext = nullptr;
AreDpiAwarenessContextsEqual_Func AreDpiAwarenessContextsEqual = nullptr;
EnableNonClientDpiScaling_Func EnableNonClientDpiScaling = nullptr;
GetDpiForWindow_Func GetDpiForWindow = nullptr;
GetSystemMetricsForDpi_Func GetSystemMetricsForDpi = nullptr;
AdjustWindowRectExForDpi_Func AdjustWindowRectExForDpi = nullptr;

// Functions introduced on Windows 10 version 1703
SetProcessDpiAwarenessContext_Func SetProcessDpiAwarenessContext = nullptr;

Expand Down
65 changes: 58 additions & 7 deletions os/win/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ WindowWin::Touch::Touch() : fingers(0), canBeMouse(false), asMouse(false), timer
WindowWin::WindowWin(const WindowSpec& spec)
: m_clientSize(1, 1)
, m_scale(spec.scale())
, m_baseScale(spec.scale())
, m_isCreated(false)
, m_adjustShadow(true)
, m_translateDeadKeys(false)
Expand Down Expand Up @@ -263,6 +264,11 @@ WindowWin::WindowWin(const WindowSpec& spec)

SetWindowLongPtr(m_hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));

if (winApi.GetWindowDpiAwarenessContext) {
double scaleFactor = winApi.GetDpiForWindow(m_hwnd) / (double) USER_DEFAULT_SCREEN_DPI;
m_scale = std::ceil(m_baseScale * scaleFactor);
}

// This flag is used to avoid calling T::resizeImpl() when we
// add the scrollbars to the window. (As the T type could not be
// fully initialized yet.)
Expand Down Expand Up @@ -361,7 +367,10 @@ os::ColorSpaceRef WindowWin::colorSpace() const

void WindowWin::setScale(int scale)
{
m_scale = scale;
double scaleFactor = m_scale / (double) m_baseScale;
m_baseScale = scale;
// round to nearest integer, rounding 0.5 up
m_scale = std::ceil(m_baseScale * scaleFactor);

// Align window size to new scale
{
Expand Down Expand Up @@ -966,6 +975,21 @@ LRESULT WindowWin::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
}
break;

case WM_DPICHANGED: {
double scaleFactor = HIWORD(wparam) / (double) USER_DEFAULT_SCREEN_DPI;
m_scale = std::ceil(m_baseScale * scaleFactor);

RECT* prcNewWindow = (RECT*)lparam;
SetWindowPos(m_hwnd,
nullptr,
prcNewWindow ->left,
prcNewWindow ->top,
prcNewWindow->right - prcNewWindow->left,
prcNewWindow->bottom - prcNewWindow->top,
SWP_NOZORDER | SWP_NOACTIVATE);
break;
}

case WM_SETCURSOR:
// We set our custom cursor if we are in the client area, or in
// the case of windows with custom frames (borderless), we
Expand Down Expand Up @@ -1787,8 +1811,16 @@ LRESULT WindowWin::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
// scrollbars. In this way they are not visible, but we still
// get their messages.
NCCALCSIZE_PARAMS* cs = reinterpret_cast<NCCALCSIZE_PARAMS*>(lparam);
cs->rgrc[0].right += GetSystemMetrics(SM_CYVSCROLL);
cs->rgrc[0].bottom += GetSystemMetrics(SM_CYHSCROLL);

auto& winApi = system()->winApi();
if (winApi.GetWindowDpiAwarenessContext) {
UINT dpi = winApi.GetDpiForWindow(m_hwnd);
cs->rgrc[0].right += winApi.GetSystemMetricsForDpi(SM_CYVSCROLL, dpi);
cs->rgrc[0].bottom += winApi.GetSystemMetricsForDpi(SM_CYHSCROLL, dpi);
} else {
cs->rgrc[0].right += GetSystemMetrics(SM_CYVSCROLL);
cs->rgrc[0].bottom += GetSystemMetrics(SM_CYHSCROLL);
}
}
}
break;
Expand Down Expand Up @@ -2490,10 +2522,21 @@ HWND WindowWin::createHwnd(WindowWin* self, const WindowSpec& spec)
rc.w = spec.contentRect().w;
rc.h = spec.contentRect().h;
RECT ncrc = { 0, 0, rc.w, rc.h };
AdjustWindowRectEx(&ncrc,
style,
false, // Add a field to WindowSpec to add native menu bars
exStyle);

auto& winApi = system()->winApi();
if (winApi.GetWindowDpiAwarenessContext) {
UINT dpi = winApi.GetDpiForWindow(self->m_hwnd);
winApi.AdjustWindowRectExForDpi(&ncrc,
style,
false, // Add a field to WindowSpec to add native menu bars
exStyle,
dpi);
} else {
AdjustWindowRectEx(&ncrc,
style,
false, // Add a field to WindowSpec to add native menu bars
exStyle);
}

if (rc.x != CW_USEDEFAULT)
rc.x += ncrc.left;
Expand Down Expand Up @@ -2541,6 +2584,14 @@ LRESULT CALLBACK WindowWin::staticWndProc(HWND hwnd, UINT msg, WPARAM wparam, LP

if (wnd && wnd->m_hwnd == nullptr)
wnd->m_hwnd = hwnd;

// Enable scaling for titlebar with legacy per-monitor dpi awareness steeting
auto& winApi = system()->winApi();
if (winApi.GetWindowDpiAwarenessContext) {
DPI_AWARENESS_CONTEXT dpiContext = winApi.GetWindowDpiAwarenessContext(hwnd);
if (!winApi.AreDpiAwarenessContextsEqual(dpiContext, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
winApi.EnableNonClientDpiScaling(hwnd);
}
}
else {
wnd = reinterpret_cast<WindowWin*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
Expand Down
2 changes: 2 additions & 0 deletions os/win/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class WindowWin : public Window {
os::ScreenRef screen() const override;
os::ColorSpaceRef colorSpace() const override;
int scale() const override { return m_scale; }
int baseScale() const override { return m_baseScale; }
void setScale(int scale) override;
bool isVisible() const override;
void setVisible(bool visible) override;
Expand Down Expand Up @@ -144,6 +145,7 @@ class WindowWin : public Window {
std::unique_ptr<DragTargetAdapter> m_dragTargetAdapter = nullptr;

int m_scale;
int m_baseScale;
bool m_isCreated;
// Since Windows Vista, it looks like Microsoft decided to change
// the meaning of the window position to the shadow position (when
Expand Down
4 changes: 4 additions & 0 deletions os/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class Window : public RefCount {
// The window size will be a multiple of the scale.
virtual void setScale(int scale) = 0;

// Returns the current window scale for default DPI value.
// It is constant across different displays.
virtual int baseScale() const { return scale(); }

// Returns true if the window is visible in the screen.
virtual bool isVisible() const = 0;

Expand Down