aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpyside')
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt1
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp11
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp342
-rw-r--r--sources/pyside6/libpyside/pysideproperty.h10
-rw-r--r--sources/pyside6/libpyside/pysideproperty_p.h46
-rw-r--r--sources/pyside6/libpyside/pysidepropertybase_p.h95
-rw-r--r--sources/pyside6/libpyside/signalmanager.cpp2
7 files changed, 333 insertions, 174 deletions
diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
index 6aa4d7580..7640d1cce 100644
--- a/sources/pyside6/libpyside/CMakeLists.txt
+++ b/sources/pyside6/libpyside/CMakeLists.txt
@@ -29,6 +29,7 @@ set(libpyside_HEADERS # installed below
pyside_p.h
pysideglobals_p.h
pysideproperty.h
+ pysidepropertybase_p.h
pysideproperty_p.h
pysideqapp.h
pysideqenum.h
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
index db8e0c5ae..46bc3ace9 100644
--- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
@@ -275,7 +275,7 @@ void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index)
int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const
{
int notifyId = -1;
- if (property->d->notify) {
+ if (property->d->notify()) {
if (const char *signalNotify = PySide::Property::getNotifyName(property))
notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify);
}
@@ -316,13 +316,14 @@ QMetaPropertyBuilder
}
}
}
- const auto metaType = QMetaType::fromName(property->d->typeName);
+ const QByteArray &typeName = property->d->typeName();
+ const auto metaType = QMetaType::fromName(typeName);
if (!metaType.isValid()) {
const auto &msg = msgInvalidPropertyType(m_builder->className(), propertyName,
- property->d->typeName);
+ typeName);
PyErr_WarnEx(PyExc_RuntimeWarning, msg.constData(), 0);
}
- return builder->addProperty(propertyName, property->d->typeName, metaType, propertyNotifyId);
+ return builder->addProperty(propertyName, typeName, metaType, propertyNotifyId);
}
int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
@@ -336,7 +337,7 @@ int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
auto newProperty = createProperty(property, propertyName);
// Adding property attributes
- const auto &flags = property->d->flags;
+ const auto flags = property->d->flags();
newProperty.setReadable(flags.testFlag(PySide::Property::PropertyFlag::Readable));
newProperty.setWritable(flags.testFlag(PySide::Property::PropertyFlag::Writable));
newProperty.setResettable(flags.testFlag(PySide::Property::PropertyFlag::Resettable));
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
index 9df584df7..0207a7320 100644
--- a/sources/pyside6/libpyside/pysideproperty.cpp
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -16,6 +16,8 @@
#include <sbktypefactory.h>
#include <signature.h>
+#include <utility>
+
using namespace Shiboken;
using namespace Qt::StringLiterals;
@@ -101,9 +103,40 @@ PyTypeObject *PySideProperty_TypeF(void)
return type;
}
+PySidePropertyBase::PySidePropertyBase(Type t) : m_type(t)
+{
+}
+
+PySidePropertyBase::PySidePropertyBase(const PySidePropertyBase &rhs) = default;
+
+void PySidePropertyBase::tp_clearBase()
+{
+ Py_CLEAR(m_notify);
+ Py_CLEAR(m_pyTypeObject);
+}
+
+int PySidePropertyBase::tp_traverseBase(visitproc visit, void *arg)
+{
+ Py_VISIT(m_notify);
+ Py_VISIT(m_pyTypeObject);
+ return 0;
+}
+
+void PySidePropertyBase::increfBase()
+{
+ Py_XINCREF(m_notify);
+ Py_XINCREF(m_pyTypeObject);
+}
+
+PySidePropertyBase *PySidePropertyBase::clone() const
+{
+ Q_UNIMPLEMENTED();
+ return nullptr;
+}
+
// Helper to check a callable function passed to a property instance.
-bool PySidePropertyPrivate::assignCheckCallable(PyObject *source, const char *name,
- PyObject **target)
+bool PySidePropertyBase::assignCheckCallable(PyObject *source, const char *name,
+ PyObject **target)
{
if (source != nullptr && source != Py_None) {
if (PyCallable_Check(source) == 0) {
@@ -117,8 +150,32 @@ bool PySidePropertyPrivate::assignCheckCallable(PyObject *source, const char *na
return true;
}
-PySidePropertyPrivate::PySidePropertyPrivate() noexcept = default;
-PySidePropertyPrivate::~PySidePropertyPrivate() = default;
+void PySidePropertyPrivate::tp_clear()
+{
+ PySidePropertyBase::tp_clearBase();
+ Py_CLEAR(fget);
+ Py_CLEAR(fset);
+ Py_CLEAR(freset);
+ Py_CLEAR(fdel);
+}
+
+int PySidePropertyPrivate::tp_traverse(visitproc visit, void *arg)
+{
+ Py_VISIT(fget);
+ Py_VISIT(fset);
+ Py_VISIT(freset);
+ Py_VISIT(fdel);
+ return PySidePropertyBase::tp_traverseBase(visit, arg);
+}
+
+void PySidePropertyPrivate::incref()
+{
+ PySidePropertyBase::increfBase();
+ Py_XINCREF(fget);
+ Py_XINCREF(fset);
+ Py_XINCREF(freset);
+ Py_XINCREF(fdel);
+}
PyObject *PySidePropertyPrivate::getValue(PyObject *source) const
{
@@ -165,6 +222,13 @@ int PySidePropertyPrivate::reset(PyObject *source)
return -1;
}
+PySidePropertyPrivate *PySidePropertyPrivate::clone() const
+{
+ auto *result = new PySidePropertyPrivate(*this);
+ result->incref();
+ return result;
+}
+
void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, void **args)
{
switch (call) {
@@ -172,13 +236,13 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
AutoDecRef value(getValue(source));
if (value.isNull())
return;
- if (typeName == "PyObject"_ba) {
+ if (typeName() == "PyObject"_ba) {
// Manual conversion, see PyObjectWrapper converter registration
auto *pw = reinterpret_cast<PySide::PyObjectWrapper *>(args[0]);
pw->reset(value.object());
return;
}
- if (Conversions::SpecificConverter converter(typeName); converter) {
+ if (Conversions::SpecificConverter converter(typeName()); converter) {
converter.toCpp(value.object(), args[0]);
return;
}
@@ -188,7 +252,7 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
break;
case QMetaObject::WriteProperty: {
- Conversions::SpecificConverter converter(typeName);
+ Conversions::SpecificConverter converter(typeName());
if (converter) {
AutoDecRef value(converter.toPython(args[0]));
setValue(source, value);
@@ -208,35 +272,75 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
}
}
-static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+// Helpers & name for passing the the PySidePropertyPrivate
+// as a capsule when constructing.
+static const char dataCapsuleName[] = "PropertyPrivate";
+static const char dataCapsuleKeyName[] = "_PropertyPrivate"; // key in keyword args
+
+static PySidePropertyBase *getDataFromKwArgs(PyObject *kwds)
+{
+ if (kwds != nullptr && PyDict_Check(kwds) != 0) {
+ static PyObject *key = PyUnicode_InternFromString(dataCapsuleKeyName);
+ if (PyDict_Contains(kwds, key) != 0) {
+ Shiboken::AutoDecRef data(PyDict_GetItem(kwds, key));
+ if (PyCapsule_CheckExact(data.object()) != 0) {
+ if (void *p = PyCapsule_GetPointer(data.object(), dataCapsuleName))
+ return reinterpret_cast<PySidePropertyBase *>(p);
+ }
+ }
+ }
+ return nullptr;
+}
+
+static void addDataCapsuleToKwArgs(const AutoDecRef &kwds, PySidePropertyBase *data)
+{
+ auto *capsule = PyCapsule_New(data, dataCapsuleName, nullptr);
+ PyDict_SetItemString(kwds.object(), dataCapsuleKeyName, capsule);
+}
+
+static inline PySidePropertyPrivate *propertyPrivate(PyObject *self)
+{
+ auto *data = reinterpret_cast<PySideProperty *>(self);
+ Q_ASSERT(data->d != nullptr);
+ Q_ASSERT(data->d->type() == PySidePropertyBase::Type::Property);
+ return static_cast<PySidePropertyPrivate *>(data->d);
+}
+
+static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject *kwds)
{
auto *me = PepExt_TypeCallAlloc<PySideProperty>(subtype, 0);
- me->d = new PySidePropertyPrivate;
+ me->d = getDataFromKwArgs(kwds);
+ if (me->d == nullptr)
+ me->d = new PySidePropertyPrivate;
return reinterpret_cast<PyObject *>(me);
}
static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
{
- auto *data = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = data->d;
+ auto *pData = propertyPrivate(self);
+
+ if (!pData->typeName().isEmpty()) // Cloned copy, already initialized
+ return 0;
static const char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "notify",
"designable", "scriptable", "stored",
- "user", "constant", "final", nullptr};
+ "user", "constant", "final", dataCapsuleKeyName, nullptr};
char *doc{};
PyObject *type{}, *fget{}, *fset{}, *freset{}, *fdel{}, *notify{};
+ PyObject *dataCapsule{};
bool designable{true}, scriptable{true}, stored{true};
bool user{false}, constant{false}, finalProp{false};
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "O|OOOOsObbbbbb:QtCore.Property",
+ "O|OOOOsObbbbbbO:QtCore.Property",
const_cast<char **>(kwlist),
/*OO*/ &type, &fget,
/*OOO*/ &fset, &freset, &fdel,
/*s*/ &doc,
/*O*/ &notify,
/*bbb*/ &designable, &scriptable, &stored,
- /*bbb*/ &user, &constant, &finalProp)) {
+ /*bbb*/ &user, &constant, &finalProp,
+ /*O*/ &dataCapsule)) {
return -1;
}
@@ -244,27 +348,24 @@ static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
|| !PySidePropertyPrivate::assignCheckCallable(fset, "fset", &pData->fset)
|| !PySidePropertyPrivate::assignCheckCallable(freset, "freset", &pData->freset)
|| !PySidePropertyPrivate::assignCheckCallable(fdel, "fdel", &pData->fdel)) {
- pData->fget = pData->fset = pData->freset = pData->fdel = pData->notify = nullptr;
+ pData->fget = pData->fset = pData->freset = pData->fdel = nullptr;
+ pData->setNotify(nullptr);
return -1;
}
if (notify != nullptr && notify != Py_None)
- pData->notify = notify;
+ pData->setNotify(notify);
// PYSIDE-1019: Fetching the default `__doc__` from fget would fail for inherited functions
// because we don't initialize the mro with signatures (and we will not!).
// But it is efficient and in-time to do that on demand in qPropertyDocGet.
pData->getter_doc = false;
- if (doc)
- pData->doc = doc;
- else
- pData->doc.clear();
+ pData->setDoc(doc != nullptr ? QByteArray(doc) : QByteArray{});
- pData->pyTypeObject = type;
- Py_XINCREF(pData->pyTypeObject);
- pData->typeName = PySide::Signal::getTypeName(type);
+ pData->setPyTypeObject(type);
+ pData->setTypeName(PySide::Signal::getTypeName(type));
- auto &flags = pData->flags;
+ PySide::Property::PropertyFlags flags;
flags.setFlag(PySide::Property::PropertyFlag::Readable, pData->fget != nullptr);
flags.setFlag(PySide::Property::PropertyFlag::Writable, pData->fset != nullptr);
flags.setFlag(PySide::Property::PropertyFlag::Resettable, pData->freset != nullptr);
@@ -274,24 +375,22 @@ static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
flags.setFlag(PySide::Property::PropertyFlag::User, user);
flags.setFlag(PySide::Property::PropertyFlag::Constant, constant);
flags.setFlag(PySide::Property::PropertyFlag::Final, finalProp);
+ pData->setFlags(flags);
- if (type == Py_None || pData->typeName.isEmpty())
+ if (type == Py_None || pData->typeName().isEmpty())
PyErr_SetString(PyExc_TypeError, "Invalid property type or type name.");
else if (constant && pData->fset != nullptr)
PyErr_SetString(PyExc_TypeError, "A constant property cannot have a WRITE method.");
- else if (constant && pData->notify != nullptr)
+ else if (constant && pData->notify() != nullptr)
PyErr_SetString(PyExc_TypeError, "A constant property cannot have a NOTIFY signal.");
if (PyErr_Occurred() != nullptr) {
- pData->fget = pData->fset = pData->freset = pData->fdel = pData->notify = nullptr;
+ pData->fget = pData->fset = pData->freset = pData->fdel = nullptr;
+ pData->setNotify(nullptr);
return -1;
}
- Py_XINCREF(pData->fget);
- Py_XINCREF(pData->fset);
- Py_XINCREF(pData->freset);
- Py_XINCREF(pData->fdel);
- Py_XINCREF(pData->notify);
+ pData->incref();
return 0;
}
@@ -306,88 +405,80 @@ static void qpropertyDeAlloc(PyObject *self)
}
// Create a copy of the property to prevent the @property.setter from modifying
-// the property in place and avoid strange side effects in derived classes
-// (cf https://bugs.python.org/issue1620).
-static PyObject *
-_property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyObject *del)
+// the property in place and avoid strange side effects when modifying the
+// property in derived classes (cf https://bugs.python.org/issue1620,
+// pysidetest/property_python_test.py).
+static PyObject *copyProperty(PyObject *old)
{
- auto *pold = reinterpret_cast<PySideProperty *>(old);
- PySidePropertyPrivate *pData = pold->d;
-
AutoDecRef type(PyObject_Type(old));
- QByteArray doc{};
- if (type.isNull())
- return nullptr;
-
- if (get == nullptr || get == Py_None) {
- Py_XDECREF(get);
- get = pData->fget ? pData->fget : Py_None;
- }
- if (set == nullptr || set == Py_None) {
- Py_XDECREF(set);
- set = pData->fset ? pData->fset : Py_None;
- }
- if (reset == nullptr || reset == Py_None) {
- Py_XDECREF(reset);
- reset = pData->freset ? pData->freset : Py_None;
- }
- if (del == nullptr || del == Py_None) {
- Py_XDECREF(del);
- del = pData->fdel ? pData->fdel : Py_None;
- }
- // make _init use __doc__ from getter
- if ((pData->getter_doc && get != Py_None) || pData->doc.isEmpty())
- doc.clear();
- else
- doc = pData->doc;
-
- auto *notify = pData->notify ? pData->notify : Py_None;
-
- const auto &flags = pData->flags;
- PyObject *obNew =
- PyObject_CallFunction(type, "OOOOOsO" "bbb" "bbb",
- pData->pyTypeObject, get, set, reset, del, doc.data(), notify,
- flags.testFlag(PySide::Property::PropertyFlag::Designable),
- flags.testFlag(PySide::Property::PropertyFlag::Scriptable),
- flags.testFlag(PySide::Property::PropertyFlag::Stored),
- flags.testFlag(PySide::Property::PropertyFlag::User),
- flags.testFlag(PySide::Property::PropertyFlag::Constant),
- flags.testFlag(PySide::Property::PropertyFlag::Final));
-
- return obNew;
+ Shiboken::AutoDecRef kwds(PyDict_New());
+ addDataCapsuleToKwArgs(kwds, propertyPrivate(old)->clone());
+ Shiboken::AutoDecRef args(PyTuple_New(0));
+ return PyObject_Call(type.object(), args.object(), kwds.object());
}
static PyObject *qPropertyGetter(PyObject *self, PyObject *getter)
{
- return _property_copy(self, getter, nullptr, nullptr, nullptr);
+ PyObject *result = copyProperty(self);
+ if (result != nullptr) {
+ auto *data = propertyPrivate(result);
+ auto *old = std::exchange(data->fget, getter);
+ Py_XINCREF(data->fget);
+ Py_XDECREF(old);
+ data->setFlag(PySide::Property::PropertyFlag::Readable);
+ }
+ return result;
}
static PyObject *qPropertySetter(PyObject *self, PyObject *setter)
{
- return _property_copy(self, nullptr, setter, nullptr, nullptr);
+ PyObject *result = copyProperty(self);
+ if (result != nullptr) {
+ auto *data = propertyPrivate(result);
+ auto *old = std::exchange(data->fset, setter);
+ Py_XINCREF(data->fset);
+ Py_XDECREF(old);
+ data->setFlag(PySide::Property::PropertyFlag::Writable);
+ }
+ return result;
}
static PyObject *qPropertyResetter(PyObject *self, PyObject *resetter)
{
- return _property_copy(self, nullptr, nullptr, resetter, nullptr);
+ PyObject *result = copyProperty(self);
+ if (result != nullptr) {
+ auto *data = propertyPrivate(result);
+ auto *old = std::exchange(data->freset, resetter);
+ Py_XINCREF(data->freset);
+ Py_XDECREF(old);
+ data->setFlag(PySide::Property::PropertyFlag::Resettable);
+ }
+ return result;
}
static PyObject *qPropertyDeleter(PyObject *self, PyObject *deleter)
{
- return _property_copy(self, nullptr, nullptr, nullptr, deleter);
+ PyObject *result = copyProperty(self);
+ if (result != nullptr) {
+ auto *data = propertyPrivate(result);
+ auto *old = std::exchange(data->fdel, deleter);
+ Py_XINCREF(data->fdel);
+ Py_XDECREF(old);
+ }
+ return result;
}
static PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */)
{
PyObject *getter = PyTuple_GetItem(args, 0);
- return _property_copy(self, getter, nullptr, nullptr, nullptr);
+ return qPropertyGetter(self, getter);
}
// PYSIDE-1019: Provide the same getters as Pythons `PyProperty`.
static PyObject *qProperty_fget(PyObject *self, void *)
{
- auto *func = reinterpret_cast<PySideProperty *>(self)->d->fget;
+ auto *func = propertyPrivate(self)->fget;
if (func == nullptr)
Py_RETURN_NONE;
Py_INCREF(func);
@@ -396,7 +487,7 @@ static PyObject *qProperty_fget(PyObject *self, void *)
static PyObject *qProperty_fset(PyObject *self, void *)
{
- auto *func = reinterpret_cast<PySideProperty *>(self)->d->fset;
+ auto *func = propertyPrivate(self)->fset;
if (func == nullptr)
Py_RETURN_NONE;
Py_INCREF(func);
@@ -405,7 +496,7 @@ static PyObject *qProperty_fset(PyObject *self, void *)
static PyObject *qProperty_freset(PyObject *self, void *)
{
- auto *func = reinterpret_cast<PySideProperty *>(self)->d->freset;
+ auto *func = propertyPrivate(self)->freset;
if (func == nullptr)
Py_RETURN_NONE;
Py_INCREF(func);
@@ -414,7 +505,7 @@ static PyObject *qProperty_freset(PyObject *self, void *)
static PyObject *qProperty_fdel(PyObject *self, void *)
{
- auto *func = reinterpret_cast<PySideProperty *>(self)->d->fdel;
+ auto *func = propertyPrivate(self)->fdel;
if (func == nullptr)
Py_RETURN_NONE;
Py_INCREF(func);
@@ -424,16 +515,15 @@ static PyObject *qProperty_fdel(PyObject *self, void *)
static PyObject *qPropertyDocGet(PyObject *self, void *)
{
auto *data = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = data->d;
+ if (!data->d->doc().isEmpty() || data->d->type() != PySidePropertyBase::Type::Property)
+ return PyUnicode_FromString(data->d->doc());
- QByteArray doc(pData->doc);
- if (!doc.isEmpty())
- return PyUnicode_FromString(doc);
+ auto *pData = static_cast<PySidePropertyPrivate *>(data->d);
if (pData->fget != nullptr) {
// PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
AutoDecRef get_doc(PyObject_GetAttr(pData->fget, PyMagicName::doc()));
if (!get_doc.isNull() && get_doc.object() != Py_None) {
- pData->doc = String::toCString(get_doc);
+ pData->setDoc(String::toCString(get_doc));
pData->getter_doc = true;
if (Py_TYPE(self) == PySideProperty_TypeF())
return qPropertyDocGet(self, nullptr);
@@ -456,10 +546,8 @@ static PyObject *qPropertyDocGet(PyObject *self, void *)
static int qPropertyDocSet(PyObject *self, PyObject *value, void *)
{
auto *data = reinterpret_cast<PySideProperty *>(self);
- PySidePropertyPrivate *pData = data->d;
-
if (String::check(value)) {
- pData->doc = String::toCString(value);
+ data->d->setDoc(String::toCString(value));
return 0;
}
PyErr_SetString(PyExc_TypeError, "String argument expected.");
@@ -468,34 +556,20 @@ static int qPropertyDocSet(PyObject *self, PyObject *value, void *)
static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg)
{
- PySidePropertyPrivate *data = reinterpret_cast<PySideProperty *>(self)->d;
- if (!data)
- return 0;
-
- Py_VISIT(data->fget);
- Py_VISIT(data->fset);
- Py_VISIT(data->freset);
- Py_VISIT(data->fdel);
- Py_VISIT(data->notify);
- Py_VISIT(data->pyTypeObject);
- return 0;
+ auto *pData = propertyPrivate(self);
+ return pData != nullptr ? pData->tp_traverse(visit, arg) : 0;
}
static int qpropertyClear(PyObject *self)
{
- PySidePropertyPrivate *data = reinterpret_cast<PySideProperty *>(self)->d;
- if (!data)
+ auto *data = reinterpret_cast<PySideProperty *>(self);
+ if (data->d == nullptr)
return 0;
- Py_CLEAR(data->fget);
- Py_CLEAR(data->fset);
- Py_CLEAR(data->freset);
- Py_CLEAR(data->fdel);
- Py_CLEAR(data->notify);
- Py_CLEAR(data->pyTypeObject);
-
- delete data;
- reinterpret_cast<PySideProperty *>(self)->d = nullptr;
+ auto *baseData = std::exchange(data->d, nullptr);
+ Q_ASSERT(baseData->type() == PySidePropertyBase::Type::Property);
+ static_cast<PySidePropertyPrivate *>(baseData)->tp_clear();
+ delete baseData;
return 0;
}
@@ -558,22 +632,22 @@ bool checkType(PyObject *pyObj)
PyObject *getValue(PySideProperty *self, PyObject *source)
{
- return self->d->getValue(source);
+ return static_cast<PySidePropertyPrivate *>(self->d)->getValue(source);
}
int setValue(PySideProperty *self, PyObject *source, PyObject *value)
{
- return self->d->setValue(source, value);
+ return static_cast<PySidePropertyPrivate *>(self->d)->setValue(source, value);
}
int reset(PySideProperty *self, PyObject *source)
{
- return self->d->reset(source);
+ return static_cast<PySidePropertyPrivate *>(self->d)->reset(source);
}
const char *getTypeName(const PySideProperty *self)
{
- return self->d->typeName;
+ return self->d->typeName().constData();
}
PySideProperty *getObject(PyObject *source, PyObject *name)
@@ -594,30 +668,33 @@ PySideProperty *getObject(PyObject *source, PyObject *name)
const char *getNotifyName(PySideProperty *self)
{
- if (self->d->notifySignature.isEmpty()) {
- AutoDecRef str(PyObject_Str(self->d->notify));
- self->d->notifySignature = Shiboken::String::toCString(str);
+ if (self->d->notifySignature().isEmpty()) {
+ AutoDecRef str(PyObject_Str(self->d->notify()));
+ self->d->setNotifySignature(Shiboken::String::toCString(str));
}
- return self->d->notifySignature.isEmpty()
- ? nullptr : self->d->notifySignature.constData();
+ return self->d->notifySignature().isEmpty()
+ ? nullptr : self->d->notifySignature().constData();
}
void setTypeName(PySideProperty *self, const char *typeName)
{
- self->d->typeName = typeName;
+ self->d->setTypeName(typeName);
}
PyObject *getTypeObject(const PySideProperty *self)
{
- return self->d->pyTypeObject;
+ return self->d->pyTypeObject();
}
PyObject *create(const char *typeName, PyObject *getter,
- PyObject *setter, PyObject *notifySignature)
+ PyObject *setter, PyObject *notifySignature,
+ PySidePropertyBase *data)
{
Shiboken::AutoDecRef kwds(PyDict_New());
PyDict_SetItemString(kwds.object(), "type", PyUnicode_FromString(typeName));
+ if (data != nullptr)
+ addDataCapsuleToKwArgs(kwds, data);
if (getter != nullptr && getter != Py_None)
PyDict_SetItemString(kwds.object(), "fget", getter);
if (setter != nullptr && getter != Py_None)
@@ -635,12 +712,13 @@ PyObject *create(const char *typeName, PyObject *getter,
}
PyObject *create(const char *typeName, PyObject *getter,
- PyObject *setter, const char *notifySignature)
+ PyObject *setter, const char *notifySignature,
+ PySidePropertyBase *data)
{
PyObject *obNotifySignature = notifySignature != nullptr
? PyUnicode_FromString(notifySignature) : nullptr;
- PyObject *result = create(typeName, getter, setter, obNotifySignature);
+ PyObject *result = create(typeName, getter, setter, obNotifySignature, data);
Py_XDECREF(obNotifySignature);
return result;
}
diff --git a/sources/pyside6/libpyside/pysideproperty.h b/sources/pyside6/libpyside/pysideproperty.h
index 897da6ac2..c2ce006a9 100644
--- a/sources/pyside6/libpyside/pysideproperty.h
+++ b/sources/pyside6/libpyside/pysideproperty.h
@@ -10,7 +10,7 @@
#include <QtCore/qmetaobject.h>
-class PySidePropertyPrivate;
+class PySidePropertyBase;
extern "C"
{
@@ -19,7 +19,7 @@ extern "C"
struct PYSIDE_API PySideProperty
{
PyObject_HEAD
- PySidePropertyPrivate* d;
+ PySidePropertyBase* d;
};
};
@@ -70,11 +70,13 @@ PYSIDE_API void setTypeName(PySideProperty *self, const char *typeName);
/// Create a property from type, getter, setter and notification signature.
PYSIDE_API PyObject *create(const char *typeName, PyObject *getter,
- PyObject *setter, PyObject *notifySignature);
+ PyObject *setter, PyObject *notifySignature,
+ PySidePropertyBase *data = nullptr);
/// Create a property from type, getter, optional setter and notification signature.
PYSIDE_API PyObject *create(const char *typeName, PyObject *getter,
PyObject *setter = nullptr,
- const char *notifySignature = nullptr);
+ const char *notifySignature = nullptr,
+ PySidePropertyBase *data = nullptr);
} //namespace PySide::Property
diff --git a/sources/pyside6/libpyside/pysideproperty_p.h b/sources/pyside6/libpyside/pysideproperty_p.h
index bd223d0be..baf0df178 100644
--- a/sources/pyside6/libpyside/pysideproperty_p.h
+++ b/sources/pyside6/libpyside/pysideproperty_p.h
@@ -7,6 +7,7 @@
#include <sbkpython.h>
#include "pysideproperty.h"
+#include "pysidepropertybase_p.h"
#include <pysidemacros.h>
#include <QtCore/qbytearray.h>
@@ -16,53 +17,34 @@
struct PySideProperty;
-namespace PySide::Property {
-
-enum class PropertyFlag {
- Readable = 0x001,
- Writable = 0x002,
- Resettable = 0x004,
- Designable = 0x008,
- Scriptable = 0x010,
- Stored = 0x020,
- User = 0x040,
- Constant = 0x080,
- Final = 0x100
-};
-Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
-
-} // namespace PySide::Property
-
-class PYSIDE_API PySidePropertyPrivate
+class PYSIDE_API PySidePropertyPrivate : public PySidePropertyBase
{
public:
+ PySidePropertyPrivate(const PySidePropertyPrivate &) = default;
+ PySidePropertyPrivate &operator=(const PySidePropertyPrivate &) = delete;
+ PySidePropertyPrivate(PySidePropertyPrivate &&) = delete;
+ PySidePropertyPrivate &operator=(PySidePropertyPrivate &&) = delete;
- Q_DISABLE_COPY_MOVE(PySidePropertyPrivate)
+ PySidePropertyPrivate() : PySidePropertyBase(Type::Property) {}
+ ~PySidePropertyPrivate() override = default;
- PySidePropertyPrivate() noexcept;
- virtual ~PySidePropertyPrivate();
+ [[nodiscard]] PySidePropertyPrivate *clone() const override;
- virtual void metaCall(PyObject *source, QMetaObject::Call call, void **args);
+ void metaCall(PyObject *source, QMetaObject::Call call, void **args) override;
+
+ void tp_clear();
+ int tp_traverse(visitproc visit, void *arg);
+ void incref();
PyObject *getValue(PyObject *source) const;
int setValue(PyObject *source, PyObject *value);
int reset(PyObject *source);
- static bool assignCheckCallable(PyObject *source, const char *name, PyObject **target);
-
- QByteArray typeName;
- // Type object: A real PyTypeObject ("@Property(int)") or a string
- // "@Property('QVariant')".
- PyObject *pyTypeObject = nullptr;
PyObject *fget = nullptr;
PyObject *fset = nullptr;
PyObject *freset = nullptr;
PyObject *fdel = nullptr;
- PyObject *notify = nullptr;
bool getter_doc = false;
- QByteArray notifySignature;
- QByteArray doc;
- PySide::Property::PropertyFlags flags;
};
namespace PySide::Property {
diff --git a/sources/pyside6/libpyside/pysidepropertybase_p.h b/sources/pyside6/libpyside/pysidepropertybase_p.h
new file mode 100644
index 000000000..c8ef778ca
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidepropertybase_p.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDE_PROPERTYBASE_P_H
+#define PYSIDE_PROPERTYBASE_P_H
+
+#include <sbkpython.h>
+
+#include <pysidemacros.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qmetaobject.h>
+
+struct PySideProperty;
+
+namespace PySide::Property {
+
+enum class PropertyFlag {
+ Readable = 0x001,
+ Writable = 0x002,
+ Resettable = 0x004,
+ Designable = 0x008,
+ Scriptable = 0x010,
+ Stored = 0x020,
+ User = 0x040,
+ Constant = 0x080,
+ Final = 0x100
+};
+Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+
+} // namespace PySide::Property
+
+// Base class for meta-callable properties (Normal properties, QmlListProperty)
+class PYSIDE_API PySidePropertyBase
+{
+public:
+ PySidePropertyBase &operator=(const PySidePropertyBase &) = delete;
+ PySidePropertyBase(PySidePropertyBase &&) = delete;
+ PySidePropertyBase &operator=(PySidePropertyBase &&) = delete;
+
+ enum class Type : unsigned char { Property, ListProperty };
+
+ virtual ~PySidePropertyBase() = default;
+
+ // For handling decorator like "@property.getter"
+ [[nodiscard]] virtual PySidePropertyBase *clone() const;
+
+ virtual void metaCall(PyObject *source, QMetaObject::Call call, void **args) = 0;
+
+ [[nodiscard]] Type type() const { return m_type; }
+
+ [[nodiscard]] const QByteArray &typeName() const { return m_typeName; }
+ void setTypeName(const QByteArray &newTypeName) { m_typeName = newTypeName; }
+
+ [[nodiscard]] PyObject *pyTypeObject() const { return m_pyTypeObject; }
+ void setPyTypeObject(PyObject *pt) { m_pyTypeObject = pt; }
+
+ [[nodiscard]] PyObject *notify() const { return m_notify; }
+ void setNotify(PyObject *n) { m_notify = n; }
+
+ [[nodiscard]] const QByteArray &notifySignature() const { return m_notifySignature; }
+ void setNotifySignature(const QByteArray &s) { m_notifySignature = s; }
+
+ [[nodiscard]] const QByteArray &doc() const { return m_doc; }
+ void setDoc(const QByteArray &doc) { m_doc = doc; }
+
+ [[nodiscard]] PySide::Property::PropertyFlags flags() const { return m_flags; }
+ void setFlags(PySide::Property::PropertyFlags f) { m_flags = f; }
+ void setFlag(PySide::Property::PropertyFlag f) { m_flags.setFlag(f); }
+
+ static bool assignCheckCallable(PyObject *source, const char *name, PyObject **target);
+
+protected:
+ explicit PySidePropertyBase(Type t);
+ PySidePropertyBase(const PySidePropertyBase &rhs);
+
+ void tp_clearBase();
+ int tp_traverseBase(visitproc visit, void *arg);
+ void increfBase();
+
+private:
+ QByteArray m_typeName;
+ // Type object: A real PyTypeObject ("@Property(int)") or a string
+ // "@Property('QVariant')".
+ PyObject *m_pyTypeObject = nullptr;
+ PyObject *m_notify = nullptr;
+ QByteArray m_notifySignature;
+ QByteArray m_doc;
+ PySide::Property::PropertyFlags m_flags;
+ Type m_type;
+};
+
+#endif // PYSIDE_PROPERTYBASE_P_H
diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp
index 211588eea..01b08e283 100644
--- a/sources/pyside6/libpyside/signalmanager.cpp
+++ b/sources/pyside6/libpyside/signalmanager.cpp
@@ -404,7 +404,7 @@ int SignalManagerPrivate::qtPropertyMetacall(QObject *object,
PyErr_WarnFormat(PyExc_RuntimeWarning, 0,
ign ? "Unknown property type '%s' of QObject '%s' used in fset"
: "Unknown property type '%s' of QObject '%s' used in fget with %R",
- pp->d->typeName.constData(), metaObject->className(), errorStash.getException());
+ pp->d->typeName().constData(), metaObject->className(), errorStash.getException());
if (PyErr_Occurred())
Shiboken::Errors::storeErrorOrPrint();
errorStash.release();