29

I wrote a bash script that changes the wallpaper (for GNOME3).

#!/bin/bash

# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"

# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`

# Change wallpaper.
# http://bit.ly/HYEU9H
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"

Script executed in a terminal emulator (eg gnome-terminal) works great. During the execution by cron, or ttyX terminal getting the error:

** (process:26717): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n

** (process:26717): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n

** (process:26721): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n

** (process:26721): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
skaffman
  • 398,947
  • 96
  • 818
  • 769
Mateusz Jagiełło
  • 6,854
  • 12
  • 40
  • 46
  • 1
    None of the solution worked for me. :( I had to set DISPLAY=:0.0 before the command in cron expression. (http://ubuntuforums.org/showthread.php?t=1023215). P.s. I am trying to run a python script that uses pynotify. – Hussain Feb 01 '15 at 12:55
  • 1
    @Hussain: It took some time since I started the question. I bet that answer below mine should be better - just read whole discussion. – Mateusz Jagiełło Feb 01 '15 at 15:32

8 Answers8

45

Finally I managed how to solve this issue after many, many attempts.

Indeed, the problem occur because cron uses only a very restricted set of environment variables. And the only one environment variable that is responsible for running in the right way the script from the question when this is set as a cron job is DBUS_SESSION_BUS_ADDRESS, not DISPLAY or XAUTHORITY or GSETTINGS_BACKEND or something else. This fact was also pointed well in this answer.

But the problem in this answer is that there's no guarantee that the DBUS_SESSION_BUS_ADDRESS variable from that file from ~/.dbus/session-bus/ directory is updated to the current value from the current gnome session. To go over this problem a method would be to find the PID of a process in the current gnome session, and obtain the dbus address from its environment. We can do this as follow:

PID=$(pgrep gnome-session)  # instead of 'gnome-session' it can be also used 'noutilus' or 'compiz' or the name of a process of a graphical program about that you are sure that is running after you log in the X session
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

That being said, the script should look like:

#!/bin/bash

# TODO: At night only dark wallpapers.

# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"

# export DBUS_SESSION_BUS_ADDRESS environment variable
PID=$(pgrep gnome-session)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`

# Change wallpaper.
# http://bit.ly/HYEU9H
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
Community
  • 1
  • 1
Radu Rădeanu
  • 2,642
  • 2
  • 26
  • 43
  • 4
    Thanks a lot. I have a script that updates my desktop wallpaper at midnight. This script stopped working correctly some months ago. When I launched it normally, it worked, but from crontab it didn't do the job. With this trick I could solve the problem. – Jabba Feb 06 '14 at 16:35
  • 2
    For dual-screen monitors change the option `spanned` to `zoom` – n0p Oct 22 '14 at 09:13
  • 1
    Thanks for this solution. I had to modify it slightly to work with gnome-shell on Debian: `PID=$(pgrep -o gnome-shell)`. – scai Jul 05 '15 at 10:16
  • This is the correct answer for Ubuntu 15.04. I have encrypted homedir enabled, so when I try running the script from tty02 I will be prompted for a password in Unity, but when run from cron the background changes without issue. – Ch4ni Sep 29 '15 at 16:05
  • to run a X application you should add env DISPLAY=:0.0 in front. Beside that it's working great. Thanks a lot! – Mat Sep 30 '15 at 22:38
  • 1
    What happens when gnome-session isn't running? – joshreesjones Dec 14 '15 at 03:06
  • 2
    What if more than one user is logged in? Then `pgrep` will return more than one value – In78 Mar 29 '16 at 12:36
  • 2
    On Ubuntu 20.04 with X, I had to use `PID=$(pgrep -t tty2 gnome-session)` – Ray Foss Aug 07 '21 at 18:46
7

I found some solutions. When you export a variable DBUS_SESSION_BUS_ADDRESS contained in the file ~/.dbus/session-bus/*, dbus-launch does not tell more about the error. However, instead of wallpaper there are artefacts.

Added code:

sessionfile=`find "${HOME}/.dbus/session-bus/" -type f`
export `grep "DBUS_SESSION_BUS_ADDRESS" "${sessionfile}" | sed '/^#/d'`

Now the script looks like this:

#!/bin/bash

# TODO: At night only dark wallpapers.

# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"

# Weird, but necessary thing to run with cron.
sessionfile=`find "${HOME}/.dbus/session-bus/" -type f`
export `grep "DBUS_SESSION_BUS_ADDRESS" "${sessionfile}" | sed '/^#/d'`

# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`

# Change wallpaper.
# https://superuser.com/questions/298050/periodically-changing-wallpaper-under-gnome-3/298182#298182
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
Mateusz Jagiełło
  • 6,854
  • 12
  • 40
  • 46
4

Tried this and it worked great for me:

dbus-launch --exit-with-session gsettings set schema key value

Or from root cron:

sudo -u user dbus-launch --exit-with-session gsettings set schema key value

Credit: http://php.mandelson.org/wp2/?p=565

Arnon Weinberg
  • 871
  • 8
  • 20
  • There's a problem with this if you use it in an interactive session (e.g. `ssh`) and there's a separate X11 session running on the system; it seems to cause some sort of slowdown or perhaps keystroke-capturing until your session ends. The man page for `dbus` version 1.8.18 states: "To start a D-Bus session within a text\\(hymode session, do not use dbus-launch. Instead, see **dbus-run-session**(1)." (I think the weird `\(` thing is a formatting error.) Unfortunately, it appears that `dbus-run-session` is fairly new, as it's in Debian 8 but not Debian 7. – Kyle Strand Sep 01 '16 at 19:47
1

add export DISPLAY=:0 && export XAUTHORITY=/home/username/.Xauthority , where username is your ubuntu username. It should fix the X11 authorisation error.

Vivek Pradhan
  • 4,777
  • 3
  • 26
  • 46
0

To change your wallpaper through cron, just do this directly in your crontab : Execute crontab -e

Add lines like this :

30 09 * * * DISPLAY=:0 GSETTINGS_BACKEND=dconf /usr/bin/gsettings set org.gnome.desktop.background picture-uri file:////home/elison/Pictures/morning.jpg

00 12 * * * DISPLAY=:0 GSETTINGS_BACKEND=dconf /usr/bin/gsettings set org.gnome.desktop.background picture-uri file:////home/elison/Pictures/noon.jpg

Elison Niven
  • 236
  • 3
  • 12
0

Also see this solution that work for me: https://unix.stackexchange.com/questions/111188/using-notify-send-with-cron#answer-111190 :

You need to set the DBUS_SESSION_BUS_ADDRESS variable. By default cron does not have access to the variable. To remedy this put the following script somewhere and call it when the user logs in, for example using awesome and the run_once function mentioned on the wiki. Any method will do, since it does not harm if the function is called more often than required.

#!/bin/sh

touch $HOME/.dbus/Xdbus
chmod 600 $HOME/.dbus/Xdbus
env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.dbus/Xdbus
echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.dbus/Xdbus

exit 0

This creates a file containing the required Dbus evironment variable. Then in the script called by cron you import the variable by sourcing the script:

if [ -r "$HOME/.dbus/Xdbus" ]; then
  . "$HOME/.dbus/Xdbus"
fi
thierrybo
  • 41
  • 2
  • 5
0

And finally the ugly, no cron at all (darn it)! Using other methods the changes get set in gconf, but the image does not change. Maybe it is because I am running Deepin's DDE (dde makes use of the same path, different key). Ugly for the rescue: A final attempt to make this saga work.

With this script the wallpaper is changed every 420 seconds (7 minutes) in an endless loop picking a random wallpaper from one of 4 sets (or directories), acordingly to the time of the day or night.

I've created a .desktop file and added this .desktop file to the "~/.config/autostart". I've also created another pair script/desktop without the loop to be on my dock, so I can click on it and change it on fly too.

Set the ugly up: save the script as wallpaperd somewhere and make it executable:

chmod +x wallpaperd

Now create a folder called Wallpaper inside the Pictures directory. Inside this Wallpaper folder create 4 more folders with the names afternoon, duskdawn, morning and night. Put the image files you wish in those 4 directories.

mkdir -p ~/Pictures/Wallpaper/morning
mkdir ~/Pictures/Wallpaper/afternoon
mkdir ~/Pictures/Wallpaper/night
mkdir ~/Pictures/Wallpaper/duskdawn

wallpaperd

#!/bin/bash

for (( ; ; ))
do

    me="MyUser" # Change me!
    morning="morning"
    afternoon="afternoon"
    dawn="duskdawn"
    night="night"
    dusk="duskdawn"
    now="morning"
    hour=$(date +%R | sed 's/\:.*//')

    if [ "$hour" -ge 7 ] && [ "$hour" -lt 12 ]
        then
        now="morning"
    elif [ "$hour" -ge 12 ] && [ "$hour" -lt 17 ]
        then
        now="afternoon"
    elif [ "$hour" -ge 17 ] && [ "$hour" -lt 18 ]
        then
        now="duskdawn"
    elif [ "$hour" -ge 18 ] && [ "$hour" -le 23 ]
        then
        now="night"
    elif [ "$hour" -ge 0 ] && [ "$hour" -lt 6 ]
        then
        now="night"
    elif [ "$hour" -ge 6 ] && [ "$hour" -lt 7 ]
        then
        now="duskdawn"
    fi

    imgPath="/home/$me/Pictures/Wallpaper/$now/"
    imgFile=$(ls -1 $imgPath | shuf -n 1 | awk '{print $NF}')

    export bgNow=""$imgPath$imgFile""

    # Deepin desktop
    /usr/bin/gsettings set com.deepin.wrap.gnome.desktop.background picture-uri "$bgNow"

    # Gnome desktop 
    #/usr/bin/gsettings set org.gnome.desktop.background picture-uri "$bgNow"  

  sleep 420

done
  • Set the proper gsettings command for your desktop in script!

wallyd.desktop

** Autostart Path: /home/YOUR_USER/.config/autostart/wallyd.desktop**

[Desktop Entry]
Categories=System;
Comment=Change Wallpapers Agent
Exec=/home/$USER/Bin/wallpaperd
Icon=computer
Name=Wally Daemon
NoDisplay=false
Terminal=false
Type=Application
  • Edit the script's path to match the path where you saved the script.

No loop

To create a desktop icon without the loop, only to change the wally and quit do this:

Save the script as wallpaper (without the d at the end) and remove these lines:

for (( ; ; ))
do

done

Use the template above to create another .desktop file for this non looped wallpaper script. Change the Name and the Exec path for the non looped script.

Save this .desktop here:

/usr/share/applications/wally.desktop

Drag it to your taskbar or dock. Click it and it will change the wallpaper on the fly.

Mach Seven
  • 51
  • 3
0

When setting the DBUS_SESSION_BUS_ADDRESS environment variable, the PID=$(pgrep gnome-session) command may return multiple values in certain cases. This can cause issues when setting the environment variable using the grep command.

To address this issue, you can use the pgrep command with the -t option to limit the search to a specific terminal. In this case, you can use PID=$(pgrep -t tty2 gnome-session) to limit the search to the second terminal (tty2) and ensure that only one PID is returned.

Therefore, for Ubuntu 22.04, you can modify the command to:

PID=$(pgrep -t tty2 gnome-session)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

This should allow you to set the DBUS_SESSION_BUS_ADDRESS environment variable correctly, even when multiple gnome-session processes are running.

Thanks to Ray Foss for providing this solution in the comments to the original answer.

helvete
  • 2,455
  • 13
  • 33
  • 37
Matblanket
  • 55
  • 4