aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml6
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp124
-rw-r--r--sources/pyside6/tests/QtCore/qtimer_singleshot_test.py64
3 files changed, 133 insertions, 61 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index d51a80380..f7235ffc2 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -2542,10 +2542,10 @@
<include file-name="pysidestaticstrings.h" location="global"/>
</extra-includes>
<modify-function signature="singleShot(int,const QObject*,const char*)">
- <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-1"/>
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-direct-mapping"/>
</modify-function>
- <add-function signature="singleShot(int,PyCallable*)" static="yes">
- <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-2"/>
+ <add-function signature="singleShot(int@msec@,PyCallable*@functor@)" static="yes">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-functor"/>
</add-function>
<add-function signature="singleShot(int@msec@,const QObject*@context@,PyCallable*@functor@)" static="yes">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-functor-context"/>
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 46f794690..7df53d8e8 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -988,66 +988,76 @@ auto *ptr = reinterpret_cast<uchar *>(Shiboken::Buffer::getPointer(%PYARG_1, &si
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qtranslator-load
-// @snippet qtimer-singleshot-1
-// %FUNCTION_NAME() - disable generation of c++ function call
-(void) %2; // remove warning about unused variable
+// @snippet qtimer-singleshot-direct-mapping
Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = Shiboken::SbkType<QTimer>();
-auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
-auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
-auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-initFunc(pyTimer, emptyTuple, nullptr);
-
-auto timer = %CONVERTTOCPP[QTimer *](pyTimer);
-Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsOs",
- pyTimer,
- SIGNAL(timeout()),
- %PYARG_2,
- %3)
-);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->setSingleShot(true);
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater);
-timer->start(%1);
-// @snippet qtimer-singleshot-1
-
-// @snippet qtimer-singleshot-2
-// %FUNCTION_NAME() - disable generation of c++ function call
-Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = Shiboken::SbkType<QTimer>();
-auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
-auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
-auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-initFunc(pyTimer, emptyTuple, nullptr);
-QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
-timer->setSingleShot(true);
-
-if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
- PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
- Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
- Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsOO",
- pyTimer,
- SIGNAL(timeout()),
- PySide::Signal::getObject(signalInstance),
- signalSignature.object())
- );
+%CPPSELF.%FUNCTION_NAME(%1, %2, %3);
+// @snippet qtimer-singleshot-direct-mapping
+
+// @snippet qtimer-singleshot-functor
+auto msec = %1;
+if (msec == 0) {
+ if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+ auto *signal = %PYARG_2;
+ auto cppCallback = [signal]()
+ {
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef ret(PyObject_CallMethod(signal, "emit", "()"));
+ Py_DECREF(signal);
+ };
+
+ Py_INCREF(signal);
+ %CPPSELF.%FUNCTION_NAME(msec, cppCallback);
+ } else {
+ Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+ auto *callable = %PYARG_2;
+ auto cppCallback = [callable]()
+ {
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef arglist(PyTuple_New(0));
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
+ Py_DECREF(callable);
+ };
+
+ Py_INCREF(callable);
+ %CPPSELF.%FUNCTION_NAME(msec, cppCallback);
+ }
} else {
- Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsO",
- pyTimer,
- SIGNAL(timeout()),
- %PYARG_2)
- );
-}
+ // %FUNCTION_NAME() - disable generation of c++ function call
+ Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+ auto *timerType = Shiboken::SbkType<QTimer>();
+ auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
+ auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
+ auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
+ initFunc(pyTimer, emptyTuple, nullptr);
+
+ QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
+ timer->setSingleShot(true);
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->start(%1);
-// @snippet qtimer-singleshot-2
+ if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+ PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
+ Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
+ Shiboken::AutoDecRef result(
+ PyObject_CallMethod(pyTimer, "connect", "OsOO",
+ pyTimer,
+ SIGNAL(timeout()),
+ PySide::Signal::getObject(signalInstance),
+ signalSignature.object())
+ );
+ } else {
+ Shiboken::AutoDecRef result(
+ PyObject_CallMethod(pyTimer, "connect", "OsO",
+ pyTimer,
+ SIGNAL(timeout()),
+ %PYARG_2)
+ );
+ }
+
+ timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
+ Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
+ Py_XDECREF(pyTimer);
+ timer->start(msec);
+}
+// @snippet qtimer-singleshot-functor
// @snippet qtimer-singleshot-functor-context
auto msec = %1;
diff --git a/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py b/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py
index 9718a2427..2ccaa300e 100644
--- a/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py
+++ b/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py
@@ -14,7 +14,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide6.QtCore import QObject, QThread, QTimer, Signal
+from PySide6.QtCore import QObject, QThread, QTimer, Signal, Slot, SLOT
from helper.usesqapplication import UsesQApplication
@@ -74,6 +74,11 @@ class TestSingleShot(UsesQApplication):
self.app.exec()
self.assertTrue(self.called)
+ def testSingleShotZero(self):
+ QTimer.singleShot(0, self.callback)
+ self.app.exec()
+ self.assertTrue(self.called)
+
def testSingleShotWithContext(self):
thread = ThreadForContext()
thread.start()
@@ -97,6 +102,56 @@ class TestSingleShot(UsesQApplication):
self.assertEqual(self.qthread, thread.qthread)
+class TestSingleShotCallableObject(UsesQApplication):
+ '''Test case for QTimer.singleShot with callable inside an object'''
+
+ def setUp(self):
+ # Acquire resources
+ UsesQApplication.setUp(self)
+ self.watchdog = WatchDog(self)
+
+ def tearDown(self):
+ # Release resources
+ del self.watchdog
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ UsesQApplication.tearDown(self)
+
+ class CallbackObject(QObject):
+ def __init__(self, app) -> None:
+ super().__init__()
+ self.app = app
+
+ @Slot()
+ def func(self):
+ self.called = True
+ self.app.quit()
+
+ def testSingleShotWithObjectAndMember(self):
+ callback = self.CallbackObject(self.app)
+ QTimer.singleShot(100, callback, SLOT("func()"))
+ self.app.exec()
+ self.assertTrue(callback.called)
+
+ def testSingleShotWithObjectAndMemberZero(self):
+ callback = self.CallbackObject(self.app)
+ QTimer.singleShot(0, callback, SLOT("func()"))
+ self.app.exec()
+ self.assertTrue(callback.called)
+
+ def testSingleShotWithCallableInObject(self):
+ callback = self.CallbackObject(self.app)
+ QTimer.singleShot(100, callback.func)
+ self.app.exec()
+ self.assertTrue(callback.called)
+
+ def testSingleShotWithCallableInObjectZero(self):
+ callback = self.CallbackObject(self.app)
+ QTimer.singleShot(0, callback.func)
+ self.app.exec()
+ self.assertTrue(callback.called)
+
+
class SigEmitter(QObject):
sig1 = Signal()
@@ -128,6 +183,13 @@ class TestSingleShotSignal(UsesQApplication):
self.app.exec()
self.assertTrue(self.called)
+ def testSingleShotSignalZero(self):
+ emitter = SigEmitter()
+ emitter.sig1.connect(self.callback)
+ QTimer.singleShot(0, emitter.sig1)
+ self.app.exec()
+ self.assertTrue(self.called)
+
if __name__ == '__main__':
unittest.main()