Create your own i3/sway status bar with some bash and python

21 juin 2020 · 5 min read

i3 is a tiling window manager on Linux. It supports tiling, stacking, and tabbing layouts, which it handles dynamically. The advantage is that you no longer waste time organizing your windows with the mouse. With i3 the layout is automatic. The windows open by occupying the available space. Using customizable keyboard shortcuts, you can move them around, display them full screen, arrange them horizontally or vertically. This is much more convenient and faster than using the mouse.

Another advantage is that the status bar is a single line of fully configurable text. No need for extensions like on Gnome or KDE that don’t always meet your needs.

You want a status bar that displays the current price of some crypto-currencies ? a button to enable/disable VPN ? display the weather ? display your public IP address ? it is simple to do with some bash and python. Here is how to do it.

At the bottom of this article, you will find the link to a Github repository with the source code of all the widgets shown in the bar below.

i3 status

Here is a situation :

i3 status

i3 and others

i3 on GitHub is a relatively old but still active project. The system is light and powerful. i3-gaps is a “fork” that creates a gap between windows for a visual effect. There is also Sway which works with Wayland (the successor of the X11 graphics server). But it does not support NVIDIA graphics cards.

The scripts presented here will work on all those window managers.

i3status

The default status bar is i3status. A simple configuration file displays the date and time, memory usage, free disk space, battery level and other useful informations.

More advanced alternatives exist : i3pystatus, goi3bar, i3status-rust… but why to use a heavy and complicated framework when you can do it yourself ?

The i3bar protocol is well documented. You just have to produce a JSON file in standard output and read the events in standard input (click events from the bar elements).

Display date and time

In the /home/your-name/.config/i3/config file, modify the status_command line to run your bash script :

bar {
  status_command exec /home/your-name/.config/i3status/mybar.sh
}

A basic example of this bash script is given at https://github.com/i3/i3/blob/next/contrib/trivial-bar-script.sh. Let’s use this template to create the file /home/your-name/.config/i3status/mybar.sh :

# Send the header so that i3bar knows we want to use JSON:
echo '{ "version": 1 }'

# Begin the endless array.
echo '['

# We send an empty first array of blocks to make the loop simpler:
echo '[]'

# Now send blocks with information forever:
while :;
do
  echo ",[{\"name\":\"id_time\",\"full_text\":\"$(date)\"}]"
  sleep 1
done

The infinite while loop will call every second the system command date to display the date and time. You can change the sleep value to refresh every 10 seconds, for example. Reload the i3 configuration with the WIN+SHIFT+R keyboard keys. Your status bar now looks like this :

i3 status date

Click events

First, let’s create a small bash script named /home/your-name/.config/i3status/click_time.sh. It will be called when you click on the date/time field in the status bar :

#!/bin/sh
cal -y          # displays the year calendar
read -n 1 -r -s # wait for a touch key to exit the terminal

Don’t forget to make this script executable with the command chmod +x click_time.sh.

Modify the previous mybar.sh script as follows :

echo '{ "version": 1, "click_events":true }'
echo '['
echo '[]'

# launched in a background process
(while :;
do
  echo ",[{\"name\":\"id_time\",\"full_text\":\"$(date)\"}]"
  sleep 1
done) &

# Listening for STDIN events
while read line;
do
  # echo $line > /tmp/tmp.txt
  # on click, we get from STDIN :
  # {"name":"id_time","button":1,"modifiers":["Mod2"],"x":2982,"y":9,"relative_x":67,"relative_y":9,"width":95,"height":22}

  # DATE click
  if [[ $line == *"name"*"id_time"* ]]; then
    alacritty -e /home/your-name/.config/i3status/click_time.sh &
  fi  
done

Some explanations :

  • "click_events":true indicates to the i3 protocol that we are going to handle mouse events.
  • the main loop is then executed in the background so that the standard input listening loop works in parallel.
  • An example of the event received in JSON is shown in comment. Refer to the i3bar protocol documentation for more information.
  • If the ID of the item clicked contains id_time, the click_time.sh script is executed. It displays the current year’s calendar in a terminal. alacritty can be replaced with the terminal of your choice.

Demonstration ! Clicking on the date displays the annual calendar :

i3 status date

Display the processor usage rate

Let’s create the python file /home/your-name/.config/i3status/cpu.py :

#!/usr/bin/env python3
# install the package "psutil" with the command "pip3 install psutil --user"
import psutil
print(psutil.cpu_percent(interval=1), end='')

This script displays for example 1.2 if the CPU is busy at 1.2%.

Let’s modify the mybar.sh script :

echo '{ "version": 1, "click_events":true }'
echo '['
echo '[]'

# launched in a background process
(while :;
do
  echo -n ",["
  echo -n "{\"name\":\"id_cpu\",\"background\":\"#283593\",\"full_text\":\"$(/home/your-name/.config/i3status/cpu.py)%\"},"
  echo -n "{\"name\":\"id_time\",\"background\":\"#546E7A\",\"full_text\":\"$(date)\"}"
  echo -n "]"
  sleep 1
done) &

# Listening for STDIN events
while read line;
do
  # echo $line > /tmp/tmp.txt
  # on click, we get from STDIN :
  # {"name":"id_time","button":1,"modifiers":["Mod2"],"x":2982,"y":9,"relative_x":67,"relative_y":9,"width":95,"height":22}

  # DATE click
  if [[ $line == *"name"*"id_time"* ]]; then
    alacritty -e /home/your-name/.config/i3status/click_time.sh &

  # CPU click
  elif [[ $line == *"name"*"id_cpu"* ]]; then
    alacritty -e htop &
  fi
done

The bar now looks like this:

i3 status date

You may have noticed that a background color is added with the key background. When you click on the CPU usage, the htop utility is launched in a terminal.

Other useful widgets

So, this is a simple way to create an i3 status bar. If you have other ideas don’t hesitate to share them.

Icons can be displayed using the Font Awesome.

Here is a full i3 status configuration on Github where you will also find the widgets to start/stop a VPN, display the weather, public IP address, local IP address, memory usage, battery level, volume and the number of available system packages to update.