The Wrong Way to do Screensavers on an Ubuntu Server

Published on 3rd Apr, 2015

A project at work has required me to build a kiosk that runs a local web server. The requirements are that this can be easily distributed and installed via USB drive, so I decided to go with an Ubuntu Server setup as there are lots of resources for modifying and configuring Ubuntu.

I started with this fantastic tutorial.

He uses openbox and X11 as a window manager to display Chrome in kiosk mode. Easy peasy. I was quite happy with this, until I saw X's screensaver.

Now, most kiosks are intended to stay on indefinitely. This, I understand. However, the site that runs on my particular kiosk isn't really eye-catching or obvious. I wanted a screensaver that would pop up after a certain amount of inactivity that would draw the user and instruct them to move the mouse or press a key to wake the machine up.

So I started looking into the xset command which allows you to configure the screen saver options. I soon learned that X is far to simple to display an image as a screensaver. It's just not intended for that.

So I found out about the xli command. It's purpose is to display an image on an X Window. "Great!" I thought, "I just need to trigger it when the screensaver fires!". That was a dead end. The best I could get it to do was display the image I wanted as a background image behind Chrome. No matter how hard I tried, I couldn't get it to hide Chrome or come to the front. I spent a few hours and determined the core of my problem:

I can't hide the full-screen browser.

Nope. Got this browser. It's open. Takes up the whole screen. It's showing a site that I have full control over. What to do.

Those of you who are not as dense as I am have already determined the solution. It took me awhile but finally it hit me:

I have a full-screen browser!

Little javascript (with the help of this wonderful StackOverflow answer):

var idleTime = 0;
var screenSaverActive = false;
$(document).ready(function () {
    //Increment the idle time counter every minute.
    var idleInterval = setInterval(timerIncrement, 60000); // 1 minute

    //Zero the idle timer on mouse movement.
    $(this).mousemove(function (e) {
        idleTime = 0;
        screenSaverActive = false;
        $("#screensaver").animate({opacity: 0}, 300, function(){
            $("#screensaver").remove();
            $('body').css('cursor', 'default');
        });
    });
    $(this).keypress(function (e) {
        idleTime = 0;
        screenSaverActive = false;
        $("#screensaver").animate({opacity: 0}, 300, function(){
            $("#screensaver").remove();
            $('body').css('cursor', 'default');
        });
    });
});

function timerIncrement() {
    if(screenSaverActive) return false;
    idleTime = idleTime + 1;
    if (idleTime > 20) { // 20 minutes
        screenSaverActive = true;
        $("body").append('<\div id='screensaver'><\div>');
        $("#screensaver").css("opacity", 0).show().animate({opacity: 1}, 1500, function(){
            $('body').css('cursor', 'none');
        });
    }
}

And some CSS:

    #screensaver {
        display: none;
        position: absolute;
        z-index: 999999999; /*Maybe a tad unnecessary.*/
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        background: url(/my-screensaver-image.png) no-repeat 0 0;
        background-size: 100%;
    }

Now my image gently fades in over the interface and the cursor disappears. Then when any input is detected, it fades out quickly and the user can access anything they want.

This also has an added benefit of letting me reset the interface when it goes idle. After the image comes up, I can reset any form fields or anything that the user opened so that the next user will have a fresh experience.

It's so easy to come at a problem from the wrong direction. Sometimes it takes doing it the wrong way (sometimes for hours) before you finally figure out a better way. I think the trick is to not get stuck. I tend to pick a direction I think will work and then stubbornly pursue it past the point of determined to the point of obsessive.

Step back, give it a quick think before you dive into a solution you think will work.

Take care,

Richard Cagle

This article is my 24th oldest. It is 637 words long

comments powered by Disqus