diff options
author | Adrian Herrmann <adrian.herrmann@qt.io> | 2023-11-16 20:37:13 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-11-24 19:12:29 +0000 |
commit | eccbfd9bf3cbc9b6b497933ce9ddda90863bf046 (patch) | |
tree | 992df787cda1d1e8e08353c43ab81da5806c43b8 | |
parent | c3275fe632022b38c6ce06716f671bafb6c0bf38 (diff) |
QTimer: Implement singleShot signatures w/ context
On C++, it is possible to call singleShot timers with a context object
as an argument. This allows posting events to the event loop of the
given context object's thread, instead of the thread of the current
thread. Implement corresponding signatures to add this capability to
Qt for Python.
Change-Id: I0c4e3ef4b859cdfaac07415ff64c440821e7f442
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
(cherry picked from commit 671c182dce91c387037894017be314564e054c00)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/PySide6/QtCore/typesystem_core_common.xml | 6 | ||||
-rw-r--r-- | sources/pyside6/PySide6/glue/qtcore.cpp | 37 | ||||
-rw-r--r-- | sources/pyside6/tests/QtCore/qtimer_singleshot_test.py | 30 |
3 files changed, 71 insertions, 2 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index 2ef6a25e5..2011bd3e7 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -2514,12 +2514,18 @@ <include file-name="QtCore/qbuffer.h" location="global"/> </object-type> <object-type name="QTimer"> + <extra-includes> + <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"/> </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> + <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"/> + </add-function> </object-type> <object-type name="QProcess"> <configuration condition="QT_CONFIG(process)"/> diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index d0f2e8d6d..52a07aa26 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -1053,6 +1053,43 @@ Py_XDECREF(pyTimer); timer->start(%1); // @snippet qtimer-singleshot-2 +// @snippet qtimer-singleshot-functor-context +Shiboken::AutoDecRef emptyTuple(PyTuple_New(0)); +if (PyObject_TypeCheck(%3, PySideSignalInstance_TypeF())) { + auto *timerType = Shiboken::SbkType<QTimer>(); + auto *pyTimer = timerType->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr); + timerType->tp_init(pyTimer, emptyTuple, nullptr); + QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer); + timer->setSingleShot(true); + PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2); + Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance))); + Shiboken::AutoDecRef result( + PyObject_CallFunction(PySide::PySideName::qtConnect(), "OsOO", + pyTimer, + SIGNAL(timeout()), + %3, + PySide::Signal::getObject(signalInstance), + signalSignature.object()) + ); + timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection); + Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer)); + Py_XDECREF(pyTimer); + timer->start(%1); +} else { + auto *callable = %PYARG_3; + 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(%1, %2, cppCallback); +} +// @snippet qtimer-singleshot-functor-context + // @snippet qprocess-startdetached qint64 pid; %RETURN_TYPE retval = %TYPE::%FUNCTION_NAME(%1, %2, %3, &pid); diff --git a/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py b/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py index 770c9c1a9..1392281fa 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, QTimer, QCoreApplication, Signal +from PySide6.QtCore import QObject, QThread, QTimer, Signal from helper.usesqapplication import UsesQApplication @@ -32,6 +32,19 @@ class WatchDog(QObject): self.watched.exit_app_cb() +class ThreadForContext(QThread): + def __init__(self): + super().__init__() + self.called = False + self.qthread = None + self.context = QObject() + + def run(self): + self.called = True + self.qthread = QThread.currentThread() + self.exec() + + class TestSingleShot(UsesQApplication): '''Test case for QTimer.singleShot''' @@ -40,6 +53,7 @@ class TestSingleShot(UsesQApplication): UsesQApplication.setUp(self) self.watchdog = WatchDog(self) self.called = False + self.qthread = None def tearDown(self): # Release resources @@ -51,6 +65,8 @@ class TestSingleShot(UsesQApplication): def callback(self): self.called = True + self.qthread = QThread.currentThread() + self.qthread.exit() self.app.quit() def testSingleShot(self): @@ -58,6 +74,17 @@ class TestSingleShot(UsesQApplication): self.app.exec() self.assertTrue(self.called) + def testSingleShotWithContext(self): + thread = ThreadForContext() + thread.start() + thread.context.moveToThread(thread) + QTimer.singleShot(100, thread.context, self.callback) + self.app.exec() + thread.wait() + self.assertTrue(self.called) + self.assertTrue(thread.called) + self.assertEqual(self.qthread, thread.qthread) + class SigEmitter(QObject): @@ -93,4 +120,3 @@ class TestSingleShotSignal(UsesQApplication): if __name__ == '__main__': unittest.main() - |