SDL: tray: document thread-safety

From dfdc120268e4b2875bb958fcdace54297fa73703 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 19 Jan 2025 10:42:49 -0800
Subject: [PATCH] tray: document thread-safety

---
 include/SDL3/SDL_tray.h     | 46 ++++++++++++++++++++++++++++++++++++-
 src/tray/cocoa/SDL_tray.m   |  5 ++++
 src/tray/unix/SDL_tray.c    |  5 ++++
 src/tray/windows/SDL_tray.c |  5 ++++
 4 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/include/SDL3/SDL_tray.h b/include/SDL3/SDL_tray.h
index b001169856de4..54123b5020342 100644
--- a/include/SDL3/SDL_tray.h
+++ b/include/SDL3/SDL_tray.h
@@ -108,6 +108,8 @@ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should only be called on the main thread.
+ *
  * \sa SDL_CreateTrayMenu
  * \sa SDL_GetTrayMenu
  * \sa SDL_DestroyTray
@@ -122,6 +124,8 @@ extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_CreateTray(SDL_Surface *icon, const ch
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTray
  */
 extern SDL_DECLSPEC void SDLCALL SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon);
@@ -134,6 +138,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *ic
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTray
  */
 extern SDL_DECLSPEC void SDLCALL SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip);
@@ -153,6 +159,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayTooltip(SDL_Tray *tray, const char *
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTray
  * \sa SDL_GetTrayMenu
  * \sa SDL_GetTrayMenuParentTray
@@ -174,6 +182,8 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_GetTraySubmenu
  * \sa SDL_GetTrayMenuParentEntry
@@ -196,6 +206,8 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *e
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTray
  * \sa SDL_CreateTrayMenu
  */
@@ -217,6 +229,8 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_CreateTraySubmenu
  */
@@ -234,6 +248,8 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entr
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_RemoveTrayEntry
  * \sa SDL_InsertTrayEntryAt
  */
@@ -246,6 +262,8 @@ extern SDL_DECLSPEC const SDL_TrayEntry **SDLCALL SDL_GetTrayEntries(SDL_TrayMen
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  */
@@ -269,6 +287,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveTrayEntry(SDL_TrayEntry *entry);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_TrayEntryFlags
  * \sa SDL_GetTrayEntries
  * \sa SDL_RemoveTrayEntry
@@ -289,6 +309,8 @@ extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *m
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_GetTrayEntryLabel
@@ -305,6 +327,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, con
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_SetTrayEntryLabel
@@ -321,6 +345,8 @@ extern SDL_DECLSPEC const char *SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *ent
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_GetTrayEntryChecked
@@ -337,6 +363,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, b
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_SetTrayEntryChecked
@@ -351,6 +379,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetTrayEntryChecked(SDL_TrayEntry *entry);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_GetTrayEntryEnabled
@@ -365,6 +395,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, b
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  * \sa SDL_SetTrayEntryEnabled
@@ -381,6 +413,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_GetTrayEntries
  * \sa SDL_InsertTrayEntryAt
  */
@@ -392,6 +426,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryCallback(SDL_TrayEntry *entry,
  * \param entry The entry to activate.
  *
  * \since This function is available since SDL 3.1.10.
+ *
+ * \threadsafety This function should be called on the thread that created the tray.
  */
 extern SDL_DECLSPEC void SDLCALL SDL_ClickTrayEntry(SDL_TrayEntry *entry);
 
@@ -404,18 +440,22 @@ extern SDL_DECLSPEC void SDLCALL SDL_ClickTrayEntry(SDL_TrayEntry *entry);
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTray
  */
 extern SDL_DECLSPEC void SDLCALL SDL_DestroyTray(SDL_Tray *tray);
 
 /**
- * Gets the menu contianing a certain tray entry.
+ * Gets the menu containing a certain tray entry.
  *
  * \param entry the entry for which to get the parent menu.
  * \returns the parent menu.
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_InsertTrayEntryAt
  */
 extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry);
@@ -432,6 +472,8 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTraySubmenu
  * \sa SDL_GetTrayMenuParentTray
  */
@@ -449,6 +491,8 @@ extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMe
  *
  * \since This function is available since SDL 3.1.8.
  *
+ * \threadsafety This function should be called on the thread that created the tray.
+ *
  * \sa SDL_CreateTrayMenu
  * \sa SDL_GetTrayMenuParentEntry
  */
diff --git a/src/tray/cocoa/SDL_tray.m b/src/tray/cocoa/SDL_tray.m
index 15de54b24e9a6..9d2f55e2db347 100644
--- a/src/tray/cocoa/SDL_tray.m
+++ b/src/tray/cocoa/SDL_tray.m
@@ -80,6 +80,11 @@ static void DestroySDLMenu(SDL_TrayMenu *menu)
 
 SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
 {
+    if (!SDL_IsMainThread()) {
+        SDL_SetError("This function should be called on the main thread");
+        return NULL;
+    }
+
     if (icon) {
         icon = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
         if (!icon) {
diff --git a/src/tray/unix/SDL_tray.c b/src/tray/unix/SDL_tray.c
index c543ed5ba026d..c26da85a58a61 100644
--- a/src/tray/unix/SDL_tray.c
+++ b/src/tray/unix/SDL_tray.c
@@ -398,6 +398,11 @@ static void DestroySDLMenu(SDL_TrayMenu *menu)
 
 SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
 {
+    if (!SDL_IsMainThread()) {
+        SDL_SetError("This function should be called on the main thread");
+        return NULL;
+    }
+
     if (init_gtk() != true) {
         return NULL;
     }
diff --git a/src/tray/windows/SDL_tray.c b/src/tray/windows/SDL_tray.c
index dbfbabafa27a6..0afd62768f0e3 100644
--- a/src/tray/windows/SDL_tray.c
+++ b/src/tray/windows/SDL_tray.c
@@ -211,6 +211,11 @@ static HICON load_default_icon()
 
 SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
 {
+    if (!SDL_IsMainThread()) {
+        SDL_SetError("This function should be called on the main thread");
+        return NULL;
+    }
+
     SDL_Tray *tray = (SDL_Tray *)SDL_calloc(1, sizeof(*tray));
 
     if (!tray) {