module Sound.Pulse.Mainloop
( PAMainloop(..)
, PAIOEventFlags(..)
, PAMainloopApi
, getMainloopApi
)
where
import Sound.Pulse.Userdata
import Control.Applicative ((<$>), (<*>))
import Foreign.Marshal.Utils (with)
import Foreign.Storable
import Foreign.StablePtr
import Foreign.Ptr
import Foreign.C.Types
import System.Posix.Types (Fd(..))
import Data.Bits ((.&.), (.|.))
import Control.Concurrent.MVar
import Data.Time
import Data.Time.Internal
data PAIOEventFlags
= PAIOEventNull
| PAIOEventInput
| PAIOEventOutput
| PAIOEventHangup
| PAIOEventError
deriving (Eq, Show)
ioEventToCInt :: PAIOEventFlags -> CInt
ioEventToCInt PAIOEventNull = 0
ioEventToCInt PAIOEventInput = 1
ioEventToCInt PAIOEventOutput = 2
ioEventToCInt PAIOEventHangup = 4
ioEventToCInt PAIOEventError = 8
ioEventsToCInt :: [PAIOEventFlags] -> CInt
ioEventsToCInt xs = foldr (\x y -> ioEventToCInt x .|. y) 0 xs
ioEventsFromCInt :: CInt -> [PAIOEventFlags]
ioEventsFromCInt val =
let enull = potAdd PAIOEventNull []
input = potAdd PAIOEventInput enull
output = potAdd PAIOEventOutput input
hangup = potAdd PAIOEventHangup output
err = potAdd PAIOEventError hangup
in err
where potAdd :: PAIOEventFlags -> ([PAIOEventFlags] -> [PAIOEventFlags])
potAdd con = if (val .&. ioEventToCInt con) /= 0 then (con:) else id
class PAMainloop a where
data PAIOEvent a :: *
data PATimeEvent a :: *
data PADeferEvent a :: *
ioNew :: a -> Fd -> [PAIOEventFlags] -> ([PAIOEventFlags] -> IO ()) -> IO (PAIOEvent a)
ioEnable :: (PAIOEvent a) -> [PAIOEventFlags] -> IO ()
ioFree :: (PAIOEvent a) -> IO ()
ioSetDestroy :: (PAIOEvent a) -> IO () -> IO ()
timeNew :: a -> PATime -> (PATime -> IO ()) -> IO (PATimeEvent a)
timeRestart :: PATimeEvent a -> PATime -> IO ()
timeFree :: PATimeEvent a -> IO ()
timeSetDestroy :: PATimeEvent a -> IO () -> IO ()
deferNew :: a -> IO () -> IO (PADeferEvent a)
deferEnable :: PADeferEvent a -> Bool -> IO ()
deferFree :: PADeferEvent a -> IO ()
deferSetDestroy :: PADeferEvent a -> IO () -> IO ()
quitLoop :: a -> Int -> IO ()
data PAIOEventW a = PAIOEventW
(PAIOEvent a)
(Ptr Userdata)
(Ptr (PAMainloopApi a))
ioRealHandle :: PAIOEventW a -> PAIOEvent a
ioRealHandle (PAIOEventW x _ _) = x
data PATimeEventW a = PATimeEventW
(PATimeEvent a)
(Ptr Userdata)
(Ptr (PAMainloopApi a))
timeRealHandle :: PATimeEventW a -> PATimeEvent a
timeRealHandle (PATimeEventW x _ _) = x
data PADeferEventW a = PADeferEventW
(PADeferEvent a)
(Ptr Userdata)
(Ptr (PAMainloopApi a))
deferRealHandle :: PADeferEventW a -> PADeferEvent a
deferRealHandle (PADeferEventW x _ _) = x
type IOEvCB a = Ptr (PAMainloopApi a) -> StablePtr (PAIOEventW a) -> CInt -> CInt -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkIOEvCB :: FunPtr (IOEvCB a) -> (IOEvCB a)
type IONew a = Ptr (PAMainloopApi a) -> CInt -> CInt -> FunPtr (IOEvCB a) -> Ptr Userdata -> IO (StablePtr (PAIOEventW a))
foreign import ccall "wrapper" mkIONew :: IONew a -> IO (FunPtr (IONew a))
type IOEnable a = StablePtr (PAIOEventW a) -> CInt -> IO ()
foreign import ccall "wrapper" mkIOEnable :: IOEnable a -> IO (FunPtr (IOEnable a))
type IOFree a = StablePtr (PAIOEventW a) -> IO ()
foreign import ccall "wrapper" mkIOFree :: IOFree a -> IO (FunPtr (IOFree a))
type IODestroy a = Ptr (PAMainloopApi a) -> StablePtr (PAIOEventW a) -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkIODestroy :: FunPtr (IODestroy a) -> (IODestroy a)
type IOSetDestroy a = StablePtr (PAIOEventW a) -> FunPtr (IODestroy a) -> IO ()
foreign import ccall "wrapper" mkIOSetDestroy :: IOSetDestroy a -> IO (FunPtr (IOSetDestroy a))
type TimeEvCB a = Ptr (PAMainloopApi a) -> StablePtr (PATimeEventW a) -> Ptr PAITime -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkTimeEvCB :: FunPtr (TimeEvCB a) -> (TimeEvCB a)
type TimeNew a = Ptr (PAMainloopApi a) -> Ptr PAITime -> FunPtr (TimeEvCB a) -> Ptr Userdata -> IO (StablePtr (PATimeEventW a))
foreign import ccall "wrapper" mkTimeNew :: TimeNew a -> IO (FunPtr (TimeNew a))
type TimeRestart a = StablePtr (PATimeEventW a) -> Ptr PAITime -> IO ()
foreign import ccall "wrapper" mkTimeRestart :: TimeRestart a -> IO (FunPtr (TimeRestart a))
type TimeFree a = StablePtr (PATimeEventW a) -> IO ()
foreign import ccall "wrapper" mkTimeFree :: TimeFree a -> IO (FunPtr (TimeFree a))
type TimeDestroy a = Ptr (PAMainloopApi a) -> StablePtr (PATimeEventW a) -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkTimeDestroy :: FunPtr (TimeDestroy a) -> (TimeDestroy a)
type TimeSetDestroy a = StablePtr (PATimeEventW a) -> FunPtr (TimeDestroy a) -> IO ()
foreign import ccall "wrapper" mkTimeSetDestroy :: TimeSetDestroy a -> IO (FunPtr (TimeSetDestroy a))
type DeferEvCB a = Ptr (PAMainloopApi a) -> StablePtr (PADeferEventW a) -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkDeferEvCB :: FunPtr (DeferEvCB a) -> DeferEvCB a
type DeferNew a = Ptr (PAMainloopApi a) -> FunPtr (DeferEvCB a) -> Ptr Userdata -> IO (StablePtr (PADeferEventW a))
foreign import ccall "wrapper" mkDeferNew :: DeferNew a -> IO (FunPtr (DeferNew a))
type DeferEnable a = StablePtr (PADeferEventW a) -> CInt -> IO ()
foreign import ccall "wrapper" mkDeferEnable :: DeferEnable a -> IO (FunPtr (DeferEnable a))
type DeferFree a = StablePtr (PADeferEventW a) -> IO ()
foreign import ccall "wrapper" mkDeferFree :: DeferFree a -> IO (FunPtr (DeferFree a))
type DeferDestroy a = Ptr (PAMainloopApi a) -> StablePtr (PADeferEventW a) -> Ptr Userdata -> IO ()
foreign import ccall "dynamic" mkDeferDestroy :: FunPtr (DeferDestroy a) -> (DeferDestroy a)
type DeferSetDestroy a = StablePtr (PADeferEventW a) -> FunPtr (DeferDestroy a) -> IO ()
foreign import ccall "wrapper" mkDeferSetDestroy :: DeferSetDestroy a -> IO (FunPtr (DeferSetDestroy a))
type Quit a = Ptr (PAMainloopApi a) -> CInt -> IO ()
foreign import ccall "wrapper" mkQuit :: Quit a -> IO (FunPtr (Quit a))
data PAMainloopApi a = PAMainloopApi
{ userdata :: StablePtr a
, io_new :: FunPtr (IONew a)
, io_enable :: FunPtr (IOEnable a)
, io_free :: FunPtr (IOFree a)
, io_set_destroy :: FunPtr (IOSetDestroy a)
, time_new :: FunPtr (TimeNew a)
, time_restart :: FunPtr (TimeRestart a)
, time_free :: FunPtr (TimeFree a)
, time_set_destroy :: FunPtr (TimeSetDestroy a)
, defer_new :: FunPtr (DeferNew a)
, defer_enable :: FunPtr (DeferEnable a)
, defer_free :: FunPtr (DeferFree a)
, defer_set_destroy :: FunPtr (DeferSetDestroy a)
, quit :: FunPtr (Quit a)
}
instance Storable (PAMainloopApi a) where
sizeOf _ = (112)
alignment _ = (8)
peek p = PAMainloopApi
<$> (\hsc_ptr -> peekByteOff hsc_ptr 0) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 8) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 16) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 24) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 32) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 40) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 48) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 56) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 64) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 72) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 80) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 88) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 96) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 104) p
poke p (PAMainloopApi {..}) = do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) p userdata
(\hsc_ptr -> pokeByteOff hsc_ptr 8) p io_new
(\hsc_ptr -> pokeByteOff hsc_ptr 16) p io_enable
(\hsc_ptr -> pokeByteOff hsc_ptr 24) p io_free
(\hsc_ptr -> pokeByteOff hsc_ptr 32) p io_set_destroy
(\hsc_ptr -> pokeByteOff hsc_ptr 40) p time_new
(\hsc_ptr -> pokeByteOff hsc_ptr 48) p time_restart
(\hsc_ptr -> pokeByteOff hsc_ptr 56) p time_free
(\hsc_ptr -> pokeByteOff hsc_ptr 64) p time_set_destroy
(\hsc_ptr -> pokeByteOff hsc_ptr 72) p defer_new
(\hsc_ptr -> pokeByteOff hsc_ptr 80) p defer_enable
(\hsc_ptr -> pokeByteOff hsc_ptr 88) p defer_free
(\hsc_ptr -> pokeByteOff hsc_ptr 96) p defer_set_destroy
(\hsc_ptr -> pokeByteOff hsc_ptr 104) p quit
getMainloopImpl :: Ptr (PAMainloopApi a) -> IO a
getMainloopImpl p =
deRefStablePtr =<< (peek . (\hsc_ptr -> hsc_ptr `plusPtr` 0) $ p)
getMainloopApi :: PAMainloop a => a -> IO (PAMainloopApi a)
getMainloopApi api = do
io_enable <- mkIOEnable $ \ptr flags -> do
evt <- deRefStablePtr ptr
ioEnable (ioRealHandle evt) (ioEventsFromCInt flags)
io_new <- mkIONew $ \a fd flags fptr usr -> do
let fun = mkIOEvCB fptr
impl <- getMainloopImpl a
mvar <- newEmptyMVar
ret <- ioNew impl (Fd fd) (ioEventsFromCInt flags) $ \iflags -> do
evtp <- readMVar mvar
fun a evtp fd (ioEventsToCInt iflags) usr
rpt <- newStablePtr $ PAIOEventW ret usr a
putMVar mvar rpt
return rpt
io_free <- mkIOFree ((=<<) (ioFree . ioRealHandle) . deRefStablePtr)
io_set_destroy <- mkIOSetDestroy $ \ptr fptr -> do
let fun = mkIODestroy fptr
(PAIOEventW evt usr a) <- deRefStablePtr ptr
ioSetDestroy evt $ fun a ptr usr
time_new <- mkTimeNew $ \a timep fptr usr -> do
let fun = mkTimeEvCB fptr
impl <- getMainloopImpl a
mvar <- newEmptyMVar
time <- peek timep
ret <- timeNew impl (fromPAI time) $ \itime -> do
evt <- readMVar mvar
with (toPAI itime) $ flip (fun a evt) usr
rpt <- newStablePtr $ PATimeEventW ret usr a
putMVar mvar rpt
return rpt
time_restart <- mkTimeRestart $ \ptr timep -> do
time <- peek timep
flip timeRestart (fromPAI time) . timeRealHandle =<< deRefStablePtr ptr
time_free <- mkTimeFree ((=<<) (timeFree . timeRealHandle) . deRefStablePtr)
time_set_destroy <- mkTimeSetDestroy $ \ptr fptr -> do
let fun = mkTimeDestroy fptr
(PATimeEventW evt usr a) <- deRefStablePtr ptr
timeSetDestroy evt $ fun a ptr usr
defer_new <- mkDeferNew $ \a fptr usr -> do
let fun = mkDeferEvCB fptr
impl <- getMainloopImpl a
mvar <- newEmptyMVar
ret <- deferNew impl $ (flip (fun a) usr =<< readMVar mvar)
rpt <- newStablePtr $ PADeferEventW ret usr a
putMVar mvar rpt
return rpt
defer_enable <- mkDeferEnable $ \ptr switch -> do
flip deferEnable (switch /= 0) . deferRealHandle =<< deRefStablePtr ptr
defer_free <- mkDeferFree ((=<<) (deferFree . deferRealHandle) . deRefStablePtr)
defer_set_destroy <- mkDeferSetDestroy $ \ptr fptr -> do
let fun = mkDeferDestroy fptr
(PADeferEventW evt usr a) <- deRefStablePtr ptr
deferSetDestroy evt $ fun a ptr usr
quit <- mkQuit $ \ptr val -> do
impl <- getMainloopImpl ptr
quitLoop impl (fromIntegral val)
userdata <- newStablePtr api
return $ PAMainloopApi {..}