Files
obs-studio/frontend/widgets/OBSBasic_Updater.cpp
Warchamp7 14572498dc frontend: Adjust application shutdown logic
Improves app shutdown in a few ways, including separating out different
pieces of the OBSBasic close handler into their own functions.

Removes the crash handler sentinel earlier when the main window is closed,
preventing unclean shutdown warnings when a plugin causes issues. While not
ideal, the dialog is not useful when we cannot specify which plugin caused the
problem.

Increases shutdown priority of the main application so that when OBS interrupts
the session ending, CEF is not closed at the same time. This fixes a crash.

Additional safeguards and event handling to try to ensure a smoother shutdown.
2025-12-01 16:40:34 -05:00

239 lines
6.3 KiB
C++

/******************************************************************************
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
Zachary Lund <admin@computerquip.com>
Philippe Groarke <philippe.groarke@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "OBSBasic.hpp"
#include <dialogs/OBSWhatsNew.hpp>
#ifdef _WIN32
#include <utility/AutoUpdateThread.hpp>
#endif
#ifdef ENABLE_SPARKLE_UPDATER
#include <utility/MacUpdateThread.hpp>
#include <utility/OBSSparkle.hpp>
#endif
#if defined(_WIN32) || defined(WHATSNEW_ENABLED)
#include <utility/WhatsNewBrowserInitThread.hpp>
#include <utility/models/whatsnew.hpp>
#endif
#ifdef BROWSER_AVAILABLE
#include <browser-panel.hpp>
#endif
#include <qt-wrappers.hpp>
#ifdef _WIN32
#define UPDATE_CHECK_INTERVAL (60 * 60 * 24 * 4) /* 4 days */
#endif
struct QCef;
struct QCefCookieManager;
extern QCef *cef;
extern QCefCookieManager *panel_cookies;
using namespace std;
namespace {
QPointer<OBSWhatsNew> obsWhatsNew;
template<typename OBSRef> struct SignalContainer {
OBSRef ref;
vector<shared_ptr<OBSSignal>> handlers;
};
} // namespace
void OBSBasic::ReceivedIntroJson(const QString &text)
{
#ifdef WHATSNEW_ENABLED
if (isClosing()) {
return;
}
WhatsNewList items;
try {
nlohmann::json json = nlohmann::json::parse(text.toStdString());
items = json.get<WhatsNewList>();
} catch (nlohmann::json::exception &e) {
blog(LOG_WARNING, "Parsing whatsnew data failed: %s", e.what());
return;
}
std::string info_url;
int info_increment = -1;
/* check to see if there's an info page for this version */
for (const WhatsNewItem &item : items) {
if (item.os) {
WhatsNewPlatforms platforms = *item.os;
#ifdef _WIN32
if (!platforms.windows)
continue;
#elif defined(__APPLE__)
if (!platforms.macos)
continue;
#else
if (!platforms.linux)
continue;
#endif
}
int major = 0;
int minor = 0;
sscanf(item.version.c_str(), "%d.%d", &major, &minor);
if (major == LIBOBS_API_MAJOR_VER && minor == LIBOBS_API_MINOR_VER &&
item.RC == OBS_RELEASE_CANDIDATE && item.Beta == OBS_BETA) {
info_url = item.url;
info_increment = item.increment;
}
}
/* this version was not found, or no info for this version */
if (info_increment == -1) {
return;
}
#if OBS_RELEASE_CANDIDATE > 0
constexpr const char *lastInfoVersion = "InfoLastRCVersion";
#elif OBS_BETA > 0
constexpr const char *lastInfoVersion = "InfoLastBetaVersion";
#else
constexpr const char *lastInfoVersion = "InfoLastVersion";
#endif
constexpr uint64_t currentVersion = (uint64_t)LIBOBS_API_VER << 16ULL | OBS_RELEASE_CANDIDATE << 8ULL |
OBS_BETA;
uint64_t lastVersion = config_get_uint(App()->GetAppConfig(), "General", lastInfoVersion);
int current_version_increment = -1;
if ((lastVersion & ~0xFFFF0000ULL) < (currentVersion & ~0xFFFF0000ULL)) {
config_set_int(App()->GetAppConfig(), "General", "InfoIncrement", -1);
config_set_uint(App()->GetAppConfig(), "General", lastInfoVersion, currentVersion);
} else {
current_version_increment = config_get_int(App()->GetAppConfig(), "General", "InfoIncrement");
}
if (info_increment <= current_version_increment) {
return;
}
config_set_int(App()->GetAppConfig(), "General", "InfoIncrement", info_increment);
config_save_safe(App()->GetAppConfig(), "tmp", nullptr);
cef->init_browser();
WhatsNewBrowserInitThread *wnbit = new WhatsNewBrowserInitThread(QT_UTF8(info_url.c_str()));
connect(wnbit, &WhatsNewBrowserInitThread::Result, this, &OBSBasic::ShowWhatsNew, Qt::QueuedConnection);
whatsNewInitThread.reset(wnbit);
whatsNewInitThread->start();
#else
UNUSED_PARAMETER(text);
#endif
}
void OBSBasic::ShowWhatsNew(const QString &url)
{
#ifdef BROWSER_AVAILABLE
if (isClosing()) {
return;
}
if (obsWhatsNew) {
obsWhatsNew->close();
}
obsWhatsNew = new OBSWhatsNew(this, QT_TO_UTF8(url));
#else
UNUSED_PARAMETER(url);
#endif
}
void OBSBasic::TimedCheckForUpdates()
{
if (App()->IsUpdaterDisabled())
return;
if (!config_get_bool(App()->GetAppConfig(), "General", "EnableAutoUpdates"))
return;
#if defined(ENABLE_SPARKLE_UPDATER)
CheckForUpdates(false);
#elif _WIN32
long long lastUpdate = config_get_int(App()->GetAppConfig(), "General", "LastUpdateCheck");
uint32_t lastVersion = config_get_int(App()->GetAppConfig(), "General", "LastVersion");
if (lastVersion < LIBOBS_API_VER) {
lastUpdate = 0;
config_set_int(App()->GetAppConfig(), "General", "LastUpdateCheck", 0);
}
long long t = (long long)time(nullptr);
long long secs = t - lastUpdate;
if (secs > UPDATE_CHECK_INTERVAL)
CheckForUpdates(false);
#endif
}
void OBSBasic::CheckForUpdates(bool manualUpdate)
{
#if _WIN32
ui->actionCheckForUpdates->setEnabled(false);
ui->actionRepair->setEnabled(false);
if (updateCheckThread && updateCheckThread->isRunning())
return;
updateCheckThread.reset(new AutoUpdateThread(manualUpdate));
updateCheckThread->start();
#elif defined(ENABLE_SPARKLE_UPDATER)
ui->actionCheckForUpdates->setEnabled(false);
if (updateCheckThread && updateCheckThread->isRunning())
return;
MacUpdateThread *mut = new MacUpdateThread(manualUpdate);
connect(mut, &MacUpdateThread::Result, this, &OBSBasic::MacBranchesFetched, Qt::QueuedConnection);
updateCheckThread.reset(mut);
updateCheckThread->start();
#else
UNUSED_PARAMETER(manualUpdate);
#endif
}
void OBSBasic::MacBranchesFetched(const QString &branch, bool manualUpdate)
{
#ifdef ENABLE_SPARKLE_UPDATER
static OBSSparkle *updater;
if (!updater) {
updater = new OBSSparkle(QT_TO_UTF8(branch), ui->actionCheckForUpdates);
return;
}
updater->setBranch(QT_TO_UTF8(branch));
updater->checkForUpdates(manualUpdate);
#else
UNUSED_PARAMETER(branch);
UNUSED_PARAMETER(manualUpdate);
#endif
}