Copyright | (c) Yecine Megdiche <yecine.megdiche@gmail.com> |
---|---|
License | BSD3-style (see LICENSE) |
Maintainer | Yecine Megdiche <yecine.megdiche@gmail.com> |
Stability | unstable |
Portability | unportable |
Safe Haskell | None |
Language | Haskell98 |
xmonad calls the logHook with every internal state update, which is useful for (among other things) outputting status information to an external status bar program such as xmobar or dzen.
This module provides a composable interface for (re)starting these status bars and logging to them, either using pipes or X properties. There's also XMonad.Hooks.StatusBar.PP which provides an abstraction and some utilities for customization what is logged to a status bar. Together, these are a modern replacement for XMonad.Hooks.DynamicLog, which is now just a compatibility wrapper.
Synopsis
- data StatusBarConfig = StatusBarConfig {
- sbLogHook :: X ()
- sbStartupHook :: X ()
- sbCleanupHook :: X ()
- withSB :: LayoutClass l Window => StatusBarConfig -> XConfig l -> XConfig l
- withEasySB :: LayoutClass l Window => StatusBarConfig -> (XConfig Layout -> (KeyMask, KeySym)) -> XConfig l -> XConfig (ModifiedLayout AvoidStruts l)
- defToggleStrutsKey :: XConfig t -> (KeyMask, KeySym)
- statusBarProp :: String -> X PP -> StatusBarConfig
- statusBarPropTo :: String -> String -> X PP -> StatusBarConfig
- statusBarGeneric :: String -> X () -> StatusBarConfig
- statusBarPipe :: String -> X PP -> IO StatusBarConfig
- dynamicSBs :: (ScreenId -> IO StatusBarConfig) -> XConfig l -> XConfig l
- dynamicEasySBs :: LayoutClass l Window => (ScreenId -> IO StatusBarConfig) -> XConfig l -> XConfig (ModifiedLayout AvoidStruts l)
- xmonadPropLog :: String -> X ()
- xmonadPropLog' :: String -> String -> X ()
- xmonadDefProp :: String
- spawnStatusBar :: String -> X ()
- killStatusBar :: String -> X ()
- killAllStatusBars :: X ()
Usage
You can use this module with the following in your ~/.xmonad/xmonad.hs
:
import XMonad import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP
The easiest way to use this module with xmobar, as well as any other
status bar that supports property logging, is to use statusBarProp
with withEasySB
; these take care of the necessary plumbing:
mySB = statusBarProp "xmobar" (pure xmobarPP) main = xmonad $ withEasySB mySB defToggleStrutsKey def
You can read more about X11 properties here or here, although you don't have to understand them in order to use the functions mentioned above.
Most users will, however, want to customize the logging and integrate it
into their existing custom xmonad configuration. The withSB
function is more appropriate in this case: it doesn't touch your
keybindings, layout modifiers, or event hooks; instead, you're expected
to configure XMonad.Hooks.ManageDocks yourself. Here's what that might
look like:
mySB = statusBarProp "xmobar" (pure myPP) main = xmonad . withSB mySB . ewmh . docks $ def {...}
You then have to tell your status bar to read from the _XMONAD_LOG
property
of the root window. In the case of xmobar, this is achieved by simply using
the XMonadLog
plugin instead of StdinReader
in your .xmobarrc
:
Config { ... , commands = [ Run XMonadLog, ... ] , template = "%XMonadLog% }{ ..." }
If you don't have an .xmobarrc
, create it; the XMonadLog
plugin is not
part of the default xmobar configuration and your status bar will not show
workspace information otherwise!
With statusBarProp
, you need to use property logging. Make sure the
status bar you use supports reading a property string from the root window,
or use some kind of wrapper that reads the property and pipes it into the
bar (e.g. xmonadpropread | dzen2
, see scripts/xmonadpropread.hs
). The
default property is _XMONAD_LOG
, which is conveniently saved in xmonadDefProp
.
You can use another property by using the function statusBarPropTo
.
If your status bar does not support property-based logging, you may also try
statusBarPipe
.
It can be used in the same way as statusBarProp
above (for xmobar, you now
have to use the StdinReader
plugin in your .xmobarrc
). Instead of
writing to a property, this function opens a pipe and makes the given status
bar read from that pipe.
Please be aware that this kind of setup is very bug-prone and hence is
discouraged: if anything goes wrong with the bar, xmonad will freeze!
Also note that statusBarPipe
returns 'IO StatusBarConfig', so
you need to evaluate it before passing it to withSB
or withEasySB
:
main = do mySB <- statusBarPipe "xmobar" (pure myPP) xmonad $ withSB mySB myConf
data StatusBarConfig Source #
This datataype abstracts a status bar to provide a common interface
functions like statusBarPipe
or statusBarProp
. Once defined, a status
bar can be incorporated in XConfig
by using withSB
or
withEasySB
, which take care of the necessary plumbing.
StatusBarConfig | |
|
Instances
Semigroup StatusBarConfig Source # | |
Defined in XMonad.Hooks.StatusBar (<>) :: StatusBarConfig -> StatusBarConfig -> StatusBarConfig # sconcat :: NonEmpty StatusBarConfig -> StatusBarConfig # stimes :: Integral b => b -> StatusBarConfig -> StatusBarConfig # | |
Monoid StatusBarConfig Source # | |
Defined in XMonad.Hooks.StatusBar mappend :: StatusBarConfig -> StatusBarConfig -> StatusBarConfig # mconcat :: [StatusBarConfig] -> StatusBarConfig # | |
Default StatusBarConfig Source # | Per default, all the hooks do nothing. |
Defined in XMonad.Hooks.StatusBar def :: StatusBarConfig # |
:: LayoutClass l Window | |
=> StatusBarConfig | The status bar config |
-> XConfig l | The base config |
-> XConfig l |
Incorporates a StatusBarConfig
into an XConfig
by taking care of the
necessary plumbing (starting, restarting and logging to it).
Using this function multiple times to combine status bars may result in only one status bar working properly. See the section on using multiple status bars for more details.
:: LayoutClass l Window | |
=> StatusBarConfig | The status bar config |
-> (XConfig Layout -> (KeyMask, KeySym)) | The key binding |
-> XConfig l | The base config |
-> XConfig (ModifiedLayout AvoidStruts l) |
Like withSB
, but takes an extra key to toggle struts. It also
applies the avoidStruts
layout modifier and the docks
combinator.
Using this function multiple times to combine status bars may result in only one status bar working properly. See the section on using multiple status bars for more details.
defToggleStrutsKey :: XConfig t -> (KeyMask, KeySym) Source #
Default mod-b
key binding for withEasySB
Available Configs
:: String | The command line to launch the status bar |
-> X PP | The pretty printing options |
-> StatusBarConfig |
Creates a StatusBarConfig
that uses property logging to _XMONAD_LOG
, which
is set in xmonadDefProp
:: String | Property to write the string to |
-> String | The command line to launch the status bar |
-> X PP | The pretty printing options |
-> StatusBarConfig |
Like statusBarProp
, but lets you define the property
:: String | The command line to launch the status bar |
-> X () | What and how to log to the status bar ( |
-> StatusBarConfig |
A generic StatusBarConfig
that launches a status bar but takes a
generic X ()
logging function instead of a PP
. This has several uses:
- With
xmonadPropLog
orxmonadPropLog'
in the logging function, a custom non-PP
-based logger can be used for logging into anxmobar
. - With
mempty
as the logging function, it's possible to manage a status bar that reads information from EWMH properties liketaffybar
. - With
mempty
as the logging function, any other dock liketrayer
orstalonetray
can be managed by this module.
:: String | The command line to launch the status bar |
-> X PP | The pretty printing options |
-> IO StatusBarConfig |
Like statusBarProp
, but uses pipe-based logging instead.
Multiple Status Bars
StatusBarConfig
is a Monoid
, which means that multiple status bars can
be combined together using <>
or mconcat
and passed to withSB
.
Here's an example of what such declarative configuration of multiple status bars may look like:
-- Make sure to setup the xmobar configs accordingly xmobarTop = statusBarPropTo "_XMONAD_LOG_1" "xmobar -x 0 ~/.config/xmobar/xmobarrc_top" (pure ppTop) xmobarBottom = statusBarPropTo "_XMONAD_LOG_2" "xmobar -x 0 ~/.config/xmobar/xmobarrc_bottom" (pure ppBottom) xmobar1 = statusBarPropTo "_XMONAD_LOG_3" "xmobar -x 1 ~/.config/xmobar/xmobarrc1" (pure pp1) main = xmonad $ withSB (xmobarTop <> xmobarBottom <> xmobar1) myConfig
And here is an example of the related xmobar configuration for the multiple status bars mentioned above:
xmobarrc_top Config { ... , commands = [ Run XPropertyLog "_XMONAD_LOG_1", ... ] , template = "%_XMONAD_LOG_1% }{ ..." }
The above example also works if the different status bars support different logging methods: you could mix property logging and logging via pipes. One thing to keep in mind is that if multiple bars read from the same property, their content will be the same. If you want to use property-based logging with multiple bars, they should read from different properties.
XMonad.Util.Loggers includes loggers that can be bound to specific screens,
like logCurrentOnScreen
, that might be useful with multiple screens.
Long-time xmonad users will note that the above config is equivalent to the following less robust and more verbose configuration that they might find in their old configs:
main = do -- do not use this, this is an example of a deprecated config xmproc0 <- spawnPipe "xmobar -x 0 ~/.config/xmobar/xmobarrc_top" xmproc1 <- spawnPipe "xmobar -x 0 ~/.config/xmobar/xmobarrc_bottom" xmproc2 <- spawnPipe "xmobar -x 1 ~/.config/xmobar/xmobarrc1" xmonad $ def { ... , logHook = dynamicLogWithPP ppTop { ppOutput = hPutStrLn xmproc0 } >> dynamicLogWithPP ppBottom { ppOutput = hPutStrLn xmproc1 } >> dynamicLogWithPP pp1 { ppOutput = hPutStrLn xmproc2 } ... }
By using the new interface, the config becomes more declarative and there's less room for errors.
The only *problem* now is that the status bars will not be updated when your screen configuration changes (by plugging in a monitor, for example). Check the section on dynamic status bars for how to do that.
Dynamic Status Bars
Using multiple status bars by just combining them with <>
works well
as long as the screen configuration does not change often. If it does,
you should use dynamicSBs
: by providing a function that creates
status bars, it takes care of setting up the event hook, the log hook
and the startup hook necessary to make the status bars, well, dynamic.
xmobarTop = statusBarPropTo "_XMONAD_LOG_1" "xmobar -x 0 ~/.config/xmobar/xmobarrc_top" (pure ppTop) xmobarBottom = statusBarPropTo "_XMONAD_LOG_2" "xmobar -x 0 ~/.config/xmobar/xmobarrc_bottom" (pure ppBottom) xmobar1 = statusBarPropTo "_XMONAD_LOG_3" "xmobar -x 1 ~/.config/xmobar/xmobarrc1" (pure pp1) barSpawner :: ScreenId -> IO StatusBarConfig barSpawner 0 = pure $ xmobarTop <> xmobarBottom -- two bars on the main screen barSpawner 1 = pure $ xmobar1 barSpawner _ = mempty -- nothing on the rest of the screens main = xmonad $ dynamicSBs barSpawner (def { ... })
Make sure you specify which screen to place the status bar on (in xmobar,
this is achieved by the -x
argument). In addition to making sure that your
status bar lands where you intended it to land, the commands are used
internally to keep track of the status bars.
Note also that this interface can be used with one screen, or if the screen configuration doesn't change.
dynamicSBs :: (ScreenId -> IO StatusBarConfig) -> XConfig l -> XConfig l Source #
Given a function to create status bars, dynamicSBs
adds the dynamic status bar capabilities to the config.
For a version of this function that applies docks
and
avoidStruts
, check dynamicEasySBs
.
Heavily inspired by XMonad.Hooks.DynamicBars
dynamicEasySBs :: LayoutClass l Window => (ScreenId -> IO StatusBarConfig) -> XConfig l -> XConfig (ModifiedLayout AvoidStruts l) Source #
Like dynamicSBs
, but applies docks
to the
resulting config and adds avoidStruts
to the
layout.
Property Logging utilities
xmonadPropLog :: String -> X () Source #
Write a string to the _XMONAD_LOG
property on the root window.
Write a string to a property on the root window. This property is of type
UTF8_STRING
.
xmonadDefProp :: String Source #
The default property xmonad writes to. (_XMONAD_LOG
).
Managing status bar Processes
Spawns a status bar and saves its PID together with the commands that was
used to start it. This is useful when the status bars should be restarted
with xmonad. Use this in combination with killStatusBar
.
Note: in some systems, multiple processes might start, even though one command is provided. This means the first PID, of the group leader, is saved.
Kills the status bar started with spawnStatusBar
using the given command
and resets the state. This could go for example at the beginning of the
startupHook, to kill the status bars that need to be restarted.
Concretely, this function sends a sigTERM
to the saved PIDs using
signalProcessGroup
to effectively terminate all processes, regardless
of how many were started by using spawnStatusBar
.
There is one caveat to keep in mind: to keep the implementation simple; no checks are executed before terminating the processes. This means: if the started process dies for some reason, and enough time passes for the PIDs to wrap around, this function might terminate another process that happens to have the same PID. However, this isn't a typical usage scenario.
killAllStatusBars :: X () Source #
Kill all status bars started with spawnStatusBar
. Note the
caveats in cleanupStatusBar