context: #region Usage notice
  /*
   * Screensaver.cs
   * 
   * (c) Rei Miyasaka 2006
   * rei@thefraser.com
   * 
   * Last updated 2006.05.16
   * 
   * You may use this code for any purpose, in part or in whole, on two conditions:
   * 1. I cannot be held legally responsible for any damage or problems caused by this code.
   * 2. If you make something cool using this code, give me a shout and tell me about it.
   *
   */
  #endregion
  
  using System;
  using System.Windows.Forms;
  using System.Drawing;
  using System.Collections;
  using System.Text;
  using System.Runtime.InteropServices;
  
  namespace Screensavers
  {
  	/// <summary>
  	/// Provides initialization, timing and windowing facilities for screensavers.
  	/// </summary>
  	public abstract class Screensaver
  	{
  		/// <summary>
  		/// Creates a new <see cref="Screensaver"/> with the given fullscreen mode.
  		/// </summary>
  		/// <param name="fullscreenMode">A value indicating the fullscreen windowing mode.</param>
  		protected Screensaver(FullscreenMode fullscreenMode)
  		{
  			this.fullscreenMode = fullscreenMode;
  			Application.EnableVisualStyles();
  			Application.SetCompatibleTextRenderingDefault(false);
  
  			Framerate = 30;
  
  			framerateTimer.Elapsed += new System.Timers.ElapsedEventHandler(framerateTimer_Elapsed);
  			framerateTimer.Start();
  		}
  
  		/// <summary>
  		/// Creates a new <see cref="Screensaver"/> that runs one window per screen.
  		/// </summary>
  		protected Screensaver()
  			: this(FullscreenMode.MultipleWindows)
  		{
  		}
  
  		void  framerateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  		{
  			achievedFramerate = updatesThisSec;
  			updatesThisSec = 0;
  			if (OneSecondTick != null)
  				OneSecondTick(this, new EventArgs());
  		}
  
  		/// <summary>
  		/// Occurs before the screensaver windows close.
  		/// </summary>
  		public event EventHandler Exit;
  
  		#region Multimedia Timer
  
  		[DllImport("winmm.dll")]
  		static extern int timeSetEvent(int delay, int resolution, TimeCallback callback, int user, int mode);
  
  		[DllImport("winmm.dll")]
  		static extern int timeKillEvent(int id);
  
  		[DllImport("winmm.dll")]
  		static extern int timeGetTime();
  
  		delegate void TimeCallback(uint id, uint msg, IntPtr user, IntPtr param1, IntPtr param2);
  
  		TimeCallback timerCallback;
  
  		int timerId;
  
  		void StartUpdating()
  		{
  			timerCallback = new TimeCallback(TimerCallback);
  			//TIME_KILL_SYNCHRONOUS = 0x0100
  			//TIME_PERIODIC = 0x0001
  			timerId = timeSetEvent((int)(1000/(double)framerate), 0, timerCallback, 0, 0x0101);
  
  			while (timerCallback != null)
  			{
  				updateEvent.WaitOne();
  				DoUpdate();
  				Application.DoEvents();
  				updateEvent.Reset();
  			}
  
  		}
  
  		void StopUpdating()
  		{
  			timerCallback = null;
  			timeKillEvent(timerId);
  			updateEvent.WaitOne();
  		}
  
  		System.Threading.ManualResetEvent updateEvent = new System.Threading.ManualResetEvent(false);
  
  		void TimerCallback(uint id, uint msg, IntPtr user, IntPtr param1, IntPtr param2)
  		{
  			updateEvent.Set();
  		}
  
  		System.Timers.Timer framerateTimer = new System.Timers.Timer(1000);
  
  		/// <summary>
  		/// Occurs once each second on a thread separate from the window thread.
  		/// </summary>
  		public event EventHandler OneSecondTick;
  
  		int framerate;
  
  		/// <summary>
  		/// Gets or sets the target framerate.
  		/// </summary>
  		public int Framerate
  		{
  			get { return framerate; }
  			set
  			{
  				if (value < 0)
  					throw new ArgumentOutOfRangeException();
  				if (timerCallback != null)
  				{
  					StopUpdating();
  					framerate = value;
  					StartUpdating();
  				}
  				else
  					framerate = value;
  			}
  		}
  
  		#endregion
  
  		[StructLayout(LayoutKind.Sequential)]
  		struct RECT
  		{
  			public int left, top, right, bottom;
  		}
  
  		[DllImport("user32.dll")]
  		static extern bool GetClientRect(IntPtr handle, out RECT rect);
  		[DllImport("user32.dll")]
  		static extern bool IsWindowVisible(IntPtr handle);
  
  		static Rectangle GetClientRect(IntPtr handle)
  		{
  			RECT rect;
  			GetClientRect(handle, out rect);
  			return Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
  		}
  
  		/// <summary>
  		/// Occurs when the screensaver should process its logic and render.
  		/// </summary>
  		public event EventHandler Update;
  
  		event EventHandler PreUpdate;
  		event EventHandler PostUpdate;
  
  		int achievedFramerate;
  		int updatesThisSec;
  
  		/// <summary>
  		/// Actual framerate achieved. This value is updated once each second.
  		/// </summary>
  		public int AchievedFramerate
  		{
  			get { return achievedFramerate; }
  		}
  
  		void DoUpdate()
  		{
  			if (screensaverMode == ScreensaverMode.Preview && !IsWindowVisible(windowHandle))
  			{
  				StopUpdating();
  				if (Exit != null)
  					Exit(this, new EventArgs());
  				previewShutdownEvent.Set();
  				return;
  			}
  
  			if (PreUpdate != null)
  				PreUpdate(this, new EventArgs());
  			if (Update != null)
  				Update(this, new EventArgs());
  			if (PostUpdate != null)
  				PostUpdate(this, new EventArgs());
  			updatesThisSec++;
  		}
  
  		ScreensaverMode ProcessCommandLine()
  		{
  			string[] args = Environment.GetCommandLineArgs();
  
  			if (args.Length == 1 && IsScr)
  				return ScreensaverMode.Settings;
  
  			if (args.Length < 2)
  				throw new FormatException();
  
  			if (args[1].ToLower().StartsWith("/c"))
  			{
  				return ScreensaverMode.Settings;
  			}
  
  			switch (args[1].ToLower())
  			{
  				case "w":
  					return ScreensaverMode.Windowed;
  				case "/s":
  					return ScreensaverMode.Normal;
  				case "/p":
  					if (args.Length < 3)
  					{
  						throw new FormatException();
  					}
  					try
  					{
  						windowHandle = (IntPtr)uint.Parse(args[2]);
  						return ScreensaverMode.Preview;
  					}
  					catch (FormatException)
  					{
  						throw new FormatException();
  					}
  				default:
  					throw new FormatException();
  			}
  		}
  
  		bool IsScr
  		{
  			get
  			{
  				return System.IO.Path.GetExtension(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).
  					Equals(".scr", StringComparison.InvariantCultureIgnoreCase);
  			}
  		}
  
  		/// <summary>
  		/// Start the screensaver in windowed mode if the file extension is not scr, unless a mode is specified in the command line.
  		/// Otherwise, if the file extension is scr, start the screensaver in config mode.
  		/// </summary>
  		public void Run()
  		{
  			Run(ScreensaverMode.Windowed);
  		}
  
  		/// <summary>
  		/// Start the screensaver in the specified mode unless one is specified in the command line.
  		/// </summary>
  		/// <param name="mode">The mode in which to run the screensaver. This value cannot be <see cref="ScreensaverMode.Preview"/>.</param>
  		public void Run(ScreensaverMode mode)
  		{
  			if (mode == ScreensaverMode.Preview && windowHandle == IntPtr.Zero)
  				throw new ArgumentException("Cannot explicity run in preview mode", "mode");
  
  			if (isEnded)
  				throw new Exception("This screensaver has already finished running");
  
  			try
  			{
  				this.screensaverMode = ProcessCommandLine();
  			}
  			catch (FormatException)
  			{
  				this.screensaverMode = mode;
  			}
  
  			try
  			{
  				switch (screensaverMode)
  				{
  					case ScreensaverMode.Windowed:
  						RunWindowed();
  						break;
  					case ScreensaverMode.Settings:
  						ShowSettingsDialog();
  						break;
  					case ScreensaverMode.Normal:
  						if (!closeOnMouseMoveOverride)
  							closeOnMouseMove = true;
  						if (!closeOnClickOverride)
  							closeOnClick = true;
  						if (!closeOnKeyboardInputOverride)
  							closeOnKeyboardInput = true;
  
  						RunNormal();
  						break;
  					case ScreensaverMode.Preview:
  						RunPreview();
  						break;
  				}
  			}
  			finally
  			{
  				isEnded = true;
  			}
  
  		}
  
  		FullscreenMode fullscreenMode = FullscreenMode.SingleWindow;
  		ScreensaverMode screensaverMode;
  
  		/// <summary>
  		/// Gets the current running mode of the screensaver.
  		/// </summary>
  		public ScreensaverMode Mode
  		{
  			get { return screensaverMode; }
  		}
  
  		IntPtr windowHandle = IntPtr.Zero;
  
  		/// <summary>
  		/// Occurs after the windows are created, before the screensaver runs.
  		/// </summary>
  		public event EventHandler Initialize;
  
  		bool closeOnMouseMove;
  		bool closeOnMouseMoveOverride;
  
  		/// <summary>
  		/// Gets or sets a value indicating whether or not the screensaver should close when the user moves the mouse.
  		/// </summary>
  		/// <remarks>This value is <c>true</c> by default in all modes except <see cref="ScreensaverMode.Windowed"/>.</remarks>
  		public bool CloseOnMouseMove
  		{
  			get { return closeOnMouseMove; }
  			set { closeOnMouseMove = value; closeOnMouseMoveOverride = true; }
  		}
  
  		bool closeOnClick;
  		bool closeOnClickOverride;
  
  		/// <summary>
  		/// Gets or sets a value indicating whether or not the screensaver should close when the user clicks the mouse.
  		/// </summary>
  		/// <remarks>This value is <c>true</c> by default in all modes except <see cref="ScreensaverMode.Windowed"/>.</remarks>
  		public bool CloseOnClick
  		{
  			get { return closeOnClick; }
  			set { closeOnClick = value; closeOnClickOverride = true; }
  		}
  
  		bool closeOnKeyboardInput;
  		bool closeOnKeyboardInputOverride;
  
  		/// <summary>
  		/// Gets or sets a value indicating whether or not the screensaver should close when the user presses a key.
  		/// </summary>
  		/// <remarks>This value is <c>true</c> by default in all modes except <see cref="ScreensaverMode.Windowed"/>.</remarks>
  		public bool CloseOnKeyboardInput
  		{
  			get { return closeOnKeyboardInput; }
  			set { closeOnKeyboardInput = value; closeOnKeyboardInputOverride = true; }
  		}
  
  		WindowCollection windows;
  
  		/// <summary>
  		/// Gets a collection of all of the running screensaver windows.
  		/// </summary>
  		public WindowCollection Windows
  		{
  			get { return windows; }
  		}
  
  		Window window0;
  
  		/// <summary>
  		/// Gets the primary screensaver window.
  		/// </summary>
  		public Window Window0
  		{
  			get
  			{
  				if(window0 != null)
  					return window0;
  
  				if (windows == null || windows.Count == 0)
  					return null;
  
  				window0 = windows[0];
  
  				return window0;
  			}
  		}
  
  		Graphics graphics0;
  
  		/// <summary>
  		/// Gets the GDI graphics object for the primary window.
  		/// </summary>
  		public Graphics Graphics0
  		{
  			get
  			{
  				if (graphics0 != null)
  					return graphics0;
  
  				if (Window0 == null)
  					return null;
  
  				graphics0 = Window0.Graphics;
  				return graphics0;
  			}
  		}
  
  		string settingsText;
  
  		/// <summary>
  		/// Gets or sets text to be displayed in the default settings message box.
  		/// </summary>
  		public string SettingsText
  		{
  			get { return settingsText; }
  			set { settingsText = value; }
  		}
  
  		/// <summary>
  		/// Shows the settings dialog, or, by default, shows a message box indicating the assembly name, version and copyright information.
  		/// </summary>
  		protected virtual void ShowSettingsDialog()
  		{
  
gt: 			System.IO.StringWriter sw = new System.IO.StringWriter();