{-# LANGUAGE CPP #-}
module HookGenerator(hookGen) where
import Data.Char (showLitChar)
import Data.List (nub, isPrefixOf)
import System.Exit (exitWith, ExitCode(..))
import System.IO (stderr, hPutStr)
import Paths_gtk2hs_buildtools (getDataFileName)
data Types = Tunit
| Tbool
| Tchar
| Tuchar
| Tint
| Tuint
| Tlong
| Tulong
| Tenum
| Tflags
| Tfloat
| Tdouble
| Tstring
| Tmstring
| Tgstring
| Tmgstring
| Tboxed
| Tptr
| Ttobject
| Tmtobject
| Tobject
| Tmobject
deriving Eq
type Signature = (Types,[Types])
type Signatures = [Signature]
parseSignatures :: String -> Signatures
parseSignatures content = (nub.parseSig 1.scan) content
data Token = TokColon
| TokType Types
| TokComma
| TokEOL
instance Show Token where
showsPrec _ TokColon = shows ":"
showsPrec _ (TokType _) = shows "<type>"
showsPrec _ TokComma = shows ","
showsPrec _ TokEOL = shows "<EOL>"
parseSig :: Int -> [Token] -> Signatures
parseSig l [] = []
parseSig l (TokEOL: rem) = parseSig (l+1) rem
parseSig l (TokType ret: TokColon: TokType Tunit:rem) =
(ret,[]):parseSig l rem
parseSig l (TokType ret: TokColon: rem) =
let (args,rem') = parseArg l rem in
(ret,args): parseSig (l+1) rem'
parseSig l rem = error ("parse error on line "++show l++
": expected type and colon, found\n"++
concatMap show (take 5 rem))
parseArg :: Int -> [Token] -> ([Types],[Token])
parseArg l [TokType ty] = ([ty],[])
parseArg l (TokType ty: TokEOL:rem) = ([ty],rem)
parseArg l (TokType ty: TokComma:rem) =
let (args,rem') = parseArg l rem in
(ty:args, rem')
parseArg l rem = error ("parse error on line "++show l++": expected type"++
" followed by comma or EOL, found\n "++
concatMap show (take 5 rem))
scan :: String -> [Token]
scan "" = []
scan ('#':xs) = (scan.dropWhile (/='\n')) xs
scan ('\n':xs) = TokEOL:scan xs
scan (' ':xs) = scan xs
scan ('\t':xs) = scan xs
scan (':':xs) = TokColon:scan xs
scan (',':xs) = TokComma:scan xs
scan ('V':'O':'I':'D':xs) = TokType Tunit:scan xs
scan ('B':'O':'O':'L':'E':'A':'N':xs) = TokType Tbool:scan xs
scan ('C':'H':'A':'R':xs) = TokType Tchar:scan xs
scan ('U':'C':'H':'A':'R':xs) = TokType Tuchar:scan xs
scan ('I':'N':'T':xs) = TokType Tint:scan xs
scan ('U':'I':'N':'T':xs) = TokType Tuint:scan xs
scan ('L':'O':'N':'G':xs) = TokType Tuint:scan xs
scan ('U':'L':'O':'N':'G':xs) = TokType Tulong:scan xs
scan ('E':'N':'U':'M':xs) = TokType Tenum:scan xs
scan ('F':'L':'A':'G':'S':xs) = TokType Tflags:scan xs
scan ('F':'L':'O':'A':'T':xs) = TokType Tfloat:scan xs
scan ('D':'O':'U':'B':'L':'E':xs) = TokType Tdouble:scan xs
scan ('S':'T':'R':'I':'N':'G':xs) = TokType Tstring:scan xs
scan ('M':'S':'T':'R':'I':'N':'G':xs) = TokType Tmstring:scan xs
scan ('G':'L':'I':'B':'S':'T':'R':'I':'N':'G':xs) = TokType Tgstring:scan xs
scan ('M':'G':'L':'I':'B':'S':'T':'R':'I':'N':'G':xs) = TokType Tmgstring:scan xs
scan ('B':'O':'X':'E':'D':xs) = TokType Tboxed:scan xs
scan ('P':'O':'I':'N':'T':'E':'R':xs) = TokType Tptr:scan xs
scan ('T':'O':'B':'J':'E':'C':'T':xs) = TokType Ttobject:scan xs
scan ('M':'T':'O':'B':'J':'E':'C':'T':xs) = TokType Tmtobject:scan xs
scan ('O':'B':'J':'E':'C':'T':xs) = TokType Tobject:scan xs
scan ('M':'O':'B':'J':'E':'C':'T':xs) = TokType Tmobject:scan xs
scan ('N':'O':'N':'E':xs) = TokType Tunit:scan xs
scan ('B':'O':'O':'L':xs) = TokType Tbool:scan xs
scan str = error ("Invalid character in input file:\n"++
concatMap ((flip showLitChar) "") (take 5 str))
ss = showString
sc = showChar
indent :: Int -> ShowS
indent c = ss ("\n"++replicate (2*c) ' ')
identifier :: Types -> ShowS
identifier Tunit = ss "NONE"
identifier Tbool = ss "BOOL"
identifier Tchar = ss "CHAR"
identifier Tuchar = ss "UCHAR"
identifier Tint = ss "INT"
identifier Tuint = ss "WORD"
identifier Tlong = ss "LONG"
identifier Tulong = ss "ULONG"
identifier Tenum = ss "ENUM"
identifier Tflags = ss "FLAGS"
identifier Tfloat = ss "FLOAT"
identifier Tdouble = ss "DOUBLE"
identifier Tstring = ss "STRING"
identifier Tmstring = ss "MSTRING"
identifier Tgstring = ss "GLIBSTRING"
identifier Tmgstring = ss "MGLIBSTRING"
identifier Tboxed = ss "BOXED"
identifier Tptr = ss "PTR"
identifier Ttobject = ss "OBJECT"
identifier Tmtobject = ss "MOBJECT"
identifier Tobject = ss "OBJECT"
identifier Tmobject = ss "MOBJECT"
#ifdef USE_GCLOSURE_SIGNALS_IMPL
rawtype :: Types -> ShowS
rawtype Tunit = ss "()"
rawtype Tbool = ss "Bool"
rawtype Tchar = ss "Char"
rawtype Tuchar = ss "Char"
rawtype Tint = ss "Int"
rawtype Tuint = ss "Word"
rawtype Tlong = ss "Int"
rawtype Tulong = ss "Word"
rawtype Tenum = ss "Int"
rawtype Tflags = ss "Word"
rawtype Tfloat = ss "Float"
rawtype Tdouble = ss "Double"
rawtype Tstring = ss "CString"
rawtype Tmstring = ss "CString"
rawtype Tgstring = ss "CString"
rawtype Tmgstring = ss "CString"
rawtype Tboxed = ss "Ptr ()"
rawtype Tptr = ss "Ptr ()"
rawtype Ttobject = ss "Ptr GObject"
rawtype Tmtobject = ss "Ptr GObject"
rawtype Tobject = ss "Ptr GObject"
rawtype Tmobject = ss "Ptr GObject"
#else
rawtype :: Types -> ShowS
rawtype Tunit = ss "()"
rawtype Tbool = ss "{#type gboolean#}"
rawtype Tchar = ss "{#type gchar#}"
rawtype Tuchar = ss "{#type guchar#}"
rawtype Tint = ss "{#type gint#}"
rawtype Tuint = ss "{#type guint#}"
rawtype Tlong = ss "{#type glong#}"
rawtype Tulong = ss "{#type gulong#}"
rawtype Tenum = ss "{#type gint#}"
rawtype Tflags = ss "{#type guint#}"
rawtype Tfloat = ss "{#type gfloat#}"
rawtype Tdouble = ss "{#type gdouble#}"
rawtype Tstring = ss "CString"
rawtype Tmstring = ss "CString"
rawtype Tgstring = ss "CString"
rawtype Tmgstring = ss "CString"
rawtype Tboxed = ss "Ptr ()"
rawtype Tptr = ss "Ptr ()"
rawtype Ttobject = ss "Ptr GObject"
rawtype Tmtobject = ss "Ptr GObject"
rawtype Tobject = ss "Ptr GObject"
rawtype Tmobject = ss "Ptr GObject"
#endif
usertype :: Types -> [Char] -> (ShowS,[Char])
usertype Tunit cs = (ss "()",cs)
usertype Tbool (c:cs) = (ss "Bool",cs)
usertype Tchar (c:cs) = (ss "Char",cs)
usertype Tuchar (c:cs) = (ss "Char",cs)
usertype Tint (c:cs) = (ss "Int",cs)
usertype Tuint (c:cs) = (ss "Word",cs)
usertype Tlong (c:cs) = (ss "Int",cs)
usertype Tulong (c:cs) = (ss "Int",cs)
usertype Tenum (c:cs) = (sc c,cs)
usertype Tflags cs = usertype Tenum cs
usertype Tfloat (c:cs) = (ss "Float",cs)
usertype Tdouble (c:cs) = (ss "Double",cs)
usertype Tstring (c:cs) = (ss "String",cs)
usertype Tmstring (c:cs) = (ss "Maybe String",cs)
usertype Tgstring (c:cs) = (sc c.sc '\'',cs)
usertype Tmgstring (c:cs) = (ss "Maybe ".sc c.sc '\'',cs)
usertype Tboxed (c:cs) = (sc c,cs)
usertype Tptr (c:cs) = (ss "Ptr ".sc c,cs)
usertype Ttobject (c:cs) = (sc c.sc '\'',cs)
usertype Tmtobject (c:cs) = (ss "Maybe ".sc c.sc '\'',cs)
usertype Tobject (c:cs) = (sc c.sc '\'',cs)
usertype Tmobject (c:cs) = (ss "Maybe ".sc c.sc '\'',cs)
context :: [Types] -> [Char] -> [ShowS]
context (Tenum:ts) (c:cs) = ss "Enum ".sc c: context ts cs
context (Tflags:ts) (c:cs) = ss "Flags ".sc c: context ts cs
context (Ttobject:ts) (c:cs) = ss "GObjectClass ".sc c.sc '\'': context ts cs
context (Tmtobject:ts) (c:cs) = ss "GObjectClass ".sc c.sc '\'': context ts cs
context (Tobject:ts) (c:cs) = ss "GObjectClass ".sc c.sc '\'': context ts cs
context (Tmobject:ts) (c:cs) = ss "GObjectClass ".sc c.sc '\'': context ts cs
context (Tgstring:ts) (c:cs) = ss "Glib.GlibString ".sc c.sc '\'': context ts cs
context (Tmgstring:ts) (c:cs) = ss "Glib.GlibString ".sc c.sc '\'': context ts cs
context (_:ts) (c:cs) = context ts cs
context [] _ = []
marshType :: [Types] -> [Char] -> [ShowS]
marshType (Tint:ts) (c:cs) = marshType ts cs
marshType (Tuint:ts) (c:cs) = marshType ts cs
marshType (Tenum:ts) (c:cs) = marshType ts cs
marshType (Tflags:ts) cs = marshType (Tenum:ts) cs
marshType (Tboxed:ts) (c:cs) = ss "(Ptr ".sc c.ss "' -> IO ".
sc c.ss ") -> ":
marshType ts cs
marshType (Tptr:ts) (c:cs) = marshType ts cs
marshType (Tobject:ts) (c:cs) = marshType ts cs
marshType (_:ts) (c:cs) = marshType ts cs
marshType [] _ = []
type ArgNo = Int
marshArg :: Types -> ArgNo -> ShowS
marshArg Tboxed c = ss "boxedPre".shows c.sc ' '
marshArg _ _ = id
nameArg :: Types -> ArgNo -> ShowS
nameArg Tunit _ = id
nameArg Tbool c = ss "bool".shows c
nameArg Tchar c = ss "char".shows c
nameArg Tuchar c = ss "char".shows c
nameArg Tint c = ss "int".shows c
nameArg Tuint c = ss "int".shows c
nameArg Tlong c = ss "long".shows c
nameArg Tulong c = ss "long".shows c
nameArg Tenum c = ss "enum".shows c
nameArg Tflags c = ss "flags".shows c
nameArg Tfloat c = ss "float".shows c
nameArg Tdouble c = ss "double".shows c
nameArg Tstring c = ss "str".shows c
nameArg Tmstring c = ss "str".shows c
nameArg Tgstring c = ss "str".shows c
nameArg Tmgstring c = ss "str".shows c
nameArg Tboxed c = ss "box".shows c
nameArg Tptr c = ss "ptr".shows c
nameArg Ttobject c = ss "obj".shows c
nameArg Tmtobject c = ss "obj".shows c
nameArg Tobject c = ss "obj".shows c
nameArg Tmobject c = ss "obj".shows c
#ifdef USE_GCLOSURE_SIGNALS_IMPL
marshExec :: Types -> ShowS -> Int -> (ShowS -> ShowS)
marshExec Tbool arg _ body = body. sc ' '. arg
marshExec Tchar arg _ body = body. sc ' '. arg
marshExec Tuchar arg _ body = body. sc ' '. arg
marshExec Tint arg _ body = body. sc ' '. arg
marshExec Tuint arg _ body = body. sc ' '. arg
marshExec Tlong arg _ body = body. sc ' '. arg
marshExec Tulong arg _ body = body. sc ' '. arg
marshExec Tenum arg _ body = body. ss " (toEnum ". arg. sc ')'
marshExec Tflags arg _ body = body. ss " (toFlags ". arg. sc ')'
marshExec Tfloat arg _ body = body. sc ' '. arg
marshExec Tdouble arg _ body = body. sc ' '. arg
marshExec Tstring arg _ body = indent 5. ss "peekUTFString ". arg. ss " >>= \\". arg. ss "\' ->".
body. sc ' '. arg. sc '\''
marshExec Tmstring arg _ body = indent 5. ss "maybePeekUTFString ". arg. ss " >>= \\". arg. ss "\' ->".
body. sc ' '. arg. sc '\''
marshExec Tgstring arg _ body = indent 5. ss "peekUTFString ". arg. ss " >>= \\". arg. ss "\' ->".
body. sc ' '. arg. sc '\''
marshExec Tmgstring arg _ body = indent 5. ss "maybePeekUTFString ". arg. ss " >>= \\". arg. ss "\' ->".
body. sc ' '. arg. sc '\''
marshExec Tboxed arg n body = indent 5. ss "boxedPre". ss (show n). ss " (castPtr ". arg. ss ") >>= \\". arg. ss "\' ->".
body. sc ' '. arg. sc '\''
marshExec Tptr arg _ body = body. ss " (castPtr ". arg. sc ')'
marshExec Ttobject arg _ body = indent 5.ss "makeNewGObject (GObject, objectUnrefFromMainloop) (return ". arg. ss ") >>= \\". arg. ss "\' ->".
body. ss " (unsafeCastGObject ". arg. ss "\')"
marshExec Tmtobject arg _ body = indent 5.ss "maybeNull (makeNewGObject (GObject, objectUnrefFromMainloop)) (return ". arg. ss ") >>= \\". arg. ss "\' ->".
body. ss " (liftM unsafeCastGObject ". arg. ss "\')"
marshExec Tobject arg _ body = indent 5.ss "makeNewGObject (GObject, objectUnref) (return ". arg. ss ") >>= \\". arg. ss "\' ->".
body. ss " (unsafeCastGObject ". arg. ss "\')"
marshExec Tmobject arg _ body = indent 5.ss "maybeNull (makeNewGObject (GObject, objectUnref)) (return ". arg. ss ") >>= \\". arg. ss "\' ->".
body. ss " (liftM unsafeCastGObject ". arg. ss "\')"
marshRet :: Types -> (ShowS -> ShowS)
marshRet Tunit body = body
marshRet Tbool body = body
marshRet Tint body = body
marshRet Tuint body = body
marshRet Tlong body = body
marshRet Tulong body = body
marshRet Tenum body = indent 5. ss "liftM fromEnum $ ". body
marshRet Tflags body = indent 5. ss "liftM fromFlags $ ". body
marshRet Tfloat body = body
marshRet Tdouble body = body
marshRet Tstring body = body. indent 5. ss ">>= newUTFString"
marshRet Tgstring body = body. indent 5. ss ">>= newUTFString"
marshRet Tptr body = indent 5. ss "liftM castPtr $ ". body
marshRet _ _ = error "Signal handlers cannot return structured types."
#else
marshExec :: Types -> ArgNo -> ShowS
marshExec Tbool n = indent 4.ss "let bool".shows n.
ss "' = toBool bool".shows n
marshExec Tchar n = indent 4.ss "let char".shows n.
ss "' = (toEnum.fromEnum) char".shows n
marshExec Tuchar n = indent 4.ss "let char".shows n.
ss "' = (toEnum.fromEnum) char".shows n
marshExec Tint n = indent 4.ss "let int".shows n.
ss "' = fromIntegral int".shows n
marshExec Tuint n = indent 4.ss "let int".shows n.
ss "' = fromIntegral int".shows n
marshExec Tlong n = indent 4.ss "let long".shows n.
ss "' = toInteger long".shows n
marshExec Tulong n = indent 4.ss "let long".shows n.
ss "' = toInteger long".shows n
marshExec Tenum n = indent 4.ss "let enum".shows n.
ss "' = (toEnum.fromEnum) enum".shows n
marshExec Tflags n = indent 4.ss "let flags".shows n.
ss "' = (toEnum.fromEnum) flags".shows n
marshExec Tfloat n = indent 4.ss "let float".shows n.
ss "' = (fromRational.toRational) float".shows n
marshExec Tdouble n = indent 4.ss "let double".shows n.
ss "' = (fromRational.toRational) double".shows n
marshExec Tstring n = indent 4.ss "str".shows n.
ss "' <- peekCString str".shows n
marshExec Tmstring n = indent 4.ss "str".shows n.
ss "' <- maybePeekCString str".shows n
marshExec Tgstring n = indent 4.ss "str".shows n.
ss "' <- peekCString str".shows n
marshExec Tmgstring n = indent 4.ss "str".shows n.
ss "' <- maybePeekCString str".shows n
marshExec Tboxed n = indent 4.ss "box".shows n.ss "' <- boxedPre".
shows n.ss " $ castPtr box".shows n
marshExec Tptr n = indent 4.ss "let ptr".shows n.ss "' = castPtr ptr".
shows n
marshExec Ttobject n = indent 4.ss "objectRef obj".shows n.
indent 4.ss "obj".shows n.
ss "' <- liftM (unsafeCastGObject. fst mkGObject) $".
indent 5.ss "newForeignPtr obj".shows n.ss " (snd mkGObject)"
marshExec Tobject n = indent 4.ss "objectRef obj".shows n.
indent 4.ss "obj".shows n.
ss "' <- liftM (unsafeCastGObject. fst mkGObject) $".
indent 5.ss "newForeignPtr obj".shows n.ss " (snd mkGObject)"
marshExec _ _ = id
marshRet :: Types -> ShowS
marshRet Tunit = ss "id"
marshRet Tbool = ss "fromBool"
marshRet Tint = ss "fromIntegral"
marshRet Tuint = ss "fromIntegral"
marshRet Tlong = ss "fromIntegral"
marshRet Tulong = ss "fromIntegral"
marshRet Tenum = ss "(toEnum.fromEnum)"
marshRet Tflags = ss "fromFlags"
marshRet Tfloat = ss "(toRational.fromRational)"
marshRet Tdouble = ss "(toRational.fromRational)"
marshRet Tptr = ss "castPtr"
marshRet _ = ss "(error \"Signal handlers cannot return structured types.\")"
#endif
mkUserType :: Signature -> ShowS
mkUserType (ret,ts) = let
(str,cs) = foldl (\(str,cs) t ->
let (str',cs') = usertype t cs in (str.str'.ss " -> ",cs'))
(sc '(',['a'..]) ts
(str',_) = usertype ret cs
str'' = if ' ' `elem` (str' "") then (sc '('.str'.sc ')') else str'
in str.ss "IO ".str''.sc ')'
mkContext :: Signature -> ShowS
mkContext (ret,ts) = let ctxts = context (ts++[ret]) ['a'..] in
if null ctxts then ss "GObjectClass obj =>" else sc '('.
foldl1 (\a b -> a.ss ", ".b) ctxts.ss ", GObjectClass obj) =>"
mkMarshType :: Signature -> [ShowS]
mkMarshType (ret,ts) = marshType (ts++[ret]) ['a'..]
mkType sig = let types = mkMarshType sig in
if null types then id else foldl (.) (indent 1) types
mkMarshArg :: Signature -> [ShowS]
mkMarshArg (ret,ts) = zipWith marshArg (ts++[ret]) [1..]
mkArg sig = foldl (.) (sc ' ') $ mkMarshArg sig
#ifdef USE_GCLOSURE_SIGNALS_IMPL
mkMarshExec :: Signature -> ShowS
mkMarshExec (ret,ts) = foldl (\body marshaler -> marshaler body) (indent 5.ss "user")
(paramMarshalers++[returnMarshaler])
where paramMarshalers = [ marshExec t (nameArg t n) n | (t,n) <- zip ts [1..] ]
returnMarshaler = marshRet ret
#else
mkMarshExec :: Signature -> ShowS
mkMarshExec (_,ts) = foldl (.) id $
zipWith marshExec ts [1..]
#endif
mkIdentifier :: Signature -> ShowS
mkIdentifier (ret,[]) = identifier Tunit . ss "__".identifier ret
mkIdentifier (ret,ts) = foldl1 (\a b -> a.sc '_'.b) (map identifier ts).
ss "__".identifier ret
mkRawtype :: Signature -> ShowS
mkRawtype (ret,ts) =
foldl (.) id (map (\ty -> rawtype ty.ss " -> ") ts).
(case ret of
Tboxed -> ss "IO (".rawtype ret.sc ')'
Tptr -> ss "IO (".rawtype ret.sc ')'
Ttobject -> ss "IO (".rawtype ret.sc ')'
Tmtobject -> ss "IO (".rawtype ret.sc ')'
Tobject -> ss "IO (".rawtype ret.sc ')'
Tmobject -> ss "IO (".rawtype ret.sc ')'
_ -> ss "IO ".rawtype ret)
mkLambdaArgs :: Signature -> ShowS
mkLambdaArgs (_,ts) = foldl (.) id $
zipWith (\a b -> nameArg a b.sc ' ') ts [1..]
#ifndef USE_GCLOSURE_SIGNALS_IMPL
mkFuncArgs :: Signature -> ShowS
mkFuncArgs (_,ts) = foldl (.) id $
zipWith (\a b -> sc ' '.nameArg a b.sc '\'') ts [1..]
mkMarshRet :: Signature -> ShowS
mkMarshRet (ret,_) = marshRet ret
#endif
usage = do
hPutStr stderr $
"Program to generate callback hook for Gtk signals. Usage:\n\n"++
"HookGenerator [--template=<template-file>] --types=<types-file>\n"++
" [--import=<import>] --modname=<moduleName> > <outFile>\n"++
"where\n"++
" <moduleName> the module name for <outFile>\n"++
" <template-file> a path to the Signal.chs.template file\n"++
" <types-file> a path to a gtkmarshal.list file\n"++
" <import> a module to be imported into the template file\n"
exitWith $ ExitFailure 1
hookGen :: [String] -> IO String
hookGen args = do
let showHelp = not (null (filter ("-h" `isPrefixOf`) args++
filter ("--help" `isPrefixOf`) args)) || null args
if showHelp then usage else do
let outModuleName = case map (drop 10) (filter ("--modname=" `isPrefixOf`) args) of
(modName:_) -> modName
templateFile <- case map (drop 11) (filter ("--template=" `isPrefixOf`) args) of
[tplName] -> return tplName
_ -> getDataFileName "callbackGen/Signal.chs.template"
typesFile <- case map (drop 8) (filter ("--types=" `isPrefixOf`) args) of
[typName] -> return typName
_ -> usage
let extraImports = map (drop 9) (filter ("--import=" `isPrefixOf`) args)
content <- readFile typesFile
let sigs = parseSignatures content
template <- readFile templateFile
return $
templateSubstitute template (\var ->
case var of
"MODULE_NAME" -> ss outModuleName
"MODULE_EXPORTS" -> genExport sigs
"MODULE_IMPORTS" -> genImports extraImports
"MODULE_BODY" -> foldl (.) id (map generate sigs)
_ -> error var
) ""
templateSubstitute :: String -> (String -> ShowS) -> ShowS
templateSubstitute template varSubst = doSubst template
where doSubst [] = id
doSubst ('\\':'@':cs) = sc '@' . doSubst cs
doSubst ('@':cs) = let (var,_:cs') = span ('@'/=) cs
in varSubst var . doSubst cs'
doSubst (c:cs) = sc c . doSubst cs
genExport :: Signatures -> ShowS
genExport sigs = foldl (.) id (map mkId sigs)
where
mkId sig = ss "connect_".mkIdentifier sig.sc ','.indent 1
genImports :: [String] -> ShowS
genImports mods = foldl (.) id (map mkImp mods)
where
mkImp m = ss "import " . ss m . indent 0
#ifdef USE_GCLOSURE_SIGNALS_IMPL
generate :: Signature -> ShowS
generate sig = let ident = mkIdentifier sig in
indent 0.ss "connect_".ident.ss " :: ".
indent 1.mkContext sig.ss " SignalName ->".
mkType sig.
indent 1.ss "ConnectAfter -> obj ->".
indent 1.mkUserType sig.ss " ->".
indent 1.ss "IO (ConnectId obj)".
indent 0.ss "connect_".ident.ss " signal". mkArg sig. ss "after obj user =".
indent 1.ss "connectGeneric signal after obj action".
indent 1.ss "where action :: Ptr GObject -> ".mkRawtype sig.
indent 1.ss " action _ ".mkLambdaArgs sig. sc '='.
indent 5.ss "failOnGError $".
mkMarshExec sig.
indent 0
#else
generate :: Signature -> ShowS
generate sig = let ident = mkIdentifier sig in
indent 0.ss "type Tag_".ident.ss " = Ptr () -> ".
indent 1.mkRawtype sig.
indent 0.
indent 0.ss "foreign".ss " import ccall \"wrapper\" ".ss "mkHandler_".ident.ss " ::".
indent 1.ss "Tag_".ident.ss " -> ".
indent 1.ss "IO (FunPtr ".ss "Tag_".ident.sc ')'.
indent 0.
indent 0.ss "connect_".ident.ss " :: ".
indent 1.mkContext sig.ss " SignalName ->".
mkType sig.
indent 1.ss "ConnectAfter -> obj ->".
indent 1.mkUserType sig.ss " ->".
indent 1.ss "IO (ConnectId obj)".
indent 0.ss "connect_".ident.ss " signal".
mkArg sig.
indent 1.ss "after obj user =".
indent 1.ss "do".
indent 2.ss "hPtr <- mkHandler_".ident.
indent 3.ss "(\\_ ".mkLambdaArgs sig.ss "-> failOnGError $ do".
mkMarshExec sig.
indent 4.ss "liftM ".mkMarshRet sig.ss " $".
indent 5.ss "user".mkFuncArgs sig.
indent 3.sc ')'.
indent 2.ss "dPtr <- mkFunPtrClosureNotify hPtr".
indent 2.ss "sigId <- withCString signal $ \\nPtr ->".
indent 3.ss "withForeignPtr ((unGObject.toGObject) obj) $ \\objPtr ->".
indent 4.ss "{#call unsafe g_signal_connect_data#} (castPtr objPtr)".
indent 5.ss "nPtr (castFunPtr hPtr) nullPtr dPtr (fromBool after)".
indent 2.ss "return $ ConnectId sigId obj".
indent 0
#endif