Implement profile loading on service shutdown

This commit is contained in:
Adam Honse committed 2026-08-17 19:36:05 -05:00
1 parent 2d32510008
commit cf910d2616
6 files changed
+120 -3

No files matched your search

+19 -1
View File
@@ -60,9 +60,13 @@ ProfileManager::ProfileManager(const filesystem::path& config_dir)
profilemanager_settings_schema["resume_profile"]["type"] = "profile";
profilemanager_settings_schema["resume_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load after system resumes from sleep");
profilemanager_settings_schema["service_shutdown_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Service Shutdown");
profilemanager_settings_schema["service_shutdown_profile"]["type"] = "profile";
profilemanager_settings_schema["service_shutdown_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load when the OpenRGB background service shuts down");
profilemanager_settings_schema["service_startup_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Service Startup");
profilemanager_settings_schema["service_startup_profile"]["type"] = "profile";
profilemanager_settings_schema["service_startup_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load when the OpenRGB background service starts");
profilemanager_settings_schema["service_startup_profile"]["description"] = QT_TRANSLATE_NOOP("Settings", "Profile to load when the OpenRGB background service starts up");
profilemanager_settings_schema["suspend_profile"]["title"] = QT_TRANSLATE_NOOP("Settings", "Load Profile on Suspend");
profilemanager_settings_schema["suspend_profile"]["type"] = "profile";
@@ -104,6 +108,15 @@ ProfileManager::ProfileManager(const filesystem::path& config_dir)
new_settings_keys = true;
}
if(!profilemanager_settings.contains("service_shutdown_profile"))
{
json profile;
profile["enabled"] = false;
profile["name"] = "";
profilemanager_settings["service_shutdown_profile"] = profile;
new_settings_keys = true;
}
if(!profilemanager_settings.contains("service_startup_profile"))
{
json profile;
@@ -400,6 +413,11 @@ bool ProfileManager::LoadAutoProfileResume()
return(LoadAutoProfile("resume_profile"));
}
bool ProfileManager::LoadAutoProfileServiceShutdown()
{
return(LoadAutoProfile("service_shutdown_profile"));
}
bool ProfileManager::LoadAutoProfileServiceStartup()
{
return(LoadAutoProfile("service_startup_profile"));
+1
View File
@@ -93,6 +93,7 @@ public:
bool LoadAutoProfileExit();
bool LoadAutoProfileOpen();
bool LoadAutoProfileResume();
bool LoadAutoProfileServiceShutdown();
bool LoadAutoProfileServiceStartup();
bool LoadAutoProfileSuspend();
+41
View File
@@ -838,6 +838,47 @@ void ResourceManager::HandleDetectionComplete()
}
}
void ResourceManager::ServiceShutdown()
{
/*-----------------------------------------------------*\
| Only run service shutdown operations when running as |
| a background service (headless server mode). In GUI |
| mode, the GUI close event handles profile loading. |
\*-----------------------------------------------------*/
if(!start_server || start_gui)
{
return;
}
LOG_INFO("[%s] Service shutting down", RESOURCEMANAGER);
/*-----------------------------------------------------*\
| Wait for any in-progress detection to finish before |
| loading a profile so that the full device list is |
| available. |
\*-----------------------------------------------------*/
WaitForDetection();
/*-----------------------------------------------------*\
| Load the exit profile if one is configured. This |
| runs the same profile mechanism used when the GUI |
| closes, allowing a profile to be applied to |
| controllers before they are closed and deleted during |
| Cleanup(). |
\*-----------------------------------------------------*/
if(profile_manager)
{
if(profile_manager->LoadAutoProfileServiceShutdown())
{
/*---------------------------------------------*\
| Pause briefly to ensure that all profiles |
| are loaded. |
\*---------------------------------------------*/
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
}
}
void ResourceManager::RescanDevices()
{
/*-----------------------------------------------------*\
+5
View File
@@ -141,6 +141,11 @@ public:
void WaitForInitialization();
/*-----------------------------------------------------*\
| Service Shutdown |
\*-----------------------------------------------------*/
void ServiceShutdown();
private:
bool AttemptLocalConnection();
void ClientTeardownThreadFunction();
+39 -1
View File
@@ -23,8 +23,23 @@ io_connect_t macUSPCIO_driver_connection;
#include "macutils.h"
#endif
#include <condition_variable>
#include <mutex>
using namespace std::chrono_literals;
#include <csignal>
static volatile bool service_stop_requested = false;
static std::mutex service_stop_mutex;
static std::condition_variable service_stop_cv;
static void sigHandler(int s)
{
service_stop_requested = true;
service_stop_cv.notify_one();
}
/*---------------------------------------------------------*\
| WaitWhileServerOnline |
| |
@@ -33,9 +48,15 @@ using namespace std::chrono_literals;
\*---------------------------------------------------------*/
void WaitWhileServerOnline(NetworkServer* srv)
{
std::unique_lock<std::mutex> lock(service_stop_mutex);
while(srv->GetOnline())
{
std::this_thread::sleep_for(1s);
if(service_stop_requested)
{
srv->StopServer();
break;
}
service_stop_cv.wait_for(lock, 1s);
};
}
@@ -69,6 +90,16 @@ int main(int argc, char* argv[])
ret_flags & RET_FLAG_CLI_POST_DETECTION,
ret_flags & RET_FLAG_START_GUI);
/*-----------------------------------------------------*\
| If running as a headless server, register signal |
| handler for stopping server |
\*-----------------------------------------------------*/
if((ret_flags & RET_FLAG_START_SERVER) && !(ret_flags & RET_FLAG_START_GUI))
{
std::signal(SIGINT, sigHandler);
std::signal(SIGTERM, sigHandler);
}
/*-----------------------------------------------------*\
| Perform application startup and run the application. |
| This call returns only when the GUI application is |
@@ -89,6 +120,13 @@ int main(int argc, char* argv[])
}
}
/*-----------------------------------------------------*\
| Call ServiceShutdown to allow operations before |
| controllers are closed and deleted. Only runs when |
| running as a background service (headless server). |
\*-----------------------------------------------------*/
ResourceManager::get()->ServiceShutdown();
/*-----------------------------------------------------*\
| Clean up detected devices so destructors can run. |
\*-----------------------------------------------------*/
+15 -1
View File
@@ -10,6 +10,8 @@
\*---------------------------------------------------------*/
#include <algorithm>
#include <condition_variable>
#include <mutex>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
@@ -40,6 +42,8 @@ static SERVICE_STATUS service_status;
static bool started_as_service;
static volatile bool service_stop_requested;
static std::mutex service_stop_mutex;
static std::condition_variable service_stop_cv;
static bool have_console;
static std::mutex service_status_mutex;
@@ -224,6 +228,7 @@ static DWORD WINAPI ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LP
case SERVICE_CONTROL_PRESHUTDOWN:
ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 10000);
service_stop_requested = true;
service_stop_cv.notify_one();
break;
default:
@@ -518,13 +523,15 @@ void InitializeTimerResolutionThreadFunction()
\*---------------------------------------------------------*/
static void WaitWhileServerOnline(NetworkServer* srv)
{
std::unique_lock<std::mutex> lock(service_stop_mutex);
while(srv->GetOnline())
{
std::this_thread::sleep_for(1s);
if(service_stop_requested)
{
srv->StopServer();
break;
}
service_stop_cv.wait_for(lock, 1s);
};
}
@@ -633,6 +640,13 @@ static int common_main(int argc, char* argv[])
}
}
/*-----------------------------------------------------*\
| Call ServiceShutdown to allow operations before |
| controllers are closed and deleted. Only runs when |
| running as a background service (headless server). |
\*-----------------------------------------------------*/
ResourceManager::get()->ServiceShutdown();
/*-----------------------------------------------------*\
| Clean up detected devices so destructors can run. |
\*-----------------------------------------------------*/