Issue 47 * May 1, 2008

How to Write a Screen Saver
with Revolution
Without "cracking the book!"

by Bill Marriott

Screen savers have a long, venerable history. It seems we've never been satisfied with just blanking the screen; we need fish to swim around or take journeys through star systems.

These days, most CRT monitors are designed to prevent burn-in through improved phosphor coating, and LCD monitors aren't susceptible to burn-in at all. But screen savers still have plenty of useful purposes. They can show the current time and weather conditions, analyze data in the search for intelligent life, decode genomes, and present RSS feeds. Screen savers are also used for advertising purposes or to present "dashboard" type information for business managers.

On Windows-based operating systems, a screen saver is just like any other program. The only difference is that instead of an extension of ".exe" they have an extension of ".scr" - in fact, you could just change the extension of any program on your computer to ".scr" and it will become a screen saver. Yes, even Revolution standalone programs created with Studio or Enterprise. There's a little bit more to it than that, though. We want a proper screen saver to integrate well with the Display Properties control panel in Windows, and otherwise behave in the ways a screen saver ought to. Fortunately, it's a piece of cake with Revolution.

Screen Saver Basics
If you've already run off and tried to change the extension of a program to ".scr" you've probably already seen a few of the problems. The first thing is that normal programs don't exactly cover the screen to "save" it effectively. Second, normal programs aren't designed to go away when you press a key or move the mouse. And finally, a lot of programs don't like to be started up as screen savers. They'll run an installer program to "fix" themselves, or complain about the weird startup options that occur when starting a screen saver. Let's take a look at some of the important differences between screen savers and normal programs.

When a file has the extension ".scr" Windows gives it a special context menu (the one that appears when you right-click the icon). The new commands are Test, Configure, and Install. Test will show the screen saver as if it was triggered by idle time. Configure will bring up the screen saver's "Options" panel, if it has one. And Install will register the file with Windows so it appears in the list of screen savers when you open Display Properties.

I suggest as you are developing and testing your own screen saver, you don't use the Install option, as this will create multiple instances of the screen saver in the Display Properties list that will be hard to remove. Instead, just copy each iteration into C:\Windows\System32 directly, over-writing any previous versions, and Windows will find it there just fine.

Getting Started
I'm going to show you how to build a screen saver the way I figured it out, without visiting Microsoft's developer site or relying on any outside resources. Reverse engineering is more fun... live on the wild side!

So fire up your copy of Revolution and follow along. We'll start with a brand-new stack.

Quitting the Screen Saver
This is going to be the most important part. If you write a stack that fills up the whole screen, hides the cursor, and puts on a pretty show, the joy will be quickly replaced with panic as you cannot regain control of your computer and have to restart. Therefore our first thought should be about how to quit the darned thing. Standard screen savers vanish with mouse or keyboard activity. This isn't handled by the operating system, you'll have to check with these things in your stack. You'll have to ensure the program exits cleanly, leaving no remnants of itself in memory, too. So the first handlers should be something like this in the card script:


on mouseDown
  if the environment is "development" then
    pass mouseDown
  else
    ssShutDown
  end if
end mouseDown

on rawKeyDown
  if the environment is "development" then
    pass rawKeyDown
  else
    ssShutDown
  end if
end rawKeyDown

on mouseMove
  if the environment is "development" then
    pass mouseMove
  else
    ssShutDown
  end if
end mouseMove

Now, I've already been a little clever here. I don't want the stack to quit while I'm working on it, so I check to see whether I'm in the IDE or not. If the system property "environment" is "development" then I just pass the message along as if my handler wasn't there. Otherwise I call "ssShutDown" which will be a handler in the stack script. Here's what that looks like:


on ssShutDown
    if the environment is not "development" then
      
      -- cancel messages
      put the pendingMessages into stopList
      repeat for each line stopMessage in stopList
        cancel item 1 of stopMessage
      end repeat
      
      -- exit application
      quit
    else
      beep
    end if
end ssShutDown

Again, I don't want the stack to close while I'm working on it, so I check the environment variable. I might be calling this handler under other conditions and I just don't want it to quit and cause me to lose my work. Another important addition here is canceling all pending messages. Leaving a stray message or two lying around when trying to quit is a sure way to find your program still listed in the Task Manager, still hogging memory and system resources, and generally being regarded as sloppy. Anything else I will need to do when shutting down the screen saver can be handled from here.

We can actually try this out as our first attempt. Save it as a standalone application for Windows and drop it into the System32 folder. Go to the Screen Saver tab of Display Properties and you'll see it listed. Click on it, and then click "Test." You'll see your stack pop up. When you move your mouse over it, it should disappear.

I have a stack that quits properly, what to do next?

Inside Screen Savers
While we have Display Properties open, it's a good idea to check out the various buttons and behaviors of a well-behaved screen saver.

We see three elements here: A preview image in the mini-monitor, a Settings button, and a Preview button. How can our Rev stack handle these various situations?

To figure this out, I'm going to add a little bit of code to our vanilla screen saver stack. First I add a one-line field to the stack. Then I add the following code to the stack script:


on startUp
  put $1 into fld 1
end startup

No, I haven't gotten myself mixed up with BASIC, $1 is a special variable that contains the command line parameters used to launch a program. Since a screen saver is just a normal program that is started by the system when it's idle, I figured this was the most natural way for Windows to tell the screen saver what it should be doing.

Save as a standalone, change the extension to .scr, and drop it into the System32 folder to see what happens. (By the way, the name used in the Screen Saver menu is the name you assign in the General tab of the Standalone Application Settings dialog box.)

You'll discover that when you first open the Display Properties panel and select your screen saver from the drop-down, your screen saver immediately pops up with "/p" in the field. This is because Windows is calling your screen saver in order to render the preview in the little monitor... the p stands for "preview." Move your mouse over your stack. It goes away.

Now click the "Settings" button. Your stack comes up with something like, "/c:7998344" in the field. You can bet the c stands for configure. Who knows what the number is for. (Remember I said I wasn't going to read any stuffy documentation on this!)

Move your mouse over the stack to make it disappear again. And finally, click the "Preview" button. Your stack pops up with "/s" in the field. Aha, s must mean, "save screen." Eureka.

As a final exercise, set the sleep time to one minute and wait. Your stack will come up again in 60 seconds with the "/s" option showing.

What we learned in this step is that the Windows Display Properties control panel will open your stack with one of three command-line switches: p for preview, c for configuration, and s for screen saving.

Punting on Preview
Here's one limitation of refusing to read documentation or learn C++ or something hard like that. My screen saver isn't going to show a Preview in the little monitor. One of the other parameters, $2, actually passes along a number with the /p switch which is a window ID to that little monitor so we could put our screen saver in there. But there's no built-in way for Revolution to make use of that number. Well, it might be possible. Something for the folks on the use- Revolution list to figure out.

Three Stacks in One
Ok, so now I know my stack will be called with one of three command-line parameters. And it has to behave differently each time. When it gets /p, it has to quit and do nothing. When it gets /c, it has to show a configuration box. And when it gets /s it has to save the screen. Other considerations:

  • When it's in the configuration mode, it should go away (quit) only when I click OK or Cancel, not when I move the mouse around, etc.
  • When it's in screen saving mode, it's got to fill the whole screen and go away like any other screen saver
  • I have to figure out some way to save and communicate the settings between those sessions

The way I decided to handle this was to use substacks. I'll leave the "main" stack just so I have something to call home, and I'll create two sub stacks, "display" and "config."

I'm not exactly sure what my screen saver will look like yet, so I'll just create a simple dialog with basic options. Here's what mine ended up looking like:

Notice that I set the decorations so there was no close box. Next, I created a "display" substack and set the decorations to none, with a black background. (I'm not going to provide a screen shot of that, you'll just have to imagine it.)

I moved the mouseDown, mouseMove, and rawKeyDown handlers from the first card of the main stack to the first card of the display substack, because that's the one that will have to be dismissed by mouse/keyboard activity. I kept the ssShutDown handler in the main stack script. Then I wired OK and Cancel to simply call ssShutDown for the time being.

The main thing now was to have the program operate in three different ways depending on the command line parameters. So I put the following into the main stack script:

on startUp
  lock screen
  hide stack "ScreenSaver"
  hide stack "config"
  hide stack "display"
  ssInit $1
end startUp

on ssInit startupType
  switch startupType
  case "/p"
    ssSilent
    break
  case "/s"
    ssSave
    break
  default
    ssConfigure
  end switch
end ssInit

on ssSilent
  unlock screen
  quit
end ssSilent

on ssConfigure
  go stack "config"
  show stack "config"
  unlock screen
end ssConfigure

on ssSave
  go stack "display"
  show stack "display"
  unlock screen
end ssSave

The case statement defaults to configure mode because I found that no command line parameter is placed in $1 when choosing "Settings" from the Explorer context menu, and we would want to account for this possibility anyway.

Now, when you test your screen saver, you'll see the stack opens in three modes:

  • Preview, which simply quits without displaying anything
  • Configure, which shows the settings dialog
  • Screen saving, which shows the black rectangle stack

Saving Settings
There's one more important consideration and that is to have the configuration stack save settings in a way that the display stack can use them across sessions. There are many ways you could do this, including using the registry. I opted instead to write a small file to the application data folder which is read in each time the screen saver is activated.

Saving the Screen
Finally I was able to think about what I wanted the screen saver itself to do. I opted for bouncing the Revolution logo around the screen. I made up an animated GIF using a 3D program and dropped it into the card:

For the animation, I didn't want to have a crushing burden on the CPU, so I used the "send in [time]" technique along with move. The sample stack, which you can use as a template for your own screen savers can be found here

I hope you enjoyed learning how to make a screen saver with Revolution. We'd enjoy learning how you've used this technique.

Main Menu What's New