-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Volume
-- Copyright   :  (c) 2011, 2013, 2015, 2018, 2020 Thomas Tuegel
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
-- A monitor for ALSA soundcards
--
-----------------------------------------------------------------------------

module Xmobar.Plugins.Monitors.Volume
  ( runVolume
  , runVolumeWith
  , volumeConfig
  , options
  , defaultOpts
  , VolumeOpts
  ) where

import Control.Applicative ( liftA3 )
import Control.Monad ( liftM2, liftM3, mplus )
import Xmobar.Plugins.Monitors.Common
import Sound.ALSA.Mixer
import qualified Sound.ALSA.Exception as AE
import System.Console.GetOpt


volumeConfig :: IO MConfig
volumeConfig :: IO MConfig
volumeConfig =
    String -> [String] -> IO MConfig
mkMConfig
        String
"Vol: <volume>% <status>"
        [ String
"volume"
        , String
"volumebar"
        , String
"volumevbar"
        , String
"dB"
        , String
"status"
        , String
"volumeipat"
        , String
"volumestatus"
        ]

data VolumeOpts = VolumeOpts
    { VolumeOpts -> String
onString :: String
    , VolumeOpts -> String
offString :: String
    , VolumeOpts -> Maybe String
onColor :: Maybe String
    , VolumeOpts -> Maybe String
offColor :: Maybe String
    , VolumeOpts -> Float
highDbThresh :: Float
    , VolumeOpts -> Float
lowDbThresh :: Float
    , VolumeOpts -> Maybe IconPattern
volumeIconPattern :: Maybe IconPattern
    , VolumeOpts -> Maybe Float
lowVolThresh :: Maybe Float
    , VolumeOpts -> Maybe Float
highVolThresh :: Maybe Float
    , VolumeOpts -> String
lowString :: String
    , VolumeOpts -> String
mediumString :: String
    , VolumeOpts -> String
highString :: String
    }

defaultOpts :: VolumeOpts
defaultOpts :: VolumeOpts
defaultOpts = VolumeOpts :: String
-> String
-> Maybe String
-> Maybe String
-> Float
-> Float
-> Maybe IconPattern
-> Maybe Float
-> Maybe Float
-> String
-> String
-> String
-> VolumeOpts
VolumeOpts
    { onString :: String
onString = String
"[on] "
    , offString :: String
offString = String
"[off]"
    , onColor :: Maybe String
onColor = String -> Maybe String
forall a. a -> Maybe a
Just String
"green"
    , offColor :: Maybe String
offColor = String -> Maybe String
forall a. a -> Maybe a
Just String
"red"
    , highDbThresh :: Float
highDbThresh = -Float
5.0
    , lowDbThresh :: Float
lowDbThresh = -Float
30.0
    , volumeIconPattern :: Maybe IconPattern
volumeIconPattern = Maybe IconPattern
forall a. Maybe a
Nothing
    , lowVolThresh :: Maybe Float
lowVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just Float
20.0
    , highVolThresh :: Maybe Float
highVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just Float
60.0
    , lowString :: String
lowString = String
""
    , mediumString :: String
mediumString = String
""
    , highString :: String
highString = String
""
    }

data VolumeStatus
    = VolLow
    | VolMedium
    | VolHigh
    | VolOff

-- | Set the volume status according to user set thresholds and the current
-- volume
getVolStatus :: Float -- ^ Low volume threshold, in [0,100]
             -> Float -- ^ High volume threshold, in  [0,100]
             -> Float -- ^ Current volume, in [0,1]
             -> VolumeStatus
getVolStatus :: Float -> Float -> Float -> VolumeStatus
getVolStatus Float
lo Float
hi Float
val'
    | Float
val Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
hi = VolumeStatus
VolHigh
    | Float
val Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
lo = VolumeStatus
VolMedium
    | Bool
otherwise = VolumeStatus
VolLow
  where
    val :: Float
val = Float
val' Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
100

options :: [OptDescr (VolumeOpts -> VolumeOpts)]
options :: [OptDescr (VolumeOpts -> VolumeOpts)]
options =
    [ String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"O" [String
"on"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { onString :: String
onString = String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"o" [String
"off"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { offString :: String
offString = String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"lowd"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowDbThresh :: Float
lowDbThresh = String -> Float
forall a. Read a => String -> a
read String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"highd"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highDbThresh :: Float
highDbThresh = String -> Float
forall a. Read a => String -> a
read String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"C" [String
"onc"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { onColor :: Maybe String
onColor = String -> Maybe String
forall a. a -> Maybe a
Just String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"c" [String
"offc"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { offColor :: Maybe String
offColor = String -> Maybe String
forall a. a -> Maybe a
Just String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"volume-icon-pattern"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o ->
       VolumeOpts
o { volumeIconPattern :: Maybe IconPattern
volumeIconPattern = IconPattern -> Maybe IconPattern
forall a. a -> Maybe a
Just (IconPattern -> Maybe IconPattern)
-> IconPattern -> Maybe IconPattern
forall a b. (a -> b) -> a -> b
$ String -> IconPattern
parseIconPattern String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"L" [String
"lowv"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowVolThresh :: Maybe Float
lowVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just (Float -> Maybe Float) -> Float -> Maybe Float
forall a b. (a -> b) -> a -> b
$ String -> Float
forall a. Read a => String -> a
read String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"H" [String
"highv"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highVolThresh :: Maybe Float
highVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just (Float -> Maybe Float) -> Float -> Maybe Float
forall a b. (a -> b) -> a -> b
$ String -> Float
forall a. Read a => String -> a
read String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"l" [String
"lows"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowString :: String
lowString = String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"m" [String
"mediums"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { mediumString :: String
mediumString = String
x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"h" [String
"highs"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highString :: String
highString = String
x }) String
"") String
""
    ]

percent :: Integer -> Integer -> Integer -> Float
percent :: Integer -> Integer -> Integer -> Float
percent Integer
v' Integer
lo' Integer
hi' = (Float
v Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
lo) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ (Float
hi Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
lo)
  where v :: Float
v = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
v'
        lo :: Float
lo = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
lo'
        hi :: Float
hi = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
hi'

formatVol :: Integer -> Integer -> Integer -> Monitor String
formatVol :: Integer -> Integer -> Integer -> Monitor String
formatVol Integer
lo Integer
hi Integer
v =
    Float -> Monitor String
showPercentWithColors (Float -> Monitor String) -> Float -> Monitor String
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolBar :: Integer -> Integer -> Integer -> Monitor String
formatVolBar :: Integer -> Integer -> Integer -> Monitor String
formatVolBar Integer
lo Integer
hi Integer
v =
    Float -> Float -> Monitor String
showPercentBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
x) Float
x where x :: Float
x = Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolVBar :: Integer -> Integer -> Integer -> Monitor String
formatVolVBar :: Integer -> Integer -> Integer -> Monitor String
formatVolVBar Integer
lo Integer
hi Integer
v =
    Float -> Float -> Monitor String
showVerticalBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
x) Float
x where x :: Float
x = Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolDStr :: Maybe IconPattern -> Integer -> Integer -> Integer -> Monitor String
formatVolDStr :: Maybe IconPattern
-> Integer -> Integer -> Integer -> Monitor String
formatVolDStr Maybe IconPattern
ipat Integer
lo Integer
hi Integer
v =
    Maybe IconPattern -> Float -> Monitor String
showIconPattern Maybe IconPattern
ipat (Float -> Monitor String) -> Float -> Monitor String
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

switchHelper :: VolumeOpts
             -> (VolumeOpts -> Maybe String)
             -> (VolumeOpts -> String)
             -> VolumeStatus
             -> Monitor String
switchHelper :: VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
cHelp VolumeOpts -> String
strHelp VolumeStatus
vs = String -> Monitor String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Monitor String) -> String -> Monitor String
forall a b. (a -> b) -> a -> b
$
    Maybe String -> String
colorHelper (VolumeOpts -> Maybe String
cHelp VolumeOpts
opts)
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ VolumeStatus -> VolumeOpts -> String
volHelper VolumeStatus
vs VolumeOpts
opts
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ VolumeOpts -> String
strHelp VolumeOpts
opts
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (String -> String -> String
forall a b. a -> b -> a
const String
"</fc>") (VolumeOpts -> Maybe String
cHelp VolumeOpts
opts)

formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch VolumeOpts
opts Bool
True  VolumeStatus
vs = VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
onColor  VolumeOpts -> String
onString  VolumeStatus
vs
formatSwitch VolumeOpts
opts Bool
False VolumeStatus
_  = VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
offColor VolumeOpts -> String
offString VolumeStatus
VolOff

-- | Convert the current volume status into user defined strings
volHelper :: VolumeStatus -> VolumeOpts -> String
volHelper :: VolumeStatus -> VolumeOpts -> String
volHelper VolumeStatus
volStatus VolumeOpts
opts =
    case VolumeStatus
volStatus of
        VolumeStatus
VolHigh -> VolumeOpts -> String
highString VolumeOpts
opts
        VolumeStatus
VolMedium -> VolumeOpts -> String
mediumString VolumeOpts
opts
        VolumeStatus
VolLow -> VolumeOpts -> String
lowString VolumeOpts
opts
        VolumeStatus
VolOff -> String
""

colorHelper :: Maybe String -> String
colorHelper :: Maybe String -> String
colorHelper = String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\String
c -> String
"<fc=" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
">")

formatDb :: VolumeOpts -> Integer -> Monitor String
formatDb :: VolumeOpts -> Integer -> Monitor String
formatDb VolumeOpts
opts Integer
dbi = do
    Maybe String
h <- Selector (Maybe String) -> Monitor (Maybe String)
forall a. Selector a -> Monitor a
getConfigValue Selector (Maybe String)
highColor
    Maybe String
m <- Selector (Maybe String) -> Monitor (Maybe String)
forall a. Selector a -> Monitor a
getConfigValue Selector (Maybe String)
normalColor
    Maybe String
l <- Selector (Maybe String) -> Monitor (Maybe String)
forall a. Selector a -> Monitor a
getConfigValue Selector (Maybe String)
lowColor
    Int
d <- Selector Int -> Monitor Int
forall a. Selector a -> Monitor a
getConfigValue Selector Int
decDigits
    let db :: Float
db = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
dbi Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
100.0
        digits :: String
digits = Int -> Float -> String
forall a. RealFloat a => Int -> a -> String
showDigits Int
d Float
db
        startColor :: String
startColor | Float
db Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= VolumeOpts -> Float
highDbThresh VolumeOpts
opts = Maybe String -> String
colorHelper Maybe String
h
                   | Float
db Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< VolumeOpts -> Float
lowDbThresh VolumeOpts
opts = Maybe String -> String
colorHelper Maybe String
l
                   | Bool
otherwise = Maybe String -> String
colorHelper Maybe String
m
        stopColor :: String
stopColor | String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
startColor = String
""
                  | Bool
otherwise = String
"</fc>"
    String -> Monitor String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Monitor String) -> String -> Monitor String
forall a b. (a -> b) -> a -> b
$ String
startColor String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
digits String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
stopColor

runVolume :: String -> String -> [String] -> Monitor String
runVolume :: String -> String -> [String] -> Monitor String
runVolume String
mixerName String
controlName [String]
argv = do
    VolumeOpts
opts <- IO VolumeOpts -> Monitor VolumeOpts
forall a. IO a -> Monitor a
io (IO VolumeOpts -> Monitor VolumeOpts)
-> IO VolumeOpts -> Monitor VolumeOpts
forall a b. (a -> b) -> a -> b
$ [OptDescr (VolumeOpts -> VolumeOpts)]
-> VolumeOpts -> [String] -> IO VolumeOpts
forall opts.
[OptDescr (opts -> opts)] -> opts -> [String] -> IO opts
parseOptsWith [OptDescr (VolumeOpts -> VolumeOpts)]
options VolumeOpts
defaultOpts [String]
argv
    VolumeOpts -> String -> String -> Monitor String
runVolumeWith VolumeOpts
opts String
mixerName String
controlName

runVolumeWith :: VolumeOpts -> String -> String -> Monitor String
runVolumeWith :: VolumeOpts -> String -> String -> Monitor String
runVolumeWith VolumeOpts
opts String
mixerName String
controlName = do
    (Maybe Integer
lo, Maybe Integer
hi, Maybe Integer
val, Maybe Integer
db, Maybe Bool
sw) <- IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> Monitor
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. IO a -> Monitor a
io IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
readMixer
    String
p <- Maybe (Monitor String) -> Monitor String
liftMonitor (Maybe (Monitor String) -> Monitor String)
-> Maybe (Monitor String) -> Monitor String
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer -> Monitor String)
-> Maybe Integer
-> Maybe Integer
-> Maybe Integer
-> Maybe (Monitor String)
forall (m :: * -> *) a1 a2 a3 r.
Monad m =>
(a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 Integer -> Integer -> Integer -> Monitor String
formatVol Maybe Integer
lo Maybe Integer
hi Maybe Integer
val
    String
b <- Maybe (Monitor String) -> Monitor String
liftMonitor (Maybe (Monitor String) -> Monitor String)
-> Maybe (Monitor String) -> Monitor String
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer -> Monitor String)
-> Maybe Integer
-> Maybe Integer
-> Maybe Integer
-> Maybe (Monitor String)
forall (m :: * -> *) a1 a2 a3 r.
Monad m =>
(a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 Integer -> Integer -> Integer -> Monitor String
formatVolBar Maybe Integer
lo Maybe Integer
hi Maybe Integer
val
    String
v <- Maybe (Monitor String) -> Monitor String
liftMonitor (Maybe (Monitor String) -> Monitor String)
-> Maybe (Monitor String) -> Monitor String
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer -> Monitor String)
-> Maybe Integer
-> Maybe Integer
-> Maybe Integer
-> Maybe (Monitor String)
forall (m :: * -> *) a1 a2 a3 r.
Monad m =>
(a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 Integer -> Integer -> Integer -> Monitor String
formatVolVBar Maybe Integer
lo Maybe Integer
hi Maybe Integer
val
    String
d <- VolumeOpts -> Maybe Integer -> Monitor String
getFormatDB VolumeOpts
opts Maybe Integer
db
    let volStat :: Maybe VolumeStatus
volStat = (Float -> Float -> Float -> VolumeStatus)
-> Maybe Float -> Maybe Float -> Maybe Float -> Maybe VolumeStatus
forall (f :: * -> *) a b c d.
Applicative f =>
(a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 Float -> Float -> Float -> VolumeStatus
getVolStatus
                         (VolumeOpts -> Maybe Float
lowVolThresh VolumeOpts
opts)
                         (VolumeOpts -> Maybe Float
highVolThresh VolumeOpts
opts)
                         ((Integer -> Integer -> Integer -> Float)
-> Maybe Integer -> Maybe Integer -> Maybe Integer -> Maybe Float
forall (f :: * -> *) a b c d.
Applicative f =>
(a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 Integer -> Integer -> Integer -> Float
percent Maybe Integer
val Maybe Integer
lo Maybe Integer
hi) -- current volume in %
    String
s <- VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String
getFormatSwitch VolumeOpts
opts Maybe Bool
sw Maybe VolumeStatus
volStat
    String
ipat <- Maybe (Monitor String) -> Monitor String
liftMonitor (Maybe (Monitor String) -> Monitor String)
-> Maybe (Monitor String) -> Monitor String
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer -> Monitor String)
-> Maybe Integer
-> Maybe Integer
-> Maybe Integer
-> Maybe (Monitor String)
forall (m :: * -> *) a1 a2 a3 r.
Monad m =>
(a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 (Maybe IconPattern
-> Integer -> Integer -> Integer -> Monitor String
formatVolDStr (Maybe IconPattern
 -> Integer -> Integer -> Integer -> Monitor String)
-> Maybe IconPattern
-> Integer
-> Integer
-> Integer
-> Monitor String
forall a b. (a -> b) -> a -> b
$ VolumeOpts -> Maybe IconPattern
volumeIconPattern VolumeOpts
opts) Maybe Integer
lo Maybe Integer
hi Maybe Integer
val

    -- Volume and status in one.
    let vs :: String
vs = if Maybe Bool -> Bool
isVolOff Maybe Bool
sw
            then VolumeOpts -> String
offString VolumeOpts
opts -- User defined off string
            else String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
p         -- Status string, current volume in %

    [String] -> Monitor String
parseTemplate [String
p, String
b, String
v, String
d, String
s, String
ipat, String
vs]

  where

    readMixer :: IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
readMixer =
      IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> (T
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. IO a -> (T -> IO a) -> IO a
AE.catch (String
-> (Mixer
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. String -> (Mixer -> IO a) -> IO a
withMixer String
mixerName ((Mixer
  -> IO
       (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
        Maybe Bool))
 -> IO
      (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
       Maybe Bool))
-> (Mixer
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. (a -> b) -> a -> b
$ \Mixer
mixer -> do
                   Maybe Control
control <- Mixer -> String -> IO (Maybe Control)
getControlByName Mixer
mixer String
controlName
                   (Maybe CLong
lo, Maybe CLong
hi) <- Maybe (IO (CLong, CLong)) -> IO (Maybe CLong, Maybe CLong)
forall a b. Maybe (IO (a, b)) -> IO (Maybe a, Maybe b)
liftMaybe (Maybe (IO (CLong, CLong)) -> IO (Maybe CLong, Maybe CLong))
-> Maybe (IO (CLong, CLong)) -> IO (Maybe CLong, Maybe CLong)
forall a b. (a -> b) -> a -> b
$ Volume -> IO (CLong, CLong)
getRange (Volume -> IO (CLong, CLong))
-> Maybe Volume -> Maybe (IO (CLong, CLong))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Control -> Maybe Volume
volumeControl Maybe Control
control
                   Maybe Integer
val <- Maybe Volume -> IO (Maybe Integer)
getVal (Maybe Volume -> IO (Maybe Integer))
-> Maybe Volume -> IO (Maybe Integer)
forall a b. (a -> b) -> a -> b
$ Maybe Control -> Maybe Volume
volumeControl Maybe Control
control
                   Maybe Integer
db <- Maybe Volume -> IO (Maybe Integer)
getDB (Maybe Volume -> IO (Maybe Integer))
-> Maybe Volume -> IO (Maybe Integer)
forall a b. (a -> b) -> a -> b
$ Maybe Control -> Maybe Volume
volumeControl Maybe Control
control
                   Maybe Bool
sw <- Maybe Switch -> IO (Maybe Bool)
getSw (Maybe Switch -> IO (Maybe Bool))
-> Maybe Switch -> IO (Maybe Bool)
forall a b. (a -> b) -> a -> b
$ Maybe Control -> Maybe Switch
switchControl Maybe Control
control
                   (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
 Maybe Bool)
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return ((CLong -> Integer) -> Maybe CLong -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CLong -> Integer
forall a. Integral a => a -> Integer
toInteger Maybe CLong
lo, (CLong -> Integer) -> Maybe CLong -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CLong -> Integer
forall a. Integral a => a -> Integer
toInteger Maybe CLong
hi, Maybe Integer
val, Maybe Integer
db, Maybe Bool
sw))
                (IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> T
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. a -> b -> a
const (IO
   (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
    Maybe Bool)
 -> T
 -> IO
      (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
       Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
-> T
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. (a -> b) -> a -> b
$ (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
 Maybe Bool)
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Bool
forall a. Maybe a
Nothing))

    volumeControl :: Maybe Control -> Maybe Volume
    volumeControl :: Maybe Control -> Maybe Volume
volumeControl Maybe Control
c = (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
playback (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Volume -> Maybe Volume -> Maybe Volume
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
capture (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Volume -> Maybe Volume -> Maybe Volume
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
common (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)

    switchControl :: Maybe Control -> Maybe Switch
    switchControl :: Maybe Control -> Maybe Switch
switchControl Maybe Control
c = (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
playback (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Switch -> Maybe Switch -> Maybe Switch
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
capture (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Switch -> Maybe Switch -> Maybe Switch
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
common (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)

    liftMaybe :: Maybe (IO (a,b)) -> IO (Maybe a, Maybe b)
    liftMaybe :: Maybe (IO (a, b)) -> IO (Maybe a, Maybe b)
liftMaybe = (Maybe (a, b) -> (Maybe a, Maybe b))
-> IO (Maybe (a, b)) -> IO (Maybe a, Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Maybe a -> Maybe b -> (Maybe a, Maybe b))
-> (Maybe (a, b) -> Maybe a)
-> (Maybe (a, b) -> Maybe b)
-> Maybe (a, b)
-> (Maybe a, Maybe b)
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (,) (((a, b) -> a) -> Maybe (a, b) -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> a
forall a b. (a, b) -> a
fst) (((a, b) -> b) -> Maybe (a, b) -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> b
forall a b. (a, b) -> b
snd)) (IO (Maybe (a, b)) -> IO (Maybe a, Maybe b))
-> (Maybe (IO (a, b)) -> IO (Maybe (a, b)))
-> Maybe (IO (a, b))
-> IO (Maybe a, Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe (IO (a, b)) -> IO (Maybe (a, b))
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
sequenceA

    liftMonitor :: Maybe (Monitor String) -> Monitor String
    liftMonitor :: Maybe (Monitor String) -> Monitor String
liftMonitor Maybe (Monitor String)
Nothing = Monitor String
unavailable
    liftMonitor (Just Monitor String
m) = Monitor String
m

    channel' :: PerChannel a -> IO (Maybe a)
    channel' :: PerChannel a -> IO (Maybe a)
channel' PerChannel a
v = IO (Maybe a) -> (T -> IO (Maybe a)) -> IO (Maybe a)
forall a. IO a -> (T -> IO a) -> IO a
AE.catch (Channel -> PerChannel a -> IO (Maybe a)
forall x. Channel -> PerChannel x -> IO (Maybe x)
getChannel Channel
FrontLeft PerChannel a
v) (IO (Maybe a) -> T -> IO (Maybe a)
forall a b. a -> b -> a
const (Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing))

    channel :: PerChannel CLong -> IO (Maybe Integer)
    channel :: PerChannel CLong -> IO (Maybe Integer)
channel PerChannel CLong
v = (Maybe CLong -> Maybe Integer)
-> IO (Maybe CLong) -> IO (Maybe Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((CLong -> Integer) -> Maybe CLong -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CLong -> Integer
forall a. Integral a => a -> Integer
toInteger) (PerChannel CLong -> IO (Maybe CLong)
forall a. PerChannel a -> IO (Maybe a)
channel' PerChannel CLong
v)

    getDB :: Maybe Volume -> IO (Maybe Integer)
    getDB :: Maybe Volume -> IO (Maybe Integer)
getDB Maybe Volume
Nothing = Maybe Integer -> IO (Maybe Integer)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Integer
forall a. Maybe a
Nothing
    getDB (Just Volume
v) = PerChannel CLong -> IO (Maybe Integer)
channel (Volume -> PerChannel CLong
dB Volume
v)

    getVal :: Maybe Volume -> IO (Maybe Integer)
    getVal :: Maybe Volume -> IO (Maybe Integer)
getVal Maybe Volume
Nothing = Maybe Integer -> IO (Maybe Integer)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Integer
forall a. Maybe a
Nothing
    getVal (Just Volume
v) = PerChannel CLong -> IO (Maybe Integer)
channel (Volume -> PerChannel CLong
value Volume
v)

    getSw :: Maybe Switch -> IO (Maybe Bool)
    getSw :: Maybe Switch -> IO (Maybe Bool)
getSw Maybe Switch
Nothing = Maybe Bool -> IO (Maybe Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Bool
forall a. Maybe a
Nothing
    getSw (Just Switch
s) = Switch -> IO (Maybe Bool)
forall a. PerChannel a -> IO (Maybe a)
channel' Switch
s

    getFormatDB :: VolumeOpts -> Maybe Integer -> Monitor String
    getFormatDB :: VolumeOpts -> Maybe Integer -> Monitor String
getFormatDB VolumeOpts
_ Maybe Integer
Nothing = Monitor String
unavailable
    getFormatDB VolumeOpts
opts' (Just Integer
d) = VolumeOpts -> Integer -> Monitor String
formatDb VolumeOpts
opts' Integer
d

    getFormatSwitch :: VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String
    getFormatSwitch :: VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String
getFormatSwitch VolumeOpts
_ Maybe Bool
Nothing Maybe VolumeStatus
_ = Monitor String
unavailable
    getFormatSwitch VolumeOpts
_ Maybe Bool
_ Maybe VolumeStatus
Nothing = Monitor String
unavailable
    getFormatSwitch VolumeOpts
opts' (Just Bool
sw) (Just VolumeStatus
vs) = VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch VolumeOpts
opts' Bool
sw VolumeStatus
vs

    -- | Determine whether the volume is off based on the value of 'sw' from
    -- 'runVolumeWith'.
    isVolOff :: Maybe Bool -> Bool
isVolOff = (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
/=)
    unavailable :: Monitor String
unavailable = Selector String -> Monitor String
forall a. Selector a -> Monitor a
getConfigValue Selector String
naString