packages feed

monky 2.0.1.0 → 2.1.0.0

raw patch · 14 files changed

+371/−63 lines, 14 filesdep +pulseaudiodep ~netlink

Dependencies added: pulseaudio

Dependency ranges changed: netlink

Files

Monky/Battery.hs view
@@ -131,7 +131,7 @@   let gap = if online == 0 then now else full - now   change <- readValue c   let avg = (change * 20 + s * 80) `div` 100-  return (if avg >= 3600 then gap `div` (avg `div` 3600) else 0, avg)+  return (sdivUBound gap (avg `div` 3600) 0, avg)  -- |Get current loading speed in Watt/s getLoading :: BatteryHandle -> IO Float
Monky/Examples/Alsa.hs view
@@ -16,57 +16,18 @@     You should have received a copy of the GNU Lesser General Public License     along with Monky.  If not, see <http://www.gnu.org/licenses/>. -}-{-# LANGUAGE OverloadedStrings #-} {-| Module      : Monky.Examples.Alsa-Description : An example module instance for the alsa module+Description : Proxy module for backwards compat. See Monky.Examples.Sound.Alsa Maintainer  : ongy Stability   : testing Portability : Linux  -}-module Monky.Examples.Alsa+module Monky.Examples.Alsa {-# DEPRECATED "Use Monky.Examples.Sound.Alsa" #-}   ( getVOLHandle   , AlsaH   ) where -import Monky.Alsa hiding (getVOLHandle)-import qualified Monky.Alsa as A (getVOLHandle)-import Monky.Modules-import Monky.Examples.Utility--import Formatting-import Data.Text (Text)--{- ALSA module -}-getVolumeStr :: VOLHandle -> IO Text-getVolumeStr h = do-  updateVOLH h-  m <- getMute h-  v <- getVolumePercent h-  if m-    then return "Mute"-    else return $ sformat ((left 3 ' ' %. int) % "%") v--getVOLOutput :: VOLHandle -> IO [MonkyOut]-getVOLOutput h = do-  out <- getVolumeStr h-  return [MonkyPlain out]--instance PollModule AlsaH where-  getOutput (AH h) = getVOLOutput h--instance EvtModule AlsaH where-  startEvtLoop (AH h) r = do-    [fd] <- getPollFDs h-    r =<< getOutput (AH h)-    loopFd h fd r getVOLOutput---- |The handle type for this module-newtype AlsaH = AH VOLHandle---- |Get a handle which allows access to audio (alsa) subsystem information-getVOLHandle :: String -- ^The audio-card to use-             -> IO AlsaH-getVOLHandle = fmap AH . A.getVOLHandle+import Monky.Examples.Sound.Alsa
Monky/Examples/Battery.hs view
@@ -45,10 +45,10 @@ batteryColor :: BatteryState -> Int -> Text batteryColor BatLoading _ = "#5fff5f" batteryColor _ p-  | p < 20 = "#ffff00"-  | p < 15 = "#ffd700"-  | p < 10 = "#ffaf00"   | p <  5 = "#ff0000"+  | p < 10 = "#ffaf00"+  | p < 15 = "#ffd700"+  | p < 20 = "#ffff00"   | otherwise = ""  batterySymbol :: BatteryState -> Int -> Text
Monky/Examples/Modify.hs view
@@ -47,6 +47,7 @@   , IOModifyHandle   , getIOModifyHandle +  , changeImage   ) where @@ -62,7 +63,7 @@  -- |Get a handle to purely modify another modules output getModifyHandle :: ([MonkyOut] -> [MonkyOut]) -> IO a -> IO (ModifyHandle a)-getModifyHandle fun = fmap (MH fun)+getModifyHandle = fmap . MH  instance PollModule a => PollModule (ModifyHandle a) where   initialize (MH _ m) = initialize m@@ -85,3 +86,8 @@  instance EvtModule a => EvtModule (IOModifyHandle a) where   startEvtLoop (IOMH fun m) f = startEvtLoop m (\e -> f =<< fun e)++-- |Change the replacemant char in an monky image (if your font doesn't support it), returns initial value if not an image+changeImage :: Char -> MonkyOut -> MonkyOut+changeImage c (MonkyImage x _) = MonkyImage x c+changeImage _ x                = x
+ Monky/Examples/Sound/Alsa.hs view
@@ -0,0 +1,72 @@+{-+    Copyright 2015,2016 Markus Ongyerth++    This file is part of Monky.++    Monky is free software: you can redistribute it and/or modify+    it under the terms of the GNU Lesser General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    Monky is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU Lesser General Public License for more details.++    You should have received a copy of the GNU Lesser General Public License+    along with Monky.  If not, see <http://www.gnu.org/licenses/>.+-}+{-# LANGUAGE OverloadedStrings #-}+{-|+Module      : Monky.Examples.Sound.Alsa+Description : An example module instance for the alsa module+Maintainer  : ongy+Stability   : testing+Portability : Linux++-}+module Monky.Examples.Sound.Alsa+  ( getVOLHandle+  , AlsaH+  )+where++import Monky.Alsa hiding (getVOLHandle)+import qualified Monky.Alsa as A (getVOLHandle)+import Monky.Modules+import Monky.Examples.Utility++import Formatting+import Data.Text (Text)++{- ALSA module -}+getVolumeStr :: VOLHandle -> IO Text+getVolumeStr h = do+  updateVOLH h+  m <- getMute h+  v <- getVolumePercent h+  if m+    then return "Mute"+    else return $ sformat ((left 3 ' ' %. int) % "%") v++getVOLOutput :: VOLHandle -> IO [MonkyOut]+getVOLOutput h = do+  out <- getVolumeStr h+  return [MonkyPlain out]++instance PollModule AlsaH where+  getOutput (AH h) = getVOLOutput h++instance EvtModule AlsaH where+  startEvtLoop (AH h) r = do+    [fd] <- getPollFDs h+    r =<< getOutput (AH h)+    loopFd h fd r getVOLOutput++-- |The handle type for this module+newtype AlsaH = AH VOLHandle++-- |Get a handle which allows access to audio (alsa) subsystem information+getVOLHandle :: String -- ^The audio-card to use+             -> IO AlsaH+getVOLHandle = fmap AH . A.getVOLHandle
+ Monky/Examples/Sound/Pulse.hs view
@@ -0,0 +1,173 @@+{-+    Copyright 2016 Markus Ongyerth++    This file is part of Monky.++    Monky is free software: you can redistribute it and/or modify+    it under the terms of the GNU Lesser General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    Monky is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU Lesser General Public License for more details.++    You should have received a copy of the GNU Lesser General Public License+    along with Monky.  If not, see <http://www.gnu.org/licenses/>.+-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-|+Module      : Monky.Examples.Sound.Pulse+Description : Integration example for pulseaudio library.+Maintainer  : ongy+Stability   : experimental+Portability : Linux++Some of this may move into Monky.Sound.Pulse in a near-ish future.+-}+module Monky.Examples.Sound.Pulse+    ( PulseH++    , startPulse+    , startPulseMaybe+    , getPulseHandle+    )+where++import Monky.Modules+import Data.Maybe (fromMaybe)+import Control.Monad (void)+import Control.Concurrent.MVar+import Control.Concurrent++import System.Environment (getProgName)++import Sound.Pulse.Context+import Sound.Pulse.Mainloop+import Sound.Pulse.Mainloop.Simple++import Sound.Pulse.Volume+import Sound.Pulse.Subscribe+import Sound.Pulse.Serverinfo+import Sound.Pulse.Sinkinfo++import System.IO (hPutStrLn, stderr)+import Data.Word (Word32)+import Data.List (genericLength)+import Formatting++#if MIN_VERSION_base(4,8,0)+#else+import Control.Applicative ((<$>), (<*>))+#endif++-- |Pulse handle.+-- This module uses continuations, the handle is not really used+data PulseH = PulseH (Maybe String)++-- |Format a given sink to the output string.+printSink :: ([MonkyOut] -> IO ()) -> Sinkinfo -> IO ()+printSink fun sink = do+    let norm = 0x10000 :: Double+    let (CVolume vol) = siVolume sink+    let mute = siMute sink+    -- this is taken from pulseaudio pa_volume_snprint, +- rounding this is+    -- equal to pavucontrol+    let rvols =  map (\v -> (fromIntegral v*100+norm/2) / norm) vol+    let rvol = sum rvols / genericLength rvols+    let str = if mute+        then "Mute"+        else sformat ((left 3 ' ' %. int) % "%") (round rvol :: Int)+    fun [MonkyPlain str]++-- |Start the subscription loop that will give us the updates.+startLoop :: Context -> ([MonkyOut] -> IO ()) -> Sinkinfo -> IO ()+startLoop cxt cfun info = do +    void $ subscribeEvents cxt [SubscriptionMaskSink] fun+    printSink cfun info+    where fun :: ((SubscriptionEventFacility, SubscriptionEventType) -> Word32 -> IO ())+          fun _ 0 = void $ getContextSinkByIndex cxt (siIndex info) (printSink cfun)+          fun _ _ = return ()++-- |Use the name (string) to find the index, print once and find the main loop+startWithName :: Context -> String -> ([MonkyOut] -> IO ()) -> IO ()+startWithName cxt name fun = void $ getContextSinkByName cxt name (startLoop cxt fun)++-- |Get the default sink and start the main loop+getDefaultSink :: Context -> ([MonkyOut] -> IO ()) -> IO ()+getDefaultSink cxt cfun = void $ getServerInfo cxt fun+    where fun :: ServerInfo -> IO ()+          fun serv = let name = defaultSinkName serv+                     in startWithName cxt name cfun++-- |Try to start pulse loop. silently fail!+startPulse :: Maybe String -> ([MonkyOut] -> IO ()) -> IO ()+startPulse = startPulseMaybe (return ())+++-- |Connect to pulse server and try to start the main loop for this module.+startPulseMaybe+    :: IO () -- ^The continuation if everything fails+    -> Maybe String -- ^Sink to use (Nothing for default)+    -> ([MonkyOut] -> IO ()) -- ^Output function+    -> IO ()+startPulseMaybe ret sinkName fun = do+    impl <- getMainloopImpl+    name <- getProgName+    cxt <- getContext impl name+    setStateCallback cxt $ do+        state <- getContextState cxt+        case state of+            ContextFailed -> do+                hPutStrLn stderr "Could not connect to pulse :("+                quitLoop impl (-1)+            ContextReady -> fromMaybe+                (getDefaultSink cxt fun )+                (startWithName cxt <$> sinkName <*> return fun)+            _ -> return ()+    _ <- connectContext cxt Nothing []+    _ <- doLoop impl+    ret++instance EvtModule PulseH where+    startEvtLoop (PulseH server) fun = startPulseMaybe (fun [MonkyPlain "None"]) server fun+++--startSyncPulse+--    :: IO Bool+--startSyncPulse = do+--    impl <- getMainloopImpl+--    cxt <- getContext impl "monky" -- should we get the exe name?+--    var <- newEmptyMVar+--    setStateCallback cxt $ do+--        state <- getContextState cxt+--        case state of+--            ContextFailed -> do+--                hPutStrLn stderr "Could not connect to pulse :("+--                quitLoop impl (-1)+--                putMVar var False+--            ContextReady ->+--                putMVar var True+--            _ -> return ()+--    _ <- connectContext cxt Nothing []+--    _ <- forkIO . void $ doLoop impl+--    -- Should we care?+--    readMVar var++-- This (most of it) should move into pulseaudio package, not doing that yet.+-- instance PollModule PulseH where+--     initialize (PulseH _) = do+--         running <- startSyncPulse+--         if running+--            then return ()+--            else return ()+--     getOutput _ = return []++-- |Get the handle for pulse integration.+getPulseHandle+    :: Maybe String -- ^The servername (Nothing will use environment variable)+    -> IO PulseH+getPulseHandle = return . PulseH
Monky/Examples/Wifi.hs view
@@ -22,8 +22,13 @@ Maintainer  : ongy Stability   : experimental Portability : Linux++FormatSignal only makes sense when used in a pollModule. But even in pollModule+context updates may take a while because of some buffering by drivers or+netlink subsystem. -} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-} module Monky.Examples.Wifi   ( getWifiHandle@@ -33,6 +38,8 @@ where  import Formatting+import Data.Word (Word32, Word8)+import Data.Int (Int32) import Data.Text (Text) import qualified Data.Text as T import Data.Maybe (fromMaybe)@@ -56,7 +63,7 @@   | FormatRates -- ^Print the current network max supported rate (always 54Mbit/s for me)   | FormatName -- ^Print the ESSID of the current network, may look weird because SSIDs are   | FormatFreq -- ^Print the frequency the current network sends on (related to channel)-  | FormatMBM -- ^I think something something signal strength+  | FormatSignal -- ^Print link quality (0-100)   | FormatText Text -- ^Print a plaintext string  getFun :: WifiFormat -> WifiStats -> Text@@ -64,12 +71,27 @@ getFun FormatRates      = flip convertUnitSI "B" . maximum . wifiRates getFun FormatName       = T.pack . wifiName getFun FormatFreq       = sformat int . wifiFreq-getFun FormatMBM        = sformat int . wifiMBM+getFun FormatSignal     = sformat int . doStrength . wifiSig getFun (FormatText str) = const str  getFunction :: [WifiFormat] -> WifiStats -> Text getFunction xs = T.concat . (\a -> map (($ a) . getFun) xs) +-- |Do the calculation for MBM+-- This is taken from NetworkManager+doMBM :: Word32 -> Word8+doMBM e =+  let noiseFloor = -90+      signalMax  = -20+      work :: Int32 = fromIntegral e+      clamped :: Float = min signalMax $ max noiseFloor $ fromIntegral $ work `div` 100+      in floor (100 - 70 * ((signalMax - clamped) / (signalMax - noiseFloor)))++-- Helper for FormatSignal that splits signal types+doStrength :: Signal -> Word8+doStrength (SigMBM mbm) = doMBM mbm+doStrength (SigUNSPEC unspec) = unspec+ -- |Get a wifi handle getWifiHandle   :: [WifiFormat] -- ^Format "String" for output generation@@ -93,6 +115,7 @@ instance EvtModule WifiHandle where   startEvtLoop h@(WH s _ _ _) r = do     r =<< getOutput h+    prepareEvents s     loopFd h (getWifiFd s) r getEventOutput  instance PollModule WifiHandle where
Monky/Outputs/Dzen2.hs view
@@ -29,10 +29,11 @@ module Monky.Outputs.Dzen2   ( DzenOutput   , getDzenOut+  , getDzenOut'   ) where -import Data.Composition ((.:))+import System.Directory(getCurrentDirectory) import System.IO (hFlush, stdout) import Monky.Modules @@ -86,4 +87,14 @@   :: Int -- ^The height of your dzen bar in pixel (required for block-drawing)   -> Text -- ^Path to the directory cointaining your .xbm files.   -> IO DzenOutput-getDzenOut = return .: DzenOutput+getDzenOut h = return . DzenOutput h . flip T.append "/"+++-- |Get the output handle for dzen2 formatting. Will asume your .xbm files are+-- |in <monkydir>/xbm/+getDzenOut'+    :: Int -- ^The height of your dzen bar in pixel (for block drawing)+    -> IO DzenOutput+getDzenOut' h = do+    pwd <- getCurrentDirectory+    getDzenOut h (T.pack pwd `T.append` "/xbm/")
Monky/Outputs/Fallback.hs view
@@ -52,6 +52,7 @@   doLine (WO o) = doLine o  +-- |Lowerlevel access to guess which terminal out to use based on system encoding chooseTerminalOut :: IO WrapOuts chooseTerminalOut = do   l <- getLocaleEncoding
Monky/Outputs/Guess.hs view
@@ -1,6 +1,32 @@+{-+    Copyright 2016 Markus Ongyerth++    This file is part of Monky.++    Monky is free software: you can redistribute it and/or modify+    it under the terms of the GNU Lesser General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    Monky is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU Lesser General Public License for more details.++    You should have received a copy of the GNU Lesser General Public License+    along with Monky.  If not, see <http://www.gnu.org/licenses/>.+-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE CPP #-}+{-|+Module      : Monky.Outputs.Guess+Description : Guess the output that should be used based on pipe+Maintainer  : ongy+Stability   : testing+Portability : Linux++-} module Monky.Outputs.Guess   ( guessOutput   , GuessOut@@ -15,7 +41,6 @@ import Data.Maybe (catMaybes) import System.Directory (getDirectoryContents) import System.IO (hIsTerminalDevice, stdout)-import System.IO.Error (IOError) import System.Posix.Files (readSymbolicLink)  import Monky.Modules@@ -36,6 +61,7 @@   | Other   deriving (Eq, Ord, Show) +-- | Type wrapper for this to work data GuessOut = forall a . MonkyOutput a => GO a  instance MonkyOutput GuessOut where@@ -100,10 +126,11 @@   -> IO GuessOut chooseProcessOut height path x   | x == "dzen2" = GO <$> getDzenOut height path-  | x == "i3-bar" = GO <$> getI3Output+  | x == "i3bar" = GO <$> getI3Output   | x `elem`networkOuts = GO <$> getSerializeOut   | otherwise = GO <$> getShowOut +-- | Guess output based on isatty and other side of the stdout fd guessOutput   :: Int -- ^Dzen height   -> Text -- ^Dzen xbm path
Monky/Outputs/I3.hs view
@@ -24,7 +24,11 @@ Stability   : testing Portability : Linux -This module provides the output generation for i3-bar outputs+This module provides the output generation for i3-bar outputs.+Do note, if you are using this output, you have to compile monky+once before you are piping it to i3-bar.+GHC will output something during compilation step, this can't be avoided+by monky, this will break the output. -} module Monky.Outputs.I3   ( I3Output
Monky/Wifi.hs view
@@ -34,12 +34,16 @@   , Interface   , SSIDSocket   , getWifiFd+  , prepareEvents +  , Signal(..)   , WifiStats(..)   , WifiConn(..)   ) where +import Debug.Trace+ import Data.Bits ((.&.)) import Data.Word (Word8, Word32) import Data.Maybe (listToMaybe, fromMaybe)@@ -75,13 +79,18 @@   | WifiDisconnect -- ^The current network was disconnectd   | WifiConnect WifiStats -- ^A new connection was established +-- |Signal type: http://lxr.free-electrons.com/source/net/wireless/nl80211.c#L6944+data Signal+  = SigMBM Word32 -- ^Signal MBM+  | SigUNSPEC Word8 -- ^Strength 0-100 http://lxr.mein.io/source/iwinfo/api/nl80211.h#L3388+ -- |Wifi network connection information data WifiStats = WifiStats   { wifiChannel :: Word8   , wifiRates :: [Word32]   , wifiName :: String   , wifiFreq :: Word32-  , wifiMBM :: Word32+  , wifiSig :: Signal   }  -- Unsafe decode, we rely on kernel to be sensible@@ -98,7 +107,13 @@     (Left _)  -> Nothing     (Right x) -> return x +-- |Convert raw values from netlink+getSignal :: Maybe Word32 -> Maybe Word8 -> Signal+getSignal Nothing    (Just unspec) = SigUNSPEC unspec+getSignal (Just mbm) Nothing       = SigMBM mbm+getSignal x          y             = error ("Wifi signal is weird, should be either, got: " ++ show x ++ " and " ++ show y) +-- |Get WifiStats from netlink message attrToStat :: NL80211Packet -> Maybe WifiStats attrToStat pack = do   pattrs <- getBssAttrs $ packetAttributes pack@@ -109,19 +124,20 @@   rate <- M.lookup eWLAN_EID_SUPP_RATES attrs    freq <- uDecode . M.lookup eNL80211_BSS_FREQUENCY $ pattrs-  mbm <- uDecode . M.lookup eNL80211_BSS_SIGNAL_MBM $ pattrs+  let mbm = uGetWord32 . M.lookup eNL80211_BSS_SIGNAL_MBM $ pattrs+  let sig = uDecode . M.lookup eNL80211_BSS_SIGNAL_UNSPEC $ pattrs    let bs = M.lookup eWLAN_EID_EXT_SUPP_RATES attrs   let ratL = rate `BS.append` fromMaybe BS.empty bs   let rates = map (\y -> fromIntegral (y .&. 0x7F) * (500000 :: Word32)) . BS.unpack $ ratL -  return $ WifiStats channel rates name freq mbm+  return $ WifiStats channel rates name freq $getSignal mbm sig  -- |Get the stats of a currently connected wifi network getCurrentWifiStats :: SSIDSocket -> Interface -> IO (Maybe WifiStats) getCurrentWifiStats s i = do   wifis <- getConnectedWifi s i-  return $ attrToStat =<< listToMaybe wifis+  return $ attrToStat =<< listToMaybe (trace ("conn: " ++ show wifis) wifis)   -- |Get only the name of the currently connected wifi@@ -167,10 +183,13 @@               else return WifiNone           else return WifiNone +-- |Subscribe to multicast group+prepareEvents :: SSIDSocket -> IO ()+prepareEvents s = joinMulticastByName s "mlme" --- |Get a netlink socket bound to nl80211 mlme Group+-- |Get a netlink socket bound to nl80211+-- Before this is used event based, call 'prepareEvents' getSSIDSocket :: IO SSIDSocket getSSIDSocket = do   s <- makeNL80211Socket-  joinMulticastByName s "mlme"   return s
bin/Main.hs view
@@ -51,6 +51,7 @@ import System.IO (withFile, IOMode(..), hPutStr, hPutStrLn, stderr) import System.Posix.Process (executeFile) import System.Process (system)+import Data.Monoid ((<>))  import Options.Applicative 
monky.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             2.0.1.0+version:             2.1.0.0  -- The ABOVE LINE has to stay AS IS (except for version changes) for the -- template to work properly@@ -96,6 +96,10 @@   Description: enable ibus example   Default: False +Flag pulse+  Description: enable pulse example (7.6 disabled because travis)+  Default: True+ Source-repository head   type:       git   location:   https://github.com/monky-hs/monky@@ -128,12 +132,13 @@  library   exposed-modules: Monky.Disk Monky.Modules Monky.Time Monky.CPU Monky.Memory Monky.Network Monky.Utility Monky.Alsa Monky.Battery Monky-  exposed-modules: Monky.Examples.Alsa Monky.Examples.Battery Monky.Examples.CPU Monky.Examples.Disk Monky.Examples.Network Monky.Examples.Time Monky.Examples.Memory+  exposed-modules: Monky.Examples.Battery Monky.Examples.CPU Monky.Examples.Disk Monky.Examples.Network Monky.Examples.Time Monky.Examples.Memory   exposed-modules: Monky.Disk.Btrfs Monky.Disk.Device   exposed-modules: Monky.Examples.Prepend Monky.Connectivity   exposed-modules: Monky.Wifi Monky.Examples.Wifi   exposed-modules: Monky.Examples.Connectivity Monky.Network.Dynamic   exposed-modules: Monky.Network.Static Monky.Examples.File Monky.Examples.Utility+  exposed-modules: Monky.Examples.Sound.Alsa  Monky.Examples.Alsa     exposed-modules: Monky.Version Monky.Examples.Combine   exposed-modules: Monky.Examples.Plain Monky.Disk.Common Monky.Blkid@@ -147,7 +152,7 @@     build-depends:       base >=4.6.0.1 && <=5, directory, time-  build-depends:       text, unix, network, mtl, transformers, text+  build-depends:       text, unix, network, mtl, transformers   build-depends:       template-haskell, containers, stm, statvfs   build-depends:       bytestring, netlink, cereal, formatting, composition   build-depends:       env-locale >= 1.0.0.1@@ -165,6 +170,11 @@   if flag(ibus)     build-depends: ibus-hs, dbus     exposed-modules: Monky.Examples.IBus++  if impl(ghc >= 7.8)+    if flag(pulse)+      build-depends: pulseaudio+      exposed-modules: Monky.Examples.Sound.Pulse    ghc-options:         -Wall   extra-libraries: