mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
fix(tray): run tray in main event loop enabling support for macOS
Co-Authored-By: Lukas Senionis <22381748+FrogTheFrog@users.noreply.github.com>
This commit is contained in:
@@ -28,9 +28,6 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||
|
||||
set(APPLE_PLIST_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/Info.plist")
|
||||
|
||||
# todo - tray is not working on macos
|
||||
set(SUNSHINE_TRAY 0)
|
||||
|
||||
set(PLATFORM_TARGET_FILES
|
||||
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.m"
|
||||
|
||||
@@ -17,7 +17,7 @@ option(BUILD_WERROR "Enable -Werror flag." OFF)
|
||||
# if this option is set, the build will exit after configuring special package configuration files
|
||||
option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF)
|
||||
|
||||
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon. This option will be ignored on macOS." ON)
|
||||
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon." ON)
|
||||
|
||||
option(SUNSHINE_SYSTEM_WAYLAND_PROTOCOLS "Use system installation of wayland-protocols rather than the submodule." OFF)
|
||||
|
||||
|
||||
@@ -246,7 +246,6 @@ index 5b3638d..aca9481 100644
|
||||
end
|
||||
|
||||
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
|
||||
args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac?
|
||||
|
||||
# Handle system tray on Linux
|
||||
if OS.linux?
|
||||
|
||||
57
src/main.cpp
57
src/main.cpp
@@ -89,6 +89,43 @@ WINAPI BOOL ConsoleCtrlHandler(DWORD type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
constexpr bool tray_is_enabled = true;
|
||||
#else
|
||||
constexpr bool tray_is_enabled = false;
|
||||
#endif
|
||||
|
||||
void mainThreadLoop(const std::shared_ptr<safe::event_t<bool>> &shutdown_event) {
|
||||
bool run_loop = false;
|
||||
|
||||
// Conditions that would require the main thread event loop
|
||||
run_loop = tray_is_enabled;
|
||||
|
||||
if (!run_loop) {
|
||||
BOOST_LOG(info) << "No main thread features enabled, skipping event loop"sv;
|
||||
return;
|
||||
}
|
||||
|
||||
// Main thread event loop
|
||||
BOOST_LOG(info) << "Starting main loop"sv;
|
||||
while (true) {
|
||||
if (shutdown_event->peek()) {
|
||||
BOOST_LOG(info) << "Shutdown event detected, breaking main loop"sv;
|
||||
if (tray_is_enabled) {
|
||||
system_tray::end_tray();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (tray_is_enabled) {
|
||||
system_tray::process_tray_events();
|
||||
}
|
||||
|
||||
// Sleep to avoid busy waiting
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
lifetime::argv = argv;
|
||||
|
||||
@@ -243,11 +280,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
task_pool.start(1);
|
||||
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
// create tray thread and detach it
|
||||
system_tray::run_tray();
|
||||
#endif
|
||||
|
||||
// Create signal handler after logging has been initialized
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
on_signal(SIGINT, [&force_shutdown, &display_device_deinit_guard, shutdown_event]() {
|
||||
@@ -346,19 +378,22 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
rtsp_stream::rtpThread();
|
||||
std::thread rtpThread {rtsp_stream::start};
|
||||
|
||||
if (tray_is_enabled) {
|
||||
BOOST_LOG(info) << "Starting system tray"sv;
|
||||
system_tray::init_tray();
|
||||
}
|
||||
|
||||
mainThreadLoop(shutdown_event);
|
||||
|
||||
httpThread.join();
|
||||
configThread.join();
|
||||
rtpThread.join();
|
||||
|
||||
task_pool.stop();
|
||||
task_pool.join();
|
||||
|
||||
// stop system tray
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
system_tray::end_tray();
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
// Restore global NVIDIA control panel settings
|
||||
if (nvprefs_instance.owning_undo_file() && nvprefs_instance.load()) {
|
||||
|
||||
@@ -1088,7 +1088,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &option, 200, "OK", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void rtpThread() {
|
||||
void start() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||
|
||||
|
||||
@@ -59,6 +59,6 @@ namespace rtsp_stream {
|
||||
*/
|
||||
void terminate_sessions();
|
||||
|
||||
void rtpThread();
|
||||
void start();
|
||||
|
||||
} // namespace rtsp_stream
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace system_tray {
|
||||
.allIconPaths = {TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING},
|
||||
};
|
||||
|
||||
int system_tray() {
|
||||
int init_tray() {
|
||||
#ifdef _WIN32
|
||||
// If we're running as SYSTEM, Explorer.exe will not have permission to open our thread handle
|
||||
// to monitor for thread termination. If Explorer fails to open our thread, our tray icon
|
||||
@@ -195,29 +195,21 @@ namespace system_tray {
|
||||
}
|
||||
|
||||
tray_initialized = true;
|
||||
while (tray_loop(1) == 0) {
|
||||
BOOST_LOG(debug) << "System tray loop"sv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_tray() {
|
||||
// create the system tray
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
// macOS requires that UI elements be created on the main thread
|
||||
// creating tray using dispatch queue does not work, although the code doesn't actually throw any (visible) errors
|
||||
int process_tray_events() {
|
||||
if (!tray_initialized) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// system_tray();
|
||||
// });
|
||||
// Process one iteration of the tray loop with non-blocking mode (0)
|
||||
if (const int result = tray_loop(0); result != 0) {
|
||||
BOOST_LOG(warning) << "System tray loop failed"sv;
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "system_tray() is not yet implemented for this platform."sv;
|
||||
#else // Windows, Linux
|
||||
// create tray in separate thread
|
||||
std::thread tray_thread(system_tray);
|
||||
tray_thread.detach();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_tray() {
|
||||
|
||||
@@ -51,17 +51,16 @@ namespace system_tray {
|
||||
void tray_quit_cb(struct tray_menu *item);
|
||||
|
||||
/**
|
||||
* @brief Create the system tray.
|
||||
* @details This function has an endless loop, so it should be run in a separate thread.
|
||||
* @return 1 if the system tray failed to create, otherwise 0 once the tray has been terminated.
|
||||
* @brief Initializes the system tray without starting a loop.
|
||||
* @return 0 if initialization was successful, non-zero otherwise.
|
||||
*/
|
||||
int system_tray();
|
||||
int init_tray();
|
||||
|
||||
/**
|
||||
* @brief Run the system tray with platform specific options.
|
||||
* @todo macOS requires that UI elements be created on the main thread, so the system tray is not currently implemented for macOS.
|
||||
* @brief Processes a single tray event iteration.
|
||||
* @return 0 if processing was successful, non-zero otherwise.
|
||||
*/
|
||||
int run_tray();
|
||||
int process_tray_events();
|
||||
|
||||
/**
|
||||
* @brief Exit the system tray.
|
||||
|
||||
Reference in New Issue
Block a user