30

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.

Gregory Opera
  • 2,639
  • 7
  • 33
  • 59

5 Answers5

32

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
  • 468
  • 4
  • 7
  • This is a great extension, thanks for it. – Krzysztof Swiatly Mar 26 '21 at 08:28
  • I installed it but don't understand how to open it. – khatchad Apr 06 '21 at 19:59
  • 1
    @RaffiKhatchadourian that's a thing with gnome extensions - it's really not clear how to open the settings if you don't know. there's a few ways. if you installed the extension using the gnome extensions browser add-on, you can open the preferences from there. otherwise, you might want to use gnome-tweaks or using the command line: gnome-extensions prefs nightthemeswitcher@romainvigier.fr – sk22 Apr 13 '21 at 13:15
  • does it work with 22.04? when I click install on the linked page, it opens a dialog that tells me no apps available – Line Aug 10 '22 at 18:38
  • 4
    Also the extension page says Ubuntu is not supported due to their heavily patched GNOME components that conflict with the extension – Matt McCormick Dec 23 '22 at 05:06
12

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
  • 15,657
  • nice answer.... – PRATAP May 03 '20 at 17:36
  • I followed the instructions... We'll see in about half an hour whether I have done it right and / or how well it works. But why do your instructions refer to two different scripts at the end (lightscript.sh and darkscript.sh), when you are indicate that I should create a single script at the start (called "script.sh")?

    For the last section (with the reference to the two scripts), I changed the name to "script.sh" for both of them, because I only created a single script at the start... I also change the times (from "21" to "18", for 6PM).

    – Gregory Opera May 04 '20 at 07:29
  • It didn't work... :-( – Gregory Opera May 04 '20 at 08:13
  • So, the file "script.sh" is executed when you login (provided you added it in gnome-session-properties). Its work is to create lightscript.sh and darkscript.sh with proper value for DBUS_SESSION_BUS_ADDRESS. Then the crontab executes these lightscript.sh and darkscript.sh. Just restart and login and see if lightscript.sh and darkscript.sh is created where script.sh is present. Also try service cron status to see if cron is running – Shubhzgang May 04 '20 at 08:25
  • This wouldn't work with changes you made to the script names @GregoryOpera – Shubhzgang May 04 '20 at 08:57
  • All right, I went through the process again - this time leaving the script names as "lightscript.sh" and "darkscript.sh"... We'll see if it works in the morning, when I wake up (the computer usually stays on).

    Interestingly, I now have a "lightscript.sh" and "darkscript.sh" file in my "home" directory...

    – Gregory Opera May 04 '20 at 12:15
  • Edited the script – Shubhzgang May 04 '20 at 13:20
  • Went through the whole process again - after you edited the script above - exactly as stated (i.e. using lightscript.sh / darkscript.sh), then I restarted my computer... I appreciate your suggestion - but this solution simply does not work. – Gregory Opera May 05 '20 at 09:32
  • Hi i tried it when I first commented above.. it worked.. working still.. I followed the instructions as it is.. – PRATAP May 06 '20 at 13:26
  • As noted above, I went back and started the process again, following the instructions to the letter... Still doesn't work. – Gregory Opera May 09 '20 at 06:24
  • Okay, I found a command to remove ALL cron jobs, so I did that and went through the process again... The ONLY thing I changed is the "21:00" was changed to "18:00" in the script code above, and also when creating the cron job (i.e. "21" was changed to "18").

    I'm gonna reboot now, and see if it works this time...

    – Gregory Opera May 09 '20 at 06:43
  • Still didn't work... Nothing.

    I had a window Files / Nautilus window open at 1800 to see if the changes would be applied, with my desktop unlocked (i.e. not on the "lock" screen)... Nothing happened.

    – Gregory Opera May 09 '20 at 08:03
  • Downvoting! the answer has been made more complicated than it should be – Nilesh May 10 '22 at 17:55
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
  • 154
0

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
    Hello. What about later when the link does not work? Maybe include the info in the body of the answer. – David Mar 16 '22 at 14:34
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.