aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2026-09-19 14:23:07 +0200
committersaturneric <[email protected]>2026-09-19 14:23:07 +0200
commit92f4cb0cecfa9887d3ab7395c9a88de7ec69266d (patch)
treee4e4c200e613855b006a7770e8ae3235fd2f4344
parentfix(modules): correct module lifecycle setup (diff)
downloadmodules-92f4cb0cecfa9887d3ab7395c9a88de7ec69266d.tar.gz
modules-92f4cb0cecfa9887d3ab7395c9a88de7ec69266d.zip
refactor(module): relocate module author headers
- remove duplicated module author headers from the top-level include path - rely on gf_module_runtime to expose the runtime-owned interfaces - keep only SDK headers in the global include directories
-rw-r--r--CMakeLists.txt4
-rw-r--r--include/GFModule.h65
-rw-r--r--include/GFModuleBootstrap.h133
-rw-r--r--include/GFModuleCommonUtils.hpp37
-rw-r--r--include/GFModuleConvert.h216
-rw-r--r--include/GFModuleDefine.h35
-rw-r--r--include/GFModuleEvent.h236
-rw-r--r--include/GFModuleExport.h69
-rw-r--r--include/GFModuleI18n.h102
-rw-r--r--include/GFModuleLog.h77
-rw-r--r--include/GFModuleMemory.h215
11 files changed, 3 insertions, 1186 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e6d13a4..863b04c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,8 +68,10 @@ set(SDK_LIB_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
message(STATUS "GpgFrontend Modules SDK Headers Path: ${SDK_INCLUDE_PATH} ")
message(STATUS "GpgFrontend Modules SDK Library Path: ${SDK_LIB_PATH} ")
+# The module author surface now lives with the runtime that implements it
+# (src/module_runtime/include), and gf_add_module() puts it on the path by
+# linking gf_module_runtime. Only the SDK headers are still needed here.
include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
${SDK_INCLUDE_PATH}
)
diff --git a/include/GFModule.h b/include/GFModule.h
deleted file mode 100644
index 740ed81..0000000
--- a/include/GFModule.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-/**
- * @file GFModule.h
- * @brief The one header a module includes.
- *
- * Everything a module needs, grouped by what it is for. Include this; the
- * individual headers are there for when you want to see what is in each area,
- * not because you have to pick.
- *
- * | Header | What lives there |
- * | ----------------- | ------------------------------------------------ |
- * | GFModuleLog.h | `LOG_*`, `FLOG_*`, `MLog*` |
- * | GFModuleEvent.h | `LISTEN`, `CB_*`, handlers, event conversion |
- * | GFModuleI18n.h | translation context and `.qm` reader |
- * | GFModuleMemory.h | who frees what: `DUP`/`UDUP`, SDK allocation |
- * | GFModuleConvert.h | QString/QMap <-> C, `FormatString` |
- *
- * Deliberately NOT here: `GFModuleBootstrap.h`, and through it the generated
- * `GFModuleIdentity.h`. Exactly one translation unit per module bootstraps, so
- * only that one includes it. Everything else -- including the sources a
- * module's own gtest target compiles without the SDK -- then builds without
- * needing anything generated.
- *
- * A module declares itself in `module.json` beside its `CMakeLists.txt`, and
- * `gf_add_module()` turns that one file into the generated identity, the
- * translation wiring and the signed package. Nothing about a module's identity
- * is written twice.
- */
-
-#include "GFModuleConvert.h"
-#include "GFModuleEvent.h"
-#include "GFModuleExport.h"
-#include "GFModuleI18n.h"
-#include "GFModuleLog.h"
-#include "GFModuleMemory.h"
-#include "GFSDKBuildInfo.h"
diff --git a/include/GFModuleBootstrap.h b/include/GFModuleBootstrap.h
deleted file mode 100644
index c1a2642..0000000
--- a/include/GFModuleBootstrap.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKModuleApi.h>
-
-#include "GFModuleExport.h"
-#include "GFModuleIdentity.h"
-#include "GFSDKBuildInfo.h"
-
-/**
- * @file GFModuleBootstrap.h
- * @brief Define a module through the single bootstrap symbol.
- *
- * Replaces GF_MODULE_API_DECLARE + GF_MODULE_API_DEFINE, which between them
- * required a module to export ten separate symbols. Here a module exports
- * exactly one, and describes itself through a versioned table.
- *
- * WHAT A MODULE GAINS. The host hands `activate` a GFHostApi table instead of
- * the module linking ~130 global SDK symbols. That is what makes it possible
- * for the host to withhold a capability (hand over a table with the gpg group
- * null), and what lets a test supply its own table instead of compiling a
- * parallel set of stub symbols that drift from the real SDK.
- *
- * USAGE, once per module, with no arguments at all:
- *
- * GF_MODULE_BOOTSTRAP()
- *
- * Identity comes from the generated GFModuleIdentity.h, which is built from
- * the module's own module.json.
- *
- * The host api pointer is stashed in GFHost() for the module's own code to
- * reach without threading it through every function. It is valid from the
- * moment activate() is called until the module is unloaded.
- */
-
-/// The host table this module was activated with. Null before activation.
-inline const GFHostApi*& GFHostApiSlot() {
- static const GFHostApi* host = nullptr;
- return host;
-}
-
-/// Convenience accessor for module code.
-inline auto GFHost() -> const GFHostApi* { return GFHostApiSlot(); }
-
-/**
- * @brief Define this module's bootstrap symbol, lifecycle table and identity.
- *
- * Takes no arguments. Everything it needs comes from `GFModuleIdentity.h`,
- * which `gf_add_module()` generates from the module's `module.json` -- so the
- * identifier and version the host cross-checks against the signed manifest
- * cannot disagree with it, because there is only one copy.
- *
- * It replaces `GF_MODULE_BOOTSTRAP_V2(id, name, ver, desc, author)`, whose
- * five arguments were the C++ half of the same five values the CMake call
- * repeated. Three of them -- name, description, author -- fed only
- * `GFGetModuleMetaData()`, which had no callers at all: the host reads that
- * metadata from the verified package manifest instead. So they are simply
- * gone, rather than moved.
- *
- * The module still writes its lifecycle functions under their classic names --
- * GFRegisterModule, GFActiveModule, GFExecuteModule, GFDeactivateModule,
- * GFUnregisterModule -- and this adapts them onto the table.
- *
- * Note the ORDER inside activate: the host's table has no separate register
- * step, so whatever the module did in GFRegisterModule -- typically
- * registering its translator -- has to run here, before GFActiveModule starts
- * subscribing to events.
- */
-#define GF_MODULE_BOOTSTRAP() \
- /* Identity strings are BORROWED statics, not fresh allocations. */ \
- /* They used to be DUP(...)ed on every call because the SDK entry points */ \
- /* they were passed to freed their arguments. Now that arguments are */ \
- /* borrowed, allocating here would simply leak -- and GFGetModuleID() is */ \
- /* called on the order of seventy times across the modules. */ \
- auto GFGetModuleID() -> const char* { return GF_MODULE_ID; } \
- using MEvent = QMap<QString, QString>; \
- using EventHandler = std::function<int(const MEvent&)>; \
- namespace { \
- static QMap<QString, EventHandler> gModuleEventHandlers; \
- static QMap<QString, EventHandler>& _gr_module_event_handlers = \
- gModuleEventHandlers; \
- } \
- DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL \
- static int GFBootstrapActivate(const GFHostApi* host, void*) { \
- GFHostApiSlot() = host; \
- const int rc = GFRegisterModule(); \
- if (rc != 0) return rc; \
- return GFActiveModule(); \
- } \
- static void GFBootstrapUnregister() { (void)GFUnregisterModule(); } \
- extern "C" GF_MODULE_EXPORT const GFModuleApi* GFModuleGetApi( \
- uint32_t host_abi) { \
- /* Decline a host outside the range this module was built for, rather */ \
- /* than loading and failing on the first mismatched call. */ \
- if (host_abi < GF_SDK_ABI_MIN_SUPPORTED || \
- host_abi > GF_SDK_ABI_VERSION) { \
- return nullptr; \
- } \
- /* Static: the host borrows this table and never frees it. */ \
- static const GFModuleApi kApi = { \
- sizeof(GFModuleApi), GF_SDK_ABI_VERSION, GF_MODULE_ID, \
- GF_MODULE_VERSION, &GFBootstrapActivate, &GFExecuteModule, \
- &GFDeactivateModule, &GFBootstrapUnregister, \
- }; \
- return &kApi; \
- }
diff --git a/include/GFModuleCommonUtils.hpp b/include/GFModuleCommonUtils.hpp
deleted file mode 100644
index ca224fa..0000000
--- a/include/GFModuleCommonUtils.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-// DEPRECATED. This header's contents were split by concern into GFModule.h and
-// the five headers it pulls in. It remains for one cycle so that a module can
-// be ported without being rewritten in the same commit.
-//
-// Include "GFModule.h" instead.
-
-#include "GFModule.h"
diff --git a/include/GFModuleConvert.h b/include/GFModuleConvert.h
deleted file mode 100644
index f803e93..0000000
--- a/include/GFModuleConvert.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKBasic.h>
-#include <GFSDKModule.h>
-#include <GFSDKUI.h>
-#include <GFSDKUIModel.h>
-
-#include <QMap>
-#include <QString>
-#include <QStringList>
-#include <QVariant>
-#include <cstring>
-#include <string>
-#include <type_traits>
-
-#include "GFModuleMemory.h"
-
-/**
- * @file GFModuleConvert.h
- * @brief Moving values across the C boundary, and formatting strings.
- *
- * Everything here converts between what a module works in (QString, QMap,
- * QList) and what the SDK speaks (char*, null-terminated arrays, linked
- * lists). The ownership rules that apply are in GFModuleMemory.h and are not
- * repeated: as a rule of thumb, a `Convert...ToMap` consumes what it is given
- * and a `ConvertMapTo...` produces something the callee will own.
- */
-
-// ---------------------------------------------------------------- formatting
-
-inline auto FormatStringHelper(const QString& format, const std::string& arg)
- -> QString {
- return format.arg(QString::fromStdString(arg));
-}
-
-template <typename T>
-auto FormatStringHelper(const QString& format, T arg) -> QString {
- return format.arg(arg);
-}
-
-template <typename... Args>
-auto FormatStringHelper(const QString& format, const std::string& arg,
- Args... args) -> QString {
- return FormatStringHelper(format.arg(QString::fromStdString(arg)), args...);
-}
-
-template <typename T, typename... Args>
-auto FormatStringHelper(const QString& format, T arg, Args... args) -> QString {
- return FormatStringHelper(format.arg(arg), args...);
-}
-
-inline auto FormatStringHelper(const QString& format) -> QString {
- return format;
-}
-
-template <typename T>
-inline auto FormatStringHelper(const T& format) ->
- typename std::enable_if<std::is_same<T, std::string>::value,
- QString>::type {
- return FormatStringHelper(QString::fromStdString(format));
-}
-
-/// Qt-style `%1`/`%2` substitution. NOTE: `%1`, not printf's `%s`.
-template <typename... Args>
-auto FormatString(const QString& format, Args... args) -> QString {
- return FormatStringHelper(format, args...);
-}
-
-// ------------------------------------------------------------------ metadata
-
-inline auto QMapToMetaDataArray(const QMap<QString, QString>& map)
- -> MetaData** {
- auto** meta_data_array =
- static_cast<MetaData**>(GFAllocateMemory(sizeof(MetaData*) * map.size()));
-
- int index = 0;
- for (auto it = map.begin(); it != map.end(); ++it) {
- meta_data_array[index] =
- static_cast<MetaData*>(GFAllocateMemory(sizeof(MetaData)));
-
- QByteArray const key = it.key().toUtf8();
- QByteArray const value = it.value().toUtf8();
-
- meta_data_array[index]->key = GFModuleStrDup(key);
- meta_data_array[index]->value = GFModuleStrDup(value);
-
- ++index;
- }
-
- return meta_data_array;
-}
-
-// -------------------------------------------------------------- arrays, lists
-
-inline auto CharArrayToQStringList(char** pl_components, int size)
- -> QStringList {
- QStringList list;
- for (int i = 0; i < size; ++i) {
- list.append(UDUP(pl_components[i]));
- }
- GFFreeMemory(static_cast<void*>(pl_components));
- return list;
-}
-
-inline auto QStringListToCharArray(const QStringList& list) -> char** {
- char** char_array =
- static_cast<char**>(GFAllocateMemory(list.size() * sizeof(char*)));
-
- int index = 0;
- for (const QString& item : list) {
- QByteArray value = item.toUtf8();
- char_array[index] = static_cast<char*>(GFAllocateMemory(value.size() + 1));
- std::strcpy(char_array[index], value.constData());
- index++;
- }
-
- return char_array;
-}
-
-template <typename T>
-inline auto ArrayToQList(T** pl_components, int size) -> QList<T> {
- if (pl_components == nullptr || size <= 0) {
- return QList<T>();
- }
-
- QList<T> list;
- for (int i = 0; i < size; ++i) {
- list.append(*pl_components[i]);
- GFFreeMemory(pl_components[i]);
- }
- GFFreeMemory(pl_components);
- return list;
-}
-
-template <typename T>
-inline auto QListToArray(const QList<T>& list) -> T** {
- T** array = static_cast<T**>(GFAllocateMemory(list.size() * sizeof(T*)));
- int index = 0;
- for (const T& item : list) {
- auto mem = static_cast<T*>(GFAllocateMemory(sizeof(T)));
- array[index] = new (mem) T(item);
- index++;
- }
-
- return array;
-}
-
-// ------------------------------------------------------------------- QVariant
-
-inline auto ConvertQVariantToVoidPtr(const QVariant& variant) -> void* {
- void* mem = GFAllocateMemory(sizeof(QVariant));
- auto* variant_ptr = new (mem) QVariant(variant);
- return static_cast<void*>(variant_ptr);
-}
-
-inline auto ConvertVoidPtrToQVariant(void* ptr) -> QVariant {
- if (ptr == nullptr) return {};
-
- auto* variant_ptr = static_cast<QVariant*>(ptr);
- QVariant variant = *variant_ptr;
-
- GFFreeMemory(variant_ptr);
- return variant;
-}
-
-// --------------------------------------------------------------- gui objects
-
-template <typename T>
-auto GFUIGetGUIObjectAs(const QString& handle) -> T* {
- auto* obj =
- static_cast<QObject*>(GFUIGetGUIObject(handle.toUtf8().constData()));
- if (!obj) {
- return nullptr;
- }
- return qobject_cast<T*>(obj);
-}
-
-#define Q_VARIANT_Q_OBJECT_FACTORY_DECLARE(name) \
- auto name(void* data_raw_ptr) -> void*;
-
-#define Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(name, func) \
- auto name(void* data_raw_ptr) -> void* { \
- auto data = ConvertVoidPtrToQVariant(data_raw_ptr); \
- return func(data); \
- }
-
-#define GUI_OBJECT(factory, data) \
- GFUICreateGUIObject(factory, ConvertQVariantToVoidPtr(data))
diff --git a/include/GFModuleDefine.h b/include/GFModuleDefine.h
deleted file mode 100644
index 0392960..0000000
--- a/include/GFModuleDefine.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-// DEPRECATED. Its two includes are what GFModule.h does properly.
-//
-// Include "GFModule.h" instead.
-
-#include "GFModule.h"
diff --git a/include/GFModuleEvent.h b/include/GFModuleEvent.h
deleted file mode 100644
index 1ac6614..0000000
--- a/include/GFModuleEvent.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKBasic.h>
-#include <GFSDKModule.h>
-
-#include <QMap>
-#include <QString>
-#include <functional>
-
-#include "GFModuleConvert.h"
-#include "GFModuleMemory.h"
-
-/**
- * @file GFModuleEvent.h
- * @brief Subscribing to events, handling them, and answering them.
- *
- * A module says what it wants to hear with LISTEN(), declares a handler per
- * event with REGISTER_EVENT_HANDLER(), and answers with CB_SUCC() or CB_ERR().
- * The dispatch table in between is generated by
- * DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL, which the bootstrap
- * macro expands for you -- a module does not normally write it out.
- *
- * Every one of these expands GFGetModuleID(), which is why that accessor is
- * the one piece of generated identity that still exists.
- */
-
-/**
- * @brief This module's identifier.
- *
- * Declared here because this header's macros are what call it. It is *defined*
- * by GF_MODULE_BOOTSTRAP() in exactly one translation unit per module, from
- * the identifier in module.json -- so a second copy cannot exist to disagree
- * with the signed manifest the host checks it against.
- */
-auto GFGetModuleID() -> const char*;
-
-/**
- * @brief The lifecycle functions every module defines.
- *
- * Written out rather than produced by a macro. `GF_MODULE_API_DECLARE` used to
- * expand to eleven of these, six of which described entry points the host
- * stopped resolving when the bootstrap table replaced them -- so the
- * declarations outlived the functions and nothing noticed, because a
- * declaration nobody defines costs nothing until somebody calls it.
- *
- * GF_MODULE_BOOTSTRAP() adapts these onto the table the host actually uses.
- */
-extern "C" {
-auto GFRegisterModule() -> int;
-auto GFActiveModule() -> int;
-auto GFExecuteModule(GFModuleEvent*) -> int;
-auto GFDeactivateModule() -> int;
-auto GFUnregisterModule() -> int;
-}
-
-/// Subscribe to an event by id.
-///
-/// No DUP: SDK arguments are borrowed, so pre-allocating here would leak.
-#define LISTEN(event) GFModuleListenEvent(GFGetModuleID(), (event))
-
-// ------------------------------------------------------------- conversions
-
-inline auto ConvertEventParamsToMap(GFModuleEventParam* params)
- -> QMap<QString, QString> {
- QMap<QString, QString> param_map;
- GFModuleEventParam* current = params;
- GFModuleEventParam* last;
-
- while (current != nullptr) {
- const auto name = UDUP(current->name);
- const auto value = USECDUP(current->value);
-
- if (!name.isEmpty()) param_map[name] = value;
-
- last = current;
- current = current->next;
- GFFreeMemory(last);
- }
-
- return param_map;
-}
-
-inline auto ConvertMapToParams(const QMap<QString, QString>& param_map)
- -> GFModuleEventParam* {
- GFModuleEventParam* head = nullptr;
- GFModuleEventParam* prev = nullptr;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
- for (const auto& [key, value] : param_map.asKeyValueRange()) {
- auto* param = static_cast<GFModuleEventParam*>(
- GFAllocateMemory(sizeof(GFModuleEventParam)));
-
- param->name = DUP(key.toUtf8());
- param->value = SECDUP(value.toUtf8());
- param->next = nullptr;
-
- if (prev == nullptr) {
- head = param;
- } else {
- prev->next = param;
- }
- prev = param;
- }
-#else
- for (auto it = param_map.keyValueBegin(); it != param_map.keyValueEnd();
- ++it) {
- auto* param = static_cast<GFModuleEventParam*>(
- GFAllocateMemory(sizeof(GFModuleEventParam)));
-
- param->name = DUP(it->first.toUtf8());
- param->value = SECDUP(it->second.toUtf8());
- param->next = nullptr;
-
- if (prev == nullptr) {
- head = param;
- } else {
- prev->next = param;
- }
- prev = param;
- }
-#endif
-
- return head;
-}
-
-inline auto ConvertEventToMap(GFModuleEvent* event) -> QMap<QString, QString> {
- QMap<QString, QString> event_map;
-
- event_map["event_id"] = UDUP(event->id);
- event_map["trigger_id"] = UDUP(event->trigger_id);
- event_map.insert(ConvertEventParamsToMap(event->params));
-
- GFFreeMemory(event);
-
- return event_map;
-}
-
-inline auto ConvertMapToEvent(QMap<QString, QString> event_map)
- -> GFModuleEvent* {
- auto* event =
- static_cast<GFModuleEvent*>(GFAllocateMemory(sizeof(GFModuleEvent)));
-
- event->id = DUP(event_map["event_id"].toUtf8());
- event->trigger_id = DUP(event_map["trigger_id"].toUtf8());
- event->params = nullptr;
-
- return event;
-}
-
-// ---------------------------------------------------------------- answering
-
-inline void CB(const QMap<QString, QString>& event, const char* module,
- const QMap<QString, QString>& params) {
- GFModuleTriggerModuleEventCallback(ConvertMapToEvent(event), module,
- ConvertMapToParams(params));
-}
-
-#undef CB_SUCC
-/// Answer an event with success, and return from the handler.
-#define CB_SUCC(event) \
- { \
- CB(event, GFGetModuleID(), {{"ret", "0"}}); \
- return 0; \
- }
-
-#undef CB_ERR
-/// Answer an event with a failure, and return that code from the handler.
-#define CB_ERR(event, ret, err) \
- { \
- CB(event, GFGetModuleID(), \
- {{"ret", QString::number(ret)}, {"err", QString(err)}}); \
- return ret; \
- }
-
-#undef CB_ERR_NO_RET
-/// The same, without returning -- for a handler with cleanup still to do.
-#define CB_ERR_NO_RET(event, ret, err) \
- { \
- CB(event, GFGetModuleID(), \
- {{"ret", QString::number(ret)}, {"err", QString(err)}}); \
- }
-
-// ----------------------------------------------------------------- dispatch
-
-#define EXECUTE_MODULE() \
- auto GFExecuteModule(GFModuleEvent* p_event) -> int { \
- auto event = ConvertEventToMap(p_event);
-
-#define END_EXECUTE_MODULE() }
-
-#define DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL \
- EXECUTE_MODULE() { \
- auto event_id = event["event_id"]; \
- auto it = _gr_module_event_handlers.find(event_id); \
- if (it != _gr_module_event_handlers.end()) { \
- return it.value()(event); \
- } \
- CB_ERR(event, -1, QString("unsupported event id: %1").arg(event_id)); \
- } \
- END_EXECUTE_MODULE()
-
-/// Register a handler for one event id, at static-initialisation time.
-#define REGISTER_EVENT_HANDLER(event_id, handler) \
- namespace { \
- auto _gv_register_event_handler_by_id_##event_id = []() -> const bool { \
- _gr_module_event_handlers[#event_id] = handler; \
- return true; \
- }(); \
- }
diff --git a/include/GFModuleExport.h b/include/GFModuleExport.h
deleted file mode 100644
index fe61b89..0000000
--- a/include/GFModuleExport.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Copyright (C) 2021-2026 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#ifndef GF_MODULE_EXPORT_H
-#define GF_MODULE_EXPORT_H
-
-#ifdef GF_MODULE_STATIC_DEFINE
-#define GF_MODULE_EXPORT
-#define GF_MODULE_NO_EXPORT
-#else
-#ifndef GF_MODULE_EXPORT
-#ifdef GF_MODULE_EXPORTS
-/* We are building this library */
-#define GF_MODULE_EXPORT __attribute__((visibility("default")))
-#else
-/* We are using this library */
-#define GF_MODULE_EXPORT __attribute__((visibility("default")))
-#endif
-#endif
-
-#ifndef GF_MODULE_NO_EXPORT
-#define GF_MODULE_NO_EXPORT __attribute__((visibility("hidden")))
-#endif
-#endif
-
-#ifndef GF_MODULE_DEPRECATED
-#define GF_MODULE_DEPRECATED __attribute__((__deprecated__))
-#endif
-
-#ifndef GF_MODULE_DEPRECATED_EXPORT
-#define GF_MODULE_DEPRECATED_EXPORT GF_MODULE_EXPORT GF_MODULE_DEPRECATED
-#endif
-
-#ifndef GF_MODULE_DEPRECATED_NO_EXPORT
-#define GF_MODULE_DEPRECATED_NO_EXPORT GF_MODULE_NO_EXPORT GF_MODULE_DEPRECATED
-#endif
-
-#if 0 /* DEFINE_NO_DEPRECATED */
-#ifndef GF_MODULE_NO_DEPRECATED
-#define GF_MODULE_NO_DEPRECATED
-#endif
-#endif
-
-#endif /* GF_MODULE_EXPORT_H */
diff --git a/include/GFModuleI18n.h b/include/GFModuleI18n.h
deleted file mode 100644
index 613f12c..0000000
--- a/include/GFModuleI18n.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKBasic.h>
-
-#include <QCoreApplication>
-#include <QFile>
-#include <QIODevice>
-#include <QString>
-
-#include "GFModuleLog.h"
-#include "GFModuleMemory.h"
-
-/**
- * @file GFModuleI18n.h
- * @brief Translating a module's own strings.
- *
- * A module compiles its `.qm` files into itself as Qt resources, and hands
- * them to the host on request. Two lines set that up:
- *
- * DEFINE_TRANSLATIONS_STRUCTURE() // once, at file scope
- * REGISTER_TRANS_READER() // once, during activation
- *
- * The context name is no longer passed in. It comes from
- * `GF_MODULE_TRANSLATION_CONTEXT`, generated from `module.json` and supplied by
- * `GFModuleIdentity.h` -- which this header does not include, because a macro
- * is expanded where it is used: the one translation unit that bootstraps has
- * that definition, and no other source needs it. It comes from one place
- * because it used to be written out three times -- here, in
- * `gpgfrontend_collect_ts_files` and in the `.ts` filenames -- and nothing
- * checked that the three agreed. A context that disagrees with its `.ts` files
- * does not fail to build; it silently produces a module that is never
- * translated.
- */
-
-#define GF_CONCATENATE_DETAIL(x, y) x##y
-#define GF_CONCATENATE(x, y) GF_CONCATENATE_DETAIL(x, y)
-#define GF_STRINGIFY(x) #x
-#define GF_TOSTRING(x) GF_STRINGIFY(x)
-
-/// Mark a string for translation in the module's own context.
-#define GC_TR(text) QT_TRANSLATE_NOOP("GTrC", text)
-
-#define GTRC_TR(name, src) GF_CONCATENATE(GTrC_, name)::tr(src)
-#define GTRC_AS_STRING(name) GF_TOSTRING(GTrC_##name)
-
-/**
- * @brief Define the module's translation context and its `.qm` reader.
- *
- * Expands at file scope, once per module. The reader is what
- * REGISTER_TRANS_READER() hands to the host.
- */
-#define DEFINE_TRANSLATIONS_STRUCTURE() \
- class GTrC { \
- Q_DECLARE_TR_FUNCTIONS(GTrC) \
- }; \
- auto TranslatorDataReader(const char* p_l, char** p_d) -> int { \
- auto locale = QString::fromUtf8(p_l == nullptr ? "" : p_l); \
- QFile f(QString(":/i18n/%2.%1.qm") \
- .arg(locale) \
- .arg(GF_MODULE_TRANSLATION_CONTEXT)); \
- if (f.exists() && f.open(QIODevice::ReadOnly)) { \
- auto b = f.readAll(); \
- *p_d = AllocBufferAndCopy(b); \
- return b.size(); \
- } \
- FLOG_WARN("%3 loading, locale: %1, not found", locale, f.fileName(), \
- QString::fromUtf8(GFGetModuleID())); \
- *p_d = nullptr; \
- return 0; \
- }
-
-/// Tell the host where to get this module's translations.
-#define REGISTER_TRANS_READER() \
- GFAppRegisterTranslatorReader(GFGetModuleID(), TranslatorDataReader)
diff --git a/include/GFModuleLog.h b/include/GFModuleLog.h
deleted file mode 100644
index 0024ca9..0000000
--- a/include/GFModuleLog.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKLog.h>
-
-#include <QString>
-
-#include "GFModuleConvert.h"
-
-/**
- * @file GFModuleLog.h
- * @brief Logging from inside a module.
- *
- * Two families, differing only in whether they take arguments:
- *
- * LOG_INFO("started");
- * FLOG_INFO("started with %1 accounts", count);
- *
- * The placeholders are Qt's `%1`, `%2`, ... and **not** printf's `%s`/`%d`.
- * Passing a printf format produces a message with the format string in it
- * rather than the value, which is the most common mistake made here.
- *
- * ## The levels are real levels
- *
- * They were not. `LOG_INFO`, `LOG_WARN` and `LOG_ERROR` all expanded to
- * `MLogDebug`, so 58 call sites across the modules -- 46 of them `LOG_ERROR`
- * -- were emitted at debug level and never appeared at any higher one. Every
- * module author who logged an error and saw nothing was looking at this. The
- * `FLOG_*` forms were always correct, which is exactly why it went unnoticed:
- * the two families sat beside each other and only one of them worked.
- */
-
-inline void MLogDebug(const QString& s) { GFModuleLogDebug(s.toUtf8()); }
-inline void MLogInfo(const QString& s) { GFModuleLogInfo(s.toUtf8()); }
-inline void MLogWarn(const QString& s) { GFModuleLogWarn(s.toUtf8()); }
-inline void MLogError(const QString& s) { GFModuleLogError(s.toUtf8()); }
-
-#define LOG_DEBUG(format) MLogDebug(FormatString(QString(format)))
-#define LOG_INFO(format) MLogInfo(FormatString(QString(format)))
-#define LOG_WARN(format) MLogWarn(FormatString(QString(format)))
-#define LOG_ERROR(format) MLogError(FormatString(QString(format)))
-
-#define FLOG_DEBUG(format, ...) \
- MLogDebug(FormatString(QString(format), __VA_ARGS__))
-#define FLOG_INFO(format, ...) \
- MLogInfo(FormatString(QString(format), __VA_ARGS__))
-#define FLOG_WARN(format, ...) \
- MLogWarn(FormatString(QString(format), __VA_ARGS__))
-#define FLOG_ERROR(format, ...) \
- MLogError(FormatString(QString(format), __VA_ARGS__))
diff --git a/include/GFModuleMemory.h b/include/GFModuleMemory.h
deleted file mode 100644
index dce58cb..0000000
--- a/include/GFModuleMemory.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Copyright (C) 2021-2024 Saturneric <[email protected]>
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * All the source code of GpgFrontend was modified and released by
- * Saturneric <[email protected]> starting on May 12, 2021.
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#pragma once
-
-#include <GFSDKBasic.h>
-
-#include <QByteArray>
-#include <QSharedPointer>
-#include <QString>
-#include <cstring>
-#include <memory>
-#include <new>
-
-/**
- * @file GFModuleMemory.h
- * @brief Who frees what, and the helpers that make it obvious.
- *
- * ## The rule, in one place
- *
- * **SDK arguments are borrowed.** Pass a pointer straight through --
- * `s.toUtf8().constData()` for a QString -- and keep owning it. Do *not*
- * pre-allocate one to hand over: nothing on the other side will free it. That
- * is what the old `DUP()`/`QDUP()` at call sites was for, and why doing it now
- * simply leaks.
- *
- * The one exception is a struct rather than an argument: the few aggregates a
- * module builds and hands over whole -- `GFModuleEvent`, `GFModuleEventParam`,
- * `GFModuleMetaData`, `GFCommandExecuteContext` -- still transfer, so their
- * `char*` members are still allocated with GFModuleStrDup.
- *
- * **SDK return values are owned.** Reclaim them, which is what the `U...`
- * family below is for.
- */
-
-/// Allocate a copy of @p v that a transferring struct will own.
-#define DUP(v) GFModuleStrDup(v)
-
-/// The same, from the wiping allocator, for a value that is a secret.
-#define SECDUP(v) GFModuleSecStrDup(v)
-
-/// Take ownership of an SDK string and return it as a QString.
-#define UDUP(v) UnStrDup(v)
-
-/// The same, releasing it back to the wiping allocator.
-#define USECDUP(v) UnSecStrDup(v)
-
-/// Take ownership of a sized SDK buffer and return its exact octets.
-#define UDUPN(v, n) UnBytesDup(v, n)
-
-/// Takes ownership of a sized SDK buffer and returns its octets verbatim.
-///
-/// The QString forms below decode UTF-8 and stop at the first NUL, which is
-/// right for identifiers and error strings and wrong for message data: a MIME
-/// entity may be 8bit or binary, and a signature covers exact octets. Anything
-/// that crosses the crypto boundary must use this and the matching @c *N SDK
-/// entry points instead.
-inline auto UnBytesDup(const char* s, size_t size) -> QByteArray {
- if (s == nullptr) return {};
- QByteArray bytes(s, static_cast<qsizetype>(size));
- GFFreeMemory(static_cast<void*>(const_cast<char*>(s)));
- return bytes;
-}
-
-inline auto UnStrDup(const char* s) -> QString {
- auto q_s = QString::fromUtf8(s == nullptr ? "" : s);
- if (s != nullptr) GFFreeMemory(static_cast<void*>(const_cast<char*>(s)));
- return q_s;
-}
-
-inline auto UnSecStrDup(const char* s) -> QString {
- auto q_s = QString::fromUtf8(s == nullptr ? "" : s);
- if (s != nullptr) GFSecFreeMemory(static_cast<void*>(const_cast<char*>(s)));
- return q_s;
-}
-
-inline auto QStrDup(const QString& str) -> char* { return DUP(str.toUtf8()); }
-
-inline auto QSecStrDup(const QString& str) -> char* {
- return SECDUP(str.toUtf8());
-}
-
-/// Copies @p b into an SDK buffer, NUL-terminated one past the end.
-///
-/// The terminator is not optional politeness: the buffer is handed to the
-/// host, and a caller that treats it as a C string would otherwise read past
-/// the allocation. @p b .size() stays authoritative for the byte count.
-inline auto AllocBufferAndCopy(const QByteArray& b) -> char* {
- auto* p = static_cast<char*>(GFAllocateMemory(sizeof(char) * (b.size() + 1)));
- if (p == nullptr) return nullptr;
- memcpy(p, b.constData(), b.size());
- p[b.size()] = '\0';
- return p;
-}
-
-template <typename T>
-class PointerConverter {
- public:
- explicit PointerConverter(void* ptr) : ptr_(ptr) {}
-
- auto AsType() const -> T* { return static_cast<T*>(ptr_); }
-
- private:
- void* ptr_;
-};
-
-/**
- * @brief Construct a T in SDK-allocated memory, freed through the SDK.
- *
- * NAMING. These four used to be called `Secure...`, which said the wrong
- * thing: they allocate from the ORDINARY SDK arena (GFAllocateMemory), not the
- * wiping one (GFSecAllocateMemory). The old names had a comment saying so,
- * which is the weakest possible place to put it -- a name is read every time
- * and a comment once. For anything that must actually be erased, use the
- * secure entry points explicitly or a GFBuf handle.
- */
-template <typename T, typename... Args>
-auto SdkCreateSharedObject(Args&&... args) -> std::shared_ptr<T> {
- void* mem = GFAllocateMemory(sizeof(T));
- if (!mem) throw std::bad_alloc();
-
- try {
- T* obj = new (mem) T(std::forward<Args>(args)...);
- return std::shared_ptr<T>(obj, [](T* ptr) {
- ptr->~T();
- GFFreeMemory(ptr);
- });
- } catch (...) {
- GFFreeMemory(mem);
- throw;
- }
-}
-
-template <typename T, typename... Args>
-auto SdkCreateQSharedObject(Args&&... args) -> QSharedPointer<T> {
- void* mem = GFAllocateMemory(sizeof(T));
- if (!mem) throw std::bad_alloc();
-
- try {
- T* obj = new (mem) T(std::forward<Args>(args)...);
- return QSharedPointer<T>(obj, [](T* ptr) {
- ptr->~T();
- GFFreeMemory(ptr);
- });
- } catch (...) {
- GFFreeMemory(mem);
- throw;
- }
-}
-
-/// Allocate @p size bytes from the ordinary SDK arena, typed.
-template <typename T>
-auto SdkMallocAsType(std::size_t size) -> T* {
- return PointerConverter<T>(GFAllocateMemory(size)).AsType();
-}
-
-/// Resize an SDK allocation, typed.
-template <typename T>
-auto SdkReallocAsType(T* ptr, std::size_t size) -> T* {
- return PointerConverter<T>(GFReallocateMemory(ptr, size)).AsType();
-}
-
-// Deprecated spellings, kept for one cycle so a module can be ported without
-// being rewritten. They allocate from the ordinary arena, exactly as the new
-// names say and the old ones did not.
-template <typename T, typename... Args>
-[[deprecated(
- "renamed to SdkCreateSharedObject: it is not a secure allocation")]]
-auto SecureCreateSharedObject(Args&&... args) -> std::shared_ptr<T> {
- return SdkCreateSharedObject<T>(std::forward<Args>(args)...);
-}
-
-template <typename T, typename... Args>
-[[deprecated(
- "renamed to SdkCreateQSharedObject: it is not a secure allocation")]]
-auto SecureCreateQSharedObject(Args&&... args) -> QSharedPointer<T> {
- return SdkCreateQSharedObject<T>(std::forward<Args>(args)...);
-}
-
-template <typename T>
-[[deprecated("renamed to SdkMallocAsType: it is not a secure allocation")]]
-auto SecureMallocAsType(std::size_t size) -> T* {
- return SdkMallocAsType<T>(size);
-}
-
-template <typename T>
-[[deprecated("renamed to SdkReallocAsType: it is not a secure allocation")]]
-auto SecureReallocAsType(T* ptr, std::size_t size) -> T* {
- return SdkReallocAsType<T>(ptr, size);
-}