feat(macos/tray): allow tray icon paths to be set at runtime from .app bundle (#4711)

This commit is contained in:
Andy Grundman
2026-02-13 08:19:39 -05:00
committed by GitHub
parent f442ff81e7
commit 941f6453c1

View File

@@ -23,7 +23,9 @@
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing-16.png"
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing-16.png"
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked-16.png"
#include <CoreFoundation/CoreFoundation.h>
#include <dispatch/dispatch.h>
#include <unordered_map>
#endif
// standard includes
@@ -127,6 +129,58 @@ namespace system_tray {
.allIconPaths = {TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING},
};
const char *GetResourcePath(const char *relativePath) {
#ifdef __APPLE__
if (!relativePath || !*relativePath) {
return nullptr;
}
// Simple cache ensures our string pointers live forever
static std::unordered_map<std::string, std::string> g_cache;
auto search = g_cache.find(relativePath);
if (search != g_cache.end()) {
return search->second.c_str();
}
// If we're running from an .app bundle, get the internal Resources dir
CFBundleRef bundle = CFBundleGetMainBundle();
if (!bundle) {
return relativePath;
}
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
if (!resourcesURL) {
return relativePath;
}
char resourcesPath[PATH_MAX];
bool ok = CFURLGetFileSystemRepresentation(
resourcesURL,
true,
reinterpret_cast<UInt8 *>(resourcesPath),
sizeof(resourcesPath)
);
CFRelease(resourcesURL);
if (!ok) {
return relativePath;
}
std::string full;
if (relativePath && relativePath[0] == '/') {
full = relativePath;
} else {
full = std::string(resourcesPath) + "/" + relativePath;
}
BOOST_LOG(debug) << "System Tray: using " << full << " for icon path";
auto [it, inserted] = g_cache.emplace(relativePath, std::move(full));
return it->second.c_str();
#else
return relativePath;
#endif
}
int init_tray() {
#ifdef _WIN32
// If we're running as SYSTEM, Explorer.exe will not have permission to open our thread handle
@@ -190,6 +244,16 @@ namespace system_tray {
}
#endif
#ifdef __APPLE__
// if these icon paths are relative, resolve to internal .app Resources path
tray.allIconPaths[0] = GetResourcePath(TRAY_ICON);
tray.allIconPaths[1] = GetResourcePath(TRAY_ICON_LOCKED);
tray.allIconPaths[2] = GetResourcePath(TRAY_ICON_PLAYING);
tray.allIconPaths[3] = GetResourcePath(TRAY_ICON_PAUSING);
tray.icon = tray.allIconPaths[0];
#endif
if (tray_init(&tray) < 0) {
BOOST_LOG(warning) << "Failed to create system tray"sv;
return 1;