diff options
| author | saturneric <[email protected]> | 2026-04-24 18:30:04 +0200 |
|---|---|---|
| committer | saturneric <[email protected]> | 2026-04-24 18:30:04 +0200 |
| commit | da0dfb360a446c135d42d6ad1e6a6c711a61fca5 (patch) | |
| tree | 9ca652c5a2f14e603b2f8651fd67d2781c4fd356 | |
| parent | fix(version-checking): avoid thread race on UI (diff) | |
| download | modules-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.hpp | 17 | ||||
| -rw-r--r-- | src/m_email/EMailModule.cpp | 84 | ||||
| -rw-r--r-- | src/m_gpg_info/GnuPGInfoGatheringModule.cpp | 7 |
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( |
