hsqml 0.3.1.0 → 0.3.1.1
raw patch · 11 files changed
+357/−16 lines, 11 files
Files
- CHANGELOG +5/−0
- cbits/Canvas.cpp +142/−0
- cbits/Canvas.h +78/−0
- cbits/CanvasImpl.cpp +56/−0
- cbits/CanvasImpl.h +41/−0
- cbits/Manager.cpp +18/−4
- cbits/Manager.h +5/−0
- cbits/Object.cpp +2/−0
- hsqml.cabal +4/−4
- src/Graphics/QML/Internal/BindPrim.chs +3/−3
- src/Graphics/QML/Objects.hs +3/−5
CHANGELOG view
@@ -1,5 +1,10 @@ HsQML - Release History +release-0.3.1.1 - 2014.07.31++ * Fixed crash when storing Haskell objects in QML variants.+ * Fixed corrupted logging output caused by threading.+ release-0.3.1.0 - 2014.06.11 * Added properties with constant annotation.
+ cbits/Canvas.cpp view
@@ -0,0 +1,142 @@+#include "Canvas.h"+#include "CanvasImpl.h"++HsQMLGLDelegate::HsQMLGLDelegate(+ HsQMLGLPaintCb paintCb)+ : mImpl(new HsQMLGLDelegateImpl(paintCb))+{+}++HsQMLGLDelegate::~HsQMLGLDelegate()+{+}++HsQMLCanvas::HsQMLCanvas(QQuickItem* parent)+ : QQuickItem(parent)+ , mWindow(NULL)+ , mBackEnd(NULL)+ , mDisplayMode(Inline)+ , mCanvasWidth(0)+ , mCanvasWidthSet(false)+ , mCanvasHeight(0)+ , mCanvasHeightSet(false)+{+ QObject::connect(+ this, SIGNAL(windowChanged(QQuickWindow*)),+ this, SLOT(doWindowChanged(QQuickWindow*)));+}++HsQMLCanvas::~HsQMLCanvas()+{+ detachBackEnd();+}++void HsQMLCanvas::geometryChanged(const QRectF& rect, const QRectF&)+{+ if (!mCanvasWidthSet) {+ setCanvasWidth(rect.width(), false);+ }+ if (!mCanvasHeightSet) {+ setCanvasHeight(rect.height(), false);+ }+}++void HsQMLCanvas::detachBackEnd()+{+ if (mBackEnd) {+ // The back-end belongs to the rendering thread+ mBackEnd->deleteLater();+ mBackEnd = NULL;+ }+}++HsQMLCanvas::DisplayMode HsQMLCanvas::displayMode() const+{+ return mDisplayMode;+}++void HsQMLCanvas::setDisplayMode(HsQMLCanvas::DisplayMode mode)+{+ bool change = mDisplayMode != mode;+ mDisplayMode = mode;+ if (change) {+ displayModeChanged();+ }+}++qreal HsQMLCanvas::canvasWidth() const+{+ return mCanvasWidth;+}++void HsQMLCanvas::setCanvasWidth(qreal w, bool set)+{+ bool change = mCanvasWidth != w;+ mCanvasWidth = w;+ mCanvasWidthSet |= set;+ if (change) {+ canvasWidthChanged();+ }+}++void HsQMLCanvas::unsetCanvasWidth()+{+ mCanvasWidthSet = false;+ setCanvasWidth(width(), false);+}++qreal HsQMLCanvas::canvasHeight() const+{+ return mCanvasHeight;+}++void HsQMLCanvas::setCanvasHeight(qreal h, bool set)+{+ bool change = mCanvasHeight != h;+ mCanvasHeight = h;+ mCanvasHeightSet |= set;+ if (change) {+ canvasHeightChanged();+ }+}++void HsQMLCanvas::unsetCanvasHeight()+{+ mCanvasHeightSet = false;+ setCanvasHeight(height(), false);+}++void HsQMLCanvas::doWindowChanged(QQuickWindow* win)+{+ if (mWindow) {+ QObject::disconnect(mWindow, NULL, this, NULL);+ detachBackEnd();+ }+ mWindow = win;+ if (mWindow) {+ QObject::connect(+ mWindow, SIGNAL(beforeSynchronizing()),+ this, SLOT(doPreSynchronise()), Qt::DirectConnection);+ }+}++void HsQMLCanvas::doPreSynchronise()+{+ // This executes on the rendering thread+ if (!mBackEnd) {+ mBackEnd = new HsQMLCanvasBackEnd(mWindow);+ }+ mBackEnd->setModeSize(mDisplayMode, mCanvasWidth, mCanvasHeight);+}++HsQMLGLControl::HsQMLGLControl(QQuickItem* parent)+ : QQuickItem(parent)+{}++void hsqml_init_jval_gldelegate(+ HsQMLJValHandle* hndl,+ HsQMLGLPaintCb paintCb)+{+ QJSValue* value = reinterpret_cast<QJSValue*>(hndl);+ HsQMLGLDelegate delegate(paintCb);+}
+ cbits/Canvas.h view
@@ -0,0 +1,78 @@+#ifndef HSQML_CANVAS_H+#define HSQML_CANVAS_H++#include <QtCore/QExplicitlySharedDataPointer>+#include <QtQuick/QQuickItem>++#include "hsqml.h"++class HsQMLCanvasBackEnd;+class HsQMLGLDelegateImpl;++class HsQMLGLDelegate+{+public:+ HsQMLGLDelegate(HsQMLGLPaintCb);+ ~HsQMLGLDelegate();++private:+ QExplicitlySharedDataPointer<HsQMLGLDelegateImpl> mImpl;+};++class HsQMLCanvas : public QQuickItem+{+ Q_OBJECT+ Q_ENUMS(DisplayMode)+ Q_PROPERTY(DisplayMode displayMode READ displayMode WRITE setDisplayMode+ NOTIFY displayModeChanged)+ Q_PROPERTY(qreal canvasWidth READ canvasWidth WRITE setCanvasWidth+ RESET unsetCanvasWidth NOTIFY canvasWidthChanged)+ Q_PROPERTY(qreal canvasHeight READ canvasHeight WRITE setCanvasHeight+ RESET unsetCanvasHeight NOTIFY canvasHeightChanged)++public:+ enum DisplayMode {Above, Below, Inline};++ HsQMLCanvas(QQuickItem* = NULL);+ ~HsQMLCanvas();++private:+ Q_DISABLE_COPY(HsQMLCanvas);++ void geometryChanged(const QRectF&, const QRectF&) Q_DECL_OVERRIDE;+ void detachBackEnd();+ DisplayMode displayMode() const;+ void setDisplayMode(DisplayMode);+ qreal canvasWidth() const;+ void setCanvasWidth(qreal, bool = true);+ void unsetCanvasWidth();+ qreal canvasHeight() const;+ void setCanvasHeight(qreal, bool = true);+ void unsetCanvasHeight();+ Q_SIGNAL void displayModeChanged();+ Q_SIGNAL void canvasWidthChanged();+ Q_SIGNAL void canvasHeightChanged();+ Q_SLOT void doWindowChanged(QQuickWindow*);+ Q_SLOT void doPreSynchronise();++ QQuickWindow* mWindow;+ HsQMLCanvasBackEnd* mBackEnd;+ DisplayMode mDisplayMode;+ qreal mCanvasWidth;+ bool mCanvasWidthSet;+ qreal mCanvasHeight;+ bool mCanvasHeightSet;+};++class HsQMLGLControl : public QQuickItem+{+ Q_OBJECT++public:+ HsQMLGLControl(QQuickItem* = NULL);++private:+ Q_DISABLE_COPY(HsQMLGLControl);+};++#endif //HSQML_CANVAS_H
+ cbits/CanvasImpl.cpp view
@@ -0,0 +1,56 @@+#include <QtCore/qmath.h>++#include "CanvasImpl.h"+#include "Manager.h"++HsQMLGLDelegateImpl::HsQMLGLDelegateImpl(HsQMLGLPaintCb paintCb)+ : mPaintCb(paintCb)+{}++HsQMLGLDelegateImpl::~HsQMLGLDelegateImpl()+{+ gManager->freeFun(reinterpret_cast<HsFunPtr>(mPaintCb));+}++HsQMLCanvasBackEnd::HsQMLCanvasBackEnd(QQuickWindow* win)+{+ QObject::connect(+ win, SIGNAL(beforeRendering()),+ this, SLOT(doRendering()));+}++HsQMLCanvasBackEnd::~HsQMLCanvasBackEnd()+{+}++void HsQMLCanvasBackEnd::setModeSize(+ HsQMLCanvas::DisplayMode mode, qreal w, qreal h)+{+ mDisplayMode = mode;+ mCanvasWidth = w;+ mCanvasHeight = h;++ if (HsQMLCanvas::Inline == mode) {+ if (!mFBO || mFBO->width() != w || mFBO->height() != h) {+ mFBO.reset(new QOpenGLFramebufferObject(+ qCeil(w), qCeil(h), QOpenGLFramebufferObject::Depth));+ }+ }+ else {+ mFBO.reset();+ }+}++void HsQMLCanvasBackEnd::doRendering()+{+ bool inlineMode = HsQMLCanvas::Inline == mDisplayMode;+ if (inlineMode && !mFBO) {+ return;+ }+ if (inlineMode) {+ mFBO->bind();+ }+ if (inlineMode) {+ mFBO->release();+ }+}
+ cbits/CanvasImpl.h view
@@ -0,0 +1,41 @@+#ifndef HSQML_CANVAS_IMPL_H+#define HSQML_CANVAS_IMPL_H++#include <QtCore/QObject>+#include <QtCore/QScopedPointer>+#include <QtCore/QSharedData>+#include <QtGui/QOpenGLFramebufferObject>+#include <QtQuick/QQuickWindow>++#include "Canvas.h"++class HsQMLGLDelegateImpl : public QSharedData+{+public:+ HsQMLGLDelegateImpl(HsQMLGLPaintCb);+ ~HsQMLGLDelegateImpl();++ HsQMLGLPaintCb mPaintCb;+};++class HsQMLCanvasBackEnd : public QObject+{+ Q_OBJECT++public:+ HsQMLCanvasBackEnd(QQuickWindow*);+ ~HsQMLCanvasBackEnd();+ void setModeSize(HsQMLCanvas::DisplayMode, qreal, qreal);++private:+ Q_DISABLE_COPY(HsQMLCanvasBackEnd)++ Q_SLOT void doRendering();++ HsQMLCanvas::DisplayMode mDisplayMode;+ qreal mCanvasWidth;+ qreal mCanvasHeight;+ QScopedPointer<QOpenGLFramebufferObject> mFBO;+};++#endif //HSQML_CANVAS_IMPL_H
cbits/Manager.cpp view
@@ -1,4 +1,4 @@-#include <iostream>+#include <cstdio> #include <cstdlib> #include <QtCore/QBasicTimer> #include <QtCore/QMetaType>@@ -101,7 +101,8 @@ void HsQMLManager::log(const QString& msg) {- std::cerr << "HsQML: " << msg.toStdString() << std::endl;+ QMutexLocker locker(&mLogLock);+ fprintf(stderr, "HsQML: %s\n", msg.toUtf8().data()); } int HsQMLManager::updateCounter(CounterId id, int delta)@@ -119,6 +120,17 @@ mFreeStable(stablePtr); } +void HsQMLManager::registerObject(const QObject* obj)+{+ mObjectSet.insert(obj);+}++void HsQMLManager::unregisterObject(const QObject* obj)+{+ bool removed = mObjectSet.remove(obj);+ Q_ASSERT(removed);+}+ void HsQMLManager::hookedConstruct(QVariant::Private* p, const void* copy) { char guard;@@ -134,7 +146,8 @@ // that the stack can be discounted, it's possible to keep an accurate // count of heap references using these hooks. if ((pp < &guard || pp > mStackBase) && p->type == QMetaType::QObjectStar) {- if (HsQMLObject* obj = dynamic_cast<HsQMLObject*>(p->data.o)) {+ if (isEventThread() && mObjectSet.contains(p->data.o)) {+ HsQMLObject* obj = static_cast<HsQMLObject*>(p->data.o); HsQMLObjectProxy* proxy = obj->proxy(); proxy->ref(HsQMLObjectProxy::Variant); proxy->tryGCLock();@@ -148,7 +161,8 @@ char guard; void* pp = reinterpret_cast<void*>(p); if ((pp < &guard || pp > mStackBase) && p->type == QMetaType::QObjectStar) {- if (HsQMLObject* obj = dynamic_cast<HsQMLObject*>(p->data.o)) {+ if (isEventThread() && mObjectSet.contains(p->data.o)) {+ HsQMLObject* obj = static_cast<HsQMLObject*>(p->data.o); obj->proxy()->deref(HsQMLObjectProxy::Variant); updateCounter(VariantCount, -1); }
cbits/Manager.h view
@@ -4,6 +4,7 @@ #include <QtCore/QAtomicPointer> #include <QtCore/QAtomicInt> #include <QtCore/QMutex>+#include <QtCore/QSet> #include <QtCore/QString> #include <QtCore/QVariant> #include <QtWidgets/QApplication>@@ -38,6 +39,8 @@ int updateCounter(CounterId, int); void freeFun(HsFunPtr); void freeStable(HsStablePtr);+ void registerObject(const QObject*);+ void unregisterObject(const QObject*); void hookedConstruct(QVariant::Private*, const void*); void hookedClear(QVariant::Private*); bool isEventThread();@@ -57,10 +60,12 @@ Q_DISABLE_COPY(HsQMLManager) int mLogLevel;+ QMutex mLogLock; QAtomicInt mCounters[TotalCounters]; bool mAtExit; void (*mFreeFun)(HsFunPtr); void (*mFreeStable)(HsStablePtr);+ QSet<const QObject*> mObjectSet; const QVariant::Handler* mOriginalHandler; QVariant::Handler mHookedHandler; HsQMLManagerApp* mApp;
cbits/Object.cpp view
@@ -167,6 +167,7 @@ QQmlEngine::setObjectOwnership( this, QQmlEngine::JavaScriptOwnership); mProxy->ref(HsQMLObjectProxy::Object);+ gManager->registerObject(this); gManager->updateCounter(HsQMLManager::QObjectCount, 1); } @@ -174,6 +175,7 @@ { mProxy->clearObject(); mProxy->deref(HsQMLObjectProxy::Object);+ gManager->unregisterObject(this); gManager->updateCounter(HsQMLManager::QObjectCount, -1); }
hsqml.cabal view
@@ -1,5 +1,5 @@ Name: hsqml-Version: 0.3.1.0+Version: 0.3.1.1 Cabal-version: >= 1.14 Build-type: Custom License: BSD3@@ -16,9 +16,9 @@ README CHANGELOG SetupNoTH.hs cbits/*.cpp cbits/*.h test/Graphics/QML/Test/*.hs Description:- A Haskell binding for Qt Quick.-- General documentation is present in the 'Graphics.QML' module.+ A Haskell binding for Qt Quick, a cross-platform framework for creating+ graphical user interfaces. For further information on installing and using+ this library, please see the project's web site. Flag UsePkgConfig Description:
src/Graphics/QML/Internal/BindPrim.chs view
@@ -26,7 +26,7 @@ `Int' fromIntegral #} hsqmlStringSize :: Int-hsqmlStringSize = unsafePerformIO $ hsqmlGetStringSize+hsqmlStringSize = unsafeDupablePerformIO $ hsqmlGetStringSize {#fun unsafe hsqml_init_string as ^ {id `HsQMLStringHandle'} ->@@ -66,14 +66,14 @@ `Int' fromIntegral #} hsqmlJValSize :: Int-hsqmlJValSize = unsafePerformIO $ hsqmlGetJvalSize+hsqmlJValSize = unsafeDupablePerformIO $ hsqmlGetJvalSize {#fun unsafe hsqml_get_jval_typeid as ^ {} -> `Int' fromIntegral #} hsqmlJValTypeId :: Int-hsqmlJValTypeId = unsafePerformIO $ hsqmlGetJvalTypeid+hsqmlJValTypeId = unsafeDupablePerformIO $ hsqmlGetJvalTypeid {#fun unsafe hsqml_init_jval_null as ^ {id `HsQMLJValHandle',
src/Graphics/QML/Objects.hs view
@@ -128,12 +128,10 @@ -- | Returns the associated value of the underlying Haskell type @tt@ from an -- instance of the QML class which wraps it. fromObjRef :: ObjRef tt -> tt-fromObjRef =- unsafePerformIO . fromObjRefIO+fromObjRef = unsafeDupablePerformIO . fromObjRefIO fromObjRefIO :: ObjRef tt -> IO tt-fromObjRefIO =- hsqmlObjectGetHsValue . objHndl +fromObjRefIO = hsqmlObjectGetHsValue . objHndl -- | Represents an instance of a QML class which wraps an arbitrary Haskell -- type. Unlike 'ObjRef', an 'AnyObjRef' only carries the type of its Haskell@@ -170,7 +168,7 @@ -- | Attempts to downcast an 'AnyObjRef' into an 'ObjRef' with the specific -- underlying Haskell type @tt@. fromAnyObjRef :: (Typeable tt) => AnyObjRef -> Maybe (ObjRef tt)-fromAnyObjRef = unsafePerformIO . fromAnyObjRefIO+fromAnyObjRef = unsafeDupablePerformIO . fromAnyObjRefIO fromAnyObjRefIO :: forall tt. (Typeable tt) => AnyObjRef -> IO (Maybe (ObjRef tt))