From 1b8ecae3b9e75d44228f34b7bcf13ee9baa06476 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 11 Feb 2019 15:27:38 -0800 Subject: [PATCH] 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. --- UI/source-tree.cpp | 13 ++++++++++--- UI/source-tree.hpp | 11 +---------- UI/window-basic-preview.cpp | 20 +++++++++----------- UI/window-basic-preview.hpp | 6 +++++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/UI/source-tree.cpp b/UI/source-tree.cpp index 92d74b10d..5c97278b8 100644 --- a/UI/source-tree.cpp +++ b/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 - (childAt(pos)); + SourceTreeItem *item = qobject_cast(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) diff --git a/UI/source-tree.hpp b/UI/source-tree.hpp index 0d7dff79f..551993b21 100644 --- a/UI/source-tree.hpp +++ b/UI/source-tree.hpp @@ -142,8 +142,6 @@ class SourceTree : public QListView { return reinterpret_cast(model()); } - SourceTreeItem *currentHover; - public: inline SourceTreeItem *GetItemWidget(int idx) { @@ -151,14 +149,6 @@ public: return reinterpret_cast(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; }; diff --git a/UI/window-basic-preview.cpp b/UI/window-basic-preview.cpp index e079e68eb..0f8f0a678 100644 --- a/UI/window-basic-preview.cpp +++ b/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(App()->GetMainWindow()); OBSBasicPreview *prev = reinterpret_cast(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); \ diff --git a/UI/window-basic-preview.hpp b/UI/window-basic-preview.hpp index 8c033f02f..e285456d8 100644 --- a/UI/window-basic-preview.hpp +++ b/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);