xmonad-extras-0.13.3: XMonad/Util/Brightness.hs
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Util.Brightness
-- License : MIT
--
-- Stability : unstable
-- Portability : unportable
--
-- Module to control the brightness of the screen in linux environments
--
-- [@Requirements@]
-- This module assumes that the following files exists:
--
-- * __\/sys\/class\/backlight\/intel_backlight\/max_brightness__
--
-- * __\/sys\/class\/backlight\/intel_backlight\/brightness__
--
-- Also, brightness should be updatable by changing the content of
-- __\/sys\/class\/backlight\/intel_backlight\/brightness__.
--
-- [@Permissions@]
-- To use this module, the owner of the __xmonad__ process will need to
-- have permission to write to __\/sys\/class\/backlight\/intel_backlight\/brightness__.
-- To achieve this, you can:
--
-- * Create a group with your user and root and give permissions to this
-- group to write to the file;
--
-- * Allow anyone to write the file through 646 permissions: __-rw-r--rw-__;
--
-----------------------------------------------------------------------------
module XMonad.Util.Brightness
( increase
, decrease
, change
) where
import XMonad
import Data.Traversable (traverse)
import System.IO (hPutStrLn, stderr)
import Data.Bitraversable (bitraverse)
import Control.Monad (join)
import Data.Bifunctor (first)
import Control.Exception (try)
import Control.Applicative (liftA2)
import Data.ByteString.Char8 (unpack)
import qualified Data.ByteString as BS
maxfile = "/sys/class/backlight/intel_backlight/max_brightness"
currentfile = "/sys/class/backlight/intel_backlight/brightness"
-- | Update brightness by +100
increase :: X ()
increase = liftIO $ change (+100) *> (pure ())
-- | Update brightness by -100
decrease :: X ()
decrease = liftIO $ change (+ (-100)) *> (pure ())
-- | Perform all needed IO to update screen brightness
change :: (Int -> Int) -> IO (Either () ())
change f = do
max <- getFromFile maxfile readInt
current <- getFromFile currentfile readInt
printError =<< apply (writeToFile currentfile) (liftA2 (guard f) max current)
apply :: (Int -> IO (Either String ())) -> Either String Int -> IO (Either String ())
apply f = fmap join . traverse f
guard :: (Int -> Int) -> Int -> Int -> Int
guard f max current
| value > max = max
| value < 0 = 0
| otherwise = value
where value = f current
readInt :: BS.ByteString -> Either String Int
readInt str = case (reads (unpack str)) of
[(n, "\n")] -> Right n
[(n, "")] -> Right n
_ -> Left "Could not parse string to int"
printError :: Either String e -> IO (Either () e)
printError = bitraverse (hPutStrLn stderr) (pure . id)
getFromFile :: FilePath -> (BS.ByteString -> Either String a) -> IO (Either String a)
getFromFile filename fcast = fmap (fcast =<<) (try' $ BS.readFile filename)
writeToFile :: FilePath -> Int -> IO (Either String ())
writeToFile filename value = try' $ writeFile filename (show value)
try' :: forall a . IO a -> IO (Either String a)
try' x = fmap (first show) (try x :: IO (Either IOError a))