Fix sound settings request ownership on rejection and cancellation

This commit is contained in:
evgeny committed 2026-10-27 15:13:26 +01:00
1 parent 821f1b8a92
commit 8d8fe8d6bf
3 files changed
+49 -51

No files matched your search

+31 -40
View File
@@ -14,7 +14,7 @@ extern "C" {
#include <QSlider>
#include <QLabel>
#include <QFrame>
#include <QDebug>
#include <QVector>
SoundSettingsPage::SoundSettingsPage(DbManager* db, QWidget* parent)
: QWidget(parent)
@@ -144,53 +144,44 @@ void SoundSettingsPage::applyAndSave() {
sm->setEnabled(enabled);
sm->setVolume(masterVol);
QVector<QPair<QByteArray, QByteArray>> values;
values.reserve(18);
for (int i = 0; i < 8; i++) {
auto& e = m_events[i];
bool on = e.check->isChecked();
float ev = e.slider->value() / 100.0f;
sm->setEvent(e.key, on, ev);
/* async DB persist — key\0value\0 */
QString onKey = QStringLiteral("sound_%1_on").arg(e.key);
QString volKey = QStringLiteral("sound_%1_vol").arg(e.key);
QByteArray onVal = on ? QByteArray("1") : QByteArray("0");
QByteArray volVal = QByteArray::number(e.slider->value());
for (int j = 0; j < 2; j++) {
const QByteArray key = (j == 0 ? onKey : volKey).toUtf8();
const char* k = key.constData();
const char* v = j == 0 ? onVal.constData() : volVal.constData();
size_t klen = strlen(k), vlen = strlen(v);
size_t total = klen + 1 + vlen + 1;
if (total > sizeof(save_ui_state_arg::data)) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: key/value too large bytes=%zu", total); continue;
}
struct save_ui_state_arg* arg = (struct save_ui_state_arg*)u_malloc(sizeof(struct save_ui_state_arg));
if (!arg) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: request allocation failed"); continue; }
arg->inst = gui_bridge_get_inst();
memcpy(arg->data, k, klen + 1);
memcpy(arg->data + klen + 1, v, vlen + 1);
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg);
}
const QByteArray prefix = QByteArray("sound_") + e.key;
values.append({prefix + "_on", on ? QByteArray("1") : QByteArray("0")});
values.append({prefix + "_vol", QByteArray::number(e.slider->value())});
}
values.append({"sound_enabled", enabled ? QByteArray("1") : QByteArray("0")});
values.append({"sound_volume", QByteArray::number(m_volumeSlider->value())});
/* save global settings */
{
const char* keys[] = {"sound_enabled", "sound_volume"};
QByteArray vals[] = {enabled ? QByteArray("1") : QByteArray("0"),
QByteArray::number(m_volumeSlider->value())};
for (int j = 0; j < 2; j++) {
size_t klen = strlen(keys[j]), vlen = vals[j].size();
size_t total = klen + 1 + vlen + 1;
if (total > sizeof(save_ui_state_arg::data)) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: global key/value too large bytes=%zu", total); continue;
}
struct save_ui_state_arg* arg = (struct save_ui_state_arg*)u_malloc(sizeof(struct save_ui_state_arg));
if (!arg) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: global request allocation failed"); continue; }
arg->inst = gui_bridge_get_inst();
memcpy(arg->data, keys[j], klen + 1);
memcpy(arg->data + klen + 1, vals[j].constData(), vlen + 1);
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg);
/* Один путь передачи владения для всех key\0value\0; принятый запрос освобождает callback либо мост при отмене. */
unsigned queued = 0, failed = 0;
for (const auto& value : values) {
const auto& key = value.first;
const size_t klen = key.size(), vlen = value.second.size(), total = klen + 1 + vlen + 1;
if (total > sizeof(save_ui_state_arg::data)) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: key=%s key/value too large bytes=%zu", key.constData(), total);
++failed; continue;
}
auto* arg = static_cast<save_ui_state_arg*>(u_malloc(sizeof(save_ui_state_arg)));
if (!arg) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: key=%s request allocation failed", key.constData());
++failed; continue;
}
arg->inst = gui_bridge_get_inst();
memcpy(arg->data, key.constData(), klen + 1);
memcpy(arg->data + klen + 1, value.second.constData(), vlen + 1);
if (gui_bridge_post_uasync_owned_fn(chat_core_save_ui_state_trampoline, arg) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Sound settings: key=%s save rejected by GUI bridge", key.constData());
u_free(arg); ++failed; continue;
}
++queued;
}
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Sound settings applied locally: enabled=%d volume=%d queued=%u failed=%u",
enabled, m_volumeSlider->value(), queued, failed);
}
+17 -11
View File
@@ -1,4 +1,5 @@
/* Форма звуков уведомлений: общий enable/volume и индивидуальные настройки событий SoundManager. */
/* GUI-форма звуков уведомлений: общий enable/volume и восемь событий SoundManager.
* После создания вызвать loadFromDb; applyAndSave применяет значения локально и асинхронно сохраняет через GUI bridge. */
#pragma once
#include <QWidget>
@@ -11,23 +12,28 @@ class QLabel;
class SoundSettingsPage : public QWidget {
Q_OBJECT
public:
/* db заимствован до уничтожения формы; nullptr допустим, но loadFromDb тогда ничего не делает. */
explicit SoundSettingsPage(DbManager* db, QWidget* parent = nullptr);
/* GUI: заполнить контролы из ui_state (с defaults), не меняя SoundManager. */
void loadFromDb();
/* GUI: немедленно обновить SoundManager и передать мосту отдельные снимки key/value.
* Отказ постановки освобождает запрос здесь, отмена — в мосте, выполнение — в callback ядра.
* Возврат не подтверждает запись в БД; частичные ошибки логируются, локальные значения сохраняются. */
void applyAndSave();
private:
struct EventRow {
const char* key;
const char* label;
QCheckBox* check = nullptr;
QSlider* slider = nullptr;
QLabel* volLabel = nullptr;
const char* key; // Статическое имя события и суффикс ключей ui_state.
const char* label; // Статический исходный текст для перевода.
QCheckBox* check = nullptr; // Дочерний контрол включения события.
QSlider* slider = nullptr; // Дочерний контрол громкости 0..100.
QLabel* volLabel = nullptr; // Дочерняя подпись громкости в процентах.
};
DbManager* m_db = nullptr;
QCheckBox* m_enabledCheck;
QSlider* m_volumeSlider;
QLabel* m_volumeLabel;
EventRow m_events[8];
DbManager* m_db = nullptr; // Заимствованный читатель БД, нужен только loadFromDb.
QCheckBox* m_enabledCheck; // Общий enable звуков, дочерний виджет.
QSlider* m_volumeSlider; // Общая громкость 0..100, дочерний виджет.
QLabel* m_volumeLabel; // Общая громкость в процентах, дочерний виджет.
EventRow m_events[8]; // Имена и контролы восьми событий уведомлений.
};
@@ -10,6 +10,7 @@
#include <cstring>
extern "C" {
#include "utun_instance.h"
#include "chat/chat_core.h"
#include "mem.h"
#include "debug_config.h"
}