diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 65b133e3..e6a104fc 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "cli.h" #include "ResourceManager.h" #include "ProfileManager.h" #include "LogManager.h" @@ -82,6 +83,7 @@ ResourceManager::ResourceManager() detection_percent = 100; detection_string = ""; detection_is_required = false; + InitThread = nullptr; DetectDevicesThread = nullptr; dynamic_detectors_processed = false; @@ -168,6 +170,13 @@ ResourceManager::ResourceManager() ResourceManager::~ResourceManager() { Cleanup(); + + if(InitThread) + { + DetectDevicesThread->join(); + delete DetectDevicesThread; + DetectDevicesThread = nullptr; + } } void ResourceManager::RegisterI2CBus(i2c_smbus_interface *bus) @@ -642,6 +651,76 @@ void ResourceManager::UnregisterNetworkClient(NetworkClient* network_client) UpdateDeviceList(); } + +/******************************************************************************************\ +* * +* AttemptLocalConnection * +* * +* Attempts an SDK connection to the local server. Returns true if success * +* * +\******************************************************************************************/ + +bool ResourceManager::AttemptLocalConnection() +{ + detection_percent = 0; + detection_string = "Attempting local server connection..."; + DetectionProgressChanged(); + + LOG_DEBUG("[ResourceManager] Attempting server connection..."); + + bool success = false; + + NetworkClient * client = new NetworkClient(ResourceManager::get()->GetRGBControllers()); + + std::string titleString = "OpenRGB "; + titleString.append(VERSION_STRING); + + client->SetName(titleString.c_str()); + client->StartClient(); + + for(int timeout = 0; timeout < 10; timeout++) + { + if(client->GetConnected()) + { + break; + } + std::this_thread::sleep_for(5ms); + } + + if(!client->GetConnected()) + { + LOG_TRACE("[main] Client failed to connect"); + client->StopClient(); + LOG_TRACE("[main] Client stopped"); + + delete client; + + client = NULL; + } + else + { + ResourceManager::get()->RegisterNetworkClient(client); + LOG_TRACE("[main] Registered network client"); + + success = true; + + /*-----------------------------------------------------*\ + | Wait up to 5 seconds for the client connection to | + | retrieve all controllers | + \*-----------------------------------------------------*/ + for(int timeout = 0; timeout < 1000; timeout++) + { + if(client->GetOnline()) + { + break; + } + std::this_thread::sleep_for(5ms); + } + } + + return success; +} + std::vector& ResourceManager::GetClients() { return(clients); @@ -744,7 +823,12 @@ void ResourceManager::ProcessDynamicDetectors() dynamic_detectors_processed = true; } -void ResourceManager::DetectDevices() +/*-----------------------------------------------------*\ +| Handle ALL pre-detection routines | +| The system should be ready to start a detection thread| +| (returns false if detection can not proceed) | +\*-----------------------------------------------------*/ +bool ResourceManager::ProcessPreDetection() { /*-----------------------------------------------------*\ | Process pre-detection hooks | @@ -773,7 +857,6 @@ void ResourceManager::DetectDevices() | Update the detector settings | \*-----------------------------------------------------*/ UpdateDetectorSettings(); - if(detection_enabled) { /*-------------------------------------------------*\ @@ -781,7 +864,7 @@ void ResourceManager::DetectDevices() \*-------------------------------------------------*/ if(detection_is_required.load()) { - return; + return false; } /*-------------------------------------------------*\ @@ -808,6 +891,16 @@ void ResourceManager::DetectDevices() | Start the device detection thread | \*-------------------------------------------------*/ detection_is_required = true; + + return true; + } + return false; +} + +void ResourceManager::DetectDevices() +{ + if(ProcessPreDetection()) + { DetectDevicesThread = new std::thread(&ResourceManager::DetectDevicesThreadFunction, this); /*-------------------------------------------------*\ @@ -816,24 +909,37 @@ void ResourceManager::DetectDevices() \*-------------------------------------------------*/ std::this_thread::sleep_for(1ms); } - else - { - /*-------------------------------------------------*\ - | Signal that detection is complete | - \*-------------------------------------------------*/ - detection_percent = 100; - DetectionProgressChanged(); - /*-----------------------------------------------------*\ - | Call detection end callbacks | - \*-----------------------------------------------------*/ - for(unsigned int callback_idx = 0; callback_idx < DetectionEndCallbacks.size(); callback_idx++) - { - DetectionEndCallbacks[callback_idx](DetectionEndCallbackArgs[callback_idx]); - } + if(!detection_enabled) + { + ProcessPostDetection(); } } +void ResourceManager::ProcessPostDetection() +{ + /*-------------------------------------------------*\ + | Signal that detection is complete | + \*-------------------------------------------------*/ + detection_percent = 100; + DetectionProgressChanged(); + + LOG_INFO("[ResourceManager] Calling Post-detection callbacks"); + /*-----------------------------------------------------*\ + | Call detection end callbacks | + \*-----------------------------------------------------*/ + for(unsigned int callback_idx = 0; callback_idx < DetectionEndCallbacks.size(); callback_idx++) + { + DetectionEndCallbacks[callback_idx](DetectionEndCallbackArgs[callback_idx]); + } + + detection_is_required = false; + + LOG_INFO("------------------------------------------------------"); + LOG_INFO("| Detection completed |"); + LOG_INFO("------------------------------------------------------"); +} + void ResourceManager::DisableDetection() { detection_enabled = false; @@ -1379,26 +1485,10 @@ void ResourceManager::DetectDevicesThreadFunction() | Make sure that when the detection is done, | | progress bar is set to 100% | \*-------------------------------------------------*/ - detection_is_required = false; - detection_percent = 100; - detection_string = ""; - - DetectionProgressChanged(); + ProcessPostDetection(); DetectDeviceMutex.unlock(); - /*-----------------------------------------------------*\ - | Call detection end callbacks | - \*-----------------------------------------------------*/ - for(unsigned int callback_idx = 0; callback_idx < DetectionEndCallbacks.size(); callback_idx++) - { - DetectionEndCallbacks[callback_idx](DetectionEndCallbackArgs[callback_idx]); - } - - LOG_INFO("------------------------------------------------------"); - LOG_INFO("| Detection completed |"); - LOG_INFO("------------------------------------------------------"); - #ifdef __linux__ /*-------------------------------------------------*\ | If the udev rules file is not installed, show a | @@ -1471,6 +1561,79 @@ void ResourceManager::StopDeviceDetection() detection_string = "Stopping"; } +void ResourceManager::Initialize(bool tryConnect, bool detectDevices, bool startServer, bool applyPostOptions) +{ + // Cache the parameters + // TODO: Possibly cache them in the CLI file somewhere + tryAutoConnect = tryConnect; + detection_enabled = detectDevices; + start_server = startServer; + apply_post_options = applyPostOptions; + + InitThread = new std::thread(&ResourceManager::InitThreadFunction, this); +} + +void ResourceManager::InitThreadFunction() +{ + if(tryAutoConnect) + { + detection_percent = 0; + detection_string = "Attempting server connection..."; + DetectionProgressChanged(); + + // Disable detection if a local server was found + if(AttemptLocalConnection()) + { + DisableDetection(); + } + else + { + LOG_DEBUG("[ResourceManager] Local OpenRGB server connected, running in client mode"); + } + tryAutoConnect = false; + } + + /*---------------------------------------------------------*\ + | Perform actual detection | + | Done in the same thread (InitThread), as we need to wait | + | for completion anyway | + \*---------------------------------------------------------*/ + if(detection_enabled) + { + LOG_DEBUG("[ResourceManager] Running standalone"); + if(ProcessPreDetection()) + { + DetectDevicesThreadFunction(); + } + } + else + { + ProcessPostDetection(); + } + + if(start_server) + { + detection_percent = 100; + detection_string = "Starting server"; + DetectionProgressChanged(); + + GetServer()->StartServer(); + if(!GetServer()->GetOnline()) + { + LOG_DEBUG("[ResourceManager] Server failed to start"); + } + } + + /*---------------------------------------------------------*\ + | Process command line arguments after detection only if the| + | pre-detection parsing indicated it should be run | + \*---------------------------------------------------------*/ + if(apply_post_options) + { + cli_post_detection(); + } +} + void ResourceManager::UpdateDetectorSettings() { json detector_settings; diff --git a/ResourceManager.h b/ResourceManager.h index 581b5a36..970fcc5f 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -191,13 +191,15 @@ public: void SetConfigurationDirectory(const filesystem::path &directory); - void ProcessPreDetectionHooks(); - void ProcessDynamicDetectors(); + void ProcessPreDetectionHooks(); // Consider making private + void ProcessDynamicDetectors(); // Consider making private void UpdateDeviceList(); void DeviceListChanged(); void DetectionProgressChanged(); void I2CBusListChanged(); + void Initialize(bool tryConnect, bool detectDevices, bool startServer, bool applyPostOptions); + void Cleanup(); void DetectDevices(); @@ -212,17 +214,36 @@ private: void DetectDevicesThreadFunction(); void UpdateDetectorSettings(); void SetupConfigurationDirectory(); + bool AttemptLocalConnection(); + void InitThreadFunction(); + bool ProcessPreDetection(); + void ProcessPostDetection(); /*-------------------------------------------------------------------------------------*\ | Static pointer to shared instance of ResourceManager | \*-------------------------------------------------------------------------------------*/ static ResourceManager* instance; + /*-------------------------------------------------------------------------------------*\ + | Auto connection permitting flag | + \*-------------------------------------------------------------------------------------*/ + bool tryAutoConnect; + /*-------------------------------------------------------------------------------------*\ | Detection enabled flag | \*-------------------------------------------------------------------------------------*/ bool detection_enabled; + /*-------------------------------------------------------------------------------------*\ + | Auto connection permitting flag | + \*-------------------------------------------------------------------------------------*/ + bool start_server; + + /*-------------------------------------------------------------------------------------*\ + | Auto connection permitting flag | + \*-------------------------------------------------------------------------------------*/ + bool apply_post_options; + /*-------------------------------------------------------------------------------------*\ | Profile Manager | \*-------------------------------------------------------------------------------------*/ @@ -275,7 +296,8 @@ private: /*-------------------------------------------------------------------------------------*\ | Detection Thread and Detection State | \*-------------------------------------------------------------------------------------*/ - std::thread * DetectDevicesThread; + std::thread * DetectDevicesThread; // Used for rescan + std::thread * InitThread; // Used for initial scan, initial network scan, server startup std::mutex DetectDeviceMutex; std::atomic detection_is_required; diff --git a/cli.cpp b/cli.cpp index 4683b730..16f1a0a8 100644 --- a/cli.cpp +++ b/cli.cpp @@ -38,6 +38,9 @@ static std::string profile_save_filename = ""; const unsigned int brightness_percentage = 100; const unsigned int speed_percentage = 100; +static int preserve_argc = 0; +static char** preserve_argv = nullptr; + enum { RET_FLAG_PRINT_HELP = 1, @@ -889,7 +892,7 @@ bool OptionSaveProfile(std::string argument) return(true); } -int ProcessOptions(int argc, char* argv[], Options* options, std::vector& rgb_controllers) +int ProcessOptions(Options* options, std::vector& rgb_controllers) { unsigned int ret_flags = 0; int arg_index = 1; @@ -903,18 +906,18 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vector #include #include +#include "cli.h" #include "ResourceManager.h" #include "NetworkClient.h" #include "NetworkServer.h" @@ -32,24 +33,6 @@ io_connect_t macUSPCIO_driver_connection; using namespace std::chrono_literals; -/*-------------------------------------------------------------*\ -| Command line functionality and return flags | -\*-------------------------------------------------------------*/ -extern unsigned int cli_pre_detection(int argc, char *argv[]); -extern unsigned int cli_post_detection(int argc, char *argv[]); - -enum -{ - RET_FLAG_PRINT_HELP = 1, - RET_FLAG_START_GUI = 2, - RET_FLAG_I2C_TOOLS = 4, - RET_FLAG_START_MINIMIZED = 8, - RET_FLAG_NO_DETECT = 16, - RET_FLAG_CLI_POST_DETECTION = 32, - RET_FLAG_START_SERVER = 64, - RET_FLAG_NO_AUTO_CONNECT = 128, -}; - /******************************************************************************************\ * * * InitializeTimerResolution (Win32) * @@ -95,66 +78,6 @@ void WaitWhileServerOnline(NetworkServer* srv) }; } -/******************************************************************************************\ -* * -* AttemptLocalConnection * -* * -* Attempts an SDK connection to the local server. Returns true if success * -* * -\******************************************************************************************/ - -bool AttemptLocalConnection() -{ - bool success = false; - - NetworkClient * client = new NetworkClient(ResourceManager::get()->GetRGBControllers()); - - std::string titleString = "OpenRGB "; - titleString.append(VERSION_STRING); - - client->SetName(titleString.c_str()); - client->StartClient(); - - for(int timeout = 0; timeout < 10; timeout++) - { - if(client->GetConnected()) - { - break; - } - std::this_thread::sleep_for(5ms); - } - - if(!client->GetConnected()) - { - client->StopClient(); - - delete client; - - client = NULL; - } - else - { - ResourceManager::get()->RegisterNetworkClient(client); - - success = true; - - /*-----------------------------------------------------*\ - | Wait up to 5 seconds for the client connection to | - | retrieve all controllers | - \*-----------------------------------------------------*/ - for(int timeout = 0; timeout < 1000; timeout++) - { - if(client->GetOnline()) - { - break; - } - std::this_thread::sleep_for(5ms); - } - } - - return success; -} - /******************************************************************************************\ * * * Install SMBus Driver WinRing0, If not already installed (Win32) * @@ -279,61 +202,11 @@ int main(int argc, char* argv[]) \*---------------------------------------------------------*/ unsigned int ret_flags = cli_pre_detection(argc, argv); - /*---------------------------------------------------------*\ - | Perform local connection and/or hardware detection if not | - | disabled from CLI | - \*---------------------------------------------------------*/ - if(!(ret_flags & RET_FLAG_NO_AUTO_CONNECT)) - { - printf("Attempting to connect to local OpenRGB server.\r\n"); - - if(!AttemptLocalConnection()) - { - printf("Local OpenRGB server unavailable.\r\n"); - } - else - { - printf("Local OpenRGB server connected, running in client mode\r\n"); - - ResourceManager::get()->DisableDetection(); - } - } - - /*---------------------------------------------------------*\ - | Perform hardware detection if not disabled from CLI | - \*---------------------------------------------------------*/ - if(!(ret_flags & RET_FLAG_NO_DETECT)) - { - if(ResourceManager::get()->GetDetectionEnabled()) - { - printf("Running standalone.\r\n"); - } - - ResourceManager::get()->DetectDevices(); - } - - /*---------------------------------------------------------*\ - | Start the server if requested from CLI (this must be done | - | after attempting local connection!) | - \*---------------------------------------------------------*/ - if(ret_flags & RET_FLAG_START_SERVER) - { - ResourceManager::get()->GetServer()->StartServer(); - - if(!ResourceManager::get()->GetServer()->GetOnline()) - { - printf("Server failed to start\r\n"); - } - } - - /*---------------------------------------------------------*\ - | Process command line arguments after detection only if the| - | pre-detection parsing indicated it should be run | - \*---------------------------------------------------------*/ - if(ret_flags & RET_FLAG_CLI_POST_DETECTION) - { - ret_flags |= cli_post_detection(argc, argv); - } + ResourceManager::get()->Initialize( + !(ret_flags & RET_FLAG_NO_AUTO_CONNECT), + !(ret_flags & RET_FLAG_NO_DETECT), + ret_flags & RET_FLAG_START_SERVER, + ret_flags & RET_FLAG_CLI_POST_DETECTION); /*---------------------------------------------------------*\ | If the command line parser indicates that the GUI should | @@ -342,14 +215,17 @@ int main(int argc, char* argv[]) \*---------------------------------------------------------*/ if(ret_flags & RET_FLAG_START_GUI) { + LOG_TRACE("[main] initializing GUI"); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); QGuiApplication::setDesktopFileName("org.openrgb.OpenRGB"); + LOG_TRACE("[main] QApplication created"); /*---------------------------------------------------------*\ | Main UI widget | \*---------------------------------------------------------*/ Ui::OpenRGBDialog2 dlg; + LOG_TRACE("[main] Dialog created"); if(ret_flags & RET_FLAG_I2C_TOOLS) { @@ -370,6 +246,7 @@ int main(int argc, char* argv[]) dlg.show(); } + LOG_TRACE("[main] Ready to exec() the dialog"); return a.exec(); } else diff --git a/qt/OpenRGBDialog2/OpenRGBDialog2.cpp b/qt/OpenRGBDialog2/OpenRGBDialog2.cpp index c75cac5e..f4addfd3 100644 --- a/qt/OpenRGBDialog2/OpenRGBDialog2.cpp +++ b/qt/OpenRGBDialog2/OpenRGBDialog2.cpp @@ -433,7 +433,6 @@ OpenRGBDialog2::OpenRGBDialog2(QWidget *parent) : QMainWindow(parent), ui(new Op plugin_manager = new PluginManager(); plugin_manager->RegisterAddPluginCallback(&CreatePluginCallback, this); plugin_manager->RegisterRemovePluginCallback(&DeletePluginCallback, this); - plugin_manager->ScanAndLoadPlugins(); /*-----------------------------------------------------*\ | Add the Plugins page | @@ -1448,10 +1447,19 @@ void OpenRGBDialog2::onDetectionProgressUpdated() void OpenRGBDialog2::onDetectionEnded() { - /*-----------------------------------------------------*\ - | Detect unconfigured zones and prompt for resizing | - \*-----------------------------------------------------*/ + /*-------------------------------------------------------*\ + | Detect unconfigured zones and prompt for resizing | + \*-------------------------------------------------------*/ OpenRGBZonesBulkResizer::RunChecks(this); + + /*-------------------------------------------------------*\ + | Load plugins after the first detection (ONLY the first) | + \*-------------------------------------------------------*/ + if(!plugins_loaded) + { + plugin_manager->ScanAndLoadPlugins(); + plugins_loaded = true; + } } void OpenRGBDialog2::on_SetAllDevices(unsigned char red, unsigned char green, unsigned char blue) diff --git a/qt/OpenRGBDialog2/OpenRGBDialog2.h b/qt/OpenRGBDialog2/OpenRGBDialog2.h index 718b3b6d..582e637a 100644 --- a/qt/OpenRGBDialog2/OpenRGBDialog2.h +++ b/qt/OpenRGBDialog2/OpenRGBDialog2.h @@ -108,6 +108,7 @@ private: OpenRGBNanoleafSettingsPage *NanoleafSettingsPage; bool ShowI2CTools = false; + bool plugins_loaded = false; /*-------------------------------------*\ | System tray icon and menu | @@ -188,5 +189,4 @@ private slots: void on_InformationTabBar_currentChanged(int); void on_DevicesTabBar_currentChanged(int); void on_SettingsTabBar_currentChanged(int); - };