xmobar 0.13 → 0.14
raw patch · 24 files changed
+1185/−219 lines, 24 filesdep +alsa-coredep +timezone-olsondep +timezone-seriesdep ~libmpd
Dependencies added: alsa-core, timezone-olson, timezone-series
Dependency ranges changed: libmpd
Files
- NEWS +42/−0
- README +101/−57
- src/Commands.hs +3/−4
- src/Config.hs +9/−1
- src/Localize.hsc +85/−0
- src/Main.hs +2/−5
- src/Parsers.hs +3/−2
- src/Plugins/DateZone.hs +72/−0
- src/Plugins/Kbd.hsc +397/−0
- src/Plugins/Monitors.hs +4/−0
- src/Plugins/Monitors/Batt.hs +49/−39
- src/Plugins/Monitors/Bright.hs +118/−0
- src/Plugins/Monitors/CoreCommon.hs +122/−38
- src/Plugins/Monitors/CoreTemp.hs +5/−7
- src/Plugins/Monitors/Cpu.hs +2/−2
- src/Plugins/Monitors/CpuFreq.hs +7/−11
- src/Plugins/Monitors/MPD.hs +1/−1
- src/Plugins/Monitors/Top.hs +1/−0
- src/Plugins/Monitors/Volume.hs +4/−1
- src/Plugins/Monitors/Wireless.hs +3/−4
- src/StatFS.hsc +6/−2
- src/XUtil.hsc +14/−2
- src/Xmobar.hs +106/−32
- xmobar.cabal +29/−11
NEWS view
@@ -1,6 +1,45 @@ % xmobar - Release notes % Jose A. Ortega Ruiz +## Version 0.14++_New features_++ - New brightness monitor, courtesy of Martin Perner.+ - New DateZone plugin, for configurable timezone and localized+ datetimes, also by Martin.+ - New keyboard layout monitor (Kbd). Yes, by Martin.+ - Rewrite of the event handling ([issue 53], [issue 57]), you+ guessed it.+ - Cpu monitor now also reports `iowait` field ([issue 55]).+ - Battery monitor: the full charge file is now settable in the+ monitor arguments (olpc systems use charge_full_design; see [issue 62]).++_Bug fixes_++ - [issue 45]: Fix for crashes with AC status changes in battery monitor.+ - [issue 48]: The <quality> field of Wireless behaves like a percentage.+ - [issue 50]/[issue 61]: `MPD` monitor now works with libmpd 0.6.+ - [issue 60]: Fixes for crashes on power resume for battery monitor.+ - Template sections without fields are now correctly displayed.+ - Catch errors when reading battery status (Ben Boeckel).+ - Compilation issues with ghc 7.x (Sergei Trofimovich).+ - Fixes for CoreTemp monitor in new kernels (Norbert Zeh).+ - Fix for pulseaudio problems in volume monitor (Martin Perner).+ - Fix for parsing errors when a `Run` entry ended in an array+ (Martin).+ - Fixed compilation in OpenBSD (Ivo van der Sangen).++[issue 45]: http://code.google.com/p/xmobar/issues/detail?id=45+[issue 48]: http://code.google.com/p/xmobar/issues/detail?id=48+[issue 50]: http://code.google.com/p/xmobar/issues/detail?id=50+[issue 53]: http://code.google.com/p/xmobar/issues/detail?id=53+[issue 55]: http://code.google.com/p/xmobar/issues/detail?id=55+[issue 57]: http://code.google.com/p/xmobar/issues/detail?id=57+[issue 60]: http://code.google.com/p/xmobar/issues/detail?id=60+[issue 61]: http://code.google.com/p/xmobar/issues/detail?id=61+[issue 62]: http://code.google.com/p/xmobar/issues/detail?id=62+ ## Version 0.13 (March 28, 2011) _New features_@@ -15,6 +54,9 @@ _Incompatible changes_ + - In the process of solving [issue 14], we've broken those+ configurations that rely on including alignment separators in the+ input fed to `StdinReader`. - The MPD plugin does not accept host and port options anymore: use the environment variables MPD_HOST and MPD_PORT instead. - The `Mail` plugin now takes a second parameter (a string)
README view
@@ -1,5 +1,4 @@ % xmobar - A Minimalistic Text Based Status Bar-% Andrea Rossato, Jose A. Ortega Ruiz About =====@@ -12,19 +11,27 @@ features, like dynamic color management, output templates, and extensibility through plugins. -This page documents xmobar 0.13 (see [release notes]).+This page documents xmobar 0.14 (see [release notes]). [This is a screen shot] of Andrea's desktop with [xmonad] and xmobar.-[This] is xmobar running under [sawfish], with antialiased fonts. And-[this one] is my desktop with [xmonad] and two instances of xmobar.+[This screenshot] shows xmobar running under [sawfish], with+antialiased fonts. And [this one] is my desktop with [xmonad] and two+instances of xmobar. [release notes]: http://projects.haskell.org/xmobar/releases.html [xmonad]: http://xmonad.org [Ion3]: http://tuomov.iki.fi/software/-[This is a screen shot]: http://haskell.org/sitewiki/images/a/ae/Arossato-config.png-[This]: http://projects.haskell.org/xmobar/xmobar-sawfish.png+[This screenshot]: http://projects.haskell.org/xmobar/xmobar-sawfish.png [this one]: http://projects.haskell.org/xmobar/xmobar-xmonad.png +Bug Reports+===========++To submit bug reports you can use the [bug tracker over at Google+code] or send mail to our [Mailing list].++[bug tracker over at Google code]: http://code.google.com/p/xmobar/issues+ Installation ============ @@ -46,7 +53,7 @@ If you don't have `cabal-install` installed, you can get xmobar's source code in a variety of ways: - - From [Hackage]. Just download [xmobar-0.13.tar.gz] from xmobar's+ - From [Hackage]. Just download [xmobar-0.14.tar.gz] from xmobar's hackage page. - From [Github]. You can also obtain a tarball in [Github's downloads page]. You'll find there links to each tagged release.@@ -55,13 +62,13 @@ git: git clone git://github.com/jaor/xmobar -[xmobar-0.13.tar.gz]: http://hackage.haskell.org/packages/archive/xmobar/0.13/xmobar-0.13.tar.gz+[xmobar-0.14.tar.gz]: http://hackage.haskell.org/packages/archive/xmobar/0.14/xmobar-0.14.tar.gz [Github's downloads page]: https://github.com/jaor/xmobar/downloads To install simply run (if needed): - tar xvfz xmobar-0.13- cd xmobar-0.13+ tar xvfz xmobar-0.14+ cd xmobar-0.14 If you have cabal installed, you can now use it from within xmobar's source tree. Otherwise, run the configure script:@@ -124,6 +131,10 @@ : Support for ALSA sound cards. Enables the Volume plugin. Requires the [alsa-mixer] package. +`with_datezone`+: Support for other timezones. Enables the DateZone plugin.+ Requires [timezone-olson] and [timezone-series] package.+ `all_extensions` : Enables all the extensions above. @@ -140,6 +151,14 @@ if you have the default configuration file saved as `~/.xmobarrc` +### Signal Handling++Since 0.14 xmobar reacts to SIGUSR1 and SIGUSR2:++- After receiving SIGUSR1 xmobar moves its position to the next screen.++- After receiving SIGUSR2 xmobar repositions it self on the current screen.+ Configuration ============= @@ -225,26 +244,13 @@ `template` : The output template. -## Running xmobar with i3status--xmobar can be used to display information gathered by [i3status], a-small program that gathers information and formats it suitable for-being displayed by the dzen2 status bar, wmii's status bar or xmobar's-StdinReader.--Since xmobar support has been added only recently you need to get the-git repository, and build it with the appropriate flags:-- git clone git://code.stapelberg.de/i3status--and then build it:-- cd i3status- make EXTRA_CFLAGS="-DXMOBAR--Then you can run it with:+### Running xmobar with i3status - ./i3status -c i3status.conf | xmobar -o -t "%StdinReader%" -c "[Run StdinReader]"+xmobar can be used to display information generated by [i3status], a+small program that gathers system information and outputs it in+formats suitable for being displayed by the dzen2 status bar, wmii's+status bar or xmobar's `StdinReader`. See [i3status manual] for+further details. ## Command Line Options @@ -313,13 +319,8 @@ The only internal available command is `Com` (see below Executing External Commands). All other commands are provided by plugins. xmobar comes with some plugins, providing a set of system monitors, a-standard input reader, an Unix named pipe reader, and a configurable-date plugin. These plugins install the following internal commands:-`Weather`, `Network`, `Wireless` (optional), `Memory`, `Swap`, `Cpu`,-`MultiCpu`, `Battery`, `TopProc`, `TopMem`, `DiskU`, `DiskIO`,-`Thermal`, `ThermalZone`, `CpuFreq`, `CoreTemp`, `Volume` (optional),-`MPD` (optional), `Mail` (optional), `MBox` (optional), `Date`,-`Uptime`, `StdinReader`, `CommandReader`, and `PipeReader`.+standard input reader, an Unix named pipe reader, a configurable date+plugin, and much more: we list all available plugins below. To remove them see below Installing/Removing a Plugin @@ -403,7 +404,7 @@ - Aliases to `cpu` - Args: default monitor arguments (see below) - Variables that can be used with the `-t`/`--template` argument:- `total`, `bar`, `user`, `nice`, `system`, `idle`+ `total`, `bar`, `user`, `nice`, `system`, `idle`, `iowait` - Default template: `Cpu: <total>%` `MultiCpu Args RefreshRate`@@ -441,6 +442,10 @@ - `-p`: color to display positive power (battery charging) - `-f`: file in `/sys/class/power_supply` with AC info (default: "AC/online")+ - `-c`: file in `/sys/class/power/<BAT>/` with full charge+ information (default: "charge_full"; for instance, olpc systems+ use "charge_full_design")+ - Variables that can be used with the `-t`/`--template` argument: `left`, `leftbar`, `timeleft`, `watts`, `acstatus` - Default template: `Batt: <watts>, <left>% / <timeleft>`@@ -452,7 +457,8 @@ "-L", "10", "-H", "80", "-p", "3", "--", "-O", "<fc=green>On</fc> - ", "-o", "", "-L", "-15", "-H", "-5",- "-l", "red", "-m", "blue", "-h", "green"]+ "-l", "red", "-m", "blue", "-h", "green",+ "-c", "charge_full_design"] 600 In the above example, the thresholds before the "--" separator refer to the `<left>` field, while those after the separator affect@@ -599,10 +605,12 @@ - `--lowd` _number_ Low threshold for dB. Defaults to -30.0. - Variables that can be used with the `-t`/`--template` argument: `volume`, `volumebar`, `dB`, `status`+- Note that `dB` might only return 0 on your system. This is known+ to happen on systems with a pulseaudio backend. - Default template: `Vol: <volume>% <status>`-- Requires the package [alsa-mixer] installed in your system. In addition,- to activate this plugin you must pass `--flags="with_alsa"` during- compilation.+- Requires the package [alsa-core] and [alsa-mixer] installed in your+ system. In addition, to activate this plugin you must pass+ `--flags="with_alsa"` during compilation. `MPD Args RefreshRate` @@ -679,6 +687,36 @@ [samples/xmonadpropwrite.hs script]: https://github.com/jaor/xmobar/raw/master/samples/xmonadpropwrite.hs +`Brightness Args RefreshRate`++- Aliases to `bright`+- Args: default monitor arguments (see below), plus the following specif ones:+ - `-D`: directory in `/sys/class/backlight/` with files in it+ (default: "acpi_video0")+ - `-C`: file with the current brightness (default:+ actual_brightness)+ - `-M`: file with the maximum brightness (default:+ max_brigtness)+- Variables that can be used with the `-t`/`--template` argument:+ `hbar`, `percent`, `bar`+- Default template: `<percent>`+- Example:++ Run Brightness ["-t", "<bar>"] 60++`Kbd Opts`++- Registers to XKB/X11-Events and output the currently active keyboard layout.+ Supports replacement of layoutnames.+- Aliases to `kbd`+- Opts is a list of tuple:+ - first element of the tuple is the search string+ - second element of the tuple is the corresponding replacement+- Example:++ Run Kbd [("us(dvorak)", "DV"), ("us", "US")]++ ## Monitor Plugins Commands Arguments These are the arguments that can be used for internal commands in the@@ -828,6 +866,19 @@ `strftime` function (or Haskell's `formatCalendarTime`). - Sample usage: `Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10` +`DateZone Format Locale Zone Alias RefreshRate`++- Format is a time format string, as accepted by the standard ISO C+ `strftime` function (or Haskell's `formatCalendarTime`).+- If Locale is "" the default locale of the system is used, otherwise the given+ locale. If there are more instances of DateZone, using "" as input for Locale+ is not recommended.+- Zone is the name of the TimeZone. It is assumed that the tz database is stored+ in /usr/share/zoneinfo/. If "" is given as Zone, the default system time is+ used.+- Sample usage:+ `Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10`+ `CommandReader "/path/to/program" Alias` - Runs the given program, and displays its standard output.@@ -971,23 +1022,15 @@ 3. rebuild xmobar. -Bug Reports-===========--To submit bug reports you can use the [bug tracker over at Google-code] or send mail to our [Mailing list].--[bug tracker over at Google code]: http://code.google.com/p/xmobar/issues- Credits ======= xmobar [incorporates patches] by Ben Boeckel, Roman Cheplyaka, John Goerzen, Juraj Hercek, Tomas Janousek, Spencer Janssen, Lennart-Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Svein Ove, Jens-Petersen, Petr Rockai, Andrew Sackville-West, Alexander Solovyov,-Sergei Trofimovich, Thomas Tuegel, Jan Vornberger, Daniel Wagner and-Norbert Zeh.+Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Svein Ove,+Martin Perner, Jens Petersen, Petr Rockai, Andrew Sackville-West,+Alexander Solovyov, Sergei Trofimovich, Thomas Tuegel, Jan Vornberger,+Daniel Wagner and Norbert Zeh. [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors @@ -1011,7 +1054,6 @@ - [Github page]. - [Mailing list]. - [xmobar's Ohloh page].-- Andrea's original [xmobar] home page, and [xmobar darcs repository]. - To understand the internal mysteries of xmobar you may try reading [this tutorial] on X Window Programming in Haskell.@@ -1020,8 +1062,6 @@ in [sawfish]. [xmobar's Ohloh page]: https://www.ohloh.net/p/xmobar-[xmobar]: http://code.haskell.org/~arossato/xmobar/-[xmobar darcs repository]: http://code.haskell.org/xmobar [this tutorial]: http://www.haskell.org/haskellwiki/X_window_programming_in_Haskell [sawflibs]: http://github.com/jaor/sawflibs @@ -1049,10 +1089,14 @@ [Mailing list]: http://projects.haskell.org/cgi-bin/mailman/listinfo/xmobar [MPD]: http://mpd.wikia.com/ [X11-xft]: http://hackage.haskell.org/package/X11-xft/-[i3status]: http://i3.zekjur.net/i3status/+[i3status]: http://i3wm.org/i3status/+[i3status manual]: http://i3wm.org/i3status/manpage.html#_using_i3status_with_xmobar [iwlib]: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html [hinotify]: http://hackage.haskell.org/package/hinotify/ [libmpd]: http://hackage.haskell.org/package/libmpd/ [sawfish]: http://sawfish.wikia.com/ [utf8-string]: http://hackage.haskell.org/package/utf8-string/+[alsa-core]: http://hackage.haskell.org/package/alsa-core [alsa-mixer]: http://hackage.haskell.org/package/alsa-mixer+[timezone-olson]: http://hackage.haskell.org/package/timezone-olson+[timezone-series]: http://hackage.haskell.org/package/timezone-series
src/Commands.hs view
@@ -75,8 +75,7 @@ -- is not possible to set a thread delay grater than about 45 minutes. -- With a little recursion we solve the problem. tenthSeconds :: Int -> IO ()-tenthSeconds s | s >= x = do threadDelay y- tenthSeconds (x - s)+tenthSeconds s | s >= x = do threadDelay (x * 100000)+ tenthSeconds (s - x) | otherwise = threadDelay (s * 100000)- where y = maxBound :: Int- x = y `div` 100000+ where x = (maxBound :: Int) `div` 100000
src/Config.hs view
@@ -32,12 +32,17 @@ import Plugins.StdinReader import Plugins.XMonadLog import Plugins.EWMH+import Plugins.Kbd #ifdef INOTIFY import Plugins.Mail import Plugins.MBox #endif +#ifdef DATEZONE+import Plugins.DateZone+#endif+ -- $config -- Configuration data type and default configuration @@ -108,9 +113,12 @@ -- the 'Runnable.Runnable' Read instance. To install a plugin just add -- the plugin's type to the list of types (separated by ':*:') appearing in -- this function's type signature.-runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*:+runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*: Kbd :*: #ifdef INOTIFY Mail :*: MBox :*:+#endif+#ifdef DATEZONE+ DateZone :*: #endif () runnableTypes = undefined
+ src/Localize.hsc view
@@ -0,0 +1,85 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-----------------------------------------------------------------------------+-- |+-- Module : Localize+-- Copyright : (C) 2011 Martin Perner+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Martin Perner <martin@perner.cc>+-- Stability : unstable+-- Portability : unportable+--+-- This module provides an interface to locale information e.g. for DateL+--+-----------------------------------------------------------------------------++module Localize+ ( setupTimeLocale,+ getTimeLocale+ ) where++import Foreign.C+import qualified System.Locale as L++#ifdef UTF8+import Codec.Binary.UTF8.String+#endif++-- get localized strings+type NlItem = CInt++#include <langinfo.h>+foreign import ccall unsafe "langinfo.h nl_langinfo"+ nl_langinfo :: NlItem -> IO CString++#{enum NlItem,+ , AM_STR , PM_STR \+ , D_T_FMT , D_FMT , T_FMT , T_FMT_AMPM \+ , ABDAY_1, ABDAY_7 \+ , DAY_1, DAY_7 \+ , ABMON_1, ABMON_12 \+ , MON_1, MON_12\+ }++getLangInfo :: NlItem -> IO String+getLangInfo item = do+ itemStr <- nl_langinfo item+#ifdef UTF8+ str <- peekCString itemStr+ return $ decodeString str+#else+ peekCString itemStr+#endif++#include <locale.h>+foreign import ccall unsafe "locale.h setlocale"+ setlocale :: CInt -> CString -> IO CString++setupTimeLocale :: String -> IO ()+setupTimeLocale l = withCString l (setlocale #const LC_TIME) >> return ()++getTimeLocale :: IO L.TimeLocale+getTimeLocale = do+ -- assumes that the defined values are increasing by exactly one.+ -- as they are defined consecutive in an enum this is reasonable+ days <- mapM getLangInfo [day1 .. day7]+ abdays <- mapM getLangInfo [abday1 .. abday7]++ mons <- mapM getLangInfo [mon1 .. mon12]+ abmons <- mapM getLangInfo [abmon1 .. abmon12]++ amstr <- getLangInfo amStr+ pmstr <- getLangInfo pmStr+ dtfmt <- getLangInfo dTFmt+ dfmt <- getLangInfo dFmt+ tfmt <- getLangInfo tFmt+ tfmta <- getLangInfo tFmtAmpm++ let t = L.defaultTimeLocale {L.wDays = zip days abdays+ ,L.months = zip mons abmons+ ,L.amPm = (amstr, pmstr)+ ,L.dateTimeFmt = dtfmt+ ,L.dateFmt = dfmt+ ,L.timeFmt = tfmt+ ,L.time12Fmt = tfmta}+ return t
src/Main.hs view
@@ -41,6 +41,7 @@ -- | The main entry point main :: IO () main = do+ initThreads d <- openDisplay "" args <- getArgs (o,file) <- getOpts args@@ -51,16 +52,12 @@ unless (null defaultings) $ putStrLn $ "Fields missing from config defaulted: " ++ intercalate "," defaultings - -- listen for ConfigureEvents on the root window, for xrandr support:- rootw <- rootWindow d (defaultScreen d)- selectInput d rootw structureNotifyMask- conf <- doOpts c o fs <- initFont d (font conf) cls <- mapM (parseTemplate conf) (splitTemplate conf) vars <- mapM (mapM startCommand) cls (r,w) <- createWin d fs conf- eventLoop (XConf d r w fs conf) vars+ startLoop (XConf d r w fs conf) vars -- | Splits the template in its parts splitTemplate :: Config -> [String]
src/Parsers.hs view
@@ -87,7 +87,7 @@ parseTemplate :: Config -> String -> IO [(Runnable,String,String)] parseTemplate c s = do str <- case parse (templateParser c) "" s of- Left _ -> return [("","","")]+ Left _ -> return [("", s, "")] Right x -> return x let cl = map alias (commands c) m = Map.fromList $ zip cl (commands c)@@ -159,7 +159,8 @@ return ("Static {" ++ p ++ "}") tillFieldEnd = staticPos <|> many (noneOf ",}\n\r") - commandsEnd = wrapSkip (string "]") >> oneOf "},"+ commandsEnd = wrapSkip (string "]") >> (string "}" <|> notNextRun)+ notNextRun = do { string ","; notFollowedBy $ wrapSkip $ string "Run"; return ","} readCommands = manyTill anyChar (try commandsEnd) >>= read' commandsErr . flip (++) "]" strField e n = field e n . between (strDel "start" n) (strDel "end" n) . many $ noneOf "\"\n\r"
+ src/Plugins/DateZone.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE DoAndIfThenElse #-}+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.DateZone+-- Copyright : (c) Martin Perner+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Martin Perner <martin@perner.cc>+-- Stability : unstable+-- Portability : unportable+--+-- A date plugin with localization and location support for Xmobar+--+-- Based on Plugins.Date+--+-- Usage example: in template put+--+-- > Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "UTC" "utcDate" 10+--+-----------------------------------------------------------------------------++module Plugins.DateZone (DateZone(..)) where++import Plugins++import Localize++import Control.Concurrent.STM++import Data.Time.LocalTime+import Data.Time.Format+import Data.Time.LocalTime.TimeZone.Olson+import Data.Time.LocalTime.TimeZone.Series++import System.IO.Unsafe+import System.Locale (TimeLocale)+import System.Time++++{-# NOINLINE localeLock #-}+-- ensures that only one plugin instance sets the locale+localeLock :: TMVar Bool+localeLock = unsafePerformIO (newTMVarIO False)++data DateZone = DateZone String String String String Int+ deriving (Read, Show)++instance Exec DateZone where+ alias (DateZone _ _ _ a _) = a+ start (DateZone f l z _ r) cb = do+ lock <- atomically $ takeTMVar localeLock+ setupTimeLocale l+ locale <- getTimeLocale+ atomically $ putTMVar localeLock lock+ if z /= "" then do+ timeZone <- getTimeZoneSeriesFromOlsonFile ("/usr/share/zoneinfo/" ++ z)+ go (dateZone f locale timeZone)+ else+ go (date f locale)++ where go func = func >>= cb >> tenthSeconds r >> go func++date :: String -> TimeLocale -> IO String+date format loc = do+ t <- toCalendarTime =<< getClockTime+ return $ formatCalendarTime loc format t++dateZone :: String -> TimeLocale -> TimeZoneSeries -> IO String+dateZone format loc timeZone = do+ zonedTime <- getZonedTime+ return $ formatTime loc format $ utcToLocalTime' timeZone $ zonedTimeToUTC zonedTime
+ src/Plugins/Kbd.hsc view
@@ -0,0 +1,397 @@+{-# LANGUAGE ScopedTypeVariables, ForeignFunctionInterface, MultiParamTypeClasses, DeriveDataTypeable, FlexibleInstances, PatternGuards #-}+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Kbd+-- Copyright : (c) Martin Perner+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Martin Perner <martin@perner.cc>+-- Stability : unstable+-- Portability : unportable+--+-- A keyboard layout indicator for Xmobar+--+-----------------------------------------------------------------------------++module Plugins.Kbd where++import Graphics.X11.Xlib+import Graphics.X11.Xlib.Extras+import Foreign+import Foreign.C.Types (CUInt,CULong,CInt,CUShort,CChar,CUChar)+import Foreign.C.String+import Plugins+import Control.Monad (forever)+import XUtil (nextEvent')+import Data.List (isPrefixOf, findIndex)+import Data.Maybe (fromJust)++#include <X11/XKBlib.h>+#include <X11/extensions/XKB.h>+#include <X11/extensions/XKBstr.h>++-- +-- Definition for XkbStaceRec and getKbdLayout taken from+-- XMonad.Layout.XKBLayout+--+data XkbStateRec = XkbStateRec {+ group :: CUChar,+ locked_group :: CUChar,+ base_group :: CUShort,+ latched_group :: CUShort,+ mods :: CUChar,+ base_mods :: CUChar,+ latched_mods :: CUChar,+ locked_mods :: CUChar,+ compat_state :: CUChar,+ grab_mods :: CUChar,+ compat_grab_mods :: CUChar,+ lookup_mods :: CUChar,+ compat_lookup_mods :: CUChar,+ ptr_buttons :: CUShort+}++instance Storable XkbStateRec where+ sizeOf _ = (#size XkbStateRec)+ alignment _ = alignment (undefined :: CUShort)+ peek ptr = do+ r_group <- (#peek XkbStateRec, group) ptr+ r_locked_group <- (#peek XkbStateRec, locked_group) ptr+ r_base_group <- (#peek XkbStateRec, base_group) ptr+ r_latched_group <- (#peek XkbStateRec, latched_group) ptr+ r_mods <- (#peek XkbStateRec, mods) ptr+ r_base_mods <- (#peek XkbStateRec, base_mods) ptr+ r_latched_mods <- (#peek XkbStateRec, latched_mods) ptr+ r_locked_mods <- (#peek XkbStateRec, locked_mods) ptr+ r_compat_state <- (#peek XkbStateRec, compat_state) ptr+ r_grab_mods <- (#peek XkbStateRec, grab_mods) ptr+ r_compat_grab_mods <- (#peek XkbStateRec, compat_grab_mods) ptr+ r_lookup_mods <- (#peek XkbStateRec, lookup_mods) ptr+ r_compat_lookup_mods <- (#peek XkbStateRec, compat_lookup_mods) ptr+ r_ptr_buttons <- (#peek XkbStateRec, ptr_buttons) ptr+ return XkbStateRec {+ group = r_group,+ locked_group = r_locked_group,+ base_group = r_base_group,+ latched_group = r_latched_group,+ mods = r_mods,+ base_mods = r_base_mods,+ latched_mods = r_latched_mods,+ locked_mods = r_locked_mods,+ compat_state = r_compat_state,+ grab_mods = r_grab_mods,+ compat_grab_mods = r_compat_grab_mods,+ lookup_mods = r_lookup_mods,+ compat_lookup_mods = r_compat_lookup_mods,+ ptr_buttons = r_ptr_buttons+ }++foreign import ccall unsafe "X11/XKBlib.h XkbGetState"+ xkbGetState :: Display -> CUInt -> Ptr XkbStateRec -> IO CInt+++getKbdLayout :: Display -> IO Int+getKbdLayout d = alloca $ \stRecPtr -> do+ xkbGetState d 0x100 stRecPtr+ st <- peek stRecPtr+ return $ fromIntegral (group st)++--+--+--++data XkbKeyNameRec = XkbKeyNameRec {+ name :: Ptr CChar -- array+}++--+-- the t_ before alias is just because of name collisions+--+data XkbKeyAliasRec = XkbKeyAliasRec {+ real :: Ptr CChar, -- array+ t_alias :: Ptr CChar -- array+} ++--+-- the t_ before geometry is just because of name collisions+--+data XkbNamesRec = XkbNamesRec {+ keycodes :: Atom,+ t_geometry :: Atom,+ symbols :: Atom,+ types :: Atom,+ compat :: Atom,+ vmods :: Ptr Atom,+ indicators :: Ptr Atom, -- array+ groups :: Ptr Atom, -- array+ keys :: Ptr XkbKeyNameRec,+ key_aliases :: Ptr CChar, -- dont care XkbKeyAliasRec,+ radio_groups :: Ptr Atom,+ phys_symbols :: Atom,+ num_keys :: CUChar,+ num_key_aliases :: CUChar,+ num_rg :: CUShort+}++--+-- the t_ before map, indicators and compat are just because of name collisions+--+data XkbDescRec = XkbDescRec {+ t_dpy :: Ptr CChar, -- struct _XDisplay* ; don't care+ flags :: CUShort,+ device_spec :: CUShort,+ min_key_code :: KeyCode,+ max_key_code :: KeyCode,+ ctrls :: Ptr CChar, -- XkbControlsPtr ; dont' care+ server :: Ptr CChar, -- XkbServerMapPtr ; dont' care+ t_map :: Ptr CChar, --XkbClientMapPtr ; dont' care+ t_indicators :: Ptr CChar, -- XkbIndicatorPtr ; dont' care+ names :: Ptr XkbNamesRec, -- array+ t_compat :: Ptr CChar, -- XkbCompatMap ; dont' care+ geom :: Ptr CChar -- XkbGeometryPtr ; dont' care++}++instance Storable XkbKeyNameRec where+ sizeOf _ = (#size XkbKeyNameRec)+ alignment _ = alignment (undefined :: CUShort)+ peek ptr = do+ r_name <- (#peek XkbKeyNameRec, name) ptr++ return XkbKeyNameRec {+ name = r_name+ }++instance Storable XkbKeyAliasRec where+ sizeOf _ = (#size XkbKeyAliasRec)+ alignment _ = alignment (undefined :: CUShort)+ peek ptr = do+ r_real <- (#peek XkbKeyAliasRec, real) ptr+ r_alias <- (#peek XkbKeyAliasRec, alias) ptr++ return XkbKeyAliasRec {+ real = r_real,+ t_alias = r_alias+ }++instance Storable XkbNamesRec where+ sizeOf _ = (#size XkbNamesRec)+ alignment _ = alignment (undefined :: CUShort)+ peek ptr = do+ r_keycodes <- (#peek XkbNamesRec, keycodes) ptr+ r_geometry <- (#peek XkbNamesRec, geometry) ptr+ r_symbols <- (#peek XkbNamesRec, symbols ) ptr+ r_types <- (#peek XkbNamesRec, types ) ptr+ r_compat <- (#peek XkbNamesRec, compat ) ptr + r_vmods <- (#peek XkbNamesRec, vmods ) ptr+ r_indicators <- (#peek XkbNamesRec, indicators ) ptr + r_groups <- (#peek XkbNamesRec, groups ) ptr + r_keys <- (#peek XkbNamesRec, keys ) ptr + r_key_aliases <- (#peek XkbNamesRec, key_aliases ) ptr+ r_radio_groups <- (#peek XkbNamesRec, radio_groups ) ptr + r_phys_symbols <- (#peek XkbNamesRec, phys_symbols ) ptr + r_num_keys <- (#peek XkbNamesRec,num_keys ) ptr+ r_num_key_aliases <- (#peek XkbNamesRec, num_key_aliases ) ptr+ r_num_rg <- (#peek XkbNamesRec, num_rg ) ptr++ return XkbNamesRec {+ keycodes = r_keycodes,+ t_geometry = r_geometry,+ symbols = r_symbols,+ types = r_types,+ compat = r_compat,+ vmods = r_vmods,+ indicators = r_indicators,+ groups = r_groups,+ keys = r_keys,+ key_aliases = r_key_aliases,+ radio_groups = r_radio_groups,+ phys_symbols = r_phys_symbols,+ num_keys = r_num_keys,+ num_key_aliases = r_num_key_aliases,+ num_rg = r_num_rg+ }++instance Storable XkbDescRec where+ sizeOf _ = (#size XkbDescRec)+ alignment _ = alignment (undefined :: CUShort)+ peek ptr = do+ r_dpy <- (#peek XkbDescRec, dpy) ptr+ r_flags <- (#peek XkbDescRec, flags) ptr+ r_device_spec <- (#peek XkbDescRec, device_spec) ptr+ r_min_key_code <- (#peek XkbDescRec, min_key_code) ptr+ r_max_key_code <- (#peek XkbDescRec, max_key_code) ptr+ r_ctrls <- (#peek XkbDescRec, ctrls) ptr+ r_server <- (#peek XkbDescRec, server) ptr+ r_map <- (#peek XkbDescRec, map) ptr+ r_indicators <- (#peek XkbDescRec, indicators) ptr+ r_names <- (#peek XkbDescRec, names) ptr+ r_compat <- (#peek XkbDescRec, compat) ptr+ r_geom <- (#peek XkbDescRec, geom) ptr++ return XkbDescRec {+ t_dpy = r_dpy,+ flags = r_flags,+ device_spec = r_device_spec,+ min_key_code = r_min_key_code,+ max_key_code = r_max_key_code,+ ctrls = r_ctrls,+ server = r_server,+ t_map = r_map,+ t_indicators = r_indicators,+ names = r_names,+ t_compat = r_compat,+ geom = r_geom+ }++--+-- C bindings+--++foreign import ccall unsafe "X11/XKBlib.h XkbAllocKeyboard"+ xkbAllocKeyboard :: IO (Ptr XkbDescRec)++foreign import ccall unsafe "X11/XKBlib.h XkbGetNames"+ xkbGetNames :: Display -> CUInt -> (Ptr XkbDescRec) -> IO Status++foreign import ccall unsafe "X11/XKBlib.h XGetAtomName"+ xGetAtomName :: Display -> Atom -> IO CString++foreign import ccall unsafe "X11/XKBlib.h XkbFreeNames"+ xkbFreeNames :: (Ptr XkbDescRec) -> CUInt -> CInt -> IO ()++foreign import ccall unsafe "X11/XKBlib.h XkbFreeKeyboard"+ xkbFreeKeyboard :: (Ptr XkbDescRec) -> CUInt -> CInt -> IO ()++foreign import ccall unsafe "X11/XKBlib.h XkbSelectEventDetails"+ xkbSelectEventDetails :: Display -> CUInt -> CUInt -> CULong -> CULong -> IO CUInt++foreign import ccall unsafe "X11/XKBlib.h XkbSelectEvents"+ xkbSelectEvents :: Display -> CUInt -> CUInt -> CUInt -> IO CUInt+++xkbUseCoreKbd :: CUInt+xkbUseCoreKbd = #const XkbUseCoreKbd++xkbStateNotify :: CUInt+xkbStateNotify = #const XkbStateNotify++xkbMapNotify :: CUInt+xkbMapNotify = #const XkbMapNotify++xkbMapNotifyMask :: CUInt+xkbMapNotifyMask = #const XkbMapNotifyMask++xkbNewKeyboardNotifyMask :: CUInt+xkbNewKeyboardNotifyMask = #const XkbNewKeyboardNotifyMask++xkbAllStateComponentsMask :: CULong+xkbAllStateComponentsMask = #const XkbAllStateComponentsMask++xkbGroupStateMask :: CULong+xkbGroupStateMask = #const XkbGroupStateMask++xkbSymbolsNameMask :: CUInt+xkbSymbolsNameMask = #const XkbSymbolsNameMask++xkbGroupNamesMask :: CUInt+xkbGroupNamesMask = #const XkbGroupNamesMask++type KbdOpts = [(String, String)]++-- gets the layout string+getLayoutStr :: Display -> IO String+getLayoutStr dpy = do+ kbdDescPtr <- xkbAllocKeyboard+ status <- xkbGetNames dpy xkbSymbolsNameMask kbdDescPtr+ str <- getLayoutStr' status dpy kbdDescPtr+ xkbFreeNames kbdDescPtr xkbGroupNamesMask 1+ xkbFreeKeyboard kbdDescPtr 0 1+ return str++getLayoutStr' :: Status -> Display -> (Ptr XkbDescRec) -> IO String+getLayoutStr' st dpy kbdDescPtr =+ if st == 0 then -- Success+ do+ kbdDesc <- peek kbdDescPtr+ nameArray <- peek (names kbdDesc)+ atom <- xGetAtomName dpy (symbols nameArray)+ str <- peekCString atom+ return str+ else -- Behaviour on error+ do+ return "Error while requesting layout!"+++-- 'Bad' prefixes of layouts+noLaySymbols :: [String]+noLaySymbols = ["group", "inet", "ctr", "pc", "ctrl"]+++-- splits the layout string into the actual layouts+splitLayout :: String -> [String]+splitLayout s = splitLayout' noLaySymbols $ split s '+' ++splitLayout' :: [String] -> [String] -> [String]+-- end of recursion, remove empty strings+splitLayout' [] s = map (takeWhile (\x -> x /= ':')) $ filter (\x -> length x > 0) s+-- remove current string if it has a 'bad' prefix+splitLayout' bad s = splitLayout' (tail bad) [x | x <- s, not $ isPrefixOf (head bad) x]++-- split String at each Char+split :: String -> Char -> [String]+split [] _ = [""]+split (c:cs) delim+ | c == delim = "" : rest+ | otherwise = (c : head rest) : tail rest+ where+ rest = split cs delim++-- replaces input string if on search list (exact match) with corresponding+-- element on replacement list.+-- +-- if not found, return string unchanged+searchReplaceLayout :: KbdOpts -> String -> String+searchReplaceLayout opts s = let c = findIndex (\x -> fst x == s) opts in+ case c of+ Nothing -> s+ x -> let i = (fromJust x) in+ snd $ opts!!i++-- returns the active layout+getKbdLay :: Display -> KbdOpts -> IO String+getKbdLay dpy opts = do+ lay <- getLayoutStr dpy+ curLay <- getKbdLayout dpy+ return $ searchReplaceLayout opts $ (splitLayout lay)!!(curLay)++++data Kbd = Kbd [(String, String)]+ deriving (Read, Show)++instance Exec Kbd where+ alias (Kbd _) = "kbd"+ start (Kbd opts) cb = do++ dpy <- openDisplay ""++ -- initial set of layout+ cb =<< (getKbdLay dpy opts)++ -- enable listing for+ -- group changes+ _ <- xkbSelectEventDetails dpy xkbUseCoreKbd xkbStateNotify xkbAllStateComponentsMask xkbGroupStateMask+ -- layout/geometry changes+ _ <- xkbSelectEvents dpy xkbUseCoreKbd xkbNewKeyboardNotifyMask xkbNewKeyboardNotifyMask++ allocaXEvent $ \e -> forever $ do+ nextEvent' dpy e+ _ <- getEvent e+ cb =<< (getKbdLay dpy opts)++ closeDisplay dpy+ return ()++-- vim:ft=haskell:ts=4:shiftwidth=4:softtabstop=4:expandtab:foldlevel=20:+
src/Plugins/Monitors.hs view
@@ -27,6 +27,7 @@ import Plugins.Monitors.Cpu import Plugins.Monitors.MultiCpu import Plugins.Monitors.Batt+import Plugins.Monitors.Bright import Plugins.Monitors.Thermal import Plugins.Monitors.ThermalZone import Plugins.Monitors.CpuFreq@@ -56,6 +57,7 @@ | Cpu Args Rate | MultiCpu Args Rate | Battery Args Rate+ | Brightness Args Rate | CpuFreq Args Rate | CoreTemp Args Rate | TopProc Args Rate@@ -93,6 +95,7 @@ alias (MultiCpu _ _) = "multicpu" alias (Battery _ _) = "battery" alias (BatteryP _ _ _)= "battery"+ alias (Brightness _ _) = "bright" alias (CpuFreq _ _) = "cpufreq" alias (TopProc _ _) = "top" alias (TopMem _ _) = "topmem"@@ -122,6 +125,7 @@ start (Swap a r) = runM a swapConfig runSwap r start (Battery a r) = runM a battConfig runBatt r start (BatteryP s a r) = runM a battConfig (runBatt' s) r+ start (Brightness a r) = runM a brightConfig runBright r start (CpuFreq a r) = runM a cpuFreqConfig runCpuFreq r start (CoreTemp a r) = runM a coreTempConfig runCoreTemp r start (DiskU s a r) = runM a diskUConfig (runDiskU s) r
src/Plugins/Monitors/Batt.hs view
@@ -13,11 +13,14 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE BangPatterns #-}+ module Plugins.Monitors.Batt ( battConfig, runBatt, runBatt' ) where -import qualified Data.ByteString.Lazy.Char8 as B+import Control.Exception (SomeException, handle) import Plugins.Monitors.Common import System.FilePath ((</>))+import System.IO (IOMode(ReadMode), hGetLine, withFile) import System.Posix.Files (fileExist) import System.Console.GetOpt @@ -31,6 +34,7 @@ , lowThreshold :: Float , highThreshold :: Float , onlineFile :: FilePath+ , chargeFile :: FilePath } defaultOpts :: BattOpts@@ -44,6 +48,7 @@ , lowThreshold = -12 , highThreshold = -10 , onlineFile = "AC/online"+ , chargeFile = "charge_full" } options :: [OptDescr (BattOpts -> BattOpts)]@@ -57,6 +62,7 @@ , Option "L" ["lowt"] (ReqArg (\x o -> o { lowThreshold = read x }) "") "" , Option "H" ["hight"] (ReqArg (\x o -> o { highThreshold = read x }) "") "" , Option "f" ["online"] (ReqArg (\x o -> o { onlineFile = x }) "") ""+ , Option "c" ["charge"] (ReqArg (\x o -> o { chargeFile = x }) "") "" ] parseOpts :: [String] -> IO BattOpts@@ -83,35 +89,36 @@ } | NoFiles data Battery = Battery- { full :: Float- , now :: Float- , voltage :: Float- , current :: Float+ { full :: !Float+ , now :: !Float+ , voltage :: !Float+ , current :: !Float } -batteryFiles :: String -> IO Files-batteryFiles bat =- do is_charge <- fileExist $ prefix </> "charge_now"- is_energy <- fileExist $ prefix </> "energy_now"- is_current <- fileExist $ prefix </> "current_now"+safeFileExist :: String -> IO Bool+safeFileExist f = handle noErrors $ fileExist f+ where noErrors = const (return False) :: SomeException -> IO Bool++batteryFiles :: String -> String -> IO Files+batteryFiles charge_file bat =+ do is_charge <- safeFileExist $ prefix </> "charge_now"+ is_energy <- safeFileExist $ prefix </> "energy_now"+ is_current <- safeFileExist $ prefix </> "current_now" let cf = if is_current then "current_now" else "power_now" return $ case (is_charge, is_energy) of (True, _) -> files "charge" cf (_, True) -> files "energy" cf _ -> NoFiles where prefix = sysDir </> bat- files ch cf = Files { fFull = prefix </> ch ++ "_full"+ files ch cf = Files { fFull = prefix </> charge_file , fNow = prefix </> ch ++ "_now" , fCurrent = prefix </> cf , fVoltage = prefix </> "voltage_now" } haveAc :: FilePath -> IO Bool-haveAc f = do- exists <- fileExist ofile- if exists- then fmap ((== "1\n") . B.unpack) (B.readFile ofile)- else return False- where ofile = sysDir </> f+haveAc f =+ handle onError $ withFile (sysDir </> f) ReadMode (fmap (== "1") . hGetLine)+ where onError = const (return False) :: SomeException -> IO Bool readBattery :: Files -> IO Battery readBattery NoFiles = return $ Battery 0 0 0 0@@ -123,18 +130,21 @@ return $ Battery (3600 * a / 1000000) -- wattseconds (3600 * b / 1000000) -- wattseconds (c / 1000000) -- volts- (d / c) -- amperes- where grab = fmap (read . B.unpack) . B.readFile+ (if c > 0 then (d / c) else -1) -- amperes+ where grab f = handle onError $ withFile f ReadMode (fmap read . hGetLine)+ onError = const (return (-1)) :: SomeException -> IO Float readBatteries :: BattOpts -> [Files] -> IO Result readBatteries opts bfs = do bats <- mapM readBattery (take 3 bfs) ac <- haveAc (onlineFile opts) let sign = if ac then 1 else -1- left = sum (map now bats) / sum (map full bats)+ ft = sum (map full bats)+ left = if ft > 0 then sum (map now bats) / ft else 0 watts = sign * sum (map voltage bats) * sum (map current bats) time = if watts == 0 then 0 else sum $ map time' bats- time' b = (if ac then full b - now b else now b) / (sign * watts)+ mwatts = if watts == 0 then 1 else sign * watts+ time' b = (if ac then full b - now b else now b) / mwatts acstr = if ac then onString opts else offString opts return $ if isNaN left then NA else Result left watts time acstr @@ -144,26 +154,26 @@ runBatt' :: [String] -> [String] -> Monitor String runBatt' bfs args = do opts <- io $ parseOpts args- c <- io $ readBatteries opts =<< mapM batteryFiles bfs+ c <- io $ readBatteries opts =<< mapM (batteryFiles (chargeFile opts)) bfs case c of Result x w t s -> do l <- fmtPercent x parseTemplate (l ++ s:[fmtTime $ floor t, fmtWatts w opts]) NA -> return "N/A"- where fmtPercent :: Float -> Monitor [String]- fmtPercent x = do- p <- showPercentWithColors x- b <- showPercentBar (100 * x) x- return [b, p]- fmtWatts x o = color x o $ showDigits 1 x ++ "W"- fmtTime :: Integer -> String- fmtTime x = hours ++ ":" ++ if length minutes == 2- then minutes else '0' : minutes- where hours = show (x `div` 3600)- minutes = show ((x `mod` 3600) `div` 60)- maybeColor Nothing _ = ""- maybeColor (Just c) str = "<fc=" ++ c ++ ">" ++ str ++ "</fc>"- color x o | x >= 0 = maybeColor (posColor o)- | x >= highThreshold o = maybeColor (highWColor o)- | x >= lowThreshold o = maybeColor (mediumWColor o)- | otherwise = maybeColor (lowWColor o)+ where fmtPercent :: Float -> Monitor [String]+ fmtPercent x = do+ p <- showPercentWithColors x+ b <- showPercentBar (100 * x) x+ return [b, p]+ fmtWatts x o = color x o $ showDigits 1 x ++ "W"+ fmtTime :: Integer -> String+ fmtTime x = hours ++ ":" ++ if length minutes == 2+ then minutes else '0' : minutes+ where hours = show (x `div` 3600)+ minutes = show ((x `mod` 3600) `div` 60)+ maybeColor Nothing _ = ""+ maybeColor (Just c) str = "<fc=" ++ c ++ ">" ++ str ++ "</fc>"+ color x o | x >= 0 = maybeColor (posColor o)+ | x >= highThreshold o = maybeColor (highWColor o)+ | x >= lowThreshold o = maybeColor (mediumWColor o)+ | otherwise = maybeColor (lowWColor o)
+ src/Plugins/Monitors/Bright.hs view
@@ -0,0 +1,118 @@+-----------------------------------------------------------------------------+---- |+---- Module : Plugins.Monitors.Birght+---- Copyright : (c) Martin Perner+---- License : BSD-style (see LICENSE)+----+---- Maintainer : Martin Perner <martin@perner.cc>+---- Stability : unstable+---- Portability : unportable+----+---- A screen brightness monitor for Xmobar+----+-------------------------------------------------------------------------------++module Plugins.Monitors.Bright (brightConfig, runBright) where++import Plugins.Monitors.Common+import qualified Data.ByteString.Lazy.Char8 as B+import Data.Char+import System.FilePath ((</>))+import System.Posix.Files (fileExist)+import System.Console.GetOpt++data BrightOpts = BrightOpts+ { subDir :: String+ , currBright :: String+ , maxBright :: String+ }++defaultOpts :: BrightOpts+defaultOpts = BrightOpts+ { subDir = "acpi_video0"+ , currBright = "actual_brightness"+ , maxBright = "max_brightness"+ }++options :: [OptDescr (BrightOpts -> BrightOpts)]+options =+ [ Option "D" ["device"] (ReqArg (\x o -> o { subDir = x }) "") ""+ , Option "C" ["curr"] (ReqArg (\x o -> o { currBright = x }) "") ""+ , Option "M" ["max"] (ReqArg (\x o -> o { maxBright = x }) "") ""+ ]++-- from Batt.hs+parseOpts :: [String] -> IO BrightOpts+parseOpts argv =+ case getOpt Permute options argv of+ (o, _, []) -> return $ foldr id defaultOpts o+ (_, _, errs) -> ioError . userError $ concat errs++sysDir :: FilePath+sysDir = "/sys/class/backlight/"++brightConfig :: IO MConfig+brightConfig = mkMConfig+ "<percent>" -- template+ ["hbar", "percent", "bar"] -- replacements++data Files = Files+ { fCurr :: String+ , fMax :: String+ } | NoFiles++brightFiles :: BrightOpts -> IO Files+brightFiles opts =+ do+ is_curr <- fileExist $ (fCurr files)+ is_max <- fileExist $ (fCurr files)+ if is_curr && is_max+ then return files+ else return NoFiles+ where+ prefix = sysDir </> (subDir opts)+ files = Files { fCurr = prefix </> (currBright opts)+ , fMax = prefix </> (maxBright opts)+ }+++runBright :: [String] -> Monitor String+runBright args = do+ opts <- io $ parseOpts args+ f <- io $ brightFiles opts+ c <- io $ readBright f+ case f of+ NoFiles -> return "hurz"+ _ -> do x <- fmtPercent c+ parseTemplate (x)+ where+ fmtPercent :: Float -> Monitor [String]+ fmtPercent c = do+ r <- showHorizontalBar (100 * c)+ s <- showPercentWithColors c+ t <- showPercentBar (100 * c) c+ return [r,s,t]++readBright :: Files -> IO Float+readBright NoFiles = return 0+readBright files =+ do+ currVal<- grab $ (fCurr files)+ maxVal <- grab $ (fMax files)+ return $ (currVal / maxVal) + where+ grab f = catch (fmap (read . B.unpack) $ B.readFile f)(\_ -> return 0)+++showHorizontalBar :: Float -> Monitor String+showHorizontalBar x = do+ return $ [convert x]+ where+ convert :: Float -> Char+ convert val + | t <= 9600 = ' '+ | t > 9608 = chr 9608+ | otherwise = chr t+ where+ -- we scale from 0 to 100, we have 8 slots (9 elements), 100/8 = 12+ t = 9600 + ((round val) `div` 12)
src/Plugins/Monitors/CoreCommon.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE PatternGuards, CPP #-}+ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.CoreCommon@@ -14,46 +16,128 @@ module Plugins.Monitors.CoreCommon where +import Control.Applicative+import Control.Monad+import Data.Char hiding (Space)+import Data.Function+import Data.List+import Data.Maybe import Plugins.Monitors.Common-import System.Posix.Files (fileExist)-import System.IO (withFile, IOMode(ReadMode), hGetLine) import System.Directory-import Data.Char (isDigit)-import Data.List (isPrefixOf) --- |--- Function checks the existence of first file specified by pattern and if the--- file doesn't exists failure message is shown, otherwise the data retrieval--- is performed.-checkedDataRetrieval :: (Num a, Ord a, Show a) =>- String -> String -> String -> String -> (Double -> a)- -> (a -> String) -> Monitor String-checkedDataRetrieval failureMessage dir file pattern trans fmt = do- exists <- io $ fileExist $ concat [dir, "/", pattern, "0/", file]- case exists of- False -> return failureMessage- True -> retrieveData dir file pattern trans fmt+#ifdef GHC6+import Control.Monad.Reader --- |--- Function retrieves data from files in directory dir specified by--- pattern. String values are converted to double and 'trans' applied--- to each one. Final array is processed by template parser function--- and returned as monitor string.-retrieveData :: (Num a, Ord a, Show a) =>- String -> String -> String -> (Double -> a) -> (a -> String) ->- Monitor String-retrieveData dir file pattern trans fmt = do- count <- io $ dirCount dir pattern- contents <- io $ mapM getGuts $ files count- values <- mapM (showWithColors fmt) $ map conversion contents- parseTemplate values- where- getGuts f = withFile f ReadMode hGetLine- dirCount path str = getDirectoryContents path- >>= return . length- . filter (\s -> str `isPrefixOf` s- && isDigit (last s))- files count = map (\i -> concat [dir, "/", pattern, show i, "/", file])- [0 .. count - 1]- conversion = trans . (read :: String -> Double)+instance (Monad f, Applicative f) => Applicative (ReaderT r f) where+ pure a = ReaderT $ const (pure a)+ f <*> a = ReaderT $ \r -> + ((runReaderT f r) <*> (runReaderT a r))+#endif +checkedDataRetrieval :: (Ord a, Num a)+ => String -> [String] -> Maybe (String, String -> Int)+ -> (Double -> a) -> (a -> String) -> Monitor String+checkedDataRetrieval msg path lbl trans fmt = liftM (maybe msg id) $+ retrieveData path lbl trans fmt++retrieveData :: (Ord a, Num a)+ => [String] -> Maybe (String, String -> Int)+ -> (Double -> a) -> (a -> String) -> Monitor (Maybe String)+retrieveData path lbl trans fmt = do+ pairs <- map snd . sortBy (compare `on` fst) <$> (mapM readFiles =<< findFiles path lbl)+ if null pairs+ then return Nothing+ else Just <$> ( parseTemplate+ =<< mapM (showWithColors fmt . trans . read) pairs+ )++-- | Represents the different types of path components+data Comp = Fix String+ | Var [String]+ deriving Show++-- | Used to represent parts of file names separated by slashes and spaces+data CompOrSep = Slash+ | Space+ | Comp String+ deriving (Eq, Show)++-- | Function to turn a list of of strings into a list of path components+pathComponents :: [String] -> [Comp]+pathComponents = joinComps . drop 2 . concat . intersperse [Space] . map splitParts+ where+ splitParts p | (l, _:r) <- break (== '/') p = (Comp l):Slash:splitParts r+ | otherwise = [Comp p]++ joinComps = uncurry joinComps' . partition isComp++ isComp (Comp _) = True+ isComp _ = False++ fromComp (Comp s) = s+ fromComp _ = error "fromComp applied to value other than (Comp _)"++ joinComps' cs [] = [Fix $ fromComp $ head cs] -- cs should have only one element here,+ -- but this keeps the pattern matching+ -- exhaustive+ joinComps' cs (p:ps) = let (ss, ps') = span (== p) ps+ ct = if null ps' || (p == Space) then length ss + 1+ else length ss+ (ls, rs) = splitAt (ct+1) cs+ c = case p of+ Space -> Var $ map fromComp ls+ Slash -> Fix $ intercalate "/" $ map fromComp ls+ _ -> error "Should not happen"+ in if null ps' then [c]+ else c:joinComps' rs (drop ct ps)++-- | Function to find all files matching the given path and possible label file.+-- The path must be absolute (start with a leading slash).+findFiles :: [String] -> Maybe (String, String -> Int)+ -> Monitor [(String, Either Int (String, String -> Int))]+findFiles path lbl = catMaybes+ <$> ( mapM addLabel . zip [0..] . sort+ =<< recFindFiles (pathComponents path) "/"+ )+ where+ addLabel (i, f) = maybe (return $ Just (f, Left i))+ (\(s, t) -> justIfExists f s t)+ lbl++ justIfExists f s t = let f' = take (length f - length s) f ++ s+ in ifthen (Just (f, Right (f', t))) Nothing <$> (io $ doesFileExist f')++ recFindFiles [] d = ifthen [d] []+ <$> (io $ if null d then return False else doesFileExist d)+ recFindFiles ps d = ifthen (recFindFiles' ps d) (return [])+ =<< (io $ if null d then return True else doesDirectoryExist d)++ recFindFiles' [] _ = error "Should not happen"+ recFindFiles' (Fix p:ps) d = recFindFiles ps (d ++ "/" ++ p)+ recFindFiles' (Var p:ps) d = concat+ <$> ( mapM (recFindFiles ps)+ . map (\f -> d ++ "/" ++ f)+ . filter (matchesVar p)+ =<< (io $ getDirectoryContents d)+ )++ matchesVar [] _ = False+ matchesVar [v] f = v == f+ matchesVar (v:vs) f = let f' = drop (length v) f+ f'' = dropWhile isDigit f'+ in and [ v `isPrefixOf` f+ , not (null f')+ , isDigit (head f')+ , matchesVar vs f''+ ]++-- | Function to read the contents of the given file(s)+readFiles :: (String, Either Int (String, String -> Int))+ -> Monitor (Int, String)+readFiles (fval, flbl) = (,) <$> either return (\(f, ex) -> liftM ex+ $ io $ readFile f) flbl+ <*> (io $ readFile fval)++-- | Function that captures if-then-else+ifthen :: a -> a -> Bool -> a+ifthen thn els cnd = if cnd then thn else els
src/Plugins/Monitors/CoreTemp.hs view
@@ -31,11 +31,9 @@ -- Function retrieves monitor string holding the core temperature -- (or temperatures) runCoreTemp :: [String] -> Monitor String-runCoreTemp _ = do- let dir = "/sys/bus/platform/devices"- file = "temp1_input"- pattern = "coretemp."- divisor = 1e3 :: Double- failureMessage = "CoreTemp: N/A"- checkedDataRetrieval failureMessage dir file pattern (/divisor) show+runCoreTemp _ = let path = ["/sys/bus/platform/devices/coretemp.", "/temp", "_input"]+ lbl = Just ("_label", read . drop 5)+ divisor = 1e3 :: Double+ failureMessage = "CoreTemp: N/A"+ in checkedDataRetrieval failureMessage path lbl (/divisor) show
src/Plugins/Monitors/Cpu.hs view
@@ -22,7 +22,7 @@ cpuConfig :: IO MConfig cpuConfig = mkMConfig "Cpu: <total>%"- ["bar","total","user","nice","system","idle"]+ ["bar","total","user","nice","system","idle","iowait"] type CpuDataRef = IORef [Float] @@ -45,7 +45,7 @@ formatCpu :: [Float] -> Monitor [String] formatCpu [] = return $ replicate 6 "" formatCpu xs = do- let t = foldr (+) 0 $ take 3 xs+ let t = sum $ take 3 xs b <- showPercentBar (100 * t) t ps <- showPercentsWithColors (t:xs) return (b:ps)
src/Plugins/Monitors/CpuFreq.hs view
@@ -28,16 +28,12 @@ -- replacements -- |--- Function retrieves monitor string holding the cpu frequency (or--- frequencies)+-- Function retrieves monitor string holding the cpu frequency (or frequencies) runCpuFreq :: [String] -> Monitor String-runCpuFreq _ = do- let dir = "/sys/devices/system/cpu"- file = "cpufreq/scaling_cur_freq"- pattern = "cpu"- divisor = 1e6 :: Double- failureMessage = "CpuFreq: N/A"- fmt x | x < 1 = show (round (x * 1000) :: Integer) ++ "MHz"- | otherwise = showDigits 1 x ++ "GHz"- checkedDataRetrieval failureMessage dir file pattern (/divisor) fmt+runCpuFreq _ = let path = ["/sys/devices/system/cpu/cpu", "/cpufreq/scaling_cur_freq"]+ divisor = 1e6 :: Double+ failureMessage = "CpuFreq: N/A"+ fmt x | x < 1 = (show (round (x * 1000) :: Integer)) ++ "MHz"+ | otherwise = (show x) ++ "GHz"+ in checkedDataRetrieval failureMessage path Nothing (/divisor) fmt
src/Plugins/Monitors/MPD.hs view
@@ -91,7 +91,7 @@ parseSong (Right (Just s)) = let join [] = "" join (x:xs) = foldl (\a o -> a ++ ", " ++ o) x xs- str sel = maybe "" join (M.sgGet sel s)+ str sel = maybe "" join (M.sgGetTag sel s) sels = [ M.Name, M.Artist, M.Composer, M.Performer , M.Album, M.Title, M.Track, M.Genre ] fields = M.sgFilePath s : map str sels
src/Plugins/Monitors/Top.hs view
@@ -13,6 +13,7 @@ ----------------------------------------------------------------------------- {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE BangPatterns #-} module Plugins.Monitors.Top (startTop, topMemConfig, runTopMem) where
src/Plugins/Monitors/Volume.hs view
@@ -14,10 +14,12 @@ module Plugins.Monitors.Volume (runVolume, volumeConfig) where +import Prelude hiding ( catch ) import Control.Monad ( liftM, mplus ) import Data.Maybe import Plugins.Monitors.Common import Sound.ALSA.Mixer+import Sound.ALSA.Exception ( catch ) import System.Console.GetOpt volumeConfig :: IO MConfig@@ -115,7 +117,8 @@ maybeNA = maybe (return "N/A") (lo, hi) <- io $ getRange volumeControl val <- io $ getChannel FrontLeft $ value volumeControl- db <- io $ getChannel FrontLeft $ dB volumeControl+ db <- io $ catch (getChannel FrontLeft $ dB volumeControl)+ (\_ -> return $ Just 0) sw <- io $ getChannel FrontLeft switchControl p <- maybeNA (formatVol lo hi) val b <- maybeNA (formatVolBar lo hi) val
src/Plugins/Monitors/Wireless.hs view
@@ -25,10 +25,9 @@ runWireless (iface:_) = do wi <- io $ getWirelessInfo iface let essid = wiEssid wi- qlty = wiQuality wi- fqlty = fromIntegral qlty+ qlty = fromIntegral $ wiQuality wi e = if essid == "" then "N/A" else essid- q <- if qlty >= 0 then showWithColors show qlty else showWithPadding ""- qb <- showPercentBar fqlty (fqlty / 100)+ q <- if qlty >= 0 then showPercentWithColors (qlty/100) else showWithPadding ""+ qb <- showPercentBar qlty (qlty / 100) parseTemplate [e, q, qb] runWireless _ = return ""
src/StatFS.hsc view
@@ -23,7 +23,11 @@ import Data.ByteString (useAsCString) import Data.ByteString.Char8 (pack) -#if defined (__FreeBSD__) || defined (__APPLE__)+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__APPLE__)+#define IS_BSD_SYSTEM+#endif++#ifdef IS_BSD_SYSTEM # include <sys/param.h> # include <sys/mount.h> #else@@ -47,7 +51,7 @@ data CStatfs -#if defined (__FreeBSD__) || defined (__APPLE__)+#ifdef IS_BSD_SYSTEM foreign import ccall unsafe "sys/mount.h statfs" #else foreign import ccall unsafe "sys/vfs.h statfs64"
src/XUtil.hsc view
@@ -1,8 +1,8 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE ForeignFunctionInterface #-} ----------------------------------------------------------------------------- -- | -- Module : XUtil--- Copyright : (C) 2007 Andrea Rossato+-- Copyright : (C) 2007, 2011 Andrea Rossato -- License : BSD3 -- -- Maintainer : andrea.rossato@unitn.it@@ -28,12 +28,15 @@ , fi , withColors , DynPixel(..)+ , xrrSelectInput+ , xrrQueryExtension ) where import Control.Concurrent import Control.Monad.Trans import Data.IORef import Foreign+import Foreign.C.Types import Graphics.X11.Xlib hiding (textExtents, textWidth) import qualified Graphics.X11.Xlib as Xlib (textExtents, textWidth) import Graphics.X11.Xlib.Extras@@ -257,3 +260,12 @@ setupLocale :: IO () setupLocale = return () #endif++-- XRRSelectInput+#include <X11/extensions/Xrandr.h>+foreign import ccall unsafe "X11/extensions/Xrandr.h XRRSelectInput"+ xrrSelectInput :: Display -> Window -> EventMask -> IO ()++-- XRRQueryExtension+foreign import ccall unsafe "X11/extensions/Xrandr.h XRRQueryExtension"+ xrrQueryExtension :: Display -> Ptr CInt -> Ptr CInt -> IO (Bool)
src/Xmobar.hs view
@@ -17,7 +17,7 @@ ( -- * Main Stuff -- $main X , XConf (..), runX- , eventLoop+ , startLoop -- * Program Execution -- $command , startCommand@@ -42,7 +42,9 @@ import Data.Bits import Data.Maybe(fromMaybe) import Data.Typeable (Typeable)+import Foreign import System.Posix.Process (getProcessID)+import System.Posix.Signals import Config import Parsers@@ -73,46 +75,107 @@ data WakeUp = WakeUp deriving (Show,Typeable) instance Exception WakeUp --- | The event loop-eventLoop :: XConf -> [[(Maybe ThreadId, TVar String)]] -> IO ()-eventLoop xc@(XConf d _ w fs c) vs = block $ do+data SignalType = Wakeup | Reposition | ChangeScreen++-- | Starts the main event loop and threads+startLoop :: XConf -> [[(Maybe ThreadId, TVar String)]] -> IO ()+startLoop xcfg@(XConf _ _ w _ _) vs = do tv <- atomically $ newTVar []- t <- myThreadId- ct <- forkIO (checker t tv [] `catch` \(SomeException _) -> return ())- go tv ct- where- -- interrupt the drawing thread every time a var is updated- checker t tvar ov = do+ sig <- setupSignalHandler+ _ <- forkIO (checker tv [] vs sig `catch` \(SomeException _) -> putStrLn "Thread checker failed" >> return ())+ _ <- forkOS (eventer sig `catch` \(SomeException _) -> putStrLn "Thread eventer failed" >> return ())+ eventLoop tv xcfg sig+ where+ -- Reacts on events from X+ eventer signal =+ alloca $ \ptrEventBase ->+ alloca $ \ptrErrorBase ->+ allocaXEvent $ \e -> do++ dpy <- openDisplay ""+ -- keyPressMask is the same value as RRScreenChangeNotifyMask+ xrrSelectInput dpy (defaultRootWindow dpy) keyPressMask+ selectInput dpy w (exposureMask .|. structureNotifyMask)++ _ <- xrrQueryExtension dpy ptrEventBase ptrErrorBase+ xrrEventBase <- peek ptrEventBase++ forever $ do+ nextEvent dpy e+ ev <- getEvent e+ case ev of+ ConfigureEvent {} -> putMVar signal Reposition+ ExposeEvent {} -> putMVar signal Wakeup+ _ ->+ -- 0 is the value of RRScreenChangeNotify+ when ( (fromIntegral (ev_event_type ev) - xrrEventBase) == 0)+ $ putMVar signal Reposition++-- | Send signal to eventLoop every time a var is updated+checker :: TVar [String] -> [String] -> [[(Maybe ThreadId, TVar String)]] -> MVar SignalType -> IO ()+checker tvar ov vs signal = do nval <- atomically $ do nv <- mapM concatV vs guard (nv /= ov) writeTVar tvar nv return nv- throwTo t WakeUp- checker t tvar nval+ putMVar signal Wakeup+ checker tvar nval vs signal+ where+ concatV = fmap concat . mapM (readTVar . snd) - concatV = fmap concat . mapM (readTVar . snd) - -- Continuously wait for a timer interrupt or an expose event- go tv ct = do- catch (unblock $ allocaXEvent $ \e ->- handle tv ct =<< (nextEvent' d e >> getEvent e))- (\WakeUp -> runX xc (updateWin tv) >> return ())- go tv ct+-- | Continuously wait for a signal from a thread or a interrupt handler+eventLoop :: TVar [String] -> XConf -> MVar SignalType -> IO ()+eventLoop tv xc@(XConf d _ w fs cfg) signal = do+ typ <- takeMVar signal+ case typ of+ Wakeup -> do+ runX xc (updateWin tv)+ eventLoop tv xc signal - -- event hanlder- handle _ ct (ConfigureEvent {ev_window = win}) = do- rootw <- rootWindow d (defaultScreen d)- when (win == rootw) $ block $ do- killThread ct- destroyWindow d w- (r',w') <- createWin d fs c- eventLoop (XConf d r' w' fs c) vs+ Reposition ->+ reposWindow cfg - handle tvar _ (ExposeEvent {}) = runX xc (updateWin tvar)+ ChangeScreen -> do+ ncfg <- updateConfigPosition cfg+ reposWindow ncfg - handle _ _ _ = return ()+ where+ reposWindow rcfg = do+ r' <- repositionWin d w fs rcfg+ eventLoop tv (XConf d r' w fs rcfg) signal + updateConfigPosition ocfg =+ case position ocfg of+ OnScreen n o -> do+ srs <- getScreenInfo d+ if n == length srs then+ return (ocfg {position = OnScreen 1 o})+ else+ return (ocfg {position = OnScreen (n+1) o})+ o ->+ return (ocfg {position = OnScreen 1 o})+++-- | Signal handling+setupSignalHandler :: IO (MVar SignalType)+setupSignalHandler = do+ tid <- newEmptyMVar+ installHandler sigUSR2 (Catch $ updatePosHandler tid) Nothing+ installHandler sigUSR1 (Catch $ changeScreenHandler tid) Nothing+ return tid++updatePosHandler :: MVar SignalType -> IO ()+updatePosHandler sig = do+ putMVar sig Reposition+ return ()++changeScreenHandler :: MVar SignalType -> IO ()+changeScreenHandler sig = do+ putMVar sig ChangeScreen+ return ()+ -- $command -- | Runs a command as an independent thread and returns its thread id@@ -120,7 +183,7 @@ startCommand :: (Runnable,String,String) -> IO (Maybe ThreadId, TVar String) startCommand (com,s,ss) | alias com == "" = do var <- atomically $ newTVar is- atomically $ writeTVar var "Could not parse the template"+ atomically $ writeTVar var (s ++ ss) return (Nothing,var) | otherwise = do var <- atomically $ newTVar is let cb str = atomically $ writeTVar var (s ++ str ++ ss)@@ -140,12 +203,22 @@ let ht = as + ds + 4 (r,o) = setPosition (position c) srs (fi ht) win <- newWindow d (defaultScreenOfDisplay d) rootw r o- selectInput d win (exposureMask .|. structureNotifyMask) setProperties r c d win srs when (lowerOnStart c) (lowerWindow d win) mapWindow d win return (r,win) +-- | Updates the size and position of the window+repositionWin :: Display -> Window -> XFont -> Config -> IO (Rectangle)+repositionWin d win fs c = do+ srs <- getScreenInfo d+ (as,ds) <- textExtents fs "0"+ let ht = as + ds + 4+ (r,_) = setPosition (position c) srs (fi ht)+ moveResizeWindow d win (rect_x r) (rect_y r) (rect_width r) (rect_height r)+ setProperties r c d win srs+ return r+ setPosition :: XPosition -> [Rectangle] -> Dimension -> (Rectangle,Bool) setPosition p rs ht = case p' of@@ -292,7 +365,8 @@ let (conf,d) = (config &&& display) r Rectangle _ _ wid ht = rect r totSLen = foldr (\(_,_,len) -> (+) len) 0 sl- valign = (fi ht + fi (as + ds)) `div` 2 - 1+ fntsize = fi (as + ds)+ valign = fi ht - 1 - (fi ht - fntsize) `div` 2 remWidth = fi wid - fi totSLen offset = case a of C -> (remWidth + offs) `div` 2
xmobar.cabal view
@@ -1,5 +1,5 @@ name: xmobar-version: 0.13+version: 0.14 homepage: http://projects.haskell.org/xmobar/ bug-reports: http://code.google.com/p/xmobar/issues synopsis: A Minimalistic Text Based Status Bar@@ -57,33 +57,45 @@ description: Use alsa-mixer to get the volume from soundcards. default: False +flag with_datezone+ description: Enables localized date support+ default: False+ executable xmobar hs-source-dirs: src main-is: Main.hs other-modules:- Xmobar, Config, Parsers, Commands, XUtil, StatFS, Runnable,+ Xmobar, Config, Parsers, Commands, Localize, XUtil, StatFS, Runnable, Plugins, Plugins.CommandReader, Plugins.Date, Plugins.EWMH, Plugins.PipeReader, Plugins.StdinReader, Plugins.XMonadLog,- Plugins.Utils, Plugins.Monitors, Plugins.Monitors.Batt,- Plugins.Monitors.Common, Plugins.Monitors.CoreCommon,- Plugins.Monitors.CoreTemp, Plugins.Monitors.CpuFreq,- Plugins.Monitors.Cpu, Plugins.Monitors.Disk, Plugins.Monitors.Mem,+ Plugins.Utils, Plugins.Kbd, Plugins.Monitors,+ Plugins.Monitors.Batt, Plugins.Monitors.Common,+ Plugins.Monitors.CoreCommon, Plugins.Monitors.CoreTemp,+ Plugins.Monitors.CpuFreq, Plugins.Monitors.Cpu,+ Plugins.Monitors.Disk, Plugins.Monitors.Mem, Plugins.Monitors.MultiCpu, Plugins.Monitors.Net, Plugins.Monitors.Swap, Plugins.Monitors.Thermal, Plugins.Monitors.ThermalZone, Plugins.Monitors.Top,- Plugins.Monitors.Uptime, Plugins.Monitors.Weather+ Plugins.Monitors.Uptime, Plugins.Monitors.Weather,+ Plugins.Monitors.Bright ghc-prof-options: -prof -auto-all if true- ghc-options: -funbox-strict-fields -Wall+ ghc-options: -funbox-strict-fields -Wall -threaded+ extra-libraries: Xrandr - if impl (ghc == 6.10.1) && arch (x86_64)- ghc-options: -O0+ -- Use --disable-optimization configure flag+ -- if impl (ghc == 6.10.1) && arch (x86_64)+ -- ghc-options: -O0 if impl (ghc >= 6.12.1) ghc-options: -fno-warn-unused-do-bind + -- for instance declaration in src/Plugins/Monitors/CoreCommon.hs+ if impl (ghc < 7)+ cpp-options: -DGHC6+ build-depends: X11>=1.3.0, mtl, unix, parsec, filepath, stm, time if flag(small_base)@@ -111,11 +123,17 @@ cpp-options: -DIWLIB if flag(with_mpd) || flag(all_extensions)- build-depends: libmpd >= 0.5+ build-depends: libmpd >= 0.6 other-modules: Plugins.Monitors.MPD cpp-options: -DLIBMPD if flag(with_alsa) || flag(all_extensions) build-depends: alsa-mixer == 0.1.*+ build-depends: alsa-core == 0.5.* other-modules: Plugins.Monitors.Volume cpp-options: -DALSA++ if flag(with_datezone) || flag(all_extensions)+ build-depends: timezone-olson, timezone-series+ other-modules: Plugins.DateZone+ cpp-options: -DDATEZONE