aboutsummaryrefslogtreecommitdiff
path: root/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
commit7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch)
tree27fb39be241fdb5ac2734c574de678977d1856d0 /libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details
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 <noreply@anthropic.com>
Diffstat (limited to 'libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details')
-rw-r--r--libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h59
-rw-r--r--libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h52
-rw-r--r--libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h70
-rw-r--r--libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h221
-rw-r--r--libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h47
5 files changed, 449 insertions, 0 deletions
diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h
new file mode 100644
index 0000000..45afd0c
--- /dev/null
+++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h
@@ -0,0 +1,59 @@
+#ifndef PYTHON_PYBIND11_QT_DETAILS_ENUM_HPP
+#define PYTHON_PYBIND11_QT_DETAILS_ENUM_HPP
+
+#include <type_traits>
+
+#include <pybind11/pybind11.h>
+
+#include "pybind11_qt_utils.h"
+
+namespace pybind11::detail::qt {
+
+ // EnumData, with static members (const char[])
+ // - package: name of the Python package containing the enum (e.g.,
+ // PyQt6.QtCore)
+ // - name: full path to the enum, e.g. Qt.QGlobalColor
+ //
+ template <typename T>
+ struct EnumData;
+
+ // template class for most Qt types that have Python equivalent (QWidget,
+ // etc.)
+ //
+ template <class Enum>
+ struct qt_enum_caster {
+
+ public:
+ PYBIND11_TYPE_CASTER(Enum, EnumData<Enum>::package + const_name(".") +
+ EnumData<Enum>::name);
+
+ bool load(pybind11::handle src, bool)
+ {
+ if (PyLong_Check(src.ptr())) {
+ value = static_cast<Enum>(PyLong_AsLong(src.ptr()));
+ return true;
+ }
+
+ auto pyenum =
+ get_attr_rec(EnumData<Enum>::package.text, EnumData<Enum>::name.text);
+
+ if (isinstance(src, pyenum)) {
+ value = static_cast<Enum>(src.attr("value").cast<int>());
+ return true;
+ }
+
+ return false;
+ }
+
+ static pybind11::handle cast(Enum src,
+ pybind11::return_value_policy /* policy */,
+ pybind11::handle /* parent */)
+ {
+ auto pyenum =
+ get_attr_rec(EnumData<Enum>::package.text, EnumData<Enum>::name.text);
+ return pyenum(static_cast<int>(src));
+ }
+ };
+} // namespace pybind11::detail::qt
+
+#endif
diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h
new file mode 100644
index 0000000..e640725
--- /dev/null
+++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h
@@ -0,0 +1,52 @@
+#ifndef PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP
+#define PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP
+
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+namespace pybind11::detail::qt {
+
+ // helper class for QList to construct from any proper iterable
+ //
+ template <typename Type, typename Value>
+ struct qlist_caster {
+ using value_conv = make_caster<Value>;
+
+ bool load(handle src, bool convert)
+ {
+ if (!isinstance<iterable>(src) || isinstance<bytes>(src) ||
+ isinstance<str>(src)) {
+ return false;
+ }
+ auto s = reinterpret_borrow<iterable>(src);
+ value.clear();
+
+ if (isinstance<sequence>(src)) {
+ value.reserve(s.cast<sequence>().size());
+ }
+ for (auto it : s) {
+ value_conv conv;
+ if (!conv.load(it, convert)) {
+ return false;
+ }
+ value.push_back(cast_op<Value&&>(std::move(conv)));
+ }
+ return true;
+ }
+
+ template <typename T>
+ static handle cast(T&& src, return_value_policy policy, handle parent)
+ {
+ return list_caster<QList<Value>, Value>{}.cast(std::forward<T>(src), policy,
+ parent);
+ }
+
+ // we type these as "Sequence" even if these can be constructed from Iterable,
+ // otherwise the return type will be typed as "Iterable" which is problematic
+ PYBIND11_TYPE_CASTER(Type, const_name("Sequence[") + value_conv::name +
+ const_name("]"));
+ };
+
+} // namespace pybind11::detail::qt
+
+#endif
diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h
new file mode 100644
index 0000000..ea743b7
--- /dev/null
+++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h
@@ -0,0 +1,70 @@
+#ifndef PYTHON_PYBIND11_QT_DETAILS_QMAP_HPP
+#define PYTHON_PYBIND11_QT_DETAILS_QMAP_HPP
+
+#include <pybind11/pybind11.h>
+
+namespace pybind11::detail::qt {
+
+ // helper class for QMap because QMap do not follow the standard std:: maps
+ // interface, for other containers, the pybind11 built-in xxx_caster works
+ //
+ // this code is basically a copy/paste from the pybind11 stl stuff with
+ // minor modifications
+ //
+ template <typename Type, typename Key, typename Value>
+ struct qmap_caster {
+ using key_conv = make_caster<Key>;
+ using value_conv = make_caster<Value>;
+
+ bool load(handle src, bool convert)
+ {
+ if (!isinstance<dict>(src)) {
+ return false;
+ }
+ auto d = reinterpret_borrow<dict>(src);
+ value.clear();
+ for (auto it : d) {
+ key_conv kconv;
+ value_conv vconv;
+ if (!kconv.load(it.first.ptr(), convert) ||
+ !vconv.load(it.second.ptr(), convert)) {
+ return false;
+ }
+ value[cast_op<Key&&>(std::move(kconv))] =
+ cast_op<Value&&>(std::move(vconv));
+ }
+ return true;
+ }
+
+ template <typename T>
+ static handle cast(T&& src, return_value_policy policy, handle parent)
+ {
+ dict d;
+ return_value_policy policy_key = policy;
+ return_value_policy policy_value = policy;
+ if (!std::is_lvalue_reference<T>::value) {
+ policy_key = return_value_policy_override<Key>::policy(policy_key);
+ policy_value =
+ return_value_policy_override<Value>::policy(policy_value);
+ }
+ for (auto it = src.begin(); it != src.end(); ++it) {
+ auto key = reinterpret_steal<object>(
+ key_conv::cast(forward_like<T>(it.key()), policy_key, parent));
+ auto value = reinterpret_steal<object>(value_conv::cast(
+ forward_like<T>(it.value()), policy_value, parent));
+ if (!key || !value) {
+ return handle();
+ }
+ d[key] = value;
+ }
+ return d.release();
+ }
+
+ PYBIND11_TYPE_CASTER(Type, const_name("Dict[") + key_conv::name +
+ const_name(", ") + value_conv::name +
+ const_name("]"));
+ };
+
+} // namespace pybind11::detail::qt
+
+#endif
diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h
new file mode 100644
index 0000000..556a980
--- /dev/null
+++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h
@@ -0,0 +1,221 @@
+#ifndef PYTHON_PYBIND11_QT_DETAILS_SIP_HPP
+#define PYTHON_PYBIND11_QT_DETAILS_SIP_HPP
+
+#include <type_traits>
+
+#include <pybind11/pybind11.h>
+
+#include <iostream>
+#include <pybind11/iostream.h>
+
+#include "../pybind11_qt_holder.h"
+
+struct _sipTypeDef;
+typedef struct _sipTypeDef sipTypeDef;
+
+struct _sipSimpleWrapper;
+typedef struct _sipSimpleWrapper sipSimpleWrapper;
+
+struct _sipWrapper;
+typedef struct _sipWrapper sipWrapper;
+
+namespace pybind11::detail::qt {
+
+ // helper functions to avoid bringing <sip.h> in this header
+ namespace sip {
+
+ // extract the underlying data if present from the equivalent PyQt object
+ void* extract_data(PyObject*);
+
+ const sipTypeDef* api_find_type(const char* type);
+ int api_can_convert_to_type(PyObject* pyObj, const sipTypeDef* td, int flags);
+
+ void api_transfer_to(PyObject* self, PyObject* owner);
+ void api_transfer_back(PyObject* self);
+ PyObject* api_convert_from_type(void* cpp, const sipTypeDef* td,
+ PyObject* transferObj);
+ } // namespace sip
+
+ template <typename T, class = void>
+ struct MetaData;
+
+ template <typename T>
+ struct MetaData<T, std::enable_if_t<std::is_pointer_v<T>>>
+ : MetaData<std::remove_pointer_t<T>> {};
+
+ // template class for most Qt types that have Python equivalent (QWidget,
+ // etc.)
+ //
+ template <class QClass>
+ struct qt_type_caster {
+
+ static constexpr bool is_pointer = std::is_pointer_v<QClass>;
+ using pointer = std::conditional_t<is_pointer, QClass, QClass*>;
+
+ QClass value;
+
+ public:
+ static constexpr auto name = MetaData<QClass>::python_name;
+
+ operator pointer()
+ {
+ if constexpr (is_pointer) {
+ return value;
+ }
+ else {
+ return &value;
+ }
+ }
+
+ // pybind11 requires operator T&() & and operator T&&() && but here we want to
+ // use SFINAE with is_pointer so we need to template the operator
+ //
+ // having a template <class U> operator U&&() does not work since it will not
+ // deduce the proper return type for QClass&& or QClass& so we have two separate
+ // overloads, and in each one, U is actually a reference type (lvalue or rvalue)
+ //
+
+ template <class U,
+ std::enable_if_t<std::is_same_v<std::remove_reference_t<U>, QClass> &&
+ std::is_lvalue_reference_v<U> && !is_pointer,
+ int> = 0>
+ operator U()
+ {
+ return value;
+ }
+
+ template <class U,
+ std::enable_if_t<std::is_same_v<std::remove_reference_t<U>, QClass> &&
+ std::is_rvalue_reference_v<U> && !is_pointer,
+ int> = 0>
+ operator U() &&
+ {
+ return std::move(value);
+ }
+
+ template <typename T>
+ using cast_op_type =
+ std::conditional_t<is_pointer, QClass, movable_cast_op_type<T>>;
+
+ bool load(pybind11::handle src, bool)
+ {
+ // special check for none for pointer classes
+ if constexpr (is_pointer) {
+ if (src.is_none()) {
+ value = nullptr;
+ return true;
+ }
+ }
+
+ const auto* type = sip::api_find_type(MetaData<QClass>::class_name);
+ if (type == nullptr) {
+ return false;
+ }
+ if (!sip::api_can_convert_to_type(src.ptr(), type, 0)) {
+ return false;
+ }
+
+ // this would transfer responsibility for deconstructing the
+ // object to C++, but pybind11 assumes l-value converters (such
+ // as this) don't do that instead, this should be called within
+ // the wrappers for functions which return deletable pointers.
+ //
+ // sipAPI()->api_transfer_to(objPtr, Py_None);
+ //
+ void* const data = sip::extract_data(src.ptr());
+
+ if (data) {
+ if constexpr (is_pointer) {
+ value = reinterpret_cast<QClass>(data);
+
+ // transfer ownership
+ sip::api_transfer_to(src.ptr(), Py_None);
+
+ // tie the py::object to the C++ one
+ new pybind11::detail::qt::qobject_holder_impl(value);
+ }
+ else {
+ value = *reinterpret_cast<QClass*>(data);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ template <
+ typename T,
+ std::enable_if_t<std::is_same<QClass, std::remove_cv_t<T>>::value, int> = 0>
+ static handle cast(T* src, return_value_policy policy, handle parent)
+ {
+ // note: when QClass is a pointer type, e.g. a QWidget*, T is a
+ // pointer to pointer, so we can defer to the standard cast()
+
+ if (!src) {
+ return none().release();
+ }
+
+ if (!is_pointer && policy == return_value_policy::take_ownership) {
+ auto h = cast(std::move(*src), policy, parent);
+ delete src;
+ return h;
+ }
+ return cast(*src, policy, parent);
+ }
+
+ static pybind11::handle cast(QClass src, pybind11::return_value_policy policy,
+ pybind11::handle /* parent */)
+ {
+ if constexpr (is_pointer) {
+ if (!src) {
+ return none().release();
+ }
+ }
+
+ const sipTypeDef* type = sip::api_find_type(MetaData<QClass>::class_name);
+ if (type == nullptr) {
+ return Py_None;
+ }
+
+ PyObject* sipObj;
+ void* sipData;
+
+ if constexpr (is_pointer) {
+ sipData = src;
+ }
+ else if (std::is_copy_assignable_v<QClass>) {
+ // we send to SIP a newly allocated object, and transfer the
+ // owernship to it
+ sipData =
+ new QClass(policy == ::pybind11::return_value_policy::take_ownership
+ ? std::move(src)
+ : src);
+ }
+ else {
+ sipData = &src;
+ }
+
+ sipObj = sip::api_convert_from_type(sipData, type, 0);
+
+ if (sipObj == nullptr) {
+ return Py_None;
+ }
+
+ // ensure Python deletes the C++ component
+ if constexpr (!is_pointer) {
+ sip::api_transfer_back(sipObj);
+ }
+ else {
+ if (policy == return_value_policy::take_ownership) {
+ sip::api_transfer_back(sipObj);
+ }
+ }
+
+ return sipObj;
+ }
+ };
+
+} // namespace pybind11::detail::qt
+
+#endif
diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h
new file mode 100644
index 0000000..c877c15
--- /dev/null
+++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h
@@ -0,0 +1,47 @@
+#ifndef PYTHON_PYBIND11_QT_DETAILS_UTILS_HPP
+#define PYTHON_PYBIND11_QT_DETAILS_UTILS_HPP
+
+#include <string>
+#include <string_view>
+
+#include <pybind11/pybind11.h>
+
+namespace pybind11::detail::qt {
+
+ /**
+ * @brief Convert a XXX::YYY compile time string to a XXX.YYY compile time
+ * string. Only one :: is allowed.
+ *
+ */
+ template <size_t N>
+ constexpr descr<N - 2> qt_name_cpp2py(const char (&name)[N])
+ {
+ descr<N - 2> res;
+ for (std::size_t i = 0, j = 0; i < N - 2; ++i) {
+
+ res.text[i] = name[j];
+
+ if (res.text[i] == ':') {
+ res.text[i] = '.';
+ j += 2;
+ }
+ else {
+ ++j;
+ }
+ }
+ return res;
+ }
+
+ /**
+ * @brief Retrieve the class from the given package at the given path
+ *
+ * @param package Name of the module.
+ * @param path Path to the class/object in the module.
+ *
+ * @return the object at the given path in the given module
+ */
+ pybind11::object get_attr_rec(std::string_view package, std::string_view path);
+
+} // namespace pybind11::detail::qt
+
+#endif