diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2010-2012, Robin KAY
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Robin KAY nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,224 @@
+#!/usr/bin/runhaskell 
+module Main where
+
+import Data.List
+import Distribution.Simple
+import Distribution.Simple.LocalBuildInfo
+import Distribution.Simple.PackageIndex
+import Distribution.Simple.Setup
+import Distribution.Simple.Utils (rawSystemExit)
+import qualified Distribution.InstalledPackageInfo as I
+import Distribution.PackageDescription
+import System.Directory
+import System.FilePath
+
+import Control.Monad
+import Data.Char
+import Data.Maybe
+import qualified Distribution.ModuleName as ModuleName
+import Distribution.Simple.BuildPaths
+import Distribution.Simple.Program
+import Distribution.Simple.Program.Ld
+import Distribution.Simple.Register
+import Distribution.Simple.Utils
+import Distribution.Text
+import Distribution.Version
+import Distribution.Verbosity
+import System.FilePath
+
+main :: IO ()
+main = defaultMainWithHooks simpleUserHooks {
+  confHook = confWithQt, buildHook = buildWithQt,
+  copyHook = copyWithQt, instHook = instWithQt,
+  regHook = regWithQt}
+
+confWithQt :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags ->
+  IO LocalBuildInfo
+confWithQt (gpd,hbi) flags = do
+  let verb = fromFlag $ configVerbosity flags
+  mocPath <- findProgramLocation verb "moc"
+  cppPath <- findProgramLocation verb "cpp"
+  let condLib = fromJust $ condLibrary gpd
+      fixCondLib lib = lib {
+        libBuildInfo = substPaths mocPath cppPath $ libBuildInfo lib} 
+      condLib' = mapCondTree fixCondLib condLib
+      gpd' = gpd {condLibrary = Just $ condLib'}
+  lbi <- confHook simpleUserHooks (gpd',hbi) flags
+  (_,_,db') <- requireProgramVersion verb
+    mocProgram qtVersionRange (withPrograms lbi)
+  return $ lbi {withPrograms = db'}
+
+mapCondTree :: (a -> a) -> CondTree v c a -> CondTree v c a
+mapCondTree f (CondNode val cnstr cs) =
+  CondNode (f val) cnstr $ map updateChildren cs
+  where updateChildren (cond,left,right) =
+          (cond, mapCondTree f left, fmap (mapCondTree f) right)
+
+substPaths :: Maybe FilePath -> Maybe FilePath -> BuildInfo -> BuildInfo
+substPaths mocPath cppPath build =
+  let toRoot = takeDirectory . takeDirectory . fromMaybe ""
+      substPath = replacePrefix "/QT_ROOT" (toRoot mocPath) .
+        replacePrefix "/SYS_ROOT" (toRoot cppPath)
+  in build {extraLibDirs = map substPath $ extraLibDirs build,
+            includeDirs = map substPath $ includeDirs build}
+
+replacePrefix :: (Eq a) => [a] -> [a] -> [a] -> [a]
+replacePrefix old new xs =
+  case stripPrefix old xs of
+    Just ys -> new ++ ys
+    Nothing -> xs
+
+buildWithQt ::
+  PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
+buildWithQt pkgDesc lbi hooks flags = do
+    let verb = fromFlag $ buildVerbosity flags
+    libs' <- maybeMapM (\lib -> fmap (\lib' ->
+      lib {libBuildInfo = lib'}) $ fixQtBuild verb lbi $ libBuildInfo lib) $
+      library pkgDesc
+    exes' <- mapM (\exe -> fmap (\exe' ->
+      exe {buildInfo = exe'}) $ fixQtBuild verb lbi $ buildInfo exe) $
+      executables pkgDesc
+    let pkgDesc' = pkgDesc {library = libs', executables = exes'}
+        lbi' = if (needsGHCiFix pkgDesc lbi)
+                 then lbi {withGHCiLib = False, splitObjs = False} else lbi
+    buildHook simpleUserHooks pkgDesc' lbi' hooks flags
+    case libs' of
+      Just lib -> when (needsGHCiFix pkgDesc lbi) $
+        buildGHCiFix verb pkgDesc lbi lib
+      Nothing  -> return ()
+
+fixQtBuild :: Verbosity -> LocalBuildInfo -> BuildInfo -> IO BuildInfo
+fixQtBuild verb lbi build = do
+  let moc  = fromJust $ lookupProgram mocProgram $ withPrograms lbi
+      incs = words $ fromMaybe "" $ lookup "x-moc-headers" $
+        customFieldsBI build
+      bDir = buildDir lbi
+      cpps = map (\inc ->
+        bDir </> (takeDirectory inc) </>
+        ("moc_" ++ (takeBaseName inc) ++ ".cpp")) incs
+  mapM_ (\(i,o) -> do
+      createDirectoryIfMissingVerbose verb True (takeDirectory o)
+      runProgram verb moc [i,"-o",o]) $ zip incs cpps
+  return build {cSources = cpps ++ cSources build,
+                ccOptions = "-fPIC" : ccOptions build}
+
+needsGHCiFix :: PackageDescription -> LocalBuildInfo -> Bool
+needsGHCiFix pkgDesc lbi =
+  (withGHCiLib lbi &&) $ fromMaybe False $ do
+    lib <- library pkgDesc
+    str <- lookup "x-separate-cbits" $ customFieldsBI $ libBuildInfo lib
+    simpleParse str
+
+mkGHCiFixLibPkgId :: PackageDescription -> PackageIdentifier
+mkGHCiFixLibPkgId pkgDesc =
+  let id = packageId pkgDesc
+      (PackageName name) = pkgName id
+  in id {pkgName = PackageName $ "cbits-" ++ name}
+
+mkGHCiFixLibName :: PackageDescription -> String
+mkGHCiFixLibName pkgDesc =
+  ("lib" ++ display (mkGHCiFixLibPkgId pkgDesc)) <.> dllExtension
+
+buildGHCiFix ::
+  Verbosity -> PackageDescription -> LocalBuildInfo -> Library -> IO ()
+buildGHCiFix verb pkgDesc lbi lib = do
+  let bDir = buildDir lbi
+      ms = map ModuleName.toFilePath $ libModules lib
+      hsObjs = map ((bDir </>) . (<.> "o")) ms
+  stubObjs <- fmap catMaybes $
+    mapM (findFileWithExtension ["o"] [bDir]) $ map (++ "_stub") ms
+  (ld,_) <- requireProgram verb ldProgram (withPrograms lbi)
+  combineObjectFiles verb ld
+    (bDir </> (("HS" ++) $ display $ packageId pkgDesc) <.> "o")
+    (stubObjs ++ hsObjs)
+  (ghc,_) <- requireProgram verb ghcProgram (withPrograms lbi)
+  let bi = libBuildInfo lib
+      bDir = buildDir lbi
+  runProgram verb ghc (
+    ["-shared","-o",bDir </> (mkGHCiFixLibName pkgDesc)] ++
+    (ldOptions bi) ++ (map ("-l" ++) $ extraLibs bi) ++
+    (map ("-L" ++) $ extraLibDirs bi) ++
+    (map ((bDir </>) . flip replaceExtension objExtension) $ cSources bi))
+  return ()
+
+mocProgram :: Program
+mocProgram = Program {
+  programName = "moc",
+  programFindLocation = flip findProgramLocation "moc",
+  programFindVersion = \verbosity path -> do
+    (_,line,_) <- rawSystemStdInOut verbosity path ["-v"] Nothing False
+    return $
+      findSubseq (stripPrefix "(Qt ") line >>=
+      Just . takeWhile (\c -> isDigit c || c == '.') >>=
+      simpleParse,
+  programPostConf = \_ _ -> return []
+}
+
+qtVersionRange :: VersionRange
+qtVersionRange = orLaterVersion $ Version [4,7] []
+
+copyWithQt ::
+  PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags -> IO ()
+copyWithQt pkgDesc lbi hooks flags = do
+  copyHook simpleUserHooks pkgDesc lbi hooks flags
+  let verb = fromFlag $ copyVerbosity flags
+      dest = fromFlag $ copyDest flags
+      bDir = buildDir lbi
+      libDir = libdir $ absoluteInstallDirs pkgDesc lbi dest
+      file = mkGHCiFixLibName pkgDesc
+  when (needsGHCiFix pkgDesc lbi) $
+    installOrdinaryFile verb (bDir </> file) (libDir </> file)
+
+regWithQt :: 
+  PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
+regWithQt pkg@PackageDescription { library       = Just lib  }
+         lbi@LocalBuildInfo     { libraryConfig = Just clbi } hooks flags = do
+  let verb    = fromFlag $ regVerbosity flags
+      inplace = fromFlag $ regInPlace flags
+      dist    = fromFlag $ regDistPref flags
+      pkgDb   = withPackageDB lbi
+  instPkgInfo <- generateRegistrationInfo
+    verb pkg lib lbi clbi inplace dist
+  let instPkgInfo' = if (needsGHCiFix pkg lbi)
+        then instPkgInfo {I.extraGHCiLibraries =
+          (display $ mkGHCiFixLibPkgId pkg) :
+          I.extraGHCiLibraries instPkgInfo}
+        else instPkgInfo
+  case flagToMaybe $ regGenPkgConf flags of
+    Just regFile -> do
+      let regFile = fromMaybe (display (packageId pkg) <.> "conf")
+            (fromFlag $ regGenPkgConf flags)
+      writeUTF8File regFile $ I.showInstalledPackageInfo instPkgInfo'
+    _ | fromFlag (regGenScript flags) ->
+      die "Registration scripts are not implemented."
+      | otherwise -> 
+      registerPackage verb instPkgInfo' pkg lbi inplace pkgDb
+regWithQt pkgDesc _ _ flags =
+  setupMessage (fromFlag $ regVerbosity flags) 
+    "Package contains no library to register:" (packageId pkgDesc)
+
+instWithQt ::
+  PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
+instWithQt pkgDesc lbi hooks flags = do
+  let copyFlags = defaultCopyFlags {
+        copyDistPref   = installDistPref flags,
+        copyVerbosity  = installVerbosity flags
+      }
+      regFlags = defaultRegisterFlags {
+        regDistPref  = installDistPref flags,
+        regInPlace   = installInPlace flags,
+        regPackageDB = installPackageDB flags,
+        regVerbosity = installVerbosity flags
+      }
+  copyWithQt pkgDesc lbi hooks copyFlags
+  when (hasLibs pkgDesc) $ regWithQt pkgDesc lbi hooks regFlags
+
+maybeMapM :: (Monad m) => (a -> m b) -> (Maybe a) -> m (Maybe b)
+maybeMapM f = maybe (return Nothing) $ liftM Just . f
+
+findSubseq :: ([a] -> Maybe b) -> [a] -> Maybe b
+findSubseq f [] = f []
+findSubseq f xs@(_:ys) =
+  case f xs of
+    Nothing -> findSubseq f ys
+    Just r  -> Just r
diff --git a/cbits/HsQMLClass.cpp b/cbits/HsQMLClass.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLClass.cpp
@@ -0,0 +1,113 @@
+#include <cstdlib>
+#include <HsFFI.h>
+#include <QAtomicInt>
+#include <QMetaObject>
+#include <QString>
+#include <QDebug>
+
+#include "hsqml.h"
+#include "HsQMLClass.h"
+#include "HsQMLManager.h"
+
+QAtomicInt gClassId;
+
+HsQMLClass::HsQMLClass(
+    unsigned int*  metaData,
+    char*          metaStrData,
+    HsQMLUniformFunc* methods,
+    HsQMLUniformFunc* properties)
+    : mRefCount(0)
+    , mMetaData(metaData)
+    , mMetaStrData(metaStrData)
+    , mMethods(methods)
+    , mProperties(properties)
+    , mMethodCount(metaData[MD_METHOD_COUNT])
+    , mPropertyCount(metaData[MD_PROPERTY_COUNT])
+    , mMetaObject(QMetaObject {{
+          &QObject::staticMetaObject,
+          mMetaStrData,
+          mMetaData,
+          0}})
+{
+    ref(Handle);
+}
+
+HsQMLClass::~HsQMLClass()
+{
+    for (int i=0; i<mMethodCount; i++) {
+        gManager->freeFun((HsFunPtr)mMethods[i]);
+    }
+    for (unsigned int i=0; i<2*mPropertyCount; i++) {
+        if (mProperties[i]) {
+            gManager->freeFun((HsFunPtr)mProperties[i]);
+        }
+    }
+    std::free(mMetaData);
+    std::free(mMetaStrData);
+    std::free(mMethods);
+    std::free(mProperties);
+}
+
+const char* HsQMLClass::name()
+{
+    return mMetaObject.className();
+} 
+
+const HsQMLUniformFunc* HsQMLClass::methods()
+{
+    return mMethods;
+}
+
+const HsQMLUniformFunc* HsQMLClass::properties()
+{
+    return mProperties;
+}
+
+void HsQMLClass::ref(RefSrc src)
+{
+    int count = mRefCount.fetchAndAddOrdered(1);
+
+    if (gLogLevel >= (count == 0 ? 1 : 2)) {
+        qDebug() << QString().sprintf(
+            "HsQML: %s Class, name=%s, src=%d, count=%d.",
+            count ? "Ref" : "New", name(), src, count+1);
+    }
+}
+
+void HsQMLClass::deref(RefSrc src)
+{
+    int count = mRefCount.fetchAndAddOrdered(-1);
+
+    if (gLogLevel >= (count == 1 ? 1 : 2)) {
+        qDebug() << QString().sprintf(
+            "HsQML: %s Class, name=%s, src=%d, count=%d.",
+            count > 1 ? "Deref" : "Delete", name(), src, count);
+    }
+
+    if (count == 1) {
+        delete this;
+    }
+}
+
+extern "C" int hsqml_get_next_class_id()
+{
+    return gClassId.fetchAndAddRelaxed(1);
+}
+
+extern "C" HsQMLClassHandle* hsqml_create_class(
+    unsigned int*  metaData,
+    char*          metaStrData,
+    HsQMLUniformFunc* methods,
+    HsQMLUniformFunc* properties)
+{
+    HsQMLClass* klass = new HsQMLClass(
+            metaData, metaStrData, methods, properties);
+    return (HsQMLClassHandle*)klass;
+}
+
+extern "C" void hsqml_finalise_class_handle(
+    HsQMLClassHandle* hndl)
+{
+    HsQMLClass* klass = (HsQMLClass*)hndl;
+    klass->deref(HsQMLClass::Handle);
+}
diff --git a/cbits/HsQMLClass.h b/cbits/HsQMLClass.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLClass.h
@@ -0,0 +1,41 @@
+#ifndef HSQML_CLASS_H
+#define HSQML_CLASS_H
+
+#include <QObject>
+#include <QAtomicInt>
+
+#include "hsqml.h"
+
+enum MDFields {
+    MD_CLASS_NAME     = 1,
+    MD_METHOD_COUNT   = 4,
+    MD_PROPERTY_COUNT = 6,
+};
+
+class HsQMLClass
+{
+public:
+    HsQMLClass(
+        unsigned int*, char*, HsQMLUniformFunc*, HsQMLUniformFunc*);
+    ~HsQMLClass();
+    const char* name();
+    const HsQMLUniformFunc* methods();
+    const HsQMLUniformFunc* properties();
+    enum RefSrc {Handle, ObjProxy};
+    void ref(RefSrc);
+    void deref(RefSrc);
+
+private:
+    QAtomicInt mRefCount;
+    unsigned int* mMetaData;
+    char* mMetaStrData;
+    HsQMLUniformFunc* mMethods;
+    HsQMLUniformFunc* mProperties;
+
+public:
+    const int mMethodCount;
+    const int mPropertyCount;
+    const QMetaObject mMetaObject;
+};
+
+#endif /*HSQML_CLASS_H*/
diff --git a/cbits/HsQMLEngine.cpp b/cbits/HsQMLEngine.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLEngine.cpp
@@ -0,0 +1,55 @@
+#include "hsqml.h"
+#include "HsQMLManager.h"
+#include "HsQMLEngine.h"
+#include "HsQMLObject.h"
+#include "HsQMLWindow.h"
+
+HsQMLEngine::HsQMLEngine(HsQMLEngineConfig& config)
+{
+    // Obtain, re-parent, and set QML global object
+    if (config.contextObject) {
+        QObject* contextObject = config.contextObject->object();
+        contextObject->setParent(this);
+        mEngine.rootContext()->setContextObject(contextObject);
+    }
+
+    // Create window
+    HsQMLWindow* win = new HsQMLWindow(this);
+    win->setSource(config.initialURL);
+    win->setVisible(config.showWindow);
+    if (config.setWindowTitle) {
+        win->setTitle(config.windowTitle);
+    }
+    mWindows.insert(win);
+}
+
+HsQMLEngine::~HsQMLEngine()
+{
+}
+
+QDeclarativeEngine* HsQMLEngine::engine()
+{
+    return &mEngine;
+}
+
+extern "C" void hsqml_create_engine(
+    HsQMLObjectHandle* contextObject,
+    HsQMLUrlHandle* initialURL,
+    int showWindow,
+    int setWindowTitle,
+    HsQMLStringHandle* windowTitle)
+{
+    HsQMLEngineConfig config;
+    config.contextObject = reinterpret_cast<HsQMLObjectProxy*>(contextObject);
+    config.initialURL = *reinterpret_cast<QUrl*>(initialURL);
+    config.showWindow = static_cast<bool>(showWindow);
+    if (setWindowTitle) {
+        config.setWindowTitle = true;
+        config.windowTitle = *reinterpret_cast<QString*>(windowTitle);
+    }
+
+    Q_ASSERT (gManager);
+    QMetaObject::invokeMethod(
+        gManager, "createEngine", Qt::QueuedConnection,
+        Q_ARG(HsQMLEngineConfig, config));
+}
diff --git a/cbits/HsQMLEngine.h b/cbits/HsQMLEngine.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLEngine.h
@@ -0,0 +1,41 @@
+#ifndef HSQML_ENGINE_H
+#define HSQML_ENGINE_H
+
+#include <QSet>
+#include <QString>
+#include <QUrl>
+#include <QDeclarativeEngine>
+
+class HsQMLObjectProxy;
+class HsQMLWindow;
+
+struct HsQMLEngineConfig
+{
+    HsQMLEngineConfig()
+        : contextObject(NULL)
+        , showWindow(false)
+        , setWindowTitle(false)
+    {}
+
+    HsQMLObjectProxy* contextObject;
+    QUrl initialURL;
+    bool showWindow;
+    bool setWindowTitle;
+    QString windowTitle;
+};
+
+class HsQMLEngine : public QObject
+{
+    Q_OBJECT
+
+public:
+    HsQMLEngine(HsQMLEngineConfig&);
+    ~HsQMLEngine();
+    QDeclarativeEngine* engine();
+
+private:
+    QDeclarativeEngine mEngine;
+    QSet<HsQMLWindow*> mWindows;
+};
+
+#endif /*HSQML_ENGINE_H*/
diff --git a/cbits/HsQMLIntrinsics.cpp b/cbits/HsQMLIntrinsics.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLIntrinsics.cpp
@@ -0,0 +1,77 @@
+#include <cstdlib>
+#include <cstring>
+
+#include <QString>
+#include <QUrl>
+
+#include "hsqml.h"
+
+/* String */
+extern "C" size_t hsqml_get_string_size()
+{
+    return sizeof(QString);
+}
+
+extern "C" void hsqml_init_string(HsQMLStringHandle* hndl)
+{
+    new((void*)hndl) QString();
+}
+
+extern "C" void hsqml_deinit_string(HsQMLStringHandle* hndl)
+{
+    QString* string = (QString*)hndl;
+    string->~QString();
+}
+
+extern "C" UTF16* hsqml_marshal_string(
+    int bufLen, HsQMLStringHandle* hndl)
+{
+    QString* string = (QString*)hndl;
+    string->resize(bufLen);
+    return reinterpret_cast<UTF16*>(string->data());
+}
+
+extern "C" int hsqml_unmarshal_string(
+    HsQMLStringHandle* hndl, UTF16** bufPtr)
+{
+    QString* string = (QString*)hndl;
+    *bufPtr = reinterpret_cast<UTF16*>(string->data());
+    return string->length();
+}
+
+/* URL */
+extern "C" size_t hsqml_get_url_size()
+{
+    return sizeof(QUrl);
+}
+
+extern "C" void hsqml_init_url(HsQMLUrlHandle* hndl)
+{
+    new((void*)hndl) QUrl();
+}
+
+extern "C" void hsqml_deinit_url(HsQMLUrlHandle* hndl)
+{
+    QUrl* url = (QUrl*)hndl;
+    url->~QUrl();
+}
+
+extern "C" void hsqml_marshal_url(
+    char* buf, int bufLen, HsQMLUrlHandle* hndl)
+{
+    QUrl* url = (QUrl*)hndl;
+    QByteArray cstr(buf, bufLen);
+    url->setEncodedUrl(cstr, QUrl::StrictMode);
+}
+
+extern "C" int hsqml_unmarshal_url(
+    HsQMLUrlHandle* hndl, char** bufPtr)
+{
+    QUrl* url = (QUrl*)hndl;
+    QByteArray cstr = url->toEncoded();
+    int bufLen = cstr.length();
+    char* buf = reinterpret_cast<char*>(malloc(bufLen));
+    memcpy(buf, cstr.data(), bufLen);
+    *bufPtr = buf;
+    return bufLen;
+}
diff --git a/cbits/HsQMLManager.cpp b/cbits/HsQMLManager.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLManager.cpp
@@ -0,0 +1,78 @@
+#include <QMetaType>
+
+#include "HsQMLManager.h"
+
+QMutex gMutex;
+HsQMLManager* gManager;
+int gLogLevel;
+
+HsQMLManager::HsQMLManager(
+    int& argc,
+    char** argv,
+    void (*freeFun)(HsFunPtr),
+    void (*freeStable)(HsStablePtr))
+    : mApp(argc, argv)
+    , mFreeFun(freeFun)
+    , mFreeStable(freeStable)
+{
+}
+
+HsQMLManager::~HsQMLManager()
+{
+}
+
+void HsQMLManager::run()
+{
+    mApp.exec();
+
+    // Delete engines once the event loop returns
+    for (QVector<HsQMLEngine*>::iterator it = mEngines.begin();
+            it != mEngines.end(); ++it) {
+        delete *it;
+    }
+    mEngines.clear();
+}
+
+void HsQMLManager::freeFun(HsFunPtr funPtr)
+{
+    mFreeFun(funPtr);
+}
+
+void HsQMLManager::freeStable(HsStablePtr stablePtr)
+{
+    mFreeStable(stablePtr);
+}
+
+void HsQMLManager::createEngine(HsQMLEngineConfig config)
+{
+    mEngines.push_back(new HsQMLEngine(config));
+}
+
+extern "C" void hsqml_init(
+    void (*free_fun)(HsFunPtr),
+    void (*free_stable)(HsStablePtr))
+{
+    gMutex.lock();
+    if (!gManager) {
+        qRegisterMetaType<HsQMLEngineConfig>("HsQMLEngineConfig");
+
+        int* argcp = new int[1];
+        *argcp = 1;
+        char** argv = new char*[1];
+        argv[0] = new char[1];
+        argv[0][0] = '\0';
+        gManager = new HsQMLManager(*argcp, argv, free_fun, free_stable);
+    }
+    gMutex.unlock();
+}
+
+extern "C" void hsqml_run()
+{
+    Q_ASSERT (gManager);
+    gManager->run();
+}
+
+extern "C" void hsqml_set_debug_loglevel(int level)
+{
+    gLogLevel = level;
+}
diff --git a/cbits/HsQMLManager.h b/cbits/HsQMLManager.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLManager.h
@@ -0,0 +1,42 @@
+#ifndef HSQML_MANAGER_H
+#define HSQML_MANAGER_H
+
+#include <QApplication>
+#include <QMutex>
+#include <QVector>
+#include <QUrl>
+
+#include "hsqml.h"
+#include "HsQMLEngine.h"
+
+class HsQMLManager : public QObject
+{
+    Q_OBJECT
+
+public:
+    HsQMLManager(
+        int& argc,
+        char** argv,
+        void (*)(HsFunPtr),
+        void (*)(HsStablePtr));
+    ~HsQMLManager();
+    void run();
+    void freeFun(HsFunPtr);
+    void freeStable(HsStablePtr);
+    Q_SLOT void createEngine(HsQMLEngineConfig);
+
+private:
+    HsQMLManager(const HsQMLManager&);
+    HsQMLManager& operator=(const HsQMLManager&);
+
+    QApplication mApp;
+    QVector<HsQMLEngine*> mEngines;
+    void (*mFreeFun)(HsFunPtr);
+    void (*mFreeStable)(HsStablePtr);
+};
+
+extern QMutex gMutex;
+extern HsQMLManager* gManager;
+extern int gLogLevel;
+
+#endif /*HSQML_MANAGER_H*/
diff --git a/cbits/HsQMLObject.cpp b/cbits/HsQMLObject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLObject.cpp
@@ -0,0 +1,199 @@
+#include <HsFFI.h>
+#include <QDeclarativeEngine>
+#include <QString>
+#include <QDebug>
+
+#include "HsQMLObject.h"
+#include "HsQMLClass.h"
+#include "HsQMLManager.h"
+
+HsQMLObjectProxy::HsQMLObjectProxy(HsStablePtr haskell, HsQMLClass* klass)
+    : mHaskell(haskell)
+    , mKlass(klass)
+    , mObject(NULL)
+    , mRefCount(0)
+{
+    ref(Handle);
+    mKlass->ref(HsQMLClass::ObjProxy);
+}
+
+HsQMLObjectProxy::~HsQMLObjectProxy()
+{
+    mKlass->deref(HsQMLClass::ObjProxy);
+}
+
+HsStablePtr HsQMLObjectProxy::haskell() const
+{
+    return mHaskell;
+}
+
+HsQMLClass* HsQMLObjectProxy::klass() const
+{
+    return mKlass;
+}
+
+HsQMLObject* HsQMLObjectProxy::object()
+{
+    if (!mObject) {
+        mObject = new HsQMLObject(this);
+    }
+    return mObject;
+}
+
+void HsQMLObjectProxy::clearObject()
+{
+    mObject = NULL;
+}
+
+void HsQMLObjectProxy::ref(RefSrc src)
+{
+    int count = mRefCount.fetchAndAddOrdered(1);
+
+    if (gLogLevel >= (count == 0 ? 3 : 4)) {
+        qDebug() << QString().sprintf(
+            "HsQML: %s ObjProxy, class=%s, ptr=%p, src=%d, count=%d.",
+            count ? "Ref" : "New", mKlass->name(), this, src, count+1);
+    }
+}
+
+void HsQMLObjectProxy::deref(RefSrc src)
+{
+    int count = mRefCount.fetchAndAddOrdered(-1);
+
+    if (gLogLevel >= (count == 1 ? 3 : 4)) {
+        qDebug() << QString().sprintf(
+            "HsQML: %s ObjProxy, class=%s, ptr=%p, src=%d, count=%d.",
+            count > 1 ? "Deref" : "Delete", mKlass->name(), this, src, count);
+    }
+
+    if (count == 1) {
+        delete this;
+    }
+}
+
+HsQMLObject::HsQMLObject(HsQMLObjectProxy* proxy)
+    : mProxy(proxy)
+    , mHaskell(proxy->haskell())
+    , mKlass(proxy->klass())
+{
+    QDeclarativeEngine::setObjectOwnership(
+        this, QDeclarativeEngine::JavaScriptOwnership);
+    mProxy->ref(HsQMLObjectProxy::Object);
+}
+
+HsQMLObject::~HsQMLObject()
+{
+    mProxy->clearObject();
+    mProxy->deref(HsQMLObjectProxy::Object);
+}
+
+const QMetaObject* HsQMLObject::metaObject() const
+{
+    return QObject::d_ptr->metaObject ?
+        QObject::d_ptr->metaObject : &mKlass->mMetaObject;
+}
+
+void* HsQMLObject::qt_metacast(const char* clname)
+{
+    if (!clname) {
+        return 0;
+    }
+    if (!strcmp(clname,
+            mKlass->mMetaObject.d.stringdata +
+            mKlass->mMetaObject.d.data[MD_CLASS_NAME])) {
+        return static_cast<void*>(const_cast<HsQMLObject*>(this));
+    }
+    return QObject::qt_metacast(clname);
+}
+
+int HsQMLObject::qt_metacall(QMetaObject::Call c, int id, void** a)
+{
+    id = QObject::qt_metacall(c, id, a);
+    if (id < 0) {
+        return id;
+    }
+    if (QMetaObject::InvokeMetaMethod == c) {
+        mKlass->methods()[id](this, a);
+        id -= mKlass->mMethodCount;
+    }
+    else if (QMetaObject::ReadProperty == c) {
+        mKlass->properties()[2*id](this, a);
+        id -= mKlass->mPropertyCount;
+    }
+    else if (QMetaObject::WriteProperty == c) {
+        HsQMLUniformFunc uf = mKlass->properties()[2*id+1];
+        if (uf) {
+            uf(this, a);
+        }
+        id -= mKlass->mPropertyCount;
+    }
+    else if (QMetaObject::QueryPropertyDesignable == c ||
+             QMetaObject::QueryPropertyScriptable == c ||
+             QMetaObject::QueryPropertyStored == c ||
+             QMetaObject::QueryPropertyEditable == c ||
+             QMetaObject::QueryPropertyUser == c) {
+        id -= mKlass->mPropertyCount;
+    }
+    return id;
+}
+
+HsQMLObjectProxy* HsQMLObject::proxy() const
+{
+    return mProxy;
+}
+
+extern "C" HsQMLObjectHandle* hsqml_create_object(
+    HsStablePtr haskell, HsQMLClassHandle* kHndl)
+{
+    HsQMLObjectProxy* proxy = new HsQMLObjectProxy(haskell, (HsQMLClass*)kHndl);
+    return (HsQMLObjectHandle*)proxy;
+}
+
+extern HsStablePtr hsqml_object_get_haskell(
+    HsQMLObjectHandle* hndl)
+{
+    HsQMLObjectProxy* proxy = (HsQMLObjectProxy*)hndl;
+    return proxy->haskell();
+}
+
+extern void* hsqml_object_get_pointer(
+    HsQMLObjectHandle* hndl)
+{
+    HsQMLObjectProxy* proxy = (HsQMLObjectProxy*)hndl;
+    return (void*)proxy->object();
+}
+
+extern HsQMLObjectHandle* hsqml_get_object_handle(
+    void* ptr, HsQMLClassHandle* klassHndl)
+{
+    // Return NULL if the input pointer is NULL
+    if (!ptr) {
+        return NULL;
+    }
+
+    // Return NULL if the object type doesn't match any supplied class
+    if (klassHndl) {
+        HsQMLClass* klass = (HsQMLClass*)klassHndl;
+        QObject* qObj = static_cast<QObject*>(ptr);
+        if (0 != strcmp(
+            qObj->metaObject()->className(),
+            klass->mMetaObject.className())) {
+            return NULL;
+        }
+    }
+
+    // Return object proxy
+    HsQMLObject* object = (HsQMLObject*)ptr;
+    HsQMLObjectProxy* proxy = object->proxy();
+    proxy->ref(HsQMLObjectProxy::Handle);
+    return (HsQMLObjectHandle*)proxy;
+}
+
+extern void hsqml_finalise_object_handle(
+    HsQMLObjectHandle* hndl)
+{
+    if (hndl) {
+        HsQMLObjectProxy* proxy = (HsQMLObjectProxy*)hndl;
+        proxy->deref(HsQMLObjectProxy::Handle);
+    }
+}
diff --git a/cbits/HsQMLObject.h b/cbits/HsQMLObject.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLObject.h
@@ -0,0 +1,45 @@
+#ifndef HSQML_OBJECT_H
+#define HSQML_OBJECT_H
+
+#include <QObject>
+
+class HsQMLClass;
+class HsQMLObject;
+
+class HsQMLObjectProxy
+{
+public:
+    HsQMLObjectProxy(HsStablePtr, HsQMLClass*);
+    virtual ~HsQMLObjectProxy();
+    HsStablePtr haskell() const;
+    HsQMLClass* klass() const;
+    HsQMLObject* object();
+    void clearObject();
+    enum RefSrc {Handle, Object};
+    void ref(RefSrc);
+    void deref(RefSrc);
+
+private:
+    HsStablePtr mHaskell;
+    HsQMLClass* mKlass;
+    HsQMLObject* mObject;
+    QAtomicInt mRefCount;
+};
+
+class HsQMLObject : public QObject
+{
+public:
+    HsQMLObject(HsQMLObjectProxy*);
+    virtual ~HsQMLObject();
+    virtual const QMetaObject* metaObject() const;
+    virtual void* qt_metacast(const char*);
+    virtual int qt_metacall(QMetaObject::Call, int, void**);
+    HsQMLObjectProxy* proxy() const;
+
+private:
+    HsQMLObjectProxy* mProxy;
+    HsStablePtr mHaskell;
+    HsQMLClass* mKlass;
+};
+
+#endif /*HSQML_OBJECT_H*/
diff --git a/cbits/HsQMLWindow.cpp b/cbits/HsQMLWindow.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLWindow.cpp
@@ -0,0 +1,104 @@
+#include "hsqml.h"
+#include "HsQMLManager.h"
+#include "HsQMLWindow.h"
+
+HsQMLWindow::HsQMLWindow(HsQMLEngine* engine)
+    : QObject(engine)
+    , mEngine(engine)
+    , mContext(engine->engine())
+    , mView(&mScene)
+    , mComponent(NULL)
+{
+    // Setup context
+    mContext.setContextProperty("window", this);
+
+    // Don't delete on close
+    mWindow.setAttribute(Qt::WA_DeleteOnClose, false);
+
+    // Setup for QML performance
+    mView.setOptimizationFlags(QGraphicsView::DontSavePainterState);
+    mView.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+    mScene.setItemIndexMethod(QGraphicsScene::NoIndex);
+
+    // Setup for QML key handling
+    mView.viewport()->setFocusPolicy(Qt::NoFocus);
+    mView.setFocusPolicy(Qt::StrongFocus);
+    mScene.setStickyFocus(true);
+
+    mWindow.setCentralWidget(&mView);
+}
+
+HsQMLWindow::~HsQMLWindow()
+{
+}
+
+QUrl HsQMLWindow::source() const
+{
+    return mSource;
+}
+
+void HsQMLWindow::setSource(const QUrl& url)
+{
+    mSource = url;
+    if (mComponent) {
+        delete mComponent;
+        mComponent = NULL;
+    }
+    if (!mSource.isEmpty()) {
+        mComponent = new QDeclarativeComponent(
+            mEngine->engine(), mSource, this);
+        if (mComponent->isLoading()) {
+            QObject::connect(
+                mComponent,
+                SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+                this,
+                SLOT(completeSetSource()));
+        }
+        else {
+            completeSetSource();
+        }
+    }
+}
+
+void HsQMLWindow::completeSetSource()
+{
+    QObject::disconnect(
+        mComponent, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+        this, SLOT(completeSetSource()));
+    QDeclarativeItem* item =
+        qobject_cast<QDeclarativeItem*>(mComponent->create(&mContext));
+    if (item) {
+        mScene.addItem(item);
+    }
+}
+
+QString HsQMLWindow::title() const
+{
+    return mWindow.windowTitle();
+}
+
+void HsQMLWindow::setTitle(const QString& title)
+{
+    mWindow.setWindowTitle(title);
+}
+
+bool HsQMLWindow::visible() const
+{
+    return mWindow.isVisible();
+}
+
+void HsQMLWindow::setVisible(bool visible)
+{
+    mWindow.setVisible(visible);
+}
+
+void HsQMLWindow::close()
+{
+    QMetaObject::invokeMethod(
+        this, "completeClose", Qt::QueuedConnection);
+}
+
+void HsQMLWindow::completeClose()
+{
+    delete this;
+}
diff --git a/cbits/HsQMLWindow.h b/cbits/HsQMLWindow.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsQMLWindow.h
@@ -0,0 +1,45 @@
+#ifndef HSQML_WINDOW_H
+#define HSQML_WINDOW_H
+
+#include <QMainWindow>
+#include <QDeclarativeContext>
+#include <QDeclarativeItem>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QUrl>
+
+#include "HsQMLManager.h"
+
+class QDeclarativeComponent;
+
+class HsQMLWindow : public QObject
+{
+    Q_OBJECT
+
+public:
+    HsQMLWindow(HsQMLEngine*);
+    virtual ~HsQMLWindow();
+    QUrl source() const;
+    void setSource(const QUrl&);
+    Q_PROPERTY(QUrl source READ source WRITE setSource);
+    QString title() const;
+    void setTitle(const QString&);
+    Q_PROPERTY(QString title READ title WRITE setTitle);
+    bool visible() const;
+    void setVisible(bool);
+    Q_PROPERTY(bool visible READ visible WRITE setVisible);
+    Q_SCRIPTABLE void close();
+
+private:
+    Q_SLOT void completeSetSource();
+    Q_SLOT void completeClose();
+    HsQMLEngine* mEngine;
+    QDeclarativeContext mContext;
+    QMainWindow mWindow;
+    QGraphicsScene mScene;
+    QGraphicsView mView;
+    QUrl mSource;
+    QDeclarativeComponent* mComponent;
+};
+
+#endif /*HSQML_WINDOW_H*/
diff --git a/cbits/hsqml.h b/cbits/hsqml.h
new file mode 100644
--- /dev/null
+++ b/cbits/hsqml.h
@@ -0,0 +1,99 @@
+#ifndef HSQML_H
+#define HSQML_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <HsFFI.h>
+
+/* Manager */
+extern void hsqml_init(
+    void (*)(HsFunPtr),
+    void (*)(HsStablePtr));
+
+extern void hsqml_run();
+
+extern void hsqml_set_debug_loglevel(int);
+
+/* String */
+typedef char HsQMLStringHandle;
+
+typedef unsigned short UTF16;
+
+extern size_t hsqml_get_string_size();
+
+extern void hsqml_init_string(
+    HsQMLStringHandle*);
+
+extern void hsqml_deinit_string(
+    HsQMLStringHandle*);
+
+extern UTF16* hsqml_marshal_string(
+    int, HsQMLStringHandle*);
+
+extern int hsqml_unmarshal_string(
+    HsQMLStringHandle*, UTF16**);
+
+/* URL */
+typedef char HsQMLUrlHandle;
+
+extern size_t hsqml_get_url_size();
+
+extern void hsqml_init_url(
+    HsQMLUrlHandle*);
+
+extern void hsqml_deinit_url(
+    HsQMLUrlHandle*);
+
+extern void hsqml_marshal_url(
+    char*, int, HsQMLUrlHandle*);
+
+extern int hsqml_unmarshal_url(
+    HsQMLUrlHandle*, char**);
+
+/* Class */
+typedef char HsQMLClassHandle;
+
+typedef void (*HsQMLUniformFunc)(void*, void**);
+
+extern int hsqml_get_next_class_id();
+
+extern HsQMLClassHandle* hsqml_create_class(
+    unsigned int*, char*, HsQMLUniformFunc*, HsQMLUniformFunc*);
+
+extern void hsqml_finalise_class_handle(
+    HsQMLClassHandle* hndl);
+
+/* Object */
+typedef char HsQMLObjectHandle;
+
+extern HsQMLObjectHandle* hsqml_create_object(
+    HsStablePtr, HsQMLClassHandle*);
+
+extern HsStablePtr hsqml_object_get_haskell(
+    HsQMLObjectHandle*);
+
+extern void* hsqml_object_get_pointer(
+    HsQMLObjectHandle*);
+
+extern HsQMLObjectHandle* hsqml_get_object_handle(
+    void*, HsQMLClassHandle*);
+
+extern void hsqml_finalise_object_handle(
+    HsQMLObjectHandle*);
+
+/* Engine */
+extern void hsqml_create_engine(
+    HsQMLObjectHandle*,
+    HsQMLUrlHandle*,
+    int,
+    int,
+    HsQMLStringHandle*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*HSQML_H*/
diff --git a/hsqml.cabal b/hsqml.cabal
new file mode 100644
--- /dev/null
+++ b/hsqml.cabal
@@ -0,0 +1,84 @@
+Name:               hsqml
+Version:            0.1.0
+Cabal-version:      >= 1.10
+Build-type:         Custom
+License:            BSD3
+License-file:       LICENSE
+Copyright:          (c) 2010-2012 Robin KAY
+Author:             Robin KAY
+Maintainer:         komadori@gekkou.co.uk
+Stability:          experimental
+Homepage:           http://www.gekkou.co.uk/
+Category:           Graphics
+Synopsis:           Haskell binding for Qt Quick
+Extra-source-files: cbits/*.cpp cbits/*.h
+Description:
+    A Haskell binding for Qt Quick.
+
+    General documentation is present in the 'Graphics.QML' module.
+
+Library
+    Default-language: Haskell2010
+    Build-depends:
+        base         == 4.*,
+        containers   == 0.4.*,
+        filepath     == 1.3.*,
+        network      == 2.3.*,
+        text         == 0.11.*,
+        tagged       == 0.4.*,
+        transformers >= 0.2 && < 0.4
+    Exposed-modules:
+        Graphics.QML
+        Graphics.QML.Debug
+        Graphics.QML.Engine
+        Graphics.QML.Marshal
+        Graphics.QML.Objects
+    Other-modules:
+        Graphics.QML.Internal.Marshal
+        Graphics.QML.Internal.Objects
+        Graphics.QML.Internal.PrimValues
+        Graphics.QML.Internal.Engine
+    Hs-source-dirs: src
+    Cc-options: -std=c++0x
+    C-sources:
+        cbits/HsQMLClass.cpp
+        cbits/HsQMLEngine.cpp
+        cbits/HsQMLIntrinsics.cpp
+        cbits/HsQMLManager.cpp
+        cbits/HsQMLObject.cpp
+        cbits/HsQMLWindow.cpp
+    Include-dirs: cbits
+    X-moc-headers:
+        cbits/HsQMLEngine.h
+        cbits/HsQMLManager.h
+        cbits/HsQMLWindow.h
+    X-separate-cbits: True
+    Build-tools: c2hs
+    if os(windows)
+        Include-dirs:
+            /QT_ROOT/include
+            /QT_ROOT/include/QtCore
+            /QT_ROOT/include/QtGui
+            /QT_ROOT/include/QtDeclarative
+        Extra-libraries: QtCore4, QtGui4, QtDeclarative4, stdc++
+        Extra-lib-dirs:
+            /SYS_ROOT/bin
+            /QT_ROOT/bin
+    else
+        Pkgconfig-depends:
+            QtDeclarative >= 4.7
+
+Test-Suite hsqml-test1
+    Type: exitcode-stdio-1.0
+    Default-language: Haskell2010
+    Hs-source-dirs: test
+    Main-is: Test1.hs
+    Build-depends:
+        base      == 4.*,
+        directory == 1.1.*,
+        network   == 2.3.*,
+        hsqml     == 0.1.*
+
+Source-repository head
+    type:     darcs
+    location: https://patch-tag.com/r/komadori/HsQML
diff --git a/src/Graphics/QML.hs b/src/Graphics/QML.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML.hs
@@ -0,0 +1,45 @@
+-- | This module imports the entire package, except 'Graphics.QML.Debug'.
+module Graphics.QML (
+-- * Overview
+{-|
+HsQML layers a low to medium level Haskell API on top of the C++ Qt Quick
+framework. It allows you to write graphical applications where the front-end is 
+written in Qt Quick's QML language (incorporating JavaScript) and the back-end
+is written in Haskell. To this end, this library provides two pieces of
+functionality:-
+
+The 'Graphics.QML.Engine' module allows you to create windows which host QML
+content. You can specify a custom global object to be made available to the
+JavaScript running inside the content. In this way, the content can interface
+with the Haskell program.
+
+The 'Graphics.QML.Objects' module allows you to define your own custom object
+types which can be marshalled between Haskell and JavaScript.
+ -}
+-- * Script-side APIs
+{-|
+The @window@ object provides the following methods and properties to QML
+scripts.
+
+/Properties/
+
+[@source : url@] URL for the Window's QML document.
+
+[@title : string@] Window title.
+
+[@visible : bool@] Window visibility.
+
+/Methods/
+
+[@close()@] Closes the window.
+
+ -}
+-- * Graphics.QML
+  module Graphics.QML.Engine,
+  module Graphics.QML.Marshal,
+  module Graphics.QML.Objects
+) where
+
+import Graphics.QML.Engine
+import Graphics.QML.Marshal
+import Graphics.QML.Objects
diff --git a/src/Graphics/QML/Debug.hs b/src/Graphics/QML/Debug.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Debug.hs
@@ -0,0 +1,11 @@
+-- | Debug Options
+module Graphics.QML.Debug (
+    setDebugLogLevel
+) where
+
+import Graphics.QML.Internal.Engine
+
+-- | Sets the global debug log level. At level zero, no logging information
+-- will be printed. Higher levels will increase debug verbosity.
+setDebugLogLevel :: Int -> IO ()
+setDebugLogLevel = hsqmlSetDebugLoglevel
diff --git a/src/Graphics/QML/Engine.hs b/src/Graphics/QML/Engine.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Engine.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE
+    ExistentialQuantification,
+    Rank2Types
+  #-}
+
+-- | Functions for starting QML engines, displaying content in a window.
+module Graphics.QML.Engine (
+  InitialWindowState(
+    ShowWindow,
+    ShowWindowWithTitle,
+    HideWindow),
+  EngineConfig(
+    EngineConfig,
+    initialURL,
+    initialWindowState,
+    contextObject),
+  defaultEngineConfig,
+  createEngine,
+  runEngines,
+  filePathToURI
+) where
+
+import Graphics.QML.Internal.Marshal
+import Graphics.QML.Internal.Objects
+import Graphics.QML.Internal.Engine
+import Graphics.QML.Marshal
+import Graphics.QML.Objects
+
+import Data.List
+import Data.Maybe
+import Data.Typeable
+import Foreign.Storable
+import System.FilePath (isAbsolute, splitDirectories, pathSeparators)
+import Network.URI (URI(URI), URIAuth(URIAuth), nullURI, uriPath)
+
+-- | Specifies the intial state of the display window.
+data InitialWindowState
+  -- | A visible window should be created for the initial document with a
+  -- default title.
+  = ShowWindow
+  -- | A visible window should be created for the initial document with the
+  -- given title.
+  | ShowWindowWithTitle String
+  -- | A window should be created for the initial document, but it will remain
+  -- hidden until made visible by the QML script.
+  | HideWindow
+
+-- | Holds parameters for configuring a QML runtime engine.
+data EngineConfig a = EngineConfig {
+  -- | URL for the first QML document to be loaded.
+  initialURL         :: URI,
+  -- | Window state for the initial QML document.
+  initialWindowState :: InitialWindowState,
+  -- | Context 'Object' made available to QML script code.
+  contextObject      :: Maybe (ObjRef a)
+}
+
+-- | Default engine configuration. Loads @\"main.qml\"@ from the current
+-- working directory into a visible window with no context object.
+defaultEngineConfig :: EngineConfig a
+defaultEngineConfig = EngineConfig {
+  initialURL         = nullURI {uriPath = "main.qml"},
+  initialWindowState = ShowWindow,
+  contextObject      = Nothing
+}
+
+isWindowShown :: InitialWindowState -> Bool
+isWindowShown ShowWindow = True
+isWindowShown (ShowWindowWithTitle _) = True
+isWindowShown HideWindow = False
+
+getWindowTitle :: InitialWindowState -> Maybe String
+getWindowTitle (ShowWindowWithTitle t) = Just t
+getWindowTitle _ = Nothing
+
+-- | Create a QML engine from a specification of its configuration.
+createEngine :: (Object a) => EngineConfig a -> IO ()
+createEngine config = do
+  hsqmlInit
+  let hndl = fmap (\(ObjRef h) -> h) $ contextObject config
+      url = initialURL config
+      state = initialWindowState config
+      showWin = isWindowShown state
+      maybeTitle = getWindowTitle state
+      setTitle = isJust maybeTitle
+      titleStr = fromMaybe "" maybeTitle
+  mOutAlloc url $ \urlPtr -> do
+    mOutAlloc titleStr $ \titlePtr -> do
+      hsqmlCreateEngine hndl urlPtr showWin setTitle titlePtr
+
+-- | Enters the Qt event loop and runs until all engines have terminated.
+runEngines :: IO ()
+runEngines = do
+  hsqmlInit
+  hsqmlRun
+
+-- | Convenience function for converting local file paths into URIs.
+filePathToURI :: FilePath -> URI
+filePathToURI fp =
+    let ds = splitDirectories fp
+        abs = isAbsolute fp
+        fixHead =
+            (\cs -> if null cs then [] else '/':cs) .
+            takeWhile (\c -> not $ c `elem` pathSeparators)
+        mapHead _ [] = []
+        mapHead f (x:xs) = f x : xs
+        afp = intercalate "/" $ mapHead fixHead ds
+        rfp = intercalate "/" ds
+    in if abs
+       then URI "file:" (Just $ URIAuth "" "" "") afp "" ""
+       else URI "" Nothing rfp "" ""
diff --git a/src/Graphics/QML/Internal/Engine.chs b/src/Graphics/QML/Internal/Engine.chs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Internal/Engine.chs
@@ -0,0 +1,48 @@
+{-# LANGUAGE
+    ForeignFunctionInterface
+  #-}
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.QML.Internal.Engine where
+
+{#import Graphics.QML.Internal.Objects #}
+
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Marshal.Utils
+import Foreign.Ptr
+import Foreign.StablePtr
+
+#include <HsFFI.h>
+
+#include "hsqml.h"
+
+type HsFreeFunPtr = FunPtr (FunPtr (IO ()) -> IO ())
+foreign import ccall "HsFFI.h &hs_free_fun_ptr"
+  hsFreeFunPtr :: HsFreeFunPtr
+
+type HsFreeStablePtr = FunPtr (Ptr () -> IO ())
+foreign import ccall "HsFFI.h &hs_free_stable_ptr"
+  hsFreeStablePtr :: HsFreeStablePtr
+
+{#fun unsafe hsqml_init as hsqmlInit_
+  {id `HsFreeFunPtr',
+   id `HsFreeStablePtr'} ->
+  `()' #}
+
+hsqmlInit :: IO ()
+hsqmlInit = hsqmlInit_ hsFreeFunPtr hsFreeStablePtr
+
+{#fun unsafe hsqml_create_engine as ^
+  {withMaybeHsQMLObjectHandle* `Maybe HsQMLObjectHandle',
+   castPtr `Ptr ()',
+   fromBool `Bool',
+   fromBool `Bool',
+   castPtr `Ptr ()'} ->
+  `()' #}
+
+{#fun hsqml_run as ^ {} -> `()' #}
+
+{#fun hsqml_set_debug_loglevel as ^
+  {fromIntegral `Int'} -> `()'
+  #}
diff --git a/src/Graphics/QML/Internal/Marshal.hs b/src/Graphics/QML/Internal/Marshal.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Internal/Marshal.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE
+    ScopedTypeVariables
+  #-}
+
+module Graphics.QML.Internal.Marshal where
+
+import Control.Monad.Trans.Maybe
+import Data.Maybe
+import Data.Tagged
+import Foreign.Ptr
+import System.IO
+
+-- | Represents a QML type name.
+newtype TypeName = TypeName {
+  typeName :: String
+}
+
+-- | The class 'MarshalIn' allows QML values to be converted into Haskell
+-- values.
+class MarshalIn a where
+  mIn :: InMarshaller a
+
+type ErrIO a = MaybeT IO a
+
+runErrIO :: ErrIO a -> IO ()
+runErrIO m = do
+  r <- runMaybeT m
+  if isNothing r
+  then hPutStrLn stderr "Warning: Marshalling error."
+  else return ()
+
+errIO :: IO a -> ErrIO a
+errIO = MaybeT . fmap Just
+
+-- | Encapsulates the functionality to needed to implement an instance of
+-- 'MarshalIn' so that such instances can be defined without access to
+-- implementation details.
+data InMarshaller a = InMarshaller {
+  mInFuncFld :: Ptr () -> ErrIO a,
+  mIOTypeFld :: Tagged a TypeName
+}
+
+mInFunc :: (MarshalIn a) => Ptr () -> ErrIO a
+mInFunc = mInFuncFld mIn 
+
+mIOType :: (MarshalIn a) => Tagged a TypeName
+mIOType = mIOTypeFld mIn
+
+-- | The class 'MarshalOut' allows Haskell values to be converted into QML
+-- values.
+class (MarshalIn a) => MarshalOut a where
+  mOutFunc  :: Ptr () -> a -> IO ()
+  mOutAlloc :: a -> (Ptr () -> IO b) -> IO b
+
+instance MarshalOut () where
+  mOutFunc _ _ = return ()
+  mOutAlloc _ f = f nullPtr
+
+instance MarshalIn () where
+  mIn = InMarshaller {
+    mInFuncFld = \_ -> return (),
+    mIOTypeFld = Tagged $ TypeName ""
+  }
diff --git a/src/Graphics/QML/Internal/Objects.chs b/src/Graphics/QML/Internal/Objects.chs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Internal/Objects.chs
@@ -0,0 +1,143 @@
+{-# LANGUAGE
+    ForeignFunctionInterface
+  #-}
+
+module Graphics.QML.Internal.Objects where
+
+import Foreign.C.Types
+import Foreign.Ptr
+import Foreign.ForeignPtr.Safe
+import Foreign.ForeignPtr.Unsafe
+import Foreign.StablePtr
+
+#include "hsqml.h"
+
+{#fun unsafe hsqml_get_next_class_id as ^
+  {} ->
+  `CInt' id #}
+
+type UniformFunc = Ptr () -> Ptr (Ptr ()) -> IO ()
+
+foreign import ccall "wrapper"  
+  marshalFunc :: UniformFunc -> IO (FunPtr UniformFunc)
+
+{#pointer *HsQMLClassHandle as ^ foreign newtype #}
+
+foreign import ccall "hsqml.h &hsqml_finalise_class_handle"
+  hsqmlFinaliseClassHandlePtr :: FunPtr (Ptr (HsQMLClassHandle) -> IO ())
+
+newClassHandle :: Ptr HsQMLClassHandle -> IO (Maybe HsQMLClassHandle)
+newClassHandle p =
+  if nullPtr == p
+    then return Nothing
+    else do
+      fp <- newForeignPtr hsqmlFinaliseClassHandlePtr p
+      return $ Just $ HsQMLClassHandle fp
+
+{#fun unsafe hsqml_create_class as ^
+  {id `Ptr CUInt',
+   id `Ptr CChar',
+   id `Ptr (FunPtr UniformFunc)',
+   id `Ptr (FunPtr UniformFunc)'} ->
+  `Maybe HsQMLClassHandle' newClassHandle* #}
+
+withMaybeHsQMLClassHandle ::
+    Maybe HsQMLClassHandle -> (Ptr HsQMLClassHandle -> IO b) -> IO b
+withMaybeHsQMLClassHandle (Just (HsQMLClassHandle fp)) = withForeignPtr fp
+withMaybeHsQMLClassHandle Nothing = \f -> f nullPtr
+
+withMaybeHsQMLObjectHandle ::
+    Maybe HsQMLObjectHandle -> (Ptr HsQMLObjectHandle -> IO b) -> IO b
+withMaybeHsQMLObjectHandle (Just (HsQMLObjectHandle fp)) = withForeignPtr fp
+withMaybeHsQMLObjectHandle Nothing = \f -> f nullPtr
+
+{#pointer *HsQMLObjectHandle as ^ foreign newtype #}
+
+foreign import ccall "hsqml.h &hsqml_finalise_object_handle"
+  hsqmlFinaliseObjectHandlePtr :: FunPtr (Ptr (HsQMLObjectHandle) -> IO ())
+
+newObjectHandle :: Ptr HsQMLObjectHandle -> IO HsQMLObjectHandle
+newObjectHandle p = do
+  fp <- newForeignPtr hsqmlFinaliseObjectHandlePtr p
+  return $ HsQMLObjectHandle fp
+
+isNullObjectHandle :: HsQMLObjectHandle -> Bool
+isNullObjectHandle (HsQMLObjectHandle fp) =
+  nullPtr == unsafeForeignPtrToPtr fp
+
+-- | Represents an instance of the QML class which wraps the type @tt@.
+data ObjRef tt = ObjRef {
+  objHndl :: HsQMLObjectHandle
+}
+
+objToPtr :: a -> (Ptr () -> IO b) -> IO b
+objToPtr obj f = do
+  sPtr <- newStablePtr obj
+  res <- f $ castStablePtrToPtr sPtr
+  return res
+
+{#fun unsafe hsqml_create_object as ^
+  {objToPtr* `a',
+   withHsQMLClassHandle* `HsQMLClassHandle'} ->
+  `HsQMLObjectHandle' newObjectHandle* #}
+
+ptrToObj :: Ptr () -> IO a
+ptrToObj =
+  deRefStablePtr . castPtrToStablePtr
+
+{#fun unsafe hsqml_object_get_haskell as ^
+  {withHsQMLObjectHandle* `HsQMLObjectHandle'} ->
+  `a' ptrToObj* #}
+
+{#fun unsafe hsqml_object_get_pointer as ^
+  {withHsQMLObjectHandle* `HsQMLObjectHandle'} ->
+  `Ptr ()' id #}
+
+{#fun unsafe hsqml_get_object_handle as ^
+  {id `Ptr ()',
+   withMaybeHsQMLClassHandle* `Maybe HsQMLClassHandle'} ->
+  `HsQMLObjectHandle' newObjectHandle* #}
+
+ofDynamicMetaObject :: CUInt
+ofDynamicMetaObject = 0x01
+
+mfAccessPrivate, mfAccessProtected, mfAccessPublic, mfAccessMask,
+  mfMethodMethod, mfMethodSignal, mfMethodSlot, mfMethodConstructor,
+  mfMethodTypeMask, mfMethodCompatibility, mfMethodCloned, mfMethodScriptable
+  :: CUInt
+mfAccessPrivate   = 0x00
+mfAccessProtected = 0x01
+mfAccessPublic    = 0x02
+mfAccessMask      = 0x03
+mfMethodMethod      = 0x00
+mfMethodSignal      = 0x04
+mfMethodSlot        = 0x08
+mfMethodConstructor = 0x0c
+mfMethodTypeMask    = 0x0c
+mfMethodCompatibility = 0x10
+mfMethodCloned        = 0x20
+mfMethodScriptable    = 0x40
+
+pfInvalid, pfReadable, pfWritable, pfResettable, pfEnumOrFlag, pfStdCppSet,
+  pfConstant, pfFinal, pfDesignable, pfResolveDesignable, pfScriptable,
+  pfResolveScriptable, pfStored, pfResolveStored, pfEditable,
+  pfResolveEditable, pfUser, pfResolveUser, pfNotify :: CUInt
+pfInvalid           = 0x00000000
+pfReadable          = 0x00000001
+pfWritable          = 0x00000002
+pfResettable        = 0x00000004
+pfEnumOrFlag        = 0x00000008
+pfStdCppSet         = 0x00000100
+pfConstant          = 0x00000400
+pfFinal             = 0x00000800
+pfDesignable        = 0x00001000
+pfResolveDesignable = 0x00002000
+pfScriptable        = 0x00004000
+pfResolveScriptable = 0x00008000
+pfStored            = 0x00010000
+pfResolveStored     = 0x00020000
+pfEditable          = 0x00040000
+pfResolveEditable   = 0x00080000
+pfUser              = 0x00100000
+pfResolveUser       = 0x00200000
+pfNotify            = 0x00400000
diff --git a/src/Graphics/QML/Internal/PrimValues.chs b/src/Graphics/QML/Internal/PrimValues.chs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Internal/PrimValues.chs
@@ -0,0 +1,82 @@
+{-# LANGUAGE
+    ForeignFunctionInterface
+  #-}
+
+module Graphics.QML.Internal.PrimValues where
+
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Ptr
+import Foreign.ForeignPtr
+import Foreign.Storable
+import Foreign.Marshal.Alloc
+import Foreign.Marshal.Array
+import System.IO.Unsafe
+
+#include "hsqml.h"
+
+cIntConv :: (Integral a, Integral b) => a -> b
+cIntConv = fromIntegral
+
+--
+-- String
+--
+
+{#pointer *HsQMLStringHandle as ^ newtype #}
+
+{#fun unsafe hsqml_get_string_size as ^
+  {} ->
+  `Int' fromIntegral #}
+
+hsqmlStringSize :: Int
+hsqmlStringSize = unsafePerformIO $ hsqmlGetStringSize
+
+{#fun unsafe hsqml_init_string as ^
+  {id `HsQMLStringHandle'} ->
+  `()' #}
+
+{#fun unsafe hsqml_deinit_string as ^
+  {id `HsQMLStringHandle'} ->
+  `()' #}
+
+{#fun unsafe hsqml_marshal_string as ^
+  {`Int',
+   id `HsQMLStringHandle'} ->
+  `Ptr CUShort' id #}
+
+{#fun unsafe hsqml_unmarshal_string as ^
+  {id `HsQMLStringHandle',
+   id `Ptr (Ptr CUShort)'} ->
+  `Int' #}
+
+--
+-- URL
+--
+
+{#pointer *HsQMLUrlHandle as ^ newtype #}
+
+{#fun unsafe hsqml_get_url_size as ^
+  {} ->
+  `Int' fromIntegral #}
+
+hsqmlUrlSize :: Int
+hsqmlUrlSize = unsafePerformIO $ hsqmlGetUrlSize
+
+{#fun unsafe hsqml_init_url as ^
+  {id `HsQMLUrlHandle'} ->
+  `()' #}
+
+{#fun unsafe hsqml_deinit_url as ^
+  {id `HsQMLUrlHandle'} ->
+  `()' #}
+
+{#fun unsafe hsqml_marshal_url as ^
+  {id `Ptr CChar',
+   `Int',
+   id `HsQMLUrlHandle'} ->
+  `()' #}
+
+{#fun unsafe hsqml_unmarshal_url as ^
+  {id `HsQMLUrlHandle',
+   id `Ptr (Ptr CChar)'} ->
+  `Int' #}
diff --git a/src/Graphics/QML/Marshal.hs b/src/Graphics/QML/Marshal.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Marshal.hs
@@ -0,0 +1,155 @@
+{-# LANGUAGE
+    ScopedTypeVariables,
+    TypeSynonymInstances,
+    FlexibleInstances
+  #-}
+
+-- | Type classs and instances for marshalling values between Haskell and QML.
+module Graphics.QML.Marshal (
+  MarshalIn (
+    mIn),
+  InMarshaller,
+  MarshalOut
+) where
+
+import Graphics.QML.Internal.Marshal
+import Graphics.QML.Internal.PrimValues
+
+import Data.Maybe
+import Data.Tagged
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.Foreign as T
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Marshal.Alloc
+import Foreign.Ptr
+import Foreign.Storable
+import Network.URI (
+    URI (URI), URIAuth (URIAuth),
+    parseURIReference, unEscapeString,
+    uriToString, escapeURIString, nullURI,
+    isUnescapedInURI)
+
+--
+-- Int/int built-in type
+--
+
+instance MarshalOut Int where
+  mOutFunc ptr int =
+    poke (castPtr ptr :: Ptr CInt) (fromIntegral int)
+  mOutAlloc num f =
+    alloca $ \(ptr :: Ptr CInt) ->
+      mOutFunc (castPtr ptr) num >> f (castPtr ptr)
+
+instance MarshalIn Int where
+  mIn = InMarshaller {
+    mInFuncFld = \ptr ->
+      errIO $ peek (castPtr ptr :: Ptr CInt) >>= return . fromIntegral,
+    mIOTypeFld = Tagged $ TypeName "int"
+  }
+
+--
+-- Double/double built-in type
+--
+
+instance MarshalOut Double where
+  mOutFunc ptr num =
+    poke (castPtr ptr :: Ptr CDouble) (realToFrac num)
+  mOutAlloc num f =
+    alloca $ \(ptr :: Ptr CDouble) ->
+      mOutFunc (castPtr ptr) num >> f (castPtr ptr)
+
+instance MarshalIn Double where
+  mIn = InMarshaller {
+    mInFuncFld = \ptr ->
+      errIO $ peek (castPtr ptr :: Ptr CDouble) >>= return . realToFrac,
+    mIOTypeFld = Tagged $ TypeName "double"
+  }
+
+--
+-- Text/QString built-in type
+--
+
+instance MarshalOut Text where
+  mOutFunc ptr txt = do
+    array <- hsqmlMarshalString
+        (T.lengthWord16 txt) (HsQMLStringHandle $ castPtr ptr)
+    T.unsafeCopyToPtr txt (castPtr array)
+  mOutAlloc txt f =
+    allocaBytes hsqmlStringSize $ \ptr -> do
+      hsqmlInitString $ HsQMLStringHandle ptr
+      mOutFunc (castPtr ptr) txt
+      ret <- f (castPtr ptr)
+      hsqmlDeinitString $ HsQMLStringHandle ptr
+      return ret
+
+instance MarshalIn Text where
+  mIn = InMarshaller {
+    mInFuncFld = \ptr -> errIO $ do
+      pair <- alloca (\bufPtr -> do
+        len <- hsqmlUnmarshalString (HsQMLStringHandle $ castPtr ptr) bufPtr
+        buf <- peek bufPtr
+        return (castPtr buf, fromIntegral len))
+      uncurry T.fromPtr pair,
+    mIOTypeFld = Tagged $ TypeName "QString"
+  }
+
+--
+-- String/QString built-in type
+--
+
+instance MarshalOut String where
+  mOutFunc ptr str = mOutFunc ptr $ T.pack str
+  mOutAlloc txt f =
+    allocaBytes hsqmlStringSize $ \ptr -> do
+      hsqmlInitString $ HsQMLStringHandle ptr
+      mOutFunc (castPtr ptr) txt
+      ret <- f (castPtr ptr)
+      hsqmlDeinitString $ HsQMLStringHandle ptr
+      return ret
+
+instance MarshalIn String where
+  mIn = InMarshaller {
+    mInFuncFld = fmap T.unpack . mInFuncFld mIn,
+    mIOTypeFld = Tagged $ TypeName "QString"
+  }
+
+--
+-- URI/QUrl built-in type
+--
+
+mapURIStrings :: (String -> String) -> URI -> URI
+mapURIStrings f (URI scheme auth path query frag) =
+    URI (f scheme) (mapAuth auth) (f path) (f query) (f frag)
+    where mapAuth (Just (URIAuth user name port)) =
+              Just $ URIAuth (f user) (f name) (f port)
+          mapAuth Nothing = Nothing
+
+instance MarshalOut URI where
+  mOutFunc ptr uri =
+    let str = uriToString id (mapURIStrings
+                (escapeURIString isUnescapedInURI) uri) ""
+    in withCStringLen str (\(buf, bufLen) ->
+         hsqmlMarshalUrl buf bufLen (HsQMLUrlHandle $ castPtr ptr))
+  mOutAlloc uri f =
+    allocaBytes hsqmlUrlSize $ \ptr -> do
+      hsqmlInitUrl $ HsQMLUrlHandle ptr
+      mOutFunc (castPtr ptr) uri
+      ret <- f (castPtr ptr)
+      hsqmlDeinitUrl $ HsQMLUrlHandle ptr
+      return ret
+
+instance MarshalIn URI where
+  mIn = InMarshaller {
+    mInFuncFld = \ptr -> errIO $ do
+      pair <- alloca (\bufPtr -> do
+        len <- hsqmlUnmarshalUrl (HsQMLUrlHandle $ castPtr ptr) bufPtr
+        buf <- peek bufPtr
+        return (castPtr buf, fromIntegral len))
+      str <- peekCStringLen pair
+      free $ fst pair
+      return $ mapURIStrings unEscapeString $
+        fromMaybe nullURI $ parseURIReference str,
+    mIOTypeFld = Tagged $ TypeName "QUrl"
+  }
diff --git a/src/Graphics/QML/Objects.hs b/src/Graphics/QML/Objects.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/QML/Objects.hs
@@ -0,0 +1,450 @@
+{-# LANGUAGE
+    ScopedTypeVariables,
+    TypeFamilies,
+    FlexibleContexts
+  #-}
+
+-- | Facilities for defining new object types which can be marshalled between
+-- Haskell and QML.
+module Graphics.QML.Objects (
+  -- * Class Definition
+  Object (
+    classDef),
+  ClassDef,
+  Member,
+  defClass,
+
+  -- * Methods
+  defMethod,
+  MethodSuffix,
+
+  -- * Properties
+  defPropertyRO,
+  defPropertyRW,
+
+  -- * Object References
+  ObjRef,
+  newObject,
+  fromObjRef,
+
+  -- * Marshalling Type-classes
+  objectInMarshaller,
+  MarshalThis (
+    type ThisObj,
+    mThis),
+  objectThisMarshaller
+) where
+
+import Graphics.QML.Internal.Marshal
+import Graphics.QML.Internal.Objects
+import Graphics.QML.Internal.Engine
+
+import Control.Monad
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.State
+import Data.Bits
+import Data.Char
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Maybe
+import Data.Tagged
+import Data.Typeable
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Ptr
+import Foreign.Storable
+import Foreign.Marshal.Alloc
+import Foreign.Marshal.Array
+import System.IO.Unsafe
+import Numeric
+
+--
+-- ObjRef
+--
+
+-- | The class 'MarshalThis' allows objects to be marshalled back into
+-- Haskell as the \"this\" value for callbacks.
+class (Object (ThisObj tt)) => MarshalThis tt where
+  type ThisObj tt
+  mThis :: ThisMarshaller tt
+
+-- | Encapsulates the functionality to needed to implement an instance of
+-- 'MarshalThis' so that such instances can be defined without access to
+-- implementation details.
+data ThisMarshaller tt = ThisMarshaller {
+  mThisFuncFld :: Ptr () -> IO tt
+}
+
+mThisFunc :: (MarshalThis tt) => Ptr () -> IO tt
+mThisFunc = mThisFuncFld mThis
+
+instance (Object tt) => MarshalOut (ObjRef tt) where
+  mOutFunc ptr obj = do
+    objPtr <- hsqmlObjectGetPointer $ objHndl obj
+    poke (castPtr ptr) objPtr
+  mOutAlloc obj f =
+    alloca $ \(ptr :: Ptr (Ptr ())) ->
+      mOutFunc (castPtr ptr) obj >> f (castPtr ptr)
+
+instance (Object tt) => MarshalIn (ObjRef tt) where
+  mIn = InMarshaller {
+    mInFuncFld = \ptr -> MaybeT $ do
+      objPtr <- peek (castPtr ptr)
+      hndl <- hsqmlGetObjectHandle objPtr $
+        Just $ classHndl (classDefCAF :: ClassDef tt)
+      return $ if isNullObjectHandle hndl
+        then Nothing else Just $ ObjRef hndl,
+    mIOTypeFld = Tagged $ TypeName "QObject*"
+  }
+
+instance (Object tt) => MarshalThis (ObjRef tt) where
+  type ThisObj (ObjRef tt) = tt
+  mThis = ThisMarshaller {
+      mThisFuncFld = \ptr -> do
+      hndl <- hsqmlGetObjectHandle ptr Nothing
+      return $ ObjRef hndl
+  }
+
+retagType :: Tagged (ObjRef tt) TypeName -> Tagged tt TypeName
+retagType = retag
+
+-- | Provides an 'InMarshaller' which allows you to define instances of
+-- 'MarshalIn' for custom object types. For example:
+--
+-- @
+-- instance MarshalIn MyObjectType where
+--     mIn = objectInMarshaller
+-- @
+--
+-- This instance would allow @MyObjectType@ to be used as a parameter type
+-- in callbacks. An instance is provided for @'ObjRef' MyObjectType@ by
+-- default.
+objectInMarshaller :: (Object tt) => InMarshaller tt
+objectInMarshaller =
+  InMarshaller {
+    mInFuncFld = fmap fromObjRef . mInFunc,
+    mIOTypeFld = retagType mIOType
+  }
+
+-- | Provides an 'ThisMarshaller' which allows you to define instances of
+-- 'MarshalThis' for custom object types. For example:
+--
+-- @
+-- instance MarshalThis MyObjectType where
+--     type (ThisObj MyObjectType) = MyObjectType
+--     mIn = objectInMarshaller
+-- @
+--
+-- This instance would allow @MyObjectType@ to be used as the \"this\" type
+-- for callbacks. An instance is provided for @'ObjRef' MyObjectType@ by
+-- default.
+objectThisMarshaller :: (Object tt, (ThisObj tt) ~ tt) => ThisMarshaller tt
+objectThisMarshaller =
+  ThisMarshaller {
+    mThisFuncFld = fmap fromObjRef . mThisFunc
+  }
+
+-- | Creates an instance of a QML class given a value of the underlying Haskell 
+-- type @tt@.
+newObject :: forall tt. (Object tt) => tt -> IO (ObjRef tt)
+newObject obj = do
+  hndl <- hsqmlCreateObject obj $ classHndl (classDefCAF :: ClassDef tt)
+  return $ ObjRef hndl
+
+-- | 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 . hsqmlObjectGetHaskell . objHndl
+
+--
+-- Object
+--
+
+-- | The class 'Object' allows Haskell types to expose an object-oriented
+-- interface to QML. 
+class (Typeable tt) => Object tt where
+  classDef :: ClassDef tt
+
+-- | Uninlinable version of classDef to try and ensure that class definitions
+-- get stored as constant applicable forms.
+{-# NOINLINE classDefCAF #-}
+classDefCAF :: (Object tt) => ClassDef tt
+classDefCAF = classDef
+
+--
+-- ClassDef
+--
+
+-- | Represents the API of the QML class which wraps the type @tt@.
+data ClassDef tt = ClassDef {
+  classType :: TypeName,
+  classHndl :: HsQMLClassHandle
+}
+
+-- | Generates a 'ClassDef' from a list of 'Member's.
+defClass :: forall tt. (Object tt) => [Member tt] -> ClassDef tt
+defClass ms = unsafePerformIO $ do
+  let typ  = typeOf (undefined :: tt)
+      con  = typeRepTyCon typ
+      name = showString (tyConModule con) $ showChar '.' $ tyConName con
+  id <- hsqmlGetNextClassId
+  createClass (showString name $ showChar '_' $ showInt id "") ms
+
+createClass :: forall tt. (Object tt) =>
+  String -> [Member tt] -> IO (ClassDef tt)
+createClass name ms = do
+  let methods = methodMembers ms
+      properties = propertyMembers ms
+      (MOCOutput metaData metaStrData) = compileClass name methods properties
+  metaDataPtr <- newArray metaData
+  metaStrDataPtr <- newArray metaStrData
+  methodsPtr <- mapM (marshalFunc . methodFunc) methods >>= newArray
+  pReads <- mapM (marshalFunc . propertyReadFunc) properties
+  pWrites <- mapM (fromMaybe (return nullFunPtr) . fmap marshalFunc .
+    propertyWriteFunc) properties
+  propertiesPtr <- newArray $ interleave pReads pWrites
+  hsqmlInit
+  hndl <- hsqmlCreateClass metaDataPtr metaStrDataPtr methodsPtr propertiesPtr
+  return $ case hndl of 
+    Just hndl' -> ClassDef (TypeName name) hndl'
+    Nothing    -> error ("Failed to create QML class '"++name++"'.")
+
+interleave :: [a] -> [a] -> [a]
+interleave [] ys = ys
+interleave (x:xs) ys = x : ys `interleave` xs 
+
+--
+-- Member
+--
+
+-- | Represents a named member of the QML class which wraps type @tt@.
+data Member tt
+  -- | Constructs a 'Member' from a 'Method'.
+  = MethodMember (Method tt)
+  -- | Constructs a 'Member' from a 'Property'.
+  | PropertyMember (Property tt)
+
+-- | Returns the methods in a list of members.
+methodMembers :: [Member tt] -> [Method tt]
+methodMembers = mapMaybe f
+  where f (MethodMember m) = Just m
+        f _ = Nothing
+
+-- | Returns the properties in a list of members.
+propertyMembers :: [Member tt] -> [Property tt]
+propertyMembers = mapMaybe f
+  where f (PropertyMember m) = Just m
+        f _ = Nothing
+
+--
+-- Method
+--
+
+-- | Represents a named method which can be invoked from QML on an object of
+-- type @tt@.
+data Method tt = Method {
+  -- | Gets the name of a 'Method'.
+  methodName  :: String,
+  -- | Gets the 'TypeName's which comprise the signature of a 'Method'.
+  -- The head of the list is the return type and the tail the arguments.
+  methodTypes :: [TypeName],
+  methodFunc  :: UniformFunc
+}
+
+data CrudeMethodTypes = CrudeMethodTypes {
+    methodParamTypes :: [TypeName],
+    methodReturnType :: TypeName
+  }
+
+crudeTypesToList :: CrudeMethodTypes -> [TypeName]
+crudeTypesToList (CrudeMethodTypes p r) = r:p
+
+-- | Supports marshalling Haskell functions with an arbitrary number of
+-- arguments.
+class MethodSuffix a where
+  mkMethodFunc  :: Int -> a -> Ptr (Ptr ()) -> ErrIO ()
+  mkMethodTypes :: Tagged a CrudeMethodTypes
+
+instance (MarshalIn a, MethodSuffix b) => MethodSuffix (a -> b) where
+  mkMethodFunc n f pv = do
+    ptr <- errIO $ peekElemOff pv n
+    val <- mInFunc ptr
+    mkMethodFunc (n+1) (f val) pv
+    return ()
+  mkMethodTypes =
+    let (CrudeMethodTypes p r) =
+          untag (mkMethodTypes :: Tagged b CrudeMethodTypes)
+        ty = untag (mIOType :: Tagged a TypeName)
+    in Tagged $ CrudeMethodTypes (ty:p) r
+
+instance (MarshalOut a) => MethodSuffix (IO a) where
+  mkMethodFunc _ f pv = errIO $ do
+    ptr <- peekElemOff pv 0
+    val <- f
+    if nullPtr == ptr
+    then return ()
+    else mOutFunc ptr val
+  mkMethodTypes =
+    let ty = untag (mIOType :: Tagged a TypeName)
+    in Tagged $ CrudeMethodTypes [] ty
+
+mkUniformFunc :: forall tt ms. (MarshalThis tt, MethodSuffix ms) =>
+  (tt -> ms) -> UniformFunc
+mkUniformFunc f = \pt pv -> do
+  this <- mThisFunc pt
+  runErrIO $ mkMethodFunc 1 (f this) pv
+
+-- | Defines a named method using a function @f@ in the IO monad.
+--
+-- The first argument to @f@ receives the \"this\" object and hence must match
+-- the type of the class on which the method is being defined. Subsequently,
+-- there may be zero or more parameter arguments followed by an optional return
+-- argument in the IO monad. These argument types must be members of the
+-- 'MarshalThis', 'MarshalIn', and 'MarshalOut' typeclasses respectively.
+
+defMethod ::
+  forall tt ms. (MarshalThis tt, MethodSuffix ms) =>
+  String -> (tt -> ms) -> Member (ThisObj tt)
+defMethod name f = MethodMember $ Method name
+  (crudeTypesToList $ untag (mkMethodTypes :: Tagged ms CrudeMethodTypes))
+  (mkUniformFunc f)
+
+--
+-- Property
+--
+
+-- | Represents a named property which can be accessed from QML on an object
+-- of type @tt@.
+data Property tt = Property {
+  -- | Gets the name of a 'Property'.
+  propertyName :: String,
+  propertyType :: TypeName,
+  propertyReadFunc :: UniformFunc,
+  propertyWriteFunc :: Maybe UniformFunc
+}
+
+-- | Defines a named read-only property using an accessor function in the IO
+-- monad.
+defPropertyRO ::
+  forall tt tr. (MarshalThis tt, MarshalOut tr) =>
+  String -> (tt -> IO tr) -> Member (ThisObj tt)
+defPropertyRO name g = PropertyMember $ Property name
+  (untag (mIOType :: Tagged tr TypeName))
+  (mkUniformFunc g)
+  Nothing
+
+-- | Defines a named read-write property using a pair of accessor and mutator
+-- functions in the IO monad.
+defPropertyRW ::
+  forall tt tr. (MarshalThis tt, MarshalOut tr) =>
+  String -> (tt -> IO tr) -> (tt -> tr -> IO ()) -> Member (ThisObj tt)
+defPropertyRW name g s = PropertyMember $ Property name
+  (untag (mIOType :: Tagged tr TypeName))
+  (mkUniformFunc g)
+  (Just $ mkUniformFunc s)
+
+--
+-- Meta Object Compiler
+--
+
+data MOCState = MOCState {
+  mData            :: [CUInt],
+  mDataLen         :: Int,
+  mDataMethodsIdx  :: Maybe Int,
+  mDataPropsIdx    :: Maybe Int,
+  mStrData         :: [CChar],
+  mStrDataLen      :: Int,
+  mStrDataMap      :: Map String CUInt
+} deriving Show
+
+data MOCOutput = MOCOutput [CUInt] [CChar]
+
+newMOCState :: MOCState
+newMOCState = MOCState [] 0 Nothing Nothing [] 0 Map.empty
+
+writeInt :: CUInt -> State MOCState ()
+writeInt int = do
+  state <- get
+  let md    = mData state
+      mdLen = mDataLen state
+  put $ state {mData = int:md, mDataLen = mdLen+1}
+  return ()
+
+writeString :: String -> State MOCState ()
+writeString str = do
+  state <- get
+  let msd    = mStrData state
+      msdLen = mStrDataLen state
+      msdMap = mStrDataMap state
+  case (Map.lookup str msdMap) of
+    Just idx -> writeInt idx
+    Nothing  -> do
+      let idx = fromIntegral msdLen
+          msd' = 0 : (map castCharToCChar (reverse str) ++ msd)
+          msdLen' = msdLen + length str + 1
+          msdMap' = Map.insert str idx msdMap
+      put $ state {
+        mStrData = msd',
+        mStrDataLen = msdLen',
+        mStrDataMap = msdMap'}
+      writeInt idx
+
+writeMethod :: Method tt -> State MOCState ()
+writeMethod m = do
+  idx <- get >>= return . mDataLen
+  writeString $ methodSignature m
+  writeString $ methodParameters m
+  writeString $ typeName $ head $ methodTypes m
+  writeString ""
+  writeInt (mfAccessPublic .|. mfMethodScriptable)
+  state <- get
+  put $ state {mDataMethodsIdx = mplus (mDataMethodsIdx state) (Just idx)}
+  return ()
+
+writeProperty :: Property tt -> State MOCState ()
+writeProperty p = do
+  idx <- get >>= return . mDataLen
+  writeString $ propertyName p
+  writeString $ typeName $ propertyType p
+  writeInt (pfReadable .|. pfScriptable .|.
+    if (isJust $ propertyWriteFunc p) then pfWritable else 0)
+  state <- get
+  put $ state {mDataPropsIdx = mplus (mDataPropsIdx state) (Just idx)}
+  return ()
+
+compileClass :: String -> [Method tt] -> [Property tt] -> MOCOutput
+compileClass name ms ps = 
+  let enc = flip execState newMOCState $ do
+        writeInt 5                           -- Revision
+        writeString name                     -- Class name
+        writeInt 0 >> writeInt 0             -- Class info
+        writeInt $ fromIntegral $ length ms  -- Methods
+        writeInt $ fromIntegral $
+          fromMaybe 0 $ mDataMethodsIdx enc  -- Methods (data index)
+        writeInt $ fromIntegral $ length ps  -- Properties
+        writeInt $ fromIntegral $
+          fromMaybe 0 $ mDataPropsIdx enc    -- Properties (data index)
+        writeInt 0 >> writeInt 0             -- Enums
+        writeInt 0 >> writeInt 0             -- Constructors
+        writeInt 0                           -- Flags
+        writeInt 0                           -- Signals        
+        mapM_ writeMethod ms
+        mapM_ writeProperty ps
+        writeInt 0
+  in MOCOutput (reverse $ mData enc) (reverse $ mStrData enc)
+
+foldr0 :: (a -> a -> a) -> a -> [a] -> a
+foldr0 _ x [] = x
+foldr0 f _ xs = foldr1 f xs
+
+methodSignature :: Method tt -> String
+methodSignature method =
+  let paramTypes = tail $ methodTypes method
+  in (showString (methodName method) . showChar '(' .
+       foldr0 (\l r -> l . showChar ',' . r) id
+         (map (showString . typeName) paramTypes) . showChar ')') ""
+
+methodParameters :: Method tt -> String
+methodParameters method =
+  replicate (flip (-) 2 $ length $ methodTypes method) ','
diff --git a/test/Test1.hs b/test/Test1.hs
new file mode 100644
--- /dev/null
+++ b/test/Test1.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+module Main where
+
+import Graphics.QML
+import Control.Monad
+import Data.IORef
+import Data.List
+import Data.Maybe
+import Data.Typeable
+import Network.URI
+import System.Exit
+import System.IO
+import System.Directory
+
+data HarnessObject = HarnessObject {
+    globalState :: IORef [String]
+} deriving Typeable
+
+markTaskComplete :: HarnessObject -> String -> IO ()
+markTaskComplete go task = do
+    let ref = globalState go
+    list <- readIORef ref
+    if elem task list
+    then do
+        putStrLn (
+            showString "Completed task '" .
+            showString task $ showString "'." [])
+        writeIORef ref $ delete task list
+    else do
+        putStrLn (showString "Unexpected task '" .
+            showString task $ showString "' completed." [])
+        writeIORef ref $ ("unexpected_" ++ task) : list
+
+testInt :: Int
+testInt = 8888
+
+testDouble :: Double
+testDouble = 0.25
+
+testString :: String
+testString = "我係QuickBrownFox"
+
+testURI :: URI
+testURI =
+    URI "http:" (Just $ URIAuth "" "www.example.com" "")
+        "/with space" "" "#test"
+
+data TestObject = TestObject deriving (Eq, Typeable)
+
+instance Object TestObject where
+    classDef = defClass []
+
+instance MarshalIn TestObject where
+    mIn = objectInMarshaller
+
+instance Object HarnessObject where
+    classDef = defClass [
+        defMethod "getInt" (\go -> do
+            markTaskComplete (fromObjRef go) "getInt"
+            return testInt),
+        defMethod "setInt" (\go i -> do
+            markTaskComplete (fromObjRef go) "setInt"
+            if (i == testInt)
+            then markTaskComplete (fromObjRef go) "setIntCorrect"
+            else return ()),
+        defMethod "getDouble" (\go -> do
+            markTaskComplete (fromObjRef go) "getDouble"
+            return testDouble),
+        defMethod "setDouble" (\go i -> do
+            markTaskComplete (fromObjRef go) "setDouble"
+            if (i == testDouble)
+            then markTaskComplete (fromObjRef go) "setDoubleCorrect"
+            else return ()),
+        defMethod "getString" (\go -> do
+            markTaskComplete (fromObjRef go) "getString"
+            return testString),
+        defMethod "setString" (\go i -> do
+            markTaskComplete (fromObjRef go) "setString"
+            if (i == testString)
+            then markTaskComplete (fromObjRef go) "setStringCorrect"
+            else return ()),
+        defMethod "getURI" (\go -> do
+            markTaskComplete (fromObjRef go) "getURI"
+            return testURI),
+        defMethod "setURI" (\go i -> do
+            markTaskComplete (fromObjRef go) "setURI"
+            if (i == testURI)
+            then markTaskComplete (fromObjRef go) "setURICorrect"
+            else return ()),
+        defMethod "getObject" (\go -> do
+            markTaskComplete (fromObjRef go) "getObject"
+            newObject TestObject),
+        defMethod "setObject" (\go i -> do
+            markTaskComplete (fromObjRef go) "setObject"
+            if (i == TestObject)
+            then markTaskComplete (fromObjRef go) "setObjectCorrect"
+            else return ())]
+
+testScript :: String
+testScript = unlines [
+    "import Qt 4.7",
+    "Rectangle {",
+    "    id: page;",
+    "    width: 100; height: 100;",
+    "    color: 'green';",
+    "    Component.onCompleted: {",
+    "        var intVar = getInt();",
+    "        setInt(intVar);",
+    "        var dblVar = getDouble();",
+    "        setDouble(dblVar);",
+    "        var strVar = getString();",
+    "        setString(strVar);",
+    "        var uriVar = getURI();",
+    "        setURI(uriVar);",
+    "        var objVar = getObject();",
+    "        setObject(objVar);",
+    "        window.close();",
+    "    }",
+    "}"]
+
+testTasks :: [String]
+testTasks = [
+    "getInt", "setInt", "setIntCorrect",
+    "getDouble", "setDouble", "setDoubleCorrect",
+    "getString", "setString", "setStringCorrect",
+    "getURI", "setURI", "setURICorrect",
+    "getObject", "setObject", "setObjectCorrect"]
+
+main :: IO ()
+main = do
+    tmpDir <- getTemporaryDirectory
+    (qmlPath, hndl) <- openTempFile tmpDir "test1-.qml"
+    hPutStr hndl testScript
+    hClose hndl
+    list <- newIORef testTasks
+    go <- newObject $ HarnessObject list
+    createEngine defaultEngineConfig {
+        initialURL = fromJust $ parseURIReference qmlPath,
+        contextObject = Just go}
+    runEngines
+    removeFile qmlPath
+    ts <- readIORef list
+    forM_ ts (\t -> putStrLn (
+        showString "Incomplete task '" . showString t $ showString "'." []))
+    if null ts
+    then exitSuccess
+    else exitFailure
