fix(tray): continue when system tray is unavailable (#5968)

This commit is contained in:
Dave Lane authored and GitHub committed 2026-10-20 22:45:21 -04:00
1 parent cf0fff2563
commit 3494b23e20
3 files changed
+44

No files matched your search

+6
View File
@@ -820,6 +820,12 @@ namespace system_tray {
} }
void run_tray_until_exit(const std::shared_ptr<safe::event_t<bool>> &shutdown_event) { void run_tray_until_exit(const std::shared_ptr<safe::event_t<bool>> &shutdown_event) {
if (!tray_initialized_state().load()) {
BOOST_LOG(info) << "System tray is unavailable; continuing without it"sv;
shutdown_event->view();
return;
}
while (process_tray_events() == 0); while (process_tray_events() == 0);
shutdown_event->raise(true); shutdown_event->raise(true);
} }
+3
View File
@@ -95,6 +95,9 @@ namespace system_tray {
/** /**
* @brief Process tray events until exit and notify the application's workers. * @brief Process tray events until exit and notify the application's workers.
* *
* If tray initialization failed, wait for the application's shutdown event instead
* of stopping its workers. An initialized tray still requests shutdown when its loop exits.
*
* @param shutdown_event Event used to stop Sunshine's server threads. * @param shutdown_event Event used to stop Sunshine's server threads.
*/ */
void run_tray_until_exit(const std::shared_ptr<safe::event_t<bool>> &shutdown_event); void run_tray_until_exit(const std::shared_ptr<safe::event_t<bool>> &shutdown_event);
+35
View File
@@ -18,6 +18,7 @@
#include <cstdlib> #include <cstdlib>
#include <filesystem> #include <filesystem>
#include <format> #include <format>
#include <future>
#include <optional> #include <optional>
#include <string> #include <string>
#include <thread> #include <thread>
@@ -670,6 +671,40 @@ TEST_F(SystemTrayTest, ShowsMacBrokerLicenseAndAvailabilityWithOptionalStartupNo
} }
#endif #endif
/**
* @brief Verify the tray fallback waits for shutdown using an explicitly owned worker thread.
*/
TEST_F(SystemTrayTest, KeepsWorkersRunningWhenTrayIsUnavailable) {
ASSERT_FALSE(system_tray::tray_initialized_for_testing());
auto shutdown_event = std::make_shared<safe::event_t<bool>>();
std::promise<void> tray_loop_exited;
auto tray_loop = tray_loop_exited.get_future();
std::jthread tray_worker([shutdown_event, &tray_loop_exited]() {
system_tray::run_tray_until_exit(shutdown_event);
tray_loop_exited.set_value();
});
EXPECT_EQ(tray_loop.wait_for(100ms), std::future_status::timeout);
EXPECT_FALSE(shutdown_event->view(0ms));
shutdown_event->raise(true);
EXPECT_EQ(tray_loop.wait_for(5s), std::future_status::ready);
tray_worker.join();
EXPECT_TRUE(shutdown_event->peek());
EXPECT_FALSE(system_tray::tray_initialized_for_testing());
}
TEST_F(SystemTrayTest, HonorsPendingShutdownWhenTrayIsUnavailable) {
ASSERT_FALSE(system_tray::tray_initialized_for_testing());
auto shutdown_event = std::make_shared<safe::event_t<bool>>();
shutdown_event->raise(true);
system_tray::run_tray_until_exit(shutdown_event);
EXPECT_TRUE(shutdown_event->peek());
EXPECT_FALSE(system_tray::tray_initialized_for_testing());
}
#ifndef _WIN32 #ifndef _WIN32
TEST_F(SystemTrayTest, LifecycleMenuAndStateTransitions) { TEST_F(SystemTrayTest, LifecycleMenuAndStateTransitions) {
if (const int result = initialize_tray(); result != 0) { if (const int result = initialize_tray(); result != 0) {