From 6a60ce384b49bb8900b32f533300ad0a08a0fc01 Mon Sep 17 00:00:00 2001 From: Jens Nolte <git@queezle.net> Date: Sun, 5 Sep 2021 21:40:09 +0200 Subject: [PATCH] Connect to wayland socket --- quasar-wayland.cabal | 4 ++- src/Quasar/Wayland/Client.hs | 70 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/Quasar/Wayland/Client.hs diff --git a/quasar-wayland.cabal b/quasar-wayland.cabal index 59a9904..61b0156 100644 --- a/quasar-wayland.cabal +++ b/quasar-wayland.cabal @@ -83,6 +83,7 @@ common shared-executable-properties library import: shared-properties exposed-modules: + Quasar.Wayland.Client Quasar.Wayland.Protocol Quasar.Wayland.TH build-depends: @@ -90,8 +91,9 @@ library --binary, bytestring, exceptions, + filepath, --mtl, - --network, + network, quasar, template-haskell, --unix, diff --git a/src/Quasar/Wayland/Client.hs b/src/Quasar/Wayland/Client.hs new file mode 100644 index 0000000..762732b --- /dev/null +++ b/src/Quasar/Wayland/Client.hs @@ -0,0 +1,70 @@ +module Quasar.Wayland.Client ( + connectWaylandClient, + newWaylandClient, +) where + +import Control.Monad.Catch +import Network.Socket qualified as Socket +import Network.Socket (Socket) +import Quasar.Disposable +import Quasar.Prelude +import Quasar.ResourceManager +import System.Environment (getEnv, lookupEnv) +import System.FilePath ((</>), isRelative) +import Text.Read (readEither) + +data WaylandClient = WaylandClient { + socket :: Socket, + resourceManager :: ResourceManager +} + +instance IsResourceManager WaylandClient where + toResourceManager client = client.resourceManager + +instance IsDisposable WaylandClient where + toDisposable client = toDisposable client.resourceManager + +newWaylandClient :: MonadResourceManager m => Socket -> m WaylandClient +newWaylandClient socket = do + resourceManager <- newResourceManager + onResourceManager resourceManager do + registerDisposeAction (pure () <$ Socket.close socket) + pure WaylandClient { + socket, + resourceManager + } + +connectWaylandClient :: MonadResourceManager m => m WaylandClient +connectWaylandClient = mask_ do + socket <- liftIO connectWaylandSocket + newWaylandClient socket + where + connectWaylandSocket :: IO Socket + connectWaylandSocket = do + lookupEnv "WAYLAND_SOCKET" >>= \case + -- Parent process already established connection + Just waylandSocketEnv -> do + case readEither waylandSocketEnv of + Left err -> fail $ "Failed to parse WAYLAND_SOCKET: " <> err + Right fd -> Socket.mkSocket fd + Nothing -> do + path <- getWaylandSocketPath + newUnixSocket path + + getWaylandSocketPath :: IO FilePath + getWaylandSocketPath = do + waylandDisplayEnv <- lookupEnv "WAYLAND_DISPLAY" + let waylandDisplay = fromMaybe "wayland-0" waylandDisplayEnv + if isRelative waylandDisplay + then do + xdgRuntimeDir <- getEnv "XDG_RUNTIME_DIR" + pure (xdgRuntimeDir </> waylandDisplay) + else + pure waylandDisplay + + newUnixSocket :: FilePath -> IO Socket + newUnixSocket socketPath = + bracketOnError (Socket.socket Socket.AF_UNIX Socket.Stream Socket.defaultProtocol) Socket.close $ \sock -> do + Socket.withFdSocket sock Socket.setCloseOnExecIfNeeded + Socket.connect sock $ Socket.SockAddrUnix socketPath + pure sock -- GitLab