Guard desktop modal owners and remove obsolete message helpers

This commit is contained in:
evgeny committed 2026-10-28 00:59:00 +01:00
1 parent 8b2b68d383
commit 7556695cc5
3 files changed
+20 -51

No files matched your search

+17 -14
View File
@@ -179,8 +179,7 @@ MainWindow::MainWindow(QWidget *parent, DbManager* db, const QString& cfgPath,
m_cpuLoadTimer = new QTimer(this);
m_cpuLoadTimer->setTimerType(Qt::PreciseTimer);
connect(m_cpuLoadTimer, &QTimer::timeout, this, [this] {
auto* inst = gui_bridge_get_inst();
if (!m_node || !m_node->isRunning() || !inst || !gui_bridge_is_uasync_ready()) {
if (!m_node || !m_node->isRunning() || !gui_bridge_is_uasync_ready()) {
m_cpuLoadPending = false; m_channelList->setCpuLoad(0); return;
}
if (m_cpuLoadPending) return;
@@ -889,6 +888,7 @@ void MainWindow::onRadioCallEvent(const uint8_t* data, int len) {
auto* box = new QMessageBox(QMessageBox::Question, QCoreApplication::translate("ChatGui", "Radio call"),
QCoreApplication::translate("ChatGui", incoming ? "Incoming radio call from %1\nChannel: %2" : "Calling %1 by radio\nChannel: %2")
.arg(name, channelName), QMessageBox::NoButton, this);
box->setTextFormat(Qt::PlainText);
box->setAttribute(Qt::WA_DeleteOnClose);
m_radioCallId = id; m_radioCallWindow = box; m_radioCallAnswered = false;
if (incoming) {
@@ -1291,8 +1291,8 @@ void MainWindow::onTrayActivated(QSystemTrayIcon::ActivationReason reason) {
void MainWindow::showShareInviteDialog(const QString& channelId) {
if (!m_db || !m_db->isOpen()) return;
ShareInviteDialog dlg(channelId, m_db, this);
dlg.exec();
QPointer<ShareInviteDialog> dialog = new ShareInviteDialog(channelId, m_db, this);
auto release = qScopeGuard([&] { delete dialog.data(); }); dialog->exec();
}
void MainWindow::showInviteByLinkDialog(const QString& channelId) {
@@ -1300,8 +1300,8 @@ void MainWindow::showInviteByLinkDialog(const QString& channelId) {
QMessageBox::warning(this, QCoreApplication::translate("ChatGui", "Error"), QCoreApplication::translate("ChatGui", "Node is not running."));
return;
}
InviteByLinkDialog dlg(channelId, m_node, this);
dlg.exec();
QPointer<InviteByLinkDialog> dialog = new InviteByLinkDialog(channelId, m_node, this);
auto release = qScopeGuard([&] { delete dialog.data(); }); dialog->exec();
}
void MainWindow::showJoinDialog() {
@@ -1321,14 +1321,15 @@ void MainWindow::showJoinDialog() {
autoLink = selText;
}
JoinDialog dlg(m_node, m_db, this, autoLink);
dlg.exec();
QPointer<JoinDialog> dialog = new JoinDialog(m_node, m_db, this, autoLink);
auto release = qScopeGuard([&] { delete dialog.data(); }); dialog->exec();
}
void MainWindow::showSettings() {
SettingsDialog dlg(m_cfgPath, m_db, m_node, m_recorder, this);
dlg.exec();
reloadChannels();
QPointer<MainWindow> self(this);
QPointer<SettingsDialog> dialog = new SettingsDialog(m_cfgPath, m_db, m_node, m_recorder, this);
auto release = qScopeGuard([&] { delete dialog.data(); }); dialog->exec();
if (self) reloadChannels();
}
void MainWindow::openVideo(const QString& filePath) {
@@ -1457,10 +1458,12 @@ void MainWindow::onCreateGroupRequested() {
return;
}
CreateGroupDialog dlg(this);
if (dlg.exec() != QDialog::Accepted) return;
QPointer<MainWindow> self(this); QPointer<CreateGroupDialog> dialog = new CreateGroupDialog(this);
auto release = qScopeGuard([&] { delete dialog.data(); });
const int result = dialog->exec();
if (!self || !dialog || result != QDialog::Accepted) return;
QString name = dlg.groupName();
QString name = dialog->groupName();
if (name.isEmpty()) return;
auto* arg = static_cast<chat_create_auto_arg*>(u_calloc(1, sizeof(chat_create_auto_arg)));
-35
View File
@@ -104,40 +104,6 @@ static QPixmap makeAvatar(const QColor &color, const QString &letter, int size =
return pix;
}
static QVariant makeReaction(const QString &emoji, int count,
const QList<QColor> &colors = {}) {
QVariantMap m;
m["emoji"] = emoji;
m["count"] = count;
if (!colors.isEmpty())
m["colors"] = QVariant::fromValue(colors);
return m;
}
static QString parseJsonField(const QByteArray& data, const char* field) {
QByteArray pat = QByteArray("\"") + field + "\":\"";
int idx = data.indexOf(pat);
if (idx < 0) return {};
idx += pat.size();
int end = data.indexOf('"', idx);
if (end < 0) return {};
return QString::fromUtf8(data.mid(idx, end - idx));
}
static QString parseJsonFieldNum(const QByteArray& data, const char* field) {
QByteArray pat = QByteArray("\"") + field + "\":";
int idx = data.indexOf(pat);
if (idx < 0) return {};
idx += pat.size();
int end = data.indexOf(',', idx);
if (end < 0) end = data.indexOf('}', idx);
if (end < 0) return {};
return QString::fromUtf8(data.mid(idx, end - idx));
}
static QString contentTypeFromJson(const QByteArray& data) {
return parseJsonField(data, "ct");
}
static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
const QString& contentType, const QString& mediaDirBase,
@@ -154,7 +120,6 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
}
}
QString ct = contentType;
if (ct.isEmpty()) ct = contentTypeFromJson(data);
if (ct.isEmpty()) ct = "text/plain";
item->setData(ct, MsgContentTypeRole);
item->setData(channelId, MsgChannelIdRole);
+3 -2
View File
@@ -3,8 +3,9 @@
* start подтверждает готовность сервисов и медиапривязок перед входом в poll.
* start/stop/настройки принадлежат GUI-потоку; настройки менять при остановленном узле.
* requestStop допускается из другого потока, stop ждёт worker и освобождает uasync вне callbacks.
* Worker уничтожает instance; идентичность и NTP читаются через защищённую копию состояния,
* обновляемую перед подтверждением старта и после каждого poll. instance — только заимствованный
* Worker уничтожает instance после подтверждённого stopping в GUI: читатели SQLite должны снять handle в его слотах.
* Идентичность, путь БД и NTP читаются через защищённую копию состояния перед стартом и после poll.
* instance — только заимствованный
* указатель для кода ядра: использовать в uasync, согласовав время жизни с stop/restart.
* Logger общий для процесса; путь файла принадлежит объекту до закрытия лога. */
#ifndef UTUN_NODE_H