Polybar (https://polybar.github.io/) is:
- Minimal
- Configurable
- Provides a reliable system tray
- Easy to integrate with Emacs!
First install Polybar using your distro’s package manager. Strangely it’s not in Ubuntu 20.04!
Here’s how to compile it if your distro doesn’t have it (which is rare):
# Install dependencies on Ubuntu 20.04
sudo apt update
sudo apt install build-essential git cmake cmake-data pkg-config \
python3-sphinx libcairo2-dev libxcb1-dev libxcb-util0-dev \
libxcb-randr0-dev libxcb-composite0-dev python3-xcbgen xcb-proto \
libxcb-image0-dev libxcb-ewmh-dev libxcb-icccm4-dev
# Clone the repo and compile version
git clone --recursive https://github.com/polybar/polybar
cd polybar
git checkout 3.5.2
./build.sh
NOTE: The build.sh
script will ask you about features to enable in the Polybar build. It is necessary to say answer Y
to the polybar-msg
feature! You should also answer Y
to the question about running sudo make install
.
Also install some icon fonts:
sudo apt install fonts-font-awesome fonts-material-design-icons-iconfont
Tangle this to .config/polybar/config
; Docs: https://github.com/polybar/polybar
;==========================================================
[settings]
screenchange-reload = true
[global/wm]
margin-top = 0
margin-bottom = 0
[colors]
background = #f0232635
background-alt = #576075
foreground = #A6Accd
foreground-alt = #555
primary = #ffb52a
secondary = #e60053
alert = #bd2c40
underline-1 = #c792ea
[bar/panel]
width = 100%
height = 35
offset-x = 0
offset-y = 0
fixed-center = true
enable-ipc = true
background = ${colors.background}
foreground = ${colors.foreground}
line-size = 2
line-color = #f00
border-size = 0
border-color = #00000000
padding-top = 5
padding-left = 1
padding-right = 1
module-margin = 1
font-0 = "Cantarell:size=18:weight=bold;2"
font-1 = "Font Awesome:size=14;2"
font-2 = "Material Icons:size=20;5"
font-3 = "Fira Mono:size=13;-3"
modules-right = cpu temperature battery date
tray-position = right
tray-padding = 2
tray-maxsize = 28
cursor-click = pointer
cursor-scroll = ns-resize
[module/cpu]
type = internal/cpu
interval = 2
format = <label> <ramp-coreload>
format-underline = ${colors.underline-1}
click-left = emacsclient -e "(proced)"
label = %percentage:2%%
ramp-coreload-spacing = 0
ramp-coreload-0 = ▁
ramp-coreload-0-foreground = ${colors.foreground-alt}
ramp-coreload-1 = ▂
ramp-coreload-2 = ▃
ramp-coreload-3 = ▄
ramp-coreload-4 = ▅
ramp-coreload-5 = ▆
ramp-coreload-6 = ▇
[module/date]
type = internal/date
interval = 5
date = "%a %b %e"
date-alt = "%A %B %d %Y"
time = %l:%M %p
time-alt = %H:%M:%S
format-prefix-foreground = ${colors.foreground-alt}
format-underline = ${colors.underline-1}
label = %date% %time%
[module/battery]
type = internal/battery
battery = BAT0
adapter = ADP1
full-at = 98
time-format = %-l:%M
label-charging = %percentage%% / %time%
format-charging = <animation-charging> <label-charging>
format-charging-underline = ${colors.underline-1}
label-discharging = %percentage%% / %time%
format-discharging = <ramp-capacity> <label-discharging>
format-discharging-underline = ${self.format-charging-underline}
format-full = <ramp-capacity> <label-full>
format-full-underline = ${self.format-charging-underline}
ramp-capacity-0 =
ramp-capacity-1 =
ramp-capacity-2 =
ramp-capacity-3 =
ramp-capacity-4 =
animation-charging-0 =
animation-charging-1 =
animation-charging-2 =
animation-charging-3 =
animation-charging-4 =
animation-charging-framerate = 750
[module/temperature]
type = internal/temperature
thermal-zone = 0
warn-temperature = 60
format = <label>
format-underline = ${colors.underline-1}
format-warn = <label-warn>
format-warn-underline = ${self.format-underline}
label = %temperature-c%
label-warn = %temperature-c%!
label-warn-foreground = ${colors.secondary}
Launch it with this command:
polybar panel
(defvar efs/polybar-process nil
"Holds the process of the running Polybar instance, if any")
(defun efs/kill-panel ()
(interactive)
(when efs/polybar-process
(ignore-errors
(kill-process efs/polybar-process)))
(setq efs/polybar-process nil))
(defun efs/start-panel ()
(interactive)
(efs/kill-panel)
(setq efs/polybar-process (start-process-shell-command "polybar" nil "polybar panel")))
Now we can start Polybar when EXWM starts up, inside of efs/exwm-init-hook
:
;; Start the Polybar panel
(efs/start-panel)
NOTE: Disable exwm-systemtray
before restarting Emacs so that the tray works!
Use the power of emacsclient
! We’ll cover this more in a video next week.
;; Make sure the server is started (better to do this in your main Emacs config!)
(server-start)
Use it to get the EXWM workspace number:
emacsclient -e "exwm-workspace-current-index"
Define a function to call the workspaces whatever you want!
(defun efs/polybar-exwm-workspace ()
(pcase exwm-workspace-current-index
(0 "")
(1 "")
(2 "")
(3 "")
(4 "")))
Try it out:
emacsclient -e "exwm-workspace-current-index"
One thing to keep in mind is that this works well for global variables, but not so great for frame parameters! The timing has to be perfect to get the value of a frame parameter for the workspace frame you land on. It’s possible, but requires more code.
modules-left = exwm-workspace
[module/exwm-workspace]
type = custom/ipc
hook-0 = emacsclient -e "(efs/polybar-exwm-workspace)" | sed -e 's/^"//' -e 's/"$//'
initial = 1
format-underline = ${colors.underline-1}
format-padding = 1
NOTE: The extra sed
part is necessary! If you don’t have this command available, you can install it from your distro’s package repository.
Use the polybar-msg
command to invoke a “hook index” to have the module update itself:
polybar-msg hook exwm 1
Learn more about the IPC module on the Polybar Wiki: https://github.com/polybar/polybar/wiki/Module:-ipc
(defun efs/send-polybar-hook (module-name hook-index)
(start-process-shell-command "polybar-msg" nil (format "polybar-msg hook %s %s" module-name hook-index)))
(defun efs/send-polybar-exwm-workspace ()
(efs/send-polybar-hook "exwm-workspace" 1))
;; Update panel indicator when workspace changes
(add-hook 'exwm-workspace-switch-hook #'efs/send-polybar-exwm-workspace)
Learn how to configure everything else in Polybar:
https://github.com/polybar/polybar/wiki
Some useful bits from my own configuration: