UI: Don't open settings or close in event subloop

Fixes a crash that can happen if you try to use the settings window
while in an even subloop, or if you try to close OBS while in an event
subloop.  Continually retries (defers) the actions every one second
until the subloop has finished.
This commit is contained in:
jp9000 2019-03-26 22:01:22 -07:00
parent 11c0d6e976
commit 29a1a97392
2 changed files with 37 additions and 0 deletions

View file

@ -19,6 +19,7 @@
#include "obs-app.hpp"
#include <graphics/graphics.h>
#include <util/threading.h>
#include <QWidget>
#include <QLayout>
#include <QMessageBox>
@ -224,6 +225,8 @@ QThread *CreateQThread(std::function<void()> func)
return new QuickThread(func);
}
volatile long insideEventLoop = 0;
void ExecuteFuncSafeBlock(std::function<void()> func)
{
QEventLoop eventLoop;
@ -235,10 +238,12 @@ void ExecuteFuncSafeBlock(std::function<void()> func)
Qt::QueuedConnection);
};
os_atomic_inc_long(&insideEventLoop);
QScopedPointer<QThread> thread(CreateQThread(wait));
thread->start();
eventLoop.exec();
thread->wait();
os_atomic_dec_long(&insideEventLoop);
}
void ExecuteFuncSafeBlockMsgBox(
@ -258,10 +263,12 @@ void ExecuteFuncSafeBlockMsgBox(
QMetaObject::invokeMethod(&dlg, "accept", Qt::QueuedConnection);
};
os_atomic_inc_long(&insideEventLoop);
QScopedPointer<QThread> thread(CreateQThread(wait));
thread->start();
dlg.exec();
thread->wait();
os_atomic_dec_long(&insideEventLoop);
}
static bool enable_message_boxes = false;

View file

@ -98,6 +98,8 @@ struct SignalContainer {
}
extern volatile long insideEventLoop;
Q_DECLARE_METATYPE(OBSScene);
Q_DECLARE_METATYPE(OBSSceneItem);
Q_DECLARE_METATYPE(OBSSource);
@ -3761,6 +3763,15 @@ void OBSBasic::ClearSceneData()
void OBSBasic::closeEvent(QCloseEvent *event)
{
/* Do not close window if inside of a temporary event loop because we
* could be inside of an Auth::LoadUI call. Keep trying once per
* second until we've exit any known sub-loops. */
if (os_atomic_load_long(&insideEventLoop) != 0) {
QTimer::singleShot(1000, this, SLOT(close()));
event->ignore();
return;
}
if (isVisible())
config_set_string(App()->GlobalConfig(),
"BasicWindow", "geometry",
@ -3860,9 +3871,28 @@ void OBSBasic::on_actionRemux_triggered()
void OBSBasic::on_action_Settings_triggered()
{
static bool settings_already_executing = false;
/* Do not load settings window if inside of a temporary event loop
* because we could be inside of an Auth::LoadUI call. Keep trying
* once per second until we've exit any known sub-loops. */
if (os_atomic_load_long(&insideEventLoop) != 0) {
QTimer::singleShot(1000, this,
SLOT(on_action_Settings_triggered()));
return;
}
if (settings_already_executing) {
return;
}
settings_already_executing = true;
OBSBasicSettings settings(this);
settings.exec();
SystemTray(false);
settings_already_executing = false;
}
void OBSBasic::on_actionAdvAudioProperties_triggered()