From 07a151ebdf2aff41ec6ac0897c5a2e7688cb38a0 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Fri, 30 Jan 2026 12:49:47 -0700 Subject: [PATCH] Fix crash --- gui/GraphEditorWidget.cpp | 33 +++++++++++++++++++++++++++++---- gui/GraphEditorWidget.h | 5 ++++- src/warppipe.cpp | 16 ++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/gui/GraphEditorWidget.cpp b/gui/GraphEditorWidget.cpp index a7b32c6..e05eef2 100644 --- a/gui/GraphEditorWidget.cpp +++ b/gui/GraphEditorWidget.cpp @@ -496,6 +496,12 @@ void GraphEditorWidget::scheduleSaveLayout() { } } +GraphEditorWidget::~GraphEditorWidget() { + if (m_client) { + m_client->SetChangeCallback(nullptr); + } +} + int GraphEditorWidget::nodeCount() const { return static_cast(m_model->allNodeIds().size()); } @@ -712,6 +718,13 @@ void GraphEditorWidget::showNodeContextMenu(const QPoint &screenPos, deleteAction->setShortcut(QKeySequence::Delete); } + QAction *createRuleAction = nullptr; + if (type == WarpNodeType::kApplication) { + menu.addSeparator(); + createRuleAction = menu.addAction(QStringLiteral("Create Rule...")); + } + + menu.addSeparator(); QAction *pasteAction = menu.addAction(QStringLiteral("Paste")); pasteAction->setShortcut(QKeySequence::Paste); pasteAction->setEnabled(!m_clipboardJson.isEmpty() || @@ -732,6 +745,10 @@ void GraphEditorWidget::showNodeContextMenu(const QPoint &screenPos, deleteSelection(); } else if (chosen == pasteAction) { pasteSelection(QPointF(0, 0)); + } else if (chosen == createRuleAction) { + showAddRuleDialog(data->info.application_name, + data->info.process_binary, + data->info.media_role); } } @@ -1476,14 +1493,14 @@ void GraphEditorWidget::rebuildRulesList() { infoLayout->addWidget(matchLabel); auto *targetLabel = new QLabel( - QStringLiteral("\xe2\x86\x92 ") + + QString(QChar(0x2192)) + QStringLiteral(" ") + QString::fromStdString(rule.target_node)); targetLabel->setStyleSheet(labelStyle); infoLayout->addWidget(targetLabel); cardLayout->addLayout(infoLayout, 1); - auto *delBtn = new QPushButton(QStringLiteral("\xe2\x9c\x95")); + auto *delBtn = new QPushButton(QString(QChar(0x2715))); delBtn->setFixedSize(24, 24); delBtn->setStyleSheet(delBtnStyle); warppipe::RuleId ruleId = rule.id; @@ -1500,13 +1517,15 @@ void GraphEditorWidget::rebuildRulesList() { auto *addBtn = new QPushButton(QStringLiteral("Add Rule...")); addBtn->setStyleSheet(btnStyle); connect(addBtn, &QPushButton::clicked, this, - &GraphEditorWidget::showAddRuleDialog); + [this]() { showAddRuleDialog(); }); layout->addWidget(addBtn); static_cast(layout)->addStretch(); } -void GraphEditorWidget::showAddRuleDialog() { +void GraphEditorWidget::showAddRuleDialog(const std::string &prefillApp, + const std::string &prefillBin, + const std::string &prefillRole) { if (!m_client) return; @@ -1529,14 +1548,20 @@ void GraphEditorWidget::showAddRuleDialog() { auto *appNameEdit = new QLineEdit(); appNameEdit->setPlaceholderText(QStringLiteral("e.g. Firefox")); + if (!prefillApp.empty()) + appNameEdit->setText(QString::fromStdString(prefillApp)); form->addRow(QStringLiteral("Application Name:"), appNameEdit); auto *processBinEdit = new QLineEdit(); processBinEdit->setPlaceholderText(QStringLiteral("e.g. firefox")); + if (!prefillBin.empty()) + processBinEdit->setText(QString::fromStdString(prefillBin)); form->addRow(QStringLiteral("Process Binary:"), processBinEdit); auto *mediaRoleEdit = new QLineEdit(); mediaRoleEdit->setPlaceholderText(QStringLiteral("e.g. Music")); + if (!prefillRole.empty()) + mediaRoleEdit->setText(QString::fromStdString(prefillRole)); form->addRow(QStringLiteral("Media Role:"), mediaRoleEdit); auto *targetCombo = new QComboBox(); diff --git a/gui/GraphEditorWidget.h b/gui/GraphEditorWidget.h index c327aff..deec287 100644 --- a/gui/GraphEditorWidget.h +++ b/gui/GraphEditorWidget.h @@ -35,6 +35,7 @@ class GraphEditorWidget : public QWidget { public: explicit GraphEditorWidget(warppipe::Client *client, QWidget *parent = nullptr); + ~GraphEditorWidget() override; int nodeCount() const; int linkCount() const; @@ -73,7 +74,9 @@ private: void updateMeters(); void rebuildNodeMeters(); void rebuildRulesList(); - void showAddRuleDialog(); + void showAddRuleDialog(const std::string &prefillApp = {}, + const std::string &prefillBin = {}, + const std::string &prefillRole = {}); struct PendingPasteLink { std::string outNodeName; diff --git a/src/warppipe.cpp b/src/warppipe.cpp index 36fe7e0..593c450 100644 --- a/src/warppipe.cpp +++ b/src/warppipe.cpp @@ -1043,6 +1043,22 @@ void Client::Impl::ProcessSavedLinks() { { std::lock_guard lock(cache_mutex); for (auto it = saved_links.begin(); it != saved_links.end();) { + bool covered_by_rule = false; + for (const auto& node_entry : nodes) { + if (node_entry.second.name != it->out_node) continue; + for (const auto& rule_entry : route_rules) { + if (MatchesRule(node_entry.second, rule_entry.second.match) && + rule_entry.second.target_node == it->in_node) { + covered_by_rule = true; + break; + } + } + if (covered_by_rule) break; + } + if (covered_by_rule) { + it = saved_links.erase(it); + continue; + } uint32_t out_id = 0, in_id = 0; for (const auto& port_entry : ports) { const PortInfo& port = port_entry.second;