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);
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<Potato::LinkInfo> links = m_controller->links();
|
||||
for (const auto &link : links) {
|
||||
onLinkAdded(link);
|
||||
|
|
@ -241,6 +240,8 @@ void GraphEditorWidget::refreshGraph()
|
|||
m_ignoreDelete.clear();
|
||||
m_connectionToLinkId.clear();
|
||||
m_linkIdToConnection.clear();
|
||||
m_nodeLinkCounts.clear();
|
||||
m_linksById.clear();
|
||||
|
||||
m_model->reset();
|
||||
syncGraph();
|
||||
|
|
@ -268,6 +269,7 @@ void GraphEditorWidget::onNodeChanged(const Potato::NodeInfo &node)
|
|||
}
|
||||
|
||||
refreshNodeMeter(node.id, node);
|
||||
updateNodeMeterState(node.id, node);
|
||||
}
|
||||
|
||||
void GraphEditorWidget::onNodeRemoved(uint32_t nodeId)
|
||||
|
|
@ -275,6 +277,7 @@ void GraphEditorWidget::onNodeRemoved(uint32_t nodeId)
|
|||
m_model->removePipeWireNode(nodeId);
|
||||
|
||||
m_controller->removeNodeMeter(nodeId);
|
||||
m_nodeLinkCounts.remove(nodeId);
|
||||
|
||||
if (m_nodeMeterRows.contains(nodeId)) {
|
||||
QWidget *row = m_nodeMeterRows.take(nodeId);
|
||||
|
|
@ -295,6 +298,23 @@ void GraphEditorWidget::onLinkAdded(const Potato::LinkInfo &link)
|
|||
}
|
||||
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -310,16 +330,22 @@ void GraphEditorWidget::onLinkAdded(const Potato::LinkInfo &link)
|
|||
|
||||
void GraphEditorWidget::onLinkRemoved(uint32_t linkId)
|
||||
{
|
||||
if (!m_linkIdToConnection.contains(linkId)) {
|
||||
m_model->removePipeWireConnection(linkId);
|
||||
if (m_ignoreLinkRemoved.contains(linkId)) {
|
||||
m_ignoreLinkRemoved.remove(linkId);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString key = m_linkIdToConnection.value(linkId);
|
||||
m_ignoreDelete.insert(key);
|
||||
m_linkIdToConnection.remove(linkId);
|
||||
m_connectionToLinkId.remove(key);
|
||||
m_model->removePipeWireConnection(linkId);
|
||||
if (m_linkIdToConnection.contains(linkId)) {
|
||||
const QString key = m_linkIdToConnection.value(linkId);
|
||||
m_ignoreDelete.insert(key);
|
||||
m_linkIdToConnection.remove(linkId);
|
||||
m_connectionToLinkId.remove(key);
|
||||
m_model->removePipeWireConnection(linkId);
|
||||
} else {
|
||||
m_model->removePipeWireConnection(linkId);
|
||||
}
|
||||
|
||||
handleLinkRemoved(linkId);
|
||||
}
|
||||
|
||||
void GraphEditorWidget::onConnectionCreated(QtNodes::ConnectionId const connectionId)
|
||||
|
|
@ -362,6 +388,17 @@ void GraphEditorWidget::onConnectionCreated(QtNodes::ConnectionId const connecti
|
|||
|
||||
m_connectionToLinkId.insert(key, linkId);
|
||||
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)
|
||||
|
|
@ -379,6 +416,8 @@ void GraphEditorWidget::onConnectionDeleted(QtNodes::ConnectionId const connecti
|
|||
const uint32_t linkId = m_connectionToLinkId.value(key);
|
||||
m_connectionToLinkId.remove(key);
|
||||
m_linkIdToConnection.remove(linkId);
|
||||
m_ignoreLinkRemoved.insert(linkId);
|
||||
handleLinkRemoved(linkId);
|
||||
m_controller->destroyLink(linkId);
|
||||
}
|
||||
|
||||
|
|
@ -425,20 +464,6 @@ void GraphEditorWidget::refreshNodeMeter(uint32_t nodeId, const Potato::NodeInfo
|
|||
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 *rowLayout = new QHBoxLayout(row);
|
||||
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_nodeMeterLabels.insert(nodeId, 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)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ private:
|
|||
void refreshGraph();
|
||||
void updateLayoutState();
|
||||
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;
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
|
|
@ -52,6 +56,7 @@ private:
|
|||
|
||||
QSet<QString> m_ignoreCreate;
|
||||
QSet<QString> m_ignoreDelete;
|
||||
QSet<uint32_t> m_ignoreLinkRemoved;
|
||||
QMap<QString, uint32_t> m_connectionToLinkId;
|
||||
QMap<uint32_t, QString> m_linkIdToConnection;
|
||||
AudioLevelMeter *m_meter = nullptr;
|
||||
|
|
@ -62,4 +67,6 @@ private:
|
|||
QMap<uint32_t, AudioLevelMeter*> m_nodeMeters;
|
||||
QMap<uint32_t, QWidget*> m_nodeMeterRows;
|
||||
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)
|
||||
{
|
||||
QMutexLocker lock(&m_meterMutex);
|
||||
if (!m_nodeMeters.contains(nodeId)) {
|
||||
return;
|
||||
NodeMeter *meter = nullptr;
|
||||
{
|
||||
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) {
|
||||
lock();
|
||||
pw_stream_destroy(meter->stream);
|
||||
unlock();
|
||||
}
|
||||
delete meter;
|
||||
}
|
||||
|
|
@ -494,6 +499,19 @@ uint32_t PipeWireController::createLink(uint32_t outputNodeId, uint32_t outputPo
|
|||
qWarning() << "Cannot create link: not connected to PipeWire";
|
||||
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();
|
||||
|
||||
|
|
@ -591,15 +609,21 @@ bool PipeWireController::destroyLink(uint32_t linkId)
|
|||
|
||||
unlock();
|
||||
|
||||
{
|
||||
QMutexLocker lock(&m_nodesMutex);
|
||||
m_links.remove(linkId);
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
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);
|
||||
|
||||
qInfo() << "Link destroyed:" << linkId;
|
||||
return true;
|
||||
|
||||
qWarning() << "Link destroy requested but ID still present" << linkId;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString PipeWireController::dumpGraph() const
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue