This commit is contained in:
Hayden Gray 2026-06-05 14:01:23 -06:00 committed by GitHub
commit 5614a20811
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 18 deletions

View file

@ -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 0x00000004u /**< 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.
@ -160,13 +175,20 @@ 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. 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
* 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.

View file

@ -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;
@ -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;
@ -354,8 +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) {
tray_dbus->r_cb(tray_dbus->udata, tray);
if (tray_dbus->menu_open_cb) {
Sint32 x = 0, y = 0;
TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y);
tray_dbus->menu_open_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES);
}
reply = driver->dbus->message_new_method_return(msg);
@ -363,8 +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) {
tray_dbus->l_cb(tray_dbus->udata, tray);
if (tray_dbus->activate_cb) {
Sint32 x = 0, y = 0;
TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y);
tray_dbus->activate_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES);
}
reply = driver->dbus->message_new_method_return(msg);
@ -372,8 +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) {
tray_dbus->m_cb(tray_dbus->udata, tray);
if (tray_dbus->secondary_activate_cb) {
Sint32 x = 0, y = 0;
TrayGetClickCoordinatesFromMessage(driver, msg, &x, &y);
tray_dbus->secondary_activate_cb(tray_dbus->udata, tray, x, y, SDL_TRAYCALLBACKCAPABILITIES_CLICK_COORDINATES);
}
reply = driver->dbus->message_new_method_return(msg);
@ -512,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;
@ -738,7 +757,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->menu_open_cb(tray_dbus->udata, tray, 0, 0, SDL_TRAYCALLBACKCAPABILITIES_NONE);
}
void TraySendNewMenu(SDL_Tray *tray, const char *new_path)
@ -886,7 +905,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);
}

View file

@ -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;
}