mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-02-04 09:15:42 +00:00
fix(tray): optionally run tray in main event loop enabling support for macOS (#3818)
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")
|
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
|
set(PLATFORM_TARGET_FILES
|
||||||
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.h"
|
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.h"
|
||||||
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.m"
|
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_audio.m"
|
||||||
|
|||||||
@ -16,7 +16,7 @@ option(BUILD_WERROR "Enable -Werror flag." OFF)
|
|||||||
# if this option is set, the build will exit after configuring special package configuration files
|
# 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_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)
|
option(SUNSHINE_SYSTEM_WAYLAND_PROTOCOLS "Use system installation of wayland-protocols rather than the submodule." OFF)
|
||||||
|
|
||||||
|
|||||||
@ -120,7 +120,6 @@ class @PROJECT_NAME@ < Formula
|
|||||||
end
|
end
|
||||||
|
|
||||||
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
|
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
|
||||||
args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac?
|
|
||||||
|
|
||||||
system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles",
|
system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles",
|
||||||
*std_cmake_args,
|
*std_cmake_args,
|
||||||
|
|||||||
76
src/main.cpp
76
src/main.cpp
@ -88,6 +88,45 @@ WINAPI BOOL ConsoleCtrlHandler(DWORD type) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
||||||
|
#ifndef _WIN32
|
||||||
|
run_loop = tray_is_enabled; // On Windows, tray runs in separate thread, so no main loop needed for tray
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
lifetime::argv = argv;
|
lifetime::argv = argv;
|
||||||
|
|
||||||
@ -157,7 +196,7 @@ int main(int argc, char *argv[]) {
|
|||||||
BOOST_LOG(error) << "Display device session failed to initialize"sv;
|
BOOST_LOG(error) << "Display device session failed to initialize"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
// Modify relevant NVIDIA control panel settings if the system has corresponding gpu
|
// Modify relevant NVIDIA control panel settings if the system has corresponding gpu
|
||||||
if (nvprefs_instance.load()) {
|
if (nvprefs_instance.load()) {
|
||||||
// Restore global settings to the undo file left by improper termination of sunshine.exe
|
// Restore global settings to the undo file left by improper termination of sunshine.exe
|
||||||
@ -246,11 +285,6 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
task_pool.start(1);
|
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
|
// Create signal handler after logging has been initialized
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||||
on_signal(SIGINT, [&force_shutdown, &display_device_deinit_guard, shutdown_event]() {
|
on_signal(SIGINT, [&force_shutdown, &display_device_deinit_guard, shutdown_event]() {
|
||||||
@ -350,7 +384,23 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Wait for shutdown
|
if (tray_is_enabled) {
|
||||||
|
BOOST_LOG(info) << "Starting system tray"sv;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO: Windows has a weird bug where when running as a service and on the first Windows boot,
|
||||||
|
// he tray icon would not appear even though Sunshine is running correctly otherwise.
|
||||||
|
// Restarting the service would allow the icon to appear normally.
|
||||||
|
// For now we will keep the Windows tray icon on a separate thread.
|
||||||
|
// Ideally, we would run the system tray on the main thread for all platforms.
|
||||||
|
system_tray::init_tray_threaded();
|
||||||
|
#else
|
||||||
|
system_tray::init_tray();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
mainThreadLoop(shutdown_event);
|
||||||
|
|
||||||
|
// Wait for shutdown, this is not necessary when we're using the main event loop
|
||||||
shutdown_event->view();
|
shutdown_event->view();
|
||||||
|
|
||||||
httpThread.join();
|
httpThread.join();
|
||||||
@ -360,17 +410,17 @@ int main(int argc, char *argv[]) {
|
|||||||
task_pool.stop();
|
task_pool.stop();
|
||||||
task_pool.join();
|
task_pool.join();
|
||||||
|
|
||||||
// stop system tray
|
#ifdef _WIN32
|
||||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
|
||||||
system_tray::end_tray();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
// Restore global NVIDIA control panel settings
|
// Restore global NVIDIA control panel settings
|
||||||
if (nvprefs_instance.owning_undo_file() && nvprefs_instance.load()) {
|
if (nvprefs_instance.owning_undo_file() && nvprefs_instance.load()) {
|
||||||
nvprefs_instance.restore_global_profile();
|
nvprefs_instance.restore_global_profile();
|
||||||
nvprefs_instance.unload();
|
nvprefs_instance.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop the threaded tray if it was started
|
||||||
|
if (tray_is_enabled) {
|
||||||
|
system_tray::end_tray_threaded();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return lifetime::desired_exit_code;
|
return lifetime::desired_exit_code;
|
||||||
|
|||||||
@ -27,8 +27,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// standard includes
|
// standard includes
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
@ -47,38 +51,43 @@ using namespace std::literals;
|
|||||||
|
|
||||||
// system_tray namespace
|
// system_tray namespace
|
||||||
namespace system_tray {
|
namespace system_tray {
|
||||||
static std::atomic<bool> tray_initialized = false;
|
static std::atomic tray_initialized = false;
|
||||||
|
|
||||||
void tray_open_ui_cb(struct tray_menu *item) {
|
// Threading variables for all platforms
|
||||||
|
static std::thread tray_thread;
|
||||||
|
static std::atomic tray_thread_running = false;
|
||||||
|
static std::atomic tray_thread_should_exit = false;
|
||||||
|
|
||||||
|
void tray_open_ui_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
||||||
launch_ui();
|
launch_ui();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_donate_github_cb(struct tray_menu *item) {
|
void tray_donate_github_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
platf::open_url("https://github.com/sponsors/LizardByte");
|
platf::open_url("https://github.com/sponsors/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_donate_patreon_cb(struct tray_menu *item) {
|
void tray_donate_patreon_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
platf::open_url("https://www.patreon.com/LizardByte");
|
platf::open_url("https://www.patreon.com/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_donate_paypal_cb(struct tray_menu *item) {
|
void tray_donate_paypal_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
platf::open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
platf::open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_reset_display_device_config_cb(struct tray_menu *item) {
|
void tray_reset_display_device_config_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Resetting display device config from system tray"sv;
|
BOOST_LOG(info) << "Resetting display device config from system tray"sv;
|
||||||
|
|
||||||
std::ignore = display_device::reset_persistence();
|
std::ignore = display_device::reset_persistence();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_restart_cb(struct tray_menu *item) {
|
void tray_restart_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Restarting from system tray"sv;
|
BOOST_LOG(info) << "Restarting from system tray"sv;
|
||||||
|
|
||||||
platf::restart();
|
platf::restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_quit_cb(struct tray_menu *item) {
|
void tray_quit_cb([[maybe_unused]] struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Quitting from system tray"sv;
|
BOOST_LOG(info) << "Quitting from system tray"sv;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -123,7 +132,7 @@ namespace system_tray {
|
|||||||
.allIconPaths = {TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING},
|
.allIconPaths = {TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING},
|
||||||
};
|
};
|
||||||
|
|
||||||
int system_tray() {
|
int init_tray() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// If we're running as SYSTEM, Explorer.exe will not have permission to open our thread handle
|
// 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
|
// to monitor for thread termination. If Explorer fails to open our thread, our tray icon
|
||||||
@ -189,39 +198,32 @@ namespace system_tray {
|
|||||||
if (tray_init(&tray) < 0) {
|
if (tray_init(&tray) < 0) {
|
||||||
BOOST_LOG(warning) << "Failed to create system tray"sv;
|
BOOST_LOG(warning) << "Failed to create system tray"sv;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
BOOST_LOG(info) << "System tray created"sv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "System tray created"sv;
|
||||||
tray_initialized = true;
|
tray_initialized = true;
|
||||||
while (tray_loop(1) == 0) {
|
return 0;
|
||||||
BOOST_LOG(debug) << "System tray loop"sv;
|
}
|
||||||
|
|
||||||
|
int process_tray_events() {
|
||||||
|
if (!tray_initialized) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
|
||||||
|
|
||||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
// system_tray();
|
|
||||||
// });
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
int end_tray() {
|
int end_tray() {
|
||||||
tray_initialized = false;
|
if (tray_initialized) {
|
||||||
tray_exit();
|
tray_initialized = false;
|
||||||
|
tray_exit();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +240,10 @@ namespace system_tray {
|
|||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
tray.icon = TRAY_ICON_PLAYING;
|
tray.icon = TRAY_ICON_PLAYING;
|
||||||
tray.notification_title = "Stream Started";
|
tray.notification_title = "Stream Started";
|
||||||
char msg[256];
|
|
||||||
snprintf(msg, std::size(msg), "Streaming started for %s", app_name.c_str());
|
static std::string msg = std::format("Streaming started for {}", app_name);
|
||||||
tray.notification_text = msg;
|
tray.notification_text = msg.c_str();
|
||||||
tray.tooltip = msg;
|
tray.tooltip = msg.c_str();
|
||||||
tray.notification_icon = TRAY_ICON_PLAYING;
|
tray.notification_icon = TRAY_ICON_PLAYING;
|
||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
}
|
}
|
||||||
@ -257,12 +259,12 @@ namespace system_tray {
|
|||||||
tray.notification_icon = nullptr;
|
tray.notification_icon = nullptr;
|
||||||
tray.icon = TRAY_ICON_PAUSING;
|
tray.icon = TRAY_ICON_PAUSING;
|
||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
char msg[256];
|
|
||||||
snprintf(msg, std::size(msg), "Streaming paused for %s", app_name.c_str());
|
static std::string msg = std::format("Streaming paused for {}", app_name);
|
||||||
tray.icon = TRAY_ICON_PAUSING;
|
tray.icon = TRAY_ICON_PAUSING;
|
||||||
tray.notification_title = "Stream Paused";
|
tray.notification_title = "Stream Paused";
|
||||||
tray.notification_text = msg;
|
tray.notification_text = msg.c_str();
|
||||||
tray.tooltip = msg;
|
tray.tooltip = msg.c_str();
|
||||||
tray.notification_icon = TRAY_ICON_PAUSING;
|
tray.notification_icon = TRAY_ICON_PAUSING;
|
||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
}
|
}
|
||||||
@ -278,12 +280,12 @@ namespace system_tray {
|
|||||||
tray.notification_icon = nullptr;
|
tray.notification_icon = nullptr;
|
||||||
tray.icon = TRAY_ICON;
|
tray.icon = TRAY_ICON;
|
||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
char msg[256];
|
|
||||||
snprintf(msg, std::size(msg), "Application %s successfully stopped", app_name.c_str());
|
static std::string msg = std::format("Application {} successfully stopped", app_name);
|
||||||
tray.icon = TRAY_ICON;
|
tray.icon = TRAY_ICON;
|
||||||
tray.notification_icon = TRAY_ICON;
|
tray.notification_icon = TRAY_ICON;
|
||||||
tray.notification_title = "Application Stopped";
|
tray.notification_title = "Application Stopped";
|
||||||
tray.notification_text = msg;
|
tray.notification_text = msg.c_str();
|
||||||
tray.tooltip = PROJECT_NAME;
|
tray.tooltip = PROJECT_NAME;
|
||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
}
|
}
|
||||||
@ -310,5 +312,94 @@ namespace system_tray {
|
|||||||
tray_update(&tray);
|
tray_update(&tray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Threading functions available on all platforms
|
||||||
|
static void tray_thread_worker() {
|
||||||
|
BOOST_LOG(info) << "System tray thread started"sv;
|
||||||
|
|
||||||
|
// Initialize the tray in this thread
|
||||||
|
if (init_tray() != 0) {
|
||||||
|
BOOST_LOG(error) << "Failed to initialize tray in thread"sv;
|
||||||
|
tray_thread_running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tray_thread_running = true;
|
||||||
|
|
||||||
|
// Main tray event loop
|
||||||
|
while (!tray_thread_should_exit) {
|
||||||
|
if (process_tray_events() != 0) {
|
||||||
|
BOOST_LOG(warning) << "Tray event processing failed in thread"sv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sleep to avoid busy waiting
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the tray
|
||||||
|
end_tray();
|
||||||
|
tray_thread_running = false;
|
||||||
|
BOOST_LOG(info) << "System tray thread ended"sv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_tray_threaded() {
|
||||||
|
if (tray_thread_running) {
|
||||||
|
BOOST_LOG(warning) << "Tray thread is already running"sv;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tray_thread_should_exit = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
tray_thread = std::thread(tray_thread_worker);
|
||||||
|
|
||||||
|
// Wait for the thread to start and initialize
|
||||||
|
const auto start_time = std::chrono::steady_clock::now();
|
||||||
|
while (!tray_thread_running && !tray_thread_should_exit) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
// Timeout after 10 seconds
|
||||||
|
if (std::chrono::steady_clock::now() - start_time > std::chrono::seconds(10)) {
|
||||||
|
BOOST_LOG(error) << "Tray thread initialization timeout"sv;
|
||||||
|
tray_thread_should_exit = true;
|
||||||
|
if (tray_thread.joinable()) {
|
||||||
|
tray_thread.join();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tray_thread_running) {
|
||||||
|
BOOST_LOG(error) << "Tray thread failed to start"sv;
|
||||||
|
if (tray_thread.joinable()) {
|
||||||
|
tray_thread.join();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "System tray thread initialized successfully"sv;
|
||||||
|
return 0;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
BOOST_LOG(error) << "Failed to create tray thread: " << e.what();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int end_tray_threaded() {
|
||||||
|
if (!tray_thread_running) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "Stopping system tray thread"sv;
|
||||||
|
tray_thread_should_exit = true;
|
||||||
|
|
||||||
|
if (tray_thread.joinable()) {
|
||||||
|
tray_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "System tray thread stopped"sv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace system_tray
|
} // namespace system_tray
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -12,56 +12,55 @@ namespace system_tray {
|
|||||||
* @brief Callback for opening the UI from the system tray.
|
* @brief Callback for opening the UI from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_open_ui_cb(struct tray_menu *item);
|
void tray_open_ui_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for opening GitHub Sponsors from the system tray.
|
* @brief Callback for opening GitHub Sponsors from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_github_cb(struct tray_menu *item);
|
void tray_donate_github_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for opening Patreon from the system tray.
|
* @brief Callback for opening Patreon from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_patreon_cb(struct tray_menu *item);
|
void tray_donate_patreon_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for opening PayPal donation from the system tray.
|
* @brief Callback for opening PayPal donation from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_paypal_cb(struct tray_menu *item);
|
void tray_donate_paypal_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for resetting display device configuration.
|
* @brief Callback for resetting display device configuration.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_reset_display_device_config_cb(struct tray_menu *item);
|
void tray_reset_display_device_config_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for restarting Sunshine from the system tray.
|
* @brief Callback for restarting Sunshine from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_restart_cb(struct tray_menu *item);
|
void tray_restart_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for exiting Sunshine from the system tray.
|
* @brief Callback for exiting Sunshine from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_quit_cb(struct tray_menu *item);
|
void tray_quit_cb([[maybe_unused]] struct tray_menu *item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create the system tray.
|
* @brief Initializes the system tray without starting a loop.
|
||||||
* @details This function has an endless loop, so it should be run in a separate thread.
|
* @return 0 if initialization was successful, non-zero otherwise.
|
||||||
* @return 1 if the system tray failed to create, otherwise 0 once the tray has been terminated.
|
|
||||||
*/
|
*/
|
||||||
int system_tray();
|
int init_tray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run the system tray with platform specific options.
|
* @brief Processes a single tray event iteration.
|
||||||
* @todo macOS requires that UI elements be created on the main thread, so the system tray is not currently implemented for macOS.
|
* @return 0 if processing was successful, non-zero otherwise.
|
||||||
*/
|
*/
|
||||||
int run_tray();
|
int process_tray_events();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Exit the system tray.
|
* @brief Exit the system tray.
|
||||||
@ -91,4 +90,16 @@ namespace system_tray {
|
|||||||
* @brief Spawns a notification for PIN Pairing. Clicking it opens the PIN Web UI Page
|
* @brief Spawns a notification for PIN Pairing. Clicking it opens the PIN Web UI Page
|
||||||
*/
|
*/
|
||||||
void update_tray_require_pin();
|
void update_tray_require_pin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes and runs the system tray in a separate thread.
|
||||||
|
* @return 0 if initialization was successful, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int init_tray_threaded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the threaded system tray and waits for the thread to finish.
|
||||||
|
* @return 0 after stopping the threaded tray.
|
||||||
|
*/
|
||||||
|
int end_tray_threaded();
|
||||||
} // namespace system_tray
|
} // namespace system_tray
|
||||||
|
|||||||
Reference in New Issue
Block a user