|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis starter kit and sample code can be used as a starter project to write your own screen saver. It handles the arguments passed to a screen saver application by the system, which includes the preview in the desktop screen saver property dialog, as well as a configuration dialog. This code simplifies the necessary steps to an absolute minimum. BackgroundI wanted to write a simple screen saver by myself: worms. I started with the Screen Saver Starter Kit that comes with Visual Studio 2005, but wasn't happy with how they implemented it. The disadvantages of it are:
My intention was not to write an application with high quality and/or fancy-rendering OpenGL or DirectX animations (there are hundreds to find on the web). It should be a starter kit that:
Using the CodeDifference to a Normal ApplicationThe big difference between a screen saver application and a normal Windows application is that we have the full screen for us when it's running, so we don't have to be able to re-draw any part of the client area in a paint event handler. Either the screen saver is on and the full screen is ours, or it is off. This means that we don't use the paint event handler to draw our animation; we can do it directly in the timer event handler. Also, if we have just little parts on the screen that change in every animation step, we can directly update these parts and don't have to refresh the full screen. This saves a lot of CPU usage. What the Starter Kit Does
Class ScreenSaverFormThe constructor gets an integer passed, which is the Windows handle for a possible preview window. If the system calls the screen saver in preview mode, it passes this handle as the second argument after In full screen mode, the form is initialized as a maximized and top-most window, a simple task to do. In preview mode, we have to manipulate the window settings with some Windows API calls. The trick is to set the parent window of our form to the passed Windows handle. We also have to set the window style of our form to be a child window. This is so that it will properly receive a close message from the systems screen saver properties dialog when a new screen saver is selected for the preview window. After that, we read the parent's client size and set that for our form, too. Finally, we set the global screen size to use. The next steps is to capture the screen (full or preview) in a bitmap so that we can re-draw it later. We also need to load and set up the timer values. After all that, we instantiate the screen saver of choice and call its private void ScreenSaverForm_Load( object sender, EventArgs e )
{
// use full screen
if( _ipParentHandle == IntPtr.Zero )
{
this.WindowState = FormWindowState.Maximized;
this.TopMost = true;
}
// use preview screen that's handle was passed to the application
else
{
_boFullScreen = false;
// set the (new) parent window
WinAPI.SetParent( this.Handle, _ipParentHandle );
// make this a child window, so it will properly
// receive a close message
// from the systems screen saver properties dialog when
// a new screen saver
// is selected for the preview window
WinAPI.SetWindowLong( this.Handle, WinAPI.SysConst.GWL_STYLE,
WinAPI.GetWindowLong( this.Handle, WinAPI.SysConst.GWL_STYLE ) |
WinAPI.SysConst.WS_CHILD );
// get the parents window size and set it for this form too
Rectangle rect;
WinAPI.GetClientRect( _ipParentHandle, out rect );
this.Size = rect.Size;
this.Location = new Point( 0, 0 );
}
Globals.ScreenSize = this.Size;
// save the background in a bitmap
Globals.BackGroundBitmap =
new Bitmap( Globals.ScreenSize.Width, Globals.ScreenSize.Height );
Graphics g = Graphics.FromImage( Globals.BackGroundBitmap );
g.CopyFromScreen( this.DesktopLocation, new Point( 0, 0 ),
Globals.ScreenSize );
g.Dispose();
// setup the timer, but don't start it yet
_tsBlackAfter =
new TimeSpan( Math.Min( Math.Max( 0,
Properties.Settings.Default.Main_BlackAfterHH ), 23 ),
Math.Min( Math.Max( 0,
Properties.Settings.Default.Main_BlackAfterMM ), 59 ),
Math.Min( Math.Max( 0,
Properties.Settings.Default.Main_BlackAfterSS ), 59 ) );
Globals.ScrSvrTimer = new Timer();
Globals.ScrSvrTimer.Interval = 100;
Globals.ScrSvrTimer.Tick += new System.EventHandler( this.timer1_Tick );
//////////////////////////////////////////////////////////////////////
// instantiate and load the screen saver
switch( Properties.Settings.Default.Main_ScreenSaver % 4 )
{
case 0:
_scrSvr = new ScreenSaverWorms();
break;
case 1:
_scrSvr = new ScreenSaverPacman();
break;
case 2:
_scrSvr = new ScreenSaverMaze();
break;
case 3:
_scrSvr = new ScreenSaverChromachron();
break;
}
_scrSvr.OnLoad( sender, e );
////////////////////////////////////////////////////////////////////
// last inits
Globals.Graph = CreateGraphics();
_pntMouseLocation = Control.MousePosition;
_dtStart = DateTime.Now;
Globals.ScrSvrTimer.Start();
}
The implemented event handlers of the form are very simple. When a Class ScreenSaverBaseClass Class GlobalsThis contains all the objects that are needed for the animation drawing, so we don't have to allocate it in every timer event.
The Screen Saver Samples
How to Write Your Own Screen Saver AnimationTo implement your own screen saver, just derive a class from Points of InterestWhile working on the problem to handle the preview mode, I created another project,
I put a batch file to the debug directory that copies the file to c:\windows\system32 and renames it to extension *.scr so you can select it in the desktop property dialog. Unfortunately, there are two things I couldn't solve:
Maybe someone has an answer to these two points. LicenseThis code is free to use for anybody. Copy, rename, change and/or expand it. History04.11.2007 First post
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||