I didn’t find an easy way to switch between light and dark mode in i3 on Ubuntu using Gnome. I really prefer light schemes in a well-lit office, and a darker screen when sitting at night. On that note, I really appreciate redshift.

This is how I approached easily changing between light and dark mode:

  • Figure out how to toggle the light/dark preference programmatically
  • Make sure all software reacts to it
    • Preferably: supporting the system settings
    • Fallback: hook into the toggling and adapt the specific programs one-by-one to change themes etc.

Changing theme programmatically

Creating a clickable button in the i3blocks menu is easy:

# in ~/.i3blocks.conf

[colorscheme]
# font awesome sun (f185)
full_text=
command=~/bin/color-scheme>/dev/null

A left click toggles between light and dark, here’s the ~/bin/color-scheme script:

#!/bin/sh

current=$(gsettings get org.gnome.desktop.interface color-scheme)
if [ $? -ne 0 ]; then echo "Could not fetch current color-scheme" >&2; exit 1; fi
echo "Current color-scheme: $current"

case "$current" in
	"'prefer-dark'") new_color_scheme="prefer-light" ;;
	"'prefer-light'"|"'default'") new_color_scheme="prefer-dark" ;;
esac

echo "New color-scheme: $new_color_scheme"

if ! $(gsettings set org.gnome.desktop.interface color-scheme "$new_color_scheme"); then
	echo "Could not set new color-scheme" >&2
	exit 1
fi

Make software react to the system setting

Software that can be configured to adapt to the system wide settings:

  • Firefox
  • gnome-console
    • The default terminal, gnome-terminal, doesn’t support listening in on the system wide color scheme.
    • The apt package is called gnome-console but the terminal’s program is called kgx.
    • After installing it, do a sudo update-alternatives --install /usr/bin/x-terminal-emulator x-terminal-emulator /usr/bin/kgx 1 and sudo update-alternatives --set x-terminal-emulator /usr/bin/kgx, to make it the default terminal.
    • Also: since I’m using i3 and it doesn’t have kgx in its allowlist in /usr/bin/i3-sensible-terminal, I also export TERMINAL=kgx in my .zshrc
  • bat
    • Use the base16 or ansi theme (either in a configuration file, or alias bat="bat --theme=base16")
  • doom emacs
  • Slack
  • element, a matrix chat client
  • elly, my tool for keeping track of Github pull requests (yes, this is a shameless plug; no, it doesn’t need to be configured, because media queries)

Left to fix:

Previous attempt: “signal-lamp”

I tried, and failed, to solve this problem previously, in https://github.com/chelmertz/signal-lamp.

I tried to take ownership of the current state/scheme myself, which would require hooks/APIs for every program I’d like to change.

A particularly bad example: I never found a way to change the theme of all open gnome-terminal windows, so I used wmctrl and xdotool in a loop 🙈 It turned out super buggy and the code wasn’t even pretty to read. A do-over was necessary.

Elsewhere: darkman

I just found Darkman (intro, repo) but it is a bit intrusive. I like the dbus parts but having a separate service for this, and the scripts for every application, is a bit like the “signal-lamp” attempt and rubs me the wrong way (configuration rabbit hole).