{-# LANGUAGE ScopedTypeVariables, GADTs, DataKinds, KindSignatures, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, PolyKinds, EmptyDataDecls, ConstraintKinds #-} {-# OPTIONS_GHC -Wall -fno-warn-orphans #-} module Data.GI.Base.Properties ( new , setObjectPropertyString , setObjectPropertyStringArray , setObjectPropertyPtr , setObjectPropertyCInt , setObjectPropertyCUInt , setObjectPropertyInt64 , setObjectPropertyUInt64 , setObjectPropertyFloat , setObjectPropertyDouble , setObjectPropertyBool , setObjectPropertyGType , setObjectPropertyObject , setObjectPropertyBoxed , setObjectPropertyEnum , setObjectPropertyFlags , setObjectPropertyVariant , setObjectPropertyByteArray , setObjectPropertyPtrGList , setObjectPropertyHash , getObjectPropertyString , getObjectPropertyStringArray , getObjectPropertyPtr , getObjectPropertyCInt , getObjectPropertyCUInt , getObjectPropertyInt64 , getObjectPropertyUInt64 , getObjectPropertyFloat , getObjectPropertyDouble , getObjectPropertyBool , getObjectPropertyGType , getObjectPropertyObject , getObjectPropertyBoxed , getObjectPropertyEnum , getObjectPropertyFlags , getObjectPropertyVariant , getObjectPropertyByteArray , getObjectPropertyPtrGList , getObjectPropertyHash , constructObjectPropertyString , constructObjectPropertyStringArray , constructObjectPropertyPtr , constructObjectPropertyCInt , constructObjectPropertyCUInt , constructObjectPropertyInt64 , constructObjectPropertyUInt64 , constructObjectPropertyFloat , constructObjectPropertyDouble , constructObjectPropertyBool , constructObjectPropertyGType , constructObjectPropertyObject , constructObjectPropertyBoxed , constructObjectPropertyEnum , constructObjectPropertyFlags , constructObjectPropertyVariant , constructObjectPropertyByteArray , constructObjectPropertyPtrGList , constructObjectPropertyHash ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif import Control.Monad ((>=>)) import Control.Monad.IO.Class (MonadIO, liftIO) import qualified Data.ByteString.Char8 as B import Data.Text (Text) import Data.Proxy (Proxy(..)) import Data.GI.Base.BasicTypes import Data.GI.Base.BasicConversions import Data.GI.Base.ManagedPtr import Data.GI.Base.Attributes import Data.GI.Base.GValue import Data.GI.Base.GVariant (newGVariantFromPtr) import Data.GI.Base.Overloading (ResolveAttribute) import Foreign hiding (new) import Foreign.C #include foreign import ccall "dbg_g_object_newv" g_object_newv :: GType -> CUInt -> Ptr a -> IO (Ptr b) -- | Construct a GObject given the constructor and a list of settable -- attributes. AttrOps are always constructible, so we don't need to -- enforce constraints here. new :: forall o m. (GObject o, MonadIO m) => (ForeignPtr o -> o) -> [AttrOp o 'AttrConstruct] -> m o new constructor attrs = liftIO $ do props <- mapM construct attrs let nprops = length props params <- mallocBytes (nprops*gparameterSize) fill params props gtype <- gobjectType (undefined :: o) result <- g_object_newv gtype (fromIntegral nprops) params freeStrings nprops params free params -- Make sure that the GValues defining the GProperties are still -- alive at this point (so, in particular, they are still alive when -- g_object_newv is called). Without this the GHC garbage collector -- may free the GValues before g_object_newv us called, which will -- unref the referred to objects, which may drop the last reference -- to the contained objects. g_object_newv then tries to access the -- (now invalid) contents of the GValue, and mayhem ensues. mapM_ (touchManagedPtr . snd) props wrapObject constructor (result :: Ptr o) where resolve :: AttrLabelProxy attr -> Proxy (ResolveAttribute attr o) resolve _ = Proxy construct :: AttrOp o 'AttrConstruct -> IO (String, GValue) construct (attr := x) = attrConstruct (resolve attr) x construct (attr :=> x) = x >>= attrConstruct (resolve attr) gvalueSize = #size GValue gparameterSize = #size GParameter -- Fill the given memory address with the contents of the array of -- GParameters. fill :: Ptr () -> [(String, GValue)] -> IO () fill _ [] = return () fill dataPtr ((str, gvalue):xs) = do cstr <- newCString str poke (castPtr dataPtr) cstr withManagedPtr gvalue $ \gvalueptr -> copyBytes (dataPtr `plusPtr` sizeOf nullPtr) gvalueptr gvalueSize fill (dataPtr `plusPtr` gparameterSize) xs -- Free the strings in the GParameter array (the GValues will be -- freed separately). freeStrings :: Int -> Ptr () -> IO () freeStrings 0 _ = return () freeStrings n dataPtr = do cstr <- peek (castPtr dataPtr) :: IO CString free cstr freeStrings (n-1) (dataPtr `plusPtr` gparameterSize) foreign import ccall "g_object_set_property" g_object_set_property :: Ptr a -> CString -> Ptr GValue -> IO () setObjectProperty :: GObject a => a -> String -> b -> (GValue -> b -> IO ()) -> GType -> IO () setObjectProperty obj propName propValue setter (GType gtype) = do gvalue <- buildGValue (GType gtype) setter propValue withManagedPtr obj $ \objPtr -> withCString propName $ \cPropName -> withManagedPtr gvalue $ \gvalueptr -> g_object_set_property objPtr cPropName gvalueptr foreign import ccall "g_object_get_property" g_object_get_property :: Ptr a -> CString -> Ptr GValue -> IO () getObjectProperty :: GObject a => a -> String -> (GValue -> IO b) -> GType -> IO b getObjectProperty obj propName getter gtype = do gvalue <- newGValue gtype withManagedPtr obj $ \objPtr -> withCString propName $ \cPropName -> withManagedPtr gvalue $ \gvalueptr -> g_object_get_property objPtr cPropName gvalueptr getter gvalue constructObjectProperty :: String -> b -> (GValue -> b -> IO ()) -> GType -> IO (String, GValue) constructObjectProperty propName propValue setter gtype = do gvalue <- buildGValue gtype setter propValue return (propName, gvalue) setObjectPropertyString :: GObject a => a -> String -> Text -> IO () setObjectPropertyString obj propName str = setObjectProperty obj propName str set_string (GType #const G_TYPE_STRING) constructObjectPropertyString :: String -> Text -> IO (String, GValue) constructObjectPropertyString propName str = constructObjectProperty propName str set_string (GType #const G_TYPE_STRING) getObjectPropertyString :: GObject a => a -> String -> IO Text getObjectPropertyString obj propName = getObjectProperty obj propName get_string (GType #const G_TYPE_STRING) setObjectPropertyPtr :: GObject a => a -> String -> Ptr b -> IO () setObjectPropertyPtr obj propName ptr = setObjectProperty obj propName ptr set_pointer (GType #const G_TYPE_POINTER) constructObjectPropertyPtr :: String -> Ptr b -> IO (String, GValue) constructObjectPropertyPtr propName ptr = constructObjectProperty propName ptr set_pointer (GType #const G_TYPE_POINTER) getObjectPropertyPtr :: GObject a => a -> String -> IO (Ptr b) getObjectPropertyPtr obj propName = getObjectProperty obj propName get_pointer (GType #const G_TYPE_POINTER) setObjectPropertyCInt :: GObject a => a -> String -> Int32 -> IO () setObjectPropertyCInt obj propName int = setObjectProperty obj propName int set_int32 (GType #const G_TYPE_INT) constructObjectPropertyCInt :: String -> Int32 -> IO (String, GValue) constructObjectPropertyCInt propName int = constructObjectProperty propName int set_int32 (GType #const G_TYPE_INT) getObjectPropertyCInt :: GObject a => a -> String -> IO Int32 getObjectPropertyCInt obj propName = getObjectProperty obj propName get_int32 (GType #const G_TYPE_INT) setObjectPropertyCUInt :: GObject a => a -> String -> Word32 -> IO () setObjectPropertyCUInt obj propName uint = setObjectProperty obj propName uint set_uint32 (GType #const G_TYPE_UINT) constructObjectPropertyCUInt :: String -> Word32 -> IO (String, GValue) constructObjectPropertyCUInt propName uint = constructObjectProperty propName uint set_uint32 (GType #const G_TYPE_UINT) getObjectPropertyCUInt :: GObject a => a -> String -> IO Word32 getObjectPropertyCUInt obj propName = getObjectProperty obj propName get_uint32 (GType #const G_TYPE_UINT) setObjectPropertyInt64 :: GObject a => a -> String -> Int64 -> IO () setObjectPropertyInt64 obj propName int64 = setObjectProperty obj propName int64 set_int64 (GType #const G_TYPE_INT64) constructObjectPropertyInt64 :: String -> Int64 -> IO (String, GValue) constructObjectPropertyInt64 propName int64 = constructObjectProperty propName int64 set_int64 (GType #const G_TYPE_INT64) getObjectPropertyInt64 :: GObject a => a -> String -> IO Int64 getObjectPropertyInt64 obj propName = getObjectProperty obj propName get_int64 (GType #const G_TYPE_INT64) setObjectPropertyUInt64 :: GObject a => a -> String -> Word64 -> IO () setObjectPropertyUInt64 obj propName uint64 = setObjectProperty obj propName uint64 set_uint64 (GType #const G_TYPE_UINT64) constructObjectPropertyUInt64 :: String -> Word64 -> IO (String, GValue) constructObjectPropertyUInt64 propName uint64 = constructObjectProperty propName uint64 set_uint64 (GType #const G_TYPE_UINT64) getObjectPropertyUInt64 :: GObject a => a -> String -> IO Word64 getObjectPropertyUInt64 obj propName = getObjectProperty obj propName get_uint64 (GType #const G_TYPE_UINT64) setObjectPropertyFloat :: GObject a => a -> String -> Float -> IO () setObjectPropertyFloat obj propName float = setObjectProperty obj propName float set_float (GType #const G_TYPE_FLOAT) constructObjectPropertyFloat :: String -> Float -> IO (String, GValue) constructObjectPropertyFloat propName float = constructObjectProperty propName float set_float (GType #const G_TYPE_FLOAT) getObjectPropertyFloat :: GObject a => a -> String -> IO Float getObjectPropertyFloat obj propName = getObjectProperty obj propName get_float (GType #const G_TYPE_FLOAT) setObjectPropertyDouble :: GObject a => a -> String -> Double -> IO () setObjectPropertyDouble obj propName double = setObjectProperty obj propName double set_double (GType #const G_TYPE_DOUBLE) constructObjectPropertyDouble :: String -> Double -> IO (String, GValue) constructObjectPropertyDouble propName double = constructObjectProperty propName double set_double (GType #const G_TYPE_DOUBLE) getObjectPropertyDouble :: GObject a => a -> String -> IO Double getObjectPropertyDouble obj propName = getObjectProperty obj propName get_double (GType #const G_TYPE_DOUBLE) setObjectPropertyBool :: GObject a => a -> String -> Bool -> IO () setObjectPropertyBool obj propName bool = setObjectProperty obj propName bool set_boolean (GType #const G_TYPE_BOOLEAN) constructObjectPropertyBool :: String -> Bool -> IO (String, GValue) constructObjectPropertyBool propName bool = constructObjectProperty propName bool set_boolean (GType #const G_TYPE_BOOLEAN) getObjectPropertyBool :: GObject a => a -> String -> IO Bool getObjectPropertyBool obj propName = getObjectProperty obj propName get_boolean (GType #const G_TYPE_BOOLEAN) setObjectPropertyGType :: GObject a => a -> String -> GType -> IO () setObjectPropertyGType obj propName gtype = setObjectProperty obj propName gtype set_gtype (GType #const G_TYPE_GTYPE) constructObjectPropertyGType :: String -> GType -> IO (String, GValue) constructObjectPropertyGType propName bool = constructObjectProperty propName bool set_gtype (GType #const G_TYPE_GTYPE) getObjectPropertyGType :: GObject a => a -> String -> IO GType getObjectPropertyGType obj propName = getObjectProperty obj propName get_gtype (GType #const G_TYPE_GTYPE) setObjectPropertyObject :: (GObject a, GObject b) => a -> String -> b -> IO () setObjectPropertyObject obj propName object = do gtype <- gobjectType object withManagedPtr object $ \objectPtr -> setObjectProperty obj propName objectPtr set_object gtype constructObjectPropertyObject :: GObject a => String -> a -> IO (String, GValue) constructObjectPropertyObject propName object = do gtype <- gobjectType object withManagedPtr object $ \objectPtr -> constructObjectProperty propName objectPtr set_object gtype getObjectPropertyObject :: forall a b. (GObject a, GObject b) => a -> String -> (ForeignPtr b -> b) -> IO b getObjectPropertyObject obj propName constructor = do gtype <- gobjectType (undefined :: b) getObjectProperty obj propName (\val -> (get_object val :: IO (Ptr b)) >>= newObject constructor) gtype setObjectPropertyBoxed :: (GObject a, BoxedObject b) => a -> String -> b -> IO () setObjectPropertyBoxed obj propName boxed = do gtype <- boxedType boxed withManagedPtr boxed $ \boxedPtr -> setObjectProperty obj propName boxedPtr set_boxed gtype constructObjectPropertyBoxed :: (BoxedObject a) => String -> a -> IO (String, GValue) constructObjectPropertyBoxed propName boxed = do gtype <- boxedType boxed withManagedPtr boxed $ \boxedPtr -> constructObjectProperty propName boxedPtr set_boxed gtype getObjectPropertyBoxed :: forall a b. (GObject a, BoxedObject b) => a -> String -> (ForeignPtr b -> b) -> IO b getObjectPropertyBoxed obj propName constructor = do gtype <- boxedType (undefined :: b) getObjectProperty obj propName (get_boxed >=> newBoxed constructor) gtype setObjectPropertyStringArray :: GObject a => a -> String -> [Text] -> IO () setObjectPropertyStringArray obj propName strv = do cStrv <- packZeroTerminatedUTF8CArray strv setObjectProperty obj propName cStrv set_boxed (GType #const G_TYPE_STRV) mapZeroTerminatedCArray free cStrv free cStrv constructObjectPropertyStringArray :: String -> [Text] -> IO (String, GValue) constructObjectPropertyStringArray propName strv = do cStrv <- packZeroTerminatedUTF8CArray strv result <- constructObjectProperty propName cStrv set_boxed (GType #const G_TYPE_STRV) mapZeroTerminatedCArray free cStrv free cStrv return result getObjectPropertyStringArray :: GObject a => a -> String -> IO [Text] getObjectPropertyStringArray obj propName = getObjectProperty obj propName (get_boxed >=> unpackZeroTerminatedUTF8CArray . castPtr) (GType #const G_TYPE_STRV) setObjectPropertyEnum :: (GObject a, Enum b, BoxedEnum b) => a -> String -> b -> IO () setObjectPropertyEnum obj propName enum = do gtype <- boxedEnumType enum let cEnum = (fromIntegral . fromEnum) enum setObjectProperty obj propName cEnum set_enum gtype constructObjectPropertyEnum :: (Enum a, BoxedEnum a) => String -> a -> IO (String, GValue) constructObjectPropertyEnum propName enum = do gtype <- boxedEnumType enum let cEnum = (fromIntegral . fromEnum) enum constructObjectProperty propName cEnum set_enum gtype getObjectPropertyEnum :: forall a b. (GObject a, Enum b, BoxedEnum b) => a -> String -> IO b getObjectPropertyEnum obj propName = do gtype <- boxedEnumType (undefined :: b) getObjectProperty obj propName (\val -> toEnum . fromIntegral <$> get_enum val) gtype setObjectPropertyFlags :: (IsGFlag b, GObject a) => a -> String -> [b] -> IO () setObjectPropertyFlags obj propName flags = let cFlags = gflagsToWord flags in setObjectProperty obj propName cFlags set_flags (GType #const G_TYPE_FLAGS) constructObjectPropertyFlags :: IsGFlag a => String -> [a] -> IO (String, GValue) constructObjectPropertyFlags propName flags = let cFlags = gflagsToWord flags in constructObjectProperty propName cFlags set_flags (GType #const G_TYPE_FLAGS) getObjectPropertyFlags :: (GObject a, IsGFlag b) => a -> String -> IO [b] getObjectPropertyFlags obj propName = getObjectProperty obj propName (\val -> wordToGFlags <$> get_flags val) (GType #const G_TYPE_FLAGS) setObjectPropertyVariant :: GObject a => a -> String -> GVariant -> IO () setObjectPropertyVariant obj propName variant = withManagedPtr variant $ \variantPtr -> setObjectProperty obj propName variantPtr set_variant (GType #const G_TYPE_VARIANT) constructObjectPropertyVariant :: String -> GVariant -> IO (String, GValue) constructObjectPropertyVariant propName obj = withManagedPtr obj $ \objPtr -> constructObjectProperty propName objPtr set_variant (GType #const G_TYPE_VARIANT) getObjectPropertyVariant :: GObject a => a -> String -> IO GVariant getObjectPropertyVariant obj propName = getObjectProperty obj propName (get_variant >=> newGVariantFromPtr) (GType #const G_TYPE_VARIANT) setObjectPropertyByteArray :: GObject a => a -> String -> B.ByteString -> IO () setObjectPropertyByteArray obj propName bytes = do packed <- packGByteArray bytes setObjectProperty obj propName packed set_boxed (GType #const G_TYPE_BYTE_ARRAY) unrefGByteArray packed constructObjectPropertyByteArray :: String -> B.ByteString -> IO (String, GValue) constructObjectPropertyByteArray propName bytes = do packed <- packGByteArray bytes result <- constructObjectProperty propName packed set_boxed (GType #const G_TYPE_BYTE_ARRAY) unrefGByteArray packed return result getObjectPropertyByteArray :: GObject a => a -> String -> IO B.ByteString getObjectPropertyByteArray obj propName = getObjectProperty obj propName (get_boxed >=> unpackGByteArray) (GType #const G_TYPE_BYTE_ARRAY) setObjectPropertyPtrGList :: GObject a => a -> String -> [Ptr b] -> IO () setObjectPropertyPtrGList obj propName ptrs = do packed <- packGList ptrs setObjectProperty obj propName packed set_boxed (GType #const G_TYPE_POINTER) g_list_free packed constructObjectPropertyPtrGList :: String -> [Ptr a] -> IO (String, GValue) constructObjectPropertyPtrGList propName ptrs = do packed <- packGList ptrs result <- constructObjectProperty propName packed set_boxed (GType #const G_TYPE_POINTER) g_list_free packed return result getObjectPropertyPtrGList :: GObject a => a -> String -> IO [Ptr b] getObjectPropertyPtrGList obj propName = getObjectProperty obj propName (get_pointer >=> unpackGList) (GType #const G_TYPE_POINTER) setObjectPropertyHash :: GObject a => a -> String -> b -> IO () setObjectPropertyHash = error $ "Setting GHashTable properties not supported yet." constructObjectPropertyHash :: String -> b -> IO (String, GValue) constructObjectPropertyHash = error $ "Constructing GHashTable properties not supported yet." getObjectPropertyHash :: GObject a => a -> String -> IO b getObjectPropertyHash = error $ "Getting GHashTable properties not supported yet."