From 9d8d0b79aa8c20258d59b0993fcc9a1116d15947 Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 11:08:40 -0400 Subject: [PATCH 1/6] [tray/dbus] fix tooltips not showing on KDE --- src/tray/unix/SDL_dbustray.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tray/unix/SDL_dbustray.c b/src/tray/unix/SDL_dbustray.c index c2c66679e7..99b3ce5f58 100644 --- a/src/tray/unix/SDL_dbustray.c +++ b/src/tray/unix/SDL_dbustray.c @@ -211,8 +211,8 @@ static DBusHandlerResult TrayHandleGetAllProps(SDL_Tray *tray, SDL_TrayDBus *tra driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(iiay)", &array_iter); driver->dbus->message_iter_close_container(&struct_iter, &array_iter); - driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &tray_dbus->tooltip); + driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_close_container(&variant_iter, &struct_iter); driver->dbus->message_iter_close_container(&entry_iter, &variant_iter); driver->dbus->message_iter_close_container(&dict_iter, &entry_iter); @@ -311,8 +311,8 @@ static DBusHandlerResult TrayHandleGetProp(SDL_Tray *tray, SDL_TrayDBus *tray_db driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(iiay)", &array_iter); driver->dbus->message_iter_close_container(&struct_iter, &array_iter); - driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &tray_dbus->tooltip); + driver->dbus->message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &empty); driver->dbus->message_iter_close_container(&variant_iter, &struct_iter); driver->dbus->message_iter_close_container(&iter, &variant_iter); } else if (!SDL_strcmp(property, "WindowId")) { From a0906df3a107a5151ece32e03c2c1c393e23f66c Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 12:50:12 -0400 Subject: [PATCH 2/6] [tray] added basic skeleton of tray callback capabilities --- include/SDL3/SDL_tray.h | 17 ++++++++++++++++- src/tray/unix/SDL_dbustray.c | 27 +++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/include/SDL3/SDL_tray.h b/include/SDL3/SDL_tray.h index 8586ce8c8b..e9b09dd453 100644 --- a/include/SDL3/SDL_tray.h +++ b/include/SDL3/SDL_tray.h @@ -84,6 +84,18 @@ typedef Uint32 SDL_TrayEntryFlags; #define SDL_TRAYENTRY_DISABLED 0x80000000u /**< Make the entry disabled. Optional. */ #define SDL_TRAYENTRY_CHECKED 0x40000000u /**< Make the entry checked. This is valid only for checkboxes. Optional. */ +/** + * Flags that indicate the capabilities of tray callbacks. + * + * \since This datatype is available since SDL 3.6.0 + */ +typedef Uint32 SDL_TrayCallbackCapabilities; + +#define SDL_TRAYCALLBACKCAPABILITIES_NONE 0x00000000u /**< Tray callbacks have no capabilities */ +#define SDL_TRAYCALLBACKCAPABILITIES_SUPPRESS_MENU 0x00000001u /**< Tray callbacks can suppress context menu */ +#define SDL_TRAYCALLBACKCAPABILITIES_REQUEST_MENU 0x00000002u /**< Tray callbacks can request context menu open */ +#define SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES 0x00000003u /**< Tray callbacks include screen-space coordinates */ + /** * A callback that is invoked when a tray entry is selected. * @@ -103,6 +115,9 @@ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry); * \param userdata an optional pointer to pass extra data to the callback when * it will be invoked. May be NULL. * \param tray the tray that was clicked. + * \param x the screen-space x coordinate of the tray click + * \param y the screen-space y coordinate of the tray click + * \param capabilities the capabilities of the tray callbacks * \returns true to show the tray menu after the callback returns, false to * skip showing the menu. This return value is only used for left and * right click callbacks; other mouse events ignore the return value. @@ -111,7 +126,7 @@ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry); * * \sa SDL_CreateTrayWithProperties */ -typedef bool (SDLCALL *SDL_TrayClickCallback)(void *userdata, SDL_Tray *tray); +typedef bool (SDLCALL *SDL_TrayClickCallback)(void *userdata, SDL_Tray *tray, Sint32 x, Sint32 y, SDL_TrayCallbackCapabilities capabilities); /** * Create an icon to be placed in the operating system's tray, or equivalent. diff --git a/src/tray/unix/SDL_dbustray.c b/src/tray/unix/SDL_dbustray.c index 99b3ce5f58..a0c6603a3d 100644 --- a/src/tray/unix/SDL_dbustray.c +++ b/src/tray/unix/SDL_dbustray.c @@ -332,6 +332,19 @@ static DBusHandlerResult TrayHandleGetProp(SDL_Tray *tray, SDL_TrayDBus *tray_db return DBUS_HANDLER_RESULT_HANDLED; } +static bool TrayGetClickCoordinatesFromMessage(SDL_TrayDriverDBus *driver, DBusMessage *msg, Sint32 *x, Sint32 *y) { + DBusError err; + driver->dbus->error_init(&err); + if (!driver->dbus->message_get_args(msg, &err, + DBUS_TYPE_INT32, &x, + DBUS_TYPE_INT32, &y, + DBUS_TYPE_INVALID)) { + driver->dbus->error_free(&err); + return false; + } + return true; +} + static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMessage *msg, void *user_data) { SDL_Tray *tray; @@ -355,7 +368,9 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "ContextMenu")) { if (tray_dbus->r_cb) { - tray_dbus->r_cb(tray_dbus->udata, tray); + Sint32 x = 0, y = 0; + TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); + tray_dbus->r_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -364,7 +379,9 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "Activate")) { if (tray_dbus->l_cb) { - tray_dbus->l_cb(tray_dbus->udata, tray); + Sint32 x = 0, y = 0; + TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); + tray_dbus->l_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -373,7 +390,9 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "SecondaryActivate")) { if (tray_dbus->m_cb) { - tray_dbus->m_cb(tray_dbus->udata, tray); + Sint32 x = 0, y = 0; + TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); + tray_dbus->m_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -742,7 +761,7 @@ bool TrayRightClickHandler(SDL_ListNode *menu, void *udata) SDL_Tray *tray = (SDL_Tray *)udata; SDL_TrayDBus *tray_dbus = (SDL_TrayDBus *)tray->internal; - return tray_dbus->r_cb(tray_dbus->udata, tray); + return tray_dbus->r_cb(tray_dbus->udata, tray, 0, 0, SDL_TRAYCALLBACKCAPABILITIES_NONE); } void TraySendNewMenu(SDL_Tray *tray, const char *new_path) From 5f936690e0ed08ae4ad9b993fa5c11d0f9e0a59d Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 12:57:53 -0400 Subject: [PATCH 3/6] [tray/dbus] renamed callbacks for accuracy --- src/tray/unix/SDL_dbustray.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/tray/unix/SDL_dbustray.c b/src/tray/unix/SDL_dbustray.c index a0c6603a3d..64ccce774c 100644 --- a/src/tray/unix/SDL_dbustray.c +++ b/src/tray/unix/SDL_dbustray.c @@ -46,9 +46,9 @@ typedef struct SDL_TrayDBus char *tooltip; SDL_Surface *surface; - SDL_TrayClickCallback l_cb; - SDL_TrayClickCallback r_cb; - SDL_TrayClickCallback m_cb; + SDL_TrayClickCallback activate_cb; + SDL_TrayClickCallback secondary_activate_cb; + SDL_TrayClickCallback menu_open_cb; void *udata; bool block; @@ -367,10 +367,10 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess driver->dbus->message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "ContextMenu")) { - if (tray_dbus->r_cb) { + if (tray_dbus->menu_open_cb) { Sint32 x = 0, y = 0; TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); - tray_dbus->r_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); + tray_dbus->menu_open_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -378,10 +378,10 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess driver->dbus->message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "Activate")) { - if (tray_dbus->l_cb) { + if (tray_dbus->activate_cb) { Sint32 x = 0, y = 0; TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); - tray_dbus->l_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); + tray_dbus->activate_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -389,10 +389,10 @@ static DBusHandlerResult TrayMessageHandler(DBusConnection *connection, DBusMess driver->dbus->message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } else if (driver->dbus->message_is_method_call(msg, SNI_INTERFACE, "SecondaryActivate")) { - if (tray_dbus->m_cb) { + if (tray_dbus->secondary_activate_cb) { Sint32 x = 0, y = 0; TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y); - tray_dbus->m_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); + tray_dbus->secondary_activate_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES); } reply = driver->dbus->message_new_method_return(msg); @@ -531,9 +531,9 @@ SDL_Tray *CreateTray(SDL_TrayDriver *driver, SDL_PropertiesID props) } /* Icon mouse event callbacks */ - tray_dbus->l_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_LEFTCLICK_CALLBACK_POINTER, NULL); - tray_dbus->r_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER, NULL); - tray_dbus->m_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_MIDDLECLICK_CALLBACK_POINTER, NULL); + tray_dbus->activate_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_LEFTCLICK_CALLBACK_POINTER, NULL); + tray_dbus->menu_open_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER, NULL); + tray_dbus->secondary_activate_cb = (SDL_TrayClickCallback)SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_MIDDLECLICK_CALLBACK_POINTER, NULL); tray_dbus->udata = SDL_GetPointerProperty(props, SDL_PROP_TRAY_CREATE_USERDATA_POINTER, NULL); return tray; @@ -761,7 +761,7 @@ bool TrayRightClickHandler(SDL_ListNode *menu, void *udata) SDL_Tray *tray = (SDL_Tray *)udata; SDL_TrayDBus *tray_dbus = (SDL_TrayDBus *)tray->internal; - return tray_dbus->r_cb(tray_dbus->udata, tray, 0, 0, SDL_TRAYCALLBACKCAPABILITIES_NONE); + return tray_dbus->menu_open_cb(tray_dbus->udata, tray, 0, 0, SDL_TRAYCALLBACKCAPABILITIES_NONE); } void TraySendNewMenu(SDL_Tray *tray, const char *new_path) @@ -909,7 +909,7 @@ SDL_TrayEntry *InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, } } - if (menu->parent_tray && !menu->parent_entry && tray_dbus->r_cb) { + if (menu->parent_tray && !menu->parent_entry && tray_dbus->menu_open_cb) { SDL_DBus_RegisterMenuOpenCallback(menu_dbus->menu, TrayRightClickHandler, tray); } From d3e3d962dfeb82b869584317cead8edb1a79fd34 Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 13:10:54 -0400 Subject: [PATCH 4/6] [tray/windows] added capabilities and position for windows --- src/tray/windows/SDL_tray.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/tray/windows/SDL_tray.c b/src/tray/windows/SDL_tray.c index fd46b6e3fb..3ba9e11b86 100644 --- a/src/tray/windows/SDL_tray.c +++ b/src/tray/windows/SDL_tray.c @@ -126,11 +126,20 @@ LRESULT CALLBACK TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_TRAYICON: { bool show_menu = false; + POINT cursor_pos; + GetCursorPos(&cursor_pos); switch (LOWORD(lParam)) { case WM_LBUTTONUP: if (tray->left_click_callback) { - show_menu = tray->left_click_callback(tray->userdata, tray); + show_menu = tray->left_click_callback( + tray->userdata, tray, + (Sint32)cursor_pos.x, + (Sint32)cursor_pos.y, + SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES | + SDL_TRAYCALLBACKCAPABILITIES_SUPPRESS_MENU | + SDL_TRAYCALLBACKCAPABILITIES_REQUEST_MENU + ); } else { show_menu = true; } @@ -138,7 +147,14 @@ LRESULT CALLBACK TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_CONTEXTMENU: if (tray->right_click_callback) { - show_menu = tray->right_click_callback(tray->userdata, tray); + show_menu = tray->right_click_callback( + tray->userdata, tray, + (Sint32)cursor_pos.x, + (Sint32)cursor_pos.y, + SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES | + SDL_TRAYCALLBACKCAPABILITIES_SUPPRESS_MENU | + SDL_TRAYCALLBACKCAPABILITIES_REQUEST_MENU + ); } else { show_menu = true; } @@ -146,7 +162,12 @@ LRESULT CALLBACK TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_MBUTTONUP: if (tray->middle_click_callback) { - tray->middle_click_callback(tray->userdata, tray); + tray->middle_click_callback( + tray->userdata, tray, + (Sint32)cursor_pos.x, + (Sint32)cursor_pos.y, + SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES + ); } break; } From 59c5a24e401068b56b90f284a09719cff2b90c00 Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 15:04:17 -0400 Subject: [PATCH 5/6] [tray] document Linux callback oddities --- include/SDL3/SDL_tray.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/SDL3/SDL_tray.h b/include/SDL3/SDL_tray.h index e9b09dd453..766f25dbc8 100644 --- a/include/SDL3/SDL_tray.h +++ b/include/SDL3/SDL_tray.h @@ -175,13 +175,19 @@ extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_CreateTray(SDL_Surface *icon, const c * SDL_TrayClickCallback to be invoked when the tray icon is left-clicked. * Not supported on all platforms. The callback should return true to show * the default menu, or false to skip showing it. May be NULL. + * On Linux, this will only run when the "Activate" signal is sent from + * the SNI host to the client. * - `SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER`: an * SDL_TrayClickCallback to be invoked when the tray icon is right-clicked. * Not supported on all platforms. The callback should return true to show * the default menu, or false to skip showing it. May be NULL. + * On Linux, this will only run when the menu is shown or the + * "ContextMenu" signal is sent from the SNI host to the client. * - `SDL_PROP_TRAY_CREATE_MIDDLECLICK_CALLBACK_POINTER`: an * SDL_TrayClickCallback to be invoked when the tray icon is middle-clicked. * Not supported on all platforms. May be NULL. + * On Linux, this is only sent when the "SecondaryActivate" signal is sent + * from the SNI host to the client. * * \param props the properties to use. * \returns The newly created system tray icon. From 5ab5060b5d09d6bd9b6e02f0f4d09cf6321efa07 Mon Sep 17 00:00:00 2001 From: A1029384756 Date: Fri, 24 Apr 2026 16:34:00 -0400 Subject: [PATCH 6/6] [tray] fixed flags and clarified linux behavior --- include/SDL3/SDL_tray.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/SDL3/SDL_tray.h b/include/SDL3/SDL_tray.h index 766f25dbc8..2140435ed4 100644 --- a/include/SDL3/SDL_tray.h +++ b/include/SDL3/SDL_tray.h @@ -94,7 +94,7 @@ typedef Uint32 SDL_TrayCallbackCapabilities; #define SDL_TRAYCALLBACKCAPABILITIES_NONE 0x00000000u /**< Tray callbacks have no capabilities */ #define SDL_TRAYCALLBACKCAPABILITIES_SUPPRESS_MENU 0x00000001u /**< Tray callbacks can suppress context menu */ #define SDL_TRAYCALLBACKCAPABILITIES_REQUEST_MENU 0x00000002u /**< Tray callbacks can request context menu open */ -#define SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES 0x00000003u /**< Tray callbacks include screen-space coordinates */ +#define SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES 0x00000004u /**< Tray callbacks include screen-space coordinates */ /** * A callback that is invoked when a tray entry is selected. @@ -176,7 +176,8 @@ extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_CreateTray(SDL_Surface *icon, const c * Not supported on all platforms. The callback should return true to show * the default menu, or false to skip showing it. May be NULL. * On Linux, this will only run when the "Activate" signal is sent from - * the SNI host to the client. + * the SNI host to the client. This does not occur when a tray menu is + * registered. * - `SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER`: an * SDL_TrayClickCallback to be invoked when the tray icon is right-clicked. * Not supported on all platforms. The callback should return true to show