Skip to content

Commit 73f84fb

Browse files
fix(tray): optionally run tray in main event loop enabling support for macOS (#3818)
Co-authored-by: Lukas Senionis <[email protected]>
1 parent 705d763 commit 73f84fb

File tree

6 files changed

+224
-76
lines changed

6 files changed

+224
-76
lines changed

cmake/compile_definitions/macos.cmake

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
2828

2929
set(APPLE_PLIST_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/Info.plist")
3030

31-
# todo - tray is not working on macos
32-
set(SUNSHINE_TRAY 0)
33-
3431
set(PLATFORM_TARGET_FILES
3532
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.h"
3633
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.m"

cmake/prep/options.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ option(BUILD_WERROR "Enable -Werror flag." OFF)
1616
# if this option is set, the build will exit after configuring special package configuration files
1717
option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF)
1818

19-
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon. This option will be ignored on macOS." ON)
19+
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon." ON)
2020

2121
option(SUNSHINE_SYSTEM_WAYLAND_PROTOCOLS "Use system installation of wayland-protocols rather than the submodule." OFF)
2222

packaging/sunshine.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ def install
120120
end
121121

122122
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
123-
args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac?
124123

125124
system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles",
126125
*std_cmake_args,

src/main.cpp

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,45 @@ WINAPI BOOL ConsoleCtrlHandler(DWORD type) {
8888
}
8989
#endif
9090

91+
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
92+
constexpr bool tray_is_enabled = true;
93+
#else
94+
constexpr bool tray_is_enabled = false;
95+
#endif
96+
97+
void mainThreadLoop(const std::shared_ptr<safe::event_t<bool>> &shutdown_event) {
98+
bool run_loop = false;
99+
100+
// Conditions that would require the main thread event loop
101+
#ifndef _WIN32
102+
run_loop = tray_is_enabled; // On Windows, tray runs in separate thread, so no main loop needed for tray
103+
#endif
104+
105+
if (!run_loop) {
106+
BOOST_LOG(info) << "No main thread features enabled, skipping event loop"sv;
107+
return;
108+
}
109+
110+
// Main thread event loop
111+
BOOST_LOG(info) << "Starting main loop"sv;
112+
while (true) {
113+
if (shutdown_event->peek()) {
114+
BOOST_LOG(info) << "Shutdown event detected, breaking main loop"sv;
115+
if (tray_is_enabled) {
116+
system_tray::end_tray();
117+
}
118+
break;
119+
}
120+
121+
if (tray_is_enabled) {
122+
system_tray::process_tray_events();
123+
}
124+
125+
// Sleep to avoid busy waiting
126+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
127+
}
128+
}
129+
91130
int main(int argc, char *argv[]) {
92131
lifetime::argv = argv;
93132

@@ -157,7 +196,7 @@ int main(int argc, char *argv[]) {
157196
BOOST_LOG(error) << "Display device session failed to initialize"sv;
158197
}
159198

160-
#ifdef WIN32
199+
#ifdef _WIN32
161200
// Modify relevant NVIDIA control panel settings if the system has corresponding gpu
162201
if (nvprefs_instance.load()) {
163202
// Restore global settings to the undo file left by improper termination of sunshine.exe
@@ -246,11 +285,6 @@ int main(int argc, char *argv[]) {
246285

247286
task_pool.start(1);
248287

249-
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
250-
// create tray thread and detach it
251-
system_tray::run_tray();
252-
#endif
253-
254288
// Create signal handler after logging has been initialized
255289
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
256290
on_signal(SIGINT, [&force_shutdown, &display_device_deinit_guard, shutdown_event]() {
@@ -350,7 +384,23 @@ int main(int argc, char *argv[]) {
350384
}
351385
#endif
352386

353-
// Wait for shutdown
387+
if (tray_is_enabled) {
388+
BOOST_LOG(info) << "Starting system tray"sv;
389+
#ifdef _WIN32
390+
// TODO: Windows has a weird bug where when running as a service and on the first Windows boot,
391+
// he tray icon would not appear even though Sunshine is running correctly otherwise.
392+
// Restarting the service would allow the icon to appear normally.
393+
// For now we will keep the Windows tray icon on a separate thread.
394+
// Ideally, we would run the system tray on the main thread for all platforms.
395+
system_tray::init_tray_threaded();
396+
#else
397+
system_tray::init_tray();
398+
#endif
399+
}
400+
401+
mainThreadLoop(shutdown_event);
402+
403+
// Wait for shutdown, this is not necessary when we're using the main event loop
354404
shutdown_event->view();
355405

356406
httpThread.join();
@@ -360,17 +410,17 @@ int main(int argc, char *argv[]) {
360410
task_pool.stop();
361411
task_pool.join();
362412

363-
// stop system tray
364-
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
365-
system_tray::end_tray();
366-
#endif
367-
368-
#ifdef WIN32
413+
#ifdef _WIN32
369414
// Restore global NVIDIA control panel settings
370415
if (nvprefs_instance.owning_undo_file() && nvprefs_instance.load()) {
371416
nvprefs_instance.restore_global_profile();
372417
nvprefs_instance.unload();
373418
}
419+
420+
// Stop the threaded tray if it was started
421+
if (tray_is_enabled) {
422+
system_tray::end_tray_threaded();
423+
}
374424
#endif
375425

376426
return lifetime::desired_exit_code;

0 commit comments

Comments
 (0)