Browse Source

UI: Fix potential race condition for hover items

The graphics thread should not be accessing any Qt objects that aren't
guaranteed to exist.  Instead, store the currently hovering list/preview
scene items in the preview class.
jp9000 6 years ago
parent
commit
1b8ecae3b9
4 changed files with 25 additions and 25 deletions
  1. 10 3
      UI/source-tree.cpp
  2. 1 10
      UI/source-tree.hpp
  3. 9 11
      UI/window-basic-preview.cpp
  4. 5 1
      UI/window-basic-preview.hpp

+ 10 - 3
UI/source-tree.cpp

@@ -1270,14 +1270,21 @@ void SourceTree::dropEvent(QDropEvent *event)
 void SourceTree::mouseMoveEvent(QMouseEvent *event)
 {
 	QPoint pos = event->pos();
-	SourceTreeItem *item = qobject_cast<SourceTreeItem *>
-		(childAt(pos));
+	SourceTreeItem *item = qobject_cast<SourceTreeItem *>(childAt(pos));
 
-	currentHover = item;
+	OBSBasicPreview *preview = OBSBasicPreview::Get();
+	preview->hoveredListItem = !!item ? item->sceneitem : nullptr;
 
 	QListView::mouseMoveEvent(event);
 }
 
+void SourceTree::leaveEvent(QEvent *event)
+{
+	OBSBasicPreview *preview = OBSBasicPreview::Get();
+	preview->hoveredListItem = nullptr;
+	QListView::leaveEvent(event);
+}
+
 void SourceTree::selectionChanged(
 		const QItemSelection &selected,
 		const QItemSelection &deselected)

+ 1 - 10
UI/source-tree.hpp

@@ -142,8 +142,6 @@ class SourceTree : public QListView {
 		return reinterpret_cast<SourceTreeModel *>(model());
 	}
 
-	SourceTreeItem *currentHover;
-
 public:
 	inline SourceTreeItem *GetItemWidget(int idx)
 	{
@@ -151,14 +149,6 @@ public:
 		return reinterpret_cast<SourceTreeItem *>(widget);
 	}
 
-	inline SourceTreeItem *GetHoveredItem()
-	{
-		if (underMouse()) {
-			return currentHover;
-		}
-		return nullptr;
-	}
-
 	explicit SourceTree(QWidget *parent = nullptr);
 
 	inline bool IgnoreReorder() const {return ignoreReorder;}
@@ -186,6 +176,7 @@ protected:
 	virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
 	virtual void dropEvent(QDropEvent *event) override;
 	virtual void mouseMoveEvent(QMouseEvent *event) override;
+	virtual void leaveEvent(QEvent *event) override;
 
 	virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
 };

+ 9 - 11
UI/window-basic-preview.cpp

@@ -616,7 +616,7 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
 		cropping     = false;
 
 		OBSSceneItem item = GetItemAtPos(pos, true);
-		hovered = item;
+		hoveredPreviewItem = item;
 	}
 }
 
@@ -1163,7 +1163,7 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
 		return;
 
 	if (mouseDown) {
-		hovered = nullptr;
+		hoveredPreviewItem = nullptr;
 
 		vec2 pos = GetMouseEventPos(event);
 
@@ -1205,13 +1205,13 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
 		vec2 pos = GetMouseEventPos(event);
 		OBSSceneItem item = GetItemAtPos(pos, true);
 
-		hovered = item;
+		hoveredPreviewItem = item;
 	}
 }
 
 void OBSBasicPreview::leaveEvent(QEvent *event)
 {
-	hovered = nullptr;
+	hoveredPreviewItem = nullptr;
 
 	UNUSED_PARAMETER(event);
 }
@@ -1408,16 +1408,14 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
 		gs_matrix_pop();
 	}
 
-	OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
 	OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param);
+	OBSBasic *main = OBSBasic::Get();
 
-	SourceTreeItem *hovItem = main->ui->sources->GetHoveredItem();
-	SourceTreeItem *curItem = main->GetItemWidgetFromSceneItem(item);
-
-	bool hover = (curItem && hovItem == curItem) || prev->hovered == item;
+	bool hovered = prev->hoveredPreviewItem == item ||
+	               prev->hoveredListItem == item;
 	bool selected = obs_sceneitem_selected(item);
 
-	if (!selected && !hover)
+	if (!selected && !hovered)
 		return true;
 
 	matrix4 boxTransform;
@@ -1466,7 +1464,7 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
 
 	if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) {
 #define DRAW_SIDE(side, x1, y1, x2, y2) \
-		if (hover && !selected) \
+		if (hovered && !selected) \
 			gs_effect_set_vec4(colParam, &blue); \
 		else if (crop.side > 0) \
 			gs_effect_set_vec4(colParam, &green); \

+ 5 - 1
UI/window-basic-preview.hpp

@@ -31,6 +31,8 @@ enum class ItemHandle : uint32_t {
 class OBSBasicPreview : public OBSQTDisplay {
 	Q_OBJECT
 
+	friend class SourceTree;
+
 private:
 	obs_sceneitem_crop startCrop;
 	vec2         startItemPos;
@@ -56,10 +58,12 @@ private:
 	bool         locked         = false;
 	bool         scrollMode     = false;
 	bool         fixedScaling   = false;
-	OBSSceneItem hovered        = nullptr;
 	int32_t      scalingLevel   = 0;
 	float        scalingAmount  = 1.0f;
 
+	obs_sceneitem_t *hoveredPreviewItem = nullptr;
+	obs_sceneitem_t *hoveredListItem    = nullptr;
+
 	static vec2 GetMouseEventPos(QMouseEvent *event);
 	static bool DrawSelectedOverflow(obs_scene_t *scene,
 		obs_sceneitem_t *item, void *param);