Simple Slideshow Screensaver Script for Ubuntu

Those of you on recent versions of Ubuntu may find the default screensaver slightly lacking. Gnome-screensaver’s blank screen can be a bit of a bore, luckily there are alternatives such as xscreensaver. However, the alternatives may be overkill if you just want a simple slideshow screensaver, so here’s bash script that does just that.

Xscreensaver may seem like the obvious route to more interesting screensavers on Ubuntu. This was the route I previously took with Ubuntu, configuring the webcollage screensaver to point to a local directory for showing images from.  However, if you use the ever-popular caffeine to stop screensavers and lock-screens kicking in when viewing full screen videos or games you might run into some problems. (If you’re interested in using xscreensaver there is a script that you can use to stop it running while a full-screen application has focus.) All I wanted was a simple slideshow to show off my pictures when I left my PC alone, so to avoid the workarounds needed for xscreensaver to work properly with the most recent Ubuntu I made my own bash script for it instead.

The script uses feh, a simple tool for displaying images.  You can install it with this command:

sudo apt-get install feh

The script also uses xprintidle, another simple tool – this time for identifying the time since the last input from a user.  This can be installed with the following command:

sudo apt-get install xprintidle

With both of these tools installed a simple bash script can be used to start showing a slideshow of images when a certain period of inactivity has taken place.  I have made two scripts which use the these tools, the first of these simply starts a screensaver after a period of inactivity:

screensaver.sh

The script should be downloaded into a folder containing images (or links to the images) you want to appear in the slide show. The folder can also contain folders (or links to folders) containing the images you want the screensaver to show.

To start this script a command similar to the following should be used:

bash path/to/script/screensaver.sh time

The time value should be the number of seconds the script should wait when no input is detected before starting to show the slideshow.  For example; ‘screensaver/screensaver.sh 120′ would cause the script to start showing images from the screensaver folder after 2 minutes of inactivity.

A command for running the script can be added as a start up application to get it to run automatically.

The script is designed to not start showing the slideshow if a full-screen piece of software is running in the foreground.  This means the screensaver should not kick in if you’re watching a full-screen video (through either a media player or browser). Once the slideshow starts it can be closed with the escape key.

An alternative version of the script is also available here:

screensaverwithlock.sh

This version uses the same setup and can be executed with a command similar to the following:

bash path/to/script/screensaverwithlock.sh time

This version makes use of Ubuntu’s lock screen – forcing users to enter a password when wanting to close the slideshow (and leave the screensaver).  This is included because those who still want their Ubuntu to lock after a certain amount of time may find that the screensaver will stop the gnome-screensaver (and lock) from automatically kicking in if they have caffeine running.  (If you are running this script with gnome-screensaver still doing the locking and without caffeine, you should make sure that the screensaver will kick in sometime before the lock or else you won’t get to see the slideshow.)

As I keep iterating this is a very simple script, I’ve tried to make it as secure as possible but it may not be suitable for machines where access needs to be tightly controlled.

The scripts should be usable on other linux platforms that can use bash scripts, feh and xprintidle (and gnome’s lock for the locking script).

Feel free to modify the scripts if you can think of any improvements.

Advertisement

52 thoughts on “Simple Slideshow Screensaver Script for Ubuntu

  1. Fantastic! This looks like exactly what I’m looking for (Mint Debian Edition, not Ubuntu, running Mate, not Gnome/Unity, but should be fine). Thank you!

  2. Hey, i’m a linux noob so dont judge for the question i’m going to ask
    whenever i type in the command “bash path/to/script/screensaver.sh time” (i’ve replaced path and time) i get an error saying no such file or directory. how do i fix this

    1. Hi, you may need to make the script executable, try the following command first: “sudo chmod +x path/to/script/screensaver.sh” then try to run it.

      If you have the same error running that command there’s probably a problem with your path, if so try moving the script to your home folder then you can just run it as so: “bash screensaver.sh time” (with time replaced again).

      I hope this helps.

  3. Hi JA McNaughton,
    Your script works well and was easily adapted to show slides in sequence rather than randomly as well as show slides in specific folders rather than recursively. I just copied basic script to dedicated scripts like UK2015trip which is name of folder with the uk2015 trip slides.

    I run these scripts on top of yourclassical.org’s music stream, so the obscenely large TV screen is busy while it plays the music from the Pi 3.

    Unfortunately if I have to ESC to the underlying screen, when the screensaver relaunches – even though automatically, it restarts the sequence from the first slide. I’ve done my best with the feh manual. It seems to provide for starting at a named slide, but doesn’t have a provision for writing the name of the current slide to a file. My thought was to write name of each slide as loaded to a file like ‘lastslide’ and overwrite ‘lastslide’ with each new slide as shown. Then feh would relaunch showing ‘lastslide’ and go on from there. I might then get the previous slide again on relaunch but that would be a lot better than going back to beginning of a 2k slide show.

    If the above makes any sense to you, could you point me at a way to wrestle this issue into submission?

    thanks again for a very useful script.

    best,

    J (John) A (Alexander) Ferguson

    1. Hi John, great to hear you’re getting some use out of this. Unfortunately I don’t know of anyway to get feh to output the last image it showed (if there was a way, you could save that name to a file and read from that file when calling feh again).

      I think there might be a possible way of doing it by creating a loop in the batch script which goes through all the images in your supplied directory. On each loop you’d want to call feh to show the single image (not in slideshow mode) then wait for a few seconds before stopping feh. The tricky thing with this setup is that you’d need to then start and stop instances of feh for each loop (and somehow do that so that there’s some overlap between one instance of feh ending and the next starting). The reason for taking this approach is that the bash script knows the name of the file currently being shown – then when the loop is broken (the script will need to listen for a key stroke to end the script) the script can drop the file’s name into a text file and use it next time it needs to start the screensaver.

      I hope this is of some use to you.

      1. Thanks much. your’s is not a bad idea. One of the things which was a bit of a surprise is that contrived slideshows which with our friends cannot be more than about 150 slides are not nearly as interesting as the whole raw set as photographed which of course can run indefinitely. Despite a trip producing 2k to 4k slides, there are many more worth seeing than the 150 which courtesy constrains.

        I suppose I should find out why SWMBO takes so many sheep pictures.

        best,

        john

  4. Hi,
    I emailed feh’s developer and got the following response:

    > … some of the slide files are several thousand photos. If we have reason to
    > interrupt the system, feh starts the file over again. I’ve tried hard to
    > figure out how to make it resume where it was, but if it is possible within
    > feh, I cannot figure out how.
    >
    > One thing that would help would be if there was a toggle to write current
    > slide to a file named “currentslide” it would rewrite the contents of
    > “currentslide” with each new photo. this way if I had an interruption, i
    > could simply restart the show using contents of “currentslide” as first
    > photo and then presumably feh would continue from there.

    This is already possible, though with a not entirely straightforward feature.
    feh has the –info option to execute a command on each image and display its
    output in the bottom left corner. This can also be used to just execute a
    command for each image without displaying anything.

    So, you can use

    > feh –info ‘echo %F > currentslide’ –start-at $(cat currentslide) some/directory

    to get a persistent slideshow resume feature. If the currentslide file does not
    exist yet, feh will start at the beginning.

    –Daniel

    I haven’t tried it yet maybe tomorrow.

    John

  5. This isn’t simple. I thought I could just modify what Daniel has suggested and build it into your script. it looks like the first thing to do is to set it the script up so it always runs out of ‘home’ folder and has a line early on to erase ‘currentslide’ so it doesn’t run off another slideshow. then all i need to do is figure out how to make the feh command sequence work.

    I have not yet tried everything i can think of.

  6. I found this script to be a pretty perfect solution for my raspberry pi wall calendar, as I wanted to have a simple screen saver so the calendar wasn’t burnt into the screen all the time. However, I found out that it does not come on while my calendar is on focus, because of course, the calendar is running in full screen mode! This is of course, the entire reason you wrote this script lol. But I couldn’t find anything to accomplish this as well as yours does, so I was wondering if you knew a way to implement your script without worrying about the full screen applications. We won’t ever be using this to view videos or anything, so i’m not worried about it interrupting full screen applications. But unfortunately, that feature causes it not to come on while my calendar is in full screen mode. Any suggestions?
    Thanks,
    Nate

      1. Wow, I don’t get that kind of support for paid products! You are quick on the ball my friend. I see that the script you linked is the same as your screensaverwithlock.sh script, which seems like it does the same thing as your other script, except it will lock the screen, asking for a password instead, which I don’t really need. But it still seems to not kick in if an application is using full screen. I’m trying to get it to work regardless of whether or not an application is running in full screen mode. I’m trying to dig through the script to see if I can just get it to ignore the full screen stuff, but I’m just not as good a scripter as you. 🙂 Thanks though for such a prompt reply!

      2. Hey I think I got it. It seems to be working for me, but tell me if I’m doing something stupid that will bite me later lol. Basically, near the bottom of your script, in your “while sleep” statement, I just commented out the checkFullscreen function, so that part doesn’t get called at all, and then I just put the feh command in place of it. So I guess I’m skipping all the cool hard work you did to get it to detect full screen applications, and just calling feh when it detects it’s idle. Seems to work just fine for me now. Thanks again!

      3. Ha, no worries, you’re too kind. Looks like I did it right then! My solution was exactly that, thank you very much. It works great!

    1. Hi Nate,

      I came across this script in my search for an auto run screen saver for the Pi wall calendar I’m starting out on. I’m a complete noob to python and Pi; this is my first project. I’m wanting this to run after an idle time of an hour and play the slide show until further interaction. I’m having a heck of a time getting the script right to auto run after I boot the pi. Would you mind helping a fellow out with the steps I need to take to get this to auto run? It runs just fine when in the terminal obviously.

      -JAMcNaughton- Your post has been the most useful in my quest to find a simple screen saver script. Thanks!

      Thank you,

      Ryan

      1. Well I don’t have mine set to autorun at boot because I only want it running during certain times of the day. I have mine kick off after only 10 minutes of inactivity, but from about 7am to 9am I don’t want it coming on at all. So I have it start the screensaver script via cron at 9am. Then at 7am, I wrote a script to kill it. The only way I could get it to work automatically, via cron or via reboot was to export the display manually when calling the script. so for example, here is a line in my crontab:

        00 07 * * 1,3,5 DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority /scripts/startscreensaver.sh 2>&1

        The /scripts/startscreensaver.sh script just calls the MCnaughton script like this:

        bash /home/pi/Pictures/screensaver.sh 600

        There are a few ways to get it to start on boot, but I was unsuccessful so far. Hopefully with the method I found to get it working in crontab, you can figure out how to get it to start on boot. I didn’t try too hard since I didn’t really care to have it start on boot.

  7. Hi,

    I try to autostart this script on an raspberry pi with raspberian and it won’t run. I can start it directly with a terminal in der GUI or over putty and using export DISPLAY=:0. Could you please tell me were to put the script for autostart?

    Thanks
    Tobias

    1. I had the same problem, it would run just fine from the terminal, but trying to autostart it using crontab, it didn’t know what display to use. Only way I could get it to work was to put it all directly in the crontab, display export and all. Here is the line I have in my crontab, and it’s currently working great for me:

      DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority /scripts/startscreensaver.sh 2>&1

      The /scripts/startscreensaver.sh is just a wrapper script for the screensaver.sh file J wrote. This is all that is in that file:

      bash /home/pi/Pictures/screensaver.sh 600

      I suppose it would work if I just put it in my crontab like that, but I have it working the way it is so I ain’t gonna touch it!

      1. Hi Nate,

        I solved it in the meantime. You read everywhere to modify etc/xdg/xlsessions/XLDE-pi/autostart but this is not working and would be the global config. The right place is [userfolder]/.config/autostart/screensaver.desktop

        This file will point to the script and is then executed in the user context:
        [Desktop Entry]
        Type=Application
        Exec=/home/pi/Pictures/kiosk/screensaver.sh

        All the other stuff found in the internet just did not work. This works great. Would be nice if it could be mentioned in the tut above.

      2. Hey that’s better than my solution. I would implement it except I don’t want the screen saver running during certain times of the day, so I use cron to start and stop it.

  8. In my opinion this is a better way for make this :
    #!/bin/bash
    # screensaver.sh

    # url: ###
    # This script is licensed under GNU GPL version 2.0 or above

    # Uses elements from lightsOn.sh
    # Copyright (c) 2011 iye.cba at gmail com
    # url: https://github.com/iye/lightsOn
    # This script is licensed under GNU GPL version 2.0 or above

    # Description: ####
    # screensaver.sh needs xprintidle and feh to work.

    # HOW TO USE: Start the script with the number of seconds you want the checks
    # for fullscreen to be done. Example:
    # “./screensaver.sh 120″

    # enumerate all the attached screens
    displays=””
    while read id
    do
    displays=”$displays $id”
    done< /dev/null ; then # My mod
    # echo “$SERVICE service running, everything is fine”
    if [ $idle -lt $IDLE_TIME ]; then # My mod
    pkill feh
    fi # My mod
    else # My mod
    # echo “$SERVICE is not running” # My mod
    if [ $idle -ge $IDLE_TIME ]; then
    checkFullscreen
    fi
    fi # My mod
    done

    exit 0

  9. Hi,
    I have used your script on a raspberry pi for a wall mounted calendar/ picture frame. The script works great but it shows any picture on the raspberry pi instead of only showing pictures from the folder that I specified in the script. Do you have a solution for this?

    Thanks!

    1. Hi, the problem might be to do with the way bash might handle arguments on pi. Try changing the line:
      DIR=$( cd “$( dirname “$0″ )” && pwd)
      to
      DIR=”$( cd “$( dirname “${BASH_SOURCE[0]}” )” && pwd )”

      I hope that helps.

  10. Hi, very nice script…running perfect. wondering if it can also play image file in sequence…as the file name will be 1.png, 2.png.3.png… I’m just n00b here..appreciate for you all help. thanks.

    1. Hi, yes its possible. To do this you need to open the script you’re using in a text editor and find the line that starts like this:
      feh -x -F -r -Y -Z -z -A
      Then just remove -r from this line and the files should then play in order. I hope this helps.

  11. When I’m running the slideshow it shows the folder directory of the image, anyway to get rid of that top left corner info?

  12. Using the Fullscreen version of this script on a Raspberry Pi 3 and it’s working great. Question: What’s the best way to “stop” the screensaver when user activity is detected? I can right-click and choose “Exit”, but that’s not going to work for a kiosk deployment I’m planning. Thanks in advance for any pointers in the right direction.

      1. The kiosks will only have a touchscreen virtual keyboard. So I guess I need to “helper” script to detect any new input/touch and kill the feh process. Any suggestions for how to make that happen?

      2. Hi again, I think I’ve got something that might help. Have a look at this version of the script: https://raw.githubusercontent.com/jamcnaughton/useful-linux-scripts/master/simplescreensaver/screensaverCloseOnClick.sh
        I’ve changed the line where feh is called and used xbindkeys (you’ll need to install that) to bind a command killing feh to the first mouse button while feh is running. Hopefully that’ll set you down the right path. Let me know how you get on.

      3. Glad to report the addition of xbindkeys worked. I’m using your screensaverfull.sh script so I just added the three lines below the “feh” command and all works great. Thanks again

  13. I’ve just tested the CloseOnClick-variant and it works 🙂
    Exactly as I wanted to have running on my Raspi…
    Many thanks for this!!!

    1. Good morning! As long as I have used 3 seconds for testing the interworking with my other scripts, everything runs fine. Now I have detected that any other time value, 10 or more seconds, does not work. Any idea what I did wrongly?

    1. #!/bin/bash
      # screensaver.sh

      # url: ###
      # This script is licensed under GNU GPL version 2.0 or above

      # Uses elements from lightsOn.sh
      # Copyright (c) 2011 iye.cba at gmail com
      # url: https://github.com/iye/lightsOn
      # This script is licensed under GNU GPL version 2.0 or above

      # Description: ####
      # screensaver.sh needs xprintidle and feh to work.

      # HOW TO USE: Start the script with the number of seconds you want the checks
      # for fullscreen to be done. Example:
      # “./screensaver.sh 120″

      # enumerate all the attached screens
      displays=””
      while read id
      do
      displays=”$displays $id”
      done< xbindkeys.temp # create file with commands to kill feh and xbindkeys
      echo “b:1”>>xbindkeys.temp # when button 1 is pressed
      xbindkeys -n -f xbindkeys.temp # execute xbindkeys using created file and not a daemon
      rm xbindkeys.temp # dump the file
      fi
      done
      }

      # If argument empty, use 60 seconds as default.
      if [ -z “$1” ];then
      delay=60
      fi

      # If argument is not integer quit.
      if [[ $1 = *[^0-9]* ]]; then
      echo “The Argument \”$1\” is not valid, not an integer”
      exit 1
      fi

      IDLE_TIME=$(($delay*1000))

      cd $DIR
      while sleep $((1)); do
      idle=$(xprintidle)
      if [ $idle -ge $IDLE_TIME ]; then
      checkFullscreen
      fi
      done

      exit 0

    1. Yes. In the script where feh is called there is an argument for setting the delay in the slide show (-D followed by a number). In the script provided it is set to 7, you can change the 7 to the number of seconds your want a picture shown for.

  14. Hey man Im using your script to display an endless slideshow but it always stop at some point, do you know what can I do to prenvent ir from stopping, Im using it on a raspberry pi zero w with raspbian in it

    1. I’m not sure whats stopping it, feh slideshows are supposed to loop indefinitely unless told otherwise. Its possible the power settings on your device might be kicking in, I’d check those.

      1. Oh my god I wasnt expecting an fast answer actually thank you so much, I have already disable the blanking and everything but sometimes the slideshow just stop at one image and it stays there forever, it happens after that it runs for 2 or more hours I think, thank you so much for your answer and support in advance!!

  15. HI, Thanks for this script perfect for what i want to do but i was wondering if there is a way to make it stretch all images to full screen? and also is there a way to hide the cursor? Thanks a lot!

  16. Hi, Found your script..
    Did all i think was needed and now stuck here..

    Wen running the script i get.
    /home/pi/Pictures/script/screensaver.sh: regel 63: [: eenzijdige operator werd verwacht, -ge gevonden
    couldn’t open display

    I am running it on RPI3 and lattest raspian desktop.

    Thanks in advance…
    Benno

    1. This could be caused by 3 things:

      1: You’re running the script without supplying a delay argument (so “bash …/screensaver.sh” instead of “bash …/screensaver.sh 50” – in theory the script should supply the default of 60 if you don’t supply the argument but that could be broken.

      2: xprintidle isn’t installed or may not be fully supported on your system. Try typing xprintidle into a terminal and check you get a response.

      3: xprintidle may not be returning what we expect anymore (due to updates or configuration for particular systems). Try changing line 63 to the following: if [ “$idle” -ge “$IDLE_TIME” ]; then

      1. Thank you for your responses.
        Two notes here, I had this working on one pi for a few years but it seems that an update has broken some aspect of this existing installation. I ran the command xprintidle and it returned “couldn’t open display” as well as the command xvinfo 0:0 or xvinfo 0. I did verify that they were both installed but I’m either missing an environmental variable, the workings of the utils library has changed or rights have changed somehow to prevent the scripts from working as expected.

        Separately, I installed a new installation on a second raspberry pi 4B using the latest version of raspbian, followed your directions above but arrived at the same results.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s