From 169767197b7e8c5c865e0486909e83f65974aa51 Mon Sep 17 00:00:00 2001
From: Jens Nolte <git@queezle.net>
Date: Mon, 13 Dec 2021 22:39:29 +0100
Subject: [PATCH] Simplify message handling, remove (now) unused exports

---
 src/Quasar/Wayland/Display.hs       |  4 +---
 src/Quasar/Wayland/Protocol.hs      |  6 +++---
 src/Quasar/Wayland/Protocol/Core.hs | 23 +++++++++++++----------
 src/Quasar/Wayland/Protocol/TH.hs   | 20 ++++++++++----------
 4 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/src/Quasar/Wayland/Display.hs b/src/Quasar/Wayland/Display.hs
index 3d84912..c42353e 100644
--- a/src/Quasar/Wayland/Display.hs
+++ b/src/Quasar/Wayland/Display.hs
@@ -15,9 +15,7 @@ data ClientDisplay = ClientDisplay {
   registry :: ClientRegistry
 }
 
-newClientDisplay
-  :: (IsInterfaceSide 'Client Interface_wl_display)
-  => STM (ClientDisplay, ProtocolHandle 'Client)
+newClientDisplay :: STM (ClientDisplay, ProtocolHandle 'Client)
 newClientDisplay =
   initializeProtocol wlDisplayEventHandler \wlDisplay -> do
     registry <- createClientRegistry wlDisplay
diff --git a/src/Quasar/Wayland/Protocol.hs b/src/Quasar/Wayland/Protocol.hs
index 94d7612..6cbd1ad 100644
--- a/src/Quasar/Wayland/Protocol.hs
+++ b/src/Quasar/Wayland/Protocol.hs
@@ -3,6 +3,8 @@ module Quasar.Wayland.Protocol (
   -- | This module exports everything required to implement Wayland interfaces generated by
   -- "Quasar.Wayland.Protocol.TH".
 
+  Object,
+
   -- ** Wire types
   ObjectId,
   GenericObjectId,
@@ -14,8 +16,7 @@ module Quasar.Wayland.Protocol (
   IsInterface(InterfaceName),
   interfaceName,
   Side(..),
-  IsSide(WireUp, WireDown),
-  IsInterfaceSide,
+  IsSide,
 
   -- ** Protocol execution
   ProtocolHandle,
@@ -28,7 +29,6 @@ module Quasar.Wayland.Protocol (
   ProtocolM,
   runProtocolTransaction,
   runProtocolM,
-  Object,
   newObject,
   sendMessage,
 
diff --git a/src/Quasar/Wayland/Protocol/Core.hs b/src/Quasar/Wayland/Protocol/Core.hs
index 754cc1f..fa77c9e 100644
--- a/src/Quasar/Wayland/Protocol/Core.hs
+++ b/src/Quasar/Wayland/Protocol/Core.hs
@@ -16,7 +16,7 @@ module Quasar.Wayland.Protocol.Core (
   interfaceName,
   IsInterfaceSide(..),
   IsInterfaceHandler(..),
-  Object(messageHandler),
+  Object,
   IsObject,
   IsMessage(..),
   ProtocolHandle,
@@ -29,10 +29,10 @@ module Quasar.Wayland.Protocol.Core (
   takeOutbox,
   runProtocolTransaction,
   runProtocolM,
+  enterObject,
 
   -- * Low-level protocol interaction
   sendMessage,
-  objectSendMessage,
   newObject,
   newObjectFromId,
 
@@ -223,7 +223,7 @@ class (
     IsMessage (WireDown s i)
   )
   => IsInterfaceSide (s :: Side) i where
-  objectHandleMessage :: Object s i -> WireDown s i -> STM ()
+  handleMessage :: MessageHandler s i -> WireDown s i -> ProtocolM s ()
 
 
 getWireDown :: forall s i. IsInterfaceSide s i => Object s i -> Opcode -> Get (ProtocolM s (WireDown s i))
@@ -244,7 +244,7 @@ data Side = Client | Server
 data Object s i = IsInterfaceSide s i => Object {
   objectProtocol :: (ProtocolHandle s),
   objectObjectId :: GenericObjectId,
-  messageHandler :: (MessageHandler s i)
+  messageHandler :: TMVar (MessageHandler s i)
 }
 
 instance IsInterface i => Show (Object s i) where
@@ -423,7 +423,8 @@ initializeProtocol wlDisplayMessageHandler initializationAction = do
   }
   writeTVar stateVar (Right state)
 
-  let wlDisplay = Object protocol wlDisplayId wlDisplayMessageHandler
+  messageHandlerVar <- newTMVar wlDisplayMessageHandler
+  let wlDisplay = Object protocol wlDisplayId messageHandlerVar
   modifyTVar' objectsVar (HM.insert wlDisplayId (SomeObject wlDisplay))
 
   result <- runReaderT (initializationAction wlDisplay) state
@@ -522,9 +523,10 @@ newObjectFromId
   -> ProtocolM s (Object s i)
 newObjectFromId (NewId oId) messageHandler = do
   protocol <- askProtocol
+  messageHandlerVar <- lift $ newTMVar messageHandler
   let
     genericObjectId = toGenericObjectId oId
-    object = Object protocol genericObjectId messageHandler
+    object = Object protocol genericObjectId messageHandlerVar
     someObject = SomeObject object
   modifyProtocolVar (.objectsVar) (HM.insert genericObjectId someObject)
   pure object
@@ -554,8 +556,8 @@ sendMessage object message = do
       putWord32host objectIdWord
       putWord32host $ (fromIntegral msgSize `shiftL` 16) .|. fromIntegral opcode
 
-objectSendMessage :: forall s i. IsInterfaceSide s i => Object s i -> WireUp s i -> STM ()
-objectSendMessage object message = runProtocolM object.objectProtocol $ sendMessage object message
+enterObject :: forall s i a. Object s i -> ProtocolM s a -> STM a
+enterObject object action = runProtocolM object.objectProtocol action
 
 
 receiveMessages :: IsSide s => ProtocolM s ()
@@ -583,7 +585,7 @@ handleRawMessage (oId, opcode, body) = do
       throwM $ ProtocolException $ "Received message for object without handler: " <> interface <> "@" <> show oId
   where
     getMessageAction
-      :: IsInterfaceSide s i
+      :: forall s i. IsInterfaceSide s i
       => Object s i
       -> Opcode
       -> Get (ProtocolM s ())
@@ -592,7 +594,8 @@ handleRawMessage (oId, opcode, body) = do
       pure do
         message <- verifyMessage
         traceM $ "<- " <> showObjectMessage object message
-        lift $ objectHandleMessage object message
+        messageHandler <- lift $ readTMVar object.messageHandler
+        handleMessage @s @i messageHandler message
 
 type RawMessage = (GenericObjectId, Opcode, BSL.ByteString)
 
diff --git a/src/Quasar/Wayland/Protocol/TH.hs b/src/Quasar/Wayland/Protocol/TH.hs
index e178f56..362ee86 100644
--- a/src/Quasar/Wayland/Protocol/TH.hs
+++ b/src/Quasar/Wayland/Protocol/TH.hs
@@ -190,9 +190,9 @@ interfaceDecs interface = do
     eventProxyInstanceDecs :: Q [Dec]
     eventProxyInstanceDecs = messageProxyInstanceDecs [t|'Server|] wireEventContexts
 
-    objectName = mkName "object"
-    objectP = varP objectName
-    objectE = varE objectName
+    handlerName = mkName "handler"
+    handlerP = varP handlerName
+    handlerE = varE handlerName
 
     interfaceSideInstanceDs :: Q [Dec]
     interfaceSideInstanceDs = execWriterT do
@@ -200,29 +200,29 @@ interfaceDecs interface = do
       tellQ $ instanceD (pure []) ([t|IsInterfaceSide 'Server $iT|]) [handleMessageD Server]
 
     handleMessageD :: Side -> Q Dec
-    handleMessageD Client = funD 'objectHandleMessage (handleMessageClauses wireEventContexts)
-    handleMessageD Server = funD 'objectHandleMessage (handleMessageClauses wireRequestContexts)
+    handleMessageD Client = funD 'handleMessage (handleMessageClauses wireEventContexts)
+    handleMessageD Server = funD 'handleMessage (handleMessageClauses wireRequestContexts)
 
     handleMessageClauses :: [MessageContext] -> [Q Clause]
     handleMessageClauses [] = [clause [wildP] (normalB [|absurd|]) []]
     handleMessageClauses messageContexts = handleMessageClause <$> messageContexts
 
     handleMessageClause :: MessageContext -> Q Clause
-    handleMessageClause msg = clause [objectP, msgConP msg] (normalB bodyE) []
+    handleMessageClause msg = clause [handlerP, msgConP msg] (normalB bodyE) []
       where
         fieldNameLitT :: Q Type
         fieldNameLitT = litT (strTyLit (messageFieldNameString msg))
-        fieldE :: Q Exp
-        fieldE = [|$(appTypeE [|getField|] fieldNameLitT) $objectE.messageHandler|]
+        msgHandlerE :: Q Exp
+        msgHandlerE = [|$(appTypeE [|getField|] fieldNameLitT) $handlerE|]
         bodyE :: Q Exp
-        bodyE = applyMsgArgs msg fieldE
+        bodyE = [|lift $(applyMsgArgs msg msgHandlerE)|]
 
 messageProxyInstanceDecs :: Q Type -> [MessageContext] -> Q [Dec]
 messageProxyInstanceDecs sideT messageContexts = mapM messageProxyInstanceD messageContexts
   where
     messageProxyInstanceD :: MessageContext -> Q Dec
     messageProxyInstanceD msg = instanceD (pure []) instanceT [
-      funD 'getField [clause ([varP objectName] <> msgArgPats msg) (normalB [|objectSendMessage object $(msgE msg)|]) []]
+      funD 'getField [clause ([varP objectName] <> msgArgPats msg) (normalB [|enterObject object (sendMessage object $(msgE msg))|]) []]
       ]
       where
         objectName = mkName "object"
-- 
GitLab