----------------------------------------------------------------------------- -- | -- Module : System.Taffybar -- Copyright : (c) Ivan A. Malison -- License : BSD3-style (see LICENSE) -- -- Maintainer : Ivan A. Malison -- Stability : unstable -- Portability : unportable ----------------------------------------------------------------------------- module System.Taffybar ( -- * Detail -- -- | This is a system status bar meant for use with window managers like -- XMonad. It is similar to xmobar, but with more visual flare and a different -- widget set. Contributed widgets are more than welcome. The bar is drawn -- using gtk and cairo. It is actually the simplest possible thing that could -- plausibly work: you give Taffybar a list of GTK widgets and it will render -- them in a horizontal bar for you (taking care of ugly details like -- reserving strut space so that window managers don't put windows over it). -- -- This is the real main module. The default bar should be customized to taste -- in the config file (~/.config/taffybar/taffybar.hs). Typically, this means -- adding widgets to the default config. A default configuration file is -- included in the distribution, but the essentials are covered here. -- * Config File -- -- | The config file is just a Haskell source file that is compiled at startup -- (if it has changed) to produce a custom executable with the desired set of -- widgets. You will want to import this module along with the modules of any -- widgets you want to add to the bar. Note, you can define any widgets that -- you want in your config file or other libraries. Taffybar only cares that -- you give it some GTK widgets to display. -- -- Below is a fairly typical example: -- -- > {-# LANGUAGE OverloadedStrings #-} -- > import System.Taffybar -- > import System.Taffybar.Information.CPU -- > import System.Taffybar.SimpleConfig -- > import System.Taffybar.Widget -- > import System.Taffybar.Widget.Generic.Graph -- > import System.Taffybar.Widget.Generic.PollingGraph -- > -- > cpuCallback = do -- > (_, systemLoad, totalLoad) <- cpuLoad -- > return [ totalLoad, systemLoad ] -- > -- > main = do -- > let cpuCfg = defaultGraphConfig { graphDataColors = [ (0, 1, 0, 1), (1, 0, 1, 0.5)] -- > , graphLabel = Just "cpu" -- > } -- > clock = textClockNew Nothing "%a %b %_d %H:%M" 1 -- > cpu = pollingGraphNew cpuCfg 0.5 cpuCallback -- > workspaces = workspacesNew defaultWorkspacesConfig -- > simpleConfig = defaultSimpleTaffyConfig -- > { startWidgets = [ workspaces ] -- > , endWidgets = [ sniTrayNew, clock, cpu ] -- > } -- > simpleTaffybar simpleConfig -- -- This configuration creates a bar with four widgets. On the left is a widget -- that shows information about the workspace configuration. The rightmost -- widget is the system tray, with a clock and then a CPU graph. The clock is -- formatted using standard strftime-style format strings (see the clock -- module). Note that the clock is colored using Pango markup (again, see the -- clock module). -- -- The CPU widget plots two graphs on the same widget: total CPU use in green -- and then system CPU use in a kind of semi-transparent purple on top of the -- green. -- -- It is important to note that the widget lists are *not* [Widget]. They are -- actually [TaffyIO Widget] since the bar needs to construct them after performing -- some GTK initialization. -- -- ** A note about taffybar's dependency on DBus: -- | -- * If you start your window manager using a graphical login manager like gdm -- or kdm, DBus should be started automatically for you. -- -- * If you start xmonad with a different graphical login manager that does -- not start DBus for you automatically, put the line @eval \`dbus-launch -- --auto-syntax\`@ into your ~\/.xsession *before* xmonad and taffybar are -- started. This command sets some environment variables that the two must -- agree on. -- -- * If you start xmonad via @startx@ or a similar command, add the -- above command to ~\/.xinitrc -- * Colors -- -- | While taffybar is based on GTK+, it ignores your GTK+ theme. The default -- theme that it uses lives at -- https://github.com/taffybar/taffybar/blob/master/taffybar.css You can alter -- this theme by editing @~\/.config\/taffybar\/taffybar.css@ to your liking. -- For an idea of the customizations you can make, see -- . taffybarDyreParams , dyreTaffybar , startTaffybar , dyreTaffybarMain ) where import qualified Config.Dyre as Dyre import qualified Config.Dyre.Params as Dyre import Control.Monad import qualified Data.GI.Gtk.Threading as GIThreading import qualified Data.Text as T import qualified GI.Gdk as Gdk import qualified GI.Gtk as Gtk import Graphics.X11.Xlib.Misc import System.Directory import System.Environment.XDG.BaseDir ( getUserConfigFile ) import System.Exit ( exitFailure ) import System.FilePath ( () ) import qualified System.IO as IO import System.Taffybar.Context import Paths_taffybar ( getDataDir ) -- | The parameters that are passed to Dyre when taffybar is invoked with -- 'dyreTaffybar'. taffybarDyreParams :: Dyre.Params TaffybarConfig taffybarDyreParams = Dyre.defaultParams { Dyre.projectName = "taffybar" , Dyre.realMain = dyreTaffybarMain , Dyre.showError = showError , Dyre.ghcOpts = ["-threaded", "-rtsopts"] , Dyre.rtsOptsHandling = Dyre.RTSAppend ["-I0", "-V0"] } -- | Use Dyre to configure and start taffybar. This will automatically recompile -- taffybar whenever there are changes to your taffybar.hs configuration file. dyreTaffybar :: TaffybarConfig -> IO () dyreTaffybar = Dyre.wrapMain taffybarDyreParams showError :: TaffybarConfig -> String -> TaffybarConfig showError cfg msg = cfg { errorMsg = Just msg } dyreTaffybarMain :: TaffybarConfig -> IO () dyreTaffybarMain cfg = case errorMsg cfg of Nothing -> startTaffybar cfg Just err -> do IO.hPutStrLn IO.stderr ("Error: " ++ err) exitFailure getDefaultConfigFile :: String -> IO FilePath getDefaultConfigFile name = do dataDir <- getDataDir return (dataDir name) startCSS :: IO Gtk.CssProvider startCSS = do -- Override the default GTK theme path settings. This causes the -- bar (by design) to ignore the real GTK theme and just use the -- provided minimal theme to set the background and text colors. -- Users can override this default. taffybarProvider <- Gtk.cssProviderNew let loadIfExists filePath = doesFileExist filePath >>= flip when (Gtk.cssProviderLoadFromPath taffybarProvider (T.pack filePath)) loadIfExists =<< getDefaultConfigFile "taffybar.css" loadIfExists =<< getUserConfigFile "taffybar" "taffybar.css" Just scr <- Gdk.screenGetDefault Gtk.styleContextAddProviderForScreen scr taffybarProvider 800 return taffybarProvider -- | Start taffybar with the provided 'TaffybarConfig'. Because this function -- will not handle recompiling taffybar automatically when taffybar.hs is -- updated, it is generally recommended that end users use 'dyreTaffybar' -- instead. If automatic recompilation is handled by another mechanism such as -- stack or a custom user script or not desired for some reason, it is -- perfectly fine to use this function. startTaffybar :: TaffybarConfig -> IO () startTaffybar config = do _ <- initThreads _ <- Gtk.init Nothing GIThreading.setCurrentThreadAsGUIThread _ <- startCSS _ <- buildContext config Gtk.main return ()