{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Miso.Native.MainThread
(
setStyleProperty
, setStyleProperties
, setStylePropertyTransform
, setAttribute
, getAttribute
, flushElementTree
, firstElementChild
, nextElementSibling
, parentElement
, eachFrame
, SystemInfo(..)
, getSystemInfo
, MainThreadRef
, mainThreadRef
, readMainThreadRef
, writeMainThreadRef
, modifyMainThreadRef
, modifyMainThreadRef_
) where
import Control.Monad (void, forM_)
import Control.Monad.State (State, execState)
import Data.IORef (IORef, newIORef, readIORef, writeIORef, modifyIORef')
import System.IO.Unsafe (unsafePerformIO)
import Miso.CSS (transforms, TransformFn)
import Miso.DSL
( jsg, jsg0, jsg1, jsg2, jsg3, (!), isUndefined, FromJSVal(..)
, requestAnimationFrame, syncCallback1, freeFunction, Function(..), jsNull )
import GHC.Generics (Generic)
import Miso.Effect (DOMRef)
import Miso.JSON (ToJSON(..), FromJSON(..), Value(Null))
import Miso.String (MisoString)
instance ToJSON DOMRef where
toJSON :: JSVal -> Value
toJSON JSVal
_ = Value
Null
instance FromJSON DOMRef where
parseJSON :: Value -> Parser JSVal
parseJSON Value
_ = String -> Parser JSVal
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"DOMRef: main-thread-only, never deserialized"
setStyleProperty :: DOMRef -> MisoString -> MisoString -> IO ()
setStyleProperty :: JSVal -> MisoString -> MisoString -> IO ()
setStyleProperty JSVal
node MisoString
name MisoString
value = do
IO JSVal -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MisoString -> JSVal -> MisoString -> MisoString -> IO JSVal
forall arg1 arg2 arg3.
(ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) =>
MisoString -> arg1 -> arg2 -> arg3 -> IO JSVal
jsg3 MisoString
"__AddInlineStyle" JSVal
node MisoString
name MisoString
value)
IO ()
flushElementTree
setStyleProperties :: DOMRef -> [(MisoString, MisoString)] -> IO ()
setStyleProperties :: JSVal -> [(MisoString, MisoString)] -> IO ()
setStyleProperties JSVal
node [(MisoString, MisoString)]
styles = do
[(MisoString, MisoString)]
-> ((MisoString, MisoString) -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(MisoString, MisoString)]
styles (((MisoString, MisoString) -> IO ()) -> IO ())
-> ((MisoString, MisoString) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(MisoString
name, MisoString
value) ->
IO JSVal -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MisoString -> JSVal -> MisoString -> MisoString -> IO JSVal
forall arg1 arg2 arg3.
(ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) =>
MisoString -> arg1 -> arg2 -> arg3 -> IO JSVal
jsg3 MisoString
"__AddInlineStyle" JSVal
node MisoString
name MisoString
value)
IO ()
flushElementTree
setStylePropertyTransform :: DOMRef -> [TransformFn] -> IO ()
setStylePropertyTransform :: JSVal -> [TransformFn] -> IO ()
setStylePropertyTransform JSVal
node [TransformFn]
fns = JSVal -> [(MisoString, MisoString)] -> IO ()
setStyleProperties JSVal
node [ [TransformFn] -> (MisoString, MisoString)
transforms [TransformFn]
fns ]
setAttribute :: DOMRef -> MisoString -> MisoString -> IO ()
setAttribute :: JSVal -> MisoString -> MisoString -> IO ()
setAttribute JSVal
node MisoString
key MisoString
value = do
IO JSVal -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MisoString -> JSVal -> MisoString -> MisoString -> IO JSVal
forall arg1 arg2 arg3.
(ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) =>
MisoString -> arg1 -> arg2 -> arg3 -> IO JSVal
jsg3 MisoString
"__SetAttribute" JSVal
node MisoString
key MisoString
value)
IO ()
flushElementTree
getAttribute :: DOMRef -> MisoString -> IO MisoString
getAttribute :: JSVal -> MisoString -> IO MisoString
getAttribute JSVal
node MisoString
key =
JSVal -> IO MisoString
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked (JSVal -> IO MisoString) -> IO JSVal -> IO MisoString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< MisoString -> JSVal -> MisoString -> IO JSVal
forall arg1 arg2.
(ToJSVal arg1, ToJSVal arg2) =>
MisoString -> arg1 -> arg2 -> IO JSVal
jsg2 MisoString
"__GetAttributeByName" JSVal
node MisoString
key
flushElementTree :: IO ()
flushElementTree :: IO ()
flushElementTree = IO JSVal -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (MisoString -> IO JSVal
jsg0 MisoString
"__FlushElementTree")
firstElementChild :: DOMRef -> IO DOMRef
firstElementChild :: JSVal -> IO JSVal
firstElementChild = MisoString -> JSVal -> IO JSVal
forall arg. ToJSVal arg => MisoString -> arg -> IO JSVal
jsg1 MisoString
"__FirstElement"
nextElementSibling :: DOMRef -> IO DOMRef
nextElementSibling :: JSVal -> IO JSVal
nextElementSibling = MisoString -> JSVal -> IO JSVal
forall arg. ToJSVal arg => MisoString -> arg -> IO JSVal
jsg1 MisoString
"__NextElement"
parentElement :: DOMRef -> IO DOMRef
parentElement :: JSVal -> IO JSVal
parentElement = MisoString -> JSVal -> IO JSVal
forall arg. ToJSVal arg => MisoString -> arg -> IO JSVal
jsg1 MisoString
"__GetParent"
eachFrame :: (Double -> IO Bool) -> IO ()
eachFrame :: (Double -> IO Bool) -> IO ()
eachFrame Double -> IO Bool
step = do
cbRef <- JSVal -> IO (IORef JSVal)
forall a. a -> IO (IORef a)
newIORef JSVal
jsNull
let frame JSVal
tsVal = do
keep <- Double -> IO Bool
step (Double -> IO Bool) -> IO Double -> IO Bool
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< JSVal -> IO Double
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked JSVal
tsVal
cb <- readIORef cbRef
if keep
then void (requestAnimationFrame cb)
else freeFunction (Function cb)
cb <- syncCallback1 frame
writeIORef cbRef cb
void (requestAnimationFrame cb)
data SystemInfo = SystemInfo
{ SystemInfo -> Double
pixelWidth :: Double
, SystemInfo -> Double
pixelHeight :: Double
, SystemInfo -> Double
pixelRatio :: Double
, SystemInfo -> MisoString
osVersion :: MisoString
, SystemInfo -> MisoString
platform :: MisoString
, SystemInfo -> Maybe MisoString
lynxSdkVersion :: Maybe MisoString
, SystemInfo -> Maybe MisoString
engineVersion :: Maybe MisoString
, SystemInfo -> Maybe MisoString
runtimeType :: Maybe MisoString
, SystemInfo -> Maybe Value
theme :: Maybe Value
} deriving (Int -> SystemInfo -> ShowS
[SystemInfo] -> ShowS
SystemInfo -> String
(Int -> SystemInfo -> ShowS)
-> (SystemInfo -> String)
-> ([SystemInfo] -> ShowS)
-> Show SystemInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SystemInfo -> ShowS
showsPrec :: Int -> SystemInfo -> ShowS
$cshow :: SystemInfo -> String
show :: SystemInfo -> String
$cshowList :: [SystemInfo] -> ShowS
showList :: [SystemInfo] -> ShowS
Show, SystemInfo -> SystemInfo -> Bool
(SystemInfo -> SystemInfo -> Bool)
-> (SystemInfo -> SystemInfo -> Bool) -> Eq SystemInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SystemInfo -> SystemInfo -> Bool
== :: SystemInfo -> SystemInfo -> Bool
$c/= :: SystemInfo -> SystemInfo -> Bool
/= :: SystemInfo -> SystemInfo -> Bool
Eq, (forall x. SystemInfo -> Rep SystemInfo x)
-> (forall x. Rep SystemInfo x -> SystemInfo) -> Generic SystemInfo
forall x. Rep SystemInfo x -> SystemInfo
forall x. SystemInfo -> Rep SystemInfo x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. SystemInfo -> Rep SystemInfo x
from :: forall x. SystemInfo -> Rep SystemInfo x
$cto :: forall x. Rep SystemInfo x -> SystemInfo
to :: forall x. Rep SystemInfo x -> SystemInfo
Generic)
instance FromJSVal SystemInfo
getSystemInfo :: IO (Maybe SystemInfo)
getSystemInfo :: IO (Maybe SystemInfo)
getSystemInfo = do
si <- MisoString -> IO JSVal
jsg MisoString
"lynx" IO JSVal -> (JSVal -> IO JSVal) -> IO JSVal
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (JSVal -> MisoString -> IO JSVal
forall o. ToObject o => o -> MisoString -> IO JSVal
! MisoString
"SystemInfo")
u <- isUndefined si
if u then pure Nothing else fromJSVal si
newtype MainThreadRef a = MainThreadRef (IORef a)
mainThreadRef :: a -> MainThreadRef a
mainThreadRef :: forall a. a -> MainThreadRef a
mainThreadRef a
x = IORef a -> MainThreadRef a
forall a. IORef a -> MainThreadRef a
MainThreadRef (IO (IORef a) -> IORef a
forall a. IO a -> a
unsafePerformIO (a -> IO (IORef a)
forall a. a -> IO (IORef a)
newIORef a
x))
{-# NOINLINE mainThreadRef #-}
readMainThreadRef :: MainThreadRef a -> IO a
readMainThreadRef :: forall a. MainThreadRef a -> IO a
readMainThreadRef (MainThreadRef IORef a
ref) = IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
ref
writeMainThreadRef :: MainThreadRef a -> a -> IO ()
writeMainThreadRef :: forall a. MainThreadRef a -> a -> IO ()
writeMainThreadRef (MainThreadRef IORef a
ref) = IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef a
ref
modifyMainThreadRef :: MainThreadRef a -> (a -> a) -> IO ()
modifyMainThreadRef :: forall a. MainThreadRef a -> (a -> a) -> IO ()
modifyMainThreadRef (MainThreadRef IORef a
ref) = IORef a -> (a -> a) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef a
ref
modifyMainThreadRef_ :: MainThreadRef a -> State a () -> IO ()
modifyMainThreadRef_ :: forall a. MainThreadRef a -> State a () -> IO ()
modifyMainThreadRef_ MainThreadRef a
ref State a ()
go = MainThreadRef a -> (a -> a) -> IO ()
forall a. MainThreadRef a -> (a -> a) -> IO ()
modifyMainThreadRef MainThreadRef a
ref (State a () -> a -> a
forall s a. State s a -> s -> s
execState State a ()
go)