From 64c4b73853a2328a25c52a6b5b98fa2d7abfacec Mon Sep 17 00:00:00 2001
From: FunkyFr3sh <cc.red.alert.1@googlemail.com>
Date: Sat, 4 May 2024 07:19:02 +0200
Subject: [PATCH] Add workaround for alt+tab issues on windows 7 SP1 (opengl)

---
 inc/versionhelpers.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
 src/dd.c             | 14 ++++++-
 src/fps_limiter.c    | 16 +++++++-
 3 files changed, 124 insertions(+), 4 deletions(-)
 create mode 100644 inc/versionhelpers.h

diff --git a/inc/versionhelpers.h b/inc/versionhelpers.h
new file mode 100644
index 0000000..5cb0d97
--- /dev/null
+++ b/inc/versionhelpers.h
@@ -0,0 +1,98 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#ifndef _INC_VERSIONHELPERS
+#define _INC_VERSIONHELPERS
+
+#if 1
+
+#ifdef __cplusplus
+#define VERSIONHELPERAPI inline bool
+#else
+#define VERSIONHELPERAPI FORCEINLINE BOOL
+#endif
+
+#ifndef _WIN32_WINNT_WIN8
+#define _WIN32_WINNT_WIN8                   0x0602
+#endif
+#ifndef _WIN32_WINNT_WINBLUE
+#define _WIN32_WINNT_WINBLUE                0x0603
+#endif
+#ifndef _WIN32_WINNT_WINTHRESHOLD
+#define _WIN32_WINNT_WINTHRESHOLD           0x0A00 /* ABRACADABRA_THRESHOLD*/
+#endif
+#ifndef _WIN32_WINNT_WIN10
+#define _WIN32_WINNT_WIN10                  0x0A00 /* ABRACADABRA_THRESHOLD*/
+#endif
+
+VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack)
+{
+    OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack};
+    return VerifyVersionInfoW(&vi, VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR,
+        VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
+            VER_MAJORVERSION,VER_GREATER_EQUAL),
+            VER_MINORVERSION,VER_GREATER_EQUAL),
+            VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL));
+}
+
+VERSIONHELPERAPI IsWindowsXPOrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
+}
+
+VERSIONHELPERAPI IsWindowsVistaOrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
+}
+
+VERSIONHELPERAPI IsWindows7OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
+}
+
+VERSIONHELPERAPI IsWindows7SP1OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
+}
+
+VERSIONHELPERAPI IsWindows8OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
+}
+
+VERSIONHELPERAPI IsWindows8Point1OrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
+}
+
+VERSIONHELPERAPI IsWindowsThresholdOrGreater(void) {
+    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
+}
+
+VERSIONHELPERAPI IsWindows10OrGreater(void) {
+    return IsWindowsThresholdOrGreater();
+}
+
+VERSIONHELPERAPI IsWindowsServer(void) {
+    OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION};
+    return !VerifyVersionInfoW(&vi, VER_PRODUCT_TYPE, VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL));
+}
+
+#endif
+#endif
diff --git a/src/dd.c b/src/dd.c
index 6398cc7..68f0810 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -14,6 +14,7 @@
 #include "debug.h"
 #include "utils.h"
 #include "blt.h"
+#include "versionhelpers.h"
 
 
 CNCDDRAW g_ddraw;
@@ -1271,8 +1272,17 @@ HRESULT dd_WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent)
 {
     if (g_config.maxgameticks == -2)
     {
-        if (fpsl_dwm_flush() || fpsl_wait_for_vblank())
-            return DD_OK;
+        /* Workaround for DwmFlush() freeze (e.g. slow alt+tab) issue on windows 7 SP1 */
+        if (g_ddraw.renderer == ogl_render_main && !g_config.is_wine && !IsWindows8OrGreater())
+        {
+            if (fpsl_wait_for_vblank())
+                return DD_OK;
+        }
+        else
+        {
+            if (fpsl_dwm_flush() || fpsl_wait_for_vblank())
+                return DD_OK;
+        }
     }
 
     if (!g_ddraw.flip_limiter.tick_length)
diff --git a/src/fps_limiter.c b/src/fps_limiter.c
index a6014bf..9d74fc5 100644
--- a/src/fps_limiter.c
+++ b/src/fps_limiter.c
@@ -4,6 +4,9 @@
 #include "debug.h"
 #include "hook.h"
 #include "config.h"
+#include "render_ogl.h"
+#include "versionhelpers.h"
+
 
 FPSLIMITER g_fpsl;
 
@@ -153,8 +156,17 @@ void fpsl_frame_end()
     if (g_config.maxfps < 0 || 
         (g_config.vsync && (!g_config.maxfps || g_config.maxfps >= g_ddraw.mode.dmDisplayFrequency)))
     {
-        if (fpsl_dwm_flush() || fpsl_wait_for_vblank())
-            return;
+        /* Workaround for DwmFlush() freeze (e.g. slow alt+tab) issue on windows 7 SP1 */
+        if (g_ddraw.renderer == ogl_render_main && !g_config.is_wine && !IsWindows8OrGreater())
+        {
+            if (fpsl_wait_for_vblank())
+                return;
+        }
+        else
+        {
+            if (fpsl_dwm_flush() || fpsl_wait_for_vblank())
+                return;
+        }
     }
 
     if (g_fpsl.tick_length > 0)