mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-05 19:08:12 +00:00
Improve move/resize visual smoothness on Windows
Fixes https://github.com/libsdl-org/SDL/issues/12528
This commit is contained in:
@@ -1859,6 +1859,13 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
{
|
||||
if (wParam == (UINT_PTR)SDL_IterateMainCallbacks) {
|
||||
SDL_OnWindowLiveResizeUpdate(data->window);
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
// Make sure graphics operations are complete for smooth refresh
|
||||
if (data->videodata->DwmFlush) {
|
||||
data->videodata->DwmFlush();
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
} break;
|
||||
|
@@ -108,6 +108,9 @@ static void WIN_DeleteDevice(SDL_VideoDevice *device)
|
||||
if (data->shcoreDLL) {
|
||||
SDL_UnloadObject(data->shcoreDLL);
|
||||
}
|
||||
if (data->dwmapiDLL) {
|
||||
SDL_UnloadObject(data->dwmapiDLL);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_DXGI_H
|
||||
if (data->pDXGIFactory) {
|
||||
@@ -184,6 +187,17 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
|
||||
} else {
|
||||
SDL_ClearError();
|
||||
}
|
||||
|
||||
data->dwmapiDLL = SDL_LoadObject("DWMAPI.DLL");
|
||||
if (data->dwmapiDLL) {
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
data->DwmFlush = (HRESULT (WINAPI *)(void))SDL_LoadFunction(data->dwmapiDLL, "DwmFlush");
|
||||
data->DwmEnableBlurBehindWindow = (HRESULT (WINAPI *)(HWND hwnd, const DWM_BLURBEHIND *pBlurBehind))SDL_LoadFunction(data->dwmapiDLL, "DwmEnableBlurBehindWindow");
|
||||
data->DwmSetWindowAttribute = (HRESULT (WINAPI *)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute))SDL_LoadFunction(data->dwmapiDLL, "DwmSetWindowAttribute");
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
} else {
|
||||
SDL_ClearError();
|
||||
}
|
||||
#endif // #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#ifdef HAVE_DXGI_H
|
||||
|
@@ -374,6 +374,45 @@ typedef struct tagINPUTCONTEXT2
|
||||
} INPUTCONTEXT2, *PINPUTCONTEXT2, NEAR *NPINPUTCONTEXT2, FAR *LPINPUTCONTEXT2;
|
||||
#endif
|
||||
|
||||
// Corner rounding support (Win 11+)
|
||||
#ifndef DWMWA_WINDOW_CORNER_PREFERENCE
|
||||
#define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
||||
#endif
|
||||
typedef enum {
|
||||
DWMWCP_DEFAULT = 0,
|
||||
DWMWCP_DONOTROUND = 1,
|
||||
DWMWCP_ROUND = 2,
|
||||
DWMWCP_ROUNDSMALL = 3
|
||||
} DWM_WINDOW_CORNER_PREFERENCE;
|
||||
|
||||
// Border Color support (Win 11+)
|
||||
#ifndef DWMWA_BORDER_COLOR
|
||||
#define DWMWA_BORDER_COLOR 34
|
||||
#endif
|
||||
|
||||
#ifndef DWMWA_COLOR_DEFAULT
|
||||
#define DWMWA_COLOR_DEFAULT 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#ifndef DWMWA_COLOR_NONE
|
||||
#define DWMWA_COLOR_NONE 0xFFFFFFFE
|
||||
#endif
|
||||
|
||||
// Transparent window support
|
||||
#ifndef DWM_BB_ENABLE
|
||||
#define DWM_BB_ENABLE 0x00000001
|
||||
#endif
|
||||
#ifndef DWM_BB_BLURREGION
|
||||
#define DWM_BB_BLURREGION 0x00000002
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
DWORD flags;
|
||||
BOOL enable;
|
||||
HRGN blur_region;
|
||||
BOOL transition_on_maxed;
|
||||
} DWM_BLURBEHIND;
|
||||
|
||||
// Private display data
|
||||
|
||||
struct SDL_VideoData
|
||||
@@ -420,6 +459,11 @@ struct SDL_VideoData
|
||||
BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
|
||||
BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
|
||||
|
||||
SDL_SharedObject *dwmapiDLL;
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
HRESULT (WINAPI *DwmFlush)(void);
|
||||
HRESULT (WINAPI *DwmEnableBlurBehindWindow)(HWND hwnd, const DWM_BLURBEHIND *pBlurBehind);
|
||||
HRESULT (WINAPI *DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
|
@@ -38,10 +38,6 @@
|
||||
// Dropfile support
|
||||
#include <shellapi.h>
|
||||
|
||||
// DWM setting support
|
||||
typedef HRESULT (WINAPI *DwmSetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
typedef HRESULT (WINAPI *DwmGetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
|
||||
|
||||
// Dark mode support
|
||||
typedef enum {
|
||||
UXTHEME_APPMODE_DEFAULT,
|
||||
@@ -80,46 +76,6 @@ typedef UxthemePreferredAppMode (WINAPI *SetPreferredAppMode_t)(UxthemePreferred
|
||||
typedef BOOL (WINAPI *SetWindowCompositionAttribute_t)(HWND, const WINDOWCOMPOSITIONATTRIBDATA *);
|
||||
typedef void (NTAPI *RtlGetVersion_t)(NT_OSVERSIONINFOW *);
|
||||
|
||||
// Corner rounding support (Win 11+)
|
||||
#ifndef DWMWA_WINDOW_CORNER_PREFERENCE
|
||||
#define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
||||
#endif
|
||||
typedef enum {
|
||||
DWMWCP_DEFAULT = 0,
|
||||
DWMWCP_DONOTROUND = 1,
|
||||
DWMWCP_ROUND = 2,
|
||||
DWMWCP_ROUNDSMALL = 3
|
||||
} DWM_WINDOW_CORNER_PREFERENCE;
|
||||
|
||||
// Border Color support (Win 11+)
|
||||
#ifndef DWMWA_BORDER_COLOR
|
||||
#define DWMWA_BORDER_COLOR 34
|
||||
#endif
|
||||
|
||||
#ifndef DWMWA_COLOR_DEFAULT
|
||||
#define DWMWA_COLOR_DEFAULT 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#ifndef DWMWA_COLOR_NONE
|
||||
#define DWMWA_COLOR_NONE 0xFFFFFFFE
|
||||
#endif
|
||||
|
||||
// Transparent window support
|
||||
#ifndef DWM_BB_ENABLE
|
||||
#define DWM_BB_ENABLE 0x00000001
|
||||
#endif
|
||||
#ifndef DWM_BB_BLURREGION
|
||||
#define DWM_BB_BLURREGION 0x00000002
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
DWORD flags;
|
||||
BOOL enable;
|
||||
HRGN blur_region;
|
||||
BOOL transition_on_maxed;
|
||||
} DWM_BLURBEHIND;
|
||||
typedef HRESULT(WINAPI *DwmEnableBlurBehindWindow_t)(HWND hwnd, const DWM_BLURBEHIND *pBlurBehind);
|
||||
|
||||
// Windows CE compatibility
|
||||
#ifndef SWP_NOCOPYBITS
|
||||
#define SWP_NOCOPYBITS 0
|
||||
@@ -744,6 +700,7 @@ static void WIN_SetKeyboardFocus(SDL_Window *window, bool set_active_focus)
|
||||
|
||||
bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
HWND hwnd = (HWND)SDL_GetPointerProperty(create_props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, SDL_GetPointerProperty(create_props, "sdl2-compat.external_window", NULL));
|
||||
HWND parent = NULL;
|
||||
if (hwnd) {
|
||||
@@ -805,24 +762,19 @@ bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
// FIXME: does not work on all hardware configurations with different renders (i.e. hybrid GPUs)
|
||||
if (window->flags & SDL_WINDOW_TRANSPARENT) {
|
||||
SDL_SharedObject *handle = SDL_LoadObject("dwmapi.dll");
|
||||
if (handle) {
|
||||
DwmEnableBlurBehindWindow_t DwmEnableBlurBehindWindowFunc = (DwmEnableBlurBehindWindow_t)SDL_LoadFunction(handle, "DwmEnableBlurBehindWindow");
|
||||
if (DwmEnableBlurBehindWindowFunc) {
|
||||
/* The region indicates which part of the window will be blurred and rest will be transparent. This
|
||||
is because the alpha value of the window will be used for non-blurred areas
|
||||
We can use (-1, -1, 0, 0) boundary to make sure no pixels are being blurred
|
||||
*/
|
||||
HRGN rgn = CreateRectRgn(-1, -1, 0, 0);
|
||||
DWM_BLURBEHIND bb;
|
||||
bb.flags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
|
||||
bb.enable = TRUE;
|
||||
bb.blur_region = rgn;
|
||||
bb.transition_on_maxed = FALSE;
|
||||
DwmEnableBlurBehindWindowFunc(hwnd, &bb);
|
||||
DeleteObject(rgn);
|
||||
}
|
||||
SDL_UnloadObject(handle);
|
||||
if (videodata->DwmEnableBlurBehindWindow) {
|
||||
/* The region indicates which part of the window will be blurred and rest will be transparent. This
|
||||
is because the alpha value of the window will be used for non-blurred areas
|
||||
We can use (-1, -1, 0, 0) boundary to make sure no pixels are being blurred
|
||||
*/
|
||||
HRGN rgn = CreateRectRgn(-1, -1, 0, 0);
|
||||
DWM_BLURBEHIND bb;
|
||||
bb.flags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
|
||||
bb.enable = TRUE;
|
||||
bb.blur_region = rgn;
|
||||
bb.transition_on_maxed = FALSE;
|
||||
videodata->DwmEnableBlurBehindWindow(hwnd, &bb);
|
||||
DeleteObject(rgn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1264,29 +1216,19 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
}
|
||||
}
|
||||
|
||||
static void WIN_UpdateCornerRoundingForHWND(HWND hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPref)
|
||||
static void WIN_UpdateCornerRoundingForHWND(SDL_VideoDevice *_this, HWND hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPref)
|
||||
{
|
||||
SDL_SharedObject *handle = SDL_LoadObject("dwmapi.dll");
|
||||
if (handle) {
|
||||
DwmSetWindowAttribute_t DwmSetWindowAttributeFunc = (DwmSetWindowAttribute_t)SDL_LoadFunction(handle, "DwmSetWindowAttribute");
|
||||
if (DwmSetWindowAttributeFunc) {
|
||||
DwmSetWindowAttributeFunc(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
|
||||
}
|
||||
|
||||
SDL_UnloadObject(handle);
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
if (videodata->DwmSetWindowAttribute) {
|
||||
videodata->DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
|
||||
}
|
||||
}
|
||||
|
||||
static void WIN_UpdateBorderColorForHWND(HWND hwnd, COLORREF colorRef)
|
||||
static void WIN_UpdateBorderColorForHWND(SDL_VideoDevice *_this, HWND hwnd, COLORREF colorRef)
|
||||
{
|
||||
SDL_SharedObject *handle = SDL_LoadObject("dwmapi.dll");
|
||||
if (handle) {
|
||||
DwmSetWindowAttribute_t DwmSetWindowAttributeFunc = (DwmSetWindowAttribute_t)SDL_LoadFunction(handle, "DwmSetWindowAttribute");
|
||||
if (DwmSetWindowAttributeFunc) {
|
||||
DwmSetWindowAttributeFunc(hwnd, DWMWA_BORDER_COLOR, &colorRef, sizeof(colorRef));
|
||||
}
|
||||
|
||||
SDL_UnloadObject(handle);
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
if (videodata->DwmSetWindowAttribute) {
|
||||
videodata->DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &colorRef, sizeof(colorRef));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1353,13 +1295,13 @@ SDL_FullscreenResult WIN_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window
|
||||
}
|
||||
|
||||
// Disable corner rounding & border color (Windows 11+) so the window fills the full screen
|
||||
WIN_UpdateCornerRoundingForHWND(hwnd, DWMWCP_DONOTROUND);
|
||||
WIN_UpdateBorderColorForHWND(hwnd, DWMWA_COLOR_NONE);
|
||||
WIN_UpdateCornerRoundingForHWND(_this, hwnd, DWMWCP_DONOTROUND);
|
||||
WIN_UpdateBorderColorForHWND(_this, hwnd, DWMWA_COLOR_NONE);
|
||||
} else {
|
||||
BOOL menu;
|
||||
|
||||
WIN_UpdateCornerRoundingForHWND(hwnd, DWMWCP_DEFAULT);
|
||||
WIN_UpdateBorderColorForHWND(hwnd, DWMWA_COLOR_DEFAULT);
|
||||
WIN_UpdateCornerRoundingForHWND(_this, hwnd, DWMWCP_DEFAULT);
|
||||
WIN_UpdateBorderColorForHWND(_this, hwnd, DWMWA_COLOR_DEFAULT);
|
||||
|
||||
/* Restore window-maximization state, as applicable.
|
||||
Special care is taken to *not* do this if and when we're
|
||||
|
Reference in New Issue
Block a user