2222#include < shared/desktop/glfw.h>
2323#include " spdlog/cfg/env.h"
2424#include < csignal>
25+ #include < future>
26+ #include < chrono>
2527
2628// Third-party includes
2729#include < fmt/format.h>
@@ -64,19 +66,59 @@ static auto DISPLAY_APP_NAME = "LED Matrix Controller";
6466static bool showMainWindow = false ;
6567
6668#ifdef _WIN32
69+ // Global variables for shutdown handling on Windows
70+ static std::string g_shutdown_hostname;
71+ static uint16_t g_shutdown_port = 0 ;
72+ static bool g_should_turn_off_on_exit = false ;
73+
6774// Console control handler for Windows
6875static BOOL WINAPI console_ctrl_handler (DWORD ctrlType) {
6976 // Request graceful shutdown
7077 shouldExit = true ;
78+ // Attempt to turn off matrix during shutdown on Windows
79+ if (g_should_turn_off_on_exit && !g_shutdown_hostname.empty () && g_shutdown_port > 0 ) {
80+ spdlog::info (" Received shutdown signal, turning Matrix OFF." );
81+ try {
82+ auto url = fmt::format (" http://{}:{}/set_enabled?enabled=false" , g_shutdown_hostname, g_shutdown_port);
83+ cpr::Response response = cpr::Get (cpr::Url (url), cpr::Timeout{3000L }); // 3 second timeout
84+ if (response.error ) {
85+ spdlog::error (" Failed to turn off matrix during shutdown: {}" , response.error .message );
86+ } else {
87+ spdlog::info (" Matrix turned OFF during shutdown." );
88+ }
89+ } catch (const std::exception &e) {
90+ spdlog::error (" Exception while turning off matrix during shutdown: {}" , e.what ());
91+ }
92+ }
7193 // Indicate we've handled the event so the process isn't terminated immediately
7294 return TRUE ;
7395}
7496#else
97+ // Global variables for shutdown handling on Linux
98+ static std::string g_shutdown_hostname;
99+ static uint16_t g_shutdown_port = 0 ;
100+ static bool g_should_turn_off_on_exit = false ;
75101// Use sig_atomic_t for async-signal-safety
76102static volatile sig_atomic_t signalReceived = 0 ;
103+
77104static void signal_handler (int /* signum*/ ) {
78105 signalReceived = 1 ;
79106 shouldExit = true ;
107+ // Attempt to turn off matrix during shutdown on Linux
108+ if (g_should_turn_off_on_exit && !g_shutdown_hostname.empty () && g_shutdown_port > 0 ) {
109+ spdlog::info (" Received shutdown signal, turning Matrix OFF." );
110+ try {
111+ auto url = fmt::format (" http://{}:{}/set_enabled?enabled=false" , g_shutdown_hostname, g_shutdown_port);
112+ cpr::Response response = cpr::Get (cpr::Url (url), cpr::Timeout{3000L }); // 3 second timeout
113+ if (response.error ) {
114+ spdlog::error (" Failed to turn off matrix during shutdown: {}" , response.error .message );
115+ } else {
116+ spdlog::info (" Matrix turned OFF during shutdown." );
117+ }
118+ } catch (const std::exception &e) {
119+ spdlog::error (" Exception while turning off matrix during shutdown: {}" , e.what ());
120+ }
121+ }
80122}
81123#endif
82124
@@ -91,24 +133,31 @@ static void window_iconify_callback(GLFWwindow *window, const int iconified) {
91133 }
92134}
93135
94- // ----- Function to change matrix status ----
95- static void change_matrix_status (const std::string &hostname, uint16_t port, bool turnOn) {
96- std::thread ([hostname, port, turnOn]() {
97- try {
98- auto url = fmt::format (" http://{}:{}/set_enabled?enabled={}" , hostname, port,
99- turnOn ? " true" : " false" );
100-
101- cpr::Response response = cpr::Get (cpr::Url (url));
102- if (response.error ) {
103- spdlog::error (" Failed to change matrix status: {}" , response.error .message );
104- } else {
105- spdlog::info (" Matrix turned {} successfully." , turnOn ? " on" : " off" );
106- }
107- } catch (const std::exception &e) {
108- spdlog::error (" Exception while changing matrix status: {}" , e.what ());
109- }
110- })
111- .detach ();
136+ // ----- Function to change matrix status (synchronous with timeout) ----
137+ static void change_matrix_status (const std::string &hostname, uint16_t port, bool turnOn, bool waitForCompletion = false ) {
138+ auto task = [hostname, port, turnOn]() {
139+ try {
140+ auto url = fmt::format (" http://{}:{}/set_enabled?enabled={}" , hostname, port,
141+ turnOn ? " true" : " false" );
142+
143+ cpr::Response response = cpr::Get (cpr::Url (url), cpr::Timeout{5000L }); // 5 second timeout
144+ if (response.error ) {
145+ spdlog::error (" Failed to change matrix status: {}" , response.error .message );
146+ } else {
147+ spdlog::info (" Matrix turned {} successfully." , turnOn ? " on" : " off" );
148+ }
149+ } catch (const std::exception &e) {
150+ spdlog::error (" Exception while changing matrix status: {}" , e.what ());
151+ }
152+ };
153+
154+ if (waitForCompletion) {
155+ // Synchronous call for shutdown scenarios
156+ task ();
157+ } else {
158+ // Asynchronous call for normal operation
159+ std::thread (task).detach ();
160+ }
112161}
113162
114163// ---- Tray setup ----
@@ -162,6 +211,12 @@ int run_app(int argc, char *argv[]) {
162211 plugin->load_config (cfg->getPluginSetting (plName));
163212 }
164213
214+ // Store shutdown configuration in global variables for signal handlers
215+ General &generalCfgRef = cfg->getGeneralConfig ();
216+ g_shutdown_hostname = generalCfgRef.getHostnameCopy ();
217+ g_shutdown_port = generalCfgRef.getPort ();
218+ g_should_turn_off_on_exit = generalCfgRef.isTurnMatrixOffOnExit ();
219+
165220 static WebsocketClient *ws;
166221 static UpdateChecker::UpdateManager updateManager;
167222 static MatrixVersionChecker::MatrixVersionManager matrixVersionManager;
@@ -548,7 +603,8 @@ int run_app(int argc, char *argv[]) {
548603 auto port = generalCfg.getPort ();
549604 if (generalCfg.isTurnMatrixOffOnExit ()) {
550605 spdlog::info (" Turning Matrix OFF on exit." );
551- change_matrix_status (hostname, port, false );
606+ // Use synchronous call on exit to ensure completion before shutdown
607+ change_matrix_status (hostname, port, false , true );
552608 }
553609 }
554610
0 commit comments