mirror of https://github.com/libsdl-org/SDL
Support PMv2 DPI awareness, add SDL_HINT_WINDOWS_DPI_AWARENESS
The hint allows setting a specific DPI awareness ("unaware", "system", "permonitor", "permonitorv2"). This is the first part of High-DPI support on Windows ( https://github.com/libsdl-org/SDL/issues/2119 ). It doesn't implement a virtualized SDL coordinate system, which will be addressed in a later commit. (This hint could be useful for SDL apps that want 1 SDL unit = 1 pixel, though.) Detecting and behaving correctly under per-monitor V2 (calling AdjustWindowRectExForDpi where needed) should fix the following issues: https://github.com/libsdl-org/SDL/issues/3286 https://github.com/libsdl-org/SDL/issues/4712
This commit is contained in:
parent
81d3adddbf
commit
51ebefeeee
|
@ -1808,6 +1808,36 @@ extern "C" {
|
|||
*/
|
||||
#define SDL_HINT_WINDOWS_USE_D3D9EX "SDL_WINDOWS_USE_D3D9EX"
|
||||
|
||||
/**
|
||||
* \brief Controls whether SDL will declare the process to be DPI aware.
|
||||
*
|
||||
* This hint must be set before initializing the video subsystem.
|
||||
*
|
||||
* The main purpose of declaring DPI awareness is to disable OS bitmap scaling of SDL windows on monitors with
|
||||
* a DPI scale factor.
|
||||
*
|
||||
* This hint is equivalent to requesting DPI awareness via external means (e.g. calling SetProcessDpiAwarenessContext)
|
||||
* and does not cause SDL to use a virtualized coordinate system, so it will generally give you 1 SDL coordinate = 1 pixel
|
||||
* even on high-DPI displays.
|
||||
*
|
||||
* For more information, see:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
|
||||
*
|
||||
* This variable can be set to the following values:
|
||||
* "" - Do not change the DPI awareness (default).
|
||||
* "unaware" - Declare the process as DPI unaware. (Windows 8.1 and later).
|
||||
* "system" - Request system DPI awareness. (Vista and later).
|
||||
* "permonitor" - Request per-monitor DPI awareness. (Windows 8.1 and later).
|
||||
* "permonitorv2" - Request per-monitor V2 DPI awareness. (Windows 10, version 1607 and later).
|
||||
* The most visible difference from "permonitor" is that window title bar will be scaled
|
||||
* to the visually correct size when dragging between monitors with different scale factors.
|
||||
* This is the preferred DPI awareness level.
|
||||
*
|
||||
* If the requested DPI awareness is not available on the currently running OS, SDL will try to request the best
|
||||
* available match.
|
||||
*/
|
||||
#define SDL_HINT_WINDOWS_DPI_AWARENESS "SDL_WINDOWS_DPI_AWARENESS"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden
|
||||
*
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "../../events/SDL_touch_c.h"
|
||||
#include "../../events/scancodes_windows.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
/* Dropfile support */
|
||||
#include <shellapi.h>
|
||||
|
@ -52,6 +53,8 @@
|
|||
#include "wmmsg.h"
|
||||
#endif
|
||||
|
||||
/* #define HIGHDPI_DEBUG */
|
||||
|
||||
/* Masks for processing the windows KEYDOWN and KEYUP messages */
|
||||
#define REPEATED_KEYMASK (1<<30)
|
||||
#define EXTENDED_KEYMASK (1<<24)
|
||||
|
@ -86,6 +89,12 @@
|
|||
#ifndef WM_UNICHAR
|
||||
#define WM_UNICHAR 0x0109
|
||||
#endif
|
||||
#ifndef WM_DPICHANGED
|
||||
#define WM_DPICHANGED 0x02E0
|
||||
#endif
|
||||
#ifndef WM_GETDPISCALEDSIZE
|
||||
#define WM_GETDPISCALEDSIZE 0x02E4
|
||||
#endif
|
||||
|
||||
#ifndef IS_HIGH_SURROGATE
|
||||
#define IS_HIGH_SURROGATE(x) (((x) >= 0xd800) && ((x) <= 0xdbff))
|
||||
|
@ -1084,7 +1093,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
size.bottom = h;
|
||||
size.right = w;
|
||||
|
||||
AdjustWindowRectEx(&size, style, menu, 0);
|
||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||
UINT dpi = data->videodata->GetDpiForWindow(hwnd);
|
||||
data->videodata->AdjustWindowRectExForDpi(&size, style, menu, 0, dpi);
|
||||
} else {
|
||||
AdjustWindowRectEx(&size, style, menu, 0);
|
||||
}
|
||||
w = size.right - size.left;
|
||||
h = size.bottom - size.top;
|
||||
}
|
||||
|
@ -1154,6 +1168,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
h = rect.bottom - rect.top;
|
||||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, h);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WM_WINDOWPOSCHANGED: Windows client rect (pixels): (%d, %d) (%d x %d)\tSDL client rect: (%d, %d) (%d x %d)\tGetDpiForWindow: %d",
|
||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||
x, y, w, h, data->videodata->GetDpiForWindow ? (int)data->videodata->GetDpiForWindow(data->hwnd) : 0);
|
||||
#endif
|
||||
|
||||
/* Forces a WM_PAINT event */
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
|
||||
|
@ -1399,6 +1419,120 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_GETDPISCALEDSIZE:
|
||||
/* Windows 10 Creators Update+ */
|
||||
/* Documented as only being sent to windows that are per-monitor V2 DPI aware. */
|
||||
if (data->videodata->GetDpiForWindow && data->videodata->AdjustWindowRectExForDpi) {
|
||||
/* Windows expects applications to scale their window rects linearly
|
||||
when dragging between monitors with different DPI's.
|
||||
e.g. a 100x100 window dragged to a 200% scaled monitor
|
||||
becomes 200x200.
|
||||
|
||||
For SDL, we instead want the client size to scale linearly.
|
||||
This is not the same as the window rect scaling linearly,
|
||||
because Windows doesn't scale the non-client area (titlebar etc.)
|
||||
linearly. So, we need to handle this message to request custom
|
||||
scaling. */
|
||||
|
||||
const int nextDPI = (int)wParam;
|
||||
const int prevDPI = (int)data->videodata->GetDpiForWindow(hwnd);
|
||||
SIZE *sizeInOut = (SIZE *)lParam;
|
||||
|
||||
int frame_w, frame_h;
|
||||
int query_client_w_win, query_client_h_win;
|
||||
|
||||
const DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
const BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WM_GETDPISCALEDSIZE: current DPI: %d potential DPI: %d input size: (%dx%d)",
|
||||
prevDPI, nextDPI, sizeInOut->cx, sizeInOut->cy);
|
||||
#endif
|
||||
|
||||
/* Subtract the window frame size that would have been used at prevDPI */
|
||||
{
|
||||
RECT rect = {0};
|
||||
|
||||
if (!(data->window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
data->videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, prevDPI);
|
||||
}
|
||||
|
||||
frame_w = -rect.left + rect.right;
|
||||
frame_h = -rect.top + rect.bottom;
|
||||
|
||||
query_client_w_win = sizeInOut->cx - frame_w;
|
||||
query_client_h_win = sizeInOut->cy - frame_h;
|
||||
}
|
||||
|
||||
/* Add the window frame size that would be used at nextDPI */
|
||||
{
|
||||
RECT rect = { 0, 0, query_client_w_win, query_client_h_win };
|
||||
|
||||
if (!(data->window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
data->videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, nextDPI);
|
||||
}
|
||||
|
||||
/* This is supposed to control the suggested rect param of WM_DPICHANGED */
|
||||
sizeInOut->cx = rect.right - rect.left;
|
||||
sizeInOut->cy = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WM_GETDPISCALEDSIZE: output size: (%dx%d)", sizeInOut->cx, sizeInOut->cy);
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED:
|
||||
/* Windows 8.1+ */
|
||||
{
|
||||
const int newDPI = HIWORD(wParam);
|
||||
RECT* const suggestedRect = (RECT*)lParam;
|
||||
int w, h;
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WM_DPICHANGED: to %d\tsuggested rect: (%d, %d), (%dx%d)\n", newDPI,
|
||||
suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
|
||||
#endif
|
||||
|
||||
/* DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 means that
|
||||
WM_GETDPISCALEDSIZE will have been called, so we can use suggestedRect. */
|
||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||
w = suggestedRect->right - suggestedRect->left;
|
||||
h = suggestedRect->bottom - suggestedRect->top;
|
||||
} else {
|
||||
RECT rect = { 0, 0, data->window->w, data->window->h };
|
||||
const DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
const BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||
|
||||
if (!(data->window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
AdjustWindowRectEx(&rect, style, menu, 0);
|
||||
}
|
||||
|
||||
w = rect.right - rect.left;
|
||||
h = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WM_DPICHANGED: current SDL window size: (%dx%d)\tcalling SetWindowPos: (%d, %d), (%dx%d)\n",
|
||||
data->window->w, data->window->h,
|
||||
suggestedRect->left, suggestedRect->top, w, h);
|
||||
#endif
|
||||
|
||||
data->expected_resize = SDL_TRUE;
|
||||
SetWindowPos(hwnd,
|
||||
NULL,
|
||||
suggestedRect->left,
|
||||
suggestedRect->top,
|
||||
w,
|
||||
h,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
data->expected_resize = SDL_FALSE;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* If there's a window proc, assume it's going to handle messages */
|
||||
|
|
|
@ -122,6 +122,16 @@ WIN_CreateDevice(int devindex)
|
|||
data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT)) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
|
||||
data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
|
||||
data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
|
||||
data->SetProcessDPIAware = (BOOL (WINAPI *)(void)) SDL_LoadFunction(data->userDLL, "SetProcessDPIAware");
|
||||
data->SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "SetProcessDpiAwarenessContext");
|
||||
data->SetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "SetThreadDpiAwarenessContext");
|
||||
data->GetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(void)) SDL_LoadFunction(data->userDLL, "GetThreadDpiAwarenessContext");
|
||||
data->GetAwarenessFromDpiAwarenessContext = (DPI_AWARENESS (WINAPI *)(DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "GetAwarenessFromDpiAwarenessContext");
|
||||
data->EnableNonClientDpiScaling = (BOOL (WINAPI *)(HWND)) SDL_LoadFunction(data->userDLL, "EnableNonClientDpiScaling");
|
||||
data->AdjustWindowRectExForDpi = (BOOL (WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT)) SDL_LoadFunction(data->userDLL, "AdjustWindowRectExForDpi");
|
||||
data->GetDpiForWindow = (UINT (WINAPI *)(HWND)) SDL_LoadFunction(data->userDLL, "GetDpiForWindow");
|
||||
data->AreDpiAwarenessContextsEqual = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "AreDpiAwarenessContextsEqual");
|
||||
data->IsValidDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "IsValidDpiAwarenessContext");
|
||||
} else {
|
||||
SDL_ClearError();
|
||||
}
|
||||
|
@ -129,6 +139,7 @@ WIN_CreateDevice(int devindex)
|
|||
data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
|
||||
if (data->shcoreDLL) {
|
||||
data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
|
||||
data->SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS)) SDL_LoadFunction(data->shcoreDLL, "SetProcessDpiAwareness");
|
||||
} else {
|
||||
SDL_ClearError();
|
||||
}
|
||||
|
@ -233,11 +244,103 @@ VideoBootStrap WINDOWS_bootstrap = {
|
|||
"windows", "SDL Windows video driver", WIN_CreateDevice
|
||||
};
|
||||
|
||||
static BOOL
|
||||
WIN_DeclareDPIAwareUnaware(_THIS)
|
||||
{
|
||||
SDL_VideoData* data = (SDL_VideoData*)_this->driverdata;
|
||||
|
||||
if (data->SetProcessDpiAwarenessContext) {
|
||||
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
|
||||
} else if (data->SetProcessDpiAwareness) {
|
||||
/* Windows 8.1 */
|
||||
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_DPI_UNAWARE));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
WIN_DeclareDPIAwareSystem(_THIS)
|
||||
{
|
||||
SDL_VideoData* data = (SDL_VideoData*)_this->driverdata;
|
||||
|
||||
if (data->SetProcessDpiAwarenessContext) {
|
||||
/* Windows 10, version 1607 */
|
||||
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
|
||||
} else if (data->SetProcessDpiAwareness) {
|
||||
/* Windows 8.1 */
|
||||
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE));
|
||||
} else if (data->SetProcessDPIAware) {
|
||||
/* Windows Vista */
|
||||
return data->SetProcessDPIAware();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
WIN_DeclareDPIAwarePerMonitor(_THIS)
|
||||
{
|
||||
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
|
||||
|
||||
if (data->SetProcessDpiAwarenessContext) {
|
||||
/* Windows 10, version 1607 */
|
||||
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
|
||||
} else if (data->SetProcessDpiAwareness) {
|
||||
/* Windows 8.1 */
|
||||
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE));
|
||||
} else {
|
||||
/* Older OS: fall back to system DPI aware */
|
||||
return WIN_DeclareDPIAwareSystem(_this);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
WIN_DeclareDPIAwarePerMonitorV2(_THIS)
|
||||
{
|
||||
SDL_VideoData* data = (SDL_VideoData*)_this->driverdata;
|
||||
|
||||
/* Declare DPI aware(may have been done in external code or a manifest, as well) */
|
||||
if (data->SetProcessDpiAwarenessContext) {
|
||||
/* Windows 10, version 1607 */
|
||||
|
||||
/* NOTE: SetThreadDpiAwarenessContext doesn't work here with OpenGL - the OpenGL contents
|
||||
end up still getting OS scaled. (tested on Windows 10 21H1 19043.1348, NVIDIA 496.49) */
|
||||
if (data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return WIN_DeclareDPIAwarePerMonitor(_this);
|
||||
}
|
||||
} else {
|
||||
/* Older OS: fall back to per-monitor (or system) */
|
||||
return WIN_DeclareDPIAwarePerMonitor(_this);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WIN_InitDPIAwareness(_THIS)
|
||||
{
|
||||
const char* hint = SDL_GetHint(SDL_HINT_WINDOWS_DPI_AWARENESS);
|
||||
|
||||
if (hint != NULL) {
|
||||
if (SDL_strcmp(hint, "permonitorv2") == 0) {
|
||||
WIN_DeclareDPIAwarePerMonitorV2(_this);
|
||||
} else if (SDL_strcmp(hint, "permonitor") == 0) {
|
||||
WIN_DeclareDPIAwarePerMonitor(_this);
|
||||
} else if (SDL_strcmp(hint, "system") == 0) {
|
||||
WIN_DeclareDPIAwareSystem(_this);
|
||||
} else if (SDL_strcmp(hint, "unaware") == 0) {
|
||||
WIN_DeclareDPIAwareUnaware(_this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
WIN_VideoInit(_THIS)
|
||||
{
|
||||
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
|
||||
|
||||
WIN_InitDPIAwareness(_this);
|
||||
|
||||
if (WIN_InitModes(_this) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -473,6 +576,19 @@ SDL_DXGIGetOutputInfo(int displayIndex, int *adapterIndex, int *outputIndex)
|
|||
#endif
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
WIN_IsPerMonitorV2DPIAware(_THIS)
|
||||
{
|
||||
SDL_VideoData* data = (SDL_VideoData*) _this->driverdata;
|
||||
|
||||
if (data->AreDpiAwarenessContextsEqual && data->GetThreadDpiAwarenessContext) {
|
||||
/* Windows 10, version 1607 */
|
||||
return (SDL_bool)data->AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
|
||||
data->GetThreadDpiAwarenessContext());
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
||||
/* vim: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -86,10 +86,40 @@ typedef enum MONITOR_DPI_TYPE {
|
|||
MDT_DEFAULT = MDT_EFFECTIVE_DPI
|
||||
} MONITOR_DPI_TYPE;
|
||||
|
||||
typedef enum PROCESS_DPI_AWARENESS {
|
||||
PROCESS_DPI_UNAWARE = 0,
|
||||
PROCESS_SYSTEM_DPI_AWARE = 1,
|
||||
PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||
} PROCESS_DPI_AWARENESS;
|
||||
|
||||
#else
|
||||
#include <shellscalingapi.h>
|
||||
#endif /* WINVER < 0x0603 */
|
||||
|
||||
#ifndef _DPI_AWARENESS_CONTEXTS_
|
||||
|
||||
typedef enum DPI_AWARENESS {
|
||||
DPI_AWARENESS_INVALID = -1,
|
||||
DPI_AWARENESS_UNAWARE = 0,
|
||||
DPI_AWARENESS_SYSTEM_AWARE = 1,
|
||||
DPI_AWARENESS_PER_MONITOR_AWARE = 2
|
||||
} DPI_AWARENESS;
|
||||
|
||||
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
|
||||
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
|
||||
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
|
||||
|
||||
#endif /* _DPI_AWARENESS_CONTEXTS_ */
|
||||
|
||||
/* Windows 10 Creators Update */
|
||||
#if NTDDI_VERSION < 0x0A000003
|
||||
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
|
||||
|
||||
#endif /* NTDDI_VERSION < 0x0A000003 */
|
||||
|
||||
typedef BOOL (*PFNSHFullScreen)(HWND, DWORD);
|
||||
typedef void (*PFCoordTransform)(SDL_Window*, POINT*);
|
||||
|
||||
|
@ -137,13 +167,24 @@ typedef struct SDL_VideoData
|
|||
BOOL (WINAPI *CloseTouchInputHandle)( HTOUCHINPUT );
|
||||
BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
|
||||
BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
|
||||
BOOL (WINAPI *SetProcessDPIAware)( void );
|
||||
BOOL (WINAPI *SetProcessDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
|
||||
DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
|
||||
DPI_AWARENESS_CONTEXT (WINAPI *GetThreadDpiAwarenessContext)( void );
|
||||
DPI_AWARENESS (WINAPI *GetAwarenessFromDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
|
||||
BOOL (WINAPI *EnableNonClientDpiScaling)( HWND );
|
||||
BOOL (WINAPI *AdjustWindowRectExForDpi)( LPRECT, DWORD, BOOL, DWORD, UINT );
|
||||
UINT (WINAPI *GetDpiForWindow)( HWND );
|
||||
BOOL (WINAPI *AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT);
|
||||
BOOL (WINAPI *IsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
|
||||
|
||||
void* shcoreDLL;
|
||||
HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR hmonitor,
|
||||
MONITOR_DPI_TYPE dpiType,
|
||||
UINT *dpiX,
|
||||
UINT *dpiY );
|
||||
|
||||
HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS dpiAwareness);
|
||||
|
||||
SDL_bool ime_com_initialized;
|
||||
struct ITfThreadMgr *ime_threadmgr;
|
||||
SDL_bool ime_initialized;
|
||||
|
@ -203,6 +244,8 @@ extern SDL_bool g_WindowFrameUsableWhileCursorHidden;
|
|||
typedef struct IDirect3D9 IDirect3D9;
|
||||
extern SDL_bool D3D_LoadDLL( void **pD3DDLL, IDirect3D9 **pDirect3D9Interface );
|
||||
|
||||
extern SDL_bool WIN_IsPerMonitorV2DPIAware(_THIS);
|
||||
|
||||
#endif /* SDL_windowsvideo_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -114,8 +114,11 @@ GetWindowStyle(SDL_Window * window)
|
|||
}
|
||||
|
||||
static void
|
||||
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
|
||||
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current,
|
||||
SDL_bool force_ignore_window_dpi)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
SDL_VideoData* videodata = SDL_GetVideoDevice() ? SDL_GetVideoDevice()->driverdata : NULL;
|
||||
RECT rect;
|
||||
|
||||
rect.left = 0;
|
||||
|
@ -126,8 +129,44 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
|
|||
/* borderless windows will have WM_NCCALCSIZE return 0 for the non-client area. When this happens, it looks like windows will send a resize message
|
||||
expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
|
||||
*/
|
||||
if (!(window->flags & SDL_WINDOW_BORDERLESS))
|
||||
AdjustWindowRectEx(&rect, style, menu, 0);
|
||||
if (!(window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||
/* With per-monitor v2, the window border/titlebar size depend on the DPI, so we need to call AdjustWindowRectExForDpi instead of
|
||||
AdjustWindowRectEx. */
|
||||
UINT dpi;
|
||||
|
||||
if (data && !force_ignore_window_dpi) {
|
||||
/* The usual case - we have a HWND, so we can look up the DPI to use. */
|
||||
dpi = videodata->GetDpiForWindow(data->hwnd);
|
||||
} else {
|
||||
/* In this case we guess the window DPI based on its rectangle on the screen.
|
||||
|
||||
This happens at creation time of an SDL window, before we have a HWND,
|
||||
and also in a bug workaround (when force_ignore_window_dpi is SDL_TRUE
|
||||
- see WIN_SetWindowFullscreen).
|
||||
*/
|
||||
UINT unused;
|
||||
RECT screen_rect;
|
||||
HMONITOR mon;
|
||||
|
||||
screen_rect.left = (use_current ? window->x : window->windowed.x);
|
||||
screen_rect.top = (use_current ? window->y : window->windowed.y);
|
||||
screen_rect.right = screen_rect.left + (use_current ? window->w : window->windowed.w);
|
||||
screen_rect.bottom = screen_rect.top + (use_current ? window->h : window->windowed.h);
|
||||
|
||||
mon = MonitorFromRect(&screen_rect, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
/* GetDpiForMonitor docs promise to return the same hdpi / vdpi */
|
||||
if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &dpi, &unused) != S_OK) {
|
||||
dpi = 96;
|
||||
}
|
||||
}
|
||||
|
||||
videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, dpi);
|
||||
} else {
|
||||
AdjustWindowRectEx(&rect, style, menu, 0);
|
||||
}
|
||||
}
|
||||
|
||||
*x = (use_current ? window->x : window->windowed.x) + rect.left;
|
||||
*y = (use_current ? window->y : window->windowed.y) + rect.top;
|
||||
|
@ -145,7 +184,7 @@ WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height
|
|||
|
||||
style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||
WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
|
||||
WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current, SDL_FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -356,7 +395,7 @@ WIN_CreateWindow(_THIS, SDL_Window * window)
|
|||
style |= GetWindowStyle(window);
|
||||
|
||||
/* Figure out what the window area will be */
|
||||
WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE);
|
||||
WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE, SDL_FALSE);
|
||||
|
||||
hwnd =
|
||||
CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
|
||||
|
@ -781,7 +820,13 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
|
|||
}
|
||||
|
||||
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||
WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
|
||||
/* HighDPI bug workaround - when leaving exclusive fullscreen, the window DPI reported
|
||||
by GetDpiForWindow will be wrong. Pass SDL_TRUE for `force_ignore_window_dpi`
|
||||
makes us recompute the DPI based on the monitor we are restoring onto.
|
||||
Fixes windows shrinking slightly when going from exclusive fullscreen to windowed
|
||||
on a HighDPI monitor with scaling.
|
||||
*/
|
||||
WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE, SDL_TRUE);
|
||||
}
|
||||
SetWindowLong(hwnd, GWL_STYLE, style);
|
||||
data->expected_resize = SDL_TRUE;
|
||||
|
|
Loading…
Reference in New Issue