{-# LANGUAGE OverloadedStrings #-} -------------------------------------------------------------------------------- -- DBus module for DBus brightness controls module XMonad.Internal.DBus.Brightness.Common ( BrightnessConfig (..) , BrightnessControls (..) , brightnessControls , brightnessExporter , callGetBrightness , matchSignal , signalDep ) where import DBus import DBus.Client import qualified DBus.Introspection as I import Data.Internal.DBus import Data.Internal.XIO import RIO import qualified RIO.Text as T import XMonad.Core (io) import XMonad.Internal.DBus.Common -------------------------------------------------------------------------------- -- External API -- -- Define four methods to increase, decrease, maximize, or minimize the -- brightness. These methods will all return the current brightness as a 32-bit -- integer and emit a signal with the same brightness value. Additionally, there -- is one method to get the current brightness. data BrightnessConfig a b = BrightnessConfig { bcMin :: (a, a) -> IO b , bcMax :: (a, a) -> IO b , bcDec :: (a, a) -> IO b , bcInc :: (a, a) -> IO b , bcGet :: (a, a) -> IO b , bcMinRaw :: a , bcGetMax :: IO a , bcPath :: ObjectPath , bcInterface :: InterfaceName , bcName :: T.Text } data BrightnessControls m = BrightnessControls { bctlMax :: Sometimes (m ()) , bctlMin :: Sometimes (m ()) , bctlInc :: Sometimes (m ()) , bctlDec :: Sometimes (m ()) } brightnessControls :: MonadUnliftIO m => XPQuery -> BrightnessConfig a b -> Maybe SesClient -> BrightnessControls m brightnessControls q bc cl = BrightnessControls { bctlMax = cb "max brightness" memMax , bctlMin = cb "min brightness" memMin , bctlInc = cb "increase brightness" memInc , bctlDec = cb "decrease brightness" memDec } where cb = callBacklight q cl bc callGetBrightness :: (MonadUnliftIO m, SafeClient c, Num n) => BrightnessConfig a b -> c -> m (Maybe n) callGetBrightness BrightnessConfig {bcPath = p, bcInterface = i} client = either (const Nothing) bodyGetBrightness <$> callMethod client xmonadBusName p i memGet signalDep :: BrightnessConfig a b -> DBusDependency_ SesClient signalDep BrightnessConfig {bcPath = p, bcInterface = i} = Endpoint [] xmonadBusName p i $ Signal_ memCur matchSignal :: (MonadUnliftIO m, SafeClient c, Num n) => BrightnessConfig a b -> (Maybe n -> m ()) -> c -> m () matchSignal BrightnessConfig {bcPath = p, bcInterface = i} cb = void . addMatchCallback brMatcher (cb . bodyGetBrightness) where -- TODO add busname to this brMatcher = matchAny { matchPath = Just p , matchInterface = Just i , matchMember = Just memCur } -------------------------------------------------------------------------------- -- Internal DBus Crap brightnessExporter :: (MonadReader env m, HasLogFunc env, MonadUnliftIO m, RealFrac b) => XPQuery -> [Fulfillment] -> [IODependency_] -> BrightnessConfig a b -> Maybe SesClient -> Sometimes (m (), m ()) brightnessExporter q ful deps bc@BrightnessConfig {bcName = n} cl = Sometimes (T.append n " DBus Interface") q [Subfeature root "exporter"] where root = DBusRoot_ (exportBrightnessControlsInner bc) tree cl tree = listToAnds (Bus ful xmonadBusName) $ fmap DBusIO deps exportBrightnessControlsInner :: (MonadReader env m, HasLogFunc env, MonadUnliftIO m, RealFrac b) => BrightnessConfig a b -> SesClient -> (m (), m ()) exportBrightnessControlsInner bc = cmd where cmd = exportPair (bcPath bc) $ \cl_ -> do -- up = liftIO $ do -- let ses = toClient cl maxval <- liftIO $ bcGetMax bc -- assume the max value will never change let bounds = (bcMinRaw bc, maxval) let autoMethod' m f = autoMethod m $ emitBrightness bc cl_ =<< f bc bounds let funget = bcGet bc -- export -- ses -- (bcPath bc) return $ defaultInterface { interfaceName = bcInterface bc , interfaceMethods = [ autoMethod' memMax bcMax , autoMethod' memMin bcMin , autoMethod' memInc bcInc , autoMethod' memDec bcDec , autoMethod memGet (round <$> funget bounds :: IO Int32) ] , interfaceSignals = [sig] } -- down = liftIO $ unexport (toClient cl) (bcPath bc) sig = I.Signal { I.signalName = memCur , I.signalArgs = [ I.SignalArg { I.signalArgName = "brightness" , I.signalArgType = TypeInt32 } ] } emitBrightness :: (MonadUnliftIO m, RealFrac b) => BrightnessConfig a b -> Client -> b -> m () emitBrightness BrightnessConfig {bcPath = p, bcInterface = i} client cur = liftIO $ emit client $ sig {signalBody = [toVariant (round cur :: Int32)]} where sig = signal p i memCur callBacklight :: MonadUnliftIO m => XPQuery -> Maybe SesClient -> BrightnessConfig a b -> T.Text -> MemberName -> Sometimes (m ()) callBacklight q cl BrightnessConfig { bcPath = p , bcInterface = i , bcName = n } controlName m = Sometimes (T.unwords [n, controlName]) q [Subfeature root "method call"] where root = DBusRoot_ cmd (Only_ $ Endpoint [] xmonadBusName p i $ Method_ m) cl cmd c = io $ void $ callMethod c xmonadBusName p i m bodyGetBrightness :: Num a => [Variant] -> Maybe a bodyGetBrightness [b] = fromIntegral <$> (fromVariant b :: Maybe Int32) bodyGetBrightness _ = Nothing -------------------------------------------------------------------------------- -- DBus Members memCur :: MemberName memCur = memberName_ "CurrentBrightness" memGet :: MemberName memGet = memberName_ "GetBrightness" memMax :: MemberName memMax = memberName_ "MaxBrightness" memMin :: MemberName memMin = memberName_ "MinBrightness" memInc :: MemberName memInc = memberName_ "IncBrightness" memDec :: MemberName memDec = memberName_ "DecBrightness"