{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE JavaScriptFFI #-} {-# LANGUAGE InterruptibleFFI #-} {-# LANGUAGE DeriveDataTypeable #-} {- | Animation frames are the browser's mechanism for smooth animation. An animation frame callback is run just before the browser repaints. When the content window is inactive, for example when the user is looking at another tab, it can take a long time for an animation frame callback to happen. Be careful structuring evaluation around this! Typically this means carefully forcing the data before the animation frame is requested, so the callback can run quickly and predictably. -} module JavaScript.Web.AnimationFrame ( waitForAnimationFrame , inAnimationFrame , cancelAnimationFrame , AnimationFrameHandle ) where import GHCJS.Foreign.Callback import GHCJS.Marshal.Pure import GHCJS.Types import Control.Exception (onException) import Data.Typeable newtype AnimationFrameHandle = AnimationFrameHandle JSVal deriving (Typeable) {- | Wait for an animation frame callback to continue running the current thread. Use 'GHCJS.Concurrent.synchronously' if the thread should not be preempted. This will return the high-performance clock time stamp once an animation frame is reached. -} waitForAnimationFrame :: IO Double waitForAnimationFrame = do h <- js_makeAnimationFrameHandle js_waitForAnimationFrame h `onException` js_cancelAnimationFrame h {- | Run the action in an animationframe callback. The action runs in a synchronous thread, and is passed the high-performance clock time stamp for that frame. -} inAnimationFrame :: OnBlocked -- ^ what to do when encountering a blocking call -> (Double -> IO ()) -- ^ the action to run -> IO AnimationFrameHandle inAnimationFrame onBlocked x = do cb <- syncCallback1 onBlocked (x . pFromJSVal) h <- js_makeAnimationFrameHandleCallback (jsval cb) js_requestAnimationFrame h return h cancelAnimationFrame :: AnimationFrameHandle -> IO () cancelAnimationFrame h = js_cancelAnimationFrame h {-# INLINE cancelAnimationFrame #-} -- ----------------------------------------------------------------------------- foreign import javascript unsafe "{ handle: null, callback: null }" js_makeAnimationFrameHandle :: IO AnimationFrameHandle foreign import javascript unsafe "{ handle: null, callback: $1 }" js_makeAnimationFrameHandleCallback :: JSVal -> IO AnimationFrameHandle foreign import javascript unsafe "h$animationFrameCancel" js_cancelAnimationFrame :: AnimationFrameHandle -> IO () foreign import javascript interruptible "$1.handle = window.requestAnimationFrame($c);" js_waitForAnimationFrame :: AnimationFrameHandle -> IO Double foreign import javascript unsafe "h$animationFrameRequest" js_requestAnimationFrame :: AnimationFrameHandle -> IO ()