Browse Source

UI: Fix crash at render_display while shutdown on macOS

The display context was sometimes created again by a resize event after
destruction from `OBSBasic::closeEvent`. That resulted in the display
context alive until reaching the destructor of the `OBSQTDisplay` class
and caused a crash in `render_display` on macOS. To avoid this, destroy
the display context at the event `SurfaceAboutToBeDestroyed` and let not
create the display context again.
Norihiro Kamae 2 years ago
parent
commit
fd502cbd4d
3 changed files with 44 additions and 5 deletions
  1. 38 0
      UI/qt-display.cpp
  2. 6 1
      UI/qt-display.hpp
  3. 0 4
      UI/window-basic-main.cpp

+ 38 - 0
UI/qt-display.cpp

@@ -13,6 +13,39 @@
 #include <Windows.h>
 #endif
 
+class SurfaceEventFilter : public QObject {
+	OBSQTDisplay *display;
+
+public:
+	SurfaceEventFilter(OBSQTDisplay *src) : display(src) {}
+
+protected:
+	bool eventFilter(QObject *obj, QEvent *event) override
+	{
+		bool result = QObject::eventFilter(obj, event);
+		QPlatformSurfaceEvent *surfaceEvent;
+
+		switch (event->type()) {
+		case QEvent::PlatformSurface:
+			surfaceEvent =
+				static_cast<QPlatformSurfaceEvent *>(event);
+
+			switch (surfaceEvent->surfaceEventType()) {
+			case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
+				display->DestroyDisplay();
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+
+		return result;
+	}
+};
+
 static inline long long color_to_int(const QColor &color)
 {
 	auto shift = [&](unsigned val, int shift) {
@@ -65,6 +98,8 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
 
 	connect(windowHandle(), &QWindow::visibleChanged, windowVisible);
 	connect(windowHandle(), &QWindow::screenChanged, screenChanged);
+
+	windowHandle()->installEventFilter(new SurfaceEventFilter(this));
 }
 
 QColor OBSQTDisplay::GetDisplayBackgroundColor() const
@@ -92,6 +127,9 @@ void OBSQTDisplay::CreateDisplay()
 	if (display)
 		return;
 
+	if (destroying)
+		return;
+
 	if (!windowHandle()->isExposed())
 		return;
 

+ 6 - 1
UI/qt-display.hpp

@@ -12,6 +12,7 @@ class OBSQTDisplay : public QWidget {
 				   SetDisplayBackgroundColor)
 
 	OBSDisplay display;
+	bool destroying = false;
 
 	virtual void paintEvent(QPaintEvent *event) override;
 	virtual void moveEvent(QMoveEvent *event) override;
@@ -38,7 +39,11 @@ public:
 	void SetDisplayBackgroundColor(const QColor &color);
 	void UpdateDisplayBackgroundColor();
 	void CreateDisplay();
-	void DestroyDisplay() { display = nullptr; };
+	void DestroyDisplay()
+	{
+		display = nullptr;
+		destroying = true;
+	};
 
 	void OnMove();
 	void OnDisplayChange();

+ 0 - 4
UI/window-basic-main.cpp

@@ -5154,10 +5154,6 @@ void OBSBasic::closeEvent(QCloseEvent *event)
 
 	delete extraBrowsers;
 
-	ui->preview->DestroyDisplay();
-	if (program)
-		program->DestroyDisplay();
-
 	config_set_string(App()->GlobalConfig(), "BasicWindow", "DockState",
 			  saveState().toBase64().constData());