SDL: properties: add formal SDL_CleanupPropertyCallback type, improve docs.

From 2626304e701b80998e622c352234c012b94bf51e Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 26 May 2024 12:17:34 -0400
Subject: [PATCH] properties: add formal SDL_CleanupPropertyCallback type,
 improve docs.

---
 include/SDL3/SDL_properties.h | 48 ++++++++++++++++++++++++++++++++++-
 src/SDL_properties.c          |  4 +--
 src/dynapi/SDL_dynapi_procs.h |  2 +-
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/include/SDL3/SDL_properties.h b/include/SDL3/SDL_properties.h
index 27e90526f9ec6..870bcedc97e7a 100644
--- a/include/SDL3/SDL_properties.h
+++ b/include/SDL3/SDL_properties.h
@@ -145,6 +145,30 @@ extern SDL_DECLSPEC int SDLCALL SDL_LockProperties(SDL_PropertiesID props);
  */
 extern SDL_DECLSPEC void SDLCALL SDL_UnlockProperties(SDL_PropertiesID props);
 
+/**
+ * A callback used to free resources when a property is deleted.
+ *
+ * This should release any resources associated with `value` that are
+ * no longer needed.
+ *
+ * This callback is set per-property. Different properties in the same
+ * set can have different cleanup callbacks.
+ *
+ * This callback will be called _during_ SDL_SetPropertyWithCleanup if the
+ * function fails for any reason.
+ *
+ * \param userdata an app-defined pointer passed to the callback.
+ * \param value the pointer assigned to the property to clean up.
+ *
+ * \threadsafety This callback may fire without any locks held; if this is
+ *               a concern, the app should provide its own locking.
+ *
+ * \since This datatype is available since SDL 3.0.0.
+ *
+ * \sa SDL_SetPropertyWithCleanup
+ */
+typedef void (SDLCALL *SDL_CleanupPropertyCallback)(void *userdata, void *value);
+
 /**
  * Set a property on a set of properties with a cleanup function that is
  * called when the property is deleted.
@@ -152,6 +176,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockProperties(SDL_PropertiesID props);
  * The cleanup function is also called if setting the property fails for any
  * reason.
  *
+ * For simply setting basic data types, like numbers, bools, or strings,
+ * use SDL_SetNumberProperty, SDL_SetBooleanProperty, or SDL_SetStringProperty
+ * instead, as those functions will handle cleanup on your behalf. This
+ * function is only for more complex, custom data.
+ *
  * \param props the properties to modify
  * \param name the name of the property to modify
  * \param value the new value of the property, or NULL to delete the property
@@ -167,8 +196,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockProperties(SDL_PropertiesID props);
  *
  * \sa SDL_GetProperty
  * \sa SDL_SetProperty
+ * \sa SDL_CleanupPropertyCallback
  */
-extern SDL_DECLSPEC int SDLCALL SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, void (SDLCALL *cleanup)(void *userdata, void *value), void *userdata);
+extern SDL_DECLSPEC int SDLCALL SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, SDL_CleanupPropertyCallback cleanup, void *userdata);
 
 /**
  * Set a property on a set of properties.
@@ -426,6 +456,22 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_GetBooleanProperty(SDL_PropertiesID pro
  */
 extern SDL_DECLSPEC int SDLCALL SDL_ClearProperty(SDL_PropertiesID props, const char *name);
 
+/**
+ * A callback used to enumerate all properties set in an SDL_PropertiesID.
+ *
+ * This callback is called from SDL_EnumerateProperties(), and is called once
+ * per property in the set.
+ *
+ * \param userdata an app-defined pointer passed to the callback.
+ * \param props the SDL_PropertiesID that is being enumerated.
+ * \param name the next property name in the enumeration.
+ *
+ * \threadsafety SDL_EnumerateProperties holds a lock on `props` during this callback.
+ *
+ * \since This datatype is available since SDL 3.0.0.
+ *
+ * \sa SDL_EnumerateProperties
+ */
 typedef void (SDLCALL *SDL_EnumeratePropertiesCallback)(void *userdata, SDL_PropertiesID props, const char *name);
 
 /**
diff --git a/src/SDL_properties.c b/src/SDL_properties.c
index 1a094caacc87e..d2dca5c9f0fef 100644
--- a/src/SDL_properties.c
+++ b/src/SDL_properties.c
@@ -38,7 +38,7 @@ typedef struct
 
     char *string_storage;
 
-    void (SDLCALL *cleanup)(void *userdata, void *value);
+    SDL_CleanupPropertyCallback cleanup;
     void *userdata;
 } SDL_Property;
 
@@ -338,7 +338,7 @@ static int SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL_
     return result;
 }
 
-int SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, void (SDLCALL *cleanup)(void *userdata, void *value), void *userdata)
+int SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, SDL_CleanupPropertyCallback cleanup, void *userdata)
 {
     SDL_Property *property;
 
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index fd97c77e5f4ea..1b069ff39981b 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -748,7 +748,7 @@ SDL_DYNAPI_PROC(int,SDL_SetPaletteColors,(SDL_Palette *a, const SDL_Color *b, in
 SDL_DYNAPI_PROC(int,SDL_SetPixelFormatPalette,(SDL_PixelFormat *a, SDL_Palette *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetPrimarySelectionText,(const char *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_SetProperty,(SDL_PropertiesID a, const char *b, void *c),(a,b,c),return)
-SDL_DYNAPI_PROC(int,SDL_SetPropertyWithCleanup,(SDL_PropertiesID a, const char *b, void *c, void (SDLCALL *d)(void *userdata, void *value), void *e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(int,SDL_SetPropertyWithCleanup,(SDL_PropertiesID a, const char *b, void *c, SDL_CleanupPropertyCallback d, void *e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(int,SDL_SetRelativeMouseMode,(SDL_bool a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderClipRect,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderColorScale,(SDL_Renderer *a, float b),(a,b),return)