diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 9baa9e4222..e6f10480d7 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -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; diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 04415b5481..6103d52334 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -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 diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index 53cfbadd72..c80a721a83 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.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) diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 4e2d412e06..cd06d5d9e9 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -38,10 +38,6 @@ // Dropfile support #include -// 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