2021-09-09

Automatically toggle light / dark theme on gnome

Most mobile apps and latest iterations of Android OS now supports automatic theme toggling for day and night. So why shouldn't your linux desktop enjoy this feature?

You can have the same day / night mode in linux OS with gnome!

To get started, we need themes. Gnome by default comes with Adwaita and it's dark version Adwaita-dark (at least on the debian linux setup that I have). You may want to use your own themes.

Now, we are going to write a script to switch between these themes.

Try running gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark' in terminal. This should switch your theme to Adwaita-dark. So, we would use this command to switch between themes.

For apps using gtk-4, that may not be enough to show dark theme. So, also run gsettings set org.gnome.desktop.interface color-scheme prefer-dark.

Write a script theme-toggle.sh as shown below which would check the current time and switch theme based on if it's day or night (I use 5:00 to 18:59 to limit the day theme selection).

#!/bin/bash

hour="$(date +"%-H")"

PID=$(pgrep -f 'gnome-session' | head -n1)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ | cut -d= -f2-)

if [[ $hour -ge 5 && $hour -le 18 ]]; then
	gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita'
    gsettings set org.gnome.desktop.interface color-scheme prefer-light
else
	gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark'
    gsettings set org.gnome.desktop.interface color-scheme prefer-dark
fi

Make this script executable (chmod +x theme-toggle.sh) and place it somewhere convenient (like ~/.local/bin/theme-toggle/theme-toggle.sh).

Try executing the script!

Now that our script is working, how would you manage to run the script when it is the time to switch?

Enter cron. It is a task runner which would run the script at specified times.

You can see all the cron scheduled jobs using the command crontab -l.

But, we want to add a new schedule for our script to run at, say 5:00 and 19:00 hours, marking day and night. So, use the command crontab -e to edit the cron schedule file. And add the following line to the end of the file and save it.

0 5,19 * * * ~/.local/bin/theme-toggle/theme-toggle.sh >/dev/null 2>&1

This schedules our script to run at 0th minute of 5 and 19 hours, on every day.

Hooray! Now your theme should be switching automatically at those specified times.

However, there is a caveat with this. What would happen if your computer was asleep at these hours? Then, cron wouldn't run our script! So, we need to run this script when our computer wakes up from sleep.

To do so, we make use of systemd service. Here, you could write a service as shown below to run your script after the system wakes up from sleep / suspend.

[Unit]
Description=Toggle theme on waking up from suspend
After=suspend.target

[Service]
ExecStart=/home/<user>/.local/bin/theme-toggle/theme-toggle.sh
User=<user>
Group=<user>

[Install]
WantedBy=suspend.target

Replace <user> with your username and groupname (if different, you could check id <user>) and place it in /etc/systemd/system/toggleThemeOnWakeUpFromSuspend.service.

You can enable this service using systemctl enable toggleThemeOnWakeUpFromSuspend.service command and check it's status using systemctl status toggleThemeOnWakeUpFromSuspend.service (It should be in loaded state, else do systemctl daemon-reload to reload the systemd daemon).

You are all set now. Enjoy the new found freedom for your eyes!