-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Cpu
-- Copyright   :  (c) 2011, 2017 Jose Antonio Ortega Ruiz
--                (c) 2007-2010 Andrea Rossato
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
-- A cpu monitor for Xmobar
--
-----------------------------------------------------------------------------

module Xmobar.Plugins.Monitors.Cpu (startCpu) where

import Xmobar.Plugins.Monitors.Common
import qualified Data.ByteString.Lazy.Char8 as B
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import System.Console.GetOpt

newtype CpuOpts = CpuOpts
  { CpuOpts -> Maybe IconPattern
loadIconPattern :: Maybe IconPattern
  }

defaultOpts :: CpuOpts
defaultOpts :: CpuOpts
defaultOpts = CpuOpts :: Maybe IconPattern -> CpuOpts
CpuOpts
  { loadIconPattern :: Maybe IconPattern
loadIconPattern = Maybe IconPattern
forall a. Maybe a
Nothing
  }

options :: [OptDescr (CpuOpts -> CpuOpts)]
options :: [OptDescr (CpuOpts -> CpuOpts)]
options =
  [ [Char]
-> [[Char]]
-> ArgDescr (CpuOpts -> CpuOpts)
-> [Char]
-> OptDescr (CpuOpts -> CpuOpts)
forall a. [Char] -> [[Char]] -> ArgDescr a -> [Char] -> OptDescr a
Option [Char]
"" [[Char]
"load-icon-pattern"] (([Char] -> CpuOpts -> CpuOpts)
-> [Char] -> ArgDescr (CpuOpts -> CpuOpts)
forall a. ([Char] -> a) -> [Char] -> ArgDescr a
ReqArg (\[Char]
x CpuOpts
o ->
     CpuOpts
o { loadIconPattern :: Maybe IconPattern
loadIconPattern = IconPattern -> Maybe IconPattern
forall a. a -> Maybe a
Just (IconPattern -> Maybe IconPattern)
-> IconPattern -> Maybe IconPattern
forall a b. (a -> b) -> a -> b
$ [Char] -> IconPattern
parseIconPattern [Char]
x }) [Char]
"") [Char]
""
  ]

cpuConfig :: IO MConfig
cpuConfig :: IO MConfig
cpuConfig = [Char] -> [[Char]] -> IO MConfig
mkMConfig
       [Char]
"Cpu: <total>%"
       [[Char]
"bar",[Char]
"vbar",[Char]
"ipat",[Char]
"total",[Char]
"user",[Char]
"nice",[Char]
"system",[Char]
"idle",[Char]
"iowait"]

type CpuDataRef = IORef [Int]

cpuData :: IO [Int]
cpuData :: IO [Int]
cpuData = ByteString -> [Int]
cpuParser (ByteString -> [Int]) -> IO ByteString -> IO [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Char] -> IO ByteString
B.readFile [Char]
"/proc/stat"

cpuParser :: B.ByteString -> [Int]
cpuParser :: ByteString -> [Int]
cpuParser = (ByteString -> Int) -> [ByteString] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> Int
forall a. Read a => [Char] -> a
read ([Char] -> Int) -> (ByteString -> [Char]) -> ByteString -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Char]
B.unpack) ([ByteString] -> [Int])
-> (ByteString -> [ByteString]) -> ByteString -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [ByteString]
forall a. [a] -> [a]
tail ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
B.words (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
forall a. [a] -> a
head ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
B.lines

parseCpu :: CpuDataRef -> IO [Float]
parseCpu :: CpuDataRef -> IO [Float]
parseCpu CpuDataRef
cref =
    do [Int]
a <- CpuDataRef -> IO [Int]
forall a. IORef a -> IO a
readIORef CpuDataRef
cref
       [Int]
b <- IO [Int]
cpuData
       CpuDataRef -> [Int] -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef CpuDataRef
cref [Int]
b
       let dif :: [Int]
dif = (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Int]
b [Int]
a
           tot :: Float
tot = Int -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Float) -> Int -> Float
forall a b. (a -> b) -> a -> b
$ [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
dif
           percent :: [Float]
percent = (Int -> Float) -> [Int] -> [Float]
forall a b. (a -> b) -> [a] -> [b]
map ((Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
tot) (Float -> Float) -> (Int -> Float) -> Int -> Float
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral) [Int]
dif
       [Float] -> IO [Float]
forall (m :: * -> *) a. Monad m => a -> m a
return [Float]
percent

formatCpu :: CpuOpts -> [Float] -> Monitor [String]
formatCpu :: CpuOpts -> [Float] -> Monitor [[Char]]
formatCpu CpuOpts
_ [] = [[Char]] -> Monitor [[Char]]
forall (m :: * -> *) a. Monad m => a -> m a
return ([[Char]] -> Monitor [[Char]]) -> [[Char]] -> Monitor [[Char]]
forall a b. (a -> b) -> a -> b
$ Int -> [Char] -> [[Char]]
forall a. Int -> a -> [a]
replicate Int
8 [Char]
""
formatCpu CpuOpts
opts [Float]
xs = do
  let t :: Float
t = [Float] -> Float
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Float] -> Float) -> [Float] -> Float
forall a b. (a -> b) -> a -> b
$ Int -> [Float] -> [Float]
forall a. Int -> [a] -> [a]
take Int
3 [Float]
xs
  [Char]
b <- Float -> Float -> Monitor [Char]
showPercentBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
t) Float
t
  [Char]
v <- Float -> Float -> Monitor [Char]
showVerticalBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
t) Float
t
  [Char]
d <- Maybe IconPattern -> Float -> Monitor [Char]
showIconPattern (CpuOpts -> Maybe IconPattern
loadIconPattern CpuOpts
opts) Float
t
  [[Char]]
ps <- [Float] -> Monitor [[Char]]
showPercentsWithColors (Float
tFloat -> [Float] -> [Float]
forall a. a -> [a] -> [a]
:[Float]
xs)
  [[Char]] -> Monitor [[Char]]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char]
b[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[Char]
v[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[Char]
d[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[[Char]]
ps)

runCpu :: CpuDataRef -> [String] -> Monitor String
runCpu :: CpuDataRef -> [[Char]] -> Monitor [Char]
runCpu CpuDataRef
cref [[Char]]
argv =
    do [Float]
c <- IO [Float] -> Monitor [Float]
forall a. IO a -> Monitor a
io (CpuDataRef -> IO [Float]
parseCpu CpuDataRef
cref)
       CpuOpts
opts <- IO CpuOpts -> Monitor CpuOpts
forall a. IO a -> Monitor a
io (IO CpuOpts -> Monitor CpuOpts) -> IO CpuOpts -> Monitor CpuOpts
forall a b. (a -> b) -> a -> b
$ [OptDescr (CpuOpts -> CpuOpts)]
-> CpuOpts -> [[Char]] -> IO CpuOpts
forall opts.
[OptDescr (opts -> opts)] -> opts -> [[Char]] -> IO opts
parseOptsWith [OptDescr (CpuOpts -> CpuOpts)]
options CpuOpts
defaultOpts [[Char]]
argv
       [[Char]]
l <- CpuOpts -> [Float] -> Monitor [[Char]]
formatCpu CpuOpts
opts [Float]
c
       [[Char]] -> Monitor [Char]
parseTemplate [[Char]]
l

startCpu :: [String] -> Int -> (String -> IO ()) -> IO ()
startCpu :: [[Char]] -> Int -> ([Char] -> IO ()) -> IO ()
startCpu [[Char]]
a Int
r [Char] -> IO ()
cb = do
  CpuDataRef
cref <- [Int] -> IO CpuDataRef
forall a. a -> IO (IORef a)
newIORef []
  [Float]
_ <- CpuDataRef -> IO [Float]
parseCpu CpuDataRef
cref
  [[Char]]
-> IO MConfig
-> ([[Char]] -> Monitor [Char])
-> Int
-> ([Char] -> IO ())
-> IO ()
runM [[Char]]
a IO MConfig
cpuConfig (CpuDataRef -> [[Char]] -> Monitor [Char]
runCpu CpuDataRef
cref) Int
r [Char] -> IO ()
cb