Windows DPI scaling/highdpi support
Adds hint "SDL_WINDOWS_DPI_SCALING" which can be set to "1" to change the SDL coordinate system units to be DPI-scaled points, rather than pixels everywhere. This means windows will be appropriately sized, even when created on high-DPI displays with scaling. e.g. requesting a 640x480 window from SDL, on a display with 125% scaling in Windows display settings, will create a window with an 800x600 client area (in pixels). Setting this to "1" implicitly requests process DPI awareness (setting SDL_WINDOWS_DPI_AWARENESS is unnecessary), and forces SDL_WINDOW_ALLOW_HIGHDPI on all windows.main
parent
df36f926fc
commit
ab81a559f4
|
@ -1838,6 +1838,27 @@ extern "C" {
|
|||
*/
|
||||
#define SDL_HINT_WINDOWS_DPI_AWARENESS "SDL_WINDOWS_DPI_AWARENESS"
|
||||
|
||||
/**
|
||||
* \brief Uses DPI-scaled points as the SDL coordinate system on Windows.
|
||||
*
|
||||
* This changes the SDL coordinate system units to be DPI-scaled points, rather than pixels everywhere.
|
||||
* This means windows will be appropriately sized, even when created on high-DPI displays with scaling.
|
||||
*
|
||||
* e.g. requesting a 640x480 window from SDL, on a display with 125% scaling in Windows display settings,
|
||||
* will create a window with an 800x600 client area (in pixels).
|
||||
*
|
||||
* Setting this to "1" implicitly requests process DPI awareness (setting SDL_WINDOWS_DPI_AWARENESS is unnecessary),
|
||||
* and forces SDL_WINDOW_ALLOW_HIGHDPI on all windows.
|
||||
*
|
||||
* This variable can be set to the following values:
|
||||
* "0" - SDL coordinates equal Windows coordinates. No automatic window resizing when dragging
|
||||
* between monitors with different scale factors (unless this is performed by
|
||||
* Windows itself, which is the case when the process is DPI unaware).
|
||||
* "1" - SDL coordinates are in DPI-scaled points. Automatically resize windows as needed on
|
||||
* displays with non-100% scale factors.
|
||||
*/
|
||||
#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden
|
||||
*
|
||||
|
|
|
@ -308,7 +308,7 @@ D3D_ActivateRenderer(SDL_Renderer * renderer)
|
|||
int w, h;
|
||||
Uint32 window_flags = SDL_GetWindowFlags(window);
|
||||
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
WIN_GetDrawableSize(window, &w, &h);
|
||||
data->pparams.BackBufferWidth = w;
|
||||
data->pparams.BackBufferHeight = h;
|
||||
if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
||||
|
@ -354,6 +354,13 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
D3D_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
||||
{
|
||||
WIN_GetDrawableSize(renderer->window, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static D3DBLEND
|
||||
GetBlendFunc(SDL_BlendFactor factor)
|
||||
{
|
||||
|
@ -1616,6 +1623,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
}
|
||||
|
||||
renderer->WindowEvent = D3D_WindowEvent;
|
||||
renderer->GetOutputSize = D3D_GetOutputSize;
|
||||
renderer->SupportsBlendMode = D3D_SupportsBlendMode;
|
||||
renderer->CreateTexture = D3D_CreateTexture;
|
||||
renderer->UpdateTexture = D3D_UpdateTexture;
|
||||
|
@ -1645,7 +1653,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
SDL_GetWindowWMInfo(window, &windowinfo);
|
||||
|
||||
window_flags = SDL_GetWindowFlags(window);
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
WIN_GetDrawableSize(window, &w, &h);
|
||||
SDL_GetWindowDisplayMode(window, &fullscreen_mode);
|
||||
|
||||
SDL_zero(pparams);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#define COBJMACROS
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "../../video/windows/SDL_windowswindow.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_syswm.h"
|
||||
|
@ -910,7 +911,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
|
|||
/* The width and height of the swap chain must be based on the display's
|
||||
* non-rotated size.
|
||||
*/
|
||||
SDL_GetWindowSize(renderer->window, &w, &h);
|
||||
WIN_GetDrawableSize(renderer->window, &w, &h);
|
||||
data->rotation = D3D11_GetCurrentRotation();
|
||||
/* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
|
||||
if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
|
||||
|
@ -1051,6 +1052,13 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
D3D11_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
||||
{
|
||||
WIN_GetDrawableSize(renderer->window, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
|
||||
{
|
||||
|
@ -2366,6 +2374,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
data->identity = MatrixIdentity();
|
||||
|
||||
renderer->WindowEvent = D3D11_WindowEvent;
|
||||
renderer->GetOutputSize = D3D11_GetOutputSize;
|
||||
renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
|
||||
renderer->CreateTexture = D3D11_CreateTexture;
|
||||
renderer->UpdateTexture = D3D11_UpdateTexture;
|
||||
|
|
|
@ -1374,12 +1374,17 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
|||
|
||||
/* Generate a mode change event here */
|
||||
if (resized) {
|
||||
#ifndef ANDROID
|
||||
#if !defined(ANDROID) && !defined(WIN32)
|
||||
/* Android may not resize the window to exactly what our fullscreen mode is, especially on
|
||||
* windowed Android environments like the Chromebook or Samsung DeX. Given this, we shouldn't
|
||||
* use fullscreen_mode.w and fullscreen_mode.h, but rather get our current native size. As such,
|
||||
* Android's SetWindowFullscreen will generate the window event for us with the proper final size.
|
||||
*/
|
||||
|
||||
/* This is also unnecessary on Win32 (WIN_SetWindowFullscreen calls SetWindowPos,
|
||||
* WM_WINDOWPOSCHANGED will send SDL_WINDOWEVENT_RESIZED). Also, on Windows with DPI scaling enabled,
|
||||
* we're keeping modes in pixels, but window sizes in dpi-scaled points, so this would be a unit mismatch.
|
||||
*/
|
||||
SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
|
||||
fullscreen_mode.w, fullscreen_mode.h);
|
||||
#endif
|
||||
|
|
|
@ -749,7 +749,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
/* Only generate mouse events for real mouse */
|
||||
if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
|
||||
lParam != data->last_pointer_update) {
|
||||
SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
|
||||
WIN_ClientPointToSDL(data->window, &x, &y);
|
||||
|
||||
SDL_SendMouseMotion(data->window, 0, 0, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1068,6 +1073,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
|
||||
SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
|
||||
|
||||
/* Convert w, h, min_w, min_h, max_w, max_h from dpi-scaled points to pixels,
|
||||
treating them as coordinates within the client area. */
|
||||
WIN_ClientPointFromSDL(data->window, &w, &h);
|
||||
WIN_ClientPointFromSDL(data->window, &min_w, &min_h);
|
||||
WIN_ClientPointFromSDL(data->window, &max_w, &max_h);
|
||||
|
||||
/* Store in min_w and min_h difference between current size and minimal
|
||||
size so we don't need to call AdjustWindowRectEx twice */
|
||||
min_w -= w;
|
||||
|
@ -1168,16 +1179,21 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
x = rect.left;
|
||||
y = rect.top;
|
||||
WIN_ScreenPointToSDL(&x, &y);
|
||||
|
||||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
|
||||
|
||||
/* Convert client area width/height from pixels to dpi-scaled points */
|
||||
w = rect.right - rect.left;
|
||||
h = rect.bottom - rect.top;
|
||||
WIN_ClientPointToSDL(data->window, &w, &h);
|
||||
|
||||
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);
|
||||
SDL_Log("WM_WINDOWPOSCHANGED: Windows client rect (pixels): (%d, %d) (%d x %d)\tSDL client rect (points): (%d, %d) (%d x %d) cached dpi %d, windows reported dpi %d",
|
||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||
x, y, w, h, data->scaling_dpi, data->videodata->GetDpiForWindow ? data->videodata->GetDpiForWindow(data->hwnd) : 0);
|
||||
#endif
|
||||
|
||||
/* Forces a WM_PAINT event */
|
||||
|
@ -1385,6 +1401,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
|
||||
w = data->window->windowed.w;
|
||||
h = data->window->windowed.h;
|
||||
WIN_ClientPointFromSDL(data->window, &w, &h);
|
||||
params->rgrc[0].right = params->rgrc[0].left + w;
|
||||
params->rgrc[0].bottom = params->rgrc[0].top + h;
|
||||
}
|
||||
|
@ -1405,6 +1422,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
SDL_HitTestResult rc;
|
||||
point.x = winpoint.x;
|
||||
point.y = winpoint.y;
|
||||
WIN_ClientPointToSDL(data->window, &point.x, &point.y);
|
||||
rc = window->hit_test(window, &point, window->hit_test_data);
|
||||
switch (rc) {
|
||||
#define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
|
||||
|
@ -1474,6 +1492,14 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
query_client_h_win = sizeInOut->cy - frame_h;
|
||||
}
|
||||
|
||||
/* Convert to new dpi if we are using scaling.
|
||||
* Otherwise leave as pixels.
|
||||
*/
|
||||
if (data->videodata->dpi_scaling_enabled) {
|
||||
query_client_w_win = MulDiv(query_client_w_win, nextDPI, prevDPI);
|
||||
query_client_h_win = MulDiv(query_client_h_win, nextDPI, prevDPI);
|
||||
}
|
||||
|
||||
/* Add the window frame size that would be used at nextDPI */
|
||||
{
|
||||
RECT rect = {0};
|
||||
|
@ -1508,6 +1534,15 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
|
||||
#endif
|
||||
|
||||
if (data->videodata->dpi_scaling_enabled) {
|
||||
/* Update the cached DPI value for this window */
|
||||
data->scaling_dpi = newDPI;
|
||||
|
||||
/* Send a SDL_WINDOWEVENT_SIZE_CHANGED saying that the client size (in dpi-scaled points) is unchanged.
|
||||
Renderers need to get this to know that the framebuffer size changed. */
|
||||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SIZE_CHANGED, data->window->w, data->window->h);
|
||||
}
|
||||
|
||||
if (data->expected_resize) {
|
||||
/* This DPI change is coming from an explicit SetWindowPos call within SDL.
|
||||
Assume all call sites are calculating the DPI-aware frame correctly, so
|
||||
|
@ -1539,6 +1574,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
rect.right = data->window->w;
|
||||
rect.bottom = data->window->h;
|
||||
|
||||
if (data->videodata->dpi_scaling_enabled) {
|
||||
/* scale client size to from points to the new DPI */
|
||||
rect.right = MulDiv(rect.right, newDPI, 96);
|
||||
rect.bottom = MulDiv(rect.bottom, newDPI, 96);
|
||||
}
|
||||
|
||||
if (!(data->window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
AdjustWindowRectEx(&rect, style, menu, 0);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#endif
|
||||
|
||||
/* #define DEBUG_MODES */
|
||||
/* #define HIGHDPI_DEBUG_VERBOSE */
|
||||
|
||||
static void
|
||||
WIN_UpdateDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode * mode)
|
||||
|
@ -50,6 +51,15 @@ WIN_UpdateDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *
|
|||
int logical_width = GetDeviceCaps( hdc, HORZRES );
|
||||
int logical_height = GetDeviceCaps( hdc, VERTRES );
|
||||
|
||||
/* High-DPI notes:
|
||||
|
||||
If DPI-unaware:
|
||||
- GetDeviceCaps( hdc, HORZRES ) will return the monitor width in points.
|
||||
- DeviceMode.dmPelsWidth is actual pixels (unlike almost all other Windows API's,
|
||||
it's not virtualized when DPI unaware).
|
||||
|
||||
If DPI-aware:
|
||||
- GetDeviceCaps( hdc, HORZRES ) will return pixels, same as DeviceMode.dmPelsWidth */
|
||||
mode->w = logical_width;
|
||||
mode->h = logical_height;
|
||||
|
||||
|
@ -301,10 +311,46 @@ WIN_InitModes(_THIS)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the monitor rect and work rect from pixels to the SDL coordinate system (monitor origins are in pixels,
|
||||
* monitor size in DPI-scaled points).
|
||||
*
|
||||
* No-op if DPI scaling is not enabled.
|
||||
*/
|
||||
static void
|
||||
WIN_MonitorInfoToSDL(const SDL_VideoData *videodata, HMONITOR monitor, MONITORINFO *info)
|
||||
{
|
||||
UINT xdpi, ydpi;
|
||||
|
||||
if (!videodata->dpi_scaling_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for Windows < 8.1*/
|
||||
if (!videodata->GetDpiForMonitor) {
|
||||
return;
|
||||
}
|
||||
if (videodata->GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK) {
|
||||
/* Shouldn't happen? */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert monitor size to points, leaving the monitor position in pixels */
|
||||
info->rcMonitor.right = info->rcMonitor.left + MulDiv(info->rcMonitor.right - info->rcMonitor.left, 96, xdpi);
|
||||
info->rcMonitor.bottom = info->rcMonitor.top + MulDiv(info->rcMonitor.bottom - info->rcMonitor.top, 96, ydpi);
|
||||
|
||||
/* Convert monitor work rect to points */
|
||||
info->rcWork.left = info->rcMonitor.left + MulDiv(info->rcWork.left - info->rcMonitor.left, 96, xdpi);
|
||||
info->rcWork.right = info->rcMonitor.left + MulDiv(info->rcWork.right - info->rcMonitor.left, 96, xdpi);
|
||||
info->rcWork.top = info->rcMonitor.top + MulDiv(info->rcWork.top - info->rcMonitor.top, 96, ydpi);
|
||||
info->rcWork.bottom = info->rcMonitor.top + MulDiv(info->rcWork.bottom - info->rcMonitor.top, 96, ydpi);
|
||||
}
|
||||
|
||||
int
|
||||
WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
||||
{
|
||||
const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
|
||||
const SDL_VideoData *videodata = (SDL_VideoData *)display->device->driverdata;
|
||||
MONITORINFO minfo;
|
||||
BOOL rc;
|
||||
|
||||
|
@ -316,6 +362,7 @@ WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
|||
return SDL_SetError("Couldn't find monitor data");
|
||||
}
|
||||
|
||||
WIN_MonitorInfoToSDL(videodata, data->MonitorHandle, &minfo);
|
||||
rect->x = minfo.rcMonitor.left;
|
||||
rect->y = minfo.rcMonitor.top;
|
||||
rect->w = minfo.rcMonitor.right - minfo.rcMonitor.left;
|
||||
|
@ -387,6 +434,7 @@ int
|
|||
WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
||||
{
|
||||
const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
|
||||
const SDL_VideoData *videodata = (SDL_VideoData *)display->device->driverdata;
|
||||
MONITORINFO minfo;
|
||||
BOOL rc;
|
||||
|
||||
|
@ -398,6 +446,7 @@ WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
|||
return SDL_SetError("Couldn't find monitor data");
|
||||
}
|
||||
|
||||
WIN_MonitorInfoToSDL(videodata, data->MonitorHandle, &minfo);
|
||||
rect->x = minfo.rcWork.left;
|
||||
rect->y = minfo.rcWork.top;
|
||||
rect->w = minfo.rcWork.right - minfo.rcWork.left;
|
||||
|
@ -406,6 +455,190 @@ WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If x, y are outside of rect, snaps them to the closest point inside rect
|
||||
* (between rect->x, rect->y, inclusive, and rect->x + w, rect->y + h, exclusive)
|
||||
*/
|
||||
static void
|
||||
SDL_GetClosestPointOnRect(const SDL_Rect *rect, int *x, int *y)
|
||||
{
|
||||
const int right = rect->x + rect->w - 1;
|
||||
const int bottom = rect->y + rect->h - 1;
|
||||
|
||||
if (*x < rect->x) {
|
||||
*x = rect->x;
|
||||
} else if (*x > right) {
|
||||
*x = right;
|
||||
}
|
||||
|
||||
if (*y < rect->y) {
|
||||
*y = rect->y;
|
||||
} else if (*y > bottom) {
|
||||
*y = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display index of the display which either encloses the given point
|
||||
* or is closest to it. The point is in SDL screen coordinates.
|
||||
*/
|
||||
static int
|
||||
SDL_GetPointDisplayIndex(int x, int y)
|
||||
{
|
||||
int i, dist;
|
||||
int closest = -1;
|
||||
int closest_dist = 0x7FFFFFFF;
|
||||
SDL_Point closest_point_on_display;
|
||||
SDL_Point delta;
|
||||
SDL_Rect rect;
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
SDL_Point point;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
|
||||
for (i = 0; i < _this->num_displays; ++i) {
|
||||
/* Check for an exact match */
|
||||
SDL_GetDisplayBounds(i, &rect);
|
||||
if (SDL_EnclosePoints(&point, 1, &rect, NULL)) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Snap x, y to the display rect */
|
||||
closest_point_on_display = point;
|
||||
SDL_GetClosestPointOnRect(&rect, &closest_point_on_display.x, &closest_point_on_display.y);
|
||||
|
||||
delta.x = point.x - closest_point_on_display.x;
|
||||
delta.y = point.y - closest_point_on_display.y;
|
||||
dist = (delta.x*delta.x + delta.y*delta.y);
|
||||
if (dist < closest_dist) {
|
||||
closest = i;
|
||||
closest_dist = dist;
|
||||
}
|
||||
}
|
||||
if (closest < 0) {
|
||||
SDL_SetError("Couldn't find any displays");
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point from the SDL coordinate system (monitor origins are in pixels,
|
||||
* offset within a monitor in DPI-scaled points) to Windows virtual screen coordinates (pixels).
|
||||
*
|
||||
* No-op if DPI scaling is not enabled (returns 96 dpi).
|
||||
*
|
||||
* Returns the DPI of the monitor that was closest to x, y and used for the conversion.
|
||||
*/
|
||||
void WIN_ScreenPointFromSDL(int *x, int *y, int *dpiOut)
|
||||
{
|
||||
const SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
|
||||
const SDL_VideoData *videodata;
|
||||
int displayIndex;
|
||||
SDL_Rect bounds;
|
||||
float ddpi, hdpi, vdpi;
|
||||
int x_sdl, y_sdl;
|
||||
|
||||
if (dpiOut) {
|
||||
*dpiOut = 96;
|
||||
}
|
||||
|
||||
if (!videodevice || !videodevice->driverdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
videodata = (SDL_VideoData *)videodevice->driverdata;
|
||||
if (!videodata->dpi_scaling_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Can't use MonitorFromPoint for this because we currently have SDL coordinates, not pixels */
|
||||
displayIndex = SDL_GetPointDisplayIndex(*x, *y);
|
||||
|
||||
if (displayIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_GetDisplayBounds(displayIndex, &bounds) < 0
|
||||
|| SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dpiOut) {
|
||||
*dpiOut = (int) ddpi;
|
||||
}
|
||||
|
||||
/* Undo the DPI-scaling within the monitor bounds to convert back to pixels */
|
||||
x_sdl = *x;
|
||||
y_sdl = *y;
|
||||
*x = bounds.x + MulDiv(x_sdl - bounds.x, (int)ddpi, 96);
|
||||
*y = bounds.y + MulDiv(y_sdl - bounds.y, (int)ddpi, 96);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG_VERBOSE
|
||||
SDL_Log("WIN_ScreenPointFromSDL: (%d, %d) points -> (%d x %d) pixels, using %d DPI monitor",
|
||||
x_sdl, y_sdl, *x, *y, (int)ddpi);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point from Windows virtual screen coordinates (pixels) to the SDL
|
||||
* coordinate system (monitor origins are in pixels, offset within a monitor in DPI-scaled points).
|
||||
*
|
||||
* No-op if DPI scaling is not enabled.
|
||||
*/
|
||||
void WIN_ScreenPointToSDL(int *x, int *y)
|
||||
{
|
||||
const SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
|
||||
const SDL_VideoData *videodata;
|
||||
POINT point;
|
||||
HMONITOR monitor;
|
||||
int i, displayIndex;
|
||||
SDL_Rect bounds;
|
||||
float ddpi, hdpi, vdpi;
|
||||
int x_pixels, y_pixels;
|
||||
|
||||
if (!videodevice || !videodevice->driverdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
videodata = (SDL_VideoData *)videodevice->driverdata;
|
||||
if (!videodata->dpi_scaling_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
point.x = *x;
|
||||
point.y = *y;
|
||||
monitor = MonitorFromPoint(point, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
/* Search for the corresponding SDL monitor */
|
||||
displayIndex = -1;
|
||||
for (i = 0; i < videodevice->num_displays; ++i) {
|
||||
SDL_DisplayData *driverdata = (SDL_DisplayData *)videodevice->displays[i].driverdata;
|
||||
if (driverdata->MonitorHandle == monitor) {
|
||||
displayIndex = i;
|
||||
}
|
||||
}
|
||||
if (displayIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get SDL display properties */
|
||||
if (SDL_GetDisplayBounds(displayIndex, &bounds) < 0
|
||||
|| SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert the point's offset within the monitor from pixels to DPI-scaled points */
|
||||
x_pixels = *x;
|
||||
y_pixels = *y;
|
||||
*x = bounds.x + MulDiv(x_pixels - bounds.x, 96, (int)ddpi);
|
||||
*y = bounds.y + MulDiv(y_pixels - bounds.y, 96, (int)ddpi);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG_VERBOSE
|
||||
SDL_Log("WIN_ScreenPointToSDL: (%d, %d) pixels -> (%d x %d) points, using %d DPI monitor",
|
||||
x_pixels, y_pixels, *x, *y, (int)ddpi);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||
{
|
||||
|
@ -432,6 +665,37 @@ WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MODES
|
||||
static void
|
||||
WIN_LogMonitor(_THIS, HMONITOR mon)
|
||||
{
|
||||
const SDL_VideoData *vid_data = (const SDL_VideoData *)_this->driverdata;
|
||||
MONITORINFOEX minfo;
|
||||
UINT xdpi = 0, ydpi = 0;
|
||||
char *name_utf8;
|
||||
|
||||
if (vid_data->GetDpiForMonitor) {
|
||||
vid_data->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
|
||||
}
|
||||
|
||||
SDL_zero(minfo);
|
||||
minfo.cbSize = sizeof(minfo);
|
||||
GetMonitorInfo(mon, (LPMONITORINFO)&minfo);
|
||||
|
||||
name_utf8 = WIN_StringToUTF8(minfo.szDevice);
|
||||
|
||||
SDL_Log("WIN_LogMonitor: monitor \"%s\": dpi: %d windows screen coordinates: %d, %d, %dx%d",
|
||||
name_utf8,
|
||||
xdpi,
|
||||
minfo.rcMonitor.left,
|
||||
minfo.rcMonitor.top,
|
||||
minfo.rcMonitor.right - minfo.rcMonitor.left,
|
||||
minfo.rcMonitor.bottom - minfo.rcMonitor.top);
|
||||
|
||||
SDL_free(name_utf8);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||
{
|
||||
|
@ -439,9 +703,30 @@ WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
|||
SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
|
||||
LONG status;
|
||||
|
||||
#ifdef DEBUG_MODES
|
||||
SDL_Log("WIN_SetDisplayMode: monitor state before mode change:");
|
||||
WIN_LogMonitor(_this, displaydata->MonitorHandle);
|
||||
#endif
|
||||
|
||||
/* High-DPI notes:
|
||||
|
||||
- ChangeDisplaySettingsEx always takes pixels.
|
||||
- e.g. if the display is set to 2880x1800 with 200% scaling in Display Settings
|
||||
- calling ChangeDisplaySettingsEx with a dmPelsWidth/Height other than 2880x1800 will
|
||||
change the monitor DPI to 96. (100% scaling)
|
||||
- calling ChangeDisplaySettingsEx with a dmPelsWidth/Height of 2880x1800 (or a NULL DEVMODE*) will
|
||||
reset the monitor DPI to 192. (200% scaling)
|
||||
|
||||
NOTE: these are temporary changes in DPI, not modifications to the Control Panel setting. */
|
||||
if (mode->driverdata == display->desktop_mode.driverdata) {
|
||||
#ifdef DEBUG_MODES
|
||||
SDL_Log("WIN_SetDisplayMode: resetting to original resolution");
|
||||
#endif
|
||||
status = ChangeDisplaySettingsExW(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL);
|
||||
} else {
|
||||
#ifdef DEBUG_MODES
|
||||
SDL_Log("WIN_SetDisplayMode: changing to %dx%d pixels", data->DeviceMode.dmPelsWidth, data->DeviceMode.dmPelsHeight);
|
||||
#endif
|
||||
status = ChangeDisplaySettingsExW(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
|
||||
}
|
||||
if (status != DISP_CHANGE_SUCCESSFUL) {
|
||||
|
@ -462,6 +747,12 @@ WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
|||
}
|
||||
return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MODES
|
||||
SDL_Log("WIN_SetDisplayMode: monitor state after mode change:");
|
||||
WIN_LogMonitor(_this, displaydata->MonitorHandle);
|
||||
#endif
|
||||
|
||||
EnumDisplaySettingsW(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
|
||||
WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode);
|
||||
return 0;
|
||||
|
|
|
@ -38,6 +38,8 @@ typedef struct
|
|||
extern int WIN_InitModes(_THIS);
|
||||
extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
|
||||
extern int WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
|
||||
extern void WIN_ScreenPointFromSDL(int *x, int *y, int *dpiOut);
|
||||
extern void WIN_ScreenPointToSDL(int *x, int *y);
|
||||
extern int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
|
||||
extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
|
||||
extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
|
||||
|
|
|
@ -290,6 +290,7 @@ WIN_WarpMouseGlobal(int x, int y)
|
|||
{
|
||||
POINT pt;
|
||||
|
||||
WIN_ScreenPointFromSDL(&x, &y, NULL);
|
||||
pt.x = x;
|
||||
pt.y = y;
|
||||
SetCursorPos(pt.x, pt.y);
|
||||
|
@ -333,6 +334,7 @@ WIN_GetGlobalMouseState(int *x, int *y)
|
|||
GetCursorPos(&pt);
|
||||
*x = (int) pt.x;
|
||||
*y = (int) pt.y;
|
||||
WIN_ScreenPointToSDL(x, y);
|
||||
|
||||
retval |= GetAsyncKeyState(!swapButtons ? VK_LBUTTON : VK_RBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
|
||||
retval |= GetAsyncKeyState(!swapButtons ? VK_RBUTTON : VK_LBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
|
||||
|
|
|
@ -676,6 +676,7 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window)
|
|||
_this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
|
||||
_this->GL_CreateContext = WIN_GLES_CreateContext;
|
||||
_this->GL_MakeCurrent = WIN_GLES_MakeCurrent;
|
||||
_this->GL_GetDrawableSize = WIN_GLES_GetDrawableSize;
|
||||
_this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
|
||||
_this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
|
||||
_this->GL_SwapWindow = WIN_GLES_SwapWindow;
|
||||
|
@ -822,6 +823,12 @@ WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WIN_GL_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
|
||||
{
|
||||
WIN_GetDrawableSize(window, w, h);
|
||||
}
|
||||
|
||||
int
|
||||
WIN_GL_SetSwapInterval(_THIS, int interval)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,7 @@ extern int WIN_GL_SetupWindow(_THIS, SDL_Window * window);
|
|||
extern SDL_GLContext WIN_GL_CreateContext(_THIS, SDL_Window * window);
|
||||
extern int WIN_GL_MakeCurrent(_THIS, SDL_Window * window,
|
||||
SDL_GLContext context);
|
||||
extern void WIN_GL_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h);
|
||||
extern int WIN_GL_SetSwapInterval(_THIS, int interval);
|
||||
extern int WIN_GL_GetSwapInterval(_THIS);
|
||||
extern int WIN_GL_SwapWindow(_THIS, SDL_Window * window);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowsopengles.h"
|
||||
#include "SDL_windowsopengl.h"
|
||||
#include "SDL_windowswindow.h"
|
||||
|
||||
/* EGL implementation of SDL OpenGL support */
|
||||
|
||||
|
@ -40,6 +41,7 @@ WIN_GLES_LoadLibrary(_THIS, const char *path) {
|
|||
_this->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
|
||||
_this->GL_CreateContext = WIN_GL_CreateContext;
|
||||
_this->GL_MakeCurrent = WIN_GL_MakeCurrent;
|
||||
_this->GL_GetDrawableSize = WIN_GL_GetDrawableSize;
|
||||
_this->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
|
||||
_this->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
|
||||
_this->GL_SwapWindow = WIN_GL_SwapWindow;
|
||||
|
@ -72,6 +74,7 @@ WIN_GLES_CreateContext(_THIS, SDL_Window * window)
|
|||
_this->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
|
||||
_this->GL_CreateContext = WIN_GL_CreateContext;
|
||||
_this->GL_MakeCurrent = WIN_GL_MakeCurrent;
|
||||
_this->GL_GetDrawableSize = WIN_GL_GetDrawableSize;
|
||||
_this->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
|
||||
_this->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
|
||||
_this->GL_SwapWindow = WIN_GL_SwapWindow;
|
||||
|
@ -99,6 +102,12 @@ WIN_GLES_DeleteContext(_THIS, SDL_GLContext context)
|
|||
SDL_EGL_SwapWindow_impl(WIN)
|
||||
SDL_EGL_MakeCurrent_impl(WIN)
|
||||
|
||||
void
|
||||
WIN_GLES_GetDrawableSize(_THIS, SDL_Window* window, int* w, int* h)
|
||||
{
|
||||
WIN_GetDrawableSize(window, w, h);
|
||||
}
|
||||
|
||||
int
|
||||
WIN_GLES_SetupWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ extern int WIN_GLES_LoadLibrary(_THIS, const char *path);
|
|||
extern SDL_GLContext WIN_GLES_CreateContext(_THIS, SDL_Window * window);
|
||||
extern int WIN_GLES_SwapWindow(_THIS, SDL_Window * window);
|
||||
extern int WIN_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
|
||||
extern void WIN_GLES_GetDrawableSize(_THIS, SDL_Window* window, int* w, int* h);
|
||||
extern void WIN_GLES_DeleteContext(_THIS, SDL_GLContext context);
|
||||
extern int WIN_GLES_SetupWindow(_THIS, SDL_Window * window);
|
||||
|
||||
|
|
|
@ -203,6 +203,7 @@ WIN_CreateDevice(int devindex)
|
|||
device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
|
||||
device->GL_CreateContext = WIN_GL_CreateContext;
|
||||
device->GL_MakeCurrent = WIN_GL_MakeCurrent;
|
||||
device->GL_GetDrawableSize = WIN_GL_GetDrawableSize;
|
||||
device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
|
||||
device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
|
||||
device->GL_SwapWindow = WIN_GL_SwapWindow;
|
||||
|
@ -214,6 +215,7 @@ WIN_CreateDevice(int devindex)
|
|||
device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
|
||||
device->GL_CreateContext = WIN_GLES_CreateContext;
|
||||
device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
|
||||
device->GL_GetDrawableSize = WIN_GLES_GetDrawableSize;
|
||||
device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
|
||||
device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
|
||||
device->GL_SwapWindow = WIN_GLES_SwapWindow;
|
||||
|
@ -224,6 +226,7 @@ WIN_CreateDevice(int devindex)
|
|||
device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary;
|
||||
device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
|
||||
device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
|
||||
device->Vulkan_GetDrawableSize = WIN_GL_GetDrawableSize;
|
||||
#endif
|
||||
|
||||
device->StartTextInput = WIN_StartTextInput;
|
||||
|
@ -373,12 +376,25 @@ WIN_InitDPIAwareness(_THIS)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WIN_InitDPIScaling(_THIS)
|
||||
{
|
||||
SDL_VideoData* data = (SDL_VideoData*)_this->driverdata;
|
||||
|
||||
if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DPI_SCALING, SDL_FALSE)) {
|
||||
WIN_DeclareDPIAwarePerMonitorV2(_this);
|
||||
|
||||
data->dpi_scaling_enabled = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
WIN_VideoInit(_THIS)
|
||||
{
|
||||
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
|
||||
|
||||
WIN_InitDPIAwareness(_this);
|
||||
WIN_InitDPIScaling(_this);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("DPI awareness: %s", WIN_GetDPIAwareness(_this));
|
||||
|
|
|
@ -188,6 +188,8 @@ typedef struct SDL_VideoData
|
|||
UINT *dpiY );
|
||||
HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS dpiAwareness);
|
||||
|
||||
SDL_bool dpi_scaling_enabled;
|
||||
|
||||
SDL_bool ime_com_initialized;
|
||||
struct ITfThreadMgr *ime_threadmgr;
|
||||
SDL_bool ime_initialized;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
#include "SDL_log.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
|
@ -115,19 +116,45 @@ GetWindowStyle(SDL_Window * window)
|
|||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns arguments to pass to SetWindowPos - the window rect, including frame, in Windows coordinates.
|
||||
*
|
||||
* Can be called before we have a HWND.
|
||||
*/
|
||||
static void
|
||||
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
SDL_VideoData* videodata = SDL_GetVideoDevice() ? SDL_GetVideoDevice()->driverdata : NULL;
|
||||
RECT rect;
|
||||
UINT dpi;
|
||||
int dpi;
|
||||
UINT frame_dpi;
|
||||
|
||||
dpi = 96;
|
||||
/* Client rect, in SDL screen coordinates */
|
||||
*x = (use_current ? window->x : window->windowed.x);
|
||||
*y = (use_current ? window->y : window->windowed.y);
|
||||
*width = (use_current ? window->w : window->windowed.w);
|
||||
*height = (use_current ? window->h : window->windowed.h);
|
||||
|
||||
/* Convert client rect from SDL coordinates to pixels (no-op if DPI scaling not enabled) */
|
||||
WIN_ScreenPointFromSDL(x, y, &dpi);
|
||||
/* Note, use the guessed DPI returned from WIN_ScreenPointFromSDL rather than the cached one in
|
||||
data->scaling_dpi.
|
||||
|
||||
- This is called before the window is created, so we can't rely on data->scaling_dpi
|
||||
- Bug workaround: when leaving exclusive fullscreen, the cached DPI and window DPI reported
|
||||
by GetDpiForWindow will be wrong, and would cause windows shrinking slightly when
|
||||
going from exclusive fullscreen to windowed on a HighDPI monitor with scaling if we used them.
|
||||
*/
|
||||
*width = MulDiv(*width, dpi, 96);
|
||||
*height = MulDiv(*height, dpi, 96);
|
||||
|
||||
/* Copy the client size in pixels into this rect structure,
|
||||
which we'll then adjust with AdjustWindowRectEx */
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = (use_current ? window->w : window->windowed.w);
|
||||
rect.bottom = (use_current ? window->h : window->windowed.h);
|
||||
rect.right = *width;
|
||||
rect.bottom = *height;
|
||||
|
||||
/* 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.
|
||||
|
@ -141,26 +168,27 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
|
|||
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);
|
||||
screen_rect.left = *x;
|
||||
screen_rect.top = *y;
|
||||
screen_rect.right = *x + *width;
|
||||
screen_rect.bottom = *y + *height;
|
||||
|
||||
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;
|
||||
if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &frame_dpi, &unused) != S_OK) {
|
||||
frame_dpi = 96;
|
||||
}
|
||||
|
||||
videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, dpi);
|
||||
videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, frame_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;
|
||||
/* Final rect in Windows screen space, including the frame */
|
||||
*x += rect.left;
|
||||
*y += rect.top;
|
||||
*width = (rect.right - rect.left);
|
||||
*height = (rect.bottom - rect.top);
|
||||
|
||||
|
@ -170,7 +198,7 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
|
|||
(use_current ? window->y : window->windowed.y),
|
||||
(use_current ? window->w : window->windowed.w),
|
||||
(use_current ? window->h : window->windowed.h),
|
||||
*x, *y, *width, *height, dpi);
|
||||
*x, *y, *width, *height, frame_dpi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -217,6 +245,43 @@ WIN_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char
|
|||
data->mouse_relative_mode_center = SDL_GetStringBoolean(hint, SDL_TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
WIN_GetScalingDPIForHWND(const SDL_VideoData *videodata, HWND hwnd)
|
||||
{
|
||||
/* DPI scaling not requested? */
|
||||
if (!videodata->dpi_scaling_enabled) {
|
||||
return 96;
|
||||
}
|
||||
|
||||
/* Window 10+ */
|
||||
if (videodata->GetDpiForWindow) {
|
||||
return videodata->GetDpiForWindow(hwnd);
|
||||
}
|
||||
|
||||
/* Window 8.1+ */
|
||||
if (videodata->GetDpiForMonitor) {
|
||||
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (monitor) {
|
||||
UINT dpi_uint, unused;
|
||||
if (S_OK == videodata->GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_uint, &unused)) {
|
||||
return (int)dpi_uint;
|
||||
}
|
||||
}
|
||||
return 96;
|
||||
}
|
||||
|
||||
/* Windows Vista-8.0 */
|
||||
{
|
||||
HDC hdc = GetDC(NULL);
|
||||
if (hdc) {
|
||||
int dpi = GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
ReleaseDC(NULL, hdc);
|
||||
return dpi;
|
||||
}
|
||||
return 96;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created)
|
||||
{
|
||||
|
@ -239,6 +304,11 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
|||
data->last_pointer_update = (LPARAM)-1;
|
||||
data->videodata = videodata;
|
||||
data->initializing = SDL_TRUE;
|
||||
data->scaling_dpi = WIN_GetScalingDPIForHWND(videodata, hwnd);
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("SetupWindowData: initialized data->scaling_dpi to %d", data->scaling_dpi);
|
||||
#endif
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
|
||||
|
||||
|
@ -274,6 +344,8 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
|||
if (GetClientRect(hwnd, &rect)) {
|
||||
int w = rect.right;
|
||||
int h = rect.bottom;
|
||||
|
||||
WIN_ClientPointToSDL(window, &w, &h);
|
||||
if ((window->windowed.w && window->windowed.w != w) || (window->windowed.h && window->windowed.h != h)) {
|
||||
/* We tried to create a window larger than the desktop and Windows didn't allow it. Override! */
|
||||
int x, y;
|
||||
|
@ -293,8 +365,11 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
|||
point.x = 0;
|
||||
point.y = 0;
|
||||
if (ClientToScreen(hwnd, &point)) {
|
||||
window->x = point.x;
|
||||
window->y = point.y;
|
||||
int x = point.x;
|
||||
int y = point.y;
|
||||
WIN_ScreenPointToSDL(&x, &y);
|
||||
window->x = x;
|
||||
window->y = y;
|
||||
}
|
||||
}
|
||||
{
|
||||
|
@ -342,6 +417,11 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
|||
videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
|
||||
}
|
||||
|
||||
/* Force the SDL_WINDOW_ALLOW_HIGHDPI window flag if we are doing DPI scaling */
|
||||
if (videodata->dpi_scaling_enabled) {
|
||||
window->flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
}
|
||||
|
||||
data->initializing = SDL_FALSE;
|
||||
|
||||
/* All done! */
|
||||
|
@ -767,12 +847,17 @@ WIN_RestoreWindow(_THIS, SDL_Window * window)
|
|||
data->expected_resize = SDL_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigures the window to fill the given display, if fullscreen is true, otherwise restores the window.
|
||||
*/
|
||||
void
|
||||
WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
|
||||
{
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
SDL_VideoData *videodata = data->videodata;
|
||||
HWND hwnd = data->hwnd;
|
||||
SDL_Rect bounds;
|
||||
MONITORINFO minfo;
|
||||
DWORD style;
|
||||
HWND top;
|
||||
int x, y;
|
||||
|
@ -785,6 +870,15 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WIN_SetWindowFullscreen: %d", (int)fullscreen);
|
||||
#endif
|
||||
|
||||
/* Clear the window size, to force SDL_SendWindowEvent to send a SDL_WINDOWEVENT_RESIZED
|
||||
event in WM_WINDOWPOSCHANGED. */
|
||||
data->window->w = 0;
|
||||
data->window->h = 0;
|
||||
|
||||
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
|
||||
top = HWND_TOPMOST;
|
||||
} else {
|
||||
|
@ -795,13 +889,20 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
|
|||
style &= ~STYLE_MASK;
|
||||
style |= GetWindowStyle(window);
|
||||
|
||||
WIN_GetDisplayBounds(_this, display, &bounds);
|
||||
/* Use GetMonitorInfo instead of WIN_GetDisplayBounds because we want the
|
||||
monitor bounds in Windows coordinates (pixels) rather than SDL coordinates (points). */
|
||||
SDL_zero(minfo);
|
||||
minfo.cbSize = sizeof(MONITORINFO);
|
||||
if (!GetMonitorInfo(displaydata->MonitorHandle, &minfo)) {
|
||||
SDL_SetError("GetMonitorInfo failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullscreen) {
|
||||
x = bounds.x;
|
||||
y = bounds.y;
|
||||
w = bounds.w;
|
||||
h = bounds.h;
|
||||
x = minfo.rcMonitor.left;
|
||||
y = minfo.rcMonitor.top;
|
||||
w = minfo.rcMonitor.right - minfo.rcMonitor.left;
|
||||
h = minfo.rcMonitor.bottom - minfo.rcMonitor.top;
|
||||
|
||||
/* Unset the maximized flag. This fixes
|
||||
https://bugzilla.libsdl.org/show_bug.cgi?id=3215
|
||||
|
@ -831,6 +932,10 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
|
|||
data->expected_resize = SDL_TRUE;
|
||||
SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
|
||||
data->expected_resize = SDL_FALSE;
|
||||
|
||||
#ifdef HIGHDPI_DEBUG
|
||||
SDL_Log("WIN_SetWindowFullscreen: %d finished. Set window to %d,%d, %dx%d", (int)fullscreen, x, y, w, h);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1122,12 +1227,19 @@ WIN_UpdateClipCursor(SDL_Window *window)
|
|||
ClientToScreen(data->hwnd, (LPPOINT) & rect);
|
||||
ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
|
||||
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
|
||||
SDL_Rect mouse_rect_win_client;
|
||||
RECT mouse_rect, intersection;
|
||||
|
||||
mouse_rect.left = rect.left + window->mouse_rect.x;
|
||||
mouse_rect.top = rect.top + window->mouse_rect.y;
|
||||
mouse_rect.right = mouse_rect.left + window->mouse_rect.w - 1;
|
||||
mouse_rect.bottom = mouse_rect.top + window->mouse_rect.h - 1;
|
||||
/* mouse_rect_win_client is the mouse rect in Windows client space */
|
||||
mouse_rect_win_client = window->mouse_rect;
|
||||
WIN_ClientPointFromSDL(window, &mouse_rect_win_client.x, &mouse_rect_win_client.y);
|
||||
WIN_ClientPointFromSDL(window, &mouse_rect_win_client.w, &mouse_rect_win_client.h);
|
||||
|
||||
/* mouse_rect is the rect in Windows screen space */
|
||||
mouse_rect.left = rect.left + mouse_rect_win_client.x;
|
||||
mouse_rect.top = rect.top + mouse_rect_win_client.y;
|
||||
mouse_rect.right = mouse_rect.left + mouse_rect_win_client.w - 1;
|
||||
mouse_rect.bottom = mouse_rect.top + mouse_rect_win_client.h - 1;
|
||||
if (IntersectRect(&intersection, &rect, &mouse_rect)) {
|
||||
SDL_memcpy(&rect, &intersection, sizeof(rect));
|
||||
} else if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) {
|
||||
|
@ -1203,6 +1315,61 @@ WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable size in pixels (GetClientRect).
|
||||
*/
|
||||
void
|
||||
WIN_GetDrawableSize(const SDL_Window *window, int *w, int *h)
|
||||
{
|
||||
const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
|
||||
HWND hwnd = data->hwnd;
|
||||
RECT rect;
|
||||
|
||||
if (GetClientRect(hwnd, &rect)) {
|
||||
*w = rect.right;
|
||||
*h = rect.bottom;
|
||||
} else {
|
||||
*w = 0;
|
||||
*h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point in the client area from pixels to DPI-scaled points.
|
||||
*
|
||||
* No-op if DPI scaling is not enabled.
|
||||
*/
|
||||
void
|
||||
WIN_ClientPointToSDL(const SDL_Window *window, int *x, int *y)
|
||||
{
|
||||
const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
|
||||
const SDL_VideoData *videodata = data->videodata;
|
||||
|
||||
if (!videodata->dpi_scaling_enabled)
|
||||
return;
|
||||
|
||||
*x = MulDiv(*x, 96, data->scaling_dpi);
|
||||
*y = MulDiv(*y, 96, data->scaling_dpi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point in the client area from DPI-scaled points to pixels.
|
||||
*
|
||||
* No-op if DPI scaling is not enabled.
|
||||
*/
|
||||
void
|
||||
WIN_ClientPointFromSDL(const SDL_Window *window, int *x, int *y)
|
||||
{
|
||||
const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
|
||||
const SDL_VideoData *videodata = data->videodata;
|
||||
|
||||
if (!videodata->dpi_scaling_enabled)
|
||||
return;
|
||||
|
||||
*x = MulDiv(*x, data->scaling_dpi, 96);
|
||||
*y = MulDiv(*y, data->scaling_dpi, 96);
|
||||
}
|
||||
|
||||
void
|
||||
WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept)
|
||||
{
|
||||
|
|
|
@ -59,6 +59,11 @@ typedef struct
|
|||
#if SDL_VIDEO_OPENGL_EGL
|
||||
EGLSurface egl_surface;
|
||||
#endif
|
||||
/**
|
||||
* Cached value of GetDpiForWindow, for use for scaling points in the client area
|
||||
* between dpi-scaled points and pixels. Only used if videodata->dpi_scaling_enabled.
|
||||
*/
|
||||
int scaling_dpi;
|
||||
} SDL_WindowData;
|
||||
|
||||
extern int WIN_CreateWindow(_THIS, SDL_Window * window);
|
||||
|
@ -91,6 +96,9 @@ extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window,
|
|||
extern void WIN_OnWindowEnter(_THIS, SDL_Window * window);
|
||||
extern void WIN_UpdateClipCursor(SDL_Window *window);
|
||||
extern int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
extern void WIN_GetDrawableSize(const SDL_Window *window, int *w, int *h);
|
||||
extern void WIN_ClientPointToSDL(const SDL_Window *window, int *w, int *h);
|
||||
extern void WIN_ClientPointFromSDL(const SDL_Window *window, int *w, int *h);
|
||||
extern void WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept);
|
||||
extern int WIN_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation);
|
||||
|
||||
|
|
Loading…
Reference in New Issue