module Desktop.Portal.Camera
  ( accessCamera,
    openPipeWireRemote,
    isCameraPresent,
  )
where

import Control.Exception (throwIO)
import DBus (InterfaceName, Variant, fromVariant, toVariant)
import DBus.Client qualified as DBus
import Data.Map (Map)
import Data.Text (Text)
import Desktop.Portal.Internal (Client, Request, callMethod, getPropertyValue, sendRequest)
import System.Posix (Fd)

cameraInterface :: InterfaceName
cameraInterface :: InterfaceName
cameraInterface = InterfaceName
"org.freedesktop.portal.Camera"

-- | Requests access to the camera.
--
-- If access is granted, then request will return '()', otherwise it will be cancelled.
accessCamera :: Client -> IO (Request ())
accessCamera :: Client -> IO (Request ())
accessCamera Client
client = do
  Client
-> InterfaceName
-> MemberName
-> [Variant]
-> Map Text Variant
-> (Map Text Variant -> IO ())
-> IO (Request ())
forall a.
Client
-> InterfaceName
-> MemberName
-> [Variant]
-> Map Text Variant
-> (Map Text Variant -> IO a)
-> IO (Request a)
sendRequest Client
client InterfaceName
cameraInterface MemberName
"AccessCamera" [] Map Text Variant
forall a. Monoid a => a
mempty (IO () -> Map Text Variant -> IO ()
forall a b. a -> b -> a
const (() -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()))

openPipeWireRemote :: Client -> IO Fd
openPipeWireRemote :: Client -> IO Fd
openPipeWireRemote Client
client = do
  [Variant]
res <- Client -> InterfaceName -> MemberName -> [Variant] -> IO [Variant]
callMethod Client
client InterfaceName
cameraInterface MemberName
"OpenPipeWireRemote" [Map Text Variant -> Variant
forall a. IsVariant a => a -> Variant
toVariant (Map Text Variant
forall a. Monoid a => a
mempty :: Map Text Variant)]
  case [Variant]
res of
    [Variant -> Maybe Fd
forall a. IsVariant a => Variant -> Maybe a
fromVariant -> Just Fd
fd] ->
      Fd -> IO Fd
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Fd
fd
    [Variant]
_ ->
      ClientError -> IO Fd
forall e a. Exception e => e -> IO a
throwIO (ClientError -> IO Fd)
-> (String -> ClientError) -> String -> IO Fd
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ClientError
DBus.clientError (String -> IO Fd) -> String -> IO Fd
forall a b. (a -> b) -> a -> b
$ String
"openPipeWireRemote: could not parse response: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [Variant] -> String
forall a. Show a => a -> String
show [Variant]
res

isCameraPresent :: Client -> IO Bool
isCameraPresent :: Client -> IO Bool
isCameraPresent Client
client = do
  Client -> InterfaceName -> MemberName -> IO Bool
forall a.
IsValue a =>
Client -> InterfaceName -> MemberName -> IO a
getPropertyValue Client
client InterfaceName
cameraInterface MemberName
"IsCameraPresent"