module Data.GI.CodeGen.OverloadedSignals
( genObjectSignals
, genInterfaceSignals
, genOverloadedSignalConnectors
) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Monad (forM_, when)
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Set as S
import Data.GI.CodeGen.API
import Data.GI.CodeGen.Code
import Data.GI.CodeGen.Inheritance (fullObjectSignalList, fullInterfaceSignalList)
import Data.GI.CodeGen.GObject (apiIsGObject)
import Data.GI.CodeGen.Signal (signalHaskellName, genSignalConnector)
import Data.GI.CodeGen.SymbolNaming (upperName, hyphensToCamelCase,
qualifiedSymbol)
import Data.GI.CodeGen.Util (lcFirst, ucFirst)
findSignalNames :: [(Name, API)] -> CodeGen [Text]
findSignalNames apis = S.toList <$> go apis S.empty
where
go :: [(Name, API)] -> S.Set Text -> CodeGen (S.Set Text)
go [] set = return set
go ((_, api):apis) set =
case api of
APIInterface iface ->
go apis $ insertSignals (ifSignals iface) set
APIObject object ->
go apis $ insertSignals (objSignals object) set
_ -> go apis set
insertSignals :: [Signal] -> S.Set Text -> S.Set Text
insertSignals props set = foldr (S.insert . sigName) set props
genOverloadedSignalConnectors :: [(Name, API)] -> CodeGen ()
genOverloadedSignalConnectors allAPIs = do
setLanguagePragmas ["DataKinds", "PatternSynonyms", "CPP",
"RankNTypes", "ScopedTypeVariables", "TypeFamilies"]
setModuleFlags [ImplicitPrelude]
line "import Data.GI.Base.Signals (SignalProxy(..))"
line "import Data.GI.Base.Overloading (ResolveSignal)"
blank
signalNames <- findSignalNames allAPIs
forM_ signalNames $ \sn -> group $ do
let camelName = hyphensToCamelCase sn
line $ "#if MIN_VERSION_base(4,8,0)"
line $ "pattern " <> camelName <>
" :: SignalProxy object (ResolveSignal \""
<> lcFirst camelName <> "\" object)"
line $ "pattern " <> camelName <> " = SignalProxy"
line $ "#else"
line $ "pattern " <> camelName <> " = SignalProxy :: forall info object. "
<> "info ~ ResolveSignal \"" <> lcFirst camelName
<> "\" object => SignalProxy object info"
line $ "#endif"
exportDecl $ "pattern " <> camelName
signalInfoName :: Name -> Signal -> CodeGen Text
signalInfoName n signal = do
let infoName = upperName n <> (ucFirst . signalHaskellName . sigName) signal
<> "SignalInfo"
qualifiedSymbol infoName n
genInstance :: Name -> Signal -> CodeGen ()
genInstance owner signal = group $ do
let name = upperName owner
let sn = (ucFirst . signalHaskellName . sigName) signal
si <- signalInfoName owner signal
bline $ "data " <> si
line $ "instance SignalInfo " <> si <> " where"
indent $ do
let signalConnectorName = name <> sn
cbHaskellType = signalConnectorName <> "Callback"
line $ "type HaskellCallbackType " <> si <> " = " <> cbHaskellType
line $ "connectSignal _ obj cb connectMode = do"
indent $ genSignalConnector signal cbHaskellType "connectMode"
export (NamedSubsection SignalSection $ lcFirst sn) si
genObjectSignals :: Name -> Object -> CodeGen ()
genObjectSignals n o = do
let name = upperName n
isGO <- apiIsGObject n (APIObject o)
when isGO $ do
mapM_ (genInstance n) (objSignals o)
infos <- fullObjectSignalList n o >>=
mapM (\(owner, signal) -> do
si <- signalInfoName owner signal
return $ "'(\"" <> (lcFirst . hyphensToCamelCase . sigName) signal
<> "\", " <> si <> ")")
group $ do
let signalListType = name <> "SignalList"
line $ "type instance O.SignalList " <> name <> " = " <> signalListType
line $ "type " <> signalListType <> " = ('[ "
<> T.intercalate ", " infos <> "] :: [(Symbol, *)])"
genInterfaceSignals :: Name -> Interface -> CodeGen ()
genInterfaceSignals n iface = do
let name = upperName n
mapM_ (genInstance n) (ifSignals iface)
infos <- fullInterfaceSignalList n iface >>=
mapM (\(owner, signal) -> do
si <- signalInfoName owner signal
return $ "'(\"" <> (lcFirst . hyphensToCamelCase . sigName) signal
<> "\", " <> si <> ")")
group $ do
let signalListType = name <> "SignalList"
line $ "type instance O.SignalList " <> name <> " = " <> signalListType
line $ "type " <> signalListType <> " = ('[ "
<> T.intercalate ", " infos <> "] :: [(Symbol, *)])"