musicScroll-0.2.0.0: src/MusicScroll/DBusSignals.hs
{-# language OverloadedStrings #-}
module MusicScroll.DBusSignals
( mediaPropChangeRule
, waitForChange
, changeMusicClient
) where
import Control.Concurrent.STM (atomically)
import Control.Concurrent.STM.TMVar (TMVar, takeTMVar, newEmptyTMVar, putTMVar)
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Trans.State (StateT, gets, modify)
import Data.Foldable (find)
import Data.Maybe (fromJust)
import DBus.Client
import DBus
import MusicScroll.DBusNames
import MusicScroll.ConnState
mediaPropChangeRule, busNameAddedRule :: MatchRule
mediaPropChangeRule = matchAny
{ matchPath = pure mediaObject
, matchInterface = pure "org.freedesktop.DBus.Properties"
, matchMember = pure "PropertiesChanged" }
busNameAddedRule = matchAny
{ matchSender = pure dbusBus -- unique name
, matchPath = pure "/org/freedesktop/DBus"
, matchInterface = pure "org.freedesktop.DBus"
, matchMember = pure "NameOwnerChanged" }
waitForChange :: MatchRule -> StateT ConnState IO ()
waitForChange rule =
do client <- gets cClient
liftIO $ do
trigger <- atomically newEmptyTMVar
disarmHandler <- armSignal client trigger rule
_ <- atomically $ takeTMVar trigger
removeMatch client disarmHandler
armSignal :: Client -> TMVar () -> MatchRule -> IO SignalHandler
armSignal client trigger rule =
addMatch client rule (\_ -> atomically ( putTMVar trigger () ))
changeMusicClient :: StateT ConnState IO ()
changeMusicClient =
do client <- gets cClient
availableStatus <- liftIO $ traverse (checkName client) allBuses
let taggedBuses = zip allBuses availableStatus
case fst <$> find snd taggedBuses of
Just newBus -> modify (setBus newBus)
Nothing -> do waitForChange busNameAddedRule
changeMusicClient
checkName :: Client -> BusName -> IO Bool
checkName client name = do
returnCall <- call_ client
(methodCall "/org/freedesktop/DBus" "org.freedesktop.DBus" "NameHasOwner")
{ methodCallDestination = Just dbusBus
, methodCallBody = [toVariant name] }
-- We assume this call is correct, as it's done to the master dbus
-- object. So fromJust/head are safe.
return . fromJust . fromVariant . head . methodReturnBody $ returnCall