From c1b6b413e564bdb09bbc1924631d03f625edc5b9 Mon Sep 17 00:00:00 2001 From: Jens Nolte <git@queezle.net> Date: Sat, 6 Aug 2022 11:46:02 +0200 Subject: [PATCH] Implement server registry --- src/Quasar/Wayland/Protocol/Core.hs | 20 +++++++++-- src/Quasar/Wayland/Server/Registry.hs | 49 +++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/Quasar/Wayland/Protocol/Core.hs b/src/Quasar/Wayland/Protocol/Core.hs index c4644a1..568d4f8 100644 --- a/src/Quasar/Wayland/Protocol/Core.hs +++ b/src/Quasar/Wayland/Protocol/Core.hs @@ -47,6 +47,7 @@ module Quasar.Wayland.Protocol.Core ( newObject, newObjectFromId, bindNewObject, + bindObjectFromId, getObject, getNullableObject, lookupObject, @@ -641,9 +642,22 @@ bindNewObject -> Version -> Maybe (MessageHandler 'Client i) -> STM (Object 'Client i, GenericNewId) -bindNewObject protocol version messageHandler = runProtocolM protocol do - (object, NewId (ObjectId newId)) <- newObject messageHandler - pure (object, GenericNewId (interfaceName @i) version newId) +bindNewObject protocol version messageHandler = + runProtocolM protocol do + (object, NewId (ObjectId newId)) <- newObject messageHandler + pure (object, GenericNewId (interfaceName @i) version newId) + +-- | Create an object from a received id. +-- object). +-- +-- For implementing wl_registry.bind (which is low-level protocol functionality, but which depends on generated code). +bindObjectFromId + :: forall i. IsInterfaceSide 'Server i + => Maybe (MessageHandler 'Server i) + -> GenericNewId + -> ProtocolM 'Server (Object 'Server i) +bindObjectFromId messageHandler (GenericNewId interface version value) = + newObjectFromId messageHandler (NewId (ObjectId value)) fromSomeObject diff --git a/src/Quasar/Wayland/Server/Registry.hs b/src/Quasar/Wayland/Server/Registry.hs index b18eefe..0e57f96 100644 --- a/src/Quasar/Wayland/Server/Registry.hs +++ b/src/Quasar/Wayland/Server/Registry.hs @@ -1,46 +1,81 @@ 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 connection when registry is destroyed +-- 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 => m Registry -newRegistry = do +newRegistry :: MonadIO m => [Global] -> m Registry +newRegistry singletons = do connections <- newTVarIO mempty globalsVar <- newTVarIO mempty - pure Registry { connections, globalsVar } + 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 = \name id -> traceM "wl_registry.bind not implemented" + 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 { - name :: Word32, interface :: WlString, - version :: Word32 + version :: Word32, + bindObject :: GenericNewId -> ProtocolM 'Server () } + +maxVersion :: Version +maxVersion = maxBound -- GitLab