Fix deletion
This commit is contained in:
parent
e326eabbf8
commit
4f240b128b
3 changed files with 187 additions and 34 deletions
|
|
@ -227,7 +227,6 @@ void GraphEditorWidget::syncGraph()
|
||||||
refreshNodeMeter(node.id, node);
|
refreshNodeMeter(node.id, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<Potato::LinkInfo> links = m_controller->links();
|
const QVector<Potato::LinkInfo> links = m_controller->links();
|
||||||
for (const auto &link : links) {
|
for (const auto &link : links) {
|
||||||
onLinkAdded(link);
|
onLinkAdded(link);
|
||||||
|
|
@ -241,6 +240,8 @@ void GraphEditorWidget::refreshGraph()
|
||||||
m_ignoreDelete.clear();
|
m_ignoreDelete.clear();
|
||||||
m_connectionToLinkId.clear();
|
m_connectionToLinkId.clear();
|
||||||
m_linkIdToConnection.clear();
|
m_linkIdToConnection.clear();
|
||||||
|
m_nodeLinkCounts.clear();
|
||||||
|
m_linksById.clear();
|
||||||
|
|
||||||
m_model->reset();
|
m_model->reset();
|
||||||
syncGraph();
|
syncGraph();
|
||||||
|
|
@ -268,6 +269,7 @@ void GraphEditorWidget::onNodeChanged(const Potato::NodeInfo &node)
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshNodeMeter(node.id, node);
|
refreshNodeMeter(node.id, node);
|
||||||
|
updateNodeMeterState(node.id, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEditorWidget::onNodeRemoved(uint32_t nodeId)
|
void GraphEditorWidget::onNodeRemoved(uint32_t nodeId)
|
||||||
|
|
@ -275,6 +277,7 @@ void GraphEditorWidget::onNodeRemoved(uint32_t nodeId)
|
||||||
m_model->removePipeWireNode(nodeId);
|
m_model->removePipeWireNode(nodeId);
|
||||||
|
|
||||||
m_controller->removeNodeMeter(nodeId);
|
m_controller->removeNodeMeter(nodeId);
|
||||||
|
m_nodeLinkCounts.remove(nodeId);
|
||||||
|
|
||||||
if (m_nodeMeterRows.contains(nodeId)) {
|
if (m_nodeMeterRows.contains(nodeId)) {
|
||||||
QWidget *row = m_nodeMeterRows.take(nodeId);
|
QWidget *row = m_nodeMeterRows.take(nodeId);
|
||||||
|
|
@ -295,6 +298,23 @@ void GraphEditorWidget::onLinkAdded(const Potato::LinkInfo &link)
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString key = connectionKey(connectionId);
|
const QString key = connectionKey(connectionId);
|
||||||
|
const bool alreadyTracked = m_linksById.contains(link.id);
|
||||||
|
if (!alreadyTracked) {
|
||||||
|
m_linksById.insert(link.id, link);
|
||||||
|
if (!isMeterNode(link.outputNodeId) && !isMeterNode(link.inputNodeId)) {
|
||||||
|
m_nodeLinkCounts[link.outputNodeId] = m_nodeLinkCounts.value(link.outputNodeId, 0) + 1;
|
||||||
|
m_nodeLinkCounts[link.inputNodeId] = m_nodeLinkCounts.value(link.inputNodeId, 0) + 1;
|
||||||
|
|
||||||
|
const Potato::NodeInfo outNode = m_controller->nodeById(link.outputNodeId);
|
||||||
|
if (outNode.id != 0) {
|
||||||
|
updateNodeMeterState(outNode.id, outNode);
|
||||||
|
}
|
||||||
|
const Potato::NodeInfo inNode = m_controller->nodeById(link.inputNodeId);
|
||||||
|
if (inNode.id != 0) {
|
||||||
|
updateNodeMeterState(inNode.id, inNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_connectionToLinkId.contains(key)) {
|
if (m_connectionToLinkId.contains(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -310,16 +330,22 @@ void GraphEditorWidget::onLinkAdded(const Potato::LinkInfo &link)
|
||||||
|
|
||||||
void GraphEditorWidget::onLinkRemoved(uint32_t linkId)
|
void GraphEditorWidget::onLinkRemoved(uint32_t linkId)
|
||||||
{
|
{
|
||||||
if (!m_linkIdToConnection.contains(linkId)) {
|
if (m_ignoreLinkRemoved.contains(linkId)) {
|
||||||
m_model->removePipeWireConnection(linkId);
|
m_ignoreLinkRemoved.remove(linkId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString key = m_linkIdToConnection.value(linkId);
|
if (m_linkIdToConnection.contains(linkId)) {
|
||||||
m_ignoreDelete.insert(key);
|
const QString key = m_linkIdToConnection.value(linkId);
|
||||||
m_linkIdToConnection.remove(linkId);
|
m_ignoreDelete.insert(key);
|
||||||
m_connectionToLinkId.remove(key);
|
m_linkIdToConnection.remove(linkId);
|
||||||
m_model->removePipeWireConnection(linkId);
|
m_connectionToLinkId.remove(key);
|
||||||
|
m_model->removePipeWireConnection(linkId);
|
||||||
|
} else {
|
||||||
|
m_model->removePipeWireConnection(linkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLinkRemoved(linkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEditorWidget::onConnectionCreated(QtNodes::ConnectionId const connectionId)
|
void GraphEditorWidget::onConnectionCreated(QtNodes::ConnectionId const connectionId)
|
||||||
|
|
@ -362,6 +388,17 @@ void GraphEditorWidget::onConnectionCreated(QtNodes::ConnectionId const connecti
|
||||||
|
|
||||||
m_connectionToLinkId.insert(key, linkId);
|
m_connectionToLinkId.insert(key, linkId);
|
||||||
m_linkIdToConnection.insert(linkId, key);
|
m_linkIdToConnection.insert(linkId, key);
|
||||||
|
|
||||||
|
const Potato::LinkInfo link(linkId, outInfo->id, outputPortId, inInfo->id, inputPortId);
|
||||||
|
if (!m_linksById.contains(linkId)) {
|
||||||
|
m_linksById.insert(linkId, link);
|
||||||
|
if (!isMeterNode(link.outputNodeId) && !isMeterNode(link.inputNodeId)) {
|
||||||
|
m_nodeLinkCounts[link.outputNodeId] = m_nodeLinkCounts.value(link.outputNodeId, 0) + 1;
|
||||||
|
m_nodeLinkCounts[link.inputNodeId] = m_nodeLinkCounts.value(link.inputNodeId, 0) + 1;
|
||||||
|
updateNodeMeterState(outInfo->id, *outInfo);
|
||||||
|
updateNodeMeterState(inInfo->id, *inInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEditorWidget::onConnectionDeleted(QtNodes::ConnectionId const connectionId)
|
void GraphEditorWidget::onConnectionDeleted(QtNodes::ConnectionId const connectionId)
|
||||||
|
|
@ -379,6 +416,8 @@ void GraphEditorWidget::onConnectionDeleted(QtNodes::ConnectionId const connecti
|
||||||
const uint32_t linkId = m_connectionToLinkId.value(key);
|
const uint32_t linkId = m_connectionToLinkId.value(key);
|
||||||
m_connectionToLinkId.remove(key);
|
m_connectionToLinkId.remove(key);
|
||||||
m_linkIdToConnection.remove(linkId);
|
m_linkIdToConnection.remove(linkId);
|
||||||
|
m_ignoreLinkRemoved.insert(linkId);
|
||||||
|
handleLinkRemoved(linkId);
|
||||||
m_controller->destroyLink(linkId);
|
m_controller->destroyLink(linkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,20 +464,6 @@ void GraphEditorWidget::refreshNodeMeter(uint32_t nodeId, const Potato::NodeInfo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node.name.isEmpty()) {
|
|
||||||
bool captureSink = node.mediaClass == Potato::MediaClass::AudioSink
|
|
||||||
|| node.mediaClass == Potato::MediaClass::AudioDuplex;
|
|
||||||
if (!captureSink) {
|
|
||||||
for (const auto &port : node.outputPorts) {
|
|
||||||
if (port.name.contains("monitor", Qt::CaseInsensitive)) {
|
|
||||||
captureSink = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_controller->ensureNodeMeter(nodeId, node.name, captureSink);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *row = new QWidget(m_meterList);
|
auto *row = new QWidget(m_meterList);
|
||||||
auto *rowLayout = new QHBoxLayout(row);
|
auto *rowLayout = new QHBoxLayout(row);
|
||||||
rowLayout->setContentsMargins(0, 0, 0, 0);
|
rowLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
@ -466,6 +491,103 @@ void GraphEditorWidget::refreshNodeMeter(uint32_t nodeId, const Potato::NodeInfo
|
||||||
m_nodeMeterRows.insert(nodeId, row);
|
m_nodeMeterRows.insert(nodeId, row);
|
||||||
m_nodeMeterLabels.insert(nodeId, label);
|
m_nodeMeterLabels.insert(nodeId, label);
|
||||||
updateNodeMeterLabel(label);
|
updateNodeMeterLabel(label);
|
||||||
|
updateNodeMeterState(nodeId, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditorWidget::updateNodeMeterState(uint32_t nodeId, const Potato::NodeInfo &node)
|
||||||
|
{
|
||||||
|
const int linkCount = activeLinkCount(nodeId);
|
||||||
|
if (linkCount <= 0) {
|
||||||
|
m_controller->removeNodeMeter(nodeId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.name.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool captureSink = node.mediaClass == Potato::MediaClass::AudioSink
|
||||||
|
|| node.mediaClass == Potato::MediaClass::AudioDuplex;
|
||||||
|
if (!captureSink) {
|
||||||
|
for (const auto &port : node.outputPorts) {
|
||||||
|
if (port.name.contains("monitor", Qt::CaseInsensitive)) {
|
||||||
|
captureSink = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_controller->ensureNodeMeter(nodeId, node.name, captureSink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditorWidget::handleLinkRemoved(uint32_t linkId)
|
||||||
|
{
|
||||||
|
Potato::LinkInfo link;
|
||||||
|
bool haveLink = false;
|
||||||
|
if (m_linksById.contains(linkId)) {
|
||||||
|
link = m_linksById.take(linkId);
|
||||||
|
haveLink = true;
|
||||||
|
} else {
|
||||||
|
const QVector<Potato::LinkInfo> links = m_controller->links();
|
||||||
|
for (const auto &candidate : links) {
|
||||||
|
if (candidate.id == linkId) {
|
||||||
|
link = candidate;
|
||||||
|
haveLink = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveLink) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMeterNode(link.outputNodeId) || isMeterNode(link.inputNodeId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto decrement = [this](uint32_t nodeId) {
|
||||||
|
if (nodeId == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int current = m_nodeLinkCounts.value(nodeId, 0);
|
||||||
|
if (current <= 1) {
|
||||||
|
m_nodeLinkCounts.remove(nodeId);
|
||||||
|
} else {
|
||||||
|
m_nodeLinkCounts[nodeId] = current - 1;
|
||||||
|
}
|
||||||
|
const Potato::NodeInfo node = m_controller->nodeById(nodeId);
|
||||||
|
if (node.id != 0) {
|
||||||
|
updateNodeMeterState(node.id, node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
decrement(link.outputNodeId);
|
||||||
|
decrement(link.inputNodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GraphEditorWidget::isMeterNode(uint32_t nodeId) const
|
||||||
|
{
|
||||||
|
const Potato::NodeInfo node = m_controller->nodeById(nodeId);
|
||||||
|
if (node.name.startsWith("Potato-Meter") || node.name.startsWith("Potato-Node-Meter")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GraphEditorWidget::activeLinkCount(uint32_t nodeId) const
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (auto it = m_linksById.cbegin(); it != m_linksById.cend(); ++it) {
|
||||||
|
const Potato::LinkInfo &link = it.value();
|
||||||
|
if (isMeterNode(link.outputNodeId) || isMeterNode(link.inputNodeId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (link.outputNodeId == nodeId || link.inputNodeId == nodeId) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEditorWidget::updateNodeMeterLabel(QLabel *label)
|
void GraphEditorWidget::updateNodeMeterLabel(QLabel *label)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ private:
|
||||||
void refreshGraph();
|
void refreshGraph();
|
||||||
void updateLayoutState();
|
void updateLayoutState();
|
||||||
void updateNodeMeterLabel(QLabel *label);
|
void updateNodeMeterLabel(QLabel *label);
|
||||||
|
void updateNodeMeterState(uint32_t nodeId, const Potato::NodeInfo &node);
|
||||||
|
void handleLinkRemoved(uint32_t linkId);
|
||||||
|
bool isMeterNode(uint32_t nodeId) const;
|
||||||
|
int activeLinkCount(uint32_t nodeId) const;
|
||||||
QString connectionKey(const QtNodes::ConnectionId &connectionId) const;
|
QString connectionKey(const QtNodes::ConnectionId &connectionId) const;
|
||||||
bool eventFilter(QObject *object, QEvent *event) override;
|
bool eventFilter(QObject *object, QEvent *event) override;
|
||||||
|
|
||||||
|
|
@ -52,6 +56,7 @@ private:
|
||||||
|
|
||||||
QSet<QString> m_ignoreCreate;
|
QSet<QString> m_ignoreCreate;
|
||||||
QSet<QString> m_ignoreDelete;
|
QSet<QString> m_ignoreDelete;
|
||||||
|
QSet<uint32_t> m_ignoreLinkRemoved;
|
||||||
QMap<QString, uint32_t> m_connectionToLinkId;
|
QMap<QString, uint32_t> m_connectionToLinkId;
|
||||||
QMap<uint32_t, QString> m_linkIdToConnection;
|
QMap<uint32_t, QString> m_linkIdToConnection;
|
||||||
AudioLevelMeter *m_meter = nullptr;
|
AudioLevelMeter *m_meter = nullptr;
|
||||||
|
|
@ -62,4 +67,6 @@ private:
|
||||||
QMap<uint32_t, AudioLevelMeter*> m_nodeMeters;
|
QMap<uint32_t, AudioLevelMeter*> m_nodeMeters;
|
||||||
QMap<uint32_t, QWidget*> m_nodeMeterRows;
|
QMap<uint32_t, QWidget*> m_nodeMeterRows;
|
||||||
QMap<uint32_t, QLabel*> m_nodeMeterLabels;
|
QMap<uint32_t, QLabel*> m_nodeMeterLabels;
|
||||||
|
QMap<uint32_t, int> m_nodeLinkCounts;
|
||||||
|
QMap<uint32_t, Potato::LinkInfo> m_linksById;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -472,14 +472,19 @@ void PipeWireController::ensureNodeMeter(uint32_t nodeId, const QString &targetN
|
||||||
|
|
||||||
void PipeWireController::removeNodeMeter(uint32_t nodeId)
|
void PipeWireController::removeNodeMeter(uint32_t nodeId)
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&m_meterMutex);
|
NodeMeter *meter = nullptr;
|
||||||
if (!m_nodeMeters.contains(nodeId)) {
|
{
|
||||||
return;
|
QMutexLocker lock(&m_meterMutex);
|
||||||
|
if (!m_nodeMeters.contains(nodeId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
meter = m_nodeMeters.take(nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeMeter *meter = m_nodeMeters.take(nodeId);
|
|
||||||
if (meter && meter->stream) {
|
if (meter && meter->stream) {
|
||||||
|
lock();
|
||||||
pw_stream_destroy(meter->stream);
|
pw_stream_destroy(meter->stream);
|
||||||
|
unlock();
|
||||||
}
|
}
|
||||||
delete meter;
|
delete meter;
|
||||||
}
|
}
|
||||||
|
|
@ -495,6 +500,19 @@ uint32_t PipeWireController::createLink(uint32_t outputNodeId, uint32_t outputPo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&m_nodesMutex);
|
||||||
|
for (auto it = m_links.cbegin(); it != m_links.cend(); ++it) {
|
||||||
|
const LinkInfo &link = it.value();
|
||||||
|
if (link.outputNodeId == outputNodeId &&
|
||||||
|
link.outputPortId == outputPortId &&
|
||||||
|
link.inputNodeId == inputNodeId &&
|
||||||
|
link.inputPortId == inputPortId) {
|
||||||
|
return link.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock();
|
lock();
|
||||||
|
|
||||||
QByteArray outNode = QByteArray::number(outputNodeId);
|
QByteArray outNode = QByteArray::number(outputNodeId);
|
||||||
|
|
@ -591,15 +609,21 @@ bool PipeWireController::destroyLink(uint32_t linkId)
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
{
|
QElapsedTimer timer;
|
||||||
QMutexLocker lock(&m_nodesMutex);
|
timer.start();
|
||||||
m_links.remove(linkId);
|
while (timer.elapsed() < 2000) {
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&m_nodesMutex);
|
||||||
|
if (!m_links.contains(linkId)) {
|
||||||
|
qInfo() << "Link destroyed:" << linkId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QThread::msleep(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit linkRemoved(linkId);
|
qWarning() << "Link destroy requested but ID still present" << linkId;
|
||||||
|
return false;
|
||||||
qInfo() << "Link destroyed:" << linkId;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PipeWireController::dumpGraph() const
|
QString PipeWireController::dumpGraph() const
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue