Fix crash

This commit is contained in:
Joey Yakimowich-Payne 2026-01-30 12:49:47 -07:00
commit 07a151ebdf
3 changed files with 49 additions and 5 deletions

View file

@ -496,6 +496,12 @@ void GraphEditorWidget::scheduleSaveLayout() {
} }
} }
GraphEditorWidget::~GraphEditorWidget() {
if (m_client) {
m_client->SetChangeCallback(nullptr);
}
}
int GraphEditorWidget::nodeCount() const { int GraphEditorWidget::nodeCount() const {
return static_cast<int>(m_model->allNodeIds().size()); return static_cast<int>(m_model->allNodeIds().size());
} }
@ -712,6 +718,13 @@ void GraphEditorWidget::showNodeContextMenu(const QPoint &screenPos,
deleteAction->setShortcut(QKeySequence::Delete); 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")); QAction *pasteAction = menu.addAction(QStringLiteral("Paste"));
pasteAction->setShortcut(QKeySequence::Paste); pasteAction->setShortcut(QKeySequence::Paste);
pasteAction->setEnabled(!m_clipboardJson.isEmpty() || pasteAction->setEnabled(!m_clipboardJson.isEmpty() ||
@ -732,6 +745,10 @@ void GraphEditorWidget::showNodeContextMenu(const QPoint &screenPos,
deleteSelection(); deleteSelection();
} else if (chosen == pasteAction) { } else if (chosen == pasteAction) {
pasteSelection(QPointF(0, 0)); 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); infoLayout->addWidget(matchLabel);
auto *targetLabel = new QLabel( auto *targetLabel = new QLabel(
QStringLiteral("\xe2\x86\x92 ") + QString(QChar(0x2192)) + QStringLiteral(" ") +
QString::fromStdString(rule.target_node)); QString::fromStdString(rule.target_node));
targetLabel->setStyleSheet(labelStyle); targetLabel->setStyleSheet(labelStyle);
infoLayout->addWidget(targetLabel); infoLayout->addWidget(targetLabel);
cardLayout->addLayout(infoLayout, 1); cardLayout->addLayout(infoLayout, 1);
auto *delBtn = new QPushButton(QStringLiteral("\xe2\x9c\x95")); auto *delBtn = new QPushButton(QString(QChar(0x2715)));
delBtn->setFixedSize(24, 24); delBtn->setFixedSize(24, 24);
delBtn->setStyleSheet(delBtnStyle); delBtn->setStyleSheet(delBtnStyle);
warppipe::RuleId ruleId = rule.id; warppipe::RuleId ruleId = rule.id;
@ -1500,13 +1517,15 @@ void GraphEditorWidget::rebuildRulesList() {
auto *addBtn = new QPushButton(QStringLiteral("Add Rule...")); auto *addBtn = new QPushButton(QStringLiteral("Add Rule..."));
addBtn->setStyleSheet(btnStyle); addBtn->setStyleSheet(btnStyle);
connect(addBtn, &QPushButton::clicked, this, connect(addBtn, &QPushButton::clicked, this,
&GraphEditorWidget::showAddRuleDialog); [this]() { showAddRuleDialog(); });
layout->addWidget(addBtn); layout->addWidget(addBtn);
static_cast<QVBoxLayout *>(layout)->addStretch(); static_cast<QVBoxLayout *>(layout)->addStretch();
} }
void GraphEditorWidget::showAddRuleDialog() { void GraphEditorWidget::showAddRuleDialog(const std::string &prefillApp,
const std::string &prefillBin,
const std::string &prefillRole) {
if (!m_client) if (!m_client)
return; return;
@ -1529,14 +1548,20 @@ void GraphEditorWidget::showAddRuleDialog() {
auto *appNameEdit = new QLineEdit(); auto *appNameEdit = new QLineEdit();
appNameEdit->setPlaceholderText(QStringLiteral("e.g. Firefox")); appNameEdit->setPlaceholderText(QStringLiteral("e.g. Firefox"));
if (!prefillApp.empty())
appNameEdit->setText(QString::fromStdString(prefillApp));
form->addRow(QStringLiteral("Application Name:"), appNameEdit); form->addRow(QStringLiteral("Application Name:"), appNameEdit);
auto *processBinEdit = new QLineEdit(); auto *processBinEdit = new QLineEdit();
processBinEdit->setPlaceholderText(QStringLiteral("e.g. firefox")); processBinEdit->setPlaceholderText(QStringLiteral("e.g. firefox"));
if (!prefillBin.empty())
processBinEdit->setText(QString::fromStdString(prefillBin));
form->addRow(QStringLiteral("Process Binary:"), processBinEdit); form->addRow(QStringLiteral("Process Binary:"), processBinEdit);
auto *mediaRoleEdit = new QLineEdit(); auto *mediaRoleEdit = new QLineEdit();
mediaRoleEdit->setPlaceholderText(QStringLiteral("e.g. Music")); mediaRoleEdit->setPlaceholderText(QStringLiteral("e.g. Music"));
if (!prefillRole.empty())
mediaRoleEdit->setText(QString::fromStdString(prefillRole));
form->addRow(QStringLiteral("Media Role:"), mediaRoleEdit); form->addRow(QStringLiteral("Media Role:"), mediaRoleEdit);
auto *targetCombo = new QComboBox(); auto *targetCombo = new QComboBox();

View file

@ -35,6 +35,7 @@ class GraphEditorWidget : public QWidget {
public: public:
explicit GraphEditorWidget(warppipe::Client *client, explicit GraphEditorWidget(warppipe::Client *client,
QWidget *parent = nullptr); QWidget *parent = nullptr);
~GraphEditorWidget() override;
int nodeCount() const; int nodeCount() const;
int linkCount() const; int linkCount() const;
@ -73,7 +74,9 @@ private:
void updateMeters(); void updateMeters();
void rebuildNodeMeters(); void rebuildNodeMeters();
void rebuildRulesList(); void rebuildRulesList();
void showAddRuleDialog(); void showAddRuleDialog(const std::string &prefillApp = {},
const std::string &prefillBin = {},
const std::string &prefillRole = {});
struct PendingPasteLink { struct PendingPasteLink {
std::string outNodeName; std::string outNodeName;

View file

@ -1043,6 +1043,22 @@ void Client::Impl::ProcessSavedLinks() {
{ {
std::lock_guard<std::mutex> lock(cache_mutex); std::lock_guard<std::mutex> lock(cache_mutex);
for (auto it = saved_links.begin(); it != saved_links.end();) { 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; uint32_t out_id = 0, in_id = 0;
for (const auto& port_entry : ports) { for (const auto& port_entry : ports) {
const PortInfo& port = port_entry.second; const PortInfo& port = port_entry.second;