36

Has anyone found a way to automatically switch between "light" and "dark" modes yet, with regards to the "Window Theme" in Ubuntu's settings (Settings → AppearanceWindow ThemeLight / Standard / Dark)?

Digging into the settings every morning or evening is a real pain. It'd be great to be able to automatically switch to "dark" mode at sunset, and automatically switch to "light" mode at sunrise.

6 Answers6

35

For GNOME, this shell extension exists: Night Theme Switcher

It has quite a lot of options and already works out of the box, without having to configure anything, but the configuration is straight forward as well!

Screenshot of the Schedule tab

Screenshot of the GTK theme tab

sk22
  • 506
15

The terminal command for changing theme is:

gsettings set org.gnome.desktop.interface gtk-theme Yaru-dark

for the Yaru-dark theme, and

gsettings set org.gnome.desktop.interface gtk-theme Yaru-light

for the Yaru-light theme.

Now, there's something called cron-job for scheduling jobs (basically executing something, repeatedly at specific time). So, you can write a cron-job to execute these commands at specified times (something like change to dark theme at 9 PM and light theme at 6 AM).

Add the following to a file named script.sh:

#!/bin/bash
echo export DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS > lightscript.sh
echo export DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS > darkscript.sh
echo "gsettings set org.gnome.desktop.interface gtk-theme Yaru-light" >> lightscript.sh
echo "gsettings set org.gnome.desktop.interface gtk-theme Yaru-dark" >> darkscript.sh
chmod 755 lightscript.sh
chmod 755 darkscript.sh

currenttime=$(date +%H:%M) if [[ "$currenttime" > "21:00" ]] || [[ "$currenttime" < "06:00" ]]; then ./darkscript.sh else ./lightscript.sh fi

Make the file executable running:

chmod 755 /path/to/script.sh

or:

chmod +x /path/to/script.sh

Run gnome-session-properties in terminal. Add a new start up program by clicking add on right side and selecting the script.sh file by browsing and save it with some name and comment. This will tell GNOME to create lightscript.sh and darkscript.sh whenever you login through GUI.

Add your job (change theme) to crontab by using the command:

crontab -e

and choosing a suitable editor or you can go to /var/spool/cron/crontabs and edit the file with your username. Accessing the file this way requires sudo privileges. Add the following two lines (with /path/to/ replaced by actual path):

0 6 * * * /path/to/lightscript.sh
0 21 * * * /path/to/darkscript.sh

It will say:

crontab: installing new crontab

after exiting the command. You can also check with:

crontab -l

This should do it. The above two lines tell cron to execute lightscript.sh at 6:00 AM and darkscript.sh at 9:00 PM everyday.

We are taking this detour instead of just adding:

0 6 * * * gsettings set org.gnome.desktop.interface gtk-theme Yaru-light

to crontab because this requires the DBUS_SESSION_BUS_ADDRESS variable to be set correctly.

Pablo Bianchi
  • 17,371
2

We can achieve this with the help of crontab and @shubhzgang's answer.

#!/bin/bash

Script that auto switches Ubuntu themes to Dark or Light,

depending on the time of day

Copy this script file to /usr/local/bin/my-auto-theme

Add following lines to crontab -e

0 9 * * * bash /usr/bin/local/my-auto-theme light

0 17 * * * bash /usr/bin/local/my-auto-theme dark

@reboot bash /usr/bin/local/my-auto-theme

set_theme() { if [[ "$1" == "dark" ]]; then new_gtk_theme="Yaru-dark" elif [[ "$1" == "light" ]]; then new_gtk_theme="Yaru-light" else echo "[!] Unsupported theme: $1" return fi

# https://askubuntu.com/a/1234819/895417
export DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS
current_gtk_theme=$(gsettings get org.gnome.desktop.interface gtk-theme)
# echo &quot;[.] Currently using ${current_gtk_theme}&quot;
if [[ &quot;${current_gtk_theme}&quot; == &quot;'${new_gtk_theme}'&quot; ]]; then
    echo &quot;[i] Already using gtk '${new_gtk_theme}' theme&quot;
else
    echo &quot;[-] Setting gtk theme to ${new_gtk_theme}&quot;
    gsettings set org.gnome.desktop.interface gtk-theme ${new_gtk_theme}
    echo &quot;[✓] gtk theme changed to ${new_gtk_theme}&quot;
fi

}

If script run without argument

if [[ -z "$1" ]]; then currenttime=$(date +%H:%M) if [[ "$currenttime" > "17:00" || "$currenttime" < "09:00" ]]; then set_theme dark else set_theme light fi else set_theme $1 fi

We added @reboot so that script runs even if PC was shut down at cron trigger time.

Mortein
  • 3
  • 2
Nilesh
  • 204
1

I work on a script to do that, and I like the result, it works similar to gnome autodarkmode, with a sunshine and sunrise time, take a look at:

https://github.com/jackfido/nightMode

You need to have internet conection to get the sunrise and sunset data, this ocurrs here:

getSunRiseAndSet.sh

#!/bin/bash

1.- Tihs files pretends to get the sunset and sunrise values from: https://www.timeanddate.com/sun/mexico/

2.- To save this values into a temporal file, called as the "yourlocation".out

3.- Then compares the dates; from the last modified file date to current date in format YYYYmmdd to determine if we have the today values

4.- If the file is for yersterday or older then we have to go for the values for today, else, do nothing

Additional:

run THIS file in startup applications to run when your session start after a shotdown or reboot

run crontab -e to run nightMode.sh file, directly, every minute to set theme as soon as the sunset/sunrise occurss -> * * * * * ~/Public/nightMode/nightMode.sh

run THIS task each 3,4, 6 or 8 hours, it depends on how many times you want to check if you download the updated file, it allow us to have the values up-to-date in case of pc enters in hibernatin or freeze state during a day change

file name and location

location="monterrey" tmpfile=~/Public/nightMode/tmp/$location.out

get dates from last file and current

lastUpdate=$(date -r $tmpfile +"%Y%m%d") currentDate=$(date +%Y%m%d)

if file doesnt exists

if [ ! -z "$lastUpdate" ]; then # compare file date with current date to determine if need download the values if [ "$lastUpdate" -lt "$currentDate" ]; then wget -q "https://www.timeanddate.com/sun/mexico/$location" -O "$tmpfile"

    echo &quot;Monterrey time getted successfully&quot;
    bash ~/Public/nightMode/nightMode.sh
fi

else wget -q "https://www.timeanddate.com/sun/mexico/$location" -O "$tmpfile"

echo &quot;Monterrey time getted successfully&quot;
bash ~/Public/nightMode/nightMode.sh

fi

nightMode.sh

    #!/bin/bash
location="monterrey"
tmpfile=~/Public/nightMode/tmp/$location.out

SUNR=$(grep "Sunrise Today" "$tmpfile" | grep -oE '((1[0-2]|0?[1-9]):([0-5][0-9]) ?([AaPp][Mm]))' | head -1) SUNS=$(grep "Sunset Today" "$tmpfile" | grep -oE '((1[0-2]|0?[1-9]):([0-5][0-9]) ?([AaPp][Mm]))' | tail -1)

Use $sunrise and $sunset variables to fit your needs. Example:

sunrise=$(date --date="$SUNR" +%Y%m%d%H%M) sunset=$(date --date="$SUNS" +%Y%m%d%H%M)

hour=$(date +%Y%m%d%H%M)

if [ $hour -gt $sunrise ] && [ $hour -lt $sunset ]; then bash ~/Public/nightMode/day.sh fi

if [ $hour -lt $sunrise ] || [ $hour -gt $sunset ]; then bash ~/Public/nightMode/night.sh fi

day.sh:

#!/bin/bash

PID=$(pgrep compiz) export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

theme2Stablish='Materia-light-compact'

theme2Stablish='Yaru' theme=$(gsettings get org.gnome.desktop.interface gtk-theme)

if [ "$theme" != "$theme2Stablish" ]; then gsettings set org.gnome.desktop.interface gtk-theme $theme2Stablish gsettings set org.gnome.desktop.interface color-scheme 'prefer-light' gsettings set org.gnome.desktop.interface icon-theme 'Papirus-Light'

notify-send "Day theme stablished"

fi

night.sh

#!/bin/bash

PID=$(pgrep compiz) export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

theme2Stablish='Materia-dark-compact'

theme2Stablish='Yaru-unity-dark' theme=$(gsettings get org.gnome.desktop.interface gtk-theme)

if [ "$theme" != "$theme2Stablish" ]; then gsettings set org.gnome.desktop.interface gtk-theme $theme2Stablish gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' gsettings set org.gnome.desktop.interface icon-theme 'Papirus-Dark'

notify-send "Night theme stablished"

fi

then add nightMode to crontab:

# Create with crontab -e command:
          • ~/Public/nightMode/nightMode.sh

0 /6 * * ~/Public/nightMode/getSunRiseAndSet.sh

I started working based in this page

https://linuxconfig.org/how-to-obtain-sunrise-sunset-time-for-any-location-from-linux-command-line

And then, in your programs configure the automatic darkmode, like in github desktop, Android Studio, firefox, etc, etc

this was my result:

Light Mode:

Light Mode

Dark Mode:

Dark Mode

Regards

1

Scripting a theme change in GNOME systems

Intro

There are several variation of the same thing here now, but I'm adding my approach, because I think it's a bit more complete, and is the only one that is working for me on a fresh (or it was yesterday) installation of Ubuntu.

My setup

System

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.1 LTS
Release:        24.04
Codename:       noble

Script

To each their own, so the following is definitely not the only way to do this, but my approach is as follows:

  1. (Create if necessary and) edit the ~/.aliases by adding the line alias theme='~/scripts/change-theme.sh'
  2. touch ~/scripts/change-theme.sh and code/nano/vim into it to edit.
  3. Copy-paste the script from bellow.

Usage

  1. theme dark and theme light commands will set the theme as expected
  2. theme whatever will gracefully fallback to theme
  3. theme will read the current theme, and changed to its opposite

The script changes gtk-theme, icon-theme, cursor-theme and color-scheme.

change-theme.sh

The normal way

Usually your gsettings (from GLib) would work as expected, and the following script will work. This is the preferred way, because gsettings is schema-aware, and you cannot break anything with its commands. gsettings also take care of the correct settings propagation, but I am unsure, if these theme settings need to be propagated anywhere else, but where they're already being set.

#!/bin/bash

if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then if [ -n "$XDG_RUNTIME_DIR" ]; then export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus" else export DBUS_SESSION_BUS_ADDRESS=$(dbus-launch | grep DBUS_SESSION_BUS_ADDRESS | cut -d= -f2-) fi fi

current_theme=$(gsettings get org.gnome.desktop.interface gtk-theme) echo "[.] Currently using ${current_theme}"

if [[ "$1" == "dark" ]]; then new_theme="Yaru-dark" elif [[ "$1" == "light" ]]; then new_theme="Yaru-light" elif [[ "${current_theme}" == "'Yaru-light'" ]]; then new_theme="Yaru-dark" else new_theme="Yaru-light" fi

if [[ "${new_theme}" == "Yaru-light" ]]; then new_color_scheme="prefer-light" else new_color_scheme="prefer-dark" fi

gsettings set org.gnome.desktop.interface gtk-theme "'${new_theme}'" gsettings set org.gnome.desktop.interface icon-theme "'${new_theme}'" gsettings set org.gnome.desktop.interface cursor-theme "'${new_theme}'" gsettings set org.gnome.desktop.interface color-scheme "'${new_color_scheme}'"

echo "[✓] Theme changed to '${new_theme}'"

The "Nix way"

In my case I have gsettings installed via Nix package manager. I love it, but every now and then, I find a package I think it'd be best to install via apt install. I think gsettings is one of them. That said, here's how to avoid using gsettings for theme changing alltogether. dconf is not schema aware, so putting a wrong value anywhere can break your GNOME. There is also no propagation, but as said, I don't know if there needs to be any for changing a theme.

#!/bin/bash

current_theme=$(dconf read /org/gnome/desktop/interface/gtk-theme) echo "[.] Currently using ${current_theme}"

if [[ "$1" == "dark" ]]; then new_theme="Yaru-dark" elif [[ "$1" == "light" ]]; then new_theme="Yaru-light" elif [[ "${current_theme}" == "'Yaru-light'" ]]; then new_theme="Yaru-dark" else new_theme="Yaru-light" fi

if [[ "${new_theme}" == "Yaru-light" ]]; then new_color_scheme="prefer-light" else new_color_scheme="prefer-dark" fi

dconf write /org/gnome/desktop/interface/gtk-theme "'${new_theme}'" dconf write /org/gnome/desktop/interface/icon-theme "'${new_theme}'" dconf write /org/gnome/desktop/interface/cursor-theme "'${new_theme}'" dconf write /org/gnome/desktop/interface/color-scheme "'${new_color_scheme}'"

echo "[✓] Theme changed to '${new_theme}'"

Scheduled theme change

Adding to CRON jobs remains the same as in other answers, so edit the crontab with crontab -e using nano (make changes, Ctrl+S, Ctrl+X) or vim (i, make changes, Esc, type :wq, Enter), with the changes being:

0 8 * * * ~/scripts/change-theme.sh light
0 20 * * * ~/scripts/change-theme.sh dark

or whatever your preferred timing is. Confirm changes are saved by listing crontabs with crontab -l.

Troubleshooting

Your CRON job might not work in case some usual environment variables are missing. If necessary find out your $DISPLAY (usually :0 or :1), and add it and $DBUS_SESSION_BUS_ADDRESS before the script:

0 8 * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus ~/scripts/change-theme.sh light
0 20 * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus ~/scripts/change-theme.sh dark

EDIT

After I migrated to Nix the first solution stopped working for me, so I added a new one.

s3c
  • 111
0

I achieved this using Shubhzgang's answer and a couple of more answers from other sources. Then added my own modifications. Here's the script I use:

#!/bin/bash

Script that auto switches Ubuntu themes to Dark or Light,

depending on the time of day

Copy this script file to /usr/local/bin/switch-theme.sh

Add following lines to crontab -e

0 10 * * * bash /usr/bin/local/switch-theme.sh light

0 19 * * * bash /usr/bin/local/switch-theme.sh dark

@reboot bash /usr/bin/local/switch-theme.sh

set_theme() { # https://askubuntu.com/a/743024/1193214 # PID may return multiple ids here, so I converted to to array and got just the first id. # Otherwise, you may try another suggestion in the link https://askubuntu.com/a/1437023/1193214 PID=($(pgrep gnome-session)) export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-) echo date Starting script execution - setting theme $1 >> ~/Scripts/switch-theme.log if [[ "$1" == "dark" ]]; then new_gtk_theme="Yaru-blue-dark" # Some apps also need color scheme new_color_scheme="prefer-dark" new_icon_theme="Yaru-blue-dark" elif [[ "$1" == "light" ]]; then new_gtk_theme="Yaru-blue" new_color_scheme="prefer-light" new_icon_theme="Yaru-blue"the else echo "[!] Unsupported theme: $1" return fi

current_gtk_theme=$(gsettings get org.gnome.desktop.interface gtk-theme)
current_color_scheme=$(gsettings get org.gnome.desktop.interface color-scheme)
if [[ &quot;${current_gtk_theme}&quot; == &quot;'${new_gtk_theme}'&quot; ]]; then
    echo &quot;`date` [i] Already using gtk '${new_gtk_theme}' theme&quot; &gt;&gt; ~/Scripts/switch-theme.log
else
    echo &quot;`date` [-] Setting gtk theme to ${new_gtk_theme}&quot; &gt;&gt; ~/Scripts/switch-theme.log
    gsettings set org.gnome.desktop.interface gtk-theme &quot;${new_gtk_theme}&quot;
    gsettings set org.gnome.desktop.interface color-scheme &quot;${new_color_scheme}&quot;
    gsettings set org.gnome.desktop.interface icon-theme &quot;${new_icon_theme}&quot;
    echo &quot;`date` [✓] gtk theme changed to ${new_gtk_theme}&quot; &gt;&gt; ~/Scripts/switch-theme.log
fi

}

If script run without argument

if [[ -z "$1" ]]; then currenttime=$(date +%H:%M) if [[ "$currenttime" > "19:00" || "$currenttime" < "10:00" ]]; then set_theme dark else set_theme light fi else set_theme $1 fi

Finally, I added this script at startup as well.