{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS -Wall #-} module Graphics.Aosd.CallbackUtil(UserData,Callback,UniversalCallback,mkUniversalCallback,tunnelCallback) where import Foreign import Graphics.Aosd.Util type UserData = Ptr () type Callback a = a -> UserData -> IO () -- | A callback which assumes that its 'UserData' argument is a @'StablePtr' (a -> IO ())@ and -- delegates the @a@ to that @a -> IO ()@. newtype UniversalCallback a = UniversalCallback (FunPtr (Callback a)) mkUniversalCallback :: forall a. (Callback a -> IO (FunPtr (Callback a))) -- ^ Should be something obtained from a @foreign import ccall \"wrapper\" ...@ declaration -> IO (UniversalCallback a) mkUniversalCallback foreignImportWrapper = UniversalCallback `fmap` foreignImportWrapper universalCallback universalCallback :: a -> Ptr () -> IO () universalCallback a userData = do handler <- deRefStablePtr (castPtrToStablePtr userData) :: IO (a -> IO ()) handler a tunnelCallback :: UniversalCallback a -> (FunPtr (Callback a) -> UserData -> IO ()) -- ^ The C-imported callback setter function -> (a -> IO ()) -- ^ The haskell function you want to be called back -> IO (StablePtr (a -> IO ())) -- ^ Returns a StablePtr which needs to be freed once the callback is no longer used tunnelCallback (UniversalCallback u) setCallback haskellCallback = do sp <- newStablePtrDebug "tunnelCallback" "callback" haskellCallback setCallback u (castStablePtrToPtr sp) return sp