Work with Polybar in Emacs X Window Manager, Part 1: Getting Started

For the past six months, I’ve used the Emacs X Window Manager daily as my main window manager and it’s been a great tool. It’s enabled me to move from using a disparate set of tools to now having an Integrated Computing Environment. It’s true: Emacs really does make a great operating system.

Starting and Stopping Polybar

Like many, I’ve adopted a lot of the configuration used by David Wilson of System Crafters. Part of that configuration includes his efs/start-panel and efs/kill-panel functions. These functions start a Polybar shell command from within Emacs while making sure to kill any existing processes before spawning a new instance. It does this by capturing a reference to the process that later can be passed to the built-in kill-process function.

The Problem

Unfortunately, I run a multi-monitor setup, and David’s script that I borrowed only launches polybar on the main screen. As a temporary workaround, I continued to use the bash script I call from within my old bspwm configuration to launch polybar. This didn’t feel very Emacs Zen-like, so I set out to devise a better way.

My Solution

I start by setting up an empty variable that will hold references to each running polybar.

(defvar bp/polybar-processes nil 
  "A list of running polybar processes. So that we can kill them later. 👿")

In the next section, I query for a list of attached monitors, this type via polybar itself. I could use xrandr for this, but this output is easier to parse. Also, it’s one less dependency to rely upon from within a single script. Using cut I split the input by the delimiter “:”, and take the first fragment, remove extraneous new lines. Finally, break the monitor names into their own entries.

(defun bp/get-monitors-list () 
  "Get a list of the currently connected monitors. Requires polybar, instead of relying on xrandr, though you probably want it installed too."
      (shell-command-to-string "polybar -m | cut -d: -f 1") 0 -1) "\n"))

As defined, the bp/kill-panel function will iterate over the list of running polybar processes and stop them in succession, and finally, resetting the process list to nil.

(defun bp/kill-panel () 
  "Stop any running polybar processes"
  (let ((process-list bp/polybar-processes)) 
      (p process-list) 
      (kill-process p))) 
    (setq bp/polybar-processes nil))

As its first order of business, the bp/start-panel function calls the bp/kill-panel function to clear out any existing running processes. It then calls bp/get-monitors-list, mapping over our list monitors and interpolating their names into the shell command to start polybar.

(defvar bp/polybar-config-location "~/.doom.d/exwm/polybar.config.ini" 
  "The customized location of your polybar config.ini. You'll most certainly want to customize this value. ")

(defun bp/start-panel () 
  "Start polybar on each connected monitor"
  (setq bp/polybar-processes 
    (mapcar (lambda (monitor) 
      (start-process-shell-command "polybar" nil 
        (format "MONITOR=%s polybar -c %s --reload main" monitor bp/polybar-config-location))) 

With these in place, I can now interactively show and hide the polybar as needed from within Emacs.

Stay tuned for part two of this series, where we’ll set up workspace indicators on polybar.


Join the conversation

Your email address will not be published. Required fields are marked *