Skip to content

Commit 6b2debe

Browse files
committed
frontend: Adjust application shutdown logic
1 parent ea7078b commit 6b2debe

File tree

7 files changed

+347
-134
lines changed

7 files changed

+347
-134
lines changed

frontend/OBSApp.cpp

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,8 @@
4242
#include <QFile>
4343
#endif
4444

45-
#ifdef _WIN32
4645
#include <QSessionManager>
47-
#else
46+
#ifndef _WIN32
4847
#include <QSocketNotifier>
4948
#endif
5049

@@ -78,6 +77,7 @@ extern string opt_starting_profile;
7877

7978
#ifndef _WIN32
8079
int OBSApp::sigintFd[2];
80+
int OBSApp::sigtermFd[2];
8181
#endif
8282

8383
// GPU hint exports for AMD/NVIDIA laptops
@@ -280,6 +280,54 @@ string CurrentDateTimeString()
280280
return buf;
281281
}
282282

283+
bool OBSNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
284+
{
285+
if (eventType == "windows_generic_MSG") {
286+
#ifdef _WIN32
287+
MSG *msg = static_cast<MSG *>(message);
288+
289+
OBSBasic *main = OBSBasic::Get();
290+
if (!main) {
291+
return false;
292+
}
293+
294+
switch (msg->message) {
295+
case WM_QUERYENDSESSION:
296+
main->saveAll();
297+
if (msg->lParam == ENDSESSION_CRITICAL) {
298+
break;
299+
}
300+
301+
if (main->shouldPromptForClose()) {
302+
*result = FALSE;
303+
return true;
304+
}
305+
306+
return false;
307+
case WM_ENDSESSION:
308+
if (msg->wParam == TRUE) {
309+
// Session is ending, start closing the main window now with no checks or prompts.
310+
main->closeWindow();
311+
} else {
312+
/* Session is no longer ending. If OBS is still open, odds are it is what held
313+
* up the session end due to it's higher than default priority. We call the
314+
* close method to trigger the confirmation window flow. We do this after the fact
315+
* to avoid blocking the main window event loop prior to this message.
316+
* Otherwise OBS is already gone and invoking this does nothing */
317+
main->close();
318+
}
319+
320+
return true;
321+
}
322+
#else
323+
UNUSED_PARAMETER(message);
324+
UNUSED_PARAMETER(result);
325+
#endif
326+
}
327+
328+
return false;
329+
}
330+
283331
#define DEFAULT_LANG "en-US"
284332

285333
bool OBSApp::InitGlobalConfigDefaults()
@@ -868,6 +916,8 @@ OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store)
868916
profilerNameStore(store),
869917
appLaunchUUID_(QUuid::createUuid())
870918
{
919+
installNativeEventFilter(new OBSNativeEventFilter);
920+
871921
/* fix float handling */
872922
#if defined(Q_OS_UNIX)
873923
if (!setlocale(LC_NUMERIC, "C"))
@@ -879,9 +929,14 @@ OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store)
879929
socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd);
880930
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
881931
connect(snInt, &QSocketNotifier::activated, this, &OBSApp::ProcessSigInt);
882-
#else
883-
connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData);
932+
933+
/* Handle SIGTERM */
934+
socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd);
935+
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
936+
connect(snTerm, &QSocketNotifier::activated, this, &OBSApp::ProcessSigTerm);
884937
#endif
938+
connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData, Qt::DirectConnection);
939+
885940
if (multi) {
886941
crashHandler_ = std::make_unique<OBS::CrashHandler>();
887942
} else {
@@ -1229,7 +1284,20 @@ bool OBSApp::OBSInit()
12291284
mainWindow = new OBSBasic();
12301285

12311286
mainWindow->setAttribute(Qt::WA_DeleteOnClose, true);
1232-
connect(mainWindow, &OBSBasic::destroyed, this, &OBSApp::quit);
1287+
1288+
connect(QApplication::instance(), &QApplication::aboutToQuit, this, [this]() {
1289+
crashHandler_->applicationShutdownHandler();
1290+
1291+
/* Ensure OBSMainWindow gets closed */
1292+
if (mainWindow) {
1293+
mainWindow->close();
1294+
delete mainWindow;
1295+
}
1296+
1297+
if (libobs_initialized) {
1298+
applicationShutdown();
1299+
}
1300+
});
12331301

12341302
mainWindow->OBSInit();
12351303

@@ -1748,6 +1816,14 @@ void OBSApp::SigIntSignalHandler(int s)
17481816
char a = 1;
17491817
send(sigintFd[0], &a, sizeof(a), 0);
17501818
}
1819+
1820+
void OBSApp::SigTermSignalHandler(int s)
1821+
{
1822+
UNUSED_PARAMETER(s);
1823+
1824+
char a = 1;
1825+
send(sigtermFd[0], &a, sizeof(a), 0);
1826+
}
17511827
#endif
17521828

17531829
void OBSApp::ProcessSigInt(void)
@@ -1759,20 +1835,39 @@ void OBSApp::ProcessSigInt(void)
17591835
recv(sigintFd[1], &tmp, sizeof(tmp), 0);
17601836

17611837
OBSBasic *main = OBSBasic::Get();
1762-
if (main)
1838+
if (main) {
1839+
main->saveAll();
17631840
main->close();
1841+
}
1842+
#endif
1843+
}
1844+
1845+
void OBSApp::ProcessSigTerm(void)
1846+
{
1847+
#ifndef _WIN32
1848+
char tmp;
1849+
recv(sigtermFd[1], &tmp, sizeof(tmp), 0);
1850+
1851+
OBSBasic *main = OBSBasic::Get();
1852+
if (main) {
1853+
main->saveAll();
1854+
}
1855+
1856+
quit();
17641857
#endif
17651858
}
17661859

1767-
#ifdef _WIN32
17681860
void OBSApp::commitData(QSessionManager &manager)
17691861
{
1770-
if (auto main = App()->GetMainWindow()) {
1771-
QMetaObject::invokeMethod(main, "close", Qt::QueuedConnection);
1772-
manager.cancel();
1862+
OBSBasic *main = OBSBasic::Get();
1863+
if (main) {
1864+
main->saveAll();
1865+
1866+
if (manager.allowsInteraction() && main->shouldPromptForClose()) {
1867+
manager.cancel();
1868+
}
17731869
}
17741870
}
1775-
#endif
17761871

17771872
void OBSApp::applicationShutdown() noexcept
17781873
{
@@ -1784,6 +1879,10 @@ void OBSApp::applicationShutdown() noexcept
17841879
delete snInt;
17851880
close(sigintFd[0]);
17861881
close(sigintFd[1]);
1882+
1883+
delete snTerm;
1884+
close(sigtermFd[0]);
1885+
close(sigtermFd[1]);
17871886
#endif
17881887

17891888
#ifdef __APPLE__

frontend/OBSApp.hpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <util/profiler.hpp>
2626
#include <util/util.hpp>
2727

28+
#include <QAbstractNativeEventFilter>
2829
#include <QApplication>
2930
#include <QPalette>
3031
#include <QPointer>
@@ -58,9 +59,16 @@ struct UpdateBranch {
5859
bool is_visible;
5960
};
6061

62+
class OBSNativeEventFilter : public QAbstractNativeEventFilter {
63+
public:
64+
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result);
65+
};
66+
6167
class OBSApp : public QApplication {
6268
Q_OBJECT
6369

70+
friend class OBSNativeEventFilter;
71+
6472
private:
6573
QUuid appLaunchUUID_;
6674
std::unique_ptr<OBS::CrashHandler> crashHandler_;
@@ -117,12 +125,13 @@ class OBSApp : public QApplication {
117125
#ifndef _WIN32
118126
static int sigintFd[2];
119127
QSocketNotifier *snInt = nullptr;
120-
#else
121-
private slots:
122-
void commitData(QSessionManager &manager);
128+
129+
static int sigtermFd[2];
130+
QSocketNotifier *snTerm = nullptr;
123131
#endif
124132

125133
private slots:
134+
void commitData(QSessionManager &manager);
126135
void addLogLine(int logLevel, const QString &message);
127136
void themeFileChanged(const QString &);
128137
void applicationShutdown() noexcept;
@@ -212,6 +221,7 @@ private slots:
212221
inline void PopUITranslation() { translatorHooks.pop_front(); }
213222
#ifndef _WIN32
214223
static void SigIntSignalHandler(int);
224+
static void SigTermSignalHandler(int);
215225
#endif
216226

217227
void loadAppModules(struct obs_module_failure_info &mfi);
@@ -222,6 +232,7 @@ private slots:
222232
public slots:
223233
void Exec(VoidFunc func);
224234
void ProcessSigInt();
235+
void ProcessSigTerm();
225236

226237
signals:
227238
void logLineAdded(int logLevel, const QString &message);

frontend/docks/OBSDock.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void OBSDock::closeEvent(QCloseEvent *event)
2828
};
2929

3030
bool warned = config_get_bool(App()->GetUserConfig(), "General", "WarnedAboutClosingDocks");
31-
if (!OBSBasic::Get()->Closing() && !warned) {
31+
if (!OBSBasic::Get()->isClosing() && !warned) {
3232
QMetaObject::invokeMethod(App(), "Exec", Qt::QueuedConnection, Q_ARG(VoidFunc, msgBox));
3333
}
3434

frontend/obs-main.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -858,13 +858,22 @@ int main(int argc, char *argv[])
858858
#ifndef _WIN32
859859
signal(SIGPIPE, SIG_IGN);
860860

861-
struct sigaction sig_handler;
861+
struct sigaction sigint_handler;
862862

863-
sig_handler.sa_handler = OBSApp::SigIntSignalHandler;
864-
sigemptyset(&sig_handler.sa_mask);
865-
sig_handler.sa_flags = 0;
863+
sigint_handler.sa_handler = OBSApp::SigIntSignalHandler;
864+
sigemptyset(&sigint_handler.sa_mask);
865+
sigint_handler.sa_flags = 0;
866866

867-
sigaction(SIGINT, &sig_handler, NULL);
867+
sigaction(SIGINT, &sigint_handler, NULL);
868+
869+
struct sigaction sigterm_handler;
870+
871+
sigterm_handler.sa_handler = OBSApp::SigTermSignalHandler;
872+
sigemptyset(&sigterm_handler.sa_mask);
873+
sigterm_handler.sa_flags = 0;
874+
875+
sigaction(SIGTERM, &sigterm_handler, NULL);
876+
sigaction(SIGHUP, &sigterm_handler, NULL);
868877

869878
/* Block SIGPIPE in all threads, this can happen if a thread calls write on
870879
a closed pipe. */
@@ -890,6 +899,14 @@ int main(int argc, char *argv[])
890899
load_debug_privilege();
891900
base_set_crash_handler(main_crash_handler, nullptr);
892901

902+
/* Shutdown priority value is a range from 0 - 4FF with higher values getting first priority.
903+
* 000 - 0FF and 400 - 4FF are reserved system ranges.
904+
* Processes start at shutdown level 0x280 by default.
905+
* We set the main OBS application to a higher priority to ensure it tries to close before
906+
* any subprocesses such as CEF.
907+
*/
908+
SetProcessShutdownParameters(0x300, SHUTDOWN_NORETRY);
909+
893910
const HMODULE hRtwq = LoadLibrary(L"RTWorkQ.dll");
894911
if (hRtwq) {
895912
typedef HRESULT(STDAPICALLTYPE * PFN_RtwqStartup)();

0 commit comments

Comments
 (0)