hsqml 0.3.2.0 → 0.3.2.1
raw patch · 9 files changed
+112/−21 lines, 9 files
Files
- CHANGELOG +7/−0
- cbits/Manager.cpp +57/−17
- cbits/Manager.h +3/−1
- cbits/Object.cpp +5/−1
- cbits/hsqml.h +3/−0
- hsqml.cabal +8/−1
- src/Graphics/QML/Engine.hs +24/−0
- src/Graphics/QML/Internal/BindCore.chs +4/−0
- src/Graphics/QML/Objects.hs +1/−1
CHANGELOG view
@@ -1,5 +1,12 @@ HsQML - Release History +release-0.3.2.1 - 2014.11.29++ * Added function to shutdown the Qt framework.+ * Fixed intermittent crash on exit under Linux.+ * Fixed reanimated objects being passed to QML as undefined.+ * Fixed typo in the names of implicit property signals.+ release-0.3.2.0 - 2014.11.13 * Added OpenGL canvas support.
cbits/Manager.cpp view
@@ -28,8 +28,20 @@ "ObjectSerial" }; -extern "C" void hsqml_dump_counters()+// This definition overrides a symbol in the GHC RTS+#ifdef HSQML_USE_EXIT_HOOK+#ifdef Q_OS_LINUX // TODO: Test on other platforms.+extern "C" void OnExitHook() {+ if (gManager) {+ gManager->shutdown();+ }+}+#endif+#endif++static void dump_counters()+{ Q_ASSERT (gManager); if (gManager->checkLogLevel(1)) { for (int i=0; i<HsQMLManager::TotalCounters; i++) {@@ -60,11 +72,11 @@ , mFreeFun(freeFun) , mFreeStable(freeStable) , mOriginalHandler(qcoreVariantHandler())- , mHookedHandler(*mOriginalHandler) , mApp(NULL) , mLock(QMutex::Recursive) , mRunning(false) , mRunCount(0)+ , mShutdown(false) , mStackBase(NULL) , mStartCb(NULL) , mJobsCb(NULL)@@ -76,17 +88,13 @@ if (env) { setLogLevel(QString(env).toInt()); }-- // Set hooked handler functions- mHookedHandler.construct = &hooked_construct;- mHookedHandler.clear = &hooked_clear; } void HsQMLManager::setLogLevel(int ll) { mLogLevel = ll; if (ll > 0 && !mAtExit) {- if (atexit(&hsqml_dump_counters) == 0) {+ if (atexit(&dump_counters) == 0) { mAtExit = true; } else {@@ -183,10 +191,13 @@ { QMutexLocker locker(&mLock); - // Check if already running+ // Check for invalid state if (mRunning) { return HSQML_EVLOOP_ALREADY_RUNNING; }+ else if (mShutdown) {+ return HSQML_EVLOOP_POST_SHUTDOWN;+ } // Check if event loop bound to a different thread if (mApp && !isEventThread()) {@@ -207,16 +218,8 @@ "Warning: CPU cannot idle when using the non-threaded RTS."); } - // Perform one-time initialisation+ // Create application object if (!mApp) {- // Install hooked handler for QVariants- QVariantPrivate::registerHandler(0, &mHookedHandler);-- // Register custom types- qRegisterMetaType<HsQMLEngineConfig>("HsQMLEngineConfig");- qmlRegisterType<HsQMLCanvas>("HsQML.Canvas", 1, 0, "HaskellCanvas");-- // Create application object mApp = new HsQMLManagerApp(); } @@ -329,13 +332,42 @@ QCoreApplication::postEvent(mApp, ev); } +HsQMLManager::EventLoopStatus HsQMLManager::shutdown()+{+ QMutexLocker locker(&mLock);++ if (mRunning) {+ return HSQML_EVLOOP_ALREADY_RUNNING;+ }+ else if (isEventThread()) {+ HSQML_LOG(1, "Deleting QApplication object.");+ delete mApp;+ mApp = NULL;+ mShutdown = true;+ }+ else if (mApp) {+ return HSQML_EVLOOP_WRONG_THREAD; + }+ return HSQML_EVLOOP_OK;+}+ HsQMLManagerApp::HsQMLManagerApp() : mArgC(1) , mArg0(0) , mArgV(&mArg0)+ , mHookedHandler(*gManager->mOriginalHandler) , mApp(mArgC, &mArgV) { mApp.setQuitOnLastWindowClosed(false);++ // Install hooked handler for QVariants+ mHookedHandler.construct = &hooked_construct;+ mHookedHandler.clear = &hooked_clear;+ QVariantPrivate::registerHandler(0, &mHookedHandler);++ // Register custom types+ qRegisterMetaType<HsQMLEngineConfig>("HsQMLEngineConfig");+ qmlRegisterType<HsQMLCanvas>("HsQML.Canvas", 1, 0, "HaskellCanvas"); } HsQMLManagerApp::~HsQMLManagerApp()@@ -415,6 +447,14 @@ extern "C" void hsqml_evloop_notify_jobs() { gManager->notifyJobs();+}++extern "C" HsQMLEventLoopStatus hsqml_evloop_shutdown()+{+ if (gManager) {+ return gManager->shutdown();+ }+ return HSQML_EVLOOP_OK; } extern "C" void hsqml_set_debug_loglevel(int ll)
cbits/Manager.h view
@@ -54,6 +54,7 @@ void setActiveEngine(HsQMLEngine*); HsQMLEngine* activeEngine(); void postObjectEvent(HsQMLObjectEvent*);+ EventLoopStatus shutdown(); private: friend class HsQMLManagerApp;@@ -67,11 +68,11 @@ void (*mFreeStable)(HsStablePtr); QSet<const QObject*> mObjectSet; const QVariant::Handler* mOriginalHandler;- QVariant::Handler mHookedHandler; HsQMLManagerApp* mApp; QMutex mLock; bool mRunning; int mRunCount;+ bool mShutdown; void* mStackBase; HsQMLTrivialCb mStartCb; HsQMLTrivialCb mJobsCb;@@ -113,6 +114,7 @@ int mArgC; char mArg0; char* mArgV;+ QVariant::Handler mHookedHandler; QApplication mApp; };
cbits/Object.cpp view
@@ -57,12 +57,16 @@ Q_ASSERT(engine); if (!mObject) { mObject = new HsQMLObject(this, engine);- tryGCLock(); HSQML_LOG(5, QString().sprintf("New QObject, class=%s, id=%d, qptr=%p.", mKlass->name(), mSerial, mObject)); }++ // Old objects may have lost their lock via weak references in addition+ // to new objects needing it.+ tryGCLock();+ return mObject; }
cbits/hsqml.h view
@@ -21,6 +21,7 @@ typedef enum { HSQML_EVLOOP_OK = 0, HSQML_EVLOOP_ALREADY_RUNNING,+ HSQML_EVLOOP_POST_SHUTDOWN, HSQML_EVLOOP_WRONG_THREAD, HSQML_EVLOOP_NOT_RUNNING, HSQML_EVLOOP_OTHER_ERROR@@ -36,6 +37,8 @@ extern void hsqml_evloop_release(); extern void hsqml_evloop_notify_jobs();++extern HsQMLEventLoopStatus hsqml_evloop_shutdown(); /* String */ typedef char HsQMLStringHandle;
hsqml.cabal view
@@ -1,5 +1,5 @@ Name: hsqml-Version: 0.3.2.0+Version: 0.3.2.1 Cabal-version: >= 1.14 Build-type: Custom License: BSD3@@ -35,6 +35,11 @@ Force enable GHCi workaround library if not using shared libraries. Default: True +Flag UseExitHook+ Description:+ Override the OnExitHook symbol to shutdown the Qt framework on exit.+ Default: True+ Library Default-language: Haskell2010 Build-depends:@@ -79,6 +84,8 @@ Build-tools: c2hs if flag(ForceGHCiLib) X-force-ghci-lib: True+ if flag(UseExitHook)+ CC-options: -DHSQML_USE_EXIT_HOOK if os(windows) && !flag(UsePkgConfig) Include-dirs: /QT_ROOT/include Extra-libraries:
src/Graphics/QML/Engine.hs view
@@ -22,6 +22,7 @@ RunQML(), runEventLoop, requireEventLoop,+ shutdownQt, EventLoopException(), -- * Document Paths@@ -168,9 +169,31 @@ Nothing -> return () bracket_ reqFn hsqmlEvloopRelease runFn +-- | Shuts down and frees resources used by the Qt framework, preventing+-- further use of the event loop. The framework is initialised when+-- 'runEventLoop' is first called and remains initialised afterwards so that+-- the event loop can be reentered if desired (e.g. when using GHCi). Once+-- shut down, the framework cannot be reinitialised.+--+-- It is recommended that you call this function at the end of your program as+-- this library will try, but cannot guarantee in all configurations to be able+-- to shut it down for you. Failing to shutdown the framework has been known to+-- intermittently cause crashes on process exit on some platforms.+--+-- This function must be called from the event loop thread and the event loop+-- must not be running at the time otherwise an 'EventLoopException' will be+-- thrown.+shutdownQt :: IO ()+shutdownQt = do+ status <- hsqmlEvloopShutdown+ case statusException status of+ Just ex -> throw ex+ Nothing -> return ()+ statusException :: HsQMLEventLoopStatus -> Maybe EventLoopException statusException HsqmlEvloopOk = Nothing statusException HsqmlEvloopAlreadyRunning = Just EventLoopAlreadyRunning+statusException HsqmlEvloopPostShutdown = Just EventLoopPostShutdown statusException HsqmlEvloopWrongThread = Just EventLoopWrongThread statusException HsqmlEvloopNotRunning = Just EventLoopNotRunning statusException _ = Just EventLoopOtherError@@ -178,6 +201,7 @@ -- | Exception type used to report errors pertaining to the event loop. data EventLoopException = EventLoopAlreadyRunning+ | EventLoopPostShutdown | EventLoopWrongThread | EventLoopNotRunning | EventLoopOtherError
src/Graphics/QML/Internal/BindCore.chs view
@@ -63,6 +63,10 @@ {} -> `()' #} +{#fun unsafe hsqml_evloop_shutdown as ^+ {} ->+ `HsQMLEventLoopStatus' cIntToEnum #}+ {#fun hsqml_create_engine as ^ {withMaybeHsQMLObjectHandle* `Maybe HsQMLObjectHandle', id `HsQMLStringHandle',
src/Graphics/QML/Objects.hs view
@@ -150,7 +150,7 @@ impKeys = filter (flip Set.notMember sigKeys) $ mapMaybe memberKey $ filterMembers PropertyMember ms impMember i k = Member SignalMember- ("__implictSignal" ++ show i)+ ("__implicitSignal" ++ show i) tyVoid [] (\_ _ -> return ())