ymonad-0.1.0.0: src/YMonad/Backend/River/Types.hs
{-# LANGUAGE OverloadedStrings #-}
module YMonad.Backend.River.Types (
RiverViewHandle (..),
RiverOutputHandle (..),
RiverSeatHandle (..),
RiverPhase (..),
RiverCallback (..),
RiverConnection (..),
RiverRuntime (..),
bindingActionForObject,
loadRiverRuntime,
emptyRiverRuntime,
allocateObjectId,
) where
import Data.ByteString qualified as BS
import Data.Map.Strict qualified as M
import Paths_ymonad (getDataFileName)
import YMonad.Config (YAction)
import YMonad.Core
import YMonad.Protocol.Wayland.Types
import YMonad.Protocol.Wayland.Xml
data RiverViewHandle = RiverViewHandle
{ riverWindowObjectId :: Word32
, riverNodeObjectId :: Maybe Word32
, riverViewTitle :: Text
, riverViewAppId :: Text
, riverViewDimensions :: Maybe Size
}
deriving stock (Eq, Ord, Show)
data RiverOutputHandle = RiverOutputHandle
{ riverOutputObjectId :: Word32
, riverOutputPosition :: Maybe Point
, riverOutputSize :: Maybe Size
}
deriving stock (Eq, Ord, Show)
newtype RiverSeatHandle = RiverSeatHandle
{ riverSeatObjectId :: Word32
}
deriving stock (Eq, Ord, Show)
data RiverPhase
= RiverPhaseIdle
| RiverPhaseManage
| RiverPhaseRender
deriving stock (Eq, Ord, Show)
data RiverCallback
= RiverViewCreated ViewId ViewMeta
| RiverViewDestroyed ViewId
| RiverOutputDiscovered OutputId OutputInfo
| RiverOutputLost OutputId
| RiverSeatFocus (Maybe ViewId)
| RiverManageStart
| RiverRenderStart
| RiverUserCommand UserCommand
| RiverActionTriggered YAction
| RiverProtocolFault Text
| RiverTrace Text
deriving stock (Eq, Ord, Show)
newtype RiverConnection = RiverConnection
{ riverSocketPath :: FilePath
}
deriving stock (Eq, Ord, Show)
data RiverRuntime = RiverRuntime
{ rrProtocol :: ProtocolSpec
, rrDisplayObject :: Word32
, rrRegistryObject :: Word32
, rrManagerObject :: Maybe Word32
, rrXkbBindingsObject :: Maybe Word32
, rrStartupSyncObject :: Maybe Word32
, rrRegistryReady :: Bool
, rrSeat :: Maybe RiverSeatHandle
, rrBindingActions :: Map Word32 YAction
, rrBindingsInstalled :: Bool
, rrViews :: Map ViewId RiverViewHandle
, rrViewsByObjectId :: Map Word32 ViewId
, rrOutputs :: Map OutputId RiverOutputHandle
, rrOutputsByObjectId :: Map Word32 OutputId
, rrObjectInterfaces :: Map Word32 Text
, rrPendingManage :: [WireMessage]
, rrPendingRender :: [WireMessage]
, rrOutgoing :: [WireMessage]
, rrInboundBuffer :: BS.ByteString
, rrNextObjectId :: Word32
, rrPhase :: RiverPhase
, rrManageDirtySent :: Bool
}
deriving stock (Eq, Show)
loadRiverRuntime :: IO (Either String RiverRuntime)
loadRiverRuntime = do
windowPath <- getDataFileName "protocol/river/river-window-management-v1.xml"
xkbPath <- getDataFileName "protocol/river/river-xkb-bindings-v1.xml"
windowSpecResult <- loadProtocolSpec windowPath
xkbSpecResult <- loadProtocolSpec xkbPath
pure $ do
windowSpec <- windowSpecResult
emptyRiverRuntime . mergeProtocolSpecs windowSpec <$> xkbSpecResult
emptyRiverRuntime :: ProtocolSpec -> RiverRuntime
emptyRiverRuntime riverSpec =
let base = baseProtocolSpec
merged = mergeProtocolSpecs base riverSpec
registryMessage = bootstrapGetRegistry
in RiverRuntime
{ rrProtocol = merged
, rrDisplayObject = 1
, rrRegistryObject = 2
, rrManagerObject = Nothing
, rrXkbBindingsObject = Nothing
, rrStartupSyncObject = Just 3
, rrRegistryReady = False
, rrSeat = Nothing
, rrBindingActions = M.empty
, rrBindingsInstalled = False
, rrViews = M.empty
, rrViewsByObjectId = M.empty
, rrOutputs = M.empty
, rrOutputsByObjectId = M.empty
, rrObjectInterfaces = M.fromList [(1, "wl_display"), (2, "wl_registry"), (3, "wl_callback")]
, rrPendingManage = []
, rrPendingRender = []
, rrOutgoing = [registryMessage, bootstrapSync 3]
, rrInboundBuffer = BS.empty
, rrNextObjectId = 4
, rrPhase = RiverPhaseIdle
, rrManageDirtySent = False
}
allocateObjectId :: RiverRuntime -> (Word32, RiverRuntime)
allocateObjectId rt = (rrNextObjectId rt, rt {rrNextObjectId = rrNextObjectId rt + 1})
baseProtocolSpec :: ProtocolSpec
baseProtocolSpec =
ProtocolSpec
{ protocolName = "wayland-core"
, protocolInterfaces =
M.fromList
[ (interfaceName wlDisplay, wlDisplay)
, (interfaceName wlRegistry, wlRegistry)
, (interfaceName wlCallback, wlCallback)
]
}
where
wlDisplay =
mkInterfaceSpec
"wl_display"
1
[ MessageSpec "sync" 0 MessageRequest [ArgSpec "callback" (ArgNewId (Just "wl_callback")) False]
, MessageSpec "get_registry" 1 MessageRequest [ArgSpec "registry" (ArgNewId (Just "wl_registry")) False]
]
[ MessageSpec
"error"
0
MessageEvent
[ ArgSpec "object_id" (ArgObject Nothing) False
, ArgSpec "code" ArgUint False
, ArgSpec "message" ArgString False
]
, MessageSpec "delete_id" 1 MessageEvent [ArgSpec "id" ArgUint False]
]
wlRegistry =
mkInterfaceSpec
"wl_registry"
1
[ MessageSpec
"bind"
0
MessageRequest
[ ArgSpec "name" ArgUint False
, ArgSpec "interface" ArgString False
, ArgSpec "version" ArgUint False
, ArgSpec "id" (ArgNewId Nothing) False
]
]
[ MessageSpec
"global"
0
MessageEvent
[ ArgSpec "name" ArgUint False
, ArgSpec "interface" ArgString False
, ArgSpec "version" ArgUint False
]
, MessageSpec "global_remove" 1 MessageEvent [ArgSpec "name" ArgUint False]
]
wlCallback =
mkInterfaceSpec
"wl_callback"
1
[]
[ MessageSpec "done" 0 MessageEvent [ArgSpec "callback_data" ArgUint False]
]
bootstrapGetRegistry :: WireMessage
bootstrapGetRegistry =
WireMessage
{ wireObjectId = 1
, wireInterface = "wl_display"
, wireMessageName = "get_registry"
, wireOpcode = 1
, wireArgs = [ArgNewIdValue 2]
}
bootstrapSync :: Word32 -> WireMessage
bootstrapSync callbackId =
WireMessage
{ wireObjectId = 1
, wireInterface = "wl_display"
, wireMessageName = "sync"
, wireOpcode = 0
, wireArgs = [ArgNewIdValue callbackId]
}
bindingActionForObject :: RiverRuntime -> Word32 -> Maybe YAction
bindingActionForObject rt objectId = M.lookup objectId (rrBindingActions rt)