module Quasar.Wayland.Server.Registry ( Registry, Global, newRegistry, addRegistryConnection, createGlobal, maxVersion, ) where import Data.Foldable (toList) import Data.HashMap.Strict qualified as HM import Data.Sequence (Seq) import Data.Sequence qualified as Seq import Quasar.Prelude import Quasar.Wayland.Protocol import Quasar.Wayland.Protocol.Core import Quasar.Wayland.Protocol.Generated -- TODO: send registry messages -- TODO: remove RegistryConnection when registry protocol connection is destroyed data Registry = Registry { connections :: TVar [RegistryConnection], singletons :: Seq Global, globalsVar :: TVar (HM.HashMap Word32 Global) } newRegistry :: MonadIO m => [Global] -> m Registry newRegistry singletons = do connections <- newTVarIO mempty globalsVar <- newTVarIO mempty pure Registry { connections, singletons = Seq.fromList singletons, globalsVar } data RegistryConnection = RegistryConnection { registry :: Registry, wlRegistry :: Object 'Server Interface_wl_registry } createGlobal :: forall i. IsInterfaceSide 'Server i => Version -> (Object 'Server i -> STM ()) -> Global createGlobal supportedVersion bindFn = Global { interface = interfaceName @i, version = min supportedVersion (interfaceVersion @i), bindObject } where bindObject :: GenericNewId -> ProtocolM 'Server () bindObject newId = do object <- bindObjectFromId Nothing newId liftSTM $ bindFn object addRegistryConnection :: Registry -> Object 'Server Interface_wl_registry -> STM () addRegistryConnection registry wlRegistry = do setMessageHandler wlRegistry messageHandler modifyTVar registry.connections (connection:) forM_ (zip [0..] (toList registry.singletons)) (sendGlobal wlRegistry) where connection = RegistryConnection { registry, wlRegistry } messageHandler :: RequestHandler_wl_registry messageHandler = RequestHandler_wl_registry { bind = bindHandler registry (objectProtocol wlRegistry) } sendGlobal :: Object 'Server Interface_wl_registry -> (Word32, Global) -> STM () sendGlobal wlRegistry (name, global) = wlRegistry.global name global.interface global.version bindHandler :: Registry -> ProtocolHandle 'Server -> Word32 -> GenericNewId -> STM () bindHandler registry protocolHandle name newId = do case Seq.lookup (fromIntegral name) registry.singletons of Just global -> runProtocolM protocolHandle (global.bindObject newId) Nothing -> traceM $ "Invalid global " <> show name -- TODO dynamic globals data Global = Global { interface :: WlString, version :: Word32, bindObject :: GenericNewId -> ProtocolM 'Server () } maxVersion :: Version maxVersion = maxBound