From fcb3ea50d313068bb64afe7e2fc6d2d18a774474 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Tue, 10 Feb 2026 21:29:19 +0100 Subject: [PATCH] Add QTimer::singleShot() wrappers to display startup dialogs on macOS --- lib/advanced-scene-switcher.cpp | 12 +-------- lib/utils/backup.cpp | 45 ++++++++++++++++++++++++++++++--- lib/utils/backup.hpp | 4 +-- lib/utils/crash-handler.cpp | 42 +++++++++++++++++++++--------- lib/utils/non-modal-dialog.cpp | 2 -- plugins/twitch/twitch-tab.cpp | 27 +++++++++++++++++++- 6 files changed, 101 insertions(+), 31 deletions(-) diff --git a/lib/advanced-scene-switcher.cpp b/lib/advanced-scene-switcher.cpp index 82f40ee1..52a93925 100644 --- a/lib/advanced-scene-switcher.cpp +++ b/lib/advanced-scene-switcher.cpp @@ -192,17 +192,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) switcher->m.lock(); if (switcher->VersionChanged(data, g_GIT_SHA1)) { - auto json = obs_data_get_json(data); - static QString jsonQString = json ? json : ""; - std::thread t([]() { - obs_queue_task( - OBS_TASK_UI, - [](void *) { - AskForBackup(jsonQString); - }, - nullptr, false); - }); - t.detach(); + AskForBackup(data); } switcher->LoadSettings(data); diff --git a/lib/utils/backup.cpp b/lib/utils/backup.cpp index 38bf2fd3..7cfe14d0 100644 --- a/lib/utils/backup.cpp +++ b/lib/utils/backup.cpp @@ -8,13 +8,18 @@ #include #include -#include -#include #include +#include +#include +#include +#include + +#include + namespace advss { -void AskForBackup(const QString &json) +static void showBackupDialogs(const QString &json) { const bool backupWasConfirmed = DisplayMessage( obs_module_text("AdvSceneSwitcher.askBackup"), true, false); @@ -42,6 +47,40 @@ void AskForBackup(const QString &json) out << json; } +void AskForBackup(obs_data_t *settings) +{ + // This function is called while the plugin settings are being loaded. + // Blocking at this stage can cause issues such as OBS failing to start + // or crashing. + // Therefore, we ask the user whether they want to back up the settings + // asynchronously. + // + // On macOS, an additional QTimer::singleShot wrapper is required for + // this to work correctly. + + auto json = obs_data_get_json(settings); + static QString jsonQString = json ? json : ""; + + static const auto askForBackupWrapper = [](void *) { +#ifdef __APPLE__ + QTimer::singleShot(0, + static_cast( + obs_frontend_get_main_window()), + []() { +#endif + showBackupDialogs(jsonQString); +#ifdef __APPLE__ + }); +#endif + }; + + std::thread t([]() { + obs_queue_task(OBS_TASK_UI, askForBackupWrapper, nullptr, + false); + }); + t.detach(); +} + void BackupSettingsOfCurrentVersion() { auto sceneCollectionName = obs_frontend_get_current_scene_collection(); diff --git a/lib/utils/backup.hpp b/lib/utils/backup.hpp index e5448d39..32cbf2e2 100644 --- a/lib/utils/backup.hpp +++ b/lib/utils/backup.hpp @@ -1,9 +1,9 @@ #pragma once -#include +#include namespace advss { -void AskForBackup(const QString &json); +void AskForBackup(obs_data_t *settings); void BackupSettingsOfCurrentVersion(); } // namespace advss diff --git a/lib/utils/crash-handler.cpp b/lib/utils/crash-handler.cpp index 5846be19..f88439c8 100644 --- a/lib/utils/crash-handler.cpp +++ b/lib/utils/crash-handler.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include @@ -104,10 +106,13 @@ static bool wasUncleanShutdown() return true; } -static bool askForStartupSkip() +static void askForStartupSkip() { - return DisplayMessage(obs_module_text("AdvSceneSwitcher.crashDetected"), - true, false); + bool skipStart = DisplayMessage( + obs_module_text("AdvSceneSwitcher.crashDetected"), true, false); + if (!skipStart) { + StartPlugin(); + } } bool ShouldSkipPluginStartOnUncleanShutdown() @@ -116,16 +121,29 @@ bool ShouldSkipPluginStartOnUncleanShutdown() return false; } + // This function is called while the plugin settings are being loaded. + // Blocking at this stage can cause issues such as OBS failing to start + // or crashing. + // Therefore, we ask the user whether they want to start the plugin + // asynchronously. + // + // On macOS, an additional QTimer::singleShot wrapper is required for + // this to work correctly. + static const auto showDialogWrapper = [](void *) { +#ifdef __APPLE__ + QTimer::singleShot(0, + static_cast( + obs_frontend_get_main_window()), + []() { +#endif + askForStartupSkip(); +#ifdef __APPLE__ + }); +#endif + }; + std::thread t([]() { - obs_queue_task( - OBS_TASK_UI, - [](void *) { - const bool skipStart = askForStartupSkip(); - if (!skipStart) { - StartPlugin(); - } - }, - nullptr, false); + obs_queue_task(OBS_TASK_UI, showDialogWrapper, nullptr, false); }); t.detach(); diff --git a/lib/utils/non-modal-dialog.cpp b/lib/utils/non-modal-dialog.cpp index 98ebd09e..8f0df6f8 100644 --- a/lib/utils/non-modal-dialog.cpp +++ b/lib/utils/non-modal-dialog.cpp @@ -1,14 +1,12 @@ #include "non-modal-dialog.hpp" #include "obs-module-helper.hpp" -#include #include #include #include #include #include #include -#include namespace advss { diff --git a/plugins/twitch/twitch-tab.cpp b/plugins/twitch/twitch-tab.cpp index d7cfcc85..a8f935a5 100644 --- a/plugins/twitch/twitch-tab.cpp +++ b/plugins/twitch/twitch-tab.cpp @@ -7,7 +7,11 @@ #include "ui-helpers.hpp" #include +#include #include +#include + +#include namespace advss { @@ -38,8 +42,29 @@ static bool setup() } }; + // This function is called while the plugin settings are being loaded. + // Blocking at this stage can cause issues such as OBS failing to start + // or crashing. + // Therefore, we ask the user whether they want to update their Twitch + // connections asynchronously. + // + // On macOS, an additional QTimer::singleShot wrapper is required for + // this to work correctly. AddLoadStep([](obs_data_t *) { - AddPostLoadStep([]() { showInvalidWarnings(); }); + AddPostLoadStep([]() { +#ifdef __APPLE__ + QTimer::singleShot( + 0, + static_cast( + obs_frontend_get_main_window()), + []() { +#endif + showInvalidWarnings(); + +#ifdef __APPLE__ + }); +#endif + }); }); return true;