Check out the final code here.
¶You need a panel!
Polybar (https://polybar.github.io/) is:
- Minimal
- Configurable
- Provides a reliable system tray
- Easy to integrate with Emacs!
¶Installing Polybar
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
¶Basic Polybar config
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
¶Starting Polybar from Emacs
(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!
¶Requesting information from Emacs
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"
¶Important caveat!
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.
¶Adding a workspace indicator to the panel
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.
¶Sending information from Emacs using hooks
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
¶Invoking the hook from within Emacs
(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)
¶Check out the Polybar wiki
Learn how to configure everything else in Polybar:
https://github.com/polybar/polybar/wiki
Some useful bits from my own configuration: