aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2026-04-24 18:30:04 +0200
committersaturneric <[email protected]>2026-04-24 18:30:04 +0200
commitda0dfb360a446c135d42d6ad1e6a6c711a61fca5 (patch)
tree9ca652c5a2f14e603b2f8651fd67d2781c4fd356
parentfix(version-checking): avoid thread race on UI (diff)
downloadmodules-da0dfb360a446c135d42d6ad1e6a6c711a61fca5.tar.gz
modules-da0dfb360a446c135d42d6ad1e6a6c711a61fca5.zip
fix(email): avoid blocking when opening email file
* Moves file reading and tab creation onto the GUI thread to prevent blocking and potential deadlocks from blocking queued invokes * Uses non-blocking error reporting in async flow to avoid invalid early returns * Skips GnuPG info gathering when `gpgconf` path is missing to prevent pointless work and errors
-rw-r--r--include/GFModuleCommonUtils.hpp17
-rw-r--r--src/m_email/EMailModule.cpp84
-rw-r--r--src/m_gpg_info/GnuPGInfoGatheringModule.cpp7
3 files changed, 67 insertions, 41 deletions
diff --git a/include/GFModuleCommonUtils.hpp b/include/GFModuleCommonUtils.hpp
index 9be8545..3170215 100644
--- a/include/GFModuleCommonUtils.hpp
+++ b/include/GFModuleCommonUtils.hpp
@@ -53,7 +53,7 @@
class GTrC { \
Q_DECLARE_TR_FUNCTIONS(GTrC) \
}; \
- auto TranslatorDataReader(const char* p_l, char** p_d) -> int { \
+ auto TranslatorDataReader(const char* p_l, char** p_d)->int { \
auto locale = UDUP(p_l); \
QFile f(QString(":/i18n/%2.%1.qm").arg(locale).arg(#name)); \
if (f.exists() && f.open(QIODevice::ReadOnly)) { \
@@ -80,8 +80,8 @@
#define TOSTRING(x) STRINGIFY(x)
#define GTRC_AS_STRING(name) TOSTRING(GTrC_##name)
-#define EXECUTE_MODULE() \
- auto GFExecuteModule(GFModuleEvent* p_event) -> int { \
+#define EXECUTE_MODULE() \
+ auto GFExecuteModule(GFModuleEvent* p_event)->int { \
auto event = ConvertEventToMap(p_event);
#define END_EXECUTE_MODULE() }
@@ -101,6 +101,13 @@
return ret; \
}
+#undef CB_ERR_NO_RET
+#define CB_ERR_NO_RET(event, ret, err) \
+ { \
+ CB(event, GFGetModuleID(), \
+ {{"ret", QString::number(ret)}, {"err", QString(err)}}); \
+ }
+
#define DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL \
EXECUTE_MODULE() { \
auto event_id = event["event_id"]; \
@@ -488,10 +495,10 @@ auto GFUIGetGUIObjectAs(const QString& handle) -> T* {
}
#define Q_VARIANT_Q_OBJECT_FACTORY_DECLARE(name) \
- auto name(void* data_raw_ptr) -> void*;
+ auto name(void* data_raw_ptr)->void*;
#define Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(name, func) \
- auto name(void* data_raw_ptr) -> void* { \
+ auto name(void* data_raw_ptr)->void* { \
auto data = ConvertVoidPtrToQVariant(data_raw_ptr); \
return func(data); \
}
diff --git a/src/m_email/EMailModule.cpp b/src/m_email/EMailModule.cpp
index 8bfb730..09be736 100644
--- a/src/m_email/EMailModule.cpp
+++ b/src/m_email/EMailModule.cpp
@@ -63,7 +63,7 @@
#include "EMailBasicGpgOpera.h"
#include "EMailHelper.h"
-GF_MODULE_API_DEFINE_V2("com.bktus.gpgfrontend.module.email", "Email", "1.1.1",
+GF_MODULE_API_DEFINE_V2("com.bktus.gpgfrontend.module.email", "Email", "1.1.2",
"Everything related to E-Mails.", "Saturneric")
DEFINE_TRANSLATIONS_STRUCTURE(ModuleEMail);
@@ -1183,20 +1183,10 @@ REGISTER_EVENT_HANDLER(
if (event["file_path"].isEmpty()) CB_ERR(event, -1, "file_path is empty");
auto file_path = event.value("file_path", "");
-
QFileInfo file_info(file_path);
- QFile file(file_path);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QMessageBox::warning(
- nullptr, QApplication::translate("EMailModule", "Warning"),
- QApplication::translate("EMailModule", "Cannot read file %1:\n%2.")
- .arg(file_path)
- .arg(file.errorString()));
- return -1;
- }
// stop here if file is too large (> 1mb)
- if (file.size() > static_cast<qint64>(1 * 1024 * 1024)) {
+ if (file_info.size() > static_cast<qint64>(1 * 1024 * 1024)) {
QMessageBox::warning(
nullptr, QApplication::translate("EMailModule", "Warning"),
QApplication::translate(
@@ -1204,41 +1194,65 @@ REGISTER_EVENT_HANDLER(
"The file %1 is too large (%2 bytes) to be opened. The "
"maximum allowed size is 1 MB.")
.arg(file_path)
- .arg(file.size()));
+ .arg(file_info.size()));
return -1;
}
auto* edit = GFUIGetGUIObjectAs<QWidget>("main_window_edit");
if (!edit) {
LOG_ERROR(
- "main window menu mounted: main_window_edit handle invalid or not "
+ "main window menu mounted: main_window_edit "
+ "handle invalid or not "
"QWidget");
- CB_ERR(event, -1, "main_window_edit handle invalid or not QWidget");
+ CB_ERR(event, -1,
+ "main_window_edit handle invalid or not "
+ "QWidget");
}
- QWidget* page = nullptr;
+ // Run in GUI thread to avoid blocking the main thread
+ QMetaObject::invokeMethod(QCoreApplication::instance(), [=]() -> void {
+ QFileInfo file_info(file_path);
+ QFile file(file_path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QMessageBox::warning(
+ nullptr, QApplication::translate("EMailModule", "Warning"),
+ QApplication::translate("EMailModule",
+ "Cannot read file %1:\n%2.")
+ .arg(file_path)
+ .arg(file.errorString()));
+ return;
+ }
- auto ok = QMetaObject::invokeMethod(
- edit, "SlotNewCustomTab", Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QWidget*, page), Q_ARG(QString, "email"),
- Q_ARG(QString, file_info.fileName()),
- Q_ARG(QIcon, QIcon(":/icons/email.png")));
+ QWidget* page = nullptr;
- if (!ok || !page) {
- LOG_ERROR("create new email tab page failed");
- CB_ERR(event, -1, "create new email tab page failed");
- }
+ auto ok = QMetaObject::invokeMethod(
+ edit, "SlotNewCustomTab", Qt::DirectConnection,
+ Q_RETURN_ARG(QWidget*, page), Q_ARG(QString, "email"),
+ Q_ARG(QString, file_info.fileName()),
+ Q_ARG(QIcon, QIcon(":/icons/email.png")));
- QPlainTextEdit* text_edit = nullptr;
- ok = QMetaObject::invokeMethod(page, "GetTextPage",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QPlainTextEdit*, text_edit));
- if (!ok || text_edit == nullptr) {
- LOG_ERROR("invoke GetTextPage failed");
- CB_ERR(event, -1, "invoke GetTextPage failed");
- }
+ if (!ok || !page) {
+ LOG_ERROR("create new email tab page failed");
+ CB_ERR_NO_RET(event, -1, "create new email tab page failed");
+ return;
+ }
+
+ QPlainTextEdit* text_edit = nullptr;
+ ok =
+ QMetaObject::invokeMethod(page, "GetTextPage", Qt::DirectConnection,
+ Q_RETURN_ARG(QPlainTextEdit*, text_edit));
+ if (!ok || text_edit == nullptr) {
+ LOG_ERROR("invoke GetTextPage failed");
+ CB_ERR_NO_RET(event, -1, "invoke GetTextPage failed");
+ return;
+ }
+
+ text_edit->setPlainText(
+ QString::fromUtf8(file.readAll()).replace("\r\n", "\n"));
+ text_edit->document()->setModified(false);
- text_edit->setPlainText(
- QString::fromUtf8(file.readAll()).replace("\r\n", "\n"));
+ QMetaObject::invokeMethod(page, "SetFilePath", Qt::DirectConnection,
+ Q_ARG(QString, file_path));
+ });
return 0;
}) \ No newline at end of file
diff --git a/src/m_gpg_info/GnuPGInfoGatheringModule.cpp b/src/m_gpg_info/GnuPGInfoGatheringModule.cpp
index d8c897f..e2d3012 100644
--- a/src/m_gpg_info/GnuPGInfoGatheringModule.cpp
+++ b/src/m_gpg_info/GnuPGInfoGatheringModule.cpp
@@ -54,7 +54,7 @@
#include "GpgInfo.h"
GF_MODULE_API_DEFINE_V2("com.bktus.gpgfrontend.module.gnupg_info_gathering",
- "GatherGnupgInfo", "1.2.1",
+ "GatherGnupgInfo", "1.2.2",
"Try gathering gnupg information.", "Saturneric")
DEFINE_TRANSLATIONS_STRUCTURE(ModuleGnuPGInfoGathering);
@@ -206,6 +206,11 @@ auto StartGatheringAllGnuPGInfo() -> int {
DUP("core"), DUP("gpgme.ctx.gpgconf_path"), DUP("")));
MLogDebug(QString("got gpgconf path from rt: %1").arg(gpgconf_path));
+ if (gpgconf_path.isEmpty()) {
+ MLogDebug("gpgconf path is empty, skip gathering gnupg info.");
+ return -1;
+ }
+
auto default_home_path = UDUP(GFModuleRetrieveRTValueOrDefault(
DUP("core"), DUP("gpgme.ctx.default_database_path"), DUP("")));
MLogDebug(