SDL: [tray/dbus] set tray session name to app subname in flatpak env (#15393)

From 1675c8267ede3d12d26a362161eed2dda0813079 Mon Sep 17 00:00:00 2001
From: Hayden Gray <[EMAIL REDACTED]>
Date: Mon, 20 Apr 2026 14:50:22 -0400
Subject: [PATCH] [tray/dbus] set tray session name to app subname in flatpak
 env (#15393)

* [tray/dbus] set tray session name to app subname in flatpak env
* [tray/dbus] have dbus service name come from the app id. app id falls
back to flatpak if in a flatpak environment
* [tray/dbus] change dbus menu path to work with apparmor
---
 src/core/linux/SDL_dbus.c    | 2 +-
 src/core/unix/SDL_appid.c    | 6 ++++++
 src/tray/unix/SDL_dbustray.c | 7 ++++++-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c
index af791b764e9f3..2416907fc68d8 100644
--- a/src/core/linux/SDL_dbus.c
+++ b/src/core/linux/SDL_dbus.c
@@ -53,7 +53,7 @@ static unsigned int screensaver_cookie = 0;
 static SDL_DBusContext dbus;
 
 #define DBUS_MENU_INTERFACE   "com.canonical.dbusmenu"
-#define DBUS_MENU_OBJECT_PATH "/Menu"
+#define DBUS_MENU_OBJECT_PATH "/StatusNotifierItem/menu"
 
 #define SDL_DBUS_UPDATE_MENU_FLAG_DO_NOT_REPLACE (1 << 0)
 static const char *menu_introspect = "<?xml version=\"1.0\"?><node name=\"/\"><interface name=\"com.canonical.dbusmenu\"><property name=\"Version\" type=\"u\" access=\"read\"></property><property name=\"TextDirection\" type=\"s\" access=\"read\"></property><property name=\"Status\" type=\"s\" access=\"read\"></property><property name=\"IconThemePath\" type=\"as\" access=\"read\"></property><method name=\"GetLayout\"><arg type=\"i\" name=\"parentId\" direction=\"in\"></arg><arg type=\"i\" name=\"recursionDepth\" direction=\"in\"></arg><arg type=\"as\" name=\"propertyNames\" direction=\"in\"></arg><arg type=\"u\" name=\"revision\" direction=\"out\"></arg><arg type=\"(ia{sv}av)\" name=\"layout\" direction=\"out\"></arg></method><method name=\"GetGroupProperties\"><arg type=\"ai\" name=\"ids\" direction=\"in\"></arg><arg type=\"as\" name=\"propertyNames\" direction=\"in\"></arg><arg type=\"a(ia{sv})\" name=\"properties\" direction=\"out\"></arg></method><method name=\"GetProperty\"><arg type=\"i\" name=\"id\" direction=\"in\"></arg><arg type=\"s\" name=\"name\" direction=\"in\"></arg><arg type=\"v\" name=\"value\" direction=\"out\"></arg></method><method name=\"Event\"><arg type=\"i\" name=\"id\" direction=\"in\"></arg><arg type=\"s\" name=\"eventId\" direction=\"in\"></arg><arg type=\"v\" name=\"data\" direction=\"in\"></arg><arg type=\"u\" name=\"timestamp\" direction=\"in\"></arg></method><method name=\"EventGroup\"><arg type=\"a(isvu)\" name=\"events\" direction=\"in\"></arg><arg type=\"ai\" name=\"idErrors\" direction=\"out\"></arg></method><method name=\"AboutToShow\"><arg type=\"i\" name=\"id\" direction=\"in\"></arg><arg type=\"b\" name=\"needUpdate\" direction=\"out\"></arg></method><method name=\"AboutToShowGroup\"><arg type=\"ai\" name=\"ids\" direction=\"in\"></arg><arg type=\"ai\" name=\"updatesNeeded\" direction=\"out\"></arg><arg type=\"ai\" name=\"idErrors\" direction=\"out\"></arg></method><signal name=\"ItemsPropertiesUpdated\"><arg type=\"a(ia{sv})\" name=\"updatedProps\" direction=\"out\"/><arg type=\"a(ias)\" name=\"removedProps\" direction=\"out\"/></signal><signal name=\"LayoutUpdated\"><arg type=\"u\" name=\"revision\" direction=\"out\"></arg><arg type=\"i\" name=\"parent\" direction=\"out\"></arg></signal><signal name=\"ItemActivationRequested\"><arg type=\"i\" name=\"id\" direction=\"out\"></arg><arg type=\"u\" name=\"timestamp\" direction=\"out\"></arg></signal></interface></node>";
diff --git a/src/core/unix/SDL_appid.c b/src/core/unix/SDL_appid.c
index 3b85cbc876ba7..afe157f2cd82d 100644
--- a/src/core/unix/SDL_appid.c
+++ b/src/core/unix/SDL_appid.c
@@ -61,6 +61,12 @@ const char *SDL_GetAppID(void)
 {
     const char *id_str = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING);
 
+#ifdef SDL_PLATFORM_LINUX
+    if (!id_str) {
+        id_str = SDL_getenv("FLATPAK_ID");
+    }
+#endif
+
     if (!id_str) {
         // If the hint isn't set, try to use the application's executable name
         id_str = SDL_GetExeName();
diff --git a/src/tray/unix/SDL_dbustray.c b/src/tray/unix/SDL_dbustray.c
index 0885da8f01b44..c2c66679e7160 100644
--- a/src/tray/unix/SDL_dbustray.c
+++ b/src/tray/unix/SDL_dbustray.c
@@ -28,6 +28,7 @@
 #ifdef SDL_USE_LIBDBUS
 
 #include "../../video/SDL_surface_c.h"
+#include "../../core/unix/SDL_appid.h"
 #include "../SDL_tray_utils.h"
 #include "SDL_unixtray.h"
 #include <unistd.h>
@@ -468,7 +469,11 @@ SDL_Tray *CreateTray(SDL_TrayDriver *driver, SDL_PropertiesID props)
 
     /* Request name */
     driver->count++;
-    SDL_asprintf(&tray_dbus->service_name, "org.kde.StatusNotifierItem-%d-%d", getpid(), driver->count);
+    if (SDL_GetSandbox() == SDL_SANDBOX_FLATPAK) {
+        SDL_asprintf(&tray_dbus->service_name, "%s.tray%d", SDL_GetAppID(), driver->count);
+    } else {
+        SDL_asprintf(&tray_dbus->service_name, "org.kde.StatusNotifierItem-%d-%d", getpid(), driver->count);
+    }
     status = dbus_driver->dbus->bus_request_name(tray_dbus->connection, tray_dbus->service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
     if (dbus_driver->dbus->error_is_set(&err)) {
         SDL_SetError("Unable to create tray: %s", err.message);