A Screen Saver class library

A screen saver provides four services: preview, configuration, password change and running the screen saver itself. The system starts the screen saver with a command-line parameter to indicate which service to provide. Some of the services also make use of a second command-line parameter which is a window handle. Extra steps have to be taken in order to debug the screen saver when providing these services (Debugging your screen saver).

The Screen Saver

TScreenSaver extracts the command line parameter and creates the object that handles the specified service, as shown in Listing 1.

To create your own screen saver, derive from TScreenSaver and override the abstract methods MakePreviewMode, MakeSaverMode, MakePasswordMode and MakeConfigMode.

Config mode

TConfigMode provides a window handle that is extracted from the command line parameters. However, the window handle is undocumented and I am unsure what its use is. It's available in the Handle property if a use for it arises. TFormConfigMode displays a single form. For most screen savers this should suffice. Simply pass the name of your form class to the constructor Create.

Password mode

If a password is enabled for the screen saver, then Windows asks the screen saver to set it. TPasswordMode uses a TScreenSaverPassword which is initialized to a TDefaultScreenSaverPassword object by default. This class uses Windows routines to store and retrieve a password. TScreenSaverForm also uses it by default to check the password before exiting. If you want to provide your own password storage/retrieval mechanism, then make a new descendent of TScreenSaverPassword and override MakePassword in TPasswordMode.

Preview mode

When the user selects a screen saver, Windows tells it to show a preview on the 'Display Properties' dialog. The system passes the window handle in which to display on the command line. Any application responding to it must idle until the window becomes visible, display the preview, then exit when the window is hidden.

TPreviewMode handles this in Listing 2. The Start, Step, and Stop methods are filled in by descendents. For example, TCanvasPreviewMode prepares a TCanvas that paints on the preview window. Descendents need only redefine Step to provide the custom painting. TWinControlPreviewMode attaches a windows control to the preview window, sizing it correctly and displaying it.

Saver mode

The screen saver should guard against being launched full screen multiple times. Windows will usually try at least once to relaunch the saver once it is running. If the saver allows multiple instances to be launched, Windows will launch again for the new instance and soon dozens of instances will be running. TSaverMode prevents multiple launches with a TPreviousInstance, which uses a Windows atom to guarantee detect previous instances, as shown in Listing 3.

Descendant classes override the OnExecute method to display the screen saver itself. The behavior of a standard screen saver is encapsulated in TScreenSaverForm, which automatically grows to the size of the screen and takes care of detecting mouse movements and keystrokes. When user action is detected, it closes if the password (if enabled) is properly entered. Most screen savers will be able to customize this form.

Listing 4 shows the Descendant forms should provide startup code in SetUpScreenSaver, because overriding OnFormCreate doesn't work. DetectMouse and DetectKeyboard can also be customized. They both return True by default. Password is initialized to TDefaultScreenSaverPassword by default, which simply uses the default Windows screen saver password.

TFormSaverMode displays a single form. If you only want to display a form for the screen saver, then pass the name of your form class to the constructor Create.

Debugging

[not finished]

Using the Screen Saver Library - Flash Screen Saver

The screen saver library provides a layer that creates a working screen saver. It's up to descendant classes to build on this layer to create a useful screen saver. Most screen savers display some sort of repeating animation. For this purpose, the Flash® player from Macromedia is ideal. It is also packaged as an ActiveX® control, and is easily imported into Delphi.

We'll want the user to be able to select a Flash® file to play as well as play that file in the preview mode as well as the screen saver mode. We will make use of several classes from the library, including TScreenSaver, TScreenSaverForm, TFormConfigMode, TPasswordMode, TWinControlPreviewMode and TFormSaverMode

What about playing the Flash file at original size?

Listings

Listing 1

constructor TScreenSaver.Create;
var
  command: string;
begin
  command := UpperCase (ParamStr (1));
if is_switch (command, 'P') then
  FMode := MakePreviewMode
else if is_switch (command, 'S') then
  FMode := MakeSaverMode
else if is_switch (command, 'A') then
  FMode := MakePasswordMode
else if is_switch (command, 'C') or (command = '') then
  FMode := MakeConfigMode;
end;

Listing 2

procedure TPreviewMode.Execute;
begin
  while not IsWindowVisible (Handle) do begin
    Application.ProcessMessages;
  end;
  try
    Start;
    while IsWindowVisible (Handle) do begin
      Step;
      Application.ProcessMessages;
    end;
  finally
    Stop;
  end;
end;

Listing 3

procedure TSaverMode.Execute;
var
  finder: TAppFinder;
begin
  finder := TAppFinder.Create;
  try
    if finder.exists then
      finder.select_existing_app
    else
      OnExecute;
    end;
  finally
    finder.Free;
  end;
end;

Listing 4

TScreenSaverForm = class (TForm)
{code omitted}
protected
  procedure SetupScreenSaver; virtual;
  function MakePassword: TScreenSaverPassword; virtual;
  function GetDetectMouse: Boolean; virtual;
  function GetDetectKeyboard: Boolean; virtual;
public
  property DetectMouse: Boolean read GetDetectMouse;
  property DetectKeyboard: Boolean read GetDetectKeyboard;
end;