diff --git a/Changelog b/Changelog
new file mode 100644
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,19 @@
+commit 76f9b0da62ba560bcb7dbc1b12f86e595d619d6f
+Author: Magicloud <1886157+Magicloud@users.noreply.github.com>
+Date:   Tue Jan 15 23:54:22 2019 +0800
+
+    Bump version
+
+commit 5be373678896aa15647f5ee33c9063171d5435f6
+Author: Magicloud <1886157+Magicloud@users.noreply.github.com>
+Date:   Tue Jan 15 23:53:08 2019 +0800
+
+    Testing case migrated from haskell-gi.
+
+commit b3b0eac9672630657778c1ce95b3fb560f8172fe
+Author: Magicloud <1886157+Magicloud@users.noreply.github.com>
+Date:   Sat Jan 12 14:05:57 2019 +0800
+
+    Bridge between GI packages and cairo-core/cairo-opts.
+    
+    Reexport structures and their gtype. Provide `Connector` for converting.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Magicloud (c) 2019
+
+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 Magicloud 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# gi-cairo
+
+Bridge between gi-* and cairo-core. Reexport the types, and a connector.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/gi-cairo-again.cabal b/gi-cairo-again.cabal
new file mode 100644
--- /dev/null
+++ b/gi-cairo-again.cabal
@@ -0,0 +1,42 @@
+name:                gi-cairo-again
+version:             1.16.0
+synopsis:            Bridge between packages gi-* and cairo-core.
+description:         Bridge between packages gi-* and cairo-core. Just `fromGI` and `toGI`.
+homepage:            https://github.com/magicloud/gi-cairo#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Magicloud
+maintainer:          magiclouds@gmail.com
+copyright:           None
+category:            Graphics
+build-type:          Simple
+extra-source-files:  README.md, Changelog
+cabal-version:       2.0
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     GI.Cairo.Connector
+                       GI.Cairo.Enums
+                       GI.Cairo.Structs.Context
+                       GI.Cairo.Structs.Device
+                       GI.Cairo.Structs.FontFace
+                       GI.Cairo.Structs.FontOptions
+                       GI.Cairo.Structs.Matrix
+                       GI.Cairo.Structs.Path
+                       GI.Cairo.Structs.Pattern
+                       GI.Cairo.Structs.RectangleInt
+                       GI.Cairo.Structs.Region
+                       GI.Cairo.Structs.ScaledFont
+                       GI.Cairo.Structs.Surface
+  other-modules:       Helper
+  build-depends:       base >= 4.7 && < 5
+                     , cairo-core
+                     , haskell-gi-base
+                     , template-haskell
+  default-language:    Haskell2010
+  default-extensions:  TemplateHaskell
+                       MultiParamTypeClasses
+
+source-repository head
+  type:     git
+  location: https://github.com/magicloud/gi-cairo
diff --git a/src/GI/Cairo/Connector.hs b/src/GI/Cairo/Connector.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Connector.hs
@@ -0,0 +1,5 @@
+module GI.Cairo.Connector where
+
+class Connector a b where
+  fromGI :: a -> IO b
+  toGI :: b -> IO a
diff --git a/src/GI/Cairo/Enums.hs b/src/GI/Cairo/Enums.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Enums.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Enums (Antialias(..), Content(..), Extend(..), FillRule(..), Filter(..), FontSlant(..), FontWeight(..), Format(..), HintMetrics(..), HintStyle(..), LineCap(..), LineJoin(..), Operator(..), PathDataType(..), SubpixelOrder(..), Status(..), FontType(..), PatternType(..), SurfaceType(..), TextClusterFlags(..), DeviceType(..), RegionOverlap(..)) where
+
+import Data.GI.Base.BasicTypes
+import Graphics.Cairo.Types
+import Helper
+
+$(concat <$> mapM genForEnum [''Antialias, ''Content, ''Extend, ''FillRule, ''Filter, ''FontSlant, ''FontWeight, ''Format, ''HintMetrics, ''HintStyle, ''LineCap, ''LineJoin, ''Operator, ''PathDataType, ''SubpixelOrder, ''Status, ''FontType, ''PatternType, ''SurfaceType, ''TextClusterFlags, ''DeviceType, ''RegionOverlap])
diff --git a/src/GI/Cairo/Structs/Context.hs b/src/GI/Cairo/Structs/Context.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Context.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.Context where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "Context")
diff --git a/src/GI/Cairo/Structs/Device.hs b/src/GI/Cairo/Structs/Device.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Device.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.Device where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "Device")
diff --git a/src/GI/Cairo/Structs/FontFace.hs b/src/GI/Cairo/Structs/FontFace.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/FontFace.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.FontFace where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "FontFace")
diff --git a/src/GI/Cairo/Structs/FontOptions.hs b/src/GI/Cairo/Structs/FontOptions.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/FontOptions.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.FontOptions where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "FontOptions")
diff --git a/src/GI/Cairo/Structs/Matrix.hs b/src/GI/Cairo/Structs/Matrix.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Matrix.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE FlexibleInstances #-}
+module GI.Cairo.Structs.Matrix where
+
+import           Data.GI.Base.BasicTypes
+import           Data.GI.Base.ManagedPtr
+import           Foreign.ForeignPtr
+import           Foreign.Marshal.Alloc
+import           Foreign.Ptr
+import           Foreign.Storable
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+newtype Matrix = Matrix (ManagedPtr Matrix)
+
+instance BoxedObject Matrix where
+  boxedType _ = matrixGType
+
+foreign import ccall safe "cairo_gobject_matrix__get_type"
+  matrixGType :: IO GType
+
+instance Connector Matrix (T.Matrix Double) where
+  fromGI (Matrix (ManagedPtr fp _ _)) = withForeignPtr (castForeignPtr fp) peek
+  toGI md = do
+    p <- malloc
+    poke p md
+    Matrix <$> newManagedPtr_ (castPtr p)
diff --git a/src/GI/Cairo/Structs/Path.hs b/src/GI/Cairo/Structs/Path.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Path.hs
@@ -0,0 +1,25 @@
+module GI.Cairo.Structs.Path where
+
+import           Data.GI.Base.BasicTypes
+import           Data.GI.Base.ManagedPtr
+import           Foreign.ForeignPtr
+import           Foreign.Marshal.Alloc
+import           Foreign.Ptr
+import           Foreign.Storable
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+newtype Path = Path (ManagedPtr Path)
+
+instance BoxedObject Path where
+  boxedType _ = pathGType
+
+foreign import ccall safe "cairo_gobject_path__get_type"
+  pathGType :: IO GType
+
+instance Connector Path T.Path where
+  fromGI (Path (ManagedPtr fp _ _)) = withForeignPtr (castForeignPtr fp) peek
+  toGI path = do
+    p <- malloc
+    poke p path
+    Path <$> newManagedPtr_ (castPtr p)
diff --git a/src/GI/Cairo/Structs/Pattern.hs b/src/GI/Cairo/Structs/Pattern.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Pattern.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.Pattern where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "Pattern")
diff --git a/src/GI/Cairo/Structs/RectangleInt.hs b/src/GI/Cairo/Structs/RectangleInt.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/RectangleInt.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE FlexibleInstances #-}
+module GI.Cairo.Structs.RectangleInt where
+
+import           Data.GI.Base.BasicTypes
+import           Data.GI.Base.ManagedPtr
+import           Foreign.ForeignPtr
+import           Foreign.Marshal.Alloc
+import           Foreign.Ptr
+import           Foreign.Storable
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+newtype RectangleInt = RectangleInt (ManagedPtr RectangleInt)
+
+instance BoxedObject RectangleInt where
+  boxedType _ = rectangle_intGType
+
+foreign import ccall safe "cairo_gobject_rectangle_int_get_type"
+  rectangle_intGType :: IO GType
+
+instance Connector RectangleInt (T.Rectangle Int) where
+  fromGI (RectangleInt (ManagedPtr fp _ _)) = withForeignPtr (castForeignPtr fp) peek
+  toGI ri = do
+    p <- malloc
+    poke p ri
+    RectangleInt <$> newManagedPtr_ (castPtr p)
diff --git a/src/GI/Cairo/Structs/Region.hs b/src/GI/Cairo/Structs/Region.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Region.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.Region where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "Region")
diff --git a/src/GI/Cairo/Structs/ScaledFont.hs b/src/GI/Cairo/Structs/ScaledFont.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/ScaledFont.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.ScaledFont where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "ScaledFont")
diff --git a/src/GI/Cairo/Structs/Surface.hs b/src/GI/Cairo/Structs/Surface.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Cairo/Structs/Surface.hs
@@ -0,0 +1,7 @@
+module GI.Cairo.Structs.Surface where
+
+import           Data.GI.Base.BasicTypes
+import qualified Graphics.Cairo.Types as T
+import           Helper
+
+$(genForStruct $ mkName "Surface")
diff --git a/src/Helper.hs b/src/Helper.hs
new file mode 100644
--- /dev/null
+++ b/src/Helper.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE QuasiQuotes #-}
+module Helper (genForEnum, genForStruct, mkName, castForeignPtr, newIORef, Connector, fromGI, toGI) where
+
+import Data.Char
+import Data.GI.Base.BasicTypes
+import Data.IORef
+import Foreign.ForeignPtr
+import GI.Cairo.Connector
+import Language.Haskell.TH
+import Language.Haskell.TH.Syntax
+
+genForEnum :: Name -> Q [Dec]
+genForEnum enumName =
+  let n = capital2underscore $ unOccName $ nameOccName enumName
+      c_fun = "cairo_gobject_" ++ n ++ "_get_type"
+      fun = mkName $ n ++ "GType"
+  in sequence
+  [ return $ ForeignD $ ImportF CCall Safe c_fun fun $ AppT (ConT $ mkName "IO") (ConT $ mkName "GType")
+  , head <$> [d|instance BoxedEnum $(conT enumName) where
+                  boxedEnumType _ = $(varE fun)|] ]
+
+genForStruct :: Name -> Q [Dec]
+genForStruct structName =
+  let n = capital2underscore $ unOccName $ nameOccName structName
+      c_fun = "cairo_gobject_" ++ n ++ "_get_type"
+      fun = mkName $ n ++ "GType"
+      qn = Name (nameOccName structName) (NameQ $ ModName "T")
+  in sequence
+  [ newtypeD (cxt []) structName [] Nothing (normalC structName [bangType (bang noSourceUnpackedness noSourceStrictness) $ appT (conT ''ManagedPtr) (conT structName)]) []
+  , head <$> [d|instance BoxedObject $(conT structName) where
+                  boxedType _ = $(varE fun)|]
+  , return $ ForeignD $ ImportF CCall Safe c_fun fun $ AppT (ConT $ mkName "IO") (ConT $ mkName "GType")
+  , head <$> [d|instance Connector $(conT structName) $(conT qn) where
+                  fromGI $(conP structName [conP (mkName "ManagedPtr") [varP $ mkName "fp", wildP, wildP]]) = return $ $(conE qn) $ castForeignPtr $(varE $ mkName "fp")
+                  toGI $(conP qn [varP (mkName "fp")]) = newIORef Nothing >>= return . $(conE structName) . ManagedPtr (castForeignPtr $(varE $ mkName "fp")) Nothing|] ]
+
+capital2underscore :: String -> String
+capital2underscore i = case concatMap (\c ->
+  if isUpper c
+    then ['_', toLower c]
+    else [c]) i of
+  '_' : x -> x
+  x -> x
+
+nameOccName :: Name -> OccName
+nameOccName (Name occName _) = occName
+
+unOccName :: OccName -> String
+unOccName (OccName s) = s
