aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2024-12-18 10:33:56 -0500
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2025-03-13 16:28:42 +0100
commit19abd816e73bebdd489408d0a3b7676822bff39c (patch)
tree8459ae9401f5e190995b3e24b6ae6968cf457baf /sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
parent3c66c456aeab597b7cb046f81c7f015433bb57a4 (diff)
Make Remote Objects usable beyond Models
While present, the Qt Remote Objects bindings to Python have not been very useful. The only usable components were those based on QAbstractItemModel, due to the lack of a way to interpret .rep files from Python. This addresses that limitation. Fixes: PYSIDE-862 Change-Id: Ice57c0c64f11c3c7e74d50ce3c48617bd9b422a3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Brett Stottlemyer <brett.stottlemyer@gmail.com>
Diffstat (limited to 'sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h')
-rw-r--r--sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h87
1 files changed, 87 insertions, 0 deletions
diff --git a/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h b/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
new file mode 100644
index 000000000..7b6abc54b
--- /dev/null
+++ b/sources/pyside6/libpysideremoteobjects/pysidecapsulemethod_p.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2025 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDE_CAPSULEMETHOD_P_H
+#define PYSIDE_CAPSULEMETHOD_P_H
+
+#include <sbkpython.h>
+
+extern "C"
+{
+
+/**
+ * This code is needed to solve, in C++ and adhering to the stable API,
+ * creating what are in effect lambda functions as instance methods on custom
+ * types. The goal is to be able to add methods to a dynamic type. If the .rep
+ * file defines a slot `mySlot`, it need to be added to the dynamic type. For
+ * Source types, this should be an abstract method that raises a
+ * NotImplementedError unless defined in the Python subclass. For Replica
+ * types, this should include an implementation that forwards the request
+ * through the underlying QRemoteObjectReplica instance.
+ *
+ * The stable API doesn't currently provide a way define a method that can
+ * receive both the `self`, `args`, and runtime (but constant per method, i.e.,
+ * lambda like) data using Py_tp_methods. Possibly post 3.13 when METH_METHOD is
+ * part of the stable API. But for now, it is not.
+ *
+ * The solution is to create a custom descriptor
+ * (https://docs.python.org/3/howto/descriptor.html) that can hold the runtime
+ * data and then when called, will return a PyCFunction_New generated PyObject
+ * that is passed both class instance `self` and the runtime data (a PyCapsule)
+ * together as a tuple as a new `self` for the method. The static method
+ * definition needs to expect and handle this, but when combined in C++, we can
+ * define a single handler that receives both the original `self` of the instance
+ * and the runtime capsule with data for handling.
+ */
+
+/**
+ * The CapsuleDescriptorData struct is what will be passed as the pseudo `self`
+ * from a CapsuleMethod or CapsuleProperty to the associated handler method. The
+ * handler method (which should look like a standard PyMethodDef method) should
+ * parse it into the payload (the "lambda variables") and the actual instance
+ * (the "self").
+ */
+struct CapsuleDescriptorData
+{
+ PyObject *self;
+ PyObject *payload;
+};
+
+/**
+ * The new type defining a descriptor that stores a PyCapsule. This is used to
+ * store the runtime data, with the __get__ method returning a new Callable.
+ */
+PyTypeObject *CapsuleMethod_TypeF(void);
+
+/**
+ * The new type defining a descriptor that stores a PyCapsule. This is used to
+ * store the runtime data, with the __get__ (and __set__ if isWritable) providing
+ * property behavior.
+ */
+PyTypeObject *CapsuleProperty_TypeF(bool isWritable);
+
+/**
+ * Add a capsule method (a descriptor) to a type. This will create a new capsule
+ * method descriptor and add it as an attribute to the type, using the given name.
+ *
+ * A single handle can then respond to what appear to be distinct methods on the
+ * type, but using the runtime data (from the capsule) when handling each call.
+ *
+ * @param type The type to attach the created descriptor to.
+ * @param method The method definition to associate with the descriptor.
+ * The name of the method will be used as the attribute name.
+ * @param capsule The capsule to store in the descriptor.
+ * @return True if the descriptor was added successfully, false otherwise.
+ */
+bool add_capsule_method_to_type(PyTypeObject *type, PyMethodDef *method,
+ PyObject *capsule);
+
+/**
+ * Make a new CapsuleProperty type.
+ */
+PyObject *make_capsule_property(PyMethodDef *method, PyObject *capsule,
+ bool isWritable = false);
+
+} // extern "C"
+
+#endif // PYSIDE_CAPSULEMETHOD_P_H