summaryrefslogtreecommitdiffhomepage
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/CMakeLists.txt1
-rw-r--r--api/lang/de_DE.ts11
-rw-r--r--api/lang/nl_NL.ts7
-rw-r--r--api/lang/ru_RU.ts7
-rw-r--r--api/lang/stub.ts7
-rw-r--r--api/lang/zh_CN.ts9
-rw-r--r--api/plugin-api.cpp102
-rw-r--r--api/plugin-api.hpp141
-rw-r--r--api/plugin-support.hpp283
9 files changed, 302 insertions, 266 deletions
diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt
index 0a040a55..1454b89e 100644
--- a/api/CMakeLists.txt
+++ b/api/CMakeLists.txt
@@ -1,3 +1,2 @@
otr_module(api NO-COMPAT BIN)
-target_link_libraries(opentrack-api opentrack-options opentrack-compat)
diff --git a/api/lang/de_DE.ts b/api/lang/de_DE.ts
new file mode 100644
index 00000000..688fe72b
--- /dev/null
+++ b/api/lang/de_DE.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+</context>
+</TS>
diff --git a/api/lang/nl_NL.ts b/api/lang/nl_NL.ts
index 9e739505..91ba449c 100644
--- a/api/lang/nl_NL.ts
+++ b/api/lang/nl_NL.ts
@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="nl_NL">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
</TS>
diff --git a/api/lang/ru_RU.ts b/api/lang/ru_RU.ts
index f62cf2e1..efaaaa47 100644
--- a/api/lang/ru_RU.ts
+++ b/api/lang/ru_RU.ts
@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
</TS>
diff --git a/api/lang/stub.ts b/api/lang/stub.ts
index 6401616d..d29cce1b 100644
--- a/api/lang/stub.ts
+++ b/api/lang/stub.ts
@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
</TS>
diff --git a/api/lang/zh_CN.ts b/api/lang/zh_CN.ts
index 6401616d..26bf67a5 100644
--- a/api/lang/zh_CN.ts
+++ b/api/lang/zh_CN.ts
@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.1">
+<TS version="2.1" language="zh_CN">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
</TS>
diff --git a/api/plugin-api.cpp b/api/plugin-api.cpp
index 6c9a21bc..4d8d90e9 100644
--- a/api/plugin-api.cpp
+++ b/api/plugin-api.cpp
@@ -1,73 +1,77 @@
#include "plugin-api.hpp"
-#include "compat/macros.hpp"
+#include <QCloseEvent>
+#include <QDebug>
-using namespace plugin_api::detail;
+namespace plugin_api::detail {
-// these exist so that vtable is emitted in a single compilation unit, not all of them.
-
-Metadata::~Metadata() {}
-IFilter::~IFilter() {}
-IProtocol::~IProtocol() {}
-ITracker::~ITracker() {}
-IExtension::~IExtension() {}
-
-void ITrackerDialog::register_tracker(ITracker*) {}
-void ITrackerDialog::unregister_tracker() {}
-
-BaseDialog::BaseDialog() {}
-
-void BaseDialog::closeEvent(QCloseEvent*)
+BaseDialog::BaseDialog() = default;
+void BaseDialog::closeEvent(QCloseEvent* e)
{
if (isVisible())
- {
- hide();
emit closing();
- }
-}
-
-bool ITracker::center() { return false; }
-
-module_status ITracker::status_ok()
-{
- return module_status();
-}
-
-module_status ITracker::error(const QString& error)
-{
- return module_status(error);
+ e->accept();
}
-Metadata::Metadata() {}
-IFilter::IFilter() {}
-IFilterDialog::IFilterDialog() {}
-IProtocol::IProtocol() {}
-IProtocolDialog::IProtocolDialog() {}
-ITracker::ITracker() {}
-ITrackerDialog::ITrackerDialog() {}
-
void BaseDialog::done(int)
{
if (isVisible())
- {
- hide();
close();
- }
}
-IExtensionDialog::~IExtensionDialog()
-{
-}
+bool BaseDialog::embeddable() noexcept { return false; }
+void BaseDialog::save() {}
+void BaseDialog::reload() {}
+void BaseDialog::set_buttons_visible(bool) {}
+
+} // ns plugin_api::detail
+
+// these exist so that vtable is emitted in a single compilation unit, not all of them.
+
+Metadata_::Metadata_() = default;
+Metadata_::~Metadata_() = default;
+Metadata::Metadata() = default;
+Metadata::~Metadata() = default;
+
+IFilter::IFilter() = default;
+IFilter::~IFilter() = default;
+IFilterDialog::IFilterDialog() = default;
+IFilterDialog::~IFilterDialog() = default;
+void IFilterDialog::register_filter(IFilter*) {}
+void IFilterDialog::unregister_filter() {}
+IProtocol::IProtocol() = default;
+IProtocol::~IProtocol() = default;
+IProtocolDialog::IProtocolDialog() = default;
+IProtocolDialog::~IProtocolDialog() = default;
+void IProtocolDialog::register_protocol(IProtocol*){}
+void IProtocolDialog::unregister_protocol() {}
+ITracker::ITracker() = default;
+ITracker::~ITracker() = default;
+bool ITracker::center() { return false; }
+ITrackerDialog::ITrackerDialog() = default;
+ITrackerDialog::~ITrackerDialog() = default;
+void ITrackerDialog::register_tracker(ITracker*) {}
+void ITrackerDialog::unregister_tracker() {}
bool module_status::is_ok() const
{
return error.isNull();
}
-
+module_status_mixin::~module_status_mixin() = default;
module_status::module_status(const QString& error) : error(error) {}
-
-module_status module_status_mixin::status_ok() { return module_status(); }
+module_status::module_status() = default;
+module_status module_status_mixin::status_ok() { return {}; }
module_status module_status_mixin::error(const QString& error)
{
- return module_status(error.isEmpty() ? _("Unknown error") : error);
+ return module_status(error.isEmpty() ? tr("Unknown error") : error);
+}
+
+module_status ITracker::status_ok()
+{
+ return module_status();
+}
+
+module_status ITracker::error(const QString& error)
+{
+ return module_status_mixin::error(error);
}
diff --git a/api/plugin-api.hpp b/api/plugin-api.hpp
index 4a797f73..2d77bdf4 100644
--- a/api/plugin-api.hpp
+++ b/api/plugin-api.hpp
@@ -14,20 +14,26 @@
#include <QIcon>
#include <QWidget>
#include <QDialog>
+#include <QCoreApplication>
-#include "compat/simple-mat.hpp"
+#include "../compat/simple-mat.hpp"
+#include "../compat/tr.hpp"
#include "export.hpp"
using Pose = Mat<double, 6, 1>;
-enum Axis {
- TX, TY, TZ, Yaw, Pitch, Roll,
-
+enum Axis : int
+{
NonAxis = -1,
+ TX = 0, TY = 1, TZ = 2,
+
+ Yaw = 3, Pitch = 4, Roll = 5,
+ Axis_MIN = TX, Axis_MAX = 5,
+
+ Axis_COUNT = 6,
};
-namespace plugin_api {
-namespace detail {
+namespace plugin_api::detail {
class OTR_API_EXPORT BaseDialog : public QDialog
{
@@ -36,50 +42,62 @@ protected:
BaseDialog();
public:
void closeEvent(QCloseEvent *) override;
+ virtual bool embeddable() noexcept;
+ virtual void set_buttons_visible(bool x); // XXX TODO remove it once all modules are converted
+ virtual void save(); // XXX HACK should be pure virtual
+ virtual void reload(); // XXX HACK should be pure virtual -sh 20211214
signals:
void closing();
private slots:
void done(int) override;
};
-} // ns
-} // ns
+} // ns plugin_api::detail
#define OTR_PLUGIN_EXPORT OTR_GENERIC_EXPORT
#define OPENTRACK_DECLARE_PLUGIN_INTERNAL(ctor_class, ctor_ret_class, metadata_class, dialog_class, dialog_ret_class) \
- extern "C" OTR_PLUGIN_EXPORT ctor_ret_class* GetConstructor(); \
- extern "C" OTR_PLUGIN_EXPORT Metadata* GetMetadata(); \
- extern "C" OTR_PLUGIN_EXPORT dialog_ret_class* GetDialog(); \
- \
- extern "C" OTR_PLUGIN_EXPORT ctor_ret_class* GetConstructor() \
- { \
- return new ctor_class; \
- } \
- extern "C" OTR_PLUGIN_EXPORT Metadata* GetMetadata() \
- { \
- return new metadata_class; \
- } \
- extern "C" OTR_PLUGIN_EXPORT dialog_ret_class* GetDialog() \
- { \
- return new dialog_class; \
+ extern "C" \
+ { \
+ OTR_PLUGIN_EXPORT ctor_ret_class* GetConstructor(void); \
+ ctor_ret_class* GetConstructor(void) \
+ { \
+ return new ctor_class; \
+ } \
+ OTR_PLUGIN_EXPORT Metadata_* GetMetadata(void); \
+ Metadata_* GetMetadata(void) \
+ { \
+ return new metadata_class; \
+ } \
+ OTR_PLUGIN_EXPORT dialog_ret_class* GetDialog(void); \
+ dialog_ret_class* GetDialog(void) \
+ { \
+ return new dialog_class; \
+ } \
}
// implement this in all plugins
// also you must link against "opentrack-api" in CMakeLists.txt to avoid vtable link errors
-struct OTR_API_EXPORT Metadata
+class OTR_API_EXPORT Metadata_
{
- Metadata(const Metadata&) = delete;
- Metadata(Metadata&&) = delete;
- Metadata& operator=(const Metadata&) = delete;
- Metadata();
+public:
+ Metadata_();
// plugin name to be displayed in the interface
virtual QString name() = 0;
// plugin icon, you can return an empty QIcon()
virtual QIcon icon() = 0;
// optional destructor
- virtual ~Metadata();
+ virtual ~Metadata_();
+};
+
+class OTR_API_EXPORT Metadata : public TR, public Metadata_
+{
+ Q_OBJECT
+
+public:
+ Metadata();
+ ~Metadata() override;
};
struct OTR_API_EXPORT module_status final
@@ -87,7 +105,8 @@ struct OTR_API_EXPORT module_status final
QString error;
bool is_ok() const;
- module_status(const QString& error = QString());
+ module_status();
+ module_status(const QString& error);
};
/*
@@ -99,18 +118,20 @@ struct OTR_API_EXPORT module_status_mixin
static module_status error(const QString& error); // return error message on init failure
virtual module_status initialize() = 0; // where to return from
+ virtual ~module_status_mixin();
+
+ Q_DECLARE_TR_FUNCTIONS(module_status_mixin)
};
// implement this in filters
struct OTR_API_EXPORT IFilter : module_status_mixin
{
IFilter(const IFilter&) = delete;
- IFilter(IFilter&&) = delete;
IFilter& operator=(const IFilter&) = delete;
IFilter();
// optional destructor
- virtual ~IFilter();
+ ~IFilter() override;
// perform filtering step.
// you have to take care of dt on your own, try "opentrack-compat/timer.hpp"
virtual void filter(const double *input, double *output) = 0;
@@ -121,6 +142,7 @@ struct OTR_API_EXPORT IFilter : module_status_mixin
struct OTR_API_EXPORT IFilterDialog : public plugin_api::detail::BaseDialog
{
IFilterDialog();
+ ~IFilterDialog() override;
// optional destructor
//~IFilterDialog() override;
@@ -138,16 +160,14 @@ struct OTR_API_EXPORT IFilterDialog : public plugin_api::detail::BaseDialog
struct OTR_API_EXPORT IProtocol : module_status_mixin
{
IProtocol();
+ ~IProtocol() override;
IProtocol(const IProtocol&) = delete;
- IProtocol(IProtocol&&) = delete;
IProtocol& operator=(const IProtocol&) = delete;
- // optional destructor
- virtual ~IProtocol();
// called 250 times a second with XYZ yaw pitch roll pose
// try not to perform intense computation here. use a thread.
- virtual void pose(const double* headpose) = 0;
+ virtual void pose(const double* pose, const double* raw) = 0;
// return game name or placeholder text
virtual QString game_name() = 0;
};
@@ -162,6 +182,7 @@ struct OTR_API_EXPORT IProtocolDialog : public plugin_api::detail::BaseDialog
virtual void unregister_protocol() = 0;
IProtocolDialog();
+ ~IProtocolDialog() override;
};
// call once with your chosen class names in the plugin
@@ -187,7 +208,6 @@ struct OTR_API_EXPORT ITracker
static module_status error(const QString& error);
ITracker(const ITracker&) = delete;
- ITracker(ITracker&&) = delete;
ITracker& operator=(const ITracker&) = delete;
};
@@ -201,55 +221,10 @@ struct OTR_API_EXPORT ITrackerDialog : public plugin_api::detail::BaseDialog
virtual void unregister_tracker();
ITrackerDialog();
+ ~ITrackerDialog() override;
};
// call once with your chosen class names in the plugin
#define OPENTRACK_DECLARE_TRACKER(tracker_class, dialog_class, metadata_class) \
OPENTRACK_DECLARE_PLUGIN_INTERNAL(tracker_class, ITracker, metadata_class, dialog_class, ITrackerDialog)
-struct OTR_API_EXPORT IExtension : module_status_mixin
-{
- enum event_mask : unsigned
- {
- none = 0u,
- on_raw = 1 << 0,
- on_before_filter = 1 << 1,
- on_before_mapping = 1 << 2,
- on_finished = 1 << 3,
- };
-
- enum event_ordinal : unsigned
- {
- ev_raw = 0,
- ev_before_filter = 1,
- ev_before_mapping = 2,
- ev_finished = 3,
-
- event_count = 4,
- };
-
- IExtension() = default;
- virtual ~IExtension();
-
- virtual event_mask hook_types() = 0;
-
- virtual void process_raw(Pose&) {}
- virtual void process_before_filter(Pose&) {}
- virtual void process_before_mapping(Pose&) {}
- virtual void process_finished(Pose&) {}
-
- IExtension(const IExtension&) = delete;
- IExtension(IExtension&&) = delete;
- IExtension& operator=(const IExtension&) = delete;
-};
-
-struct OTR_API_EXPORT IExtensionDialog : public plugin_api::detail::BaseDialog
-{
- ~IExtensionDialog() override;
-
- virtual void register_extension(IExtension& ext) = 0;
- virtual void unregister_extension() = 0;
-};
-
-#define OPENTRACK_DECLARE_EXTENSION(ext_class, dialog_class, metadata_class) \
- OPENTRACK_DECLARE_PLUGIN_INTERNAL(ext_class, IExtension, metadata_class, dialog_class, IExtensionDialog)
diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp
index 8fc01b98..4300da18 100644
--- a/api/plugin-support.hpp
+++ b/api/plugin-support.hpp
@@ -8,135 +8,124 @@
#pragma once
#include "plugin-api.hpp"
+#include "compat/library-path.hpp"
#include <memory>
#include <algorithm>
#include <cstring>
+#include <vector>
#include <QDebug>
#include <QString>
#include <QLibrary>
-#include <QList>
#include <QDir>
-#include <QList>
#include <QIcon>
-#if defined(__APPLE__)
-# define OPENTRACK_SOLIB_EXT "dylib"
-#elif defined(_WIN32)
-# define OPENTRACK_SOLIB_EXT "dll"
-#else
-# define OPENTRACK_SOLIB_EXT "so"
-#endif
+extern "C" {
+ using module_ctor_t = void* (*)(void);
+ using module_metadata_t = Metadata_* (*)(void);
+}
-#define OPENTRACK_SOLIB_PREFIX "lib"
+enum dylib_load_mode : unsigned
+{
+ dylib_load_norm = 0,
+ dylib_load_quiet = 1 << 0,
+ dylib_load_none = 1 << 1,
+};
-extern "C" typedef void* (*OPENTRACK_CTOR_FUNPTR)(void);
-extern "C" typedef Metadata* (*OPENTRACK_METADATA_FUNPTR)(void);
+enum class dylib_type : unsigned
+{
+ Filter = 0xdeadbabe,
+ Tracker = 0xcafebeef,
+ Protocol = 0xdeadf00d,
+ Video = 0xbadf00d,
+ Invalid = (unsigned)-1,
+};
struct dylib final
{
- enum Type : unsigned
- {
- Filter = 0xdeadbabeu,
- Tracker = 0xcafebeefu,
- Protocol = 0xdeadf00du,
- Extension = 0xdeadf001u,
- Invalid = 0xcafebabeu,
- };
-
- dylib(const QString& filename_, Type t) :
- type(Invalid),
+ dylib(const QString& filename_, dylib_type t, dylib_load_mode load_mode = dylib_load_norm) :
full_filename(filename_),
- module_name(trim_filename(filename_)),
- Dialog(nullptr),
- Constructor(nullptr),
- Meta(nullptr)
+ module_name(trim_filename(filename_))
{
// otherwise dlopen opens the calling executable
- if (filename_.size() == 0 || module_name.size() == 0)
+ if (filename_.isEmpty() || module_name.isEmpty())
return;
handle.setFileName(filename_);
- handle.setLoadHints(QLibrary::DeepBindHint | QLibrary::PreventUnloadHint);
-
- if (check(!handle.load()))
- return;
-
- if (check((Dialog = (OPENTRACK_CTOR_FUNPTR) handle.resolve("GetDialog"), !Dialog)))
- return;
+ handle.setLoadHints(QLibrary::DeepBindHint | QLibrary::ResolveAllSymbolsHint);
- if (check((Constructor = (OPENTRACK_CTOR_FUNPTR) handle.resolve("GetConstructor"), !Constructor)))
- return;
-
- if (check((Meta = (OPENTRACK_METADATA_FUNPTR) handle.resolve("GetMetadata"), !Meta)))
- return;
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcomma"
+#endif
- auto m = std::unique_ptr<Metadata>(Meta());
+ if (!handle.load())
+ goto fail;
- icon = m->icon();
- name = m->name();
+ if (!(load_mode & dylib_load_none))
+ {
+ std::unique_ptr<Metadata_> m;
- type = t;
- }
- ~dylib()
- {
- // QLibrary refcounts the .dll's so don't forcefully unload
- }
+ if (Dialog = (module_ctor_t) handle.resolve("GetDialog"), !Dialog)
+ goto fail;
- static QList<std::shared_ptr<dylib>> enum_libraries(const QString& library_path)
- {
- QDir module_directory(library_path);
- QList<std::shared_ptr<dylib>> ret;
+ if (Constructor = (module_ctor_t) handle.resolve("GetConstructor"), !Constructor)
+ goto fail;
- using str = QLatin1String;
+ if (Meta = (module_metadata_t) handle.resolve("GetMetadata"), !Meta)
+ goto fail;
- static const struct filter_ {
- Type type;
- QLatin1String glob;
- } filters[] = {
- { Filter, str(OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT), },
- { Tracker, str(OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT), },
- { Protocol, str(OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT), },
- { Extension, str(OPENTRACK_SOLIB_PREFIX "opentrack-ext-*." OPENTRACK_SOLIB_EXT), },
- };
+ m = std::unique_ptr<Metadata_>(Meta());
- for (const filter_& filter : filters)
- {
- for (const QString& filename : module_directory.entryList({ filter.glob }, QDir::Files, QDir::Name))
+ if (!m)
{
- std::shared_ptr<dylib> lib = std::make_shared<dylib>(QStringLiteral("%1/%2").arg(library_path).arg(filename), filter.type);
-
- if (lib->type == Invalid)
- continue;
-
- if (std::any_of(ret.cbegin(),
- ret.cend(),
- [&lib](const std::shared_ptr<dylib>& a) {
- return a->type == lib->type && a->name == lib->name;
- }))
+ if (!(load_mode & dylib_load_quiet))
{
- qDebug() << "duplicate lib" << filename << "ident" << lib->name;
- continue;
+ qDebug() << "library" << module_name << "failed: no metadata";
+ load_mode = dylib_load_quiet;
}
-
- ret.push_back(lib);
+ goto fail;
}
+
+ icon = m->icon();
+ name = m->name();
}
+ else
+ name = module_name;
- return ret;
+ type = t;
+
+ return;
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+fail:
+ if (!(load_mode & dylib_load_quiet))
+ qDebug() << "library" << module_name << "failed:" << handle.errorString();
+
+ Constructor = nullptr;
+ Dialog = nullptr;
+ Meta = nullptr;
+
+ type = dylib_type::Invalid;
}
- Type type;
+ // QLibrary refcounts the .dll's so don't forcefully unload
+ ~dylib() = default;
+
+ dylib_type type = dylib_type::Invalid;
QString full_filename;
QString module_name;
QIcon icon;
QString name;
- OPENTRACK_CTOR_FUNPTR Dialog;
- OPENTRACK_CTOR_FUNPTR Constructor;
- OPENTRACK_METADATA_FUNPTR Meta;
+ module_ctor_t Dialog = nullptr;
+ module_ctor_t Constructor = nullptr;
+ module_metadata_t Meta = nullptr;
+
private:
QLibrary handle;
@@ -150,21 +139,21 @@ private:
{
in = in.mid(idx + 1);
- if (in.startsWith(OPENTRACK_SOLIB_PREFIX) &&
- in.endsWith("." OPENTRACK_SOLIB_EXT))
+ if (in.startsWith(OPENTRACK_LIBRARY_PREFIX) &&
+ in.endsWith("." OPENTRACK_LIBRARY_EXTENSION))
{
- constexpr unsigned pfx_len = sizeof(OPENTRACK_SOLIB_PREFIX) - 1;
- constexpr unsigned rst_len = sizeof("." OPENTRACK_SOLIB_EXT) - 1;
+ constexpr unsigned pfx_len = sizeof(OPENTRACK_LIBRARY_PREFIX) - 1;
+ constexpr unsigned rst_len = sizeof("." OPENTRACK_LIBRARY_EXTENSION) - 1;
in = in.mid(pfx_len);
in = in.left(in.size() - rst_len);
- static constexpr const char* const names[] =
+ const char* const names[] =
{
- "opentrack-tracker-",
- "opentrack-proto-",
- "opentrack-filter-",
- "opentrack-ext-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-tracker-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-proto-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-filter-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-video-",
};
for (auto name : names)
@@ -174,74 +163,104 @@ private:
}
}
}
- return QString();
- }
-
- bool check(bool fail)
- {
- if (fail)
- {
- qDebug() << "library" << module_name << "failed:" << handle.errorString();
-
- if (handle.isLoaded())
- (void) handle.unload();
-
- Constructor = nullptr;
- Dialog = nullptr;
- Meta = nullptr;
-
- type = Invalid;
- }
-
- return fail;
+ return {""};
}
};
struct Modules final
{
using dylib_ptr = std::shared_ptr<dylib>;
- using dylib_list = QList<dylib_ptr>;
-
- Modules(const QString& library_path) :
- module_list(dylib::enum_libraries(library_path)),
- filter_modules(filter(dylib::Filter)),
- tracker_modules(filter(dylib::Tracker)),
- protocol_modules(filter(dylib::Protocol)),
- extension_modules(filter(dylib::Extension))
+ using dylib_list = std::vector<dylib_ptr>;
+ using type = dylib_type;
+
+ Modules(const QString& library_path, dylib_load_mode load_mode = dylib_load_norm) :
+ module_list(enum_libraries(library_path, load_mode)),
+ filter_modules(filter(type::Filter)),
+ tracker_modules(filter(type::Tracker)),
+ protocol_modules(filter(type::Protocol)),
+ video_modules(filter(type::Video))
{}
dylib_list& filters() { return filter_modules; }
dylib_list& trackers() { return tracker_modules; }
dylib_list& protocols() { return protocol_modules; }
- dylib_list& extensions() { return extension_modules; }
+
private:
dylib_list module_list;
dylib_list filter_modules;
dylib_list tracker_modules;
dylib_list protocol_modules;
- dylib_list extension_modules;
+ dylib_list video_modules;
static dylib_list& sorted(dylib_list& xs)
{
- std::sort(xs.begin(), xs.end(), [&](const dylib_ptr& a, const dylib_ptr& b) { return a->name.toLower() < b->name.toLower(); });
+ std::sort(xs.begin(), xs.end(),
+ [&](const dylib_ptr& a, const dylib_ptr& b) {
+ return a->name.toLower() < b->name.toLower();
+ });
return xs;
}
- dylib_list filter(dylib::Type t)
+ dylib_list filter(dylib_type t)
{
- QList<std::shared_ptr<dylib>> ret;
- for (auto x : module_list)
+ dylib_list ret; ret.reserve(module_list.size());
+ for (const auto& x : module_list)
if (x->type == t)
ret.push_back(x);
return sorted(ret);
}
+
+ static dylib_list enum_libraries(const QString& library_path,
+ dylib_load_mode load_mode = dylib_load_norm)
+ {
+ QDir dir(library_path);
+ dylib_list ret;
+
+ const struct filter_ {
+ type t = type::Invalid;
+ QString glob;
+ dylib_load_mode load_mode = dylib_load_norm;
+ } filters[] = {
+ { type::Filter, OPENTRACK_LIBRARY_PREFIX "opentrack-filter-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Tracker, OPENTRACK_LIBRARY_PREFIX "opentrack-tracker-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Protocol, OPENTRACK_LIBRARY_PREFIX "opentrack-proto-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Video, OPENTRACK_LIBRARY_PREFIX "opentrack-video-*." OPENTRACK_LIBRARY_EXTENSION, dylib_load_none, },
+ };
+
+ for (const filter_& filter : filters)
+ {
+ for (const QString& filename : dir.entryList({ filter.glob }, QDir::Files, QDir::Name))
+ {
+ dylib_load_mode load_mode_{filter.load_mode | load_mode};
+ auto lib = std::make_shared<dylib>(QString("%1/%2").arg(library_path, filename), filter.t, load_mode_);
+
+ if (lib->type == type::Invalid)
+ continue;
+
+ if (std::any_of(ret.cbegin(),
+ ret.cend(),
+ [&lib](const std::shared_ptr<dylib>& a) {
+ return a->type == lib->type && a->name == lib->name;
+ }))
+ {
+ if (!(load_mode & dylib_load_quiet))
+ qDebug() << "duplicate lib" << filename << "ident" << lib->name;
+ continue;
+ }
+
+ ret.push_back(std::move(lib));
+ }
+ }
+
+ return ret;
+ }
};
template<typename t>
-static inline std::shared_ptr<t> make_dylib_instance(const std::shared_ptr<dylib>& lib)
+std::shared_ptr<t> make_dylib_instance(const std::shared_ptr<dylib>& lib)
{
- std::shared_ptr<t> ret;
if (lib != nullptr && lib->Constructor)
- ret = std::shared_ptr<t>(reinterpret_cast<t*>(reinterpret_cast<OPENTRACK_CTOR_FUNPTR>(lib->Constructor)()));
- return ret;
+ return std::shared_ptr<t>{(t*)lib->Constructor()};
+ else
+ return nullptr;
}