aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Filho <renato.filho@openbossa.org>2011-05-23 11:39:17 -0300
committerHugo Parente Lima <hugo.pl@gmail.com>2012-03-08 16:54:25 -0300
commit77559ac63945da93f7e90c2910232c6eb2629487 (patch)
treed5647375e1b48d7cef0d344433ddf9c578433829
parentd9c43275a09fc68146a210a9da281a9491d62980 (diff)
Created DestroyListener class.
This class is used to keep the Python object live until the signal destroyed emission. With this is possible to use the QObject on destruction signal. Fixes bug #505. Reviewer: Marcelo Lira <marcelo.lira@openbossa.org> Hugo Parente Lima <hugo.pl@gmail.com>
-rw-r--r--libpyside/CMakeLists.txt6
-rw-r--r--libpyside/destroylistener.cpp67
-rw-r--r--libpyside/destroylistener.h32
-rw-r--r--libpyside/pyside.cpp3
-rw-r--r--tests/QtCore/CMakeLists.txt1
-rw-r--r--tests/QtCore/destroysignal_test.py27
-rw-r--r--tests/QtGui/bug_576.py1
7 files changed, 137 insertions, 0 deletions
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt
index 2d2a61375..e05a8cd7e 100644
--- a/libpyside/CMakeLists.txt
+++ b/libpyside/CMakeLists.txt
@@ -1,7 +1,11 @@
project(libpyside)
+
+qt4_wrap_cpp(DESTROYLISTENER_MOC "destroylistener.h")
+
set(libpyside_SRC
dynamicqmetaobject.cpp
+ destroylistener.cpp
signalmanager.cpp
globalreceiver.cpp
pysideclassinfo.cpp
@@ -11,6 +15,7 @@ set(libpyside_SRC
pysideproperty.cpp
pysideweakref.cpp
pyside.cpp
+ ${DESTROYLISTENER_MOC}
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
@@ -34,6 +39,7 @@ set_target_properties(pyside PROPERTIES
#
set(libpyside_HEADERS
+ destroylistener.h
dynamicqmetaobject.h
globalreceiver.h
pysideclassinfo.h
diff --git a/libpyside/destroylistener.cpp b/libpyside/destroylistener.cpp
new file mode 100644
index 000000000..600d922c3
--- /dev/null
+++ b/libpyside/destroylistener.cpp
@@ -0,0 +1,67 @@
+#include "destroylistener.h"
+
+#include <Python.h>
+#include <QObject>
+#include <shiboken.h>
+#include <QDebug>
+#include <QMutex>
+
+PySide::DestroyListener* PySide::DestroyListener::m_instance = 0;
+
+namespace PySide
+{
+
+struct DestroyListenerPrivate
+{
+ static bool m_destroyed;
+};
+
+
+DestroyListener* DestroyListener::instance()
+{
+ if (!m_instance)
+ m_instance = new DestroyListener(0);
+ return m_instance;
+}
+
+void DestroyListener::destroy()
+{
+ if (m_instance) {
+ m_instance->disconnect();
+ delete m_instance;
+ m_instance = 0;
+ }
+}
+
+void DestroyListener::listen(QObject *obj)
+{
+ SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(obj);
+ if (!wrapper) // avoid problem with multiple inheritance
+ return;
+
+ if (Py_IsInitialized() == 0)
+ onObjectDestroyed(obj);
+ else
+ QObject::connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(onObjectDestroyed(QObject*)), Qt::DirectConnection);
+}
+
+void DestroyListener::onObjectDestroyed(QObject* obj)
+{
+ SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(obj);
+ if (wrapper) //make sure the object exists before destroy
+ Shiboken::Object::destroy(wrapper, obj);
+}
+
+DestroyListener::DestroyListener(QObject *parent)
+ : QObject(parent)
+{
+ m_d = new DestroyListenerPrivate();
+}
+
+DestroyListener::~DestroyListener()
+{
+ delete m_d;
+}
+
+}//namespace
+
diff --git a/libpyside/destroylistener.h b/libpyside/destroylistener.h
new file mode 100644
index 000000000..54dda2c2e
--- /dev/null
+++ b/libpyside/destroylistener.h
@@ -0,0 +1,32 @@
+#ifndef PYSIDE_DESTROY_LISTENER
+#define PYSIDE_DESTROY_LISTENER
+
+
+#include <QObject>
+#include "pysidemacros.h"
+
+namespace PySide
+{
+class DestroyListenerPrivate;
+class PYSIDE_API DestroyListener : public QObject
+{
+ Q_OBJECT
+ public:
+ static DestroyListener* instance();
+ static void destroy();
+ void listen(QObject* obj);
+
+ public slots:
+ void onObjectDestroyed(QObject* obj);
+
+ private:
+ static DestroyListener* m_instance;
+ DestroyListenerPrivate* m_d;
+ DestroyListener(QObject *parent);
+ ~DestroyListener();
+};
+
+}//namespace
+
+#endif
+
diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp
index a4fcbccf0..af763aa44 100644
--- a/libpyside/pyside.cpp
+++ b/libpyside/pyside.cpp
@@ -31,6 +31,7 @@
#include "pysidemetafunction_p.h"
#include "pysidemetafunction.h"
#include "dynamicqmetaobject.h"
+#include "destroylistener.h"
#include <basewrapper.h>
#include <conversions.h>
@@ -101,10 +102,12 @@ void registerCleanupFunction(CleanupFunction func)
void runCleanupFunctions()
{
+ //PySide::DestroyListener::instance()->destroy();
while (!cleanupFunctionList.isEmpty()) {
CleanupFunction f = cleanupFunctionList.pop();
f();
}
+ PySide::DestroyListener::destroy();
}
static void destructionVisitor(SbkObject* pyObj, void* data)
diff --git a/tests/QtCore/CMakeLists.txt b/tests/QtCore/CMakeLists.txt
index 251add10d..365305fef 100644
--- a/tests/QtCore/CMakeLists.txt
+++ b/tests/QtCore/CMakeLists.txt
@@ -21,6 +21,7 @@ PYSIDE_TEST(classinfo_test.py)
PYSIDE_TEST(child_event_test.py)
PYSIDE_TEST(deepcopy_test.py)
PYSIDE_TEST(deletelater_test.py)
+PYSIDE_TEST(destroysignal_test.py)
PYSIDE_TEST(duck_punching_test.py)
PYSIDE_TEST(hash_test.py)
PYSIDE_TEST(max_signals.py)
diff --git a/tests/QtCore/destroysignal_test.py b/tests/QtCore/destroysignal_test.py
new file mode 100644
index 000000000..1c5f986bc
--- /dev/null
+++ b/tests/QtCore/destroysignal_test.py
@@ -0,0 +1,27 @@
+from PySide.QtCore import QTimer, QObject
+import sys
+import unittest
+
+class TestDestroySignal(unittest.TestCase):
+ def onObjectDestroyed(self, timer):
+ self.assert_(isinstance(timer, QTimer))
+ self._destroyed = True
+
+ def testSignal(self):
+ self._destroyed = False
+ t = QTimer()
+ t.destroyed[QObject].connect(self.onObjectDestroyed)
+ del t
+ self.assert_(self._destroyed)
+
+ def testWithParent(self):
+ self._destroyed = False
+ p = QTimer()
+ t = QTimer(p)
+ t.destroyed[QObject].connect(self.onObjectDestroyed)
+ del p
+ self.assert_(self._destroyed)
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/QtGui/bug_576.py b/tests/QtGui/bug_576.py
index b3c11a35c..e66e1099d 100644
--- a/tests/QtGui/bug_576.py
+++ b/tests/QtGui/bug_576.py
@@ -8,6 +8,7 @@ import unittest
class Bug576(unittest.TestCase):
def onButtonDestroyed(self, button):
self._destroyed = True
+ self.assert_(isinstance(button, QtGui.QPushButton))
def testWidgetParent(self):
self._destroyed = False