SDL: cmake: Split and store the libdecor version as individual parts

From 8b6eae2d4fad188c6c82c9b41fd944b70fbe5d39 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Thu, 28 Dec 2023 13:04:41 -0500
Subject: [PATCH] cmake: Split and store the libdecor version as individual
 parts

It is becoming necessary to enable additional features as libdecor continues to evolve, and checking against a single base version will no longer be adequate. Libdecor doesn't provide versioning defines in its headers, so split the version string into parts to allow for discrete version detection and feature enablement at build time.
---
 cmake/sdlchecks.cmake                         | 15 +++++++++++++--
 include/build_config/SDL_build_config.h.cmake |  5 ++++-
 src/video/wayland/SDL_waylanddyn.h            |  7 +++++++
 src/video/wayland/SDL_waylandsym.h            |  2 +-
 src/video/wayland/SDL_waylandwindow.c         |  6 +++---
 5 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index c91df3f395e2..55e939a8ca93 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -557,9 +557,20 @@ macro(CheckWayland)
         set(LibDecor_PKG_CONFIG_SPEC libdecor-0)
         pkg_check_modules(PC_LIBDECOR IMPORTED_TARGET ${LibDecor_PKG_CONFIG_SPEC})
         if(PC_LIBDECOR_FOUND)
-          # Version 0.2.0 or higher is needed for suspended window state and statically linked min/max getters.
+
+          # Libdecor doesn't provide internal version defines, so generate them here.
+          if (PC_LIBDECOR_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+            set(SDL_LIBDECOR_VERSION_MAJOR ${CMAKE_MATCH_1})
+            set(SDL_LIBDECOR_VERSION_MINOR ${CMAKE_MATCH_2})
+            set(SDL_LIBDECOR_VERSION_PATCH ${CMAKE_MATCH_3})
+          else()
+            message(WARNING "Failed to parse libdecor version; defaulting to lowest supported (0.1.0)")
+            set(SDL_LIBDECOR_VERSION_MAJOR 0)
+            set(SDL_LIBDECOR_VERSION_MINOR 1)
+            set(SDL_LIBDECOR_VERSION_PATCH 0)
+          endif()
+
           if(PC_LIBDECOR_VERSION VERSION_GREATER_EQUAL "0.2.0")
-            set(SDL_HAVE_LIBDECOR_VER_0_2_0 1)
             set(LibDecor_PKG_CONFIG_SPEC "libdecor-0>=0.2.0")
           endif()
           set(HAVE_WAYLAND_LIBDECOR TRUE)
diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake
index 2b4df48157d5..e44f38ef6398 100644
--- a/include/build_config/SDL_build_config.h.cmake
+++ b/include/build_config/SDL_build_config.h.cmake
@@ -492,7 +492,10 @@
 #cmakedefine SDL_VIDEO_VITA_PVR @SDL_VIDEO_VITA_PVR@
 #cmakedefine SDL_VIDEO_VITA_PVR_OGL @SDL_VIDEO_VITA_PVR_OGL@
 
-#cmakedefine SDL_HAVE_LIBDECOR_VER_0_2_0 @SDL_HAVE_LIBDECOR_VER_0_2_0@
+/* Libdecor version info */
+#define SDL_LIBDECOR_VERSION_MAJOR @SDL_LIBDECOR_VERSION_MAJOR@
+#define SDL_LIBDECOR_VERSION_MINOR @SDL_LIBDECOR_VERSION_MINOR@
+#define SDL_LIBDECOR_VERSION_PATCH @SDL_LIBDECOR_VERSION_PATCH@
 
 #if !defined(HAVE_STDINT_H) && !defined(_STDINT_H_)
 /* Most everything except Visual Studio 2008 and earlier has stdint.h now */
diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h
index e674ab8a8b97..29e4e0a49d3b 100644
--- a/src/video/wayland/SDL_waylanddyn.h
+++ b/src/video/wayland/SDL_waylanddyn.h
@@ -60,6 +60,13 @@ enum libdecor_window_state;
      (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \
      (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z))
 
+#ifdef HAVE_LIBDECOR_H
+#define SDL_LIBDECOR_CHECK_VERSION(x, y, z)                                 \
+    (SDL_LIBDECOR_VERSION_MAJOR > x ||                                      \
+     (SDL_LIBDECOR_VERSION_MAJOR == x && SDL_LIBDECOR_VERSION_MINOR > y) || \
+     (SDL_LIBDECOR_VERSION_MAJOR == x && SDL_LIBDECOR_VERSION_MINOR == y && SDL_LIBDECOR_VERSION_PATCH >= z))
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h
index 4d815c6343e1..ac512a145821 100644
--- a/src/video/wayland/SDL_waylandsym.h
+++ b/src/video/wayland/SDL_waylandsym.h
@@ -219,7 +219,7 @@ SDL_WAYLAND_SYM(bool, libdecor_configuration_get_window_state, (struct libdecor_
                                                                 enum libdecor_window_state *))
 SDL_WAYLAND_SYM(int, libdecor_dispatch, (struct libdecor *, int))
 
-#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || defined(SDL_HAVE_LIBDECOR_VER_0_2_0)
+#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || SDL_LIBDECOR_CHECK_VERSION(0, 2, 0)
 /* Only found in libdecor 0.1.1 or higher, so failure to load them is not fatal. */
 SDL_WAYLAND_SYM_OPT(void, libdecor_frame_get_min_content_size, (const struct libdecor_frame *,\
                                                             int *,\
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index df6443870ba8..09f1963d11d5 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -945,7 +945,7 @@ static void OverrideLibdecorLimits(SDL_Window *window)
     if (!libdecor_frame_get_min_content_size) {
         libdecor_frame_set_min_content_size(window->driverdata->shell_surface.libdecor.frame, window->min_w, window->min_h);
     }
-#elif !defined(SDL_HAVE_LIBDECOR_VER_0_2_0)
+#elif !SDL_LIBDECOR_CHECK_VERSION(0, 2, 0)
     libdecor_frame_set_min_content_size(window->driverdata->shell_surface.libdecor.frame, window->min_w, window->min_h);
 #endif
 }
@@ -964,7 +964,7 @@ static void LibdecorGetMinContentSize(struct libdecor_frame *frame, int *min_w,
     if (libdecor_frame_get_min_content_size != NULL) {
         libdecor_frame_get_min_content_size(frame, min_w, min_h);
     }
-#elif defined(SDL_HAVE_LIBDECOR_VER_0_2_0)
+#elif SDL_LIBDECOR_CHECK_VERSION(0, 2, 0)
     libdecor_frame_get_min_content_size(frame, min_w, min_h);
 #endif
 }
@@ -997,7 +997,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
         maximized = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
         active = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
         tiled = (window_state & tiled_states) != 0;
-#ifdef SDL_HAVE_LIBDECOR_VER_0_2_0
+#if SDL_LIBDECOR_CHECK_VERSION(0, 2, 0)
         suspended = (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) != 0;
 #endif
     }