41 KiB
Polybar config
- Presentation
- General settings
- Colors declaration for polybar
- Declaration of the bars
- Modules
- Footnotes
Presentation
Polybar is a desktop utility for displaying various information in form of bars for GNU/Linux systems. It is often used as a replacement for native bars available in window managers, such as i3. In my case, I use two instances of polybar in order to get two bars displayed on each screen. The information displayed is either related to i3 itself, or it is system information, such as CPU or disk usage. More information will be given and explained below.
If you want to learn more about how to configure Polybar, you can go to its official repository on Github.
General settings
Some general settings are available for Polybar, and they are declared under
the [settings]
section.
[settings]
Only one setting is used in this configuration though: the ability to relauch polybar on a configuration file rewrite.
screenchange-reload = true
Some global settings are also available in order to adjust the
_NET_WM_STRUT_PARTIAL
top and bottom values:
[global/wm]
margin-top = 32
margin-bottom = 22
Colors declaration for polybar
Like most status bars available, we can declare custom colors to be used in polybar. This part of the configuration file is declared with the following header:
[colors]
As I use pywal as a color scheme generator based on the color of my wallpaper, I need to tell polybar to fetch the colors it will use from xrdb. If such color cannot be used, other colors will be used as fallback colors. First, let’s declare our default background and foreground colors with their alternative option.
background = ${xrdb:color1:#50000000}
background-alt = ${xrdb:color2:#444}
foreground = ${xrdb:color7:#dfdfdf}
foreground-alt = ${xrdb:color6:#555}
Now, we can also declare our primary and secondary colors.
primary = #ffb52a
secondary = #e60053
Polybar is also aware of alerts sent by window managers such as i3 when a window opens in an unfocused workspace. For that, let’s declare an alert color.
alert = #bd2c40
Declaration of the bars
It is possible in i3 to declare as many bars as we wish, and each of these bars will be named. Naming the bar is done in its module declaration like so:
[bar/nameofthebar]
In my configuration, I use two of such bars, one atop of my screen, and one at the bottom.
Top bar declaration
As unimaginative as it might seem, I went for a rather explicit name for my
bars. The top one is simply named top
, as shown below.
[bar/top]
Positioning
We need to set on which screen the bar is to be displayed. Indeed, it is
possible to display a bar on only one specific screen if we wish to.
Actually, it is even the default behavior of polybar, but as we will see
later with the launching script, it is possible to launch bars on multiple
outputs at the same time. Here, we simply get the value of the variable
monitor
from the launch environment.
monitor = ${env:MONITOR}
We have a few position-related variables that need to be set. We can specify whether or not we want our bar at the bottom of the screen —which is the default behavior of polybar—, its width, its height, the radius for the rounding of its corners and whether the bar should be centered or not. In my case, my bars are rather small height-wise, and it occupies most of the width of my screens. There is some gaps between this bar and the border of the screen, but this is due to a border around the bar itself which acts not only on the width of the bar itself, but also on its height.
bottom = false
border-size = 5
<<position-bar-top>>
We also want to add some padding to our bar so our modules are not too close to its edges, especially due to the rounding of the top bar.
padding-left = 2
padding-right = 4
Each module will have some padding around it, so that modules aren’t glued together and instead have some room to breathe. The padding on the left is a bit less than the padding on the right for aesthetic reasons.
module-margin-left = 1
module-margin-right = 2
The top bar doesn’t include any system tray, so let’s disable that.
tray-position = none
Colors and display
As explained above, we declared some global variables when it comes to colors, and this is where they will be used. The bar’s background will be of the same color as the main background color declared earlier, and the same goes for the foreground.
background = ${colors.background}
foreground = ${colors.foreground}
If we wanted, we could also declare a default color for the underlines under the various modules that will be included in the bar, but in our case this variable is unused. So we will simply add this commented line as a memento this is possible, but it won’t have any effect with this current configuration of polybar. Same goes for the border around the bar, it is a useless variable in this configuration since we want the border to be transparent.
line-color = #f00
; border-color = #00000000
Although the variable for the default line color is not used, we still have to set the default width of the underline of our modules. By default, their underline will be three pixels thick.
line-size = 3
Fonts and locale
Now we can chose which font fill be used in order to display text in this bar, as well as the locale we want. The locale will be useful for displaying information such as date and time, which is a module we will have in this top bar. First, the declaration of the locale is done like so:
locale = ja_JP.UTF-8
Now, we can declare the fonts we want to use in Polybar. It is possible to declare several of them, the first one is the one which gets the absolute priority, and the next ones with a larger index are fallback fonts. Font declaration accepts the fontconfig format as well as possible offset1. Five fonts are used in my polybar config:
Font | fontconfig | Vertical offset | Why it’s used |
---|---|---|---|
Fira Sans | Fira Sans Book:style=Book:pixelsize=10 | 1 | Text display |
IPA Mincho | IPAMincho:style=regular:pixelsize=6 | 0 | Japanese text display |
Unifont | unifont:fontformat=truetype:size=6:antialias=false | 0 | Fallback font |
NotoEmoji | NotoEmoji:style=Book:scale=16 | 0 | Emoji display |
Siji | Siji:pixelsize=8 | 0 | Symbol display |
Default font | fixed:pixelsize=8 | 0 | Fallback font |
for i in range(0, len(table)):
print("font-{0} = {1};{2}".format(i, table[i][1], table[i][2]))
font-0 = Fira Sans Book:style=Book:pixelsize=10;1 font-1 = IPAMincho:style=regular:pixelsize=6;0 font-2 = unifont:fontformat=truetype:size=6:antialias=false;0 font-3 = NotoEmoji:scale=12:style=Book;0 font-4 = Siji:pixelsize=8;0 font-5 = fixed:pixelsize=8;0
Here’s the font configuration:
<<font-config()>>
Note that only Fira Sans get a small offset due to the size of the font and the height of the bar itself.
Modules
Finally, arguably one of the most important parts of our bar configuration: the module selection. Modules can be positioned in three different parts of our bar: to the right, in middle or to the left. On the left, we want our workspace indicator for i3. In the middle, we’ll get the title of the focused window, and to the left we’ll have the date and time.
left = 'modules-left = '
center = 'modules-center = '
right = 'modules-right = '
for line in table:
if line[1] == 'left':
left += line[0] + ' '
elif line[1] == 'center':
center += line[0] + ' '
else:
right += line[0] + ' '
return left + '\n' + center + '\n' + right
Here is the list of modules used:
Module name | Position | Brief description |
---|---|---|
i3 | left | i3 workspace indicator |
xwindow | center | Name of the focused window |
date | right | Date and time |
<<modules-generate(table=top-modules)>>
Each module will be described in details later in this document.
Bottom bar declaration
As described above, we will once again have to declare our bar with an equally unimaginative but explicit name.
[bar/bottom]
Positioning
The variables are the same as above, but two of them will be slightly modified:
bottom = true
border-size = 0
<<position-bar-bottom>>
When it comes to the bottom bar, I prefer to have it fit my outputs, without any margin around it. And of course, I have to declare it as being at the bottom of the screen, hence these modifications. As regards the padding of our modules, their own margins, and the screen output, they aren’t modified.
<<padding-bar>>
<<module-margin-bar>>
<<monitor-bar>>
However, we do display the system tray on this bottom bar at its right. It has no padding and it is not detached from the bar (this allows the bar to be displayed under the icons of the system tray), and their maximum size was chosen so they are well visible without being too big.
tray-position = right
tray-padding = 0
tray-detached = false
tray-maxsize = 15
Colors and display
Nothing changes from the top bar, all the variables stay with the same values. See Colors and display of the top bar for more information.
<<bar-colors>>
<<line-border-color>>
<<line-size-bar>>
Fonts and locale
Again, nothing changes from the top bar, so for more info on what’s going on, see Fonts and locale of the top bar.
<<locale-bar>>
<<font-config()>>
Modules
Now, we can get to something interesting again: modules. This bar has a lot more modules than the top bar. Here is the list of the modules we have on the bottom bar:
Module name | Position | Brief description |
---|---|---|
mpd | left | MPD status indicator |
filesystem | right | Free storage in our filesystem |
wlan | right | Name of the active WiFi network |
eth | right | Local address on Ethernet |
volume | right | System volume |
backlight-acpi | right | Screen backlight |
cpu | right | CPU usage |
memory | right | RAM usage |
temperature | right | CPU temperature |
custom-battery | right | Battery usage |
Here’s the corresponding configuration:
<<modules-generate(table=table-modules-bottom)>>
All these modules will be explained below.
As you may have noticed, no modules will be displayed in the middle of this bar.
Modules
Before we begin to describe the different modules, I would like to point out something that will be repeated multiple times if I don’t talk about it right now: for each module, it is possible to declare the foreground and background color of the prefix of the modules, as well as the underline color and the padding of the module. I like these parameters to be rather consistent, so the code block you will see below will often be reused. The colors refer to the colors declared earlier, and the padding is minimal.
format-prefix-foreground = ${colors.foreground-alt}
format-prefix-underline = ${colors.secondary}
format-underline = ${colors.secondary}
format-padding = 1
Hardware
Battery
This module allows the user to get a battery widget among the polybar
modules that will also send a notification to the user if the battery level
drops below a certain value. This module relies on polybar-another-battery
(link) and its generated binary polybar-ab
which should be in the $PATH
.
The first line of the module declaration lets the user name the module
however they want. In this case, the name is custom-battery
.
[module/custom-battery]
Since it is not a core module, we have to declare it as a custom script so polybar knows what to do with it.
type = custom/script
We now can specify the script execution, and whether or not the script will be continuously outputting something. In our case, the answer to this last question is yes.
exec = polybar-ab -polybar -thr 10
tail = true
The -thr 10
specifies the threshold for polybar-ab at which it should warn
the user about the battery level of the computer.
Of course, users on desktop computers won’t need this module which is aimed at laptop users. Feel free to remove it if you do not need it.
Filesystem
This module allows to display information about our filesystem, including (and this is what I use this module for) displaying the used space and remaining space on different mount points. This module is an internal module to polybar, so let’s declare it as such:
[module/filesystem]
type = internal/fs
We can specify how often the filesystem is to be checked with the variable
interval
. I prefer it not to check it too often in order to not ping too
often my drives, but I want it to be often enough so it is somewhat
responsive. This is why I settled on a 20 seconds interval.
interval = 20
We now have to indicate where our different filesystems are mounted. In the case of my main computer Marpa, I have two partitions, the root partition and the home partition. But on my travel laptop, I only have the root partition, hence the usage of the below Elisp code that determines based on the computer it is running whether or not the second mount point to my home partition should be included.
(if (string= system-name "Marpa")
"mount-1 = /home")
mount-0 = /
<<include-home-partition()>>
Now we can set the format of our module. There are two mains formats, one for mounted and one for unmounted mountpoints. For both, we’ll simply use their label.
format-mounted = <label-mounted>
format-unmounted = <label-unmounted>
When it comes to the mounted partition, we want to display the name of the mountpoint and how used it is, both in terms of gigabytes and percentage.
label-mounted = 💽 %mountpoint%: %used%/%total% (%percentage_used%%)
label-mounted-foreground = ${colors.foreground}
label-mounted-underline = ${colors.secondary}
If the volume is unmounted (which should be worrying considering the mountpoints chosen), then we’ll simply have a message telling us about that, and the foreground color will use the alternative foreground color described earlier.
label-unmounted = %mountpoint% not mounted
label-unmounted-foreground = ${colors.foreground-alt}
Xbacklight
This module is used in order to display the level of brightness of a screen. It is not used by itself, but rather by other modules, such as ACPI backlight. First of all, this module is an internal module for xbacklight. It will also display the brightness percentage, prefixed by a sun emoji. Lastly, it will be underlined by a green line.
[module/xbacklight]
type = internal/xbacklight
format = <label>
label = %percentage%%
format-prefix = "🌞 "
format-underline = #9f78e1
ACPI backlight
This module indicates the backlight level of a screen thanks to the ACPI
Linux module. There isn’t much to tell about the module itself other than it
inherits the module described above, xbacklight. It also sets which driver
should be used, in this case the intel_backlight
driver.
[module/backlight-acpi]
inherit = module/xbacklight
type = internal/backlight
card = intel_backlight
CPU
This module indicates how much of the CPU is being used. As shown below, I made it so we can see the load on each core. The first thing to do is to declare the module as an internal module dedicated to the CPU.
[module/cpu]
type = internal/cpu
Now, we can set the refresh rate in seconds of the module. I like it at two seconds:
interval = 2
Now, let’s declare what will be displayed. The format will be a computer emoji followed by ramp characters.
format = <label> <ramp-coreload>
format-prefix = "💻 "
label = %percentage%%
ramp-coreload-0 = ▁
ramp-coreload-1 = ▂
ramp-coreload-2 = ▃
ramp-coreload-3 = ▄
ramp-coreload-4 = ▅
ramp-coreload-5 = ▆
ramp-coreload-6 = ▇
ramp-coreload-7 = █
Finally, this module will be underlined in red.
format-underline = #f90000
Memory
Similarly to the CPU module, it is possible for Polybar to display the RAM load of the computer. As above, let’s declare this module as an internal module to Polybar:
[module/memory]
type = internal/memory
As the CPU module still, the refresh rate will be of two seconds.
interval = 2
Its format will be the percentage of used RAM, prefixed by a disk emoji.
format = <label>
format-prefix = "💿 "
label = %gb_used%
Lastly, it will be underlined in green.
format-underline = #4bffdc
Wlan
It is possible for Polybar to display the name of the current WiFi network the computer is connected to. For that, we first need to declare the Wlan module as an internal module of Polybar.
[module/wlan]
type = internal/network
Now, we should set the name of the interface. As this depends on the hardware I am using, I am going to rely on the machine’s hostname and on some Elisp code to get this setting right.
(cond ((string= system-name "Marpa") "wlp8s0")
((string= system-name "gampo") "wlp3s0"))
interface = <<name-wlan-interface()>>
The name of the current WiFi network will be refreshed every three seconds.
interval = 3.0
The format of the module when connected to a network will the the display of the antenna emoji, followed by the name of the network. When disconnected, the module will simply be empty.
format-connected = <label-connected>
format-connected-prefix = "📶 "
label-connected = %essid%
Ethernet
Just like any other module, the ethernet module has to be declared as an internal module.
[module/eth]
type = internal/network
And just like the Wlan module, it requires an interface which can vary depending on the machine I am using, hence this piece of Elisp:
(cond ((string= system-name "Marpa") "enp9s0")
((string= system-name "gampo") "enp0s25"))
interface = <<name-eth-interface()>>
The format of this module will be the local address of the computer on the network, and it will be prefixed by a desktop computer emoji. Meanwhile, when disconnected, the module won’t be visible.
format-connected = <<label-connected>>
format-connected-prefix = "🖥 "
label-connected = %local_ip%
format-disconnected =
The module will be underlined in green.
format-connected-underline = #55aa55
Volume
The volume module in Polybar is linked to its internal bindings to ALSA. Let’s declare it accordingly.
[module/volume]
type = internal/alsa
Its format is quite simple: if the audio is not muted, it is then prefixed with a speaker emoji, followed by the volume percentage.
format-volume = <label-volume>
format-volume-prefix = "🔈 "
label-volume = %percentage%%
If the audio is muted, then the only thing the user will see is the muted speaker emoji followed by the text “muted”.
format-muted-prefix = "🔇 "
label-muted = muted
In any case, it will be underlined in green.
format-volume-underline = #55aa55
Temperature
The temperature module checks the temperature of the CPU, and warns the user above a certain threshold of heat, in my case if my CPU is above 60°C.
[module/temperature]
type = internal/temperature
thermal-zone = 0
warn-temperature = 60
The format of the module is the thermometer emoji followed by the temperature of the CPU. If the CPU becomes too hot, the text will change color for the secondary foreground color.
format = <label>
format-underline = #f50a4d
format-warn = <label-warn>
format-warn-underline = ${self.format-underline}
format-prefix = "🌡 "
format-warn-prefix = "🌡 "
label = %temperature-c%
label-warn = %temperature-c%
label-warn-foreground = ${colors.secondary}
Software
Window title
This module’s aim is to simply provide the name of the currently focused
window given by Xorg. This module is an internal module to polybar, that is
to say it is built-in, and is of the type xwindow
. So, let’s declare the
module accordingly, including the piece of common code declared at the
beginning of the chapter:
[module/xwindow]
type = internal/xwindow
<<mod-prefix-col>>
Now we can take care of the label, which is the actual text that will be
displayed. In our case, we want the label to be the title of the current X
window, hence the value of label
, and we don’t want it to be too long,
though I’m not sure I’ve often seen window titles longer than 70 characters.
label = %title%
label-maxlen = 70
i3
Now comes the module for i3 interaction. Thanks to this module, it is possible to show which workspaces are active and focused, and it is possible to change workspaces by clicking on the ones displayed in the bar. First, let’s declare it; it is an internal module by the way.
[module/i3]
type = internal/i3
Now, let’s display only the workspaces that are on the current output. This means if a workspace is either inactive or on another screen or output, it won’t be displayed.
pin-workspaces = true
We also want our workspaces to be sorted by number rather than by output.
index-sort = true
I don’t want to be able to scroll through the workspaces when my mouse is hovering the module: when it happens, most of the time it was done accidentally. So let’s deactivate that. However, I sometimes like to click on them to switch from one another, so we’ll keep that activated.
enable-scroll = false
wrapping-scroll = false
reverse-scroll = false
enable-click = true
This parameters splits the workspaces’ name on :
. Let’s deactivate that.
strip-wsnumbers = false
An on the topic of workspaces’ name, fuzzy-match
allows the user to use
fuzzy search for workspaces’ name when we will be applying custom names
below. Not really useful since I only use the default workspaces’ name, but
it’s good to have it enabled by default.
fuzzy-match = true
The label format is described first by its label, but also by one of its three possible modes: focused, visible or unfocused. These will be discussed later, but for now let’s simply set our format.
format = <label-state> <label-mode>
We also wand to set the label mode to be whichever mode the workspace described by polybar is in. This label will also have a padding of 2 pixels, and the text will be written in white.
label-mode = %mode%
label-mode-padding = 2
label-mode-foreground = #000
Workspace icons
Now, let’s name our workspaces. We can give them whatever name we want them to have, but I just like the aesthetics of Japanese characters, so let’s go with the kanji equivalent of the number of the workspaces.
workspace number | name |
---|---|
1 | 一 |
2 | 二 |
3 | 三 |
4 | 四 |
5 | 五 |
6 | 六 |
7 | 七 |
8 | 八 |
9 | 九 |
0 | 十 |
ws-icon-0 = 1;一 ws-icon-1 = 2;二 ws-icon-2 = 3;三 ws-icon-3 = 4;四 ws-icon-4 = 5;五 ws-icon-5 = 6;六 ws-icon-6 = 7;七 ws-icon-7 = 8;八 ws-icon-8 = 9;九 ws-icon-9 = 0;十
Here are the corresponding configuration lines:
<<generate-ws-names()>>
In case we create a workspace which isn’t named from 0
to 9
, I want it
to appear as is.
ws-icon-default = %index%
Focused workspaces
Now we can define the label itself. First, we will need to define the label when the workspace is focused. We’ll simply take the alternative background for the focused label, and the underline will be defined from Xrdb’s 8th color, with yellow as the fallback color. It will also have a two pixels padding. The text itself will be the dynamic icons declared above.
label-focused = %icon%
label-focused-background = ${colors.background-alt}
label-focused-underline = ${xrdb:color8:#ffff00}
label-focused-padding = 2
Visible workspaces
The visible
label is related to the focused
labels since it is
describing workspaces that can be seen, but are not currently focused, i.e.
a workspace that appears on another screen than the one currently used so
it is visible, but it isn’t focused. The difference with the unfocused
workspaces is that the latter are neither focused nor visible. As you can
see, we are simply using all of the declarations from above for the focused
labels so we can ensure they appear the same way the focused labels do.
label-visible = ${self.label-focused}
label-visible-background = ${self.label-focused-background}
label-visible-underline = ${self.label-focused-underline}
label-visible-padding = ${self.label-focused-padding}
Unfocused workspaces
When it comes to the unfocused label, there won’t be any custom background or underline, so we’ll just copy the two remaining lines from the focused labels for unfocused labels.
label-unfocused = %icon%
label-unfocused-padding = 2
Urgent workspaces
Lastly, we get our urgent workspaces: workspaces in which most of the time it’s just a popup that appeared or a software that finally launched itself while working on something else on another workspace. To make it a bit more unique, let’s declare its background as being the color 0 from xrdb, with some dark red as the fallback color. And as the other labels, the text will be the icon and it will have a two pixels padding.
label-urgent = %icon%
label-urgent-background = ${xrdb:color0:#bd2c40}
label-urgent-padding = 2
Mpd
Mpd is a music server for GNU/Linux systems that interfaces will several front-ends, including ncmpcpp (the main one I use), ncmpcpp and mpc. It also interfaces with polybar thanks to some built in commands.
First, let’s declare our module as an internal module.
[module/mpd]
type = internal/mpd
The next thing we want to do is set the label for the module: we will display both the title and the name of the artist of the song playing. The maximum length will be 70 characters.
label-song = %title% - %artist%
label-song-maxlen = 70
label-song-ellipsis = true
While Mpd is online, the format of the module should be the control icons and then the song label.
format-online = <icon-prev> <toggle> <icon-next> <label-song>
icon-prev = ⏭
icon-stop = ⏹
icon-play = ▶
icon-pause = ⏸
icon-next = ⏭
If Mpd is offline, then I would like to display a short messages that tells the user so.
format-offline = <label-offline>
label-offline = 🎵 mpd is offline
Date
This module is really simple: it gives the current date. It is an internal module, and as declared below, it updates every second:
[module/date]
type = internal/date
interval = 1
The main date and time format is the standard one, following the ISO-8601 standard.
date = %Y-%m-%d
time = %H-%M-%S
It also has an alternative format which I occasionally use, which displays the date and time in the Japanese format.
date-alt = %A %d, %B
time-alt = %H:%M:%S
The format is quite simple: a clock emoji preceding the date and time.
format-prefix = "🕑 "
label = %date% %time%
This module is underlined in blue:
format-underline = #0a6cf5