From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- .../plugin_python/src/mobase/wrappers/wrappers.cpp | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 libs/plugin_python/src/mobase/wrappers/wrappers.cpp (limited to 'libs/plugin_python/src/mobase/wrappers/wrappers.cpp') diff --git a/libs/plugin_python/src/mobase/wrappers/wrappers.cpp b/libs/plugin_python/src/mobase/wrappers/wrappers.cpp new file mode 100644 index 0000000..10f043d --- /dev/null +++ b/libs/plugin_python/src/mobase/wrappers/wrappers.cpp @@ -0,0 +1,120 @@ + +#include "wrappers.h" + +#include "../pybind11_all.h" + +#include +#include +#include +#include + +// IOrganizer must be bring here to properly compile the Python bindings of +// plugin requirements +#include +#include +#include +#include + +using namespace pybind11::literals; +namespace py = pybind11; +using namespace MOBase; + +namespace mo2::python { + + class PyPluginRequirement : public IPluginRequirement { + public: + std::optional check(IOrganizer* organizer) const override + { + PYBIND11_OVERRIDE_PURE(std::optional, IPluginRequirement, check, + organizer); + }; + }; + + class PySaveGame : public ISaveGame { + public: + QString getFilepath() const override + { + PYBIND11_OVERRIDE_PURE(FileWrapper, ISaveGame, getFilepath, ); + } + + QDateTime getCreationTime() const override + { + PYBIND11_OVERRIDE_PURE(QDateTime, ISaveGame, getCreationTime, ); + } + + QString getName() const override + { + PYBIND11_OVERRIDE_PURE(QString, ISaveGame, getName, ); + } + + QString getSaveGroupIdentifier() const override + { + PYBIND11_OVERRIDE_PURE(QString, ISaveGame, getSaveGroupIdentifier, ); + } + + QStringList allFiles() const override + { + return toQStringList([&] { + PYBIND11_OVERRIDE_PURE(QList, ISaveGame, allFiles, ); + }()); + } + + ~PySaveGame() { std::cout << "~PySaveGame()" << std::endl; } + }; + + class PySaveGameInfoWidget : public ISaveGameInfoWidget { + public: + // Bring the constructor: + using ISaveGameInfoWidget::ISaveGameInfoWidget; + + void setSave(ISaveGame const& save) override + { + PYBIND11_OVERRIDE_PURE(void, ISaveGameInfoWidget, setSave, &save); + } + + ~PySaveGameInfoWidget() { std::cout << "~PySaveGameInfoWidget()" << std::endl; } + }; + + void add_wrapper_bindings(pybind11::module_ m) + { + // ISaveGame - custom type_caster<> for shared_ptr<> to keep the Python object + // alive when returned from Python (see shared_cpp_owner.h) + + py::class_>(m, "ISaveGame") + .def(py::init<>()) + .def("getFilepath", wrap_return_for_filepath(&ISaveGame::getFilepath)) + .def("getCreationTime", &ISaveGame::getCreationTime) + .def("getName", &ISaveGame::getName) + .def("getSaveGroupIdentifier", &ISaveGame::getSaveGroupIdentifier) + .def("allFiles", [](ISaveGame* s) -> QList { + const auto result = s->allFiles(); + return {result.begin(), result.end()}; + }); + + // ISaveGameInfoWidget - custom holder to keep the Python object alive alongside + // the widget + + py::class_> + iSaveGameInfoWidget(m, "ISaveGameInfoWidget"); + iSaveGameInfoWidget.def(py::init(), "parent"_a = (QWidget*)nullptr) + .def("setSave", &ISaveGameInfoWidget::setSave, "save"_a); + py::qt::add_qt_delegate(iSaveGameInfoWidget, "_widget"); + + // IPluginRequirement - custom type_caster<> for shared_ptr<> to keep the Python + // object alive when returned from Python (see shared_cpp_owner.h) + + py::class_, + PyPluginRequirement> + iPluginRequirementClass(m, "IPluginRequirement"); + + py::class_(iPluginRequirementClass, "Problem") + .def(py::init(), "short_description"_a, + "long_description"_a = "") + .def("shortDescription", &IPluginRequirement::Problem::shortDescription) + .def("longDescription", &IPluginRequirement::Problem::longDescription); + + iPluginRequirementClass.def("check", &IPluginRequirement::check, "organizer"_a); + } + +} // namespace mo2::python -- cgit v1.3.1