aboutsummaryrefslogtreecommitdiffstats
path: root/stats/statsview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'stats/statsview.cpp')
-rw-r--r--stats/statsview.cpp58
1 files changed, 48 insertions, 10 deletions
diff --git a/stats/statsview.cpp b/stats/statsview.cpp
index eb51810f8..5514aa35d 100644
--- a/stats/statsview.cpp
+++ b/stats/statsview.cpp
@@ -89,18 +89,20 @@ using ZNode = HideableQSGNode<QSGNode>;
class RootNode : public QSGNode
{
public:
- RootNode(QQuickWindow *w);
+ RootNode(StatsView &view);
+ ~RootNode();
+ StatsView &view;
std::unique_ptr<QSGRectangleNode> backgroundNode; // solid background
// We entertain one node per Z-level.
std::array<std::unique_ptr<ZNode>, (size_t)ChartZValue::Count> zNodes;
};
-RootNode::RootNode(QQuickWindow *w)
+RootNode::RootNode(StatsView &view) : view(view)
{
// Add a background rectangle with a solid color. This could
// also be done on the widget level, but would have to be done
// separately for desktop and mobile, so do it here.
- backgroundNode.reset(w->createRectangleNode());
+ backgroundNode.reset(view.w()->createRectangleNode());
backgroundNode->setColor(backgroundColor);
appendChildNode(backgroundNode.get());
@@ -110,21 +112,31 @@ RootNode::RootNode(QQuickWindow *w)
}
}
-QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+RootNode::~RootNode()
{
- // The QtQuick drawing interface is utterly bizzare with a distinct 1980ies-style memory management.
- // This is just a copy of what is found in Qt's documentation.
- RootNode *n = static_cast<RootNode *>(oldNode);
- if (!n)
- n = rootNode = new RootNode(window());
+ view.emergencyShutdown();
+}
- // Delete all chart items that are marked for deletion.
+void StatsView::freeDeletedChartItems()
+{
ChartItem *nextitem;
for (ChartItem *item = deletedItems.first; item; item = nextitem) {
nextitem = item->next;
delete item;
}
deletedItems.clear();
+}
+
+QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ // The QtQuick drawing interface is utterly bizzare with a distinct 1980ies-style memory management.
+ // This is just a copy of what is found in Qt's documentation.
+ RootNode *n = static_cast<RootNode *>(oldNode);
+ if (!n)
+ n = rootNode = new RootNode(*this);
+
+ // Delete all chart items that are marked for deletion.
+ freeDeletedChartItems();
if (backgroundDirty) {
rootNode->backgroundNode->setRect(plotRect);
@@ -140,6 +152,32 @@ QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod
return n;
}
+// When reparenting the QQuickWidget, QtQuick decides to delete our rootNode
+// and with it all the QSG nodes, even though we have *not* given the
+// permission to do so! If the widget is reused, we try to delete the
+// stale items, whose nodes have already been deleted by QtQuick, leading
+// to a double-free(). Instead of searching for the cause of this behavior,
+// let's just hook into the rootNodes destructor and delete the objects
+// in a controlled manner, so that QtQuick has no more access to them.
+void StatsView::emergencyShutdown()
+{
+ // Mark clean and dirty chart items for deletion...
+ cleanItems.splice(deletedItems);
+ dirtyItems.splice(deletedItems);
+
+ // ...and delete them.
+ freeDeletedChartItems();
+
+ // Now delete all the pointers we might have to chart features,
+ // axes, etc. Note that all pointers to chart items are non
+ // owning, so this only resets stale references, but does not
+ // lead to any additional deletion of chart items.
+ reset();
+
+ // The rootNode is being deleted -> remove the reference to that
+ rootNode = nullptr;
+}
+
void StatsView::addQSGNode(QSGNode *node, ChartZValue z)
{
int idx = std::clamp((int)z, 0, (int)ChartZValue::Count - 1);