packages feed

hsqml 0.3.1.0 → 0.3.1.1

raw patch · 11 files changed

+357/−16 lines, 11 files

Files

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))